This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit cfd177198116d1e5456a842ae971ad678d13ee10
Author: chao an <[email protected]>
AuthorDate: Thu Feb 26 16:25:38 2026 +0800

    serial/xlnx_ps: add common Xilinx UART Peripheral System (XUARTPS) support
    
    This PR adds complete driver support for the Xilinx UART Peripheral System 
(XUARTPS)
    in the NuttX serial driver framework. The implementation includes the core 
driver code
    (uart_xlnx_ps.c), configuration files (Kconfig-xlnxps), header definitions 
(uart_xlnx_ps.h),
    and integration with the existing NuttX build system (CMakeLists.txt, 
Make.defs, Kconfig).
    
    The driver supports UART0 configuration with customizable parameters (base 
address,
    clock frequency, IRQ number, baud rate, parity, data bits, stop bits), 
RX/TX buffer sizing,
    hardware flow control (RTS/CTS), interrupt-driven data transfer, and 
console mapping for XUARTPS UART0.
    It also provides standard serial driver operations (setup, shutdown, 
attach/detach, ioctl, send/receive)
    and early serial initialization for boot-time console access.
    
    Signed-off-by: chao an <[email protected]>
---
 drivers/serial/CMakeLists.txt       |    4 +
 drivers/serial/Kconfig              |    8 +
 drivers/serial/Kconfig-xlnxps       |  128 ++++
 drivers/serial/Make.defs            |    4 +
 drivers/serial/uart_xlnx_ps.c       | 1281 +++++++++++++++++++++++++++++++++++
 include/nuttx/serial/uart_xlnx_ps.h |   48 ++
 6 files changed, 1473 insertions(+)

diff --git a/drivers/serial/CMakeLists.txt b/drivers/serial/CMakeLists.txt
index 74f9f9d6415..ba039446bf3 100644
--- a/drivers/serial/CMakeLists.txt
+++ b/drivers/serial/CMakeLists.txt
@@ -46,6 +46,10 @@ if(CONFIG_UART_PL011)
   list(APPEND SRCS uart_pl011.c)
 endif()
 
+if(CONFIG_UART_XLNXPS)
+  list(APPEND SRCS uart_xlnx_ps.c)
+endif()
+
 if(CONFIG_RPMSG_UART)
   list(APPEND SRCS uart_rpmsg.c)
 endif()
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index def241f7934..84090d53a2b 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -114,6 +114,14 @@ if UART_PL011
 source "drivers/serial/Kconfig-pl011"
 endif
 
+menuconfig UART_XLNXPS
+       bool "Xilinx UART Peripheral System (XUARTPS) Chip support"
+       default n
+
+if UART_XLNXPS
+source "drivers/serial/Kconfig-xlnxps"
+endif # UART_XLNXPS
+
 menuconfig CMSDK_UART
        bool "CMSDK UART Chip support"
        select ARCH_HAVE_SERIAL_TERMIOS
diff --git a/drivers/serial/Kconfig-xlnxps b/drivers/serial/Kconfig-xlnxps
new file mode 100644
index 00000000000..3de1f212ce6
--- /dev/null
+++ b/drivers/serial/Kconfig-xlnxps
@@ -0,0 +1,128 @@
+#
+# For a description of the syntax of this configuration file,
+# see the file kconfig-language.txt in the NuttX tools repository.
+#
+
+if UART_XLNXPS
+
+config XLNXPS_SERIAL_DISABLE_REORDERING
+       bool "Disable reordering of ttySx devices."
+       default n
+       ---help---
+               NuttX per default reorders the serial ports (/dev/ttySx) so 
that the
+               console is always on /dev/ttyS0. If more than one UART is in 
use this
+               can, however, have the side-effect that all port mappings
+               (hardware USART1 -> /dev/ttyS0) change if the console is moved 
to another
+               UART.  This option disables that re-ordering for XLNXPS UARTs.
+
+config UART_XLNXPS0
+       bool "XLNXPS UART0"
+       default n
+
+if UART_XLNXPS0
+
+config UART_XLNXPS0_BASE
+       hex "XLNXPS UART0 base address"
+       default 0x0
+
+config UART_XLNXPS0_CLOCK
+       int "XLNXPS UART0 clock"
+       default 0
+
+config UART_XLNXPS0_IRQ
+       int "XLNXPS UART0 IRQ number"
+       default 0
+
+config UART_XLNXPS0_BAUD
+       int "XLNXPS UART0 BAUD"
+       default 115200
+
+config UART_XLNXPS0_PARITY
+       int "XLNXPS UART0 parity"
+       default 0
+       range 0 2
+       ---help---
+               XLNXPS UART0 parity.  0=None, 1=Odd, 2=Even.  Default: None
+
+config UART_XLNXPS0_BITS
+       int "XLNXPS UART0 number of bits"
+       default 8
+       ---help---
+               XLNXPS UART0 number of bits.  Default: 8
+
+config UART_XLNXPS0_2STOP
+       int "XLNXPS UART0 two stop bits"
+       default 0
+       ---help---
+               0=1 stop bit, 1=Two stop bits.  Default: 1 stop bit
+
+config UART_XLNXPS0_RX_TRIGGER
+  int "XLNXPS UART0 RX interrupt trigger level"
+       default 2
+       range 0 3
+
+config UART_XLNXPS0_RXBUFSIZE
+       int "XLNXPS UART0 Rx buffer size"
+       default 256
+       ---help---
+               XLNXPS UART0 Rx buffer size.  Default: 256
+
+config UART_XLNXPS0_TXBUFSIZE
+       int "XLNXPS UART0 Tx buffer size"
+       default 256
+       ---help---
+               XLNXPS UART0 Tx buffer size.  Default: 256
+
+config UART_XLNXPS0_IFLOWCONTROL
+       bool "XLNXPS UART0 RTS flow control"
+       default n
+       select SERIAL_IFLOWCONTROL
+       ---help---
+               Enable XLNXPS UART0 RTS flow control
+
+config UART_XLNXPS0_OFLOWCONTROL
+       bool "XLNXPS UART0 CTS flow control"
+       default n
+       select SERIAL_OFLOWCONTROL
+       ---help---
+               Enable XLNXPS UART0 CTS flow control
+
+endif # UART_XLNXPS0
+
+choice
+       prompt "XLNXPS Serial Console"
+       default XLNXPS_NO_SERIAL_CONSOLE
+       depends on DEV_CONSOLE
+
+config UART_XLNXPS0_SERIAL_CONSOLE
+       bool "XLNXPS UART0 serial console"
+       depends on UART_XLNXPS0
+       select SERIAL_CONSOLE
+
+config XLNXPS_NO_SERIAL_CONSOLE
+       bool "No XLNXPS serial console"
+
+endchoice # XLNXPS Serial Console
+
+config XLNXPS_SUPRESS_CONFIG
+       bool "Suppress XLNXPS configuration"
+       default n
+
+config XLNXPS_SUPRESS_INITIAL_CONFIG
+       bool "Suppress initial XLNXPS configuration"
+       depends on !XLNXPS_SUPRESS_CONFIG
+       default n
+       ---help---
+               This option is useful, for example, if you are using a 
bootloader
+               that configures the UART_XLNXPS.  In that case, you may want to
+               just leave the existing console configuration in place.  
Default: n
+
+config SERIAL_UART_ARCH_MMIO
+       bool "Platform access register through the memory mapping"
+       default n
+
+config SERIAL_UART_ARCH_IOCTL
+       bool "Platform has own custom IOCTL"
+       default n
+
+endif # UART_XLNXPS
diff --git a/drivers/serial/Make.defs b/drivers/serial/Make.defs
index b9ca98dbff8..22845e16959 100644
--- a/drivers/serial/Make.defs
+++ b/drivers/serial/Make.defs
@@ -58,6 +58,10 @@ ifeq ($(CONFIG_UART_HOSTFS),y)
   CSRCS += uart_hostfs.c
 endif
 
+ifeq ($(CONFIG_UART_XLNXPS),y)
+  CSRCS += uart_xlnx_ps.c
+endif
+
 # Pseudo-terminal support
 
 ifeq ($(CONFIG_PSEUDOTERM),y)
diff --git a/drivers/serial/uart_xlnx_ps.c b/drivers/serial/uart_xlnx_ps.c
new file mode 100644
index 00000000000..6257d36ba4f
--- /dev/null
+++ b/drivers/serial/uart_xlnx_ps.c
@@ -0,0 +1,1281 @@
+/***************************************************************************
+ * 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 <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);
+
+/***************************************************************************
+ * 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_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;
+
+  flags = enter_critical_section();
+
+  /* Write to Interrupt Enable Register (UART_IER) */
+
+  if (enable)
+    {
+      /* 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);
+
+      /* Fake a TX interrupt */
+
+      uart_xmitchars(dev);
+    }
+  else
+    {
+      /* 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,
+};
+
+#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 */
diff --git a/include/nuttx/serial/uart_xlnx_ps.h 
b/include/nuttx/serial/uart_xlnx_ps.h
new file mode 100644
index 00000000000..07a620db4e6
--- /dev/null
+++ b/include/nuttx/serial/uart_xlnx_ps.h
@@ -0,0 +1,48 @@
+/****************************************************************************
+ * include/nuttx/serial/uart_xlnx_ps.h
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#ifndef __INCLUDE_NUTTX_SERIAL_UART_XLNXPS_H
+#define __INCLUDE_NUTTX_SERIAL_UART_XLNXPS_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#ifdef CONFIG_UART_XLNXPS
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Public Functions Prototypes
+ ****************************************************************************/
+
+void xlnxps_earlyserialinit(void);
+
+void xlnxps_serialinit(void);
+
+#endif  /* CONFIG_UART_XLNXPS */
+
+#endif /* __INCLUDE_NUTTX_SERIAL_UART_XLNXPS_H */

Reply via email to