mirror of
https://github.com/apache/nuttx.git
synced 2026-05-21 04:52:02 +08:00
0dccc8ba21
debug.h is a NuttX-specific, non-POSIX header. Placing it in the top-level include/ directory creates naming conflicts with external projects that define their own debug.h. This commit moves the canonical header to include/nuttx/debug.h, following the NuttX convention for non-POSIX/non-standard headers, and updates all in-tree references. A backward-compatibility shim is left at include/debug.h that emits a deprecation #warning and re-includes <nuttx/debug.h>, allowing out-of-tree code to continue building while migrating. Signed-off-by: Piyush Patle <piyushpatle228@gmail.com>
1313 lines
42 KiB
C
1313 lines
42 KiB
C
/***************************************************************************
|
|
* drivers/serial/uart_xlnx_ps.c
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership. The
|
|
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance with the
|
|
* License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing permissions and limitations
|
|
* under the License.
|
|
*
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* Included Files
|
|
***************************************************************************/
|
|
|
|
#include <nuttx/config.h>
|
|
#include <sys/types.h>
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <nuttx/debug.h>
|
|
|
|
#ifdef CONFIG_SERIAL_TERMIOS
|
|
# include <termios.h>
|
|
#endif
|
|
|
|
#include <nuttx/irq.h>
|
|
#include <nuttx/arch.h>
|
|
#include <nuttx/spinlock.h>
|
|
#include <nuttx/init.h>
|
|
#include <nuttx/fs/ioctl.h>
|
|
#include <nuttx/semaphore.h>
|
|
#include <nuttx/serial/serial.h>
|
|
|
|
#ifdef CONFIG_UART_XLNXPS
|
|
|
|
/***************************************************************************
|
|
* Pre-processor Definitions
|
|
***************************************************************************/
|
|
|
|
#define getreg8(a) (*(volatile uint8_t *)(a))
|
|
#define putreg8(v,a) (*(volatile uint8_t *)(a) = (v))
|
|
#define getreg16(a) (*(volatile uint16_t *)(a))
|
|
#define putreg16(v,a) (*(volatile uint16_t *)(a) = (v))
|
|
#define getreg32(a) (*(volatile uint32_t *)(a))
|
|
#define putreg32(v,a) (*(volatile uint32_t *)(a) = (v))
|
|
#define getreg64(a) (*(volatile uint64_t *)(a))
|
|
#define putreg64(v,a) (*(volatile uint64_t *)(a) = (v))
|
|
|
|
/* Non-atomic, but more effective modification of registers */
|
|
|
|
#define modreg8(v,m,a) putreg8((getreg8(a) & ~(m)) | ((v) & (m)), (a))
|
|
#define modreg16(v,m,a) putreg16((getreg16(a) & ~(m)) | ((v) & (m)), (a))
|
|
#define modreg32(v,m,a) putreg32((getreg32(a) & ~(m)) | ((v) & (m)), (a))
|
|
#define modreg64(v,m,a) putreg64((getreg64(a) & ~(m)) | ((v) & (m)), (a))
|
|
|
|
/* UART0 is console and ttyS0 */
|
|
|
|
#define CONSOLE_DEV g_uart0port /* UART0 is console */
|
|
#define TTYS0_DEV g_uart0port /* UART0 is ttyS0 */
|
|
#define UART0_ASSIGNED 1
|
|
|
|
/***************************************************************************
|
|
* UART_XLNXPS UART Registers and Bit Definitions
|
|
*
|
|
* Register Map
|
|
*
|
|
* Register offsets for the UART.
|
|
***************************************************************************/
|
|
|
|
#define XUARTPS_CR_OFFSET 0x0000U /* Control Register [8:0] */
|
|
#define XUARTPS_MR_OFFSET 0x0004U /* Mode Register [9:0] */
|
|
#define XUARTPS_IER_OFFSET 0x0008U /* Interrupt Enable [12:0] */
|
|
#define XUARTPS_IDR_OFFSET 0x000CU /* Interrupt Disable [12:0] */
|
|
#define XUARTPS_IMR_OFFSET 0x0010U /* Interrupt Mask [12:0] */
|
|
#define XUARTPS_ISR_OFFSET 0x0014U /* Interrupt Status [12:0]*/
|
|
#define XUARTPS_BAUDGEN_OFFSET 0x0018U /* Baud Rate Generator [15:0] */
|
|
#define XUARTPS_RXTOUT_OFFSET 0x001CU /* RX Timeout [7:0] */
|
|
#define XUARTPS_RXWM_OFFSET 0x0020U /* RX FIFO Trigger Level [5:0] */
|
|
#define XUARTPS_MODEMCR_OFFSET 0x0024U /* Modem Control [5:0] */
|
|
#define XUARTPS_MODEMSR_OFFSET 0x0028U /* Modem Status [8:0] */
|
|
#define XUARTPS_SR_OFFSET 0x002CU /* Channel Status [14:0] */
|
|
#define XUARTPS_FIFO_OFFSET 0x0030U /* FIFO [7:0] */
|
|
#define XUARTPS_BAUDDIV_OFFSET 0x0034U /* Baud Rate Divider [7:0] */
|
|
#define XUARTPS_FLOWDEL_OFFSET 0x0038U /* Flow Delay [5:0] */
|
|
#define XUARTPS_TXWM_OFFSET 0x0044U /* TX FIFO Trigger Level [5:0] */
|
|
#define XUARTPS_RXBS_OFFSET 0x0048U /* RX FIFO Byte Status [11:0] */
|
|
|
|
/***************************************************************************
|
|
* Control Register
|
|
*
|
|
* The Control register (CR) controls the major functions of the device.
|
|
*
|
|
* Control Register Bit Definition
|
|
***************************************************************************/
|
|
|
|
#define XUARTPS_CR_STOPBRK 0x00000100U /* Stop transmission of break */
|
|
#define XUARTPS_CR_STARTBRK 0x00000080U /* Set break */
|
|
#define XUARTPS_CR_TORST 0x00000040U /* RX timeout counter restart */
|
|
#define XUARTPS_CR_TX_DIS 0x00000020U /* TX disabled. */
|
|
#define XUARTPS_CR_TX_EN 0x00000010U /* TX enabled */
|
|
#define XUARTPS_CR_RX_DIS 0x00000008U /* RX disabled. */
|
|
#define XUARTPS_CR_RX_EN 0x00000004U /* RX enabled */
|
|
#define XUARTPS_CR_EN_DIS_MASK 0x0000003CU /* Enable/disable Mask */
|
|
#define XUARTPS_CR_TXRST 0x00000002U /* TX logic reset */
|
|
#define XUARTPS_CR_RXRST 0x00000001U /* RX logic reset */
|
|
|
|
/***************************************************************************
|
|
* Mode Register
|
|
*
|
|
* The mode register (MR) defines the mode of transfer as well as the data
|
|
* format. If this register is modified during transmission or reception,
|
|
* data validity cannot be guaranteed.
|
|
*
|
|
* Mode Register Bit Definition
|
|
*
|
|
***************************************************************************/
|
|
#define XUARTPS_MR_CCLK 0x00000400U /* Input clock selection */
|
|
#define XUARTPS_MR_CHMODE_R_LOOP 0x00000300U /* Remote loopback mode */
|
|
#define XUARTPS_MR_CHMODE_L_LOOP 0x00000200U /* Local loopback mode */
|
|
#define XUARTPS_MR_CHMODE_ECHO 0x00000100U /* Auto echo mode */
|
|
#define XUARTPS_MR_CHMODE_NORM 0x00000000U /* Normal mode */
|
|
#define XUARTPS_MR_CHMODE_SHIFT 8U /* Mode shift */
|
|
#define XUARTPS_MR_CHMODE_MASK 0x00000300U /* Mode mask */
|
|
#define XUARTPS_MR_STOPMODE_2_BIT 0x00000080U /* 2 stop bits */
|
|
#define XUARTPS_MR_STOPMODE_1_5_BIT 0x00000040U /* 1.5 stop bits */
|
|
#define XUARTPS_MR_STOPMODE_1_BIT 0x00000000U /* 1 stop bit */
|
|
#define XUARTPS_MR_STOPMODE_SHIFT 6U /* Stop bits shift */
|
|
#define XUARTPS_MR_STOPMODE_MASK 0x000000A0U /* Stop bits mask */
|
|
#define XUARTPS_MR_PARITY_NONE 0x00000020U /* No parity mode */
|
|
#define XUARTPS_MR_PARITY_MARK 0x00000018U /* Mark parity mode */
|
|
#define XUARTPS_MR_PARITY_SPACE 0x00000010U /* Space parity mode */
|
|
#define XUARTPS_MR_PARITY_ODD 0x00000008U /* Odd parity mode */
|
|
#define XUARTPS_MR_PARITY_EVEN 0x00000000U /* Even parity mode */
|
|
#define XUARTPS_MR_PARITY_SHIFT 3U /* Parity setting shift */
|
|
#define XUARTPS_MR_PARITY_MASK 0x00000038U /* Parity mask */
|
|
#define XUARTPS_MR_CHARLEN_6_BIT 0x00000006U /* 6 bits data */
|
|
#define XUARTPS_MR_CHARLEN_7_BIT 0x00000004U /* 7 bits data */
|
|
#define XUARTPS_MR_CHARLEN_8_BIT 0x00000000U /* 8 bits data */
|
|
#define XUARTPS_MR_CHARLEN_SHIFT 1U /* Data Length shift */
|
|
#define XUARTPS_MR_CHARLEN_MASK 0x00000006U /* Data length mask */
|
|
#define XUARTPS_MR_CLKSEL 0x00000001U /* Input clock selection */
|
|
|
|
#define UART_DEFAULT_MODE XUARTPS_MR_CHMODE_NORM | \
|
|
XUARTPS_MR_STOPMODE_1_BIT | \
|
|
XUARTPS_MR_PARITY_NONE | \
|
|
XUARTPS_MR_CHARLEN_8_BIT
|
|
|
|
/***************************************************************************
|
|
* Interrupt Registers
|
|
*
|
|
* Interrupt control logic uses the interrupt enable register (IER) and the
|
|
* interrupt disable register (IDR) to set the value of the bits in the
|
|
* interrupt mask register (IMR). The IMR determines whether to pass an
|
|
* interrupt to the interrupt status register (ISR).
|
|
* Writing a 1 to IER Enbables an interrupt, writing a 1 to IDR disables an
|
|
* interrupt. IMR and ISR are read only, and IER and IDR are write only.
|
|
* Reading either IER or IDR returns 0x00.
|
|
*
|
|
* All four registers have the same bit definitions.
|
|
*
|
|
***************************************************************************/
|
|
|
|
#define XUARTPS_IXR_RBRK 0x00002000U /* Rx FIFO break detect interrupt */
|
|
#define XUARTPS_IXR_TOVR 0x00001000U /* Tx FIFO Overflow interrupt */
|
|
#define XUARTPS_IXR_TNFUL 0x00000800U /* Tx FIFO Nearly Full interrupt */
|
|
#define XUARTPS_IXR_TTRIG 0x00000400U /* Tx Trig interrupt */
|
|
#define XUARTPS_IXR_DMS 0x00000200U /* Modem status change interrupt */
|
|
#define XUARTPS_IXR_TOUT 0x00000100U /* Timeout error interrupt */
|
|
#define XUARTPS_IXR_PARITY 0x00000080U /* Parity error interrupt */
|
|
#define XUARTPS_IXR_FRAMING 0x00000040U /* Framing error interrupt */
|
|
#define XUARTPS_IXR_OVER 0x00000020U /* Overrun error interrupt */
|
|
#define XUARTPS_IXR_TXFULL 0x00000010U /* TX FIFO full interrupt. */
|
|
#define XUARTPS_IXR_TXEMPTY 0x00000008U /* TX FIFO empty interrupt. */
|
|
#define XUARTPS_IXR_RXFULL 0x00000004U /* RX FIFO full interrupt. */
|
|
#define XUARTPS_IXR_RXEMPTY 0x00000002U /* RX FIFO empty interrupt. */
|
|
#define XUARTPS_IXR_RXOVR 0x00000001U /* RX FIFO trigger interrupt. */
|
|
#define XUARTPS_IXR_MASK 0x00003FFFU /* Valid bit mask */
|
|
|
|
/***************************************************************************
|
|
* Baud Rate Generator Register
|
|
*
|
|
* The baud rate generator control register (BRGR) is a 16 bit register that
|
|
* controls the receiver bit sample clock and baud rate.
|
|
* Valid values are 1 - 65535.
|
|
*
|
|
* Bit Sample Rate = CCLK / BRGR, where the CCLK is selected by the MR_CCLK
|
|
* bit in the MR register.
|
|
*
|
|
***************************************************************************/
|
|
|
|
#define XUARTPS_BAUDGEN_DISABLE 0x00000000U /* Disable clock */
|
|
#define XUARTPS_BAUDGEN_MASK 0x0000FFFFU /* Valid bits mask */
|
|
#define XUARTPS_BAUDGEN_RESET_VAL 0x0000028BU /* Reset value */
|
|
|
|
/***************************************************************************
|
|
* Baud Divisor Rate register
|
|
*
|
|
* The baud rate divider register (BDIV) controls how much the bit sample
|
|
* rate is divided by. It sets the baud rate.
|
|
* Valid values are 0x04 to 0xFF. Writing a value less than 4 will be
|
|
* ignored.
|
|
*
|
|
* Baud rate = CCLK / ((BAUDDIV + 1) x BRGR), where the CCLK is selected by
|
|
* the MR_CCLK bit in the MR register.
|
|
*
|
|
***************************************************************************/
|
|
|
|
#define XUARTPS_BAUDDIV_MASK 0x000000FFU /* 8 bit baud divider mask */
|
|
#define XUARTPS_BAUDDIV_RESET_VAL 0x0000000FU /* Reset value */
|
|
|
|
/***************************************************************************
|
|
* The following constant defines the amount of error that is allowed for
|
|
* a specified baud rate. This error is the difference between the actual
|
|
* baud rate that will be generated using the specified clock and the
|
|
* desired baud rate.
|
|
***************************************************************************/
|
|
|
|
#define XUARTPS_MAX_BAUD_ERROR_RATE 3U /* max % error allowed */
|
|
|
|
/***************************************************************************
|
|
* The following constants indicate the max and min baud rates and these
|
|
* numbers are based only on the testing that has been done. The hardware
|
|
* is capable of other baud rates.
|
|
***************************************************************************/
|
|
|
|
#define XUARTPS_MAX_RATE 6240000U
|
|
#define XUARTPS_MIN_RATE 110U
|
|
|
|
/***************************************************************************
|
|
* Receiver Timeout Register
|
|
*
|
|
* Use the receiver timeout register (RTR) to detect an idle condition on
|
|
* the receiver data line.
|
|
*
|
|
***************************************************************************/
|
|
|
|
#define XUARTPS_RXTOUT_DISABLE 0x00000000U /* Disable time out */
|
|
#define XUARTPS_RXTOUT_MASK 0x000000FFU /* Valid bits mask */
|
|
|
|
/***************************************************************************
|
|
* Receiver FIFO Trigger Level Register
|
|
*
|
|
* Use the Receiver FIFO Trigger Level Register (RTRIG) to set the value at
|
|
* which the RX FIFO triggers an interrupt event.
|
|
*
|
|
***************************************************************************/
|
|
|
|
#define XUARTPS_RXWM_DISABLE 0x00000000U /* Disable RX trigger interrupt */
|
|
#define XUARTPS_RXWM_MASK 0x0000003FU /* Valid bits mask */
|
|
#define XUARTPS_RXWM_RESET_VAL 0x00000020U /* Reset value */
|
|
|
|
/***************************************************************************
|
|
* Transmit FIFO Trigger Level Register
|
|
*
|
|
* Use the Transmit FIFO Trigger Level Register (TTRIG) to set the value at
|
|
* which the TX FIFO triggers an interrupt event.
|
|
*
|
|
***************************************************************************/
|
|
|
|
#define XUARTPS_TXWM_MASK 0x0000003FU /* Valid bits mask */
|
|
#define XUARTPS_TXWM_RESET_VAL 0x00000020U /* Reset value */
|
|
|
|
/***************************************************************************
|
|
* Modem Control Register
|
|
*
|
|
* This register (MODEMCR) controls the interface with the modem or data
|
|
* set, or a peripheral device emulating a modem.
|
|
*
|
|
***************************************************************************/
|
|
|
|
#define XUARTPS_MODEMCR_FCM 0x00000020U /* Flow control mode */
|
|
#define XUARTPS_MODEMCR_RTS 0x00000002U /* Request to send */
|
|
#define XUARTPS_MODEMCR_DTR 0x00000001U /* Data terminal ready */
|
|
|
|
/***************************************************************************
|
|
* Modem Status Register
|
|
*
|
|
* This register (MODEMSR) indicates the current state of the control lines
|
|
* from a modem, or another peripheral device, to the CPU. In addition, four
|
|
* bits of the modem status register provide change information. These bits
|
|
* are set to a logic 1 whenever a control input from the modem changes
|
|
* state.
|
|
*
|
|
* Note: Whenever the DCTS, DDSR, TERI, or DDCD bit is set to logic 1, a
|
|
* modem status interrupt is generated and this is reflected in the modem
|
|
* status register.
|
|
*
|
|
***************************************************************************/
|
|
|
|
#define XUARTPS_MODEMSR_FCMS 0x00000100U /* Flow control mode (FCMS) */
|
|
#define XUARTPS_MODEMSR_DCD 0x00000080U /* Complement of DCD input */
|
|
#define XUARTPS_MODEMSR_RI 0x00000040U /* Complement of RI input */
|
|
#define XUARTPS_MODEMSR_DSR 0x00000020U /* Complement of DSR input */
|
|
#define XUARTPS_MODEMSR_CTS 0x00000010U /* Complement of CTS input */
|
|
#define XUARTPS_MODEMSR_DDCD 0x00000008U /* Delta DCD indicator */
|
|
#define XUARTPS_MODEMSR_TERI 0x00000004U /* Trailing Edge Ring Indicator */
|
|
#define XUARTPS_MODEMSR_DDSR 0x00000002U /* Change of DSR */
|
|
#define XUARTPS_MODEMSR_DCTS 0x00000001U /* Change of CTS */
|
|
|
|
/***************************************************************************
|
|
* Channel Status Register
|
|
*
|
|
* The channel status register (CSR) is provided to enable the control logic
|
|
* to monitor the status of bits in the channel interrupt status register,
|
|
* even if these are masked out by the interrupt mask register.
|
|
*
|
|
***************************************************************************/
|
|
|
|
#define XUARTPS_SR_TNFUL 0x00004000U /* TX FIFO Nearly Full Status */
|
|
#define XUARTPS_SR_TTRIG 0x00002000U /* TX FIFO Trigger Status */
|
|
#define XUARTPS_SR_FLOWDEL 0x00001000U /* RX FIFO fill over flow delay */
|
|
#define XUARTPS_SR_TACTIVE 0x00000800U /* TX active */
|
|
#define XUARTPS_SR_RACTIVE 0x00000400U /* RX active */
|
|
#define XUARTPS_SR_TXFULL 0x00000010U /* TX FIFO full */
|
|
#define XUARTPS_SR_TXEMPTY 0x00000008U /* TX FIFO empty */
|
|
#define XUARTPS_SR_RXFULL 0x00000004U /* RX FIFO full */
|
|
#define XUARTPS_SR_RXEMPTY 0x00000002U /* RX FIFO empty */
|
|
#define XUARTPS_SR_RXOVR 0x00000001U /* RX FIFO fill over trigger */
|
|
|
|
/***************************************************************************
|
|
* Flow Delay Register
|
|
*
|
|
* Operation of the flow delay register (FLOWDEL) is very similar to the
|
|
* receive FIFO trigger register. An internal trigger signal activates when
|
|
* the FIFO is filled to the level set by this register. This trigger will
|
|
* not cause an interrupt, although it can be read through the channel
|
|
* status register. In hardware flow control mode, RTS is deactivated when
|
|
* the trigger becomes active. RTS only resets when the FIFO level is four
|
|
* less than the level of the flow delay trigger and the flow delay trigger
|
|
* is not activated. A value less than 4 disables the flow delay.
|
|
*
|
|
***************************************************************************/
|
|
|
|
#define XUARTPS_FLOWDEL_MASK XUARTPS_RXWM_MASK /* Valid bit mask */
|
|
|
|
/***************************************************************************
|
|
* Receiver FIFO Byte Status Register
|
|
*
|
|
* The Receiver FIFO Status register is used to have a continuous
|
|
* monitoring of the raw unmasked byte status information. The register
|
|
* contains frame, parity and break status information for the top
|
|
* four bytes in the RX FIFO.
|
|
*
|
|
* Receiver FIFO Byte Status Register Bit Definition
|
|
*
|
|
***************************************************************************/
|
|
|
|
#define XUARTPS_RXBS_BYTE3_BRKE 0x00000800U /* Byte3 Break Error */
|
|
#define XUARTPS_RXBS_BYTE3_FRME 0x00000400U /* Byte3 Frame Error */
|
|
#define XUARTPS_RXBS_BYTE3_PARE 0x00000200U /* Byte3 Parity Error */
|
|
#define XUARTPS_RXBS_BYTE2_BRKE 0x00000100U /* Byte2 Break Error */
|
|
#define XUARTPS_RXBS_BYTE2_FRME 0x00000080U /* Byte2 Frame Error */
|
|
#define XUARTPS_RXBS_BYTE2_PARE 0x00000040U /* Byte2 Parity Error */
|
|
#define XUARTPS_RXBS_BYTE1_BRKE 0x00000020U /* Byte1 Break Error */
|
|
#define XUARTPS_RXBS_BYTE1_FRME 0x00000010U /* Byte1 Frame Error */
|
|
#define XUARTPS_RXBS_BYTE1_PARE 0x00000008U /* Byte1 Parity Error */
|
|
#define XUARTPS_RXBS_BYTE0_BRKE 0x00000004U /* Byte0 Break Error */
|
|
#define XUARTPS_RXBS_BYTE0_FRME 0x00000002U /* Byte0 Frame Error */
|
|
#define XUARTPS_RXBS_BYTE0_PARE 0x00000001U /* Byte0 Parity Error */
|
|
#define XUARTPS_RXBS_MASK 0x00000007U /* 3 bit RX byte status mask */
|
|
|
|
/***************************************************************************
|
|
* Private Types
|
|
***************************************************************************/
|
|
|
|
/* UART_XLNXPS UART Configuration */
|
|
|
|
struct xlnxps_config
|
|
{
|
|
unsigned long uart; /* UART Base Address */
|
|
};
|
|
|
|
/* UART_XLNXPS UART Device Data */
|
|
|
|
struct xlnxps_data
|
|
{
|
|
uint32_t baud_rate; /* UART Baud Rate */
|
|
uint32_t uartclk; /* UART clock frequency */
|
|
uint32_t ier; /* Saved IER value */
|
|
uint8_t parity; /* 0=none, 1=odd, 2=even */
|
|
uint8_t bits; /* Number of bits (7 or 8) */
|
|
bool stopbits2; /* true: Configure with 2 stop bits instead of 1 */
|
|
};
|
|
|
|
/* UART_XLNXPS UART Port */
|
|
|
|
struct xlnxps_port_s
|
|
{
|
|
struct xlnxps_data data; /* UART Device Data */
|
|
struct xlnxps_config config; /* UART Configuration */
|
|
unsigned int irq_num; /* UART IRQ Number */
|
|
bool is_console; /* 1 if this UART is console */
|
|
};
|
|
|
|
/***************************************************************************
|
|
* Private Function Prototypes
|
|
***************************************************************************/
|
|
|
|
static void xlnxps_rxint(struct uart_dev_s *dev, bool enable);
|
|
static void xlnxps_txint(struct uart_dev_s *dev, bool enable);
|
|
static bool xlnxps_txready(struct uart_dev_s *dev);
|
|
static void xlnxps_wait_send(struct uart_dev_s *dev, int ch);
|
|
|
|
/***************************************************************************
|
|
* Private Functions
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* Name: xlnxps_irq_handler
|
|
*
|
|
* Description:
|
|
* This is the common UART interrupt handler. It should call
|
|
* uart_xmitchars or uart_recvchars to perform the appropriate data
|
|
* transfers.
|
|
*
|
|
* Input Parameters:
|
|
* irq - IRQ Number
|
|
* context - Interrupt Context
|
|
* arg - UART Device
|
|
*
|
|
* Returned Value:
|
|
* OK is always returned at present.
|
|
*
|
|
***************************************************************************/
|
|
|
|
static int xlnxps_irq_handler(int irq, void *context, void *arg)
|
|
{
|
|
struct uart_dev_s *dev = (struct uart_dev_s *)arg;
|
|
struct xlnxps_port_s *port = (struct xlnxps_port_s *)dev->priv;
|
|
struct xlnxps_config *config = &port->config;
|
|
uint32_t status;
|
|
|
|
DEBUGASSERT(dev != NULL && dev->priv != NULL);
|
|
|
|
status = getreg32(config->uart + XUARTPS_ISR_OFFSET);
|
|
putreg32(status, (config->uart + XUARTPS_ISR_OFFSET));
|
|
|
|
if (status & XUARTPS_IXR_FRAMING)
|
|
{
|
|
while (!(getreg32(config->uart + XUARTPS_SR_OFFSET) &
|
|
XUARTPS_SR_RXEMPTY))
|
|
{
|
|
if (!getreg8(config->uart + XUARTPS_FIFO_OFFSET))
|
|
{
|
|
status &= ~XUARTPS_IXR_FRAMING;
|
|
}
|
|
}
|
|
|
|
putreg32(XUARTPS_IXR_FRAMING, (config->uart + XUARTPS_ISR_OFFSET));
|
|
}
|
|
|
|
if (status & XUARTPS_IXR_TXEMPTY)
|
|
{
|
|
uart_xmitchars(dev);
|
|
}
|
|
|
|
if (status & (XUARTPS_IXR_RXOVR | XUARTPS_IXR_TOUT | XUARTPS_IXR_RXFULL))
|
|
{
|
|
while (1)
|
|
{
|
|
if ((getreg32(config->uart + XUARTPS_SR_OFFSET) &
|
|
XUARTPS_SR_RXEMPTY) == XUARTPS_SR_RXEMPTY)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
uart_recvchars(dev);
|
|
}
|
|
}
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
static int xlnxps_baudrate(struct uart_dev_s *dev)
|
|
{
|
|
struct xlnxps_port_s *port = (struct xlnxps_port_s *)dev->priv;
|
|
const struct xlnxps_config *config = &port->config;
|
|
struct xlnxps_data *data = &port->data;
|
|
uint32_t iter_baud_div; /* Iterator for available baud divisor values */
|
|
uint32_t brgr_value; /* Calculated value for baud rate generator */
|
|
uint32_t calc_baudrate; /* Calculated baud rate */
|
|
uint32_t baud_error; /* Diff between calculated and requested baud rate */
|
|
uint32_t best_brgr = 0U; /* Best value for baud rate generator */
|
|
uint8_t best_baud_div = 0U; /* Best value for baud divisor */
|
|
uint32_t best_error = 0xffffffff;
|
|
uint32_t percent_error;
|
|
uint32_t reg;
|
|
uint32_t input_clk = data->uartclk;
|
|
uint32_t temp_reg;
|
|
|
|
/* Asserts validate the input arguments */
|
|
|
|
DEBUGASSERT(data->baud_rate <= (uint32_t)XUARTPS_MAX_RATE);
|
|
DEBUGASSERT(data->baud_rate >= (uint32_t)XUARTPS_MIN_RATE);
|
|
|
|
/* Make sure the baud rate is not impossilby large.
|
|
* Fastest possible baud rate is Input Clock / 2.
|
|
*/
|
|
|
|
if ((data->baud_rate * 2) > input_clk)
|
|
{
|
|
return ERROR;
|
|
}
|
|
|
|
/* Check whether the input clock is divided by 8 */
|
|
|
|
reg = getreg32(config->uart + XUARTPS_MR_OFFSET);
|
|
|
|
if (reg & XUARTPS_MR_CLKSEL)
|
|
{
|
|
input_clk = input_clk / 8;
|
|
}
|
|
|
|
/* Determine the Baud divider. It can be 4to 254.
|
|
* Loop through all possible combinations
|
|
*/
|
|
|
|
for (iter_baud_div = 4; iter_baud_div < 255; iter_baud_div++)
|
|
{
|
|
/* Calculate the value for BRGR register */
|
|
|
|
brgr_value = input_clk / (data->baud_rate * (iter_baud_div + 1));
|
|
|
|
/* Calculate the baud rate from the BRGR value */
|
|
|
|
calc_baudrate = input_clk / (brgr_value * (iter_baud_div + 1));
|
|
|
|
/* Avoid unsigned integer underflow */
|
|
|
|
if (data->baud_rate > calc_baudrate)
|
|
{
|
|
baud_error = data->baud_rate - calc_baudrate;
|
|
}
|
|
else
|
|
{
|
|
baud_error = calc_baudrate - data->baud_rate;
|
|
}
|
|
|
|
/* Find the calculated baud rate closest to requested baud rate. */
|
|
|
|
if (best_error > baud_error)
|
|
{
|
|
best_brgr = brgr_value;
|
|
best_baud_div = iter_baud_div;
|
|
best_error = baud_error;
|
|
}
|
|
}
|
|
|
|
/* Make sure the best error is not too large. */
|
|
|
|
percent_error = (best_error * 100) / data->baud_rate;
|
|
if (XUARTPS_MAX_BAUD_ERROR_RATE < percent_error)
|
|
{
|
|
return ERROR;
|
|
}
|
|
|
|
/* Disable TX and RX to avoid glitches when setting the baud rate. */
|
|
|
|
temp_reg = (((getreg32(config->uart + XUARTPS_CR_OFFSET)) &
|
|
((uint32_t)(~XUARTPS_CR_EN_DIS_MASK))) |
|
|
((uint32_t)XUARTPS_CR_RX_DIS | (uint32_t)XUARTPS_CR_TX_DIS));
|
|
putreg32(temp_reg, config->uart + XUARTPS_CR_OFFSET);
|
|
|
|
/* Set the baud rate divisor */
|
|
|
|
putreg32(best_brgr, config->uart + XUARTPS_BAUDGEN_OFFSET);
|
|
putreg32(best_baud_div, config->uart + XUARTPS_BAUDDIV_OFFSET);
|
|
|
|
/* RX and TX SW reset */
|
|
|
|
putreg32(XUARTPS_CR_TXRST | XUARTPS_CR_RXRST,
|
|
config->uart + XUARTPS_CR_OFFSET);
|
|
|
|
/* Enable device */
|
|
|
|
temp_reg = (((getreg32(config->uart + XUARTPS_CR_OFFSET)) &
|
|
((uint32_t)(~XUARTPS_CR_EN_DIS_MASK))) |
|
|
((uint32_t)XUARTPS_CR_RX_EN | (uint32_t)XUARTPS_CR_TX_EN));
|
|
putreg32(temp_reg, config->uart + XUARTPS_CR_OFFSET);
|
|
|
|
return OK;
|
|
}
|
|
|
|
/***************************************************************************
|
|
* Name: xlnxps_setup
|
|
*
|
|
* Description:
|
|
* Configure the UART baud, bits, parity, fifos, etc. This method is
|
|
* called the first time that the serial port is opened.
|
|
*
|
|
* Input Parameters:
|
|
* dev - UART Device
|
|
*
|
|
* Returned Value:
|
|
* Zero (OK) on success; a negated errno value is returned on any failure.
|
|
*
|
|
***************************************************************************/
|
|
|
|
static int xlnxps_setup(struct uart_dev_s *dev)
|
|
{
|
|
#ifndef CONFIG_SUPPRESS_UART_CONFIG
|
|
struct xlnxps_port_s *port = (struct xlnxps_port_s *)dev->priv;
|
|
const struct xlnxps_config *config = &port->config;
|
|
struct xlnxps_data *data = &port->data;
|
|
uint32_t reg = 0U;
|
|
|
|
DEBUGASSERT(data != NULL);
|
|
|
|
if (xlnxps_baudrate(dev) != OK)
|
|
{
|
|
return ERROR;
|
|
}
|
|
|
|
/* Set the parity mode */
|
|
|
|
reg = getreg32(config->uart + XUARTPS_MR_OFFSET);
|
|
|
|
/* Mask off what's already there */
|
|
|
|
reg &= (~((uint32_t)XUARTPS_MR_CHARLEN_MASK |
|
|
(uint32_t)XUARTPS_MR_STOPMODE_MASK |
|
|
(uint32_t)XUARTPS_MR_PARITY_MASK));
|
|
|
|
switch (data->bits)
|
|
{
|
|
case 6:
|
|
reg |= (uint32_t)XUARTPS_MR_CHARLEN_6_BIT;
|
|
break;
|
|
case 7:
|
|
reg |= (uint32_t)XUARTPS_MR_CHARLEN_7_BIT;
|
|
break;
|
|
case 8:
|
|
reg |= (uint32_t)XUARTPS_MR_CHARLEN_8_BIT;
|
|
break;
|
|
default:
|
|
reg |= (uint32_t)XUARTPS_MR_CHARLEN_8_BIT;
|
|
break;
|
|
}
|
|
|
|
if (data->stopbits2)
|
|
{
|
|
reg |= (uint32_t)XUARTPS_MR_STOPMODE_2_BIT;
|
|
}
|
|
else
|
|
{
|
|
reg |= (uint32_t)XUARTPS_MR_STOPMODE_1_BIT;
|
|
}
|
|
|
|
switch (data->parity)
|
|
{
|
|
case 0:
|
|
reg |= (uint32_t)XUARTPS_MR_PARITY_NONE;
|
|
break;
|
|
case 1:
|
|
reg |= (uint32_t)XUARTPS_MR_PARITY_ODD;
|
|
break;
|
|
case 2:
|
|
reg |= (uint32_t)XUARTPS_MR_PARITY_EVEN;
|
|
break;
|
|
default:
|
|
reg |= (uint32_t)XUARTPS_MR_PARITY_NONE;
|
|
break;
|
|
}
|
|
|
|
/* Write the mode register out */
|
|
|
|
putreg32(reg, config->uart + XUARTPS_MR_OFFSET);
|
|
|
|
/* Set the RX FIFO trigger at 8 data bytes. */
|
|
|
|
putreg32(0x08, config->uart + XUARTPS_RXWM_OFFSET);
|
|
|
|
/* Set the RX timeout to 1, which will be 4 character time */
|
|
|
|
putreg32(0x01, config->uart + XUARTPS_RXTOUT_OFFSET);
|
|
|
|
/* Disable all interrupts, polled mode is the default */
|
|
|
|
putreg32(XUARTPS_IXR_MASK, config->uart + XUARTPS_IDR_OFFSET);
|
|
|
|
#endif /* CONFIG_SUPPRESS_UART_CONFIG */
|
|
return OK;
|
|
}
|
|
|
|
/***************************************************************************
|
|
* Name: xlnxps_shutdown
|
|
*
|
|
* Description:
|
|
* Disable the UART Port. This method is called when the serial
|
|
* port is closed.
|
|
*
|
|
* Input Parameters:
|
|
* dev - UART Device
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
***************************************************************************/
|
|
|
|
static void xlnxps_shutdown(struct uart_dev_s *dev)
|
|
{
|
|
/* Disable the Receive and Transmit Interrupts */
|
|
|
|
xlnxps_rxint(dev, false);
|
|
xlnxps_txint(dev, false);
|
|
}
|
|
|
|
/***************************************************************************
|
|
* Name: xlnxps_attach
|
|
*
|
|
* Description:
|
|
* Configure the UART to operation in interrupt driven mode.
|
|
* This method is called when the serial port is opened.
|
|
* Normally, this is just after the setup() method is called,
|
|
* however, the serial console may operate in
|
|
* a non-interrupt driven mode during the boot phase.
|
|
*
|
|
* RX and TX interrupts are not enabled when by the attach method
|
|
* (unless the hardware supports multiple levels of interrupt
|
|
* enabling). The RX and TX interrupts are not enabled until
|
|
* the txint() and rxint() methods are called.
|
|
*
|
|
* Input Parameters:
|
|
* dev - UART Device
|
|
*
|
|
* Returned Value:
|
|
* Zero (OK) on success; a negated errno value is returned on any failure.
|
|
*
|
|
***************************************************************************/
|
|
|
|
static int xlnxps_attach(struct uart_dev_s *dev)
|
|
{
|
|
int ret;
|
|
struct xlnxps_port_s *port = (struct xlnxps_port_s *)dev->priv;
|
|
|
|
DEBUGASSERT(port != NULL);
|
|
|
|
/* Attach UART Interrupt Handler */
|
|
|
|
ret = irq_attach(port->irq_num, xlnxps_irq_handler, dev);
|
|
|
|
/* Enable UART Interrupt */
|
|
|
|
if (ret == OK)
|
|
{
|
|
up_enable_irq(port->irq_num);
|
|
}
|
|
else
|
|
{
|
|
_err("IRQ attach failed, ret=%d\n", ret);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/***************************************************************************
|
|
* Name: xlnxps_detach
|
|
*
|
|
* Description:
|
|
* Detach UART interrupts. This method is called when the serial port is
|
|
* closed normally just before the shutdown method is called. The
|
|
* exception is the serial console which is never shutdown.
|
|
*
|
|
* Input Parameters:
|
|
* dev - UART Device
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
***************************************************************************/
|
|
|
|
static void xlnxps_detach(struct uart_dev_s *dev)
|
|
{
|
|
struct xlnxps_port_s *port = (struct xlnxps_port_s *)dev->priv;
|
|
|
|
DEBUGASSERT(port != NULL);
|
|
|
|
/* Disable UART Interrupt */
|
|
|
|
up_disable_irq(port->irq_num);
|
|
|
|
/* Detach UART Interrupt Handler */
|
|
|
|
irq_detach(port->irq_num);
|
|
}
|
|
|
|
/***************************************************************************
|
|
* Name: xlnxps_ioctl
|
|
*
|
|
* Description:
|
|
* All ioctl calls will be routed through this method.
|
|
*
|
|
* Input Parameters:
|
|
* filep - File Struct
|
|
* cmd - ioctl Command
|
|
* arg - ioctl Argument
|
|
*
|
|
* Returned Value:
|
|
* Zero (OK) on success; a negated errno value is returned on any failure.
|
|
*
|
|
***************************************************************************/
|
|
|
|
static int xlnxps_ioctl(struct file *filep, int cmd, unsigned long arg)
|
|
{
|
|
int ret = OK;
|
|
|
|
UNUSED(filep);
|
|
UNUSED(arg);
|
|
|
|
switch (cmd)
|
|
{
|
|
case TIOCSBRK: /* BSD compatibility: Turn break on, unconditionally */
|
|
case TIOCCBRK: /* BSD compatibility: Turn break off, unconditionally */
|
|
default:
|
|
{
|
|
ret = -ENOTTY;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/***************************************************************************
|
|
* Name: xlnxps_receive
|
|
*
|
|
* Description:
|
|
* Called (usually) from the interrupt level to receive one
|
|
* character from the UART. Error bits associated with the
|
|
* receipt are provided in the return 'status'.
|
|
*
|
|
* Input Parameters:
|
|
* dev - UART Device
|
|
* status - Return status, zero on success
|
|
*
|
|
* Returned Value:
|
|
* Received character
|
|
*
|
|
***************************************************************************/
|
|
|
|
static int xlnxps_receive(struct uart_dev_s *dev, unsigned int *status)
|
|
{
|
|
struct xlnxps_port_s *port = (struct xlnxps_port_s *)dev->priv;
|
|
const struct xlnxps_config *config = &port->config;
|
|
uint32_t rbr;
|
|
|
|
*status = getreg8(config->uart + XUARTPS_SR_OFFSET) & XUARTPS_SR_RXEMPTY;
|
|
|
|
/* Wait until there is data */
|
|
|
|
if (*status)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
rbr = getreg8(config->uart + XUARTPS_FIFO_OFFSET);
|
|
return rbr;
|
|
}
|
|
|
|
/***************************************************************************
|
|
* Name: xlnxps_rxint
|
|
*
|
|
* Description:
|
|
* Call to enable or disable RX interrupts
|
|
*
|
|
* Input Parameters:
|
|
* dev - UART Device
|
|
* enable - True to enable RX interrupts; false to disable
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
***************************************************************************/
|
|
|
|
static void xlnxps_rxint(struct uart_dev_s *dev, bool enable)
|
|
{
|
|
struct xlnxps_port_s *port = (struct xlnxps_port_s *)dev->priv;
|
|
struct xlnxps_config *config = &port->config;
|
|
|
|
/* Write to Interrupt Enable Register (UART_IER) */
|
|
|
|
if (enable)
|
|
{
|
|
/* Write the new value for the FIFO control register to it such that
|
|
* the threshold is changed
|
|
*/
|
|
|
|
putreg32(1, config->uart + XUARTPS_RXWM_OFFSET);
|
|
|
|
/* Set XUARTPS_IXR_RXOVR bit (Enable Rx Data Available Interrupt) */
|
|
|
|
modreg32(XUARTPS_IXR_RXOVR, XUARTPS_IXR_RXOVR,
|
|
config->uart + XUARTPS_IER_OFFSET);
|
|
|
|
modreg32(0, XUARTPS_IXR_RXOVR, config->uart + XUARTPS_IDR_OFFSET);
|
|
|
|
/* Set XUARTPS_IXR_RXFULL bit (Enable RxFifo full Interrupt) */
|
|
|
|
modreg32(XUARTPS_IXR_RXFULL, XUARTPS_IXR_RXFULL,
|
|
config->uart + XUARTPS_IER_OFFSET);
|
|
|
|
modreg32(0, XUARTPS_IXR_RXFULL, config->uart + XUARTPS_IDR_OFFSET);
|
|
}
|
|
else
|
|
{
|
|
/* Set XUARTPS_IXR_RXOVR bit (Enable Rx Data Available Interrupt) */
|
|
|
|
modreg32(0, XUARTPS_IXR_RXOVR, config->uart + XUARTPS_IER_OFFSET);
|
|
modreg32(XUARTPS_IXR_RXOVR, XUARTPS_IXR_RXOVR,
|
|
config->uart + XUARTPS_IDR_OFFSET);
|
|
|
|
/* Set XUARTPS_IXR_RXFULL bit (Enable RxFifo full Interrupt) */
|
|
|
|
modreg32(0, XUARTPS_IXR_RXFULL, config->uart + XUARTPS_IER_OFFSET);
|
|
modreg32(XUARTPS_IXR_RXFULL, XUARTPS_IXR_RXFULL,
|
|
config->uart + XUARTPS_IDR_OFFSET);
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
* Name: xlnxps_rxavailable
|
|
*
|
|
* Description:
|
|
* Return true if the Receive FIFO is not empty
|
|
*
|
|
* Input Parameters:
|
|
* dev - UART Device
|
|
*
|
|
* Returned Value:
|
|
* True if the Receive FIFO is not empty; false otherwise
|
|
*
|
|
***************************************************************************/
|
|
|
|
static bool xlnxps_rxavailable(struct uart_dev_s *dev)
|
|
{
|
|
struct xlnxps_port_s *port = (struct xlnxps_port_s *)dev->priv;
|
|
struct xlnxps_config *config = &port->config;
|
|
|
|
/* RxFifo empty bit is 1 if Rx Data is unavailable */
|
|
|
|
return ((getreg8(config->uart + XUARTPS_SR_OFFSET) &
|
|
XUARTPS_SR_RXEMPTY) == 0);
|
|
}
|
|
|
|
/***************************************************************************
|
|
* Name: xlnxps_send
|
|
*
|
|
* Description:
|
|
* This method will send one byte on the UART
|
|
*
|
|
* Input Parameters:
|
|
* dev - UART Device
|
|
* ch - Character to be sent
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
***************************************************************************/
|
|
|
|
static void xlnxps_send(struct uart_dev_s *dev, int ch)
|
|
{
|
|
struct xlnxps_port_s *port = (struct xlnxps_port_s *)dev->priv;
|
|
struct xlnxps_config *config = &port->config;
|
|
|
|
/* Write char to Transmit FIFO Register */
|
|
|
|
putreg8(ch, config->uart + XUARTPS_FIFO_OFFSET);
|
|
}
|
|
|
|
/***************************************************************************
|
|
* Name: xlnxps_sendbuf
|
|
*
|
|
* Description:
|
|
* This method will send a buffer of bytes on the UART
|
|
*
|
|
***************************************************************************/
|
|
|
|
static ssize_t xlnxps_sendbuf(struct uart_dev_s *dev,
|
|
const void *buffer, size_t size)
|
|
{
|
|
for (size_t i = 0; i < size; i++)
|
|
{
|
|
while (!xlnxps_txready(dev));
|
|
xlnxps_send(dev, ((const unsigned char *)buffer)[i]);
|
|
}
|
|
|
|
return (ssize_t)size;
|
|
}
|
|
|
|
/***************************************************************************
|
|
* Name: xlnxps_txint
|
|
*
|
|
* Description:
|
|
* Call to enable or disable TX interrupts
|
|
*
|
|
* Input Parameters:
|
|
* dev - UART Device
|
|
* enable - True to enable TX interrupts; false to disable
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
***************************************************************************/
|
|
|
|
static void xlnxps_txint(struct uart_dev_s *dev, bool enable)
|
|
{
|
|
struct xlnxps_port_s *port = (struct xlnxps_port_s *)dev->priv;
|
|
struct xlnxps_config *config = &port->config;
|
|
irqstate_t flags;
|
|
|
|
/* Write to Interrupt Enable Register (UART_IER) */
|
|
|
|
if (enable)
|
|
{
|
|
#ifdef CONFIG_UART_XLNXPS_POLLING
|
|
/* In polling mode, we loop until the buffer is empty */
|
|
|
|
uart_xmitchars(dev);
|
|
#else
|
|
flags = enter_critical_section();
|
|
|
|
/* Set XUARTPS_IXR_TXEMPTY bit (Enable Tx Fifo Empty Interrupt) */
|
|
|
|
modreg32(XUARTPS_IXR_TXEMPTY, XUARTPS_IXR_TXEMPTY,
|
|
config->uart + XUARTPS_IER_OFFSET);
|
|
|
|
modreg32(0, XUARTPS_IXR_TXEMPTY, config->uart + XUARTPS_IDR_OFFSET);
|
|
leave_critical_section(flags);
|
|
|
|
/* Fake a TX interrupt */
|
|
|
|
uart_xmitchars(dev);
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
flags = enter_critical_section();
|
|
|
|
/* Clear XUARTPS_IXR_TXEMPTY bit (Disable Tx Fifo Empty Interrupt) */
|
|
|
|
modreg32(0, XUARTPS_IXR_TXEMPTY, config->uart + XUARTPS_IER_OFFSET);
|
|
modreg32(XUARTPS_IXR_TXEMPTY, XUARTPS_IXR_TXEMPTY,
|
|
config->uart + XUARTPS_IDR_OFFSET);
|
|
leave_critical_section(flags);
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
* Name: xlnxps_txready
|
|
*
|
|
* Description:
|
|
* Return true if the Transmit FIFO is not full
|
|
*
|
|
* Input Parameters:
|
|
* dev - UART Device
|
|
*
|
|
* Returned Value:
|
|
* True if the Transmit FIFO is not full; false otherwise
|
|
*
|
|
***************************************************************************/
|
|
|
|
static bool xlnxps_txready(struct uart_dev_s *dev)
|
|
{
|
|
struct xlnxps_port_s *port = (struct xlnxps_port_s *)dev->priv;
|
|
struct xlnxps_config *config = &port->config;
|
|
|
|
/* Tx FIFO is ready if THRE Bit is 1 (Tx Holding Register Empty) */
|
|
|
|
return (getreg8(config->uart + XUARTPS_SR_OFFSET)
|
|
& XUARTPS_SR_TXFULL) == 0;
|
|
}
|
|
|
|
/***************************************************************************
|
|
* Name: xlnxps_txempty
|
|
*
|
|
* Description:
|
|
* Return true if the Transmit FIFO is empty
|
|
*
|
|
* Input Parameters:
|
|
* dev - UART Device
|
|
*
|
|
* Returned Value:
|
|
* True if the Transmit FIFO is empty; false otherwise
|
|
*
|
|
***************************************************************************/
|
|
|
|
static bool xlnxps_txempty(struct uart_dev_s *dev)
|
|
{
|
|
/* Tx FIFO is empty if Tx FIFO is not full (for now) */
|
|
|
|
return xlnxps_txready(dev);
|
|
}
|
|
|
|
/***************************************************************************
|
|
* Name: xlnxps_wait_send
|
|
*
|
|
* Description:
|
|
* Wait for Transmit FIFO until it is not full, then transmit the
|
|
* character over UART.
|
|
*
|
|
* Input Parameters:
|
|
* dev - UART Device
|
|
* ch - Character to be sent
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
***************************************************************************/
|
|
|
|
static void xlnxps_wait_send(struct uart_dev_s *dev, int ch)
|
|
{
|
|
DEBUGASSERT(dev != NULL);
|
|
while (!xlnxps_txready(dev));
|
|
xlnxps_send(dev, ch);
|
|
}
|
|
|
|
/***************************************************************************
|
|
* Private Data
|
|
***************************************************************************/
|
|
|
|
/* UART Operations for Serial Driver */
|
|
|
|
static const struct uart_ops_s g_uart_ops =
|
|
{
|
|
.setup = xlnxps_setup,
|
|
.shutdown = xlnxps_shutdown,
|
|
.attach = xlnxps_attach,
|
|
.detach = xlnxps_detach,
|
|
.ioctl = xlnxps_ioctl,
|
|
.receive = xlnxps_receive,
|
|
.rxint = xlnxps_rxint,
|
|
.rxavailable = xlnxps_rxavailable,
|
|
#ifdef CONFIG_SERIAL_IFLOWCONTROL
|
|
.rxflowcontrol = NULL,
|
|
#endif
|
|
.send = xlnxps_send,
|
|
.txint = xlnxps_txint,
|
|
.txready = xlnxps_txready,
|
|
.txempty = xlnxps_txempty,
|
|
.sendbuf = xlnxps_sendbuf,
|
|
};
|
|
|
|
#ifdef CONFIG_UART_XLNXPS0
|
|
|
|
/* UART0 Port State (Console) */
|
|
|
|
static struct xlnxps_port_s g_uart0priv =
|
|
{
|
|
.data =
|
|
{
|
|
.baud_rate = CONFIG_UART_XLNXPS0_BAUD,
|
|
.uartclk = CONFIG_UART_XLNXPS0_CLOCK,
|
|
.parity = CONFIG_UART_XLNXPS0_PARITY,
|
|
.bits = CONFIG_UART_XLNXPS0_BITS,
|
|
.stopbits2 = CONFIG_UART_XLNXPS0_2STOP
|
|
},
|
|
|
|
.config =
|
|
{
|
|
.uart = CONFIG_UART_XLNXPS0_BASE
|
|
},
|
|
|
|
.irq_num = CONFIG_UART_XLNXPS0_IRQ,
|
|
.is_console = 1
|
|
};
|
|
|
|
/* UART0 I/O Buffers (Console) */
|
|
|
|
static char g_uart0rxbuffer[CONFIG_UART_XLNXPS0_RXBUFSIZE];
|
|
static char g_uart0txbuffer[CONFIG_UART_XLNXPS0_TXBUFSIZE];
|
|
|
|
/* UART0 Port Definition (Console) */
|
|
|
|
static struct uart_dev_s g_uart0port =
|
|
{
|
|
.recv =
|
|
{
|
|
.size = CONFIG_UART_XLNXPS0_RXBUFSIZE,
|
|
.buffer = g_uart0rxbuffer,
|
|
},
|
|
|
|
.xmit =
|
|
{
|
|
.size = CONFIG_UART_XLNXPS0_TXBUFSIZE,
|
|
.buffer = g_uart0txbuffer,
|
|
},
|
|
|
|
.ops = &g_uart_ops,
|
|
.priv = &g_uart0priv,
|
|
};
|
|
|
|
#endif /* CONFIG_UART_XLNXPS_UART */
|
|
|
|
/***************************************************************************
|
|
* Public Functions
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
* Name: arm64_earlyserialinit
|
|
*
|
|
* Description:
|
|
* Performs the low level UART initialization early in
|
|
* debug so that the serial console will be available
|
|
* during boot up. This must be called before arm64_serialinit.
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
***************************************************************************/
|
|
|
|
void xlnxps_earlyserialinit(void)
|
|
{
|
|
int ret;
|
|
|
|
/* NOTE: This function assumes that UART0 low level hardware configuration
|
|
* -- including all clocking and pin configuration
|
|
*/
|
|
|
|
#ifdef CONSOLE_DEV
|
|
/* Enable the console at UART0 */
|
|
|
|
CONSOLE_DEV.isconsole = true;
|
|
xlnxps_setup(&CONSOLE_DEV);
|
|
#endif
|
|
|
|
UNUSED(ret);
|
|
}
|
|
|
|
/***************************************************************************
|
|
* Name: up_putc
|
|
*
|
|
* Description:
|
|
* Provide priority, low-level access to support OS debug
|
|
* writes
|
|
*
|
|
* Input Parameters:
|
|
* ch - Character to be transmitted over UART
|
|
*
|
|
* Returned Value:
|
|
* Character that was transmitted
|
|
*
|
|
***************************************************************************/
|
|
|
|
void up_putc(int ch)
|
|
{
|
|
#ifdef CONSOLE_DEV
|
|
struct uart_dev_s *dev = &CONSOLE_DEV;
|
|
|
|
xlnxps_wait_send(dev, ch);
|
|
#endif
|
|
}
|
|
|
|
/***************************************************************************
|
|
* Name: arm64_serialinit
|
|
*
|
|
* Description:
|
|
* Register serial console and serial ports. This assumes
|
|
* that zynq_earlyserialinit was called previously.
|
|
*
|
|
* Returned Value:
|
|
* None
|
|
*
|
|
***************************************************************************/
|
|
|
|
void xlnxps_serialinit(void)
|
|
{
|
|
#ifdef CONSOLE_DEV
|
|
int ret;
|
|
|
|
ret = uart_register("/dev/console", &CONSOLE_DEV);
|
|
if (ret < 0)
|
|
{
|
|
_err("Register /dev/console failed, ret=%d\n", ret);
|
|
}
|
|
|
|
ret = uart_register("/dev/ttyS0", &TTYS0_DEV);
|
|
|
|
if (ret < 0)
|
|
{
|
|
_err("Register /dev/ttyS0 failed, ret=%d\n", ret);
|
|
}
|
|
|
|
#ifdef TTYS1_DEV
|
|
ret = uart_register("/dev/ttyS1", &TTYS1_DEV);
|
|
|
|
if (ret < 0)
|
|
{
|
|
_err("Register /dev/ttyS1 failed, ret=%d\n", ret);
|
|
}
|
|
#endif /* TTYS1_DEV */
|
|
|
|
#endif
|
|
}
|
|
|
|
#endif /* CONFIG_UART_XLNXPS */
|