You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2024/04/16 16:10:16 UTC
(nuttx) branch master updated: arch/arm64/src/imx9: Add a more capable uart driver
This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 58f0ee6364 arch/arm64/src/imx9: Add a more capable uart driver
58f0ee6364 is described below
commit 58f0ee63645d936e44d0c9958f9717b15c86aa48
Author: Jukka Laitinen <ju...@ssrc.tii.ae>
AuthorDate: Tue Apr 16 15:44:30 2024 +0300
arch/arm64/src/imx9: Add a more capable uart driver
Add an uart driver supporting LPUART1-8, dma, flow control, tc etc.
Signed-off-by: Jukka Laitinen <ju...@ssrc.tii.ae>
---
arch/arm64/src/imx9/Kconfig | 85 +-
arch/arm64/src/imx9/Make.defs | 5 +-
arch/arm64/src/imx9/hardware/imx9_lpuart.h | 403 ++-
arch/arm64/src/imx9/imx9_boot.c | 7 +
arch/arm64/src/imx9/imx9_lowputc.c | 532 ++++
.../src/imx9/{imx93_lowputc.S => imx9_lowputc.h} | 97 +-
arch/arm64/src/imx9/imx9_lpuart.c | 3121 ++++++++++++++++----
arch/arm64/src/imx9/imx9_serial.h | 228 +-
boards/arm64/imx9/imx93-evk/configs/nsh/defconfig | 4 +-
boards/arm64/imx9/imx93-evk/include/board.h | 7 +
10 files changed, 3641 insertions(+), 848 deletions(-)
diff --git a/arch/arm64/src/imx9/Kconfig b/arch/arm64/src/imx9/Kconfig
index 9368c961c1..7673dc6356 100644
--- a/arch/arm64/src/imx9/Kconfig
+++ b/arch/arm64/src/imx9/Kconfig
@@ -28,10 +28,89 @@ config IMX9_FLEXIO_PWM
default n
menu "i.MX9 Peripheral Selection"
-config IMX9_UART1
- bool "UART1"
+
+menu "LPUART"
+
+config IMX9_LPUART
+ bool
+ default n
+ select ARCH_HAVE_SERIAL_TERMIOS
+
+config IMX9_LPUART1
+ bool "LPUART1"
+ default n
+ select IMX9_LPUART
+ select LPUART1_SERIALDRIVER
+
+config IMX9_LPUART2
+ bool "LPUART2"
+ default n
+ select IMX9_LPUART
+ select LPUART2_SERIALDRIVER
+
+config IMX9_LPUART3
+ bool "LPUART3"
+ default n
+ select IMX9_LPUART
+ select LPUART3_SERIALDRIVER
+
+config IMX9_LPUART4
+ bool "LPUART4"
+ default n
+ select IMX9_LPUART
+ select LPUART4_SERIALDRIVER
+
+config IMX9_LPUART5
+ bool "LPUART5"
+ default n
+ select IMX9_LPUART
+ select LPUART5_SERIALDRIVER
+
+config IMX9_LPUART6
+ bool "LPUART6"
default n
- select UART1_SERIALDRIVER
+ select IMX9_LPUART
+ select LPUART6_SERIALDRIVER
+
+config IMX9_LPUART7
+ bool "LPUART7"
+ default n
+ select IMX9_LPUART
+ select LPUART7_SERIALDRIVER
+
+config IMX9_LPUART8
+ bool "LPUART8"
+ default n
+ select IMX9_LPUART
+ select LPUART8_SERIALDRIVER
+
+menu "LPUART Configuration"
+ depends on IMX9_LPUART
+
+config IMX9_LPUART_INVERT
+ bool "Signal Invert Support"
+ default n
+
+config IMX9_LPUART_SINGLEWIRE
+ bool "Signal Wire Support"
+ default n
+
+config IMX9_SERIAL_RXDMA_BUFFER_SIZE
+ int "RX DMA buffer size"
+ default 64
+ depends on LPUART1_RXDMA || LPUART2_RXDMA || LPUART3_RXDMA || LPUART4_RXDMA || \
+ LPUART5_RXDMA || LPUART6_RXDMA || LPUART7_RXDMA || LPUART8_RXDMA
+ ---help---
+ The DMA buffer size when using RX DMA to emulate a FIFO.
+
+ When streaming data, the generic serial layer will be called
+ every time the FIFO receives half this number of bytes.
+
+ Value given here will be rounded up to next multiple of 64 bytes.
+
+endmenu # LPUART Configuration
+
+endmenu # LPUART
config IMX9_FLEXIO1_PWM
depends on PWM
diff --git a/arch/arm64/src/imx9/Make.defs b/arch/arm64/src/imx9/Make.defs
index 27a19cb357..5e11a38b59 100644
--- a/arch/arm64/src/imx9/Make.defs
+++ b/arch/arm64/src/imx9/Make.defs
@@ -25,10 +25,7 @@ include common/Make.defs
CHIP_CSRCS = imx9_boot.c imx9_ccm.c imx9_clockconfig.c imx9_gpio.c imx9_iomuxc.c
ifeq ($(CONFIG_ARCH_CHIP_IMX93),y)
- CHIP_CSRCS += imx9_lpuart.c
- ifeq ($(CONFIG_ARCH_EARLY_PRINT),y)
- CHIP_ASRCS = imx93_lowputc.S
- endif
+ CHIP_CSRCS += imx9_lpuart.c imx9_lowputc.c
endif
ifeq ($(CONFIG_IMX9_GPIO_IRQ),y)
diff --git a/arch/arm64/src/imx9/hardware/imx9_lpuart.h b/arch/arm64/src/imx9/hardware/imx9_lpuart.h
index 3925c51bc6..c688d5966a 100644
--- a/arch/arm64/src/imx9/hardware/imx9_lpuart.h
+++ b/arch/arm64/src/imx9/hardware/imx9_lpuart.h
@@ -25,134 +25,289 @@
* Included Files
****************************************************************************/
-#include <nuttx/config.h>
+#include <hardware/imx9_memorymap.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
-/* 32-bit register definition */
-
-#define UARTVERID 0x0000 /* Version ID Register */
-#define UARTPARAM 0x0004 /* Parameter Register */
-#define UARTGLOBAL 0x0008 /* LPUART Global Register */
-#define UARTPINCFG 0x000c /* LPUART Pin Configuration Register */
-#define UARTBAUD 0x0010 /* LPUART Baud Rate Register */
-#define UARTSTAT 0x0014 /* LPUART Status Register */
-#define UARTCTRL 0x0018 /* LPUART Control Register */
-#define UARTDATA 0x001c /* LPUART Data Register */
-#define UARTMATCH 0x0020 /* LPUART Match Address Register */
-#define UARTMODIR 0x0024 /* LPUART Modem IrDA Register */
-#define UARTFIFO 0x0028 /* LPUART FIFO Register */
-#define UARTWATER 0x002c /* LPUART Watermark Register */
-
-#define UARTBAUD_MAEN1 0x80000000
-#define UARTBAUD_MAEN2 0x40000000
-#define UARTBAUD_M10 0x20000000
-#define UARTBAUD_TDMAE 0x00800000
-#define UARTBAUD_RDMAE 0x00200000
-#define UARTBAUD_RIDMAE 0x00100000
-#define UARTBAUD_MATCFG 0x00400000
-#define UARTBAUD_BOTHEDGE 0x00020000
-#define UARTBAUD_RESYNCDIS 0x00010000
-#define UARTBAUD_LBKDIE 0x00008000
-#define UARTBAUD_RXEDGIE 0x00004000
-#define UARTBAUD_SBNS 0x00002000
-#define UARTBAUD_SBR 0x00000000
-#define UARTBAUD_SBR_MASK 0x1fff
-#define UARTBAUD_OSR_MASK 0x1f
-#define UARTBAUD_OSR_SHIFT 24
-
-#define UARTSTAT_LBKDIF 0x80000000
-#define UARTSTAT_RXEDGIF 0x40000000
-#define UARTSTAT_MSBF 0x20000000
-#define UARTSTAT_RXINV 0x10000000
-#define UARTSTAT_RWUID 0x08000000
-#define UARTSTAT_BRK13 0x04000000
-#define UARTSTAT_LBKDE 0x02000000
-#define UARTSTAT_RAF 0x01000000
-#define UARTSTAT_TDRE 0x00800000
-#define UARTSTAT_TC 0x00400000
-#define UARTSTAT_RDRF 0x00200000
-#define UARTSTAT_IDLE 0x00100000
-#define UARTSTAT_OR 0x00080000
-#define UARTSTAT_NF 0x00040000
-#define UARTSTAT_FE 0x00020000
-#define UARTSTAT_PE 0x00010000
-#define UARTSTAT_MA1F 0x00008000
-#define UARTSTAT_M21F 0x00004000
-
-#define UARTCTRL_R8T9 0x80000000
-#define UARTCTRL_R9T8 0x40000000
-#define UARTCTRL_TXDIR 0x20000000
-#define UARTCTRL_TXINV 0x10000000
-#define UARTCTRL_ORIE 0x08000000
-#define UARTCTRL_NEIE 0x04000000
-#define UARTCTRL_FEIE 0x02000000
-#define UARTCTRL_PEIE 0x01000000
-#define UARTCTRL_TIE 0x00800000
-#define UARTCTRL_TCIE 0x00400000
-#define UARTCTRL_RIE 0x00200000
-#define UARTCTRL_ILIE 0x00100000
-#define UARTCTRL_TE 0x00080000
-#define UARTCTRL_RE 0x00040000
-#define UARTCTRL_RWU 0x00020000
-#define UARTCTRL_SBK 0x00010000
-#define UARTCTRL_MA1IE 0x00008000
-#define UARTCTRL_MA2IE 0x00004000
-#define UARTCTRL_IDLECFG_OFF 0x8
-#define UARTCTRL_LOOPS 0x00000080
-#define UARTCTRL_DOZEEN 0x00000040
-#define UARTCTRL_RSRC 0x00000020
-#define UARTCTRL_M 0x00000010
-#define UARTCTRL_WAKE 0x00000008
-#define UARTCTRL_ILT 0x00000004
-#define UARTCTRL_PE 0x00000002
-#define UARTCTRL_PT 0x00000001
-
-#define UARTDATA_NOISY 0x00008000
-#define UARTDATA_PARITYE 0x00004000
-#define UARTDATA_FRETSC 0x00002000
-#define UARTDATA_RXEMPT 0x00001000
-#define UARTDATA_IDLINE 0x00000800
-#define UARTDATA_MASK 0x3ff
-
-#define UARTMODIR_IREN 0x00020000
-#define UARTMODIR_RTSWATER_S 0x8
-#define UARTMODIR_TXCTSSRC 0x00000020
-#define UARTMODIR_TXCTSC 0x00000010
-#define UARTMODIR_RXRTSE 0x00000008
-#define UARTMODIR_TXRTSPOL 0x00000004
-#define UARTMODIR_TXRTSE 0x00000002
-#define UARTMODIR_TXCTSE 0x00000001
-
-#define UARTFIFO_TXEMPT 0x00800000
-#define UARTFIFO_RXEMPT 0x00400000
-#define UARTFIFO_TXOF 0x00020000
-#define UARTFIFO_RXUF 0x00010000
-#define UARTFIFO_TXFLUSH 0x00008000
-#define UARTFIFO_RXFLUSH 0x00004000
-#define UARTFIFO_RXIDEN_MASK 0x7
-#define UARTFIFO_RXIDEN_OFF 10
-#define UARTFIFO_TXOFE 0x00000200
-#define UARTFIFO_RXUFE 0x00000100
-#define UARTFIFO_TXFE 0x00000080
-#define UARTFIFO_FIFOSIZE_MASK 0x7
-#define UARTFIFO_TXSIZE_OFF 4
-#define UARTFIFO_RXFE 0x00000008
-#define UARTFIFO_RXSIZE_OFF 0
-#define UARTFIFO_DEPTH(x) (0x1 << ((x) ? ((x) + 1) : 0))
-
-#define UARTWATER_COUNT_MASK 0xff
-#define UARTWATER_TXCNT_OFF 8
-#define UARTWATER_RXCNT_OFF 24
-#define UARTWATER_WATER_MASK 0xff
-#define UARTWATER_TXWATER_OFF 0
-#define UARTWATER_RXWATER_OFF 16
-
-#define UARTGLOBAL_RST 0x2
-
-#define UARTFIFO_RXIDEN_RDRF 0x3
-#define UARTCTRL_IDLECFG 0x7
+/* LPUART Register Offsets **************************************************/
+
+#define IMX9_LPUART_VERID_OFFSET (0x00) /* Version ID Register (VERID) */
+#define IMX9_LPUART_PARAM_OFFSET (0x04) /* Parameter Register (PARAM) */
+#define IMX9_LPUART_GLOBAL_OFFSET (0x08) /* LPUART Global Register (GLOBAL) */
+#define IMX9_LPUART_PINCFG_OFFSET (0x0c) /* LPUART Pin Configuration Register (PINCFG) */
+#define IMX9_LPUART_BAUD_OFFSET (0x10) /* LPUART Baud Rate Register (BAUD) */
+#define IMX9_LPUART_STAT_OFFSET (0x14) /* LPUART Status Register (STAT) */
+#define IMX9_LPUART_CTRL_OFFSET (0x18) /* LPUART Control Register (CTRL) */
+#define IMX9_LPUART_DATA_OFFSET (0x1c) /* LPUART Data Register (DATA) */
+#define IMX9_LPUART_MATCH_OFFSET (0x20) /* LPUART Match Address Register (MATCH) */
+#define IMX9_LPUART_MODIR_OFFSET (0x24) /* LPUART Modem IrDA Register (MODIR) */
+#define IMX9_LPUART_FIFO_OFFSET (0x28) /* LPUART FIFO Register (FIFO) */
+#define IMX9_LPUART_WATER_OFFSET (0x2c) /* LPUART Watermark Register (WATER) */
+#define IMX9_LPUART_DATARO_OFFSET (0x30) /* Data read-only Register (DATARO) */
+
+/* Register bit definitions *************************************************/
+
+/* Version ID Register (VERID) */
+
+#define LPUART_VERID_FEATURE_SHIFT (0) /* Bits 0-15: Feature Identification Number (FEATURE) */
+#define LPUART_VERID_FEATURE_MASK (0xffff << LPUART_VERID_FEATURE_SHIFT)
+# define LPUART_VERID_FEATURE_STD (1 << LPUART_VERID_FEATURE_SHIFT) /* Standard feature set */
+# define LPUART_VERID_FEATURE_MODEM (3 << LPUART_VERID_FEATURE_SHIFT) /* MODEM/IrDA support */
+
+#define LPUART_VERID_MINOR_SHIFT (16) /* Bits 16-23: Minor Version Number (MINOR) */
+#define LPUART_VERID_MINOR_MASK (0xff << LPUART_VERID_MINOR_SHIFT)
+#define LPUART_VERID_MAJOR_SHIFT (24) /* Bits 24-31: Major Version Number (MAJOR) */
+#define LPUART_VERID_MAJOR_MASK (0xff << LPUART_VERID_MAJOR_SHIFT)
+
+/* Parameter Register (PARAM) */
+
+#define LPUART_PARAM_TXFIFO_SHIFT (0) /* Bits 0-7: Transmit FIFO Size (TXFIFO) */
+#define LPUART_PARAM_TXFIFO_MASK (0xff << LPUART_PARAM_TXFIFO_SHIFT)
+#define LPUART_PARAM_RXFIFO_SHIFT (8) /* Bits 8-15: Receive FIFO Size (RXFIFO) */
+#define LPUART_PARAM_RXFIFO_MASK (0xff << LPUART_PARAM_RXFIFO_SHIFT)
+ /* Bits 16-31: Reserved */
+
+/* LPUART Global Register (GLOBAL) */
+
+ /* Bit 0: Reserved */
+#define LPUART_GLOBAL_RST (1 << 1) /* Bit 1: Software Reset (RST) */
+ /* Bits 2-31: Reserved */
+
+/* LPUART Pin Configuration Register (PINCFG) */
+
+#define LPUART_PINCFG_TRGSEL_SHIFT (0) /* Bits 0-1: Trigger Select (TRGSEL) */
+#define LPUART_PINCFG_TRGSEL_MASK (0x03 << LPUART_PINCFG_TRGSEL_SHIFT)
+# define LPUART_PINCFG_TRGSEL_DISABLE (0 << LPUART_PINCFG_TRGSEL_SHIFT) /* Trigger disabled */
+# define LPUART_PINCFG_TRGSEL_RXD (1 << LPUART_PINCFG_TRGSEL_SHIFT) /* Trigger used instead of RXD pin */
+# define LPUART_PINCFG_TRGSEL_CTSB (2 << LPUART_PINCFG_TRGSEL_SHIFT) /* Trigger used instead of CTS_B pin */
+# define LPUART_PINCFG_TRGSEL_TXDMOD (3 << LPUART_PINCFG_TRGSEL_SHIFT) /* Trigger used to modulate the TXD output */
+
+ /* Bits 2-31: Reserved */
+
+/* LPUART Baud Rate Register (BAUD) */
+
+#define LPUART_BAUD_SBR_SHIFT (0) /* Bits 0-12: Baud Rate Modulo Divisor (SBR) */
+#define LPUART_BAUD_SBR_MASK (0x1fff << LPUART_BAUD_SBR_SHIFT)
+# define LPUART_BAUD_SBR(n) ((n) << LPUART_BAUD_SBR_SHIFT)
+#define LPUART_BAUD_SBNS (1 << 13) /* Bit 13: Stop Bit Number Select (SBNS) */
+#define LPUART_BAUD_RXEDGIE (1 << 14) /* Bit 14: RX Input Active Edge Interrupt Enable (RXEDGIE) */
+#define LPUART_BAUD_LBKDIE (1 << 15) /* Bit 15: LIN Break Detect Interrupt Enable (LBKDIE) */
+#define LPUART_BAUD_RESYNCDIS (1 << 16) /* Bit 16: Resynchronization Disable (RESYNCDIS) */
+#define LPUART_BAUD_BOTHEDGE (1 << 17) /* Bit 17: Both Edge Sampling (BOTHEDGE) */
+#define LPUART_BAUD_MATCFG_SHIFT (18) /* Bits 18-19: Match Configuration (MATCFG) */
+#define LPUART_BAUD_MATCFG_MASK (0x03 << LPUART_BAUD_MATCFG_SHIFT)
+# define LPUART_BAUD_MATCFG_ADDR (0 << LPUART_BAUD_MATCFG_SHIFT) /* Address Match Wakeup */
+# define LPUART_BAUD_MATCFG_IDLE (1 << LPUART_BAUD_MATCFG_SHIFT) /* Idle Match Wakeup */
+# define LPUART_BAUD_MATCFG_ONOFF (2 << LPUART_BAUD_MATCFG_SHIFT) /* Match On and Match Off */
+# define LPUART_BAUD_MATCFG_RWUENAB (3 << LPUART_BAUD_MATCFG_SHIFT) /* Enables RWU on Data Match and Match On/Off for transmitter CTS input */
+
+ /* Bit 20: Reserved */
+#define LPUART_BAUD_RDMAE (1 << 21) /* Bit 21: Receiver Full DMA Enable (RDMAE) */
+ /* Bit 22: Reserved */
+#define LPUART_BAUD_TDMAE (1 << 23) /* Bit 23: Transmitter DMA Enable (TDMAE) */
+#define LPUART_BAUD_OSR_SHIFT (24) /* Bits 24-29: Oversampling Ratio (OSR) */
+#define LPUART_BAUD_OSR_MASK (0x1f << LPUART_BAUD_OSR_SHIFT)
+# define LPUART_BAUD_OSR(n) (((n) - 1) << LPUART_BAUD_OSR_SHIFT) /* n=4..32 */
+
+#define LPUART_BAUD_M10 (1 << 29) /* Bit 29: 10-bit Mode Select (M10) */
+#define LPUART_BAUD_MAEN2 (1 << 30) /* Bit 30: Match Address Mode Enable 2 (MAEN2) */
+#define LPUART_BAUD_MAEN1 (1 << 31) /* Bit 31: Match Address Mode Enable 1 (MAEN1) */
+
+/* LPUART Status Register (STAT) */
+
+#define LPUART_STAT_LBKFE (1 << 0) /* Bit 0: LIN Break Flag Enable (LBKFE) */
+#define LPUART_STAT_AME (1 << 1) /* Bit 1: Address Mark Enable (AME) */
+ /* Bits 2-13: Reserved */
+#define LPUART_STAT_MA2F (1 << 14) /* Bit 14: Match 2 Flag (MA2F) */
+#define LPUART_STAT_MA1F (1 << 15) /* Bit 15: Match 1 Flag (MA1F) */
+#define LPUART_STAT_PF (1 << 16) /* Bit 16: Parity Error Flag (PF) */
+#define LPUART_STAT_FE (1 << 17) /* Bit 17: Framing Error Flag (FE) */
+#define LPUART_STAT_NF (1 << 18) /* Bit 18: Noise Flag (NF) */
+#define LPUART_STAT_OR (1 << 19) /* Bit 19: Receiver Overrun Flag (OR) */
+#define LPUART_STAT_IDLE (1 << 20) /* Bit 20: Idle Line Flag (IDLE) */
+#define LPUART_STAT_RDRF (1 << 21) /* Bit 21: Receive Data Register Full Flag (RDRF) */
+#define LPUART_STAT_TC (1 << 22) /* Bit 22: Transmission Complete Flag (TC) */
+#define LPUART_STAT_TDRE (1 << 23) /* Bit 23: Transmit Data Register Empty Flag (TDRE) */
+#define LPUART_STAT_RAF (1 << 24) /* Bit 24: Receiver Active Flag (RAF) */
+#define LPUART_STAT_LBKDE (1 << 25) /* Bit 25: LIN Break Detection Enable (LBKDE) */
+#define LPUART_STAT_BRK13 (1 << 26) /* Bit 26: Break Character Generation Length (BRK13) */
+#define LPUART_STAT_RWUID (1 << 27) /* Bit 27: Receive Wake Up Idle Detect (RWUID) */
+#define LPUART_STAT_RXINV (1 << 28) /* Bit 28: Receive Data Inversion (RXINV) */
+#define LPUART_STAT_MSBF (1 << 29) /* Bit 29: MSB First (MSBF) */
+#define LPUART_STAT_RXEDGIF (1 << 30) /* Bit 30: RXD Pin Active Edge Interrupt Flag (RXEDGIF) */
+#define LPUART_STAT_LBKDIF (1 << 31) /* Bit 31: LIN Break Detect Interrupt Flag (LBKDIF) */
+
+/* LPUART Control Register (CTRL) */
+
+#define LPUART_CTRL_PT (1 << 0) /* Bit 0: Parity Type */
+# define LPUART_CTRL_PT_EVEN (0 << 0) /* Even parity */
+# define LPUART_CTRL_PT_ODD (1 << 0) /* Odd parity */
+#define LPUART_CTRL_PE (1 << 1) /* Bit 1: Parity Enable */
+#define LPUART_CTRL_ILT (1 << 2) /* Bit 2: Idle Line Type Select */
+#define LPUART_CTRL_WAKE (1 << 3) /* Bit 3: Receiver Wakeup Method Select */
+#define LPUART_CTRL_M (1 << 4) /* Bit 4: 9-Bit or 8-Bit Mode Select */
+#define LPUART_CTRL_RSRC (1 << 5) /* Bit 5: Receiver Source Select */
+#define LPUART_CTRL_DOZEEN (1 << 6) /* Bit 6: Doze Enable */
+#define LPUART_CTRL_LOOPS (1 << 7) /* Bit 7: Loop Mode Select */
+#define LPUART_CTRL_IDLECFG_SHIFT (8) /* Bits 8-10: Idle Configuration */
+#define LPUART_CTRL_IDLECFG_MASK (0x07 << LPUART_CTRL_IDLECFG_SHIFT)
+# define LPUART_CTRL_IDLECFG_1 (0 << LPUART_CTRL_IDLECFG_SHIFT) /* 1 idle character */
+# define LPUART_CTRL_IDLECFG_2 (1 << LPUART_CTRL_IDLECFG_SHIFT) /* 2 idle characters */
+# define LPUART_CTRL_IDLECFG_4 (2 << LPUART_CTRL_IDLECFG_SHIFT) /* 4 idle characters */
+# define LPUART_CTRL_IDLECFG_8 (3 << LPUART_CTRL_IDLECFG_SHIFT) /* 8 idle characters */
+# define LPUART_CTRL_IDLECFG_16 (4 << LPUART_CTRL_IDLECFG_SHIFT) /* 6 idle characters */
+# define LPUART_CTRL_IDLECFG_32 (5 << LPUART_CTRL_IDLECFG_SHIFT) /* 32 idle characters */
+# define LPUART_CTRL_IDLECFG_64 (6 << LPUART_CTRL_IDLECFG_SHIFT) /* 64 idle characters */
+# define LPUART_CTRL_IDLECFG_128 (7 << LPUART_CTRL_IDLECFG_SHIFT) /* 128 idle characters */
+
+#define LPUART_CTRL_M7 (1 << 11) /* Bit 11: 7-Bit Mode Select (M7) */
+ /* Bits 12-13: Reserved */
+#define LPUART_CTRL_MA2IE (1 << 14) /* Bit 14: Match 2 Interrupt Enable (MA2IE) */
+#define LPUART_CTRL_MA1IE (1 << 15) /* Bit 15: Match 1 Interrupt Enable (MA1IE) */
+#define LPUART_CTRL_SBK (1 << 16) /* Bit 16: Send Break (SBK) */
+#define LPUART_CTRL_RWU (1 << 17) /* Bit 17: Receiver Wakeup Control (RWU) */
+#define LPUART_CTRL_RE (1 << 18) /* Bit 18: Receiver Enable (RE) */
+#define LPUART_CTRL_TE (1 << 19) /* Bit 19: Transmitter Enable (TE) */
+#define LPUART_CTRL_ILIE (1 << 20) /* Bit 20: Idle Line Interrupt Enable (ILIE) */
+#define LPUART_CTRL_RIE (1 << 21) /* Bit 21: Receiver Interrupt Enable (RIE) */
+#define LPUART_CTRL_TCIE (1 << 22) /* Bit 22: Transmission Complete Interrupt Enable (TCIE) */
+#define LPUART_CTRL_TIE (1 << 23) /* Bit 23: Transmit Interrupt Enable (TIE) */
+#define LPUART_CTRL_PEIE (1 << 24) /* Bit 24: Parity Error Interrupt Enable (PEIE) */
+#define LPUART_CTRL_FEIE (1 << 25) /* Bit 25: Framing Error Interrupt Enable (FEIE) */
+#define LPUART_CTRL_NEIE (1 << 26) /* Bit 26: Noise Error Interrupt Enable (NEIE) */
+#define LPUART_CTRL_ORIE (1 << 27) /* Bit 27: Overrun Interrupt Enable (ORIE) */
+#define LPUART_CTRL_TXINV (1 << 28) /* Bit 28: Transmit Data Inversion (TXINV) */
+#define LPUART_CTRL_TXDIR (1 << 29) /* Bit 29: TXD Pin Direction in Single-Wire Mode (TXDIR) */
+#define LPUART_CTRL_R9T8 (1 << 30) /* Bit 30: Receive Bit 9 / Transmit Bit 8 (R9T8) */
+#define LPUART_CTRL_R8T9 (1 << 31) /* Bit 31: Receive Bit 8 / Transmit Bit 9 (R8T9) */
+
+#define LPUART_ALL_INTS (LPUART_CTRL_ORIE | LPUART_CTRL_NEIE | LPUART_CTRL_FEIE | \
+ LPUART_CTRL_PEIE | LPUART_CTRL_TIE | LPUART_CTRL_TCIE | \
+ LPUART_CTRL_RIE | LPUART_CTRL_ILIE | LPUART_CTRL_MA1IE | \
+ LPUART_CTRL_MA2IE)
+
+/* LPUART Data Register (DATA) */
+
+#define LPUART_DATA_SHIFT (0) /* Bits 0-9: Data bits 0-9 (DATA)*/
+#define LPUART_DATA_MASK (0x03ff << LPUART_DATA_SHIFT)
+#define LPUART_DATA_LINBRK (1 << 10) /* Bit 10: LIN Break (LINBRK) */
+#define LPUART_DATA_STATUS_SHIFT (11) /* Bits 11-15: Status */
+#define LPUART_DATA_IDLINE (1 << 11) /* Bit 11: Idle Line (IDLINE) */
+#define LPUART_DATA_RXEMPT (1 << 12) /* Bit 12: Receive Buffer Empty (RXEMPT) */
+#define LPUART_DATA_FRETSC (1 << 13) /* Bit 13: Frame Error / Transmit Special Character (FRETSC) */
+#define LPUART_DATA_PARITYE (1 << 14) /* Bit 14: Parity Error (PARITYE) */
+#define LPUART_DATA_NOISY (1 << 15) /* Bit 15: Noisy Data Received (NOISY) */
+ /* Bits 16-31: Reserved */
+
+/* LPUART Match Address Register (MATCH) */
+
+#define LPUART_MATCH_MA1_SHIFT (0) /* Bits 0-9: Match Address 1 (MA1) */
+#define LPUART_MATCH_MA1_MASK (0x03ff << LPUART_MATCH_MA1_SHIFT)
+# define LPUART_MATCH_MA1(n) ((n) << LPUART_MATCH_MA1_SHIFT)
+ /* Bits 10-15: Reserved */
+#define LPUART_MATCH_MA2_SHIFT (16) /* Bits 16-25: Match Address 2 (MA2) */
+#define LPUART_MATCH_MA2_MASK (0x03ff << LPUART_MATCH_MA2_SHIFT)
+# define LPUART_MATCH_MA2(n) ((n) << LPUART_MATCH_MA2_SHIFT)
+ /* Bits 26-31: Reserved */
+
+/* LPUART Modem IrDA Register (MODIR) */
+
+#define LPUART_MODIR_TXCTSE (1 << 0) /* Bit 0: Transmitter clear-to-send enable (TXCTSE) */
+#define LPUART_MODIR_TXRTSE (1 << 1) /* Bit 1: Transmitter request-to-send enable (TXRTSE) */
+#define LPUART_MODIR_TXRTSPOL (1 << 2) /* Bit 2: Transmitter request-to-send polarity (TXRTSPOL) */
+#define LPUART_MODIR_RXRTSE (1 << 3) /* Bit 3: Receiver request-to-send enable (RXRTSE) */
+#define LPUART_MODIR_TXCTSC (1 << 4) /* Bit 4: Transmit CTS Configuration (TXCTSC) */
+# define LPUART_MODIR_TXCTSC_START (0 << 4) /* CTS sampled at start of character */
+# define LPUART_MODIR_TXCTSC_IDLE (1 << 4) /* CTS sampled when transmitter idle */
+#define LPUART_MODIR_TXCTSSRC (1 << 5) /* Bit 5: Transmit CTS Source (TXCTSSRC) */
+# define LPUART_MODIR_TXCTSSRC_CTSB (0 << 5) /* CTS input is CTS_B pin */
+# define LPUART_MODIR_TXCTSSRC_RXMAT (1 << 5) /* CTS input is receiver address match result */
+ /* Bits 6-7: Reserved */
+#define LPUART_MODIR_RTSWATER_SHIFT (8) /* Bits 8-9: Receive RTS Configuration (RTSWATER) */
+#define LPUART_MODIR_RTSWATER_MASK (0x03 << LPUART_MODIR_RTSWATER_SHIFT)
+# define LPUART_MODIR_RTSWATER(n) ((n) << LPUART_MODIR_RTSWATER_SHIFT)
+ /* Bits 10-15: Reserved */
+#define LPUART_MODIR_TNP_SHIFT (16) /* Bits 16-17: Transmitter narrow pulse (TNP) */
+#define LPUART_MODIR_TNP_MASK (0x03 << LPUART_MODIR_TNP_SHIFT)
+# define LPUART_MODIR_TNP(n) (((n) - 1) << LPUART_MODIR_TNP_SHIFT) /* n/OSR */
+
+#define LPUART_MODIR_IREN (1 << 18) /* Bit 18: Infrared enable (IREN) */
+ /* Bits 19-31: Reserved */
+
+/* LPUART FIFO Register (FIFO) */
+
+#define LPUART_FIFO_RXFIFOSIZE_SHIFT (0) /* Bits 0-2: Receive FIFO Buffer Depth (RXFIFOSIZE) */
+#define LPUART_FIFO_RXFIFOSIZE_MASK (0x07 << LPUART_FIFO_RXFIFOSIZE_SHIFT)
+# define LPUART_FIFO_RXFIFOSIZE_1 (0 << LPUART_FIFO_RXFIFOSIZE_SHIFT) /* 1 dataword */
+# define LPUART_FIFO_RXFIFOSIZE_4 (1 << LPUART_FIFO_RXFIFOSIZE_SHIFT) /* 4 datawords */
+# define LPUART_FIFO_RXFIFOSIZE_8 (2 << LPUART_FIFO_RXFIFOSIZE_SHIFT) /* 8 datawords */
+# define LPUART_FIFO_RXFIFOSIZE_16 (3 << LPUART_FIFO_RXFIFOSIZE_SHIFT) /* 16 datawords */
+# define LPUART_FIFO_RXFIFOSIZE_32 (4 << LPUART_FIFO_RXFIFOSIZE_SHIFT) /* 32 datawords */
+# define LPUART_FIFO_RXFIFOSIZE_64 (5 << LPUART_FIFO_RXFIFOSIZE_SHIFT) /* 64 datawords */
+# define LPUART_FIFO_RXFIFOSIZE_128 (6 << LPUART_FIFO_RXFIFOSIZE_SHIFT) /* 128 datawords */
+# define LPUART_FIFO_RXFIFOSIZE_256 (7 << LPUART_FIFO_RXFIFOSIZE_SHIFT) /* 256 datawords */
+
+#define LPUART_FIFO_RXFE (1 << 3) /* Bit 3: Receive FIFO Enable (RXFE) */
+#define LPUART_FIFO_TXFIFOSIZE_SHIFT (4) /* Bits 4-6: Transmit FIFO Buffer Depth (TXFIFOSIZE) */
+#define LPUART_FIFO_TXFIFOSIZE_MASK (0x07 << LPUART_FIFO_TXFIFOSIZE_SHIFT)
+# define LPUART_FIFO_TXFIFOSIZE_1 (0 << LPUART_FIFO_TXFIFOSIZE_SHIFT) /* 1 dataword */
+# define LPUART_FIFO_TXFIFOSIZE_4 (1 << LPUART_FIFO_TXFIFOSIZE_SHIFT) /* 4 datawords */
+# define LPUART_FIFO_TXFIFOSIZE_8 (2 << LPUART_FIFO_TXFIFOSIZE_SHIFT) /* 8 datawords */
+# define LPUART_FIFO_TXFIFOSIZE_16 (3 << LPUART_FIFO_TXFIFOSIZE_SHIFT) /* 16 datawords */
+# define LPUART_FIFO_TXFIFOSIZE_32 (4 << LPUART_FIFO_TXFIFOSIZE_SHIFT) /* 32 datawords */
+# define LPUART_FIFO_TXFIFOSIZE_64 (5 << LPUART_FIFO_TXFIFOSIZE_SHIFT) /* 64 datawords */
+# define LPUART_FIFO_TXFIFOSIZE_128 (6 << LPUART_FIFO_TXFIFOSIZE_SHIFT) /* 128 datawords */
+# define LPUART_FIFO_TXFIFOSIZE_256 (7 << LPUART_FIFO_TXFIFOSIZE_SHIFT) /* 256 datawords */
+
+#define LPUART_FIFO_TXFE (1 << 7) /* Bit 7: Transmit FIFO Enable (TXFE) */
+#define LPUART_FIFO_RXUFE (1 << 8) /* Bit 8: Receive FIFO Underflow Interrupt Enable (RXUFE) */
+#define LPUART_FIFO_TXOFE (1 << 9) /* Bit 9: Transmit FIFO Overflow Interrupt Enable (TXOFE) */
+#define LPUART_FIFO_RXIDEN_SHIFT (10) /* Bits 10-12: Receiver Idle Empty Enable (RXIDEN) */
+#define LPUART_FIFO_RXIDEN_MASK (0x07 << LPUART_FIFO_RXIDEN_SHIFT)
+# define LPUART_FIFO_RXIDEN_DISABLE (0 << LPUART_FIFO_RXIDEN_SHIFT) /* Disable RDRF assertion when receiver is idle */
+# define LPUART_FIFO_RXIDEN_1 (1 << LPUART_FIFO_RXIDEN_SHIFT) /* Enable RDRF assertion when receiver idle for 1 character */
+# define LPUART_FIFO_RXIDEN_2 (2 << LPUART_FIFO_RXIDEN_SHIFT) /* Enable RDRF assertion when receiver idle for 2 characters */
+# define LPUART_FIFO_RXIDEN_4 (3 << LPUART_FIFO_RXIDEN_SHIFT) /* Enable RDRF assertion when receiver idle for 4 characters */
+# define LPUART_FIFO_RXIDEN_8 (4 << LPUART_FIFO_RXIDEN_SHIFT) /* Enable RDRF assertion when receiver idle for 8 characters */
+# define LPUART_FIFO_RXIDEN_16 (5 << LPUART_FIFO_RXIDEN_SHIFT) /* Enable RDRF assertion when receiver idle for 16 characters */
+# define LPUART_FIFO_RXIDEN_32 (6 << LPUART_FIFO_RXIDEN_SHIFT) /* Enable RDRF assertion when receiver idle for 32 characters */
+# define LPUART_FIFO_RXIDEN_64 (7 << LPUART_FIFO_RXIDEN_SHIFT) /* Enable RDRF assertion when receiver idle for 64 characters */
+
+ /* Bit 13: Reserved */
+#define LPUART_FIFO_RXFLUSH (1 << 14) /* Bit 14: Receive FIFO Flush (RXFLUSH) */
+#define LPUART_FIFO_TXFLUSH (1 << 15) /* Bit 15: Transmit FIFO Flush (TXFLUSH) */
+#define LPUART_FIFO_RXUF (1 << 16) /* Bit 16: Receiver FIFO Underflow Flag (RXUF) */
+#define LPUART_FIFO_TXOF (1 << 17) /* Bit 17: Transmitter FIFO Overflow Flag (TXOF) */
+ /* Bits 18-21: Reserved */
+#define LPUART_FIFO_RXEMPT (1 << 22) /* Bit 22: Receive Buffer/FIFO Empty (RXEMPT) */
+#define LPUART_FIFO_TXEMPT (1 << 23) /* Bit 23: Transmit Buffer/FIFO Empty (TXEMPT) */
+ /* Bits 24-31: Reserved */
+
+/* LPUART Watermark Register (WATER) */
+
+#define LPUART_WATER_TXWATER_SHIFT (0) /* Bits 0-1: Transmit Watermark (TXWATER) */
+#define LPUART_WATER_TXWATER_MASK (0x03 << LPUART_WATER_TXWATER_SHIFT)
+# define LPUART_WATER_TXWATER(n) ((n) << LPUART_WATER_TXWATER_SHIFT)
+ /* Bits 2-7: Reserved */
+#define LPUART_WATER_TXCOUNT_SHIFT (8) /* Bits 8-10: Transmit Counter (TXCOUNT) */
+#define LPUART_WATER_TXCOUNT_MASK (0x07 << LPUART_WATER_TXCOUNT_SHIFT)
+# define LPUART_WATER_TXCOUNT(n) ((n) << LPUART_WATER_TXCOUNT_SHIFT)
+ /* Bits 11-15: Reserved */
+#define LPUART_WATER_RXWATER_SHIFT (16) /* Bits 16-17: Receive Watermark (RXWATER) */
+#define LPUART_WATER_RXWATER_MASK (0x03 << LPUART_WATER_RXWATER_SHIFT)
+# define LPUART_WATER_RXWATER(n) ((n) << LPUART_WATER_RXWATER_SHIFT)
+ /* Bits 18-23: Reserved */
+#define LPUART_WATER_RXCOUNT_SHIFT (24) /* Bits 24-26: Receive Counter (RXCOUNT) */
+#define LPUART_WATER_RXCOUNT_MASK (0x07 << LPUART_WATER_RXCOUNT_SHIFT)
+# define LPUART_WATER_RXCOUNT(n) ((n) << LPUART_WATER_RXCOUNT_SHIFT)
+ /* Bits 27-31: Reserved */
+
+/* Data read-only Register (DATARO) */
+
+#define LPUART_DATARO_DATA_SHIFT (0) /* Bits 0-15: Receive Data (DATA) */
+#define LPUART_DATARO_DATA_MASK (0xffff << LPUART_DATARO_DATA_SHIFT)
+ /* Bits 16-31: Reserved */
#endif /* __ARCH_ARM64_SRC_IMX9_HARDWARE_IMX9_LPUART_H */
diff --git a/arch/arm64/src/imx9/imx9_boot.c b/arch/arm64/src/imx9/imx9_boot.c
index 16f19de2c6..260e679974 100644
--- a/arch/arm64/src/imx9/imx9_boot.c
+++ b/arch/arm64/src/imx9/imx9_boot.c
@@ -39,6 +39,7 @@
#include "arm64_mmu.h"
#include "imx9_boot.h"
#include "imx9_serial.h"
+#include "imx9_lowputc.h"
/****************************************************************************
* Private Data
@@ -96,6 +97,12 @@ void arm64_chip_boot(void)
arm64_mmu_init(true);
+ /* Do UART early initialization & pin muxing */
+
+#ifdef CONFIG_IMX9_LPUART
+ imx9_lowsetup();
+#endif
+
/* Perform board-specific device initialization. This would include
* configuration of board specific resources such as GPIOs, LEDs, etc.
*/
diff --git a/arch/arm64/src/imx9/imx9_lowputc.c b/arch/arm64/src/imx9/imx9_lowputc.c
new file mode 100644
index 0000000000..c41f6f43ee
--- /dev/null
+++ b/arch/arm64/src/imx9/imx9_lowputc.c
@@ -0,0 +1,532 @@
+/****************************************************************************
+ * arch/arm64/src/imx9/imx9_lowputc.c
+ *
+ * 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 <stdint.h>
+#include <fixedmath.h>
+#include <assert.h>
+#include <errno.h>
+
+#include "hardware/imx9_pinmux.h"
+#include "hardware/imx9_lpuart.h"
+
+#include "arm64_internal.h"
+
+#include "imx9_lowputc.h"
+#include "imx9_ccm.h"
+#include "imx9_iomuxc.h"
+#include "hardware/imx9_ccm.h"
+#include "hardware/imx9_pinmux.h"
+
+#include <arch/board/board.h> /* Include last: has dependencies */
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Configuration ************************************************************/
+
+#if defined(CONFIG_LPUART1_SERIAL_CONSOLE)
+# define IMX9_CONSOLE_DEVOFF 0
+# define IMX9_CONSOLE_BASE IMX9_LPUART1_BASE
+# define IMX9_CONSOLE_BAUD CONFIG_LPUART1_BAUD
+# define IMX9_CONSOLE_BITS CONFIG_LPUART1_BITS
+# define IMX9_CONSOLE_PARITY CONFIG_LPUART1_PARITY
+# define IMX9_CONSOLE_2STOP CONFIG_LPUART1_2STOP
+#elif defined(CONFIG_LPUART2_SERIAL_CONSOLE)
+# define IMX9_CONSOLE_DEVNUM 1
+# define IMX9_CONSOLE_BASE IMX9_LPUART2_BASE
+# define IMX9_CONSOLE_BAUD CONFIG_LPUART2_BAUD
+# define IMX9_CONSOLE_BITS CONFIG_LPUART2_BITS
+# define IMX9_CONSOLE_PARITY CONFIG_LPUART2_PARITY
+# define IMX9_CONSOLE_2STOP CONFIG_LPUART2_2STOP
+#elif defined(CONFIG_LPUART3_SERIAL_CONSOLE)
+# define IMX9_CONSOLE_DEVNUM 2
+# define IMX9_CONSOLE_BASE IMX9_LPUART3_BASE
+# define IMX9_CONSOLE_BAUD CONFIG_LPUART3_BAUD
+# define IMX9_CONSOLE_BITS CONFIG_LPUART3_BITS
+# define IMX9_CONSOLE_PARITY CONFIG_LPUART3_PARITY
+# define IMX9_CONSOLE_2STOP CONFIG_LPUART3_2STOP
+#elif defined(CONFIG_LPUART4_SERIAL_CONSOLE)
+# define IMX9_CONSOLE_DEVNUM 3
+# define IMX9_CONSOLE_BASE IMX9_LPUART4_BASE
+# define IMX9_CONSOLE_BAUD CONFIG_LPUART4_BAUD
+# define IMX9_CONSOLE_BITS CONFIG_LPUART4_BITS
+# define IMX9_CONSOLE_PARITY CONFIG_LPUART4_PARITY
+# define IMX9_CONSOLE_2STOP CONFIG_LPUART4_2STOP
+#elif defined(CONFIG_LPUART5_SERIAL_CONSOLE)
+# define IMX9_CONSOLE_DEVNUM 4
+# define IMX9_CONSOLE_BASE IMX9_LPUART5_BASE
+# define IMX9_CONSOLE_BAUD CONFIG_LPUART5_BAUD
+# define IMX9_CONSOLE_BITS CONFIG_LPUART5_BITS
+# define IMX9_CONSOLE_PARITY CONFIG_LPUART5_PARITY
+# define IMX9_CONSOLE_2STOP CONFIG_LPUART5_2STOP
+#elif defined(CONFIG_LPUART6_SERIAL_CONSOLE)
+# define IMX9_CONSOLE_DEVNUM 5
+# define IMX9_CONSOLE_BASE IMX9_LPUART6_BASE
+# define IMX9_CONSOLE_BAUD CONFIG_LPUART6_BAUD
+# define IMX9_CONSOLE_BITS CONFIG_LPUART6_BITS
+# define IMX9_CONSOLE_PARITY CONFIG_LPUART6_PARITY
+# define IMX9_CONSOLE_2STOP CONFIG_LPUART6_2STOP
+#elif defined(CONFIG_LPUART7_SERIAL_CONSOLE)
+# define IMX9_CONSOLE_DEVNUM 6
+# define IMX9_CONSOLE_BASE IMX9_LPUART7_BASE
+# define IMX9_CONSOLE_BAUD CONFIG_LPUART7_BAUD
+# define IMX9_CONSOLE_BITS CONFIG_LPUART7_BITS
+# define IMX9_CONSOLE_PARITY CONFIG_LPUART7_PARITY
+# define IMX9_CONSOLE_2STOP CONFIG_LPUART7_2STOP
+#elif defined(CONFIG_LPUART8_SERIAL_CONSOLE)
+# define IMX9_CONSOLE_DEVNUM 7
+# define IMX9_CONSOLE_BASE IMX9_LPUART8_BASE
+# define IMX9_CONSOLE_BAUD CONFIG_LPUART8_BAUD
+# define IMX9_CONSOLE_BITS CONFIG_LPUART8_BITS
+# define IMX9_CONSOLE_PARITY CONFIG_LPUART8_PARITY
+# define IMX9_CONSOLE_2STOP CONFIG_LPUART8_2STOP
+#endif
+
+#define ABS(n) (((n) < 0) ? -(n) : (n))
+
+/* Clocking *****************************************************************/
+
+/* Functional clocking is provided via the PCC. The PCC clocking must
+ * be configured by board-specific logic prior to using the LPUART.
+ */
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+#ifdef IMX9_CONSOLE_BASE
+static const struct uart_config_s g_console_config =
+{
+ .baud = IMX9_CONSOLE_BAUD, /* Configured baud */
+ .parity = IMX9_CONSOLE_PARITY, /* 0=none, 1=odd, 2=even */
+ .bits = IMX9_CONSOLE_BITS, /* Number of bits (5-9) */
+ .stopbits2 = IMX9_CONSOLE_2STOP, /* true: Configure with 2 stop bits instead of 1 */
+};
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: imx9_lowsetup
+ *
+ * Description:
+ * Called at the very beginning of _start. Performs low level
+ * initialization including setup of the console UART. This UART done
+ * early so that the serial console is available for debugging very early
+ * in the boot sequence.
+ *
+ ****************************************************************************/
+
+void imx9_lowsetup(void)
+{
+#ifndef CONFIG_SUPPRESS_LPUART_CONFIG
+
+#ifdef CONFIG_IMX9_LPUART1
+ /* Configure LPUART1 pins: RXD and TXD. Also configure RTS and CTS if flow
+ * control is enabled.
+ */
+
+ imx9_iomux_configure(MUX_LPUART1_RX);
+ imx9_iomux_configure(MUX_LPUART1_TX);
+#ifdef CONFIG_LPUART1_OFLOWCONTROL
+ imx9_iomux_configure(MUX_LPUART1_CTS);
+#endif
+#if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART1_RS485RTSCONTROL)) || \
+ (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART1_IFLOWCONTROL)))
+ imx9_iomux_configure(MUX_LPUART1_RTS);
+#endif
+#endif
+
+#ifdef CONFIG_IMX9_LPUART2
+
+ /* Configure LPUART2 pins: RXD and TXD. Also configure RTS and CTS if flow
+ * control is enabled.
+ */
+
+ imx9_iomux_configure(MUX_LPUART2_RX);
+ imx9_iomux_configure(MUX_LPUART2_TX);
+#ifdef CONFIG_LPUART2_OFLOWCONTROL
+ imx9_iomux_configure(MUX_LPUART2_CTS);
+#endif
+#if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART2_RS485RTSCONTROL)) || \
+ (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART2_IFLOWCONTROL)))
+ imx9_iomux_configure(MUX_LPUART2_RTS);
+#endif
+#endif
+
+#ifdef CONFIG_IMX9_LPUART3
+
+ /* Configure LPUART3 pins: RXD and TXD. Also configure RTS and CTS if flow
+ * control is enabled.
+ */
+
+ imx9_iomux_configure(MUX_LPUART3_RX);
+ imx9_iomux_configure(MUX_LPUART3_TX);
+#ifdef CONFIG_LPUART3_OFLOWCONTROL
+ imx9_iomux_configure(MUX_LPUART3_CTS);
+#endif
+#if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART3_RS485RTSCONTROL)) || \
+ (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART3_IFLOWCONTROL)))
+ imx9_iomux_configure(MUX_LPUART3_RTS);
+#endif
+#endif
+
+#ifdef CONFIG_IMX9_LPUART4
+
+ /* Configure LPUART4 pins: RXD and TXD. Also configure RTS and CTS if flow
+ * control is enabled.
+ */
+
+ imx9_iomux_configure(LPUART4_RX);
+ imx9_iomux_configure(LPUART4_TX);
+#ifdef CONFIG_LPUART4_OFLOWCONTROL
+ imx9_iomux_configure(LPUART4_CTS);
+#endif
+#if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART4_RS485RTSCONTROL)) || \
+ (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART4_IFLOWCONTROL)))
+ imx9_iomux_configure(LPUART4_RTS);
+#endif
+#endif
+
+#ifdef CONFIG_IMX9_LPUART5
+
+ /* Configure LPUART5 pins: RXD and TXD. Also configure RTS and CTS if flow
+ * control is enabled.
+ */
+
+ imx9_iomux_configure(MUX_LPUART5_RX);
+ imx9_iomux_configure(MUX_LPUART5_TX);
+#ifdef CONFIG_LPUART5_OFLOWCONTROL
+ imx9_iomux_configure(MUX_LPUART5_CTS);
+#endif
+#if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART5_RS485RTSCONTROL)) || \
+ (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART5_IFLOWCONTROL)))
+ imx9_iomux_configure(MUX_LPUART5_RTS);
+#endif
+#endif
+
+#ifdef CONFIG_IMX9_LPUART6
+
+ /* Configure LPUART6 pins: RXD and TXD. Also configure RTS and CTS if flow
+ * control is enabled.
+ */
+
+ imx9_iomux_configure(MUX_LPUART6_RX);
+ imx9_iomux_configure(MUX_LPUART6_TX);
+#ifdef CONFIG_LPUART6_OFLOWCONTROL
+ imx9_iomux_configure(MUX_LPUART6_CTS);
+#endif
+#if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART6_RS485RTSCONTROL)) || \
+ (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART6_IFLOWCONTROL)))
+ imx9_iomux_configure(MUX_LPUART6_RTS);
+#endif
+#endif
+
+#ifdef CONFIG_IMX9_LPUART7
+
+ /* Configure LPUART7 pins: RXD and TXD. Also configure RTS and CTS if flow
+ * control is enabled.
+ */
+
+ imx9_iomux_configure(MUX_LPUART7_RX);
+ imx9_iomux_configure(MUX_LPUART7_TX);
+#ifdef CONFIG_LPUART7_OFLOWCONTROL
+ imx9_iomux_configure(MUX_LPUART7_CTS);
+#endif
+#if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART7_RS485RTSCONTROL)) || \
+ (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART7_IFLOWCONTROL)))
+ imx9_iomux_configure(MUX_LPUART7_RTS);
+#endif
+#endif
+
+#ifdef CONFIG_IMX9_LPUART8
+
+ /* Configure LPUART8 pins: RXD and TXD. Also configure RTS and CTS if flow
+ * control is enabled.
+ */
+
+ imx9_iomux_configure(MUX_LPUART8_RX);
+ imx9_iomux_configure(MUX_LPUART8_TX);
+#ifdef CONFIG_LPUART0_OFLOWCONTROL
+ imx9_iomux_configure(MUX_LPUART8_CTS);
+#endif
+#if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART8_RS485RTSCONTROL)) || \
+ (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART8_IFLOWCONTROL)))
+ imx9_iomux_configure(MUX_LPUART8_RTS);
+#endif
+#endif
+
+#ifdef IMX9_CONSOLE_BASE
+ /* Configure the serial console for initial, non-interrupt driver mode */
+
+ imx9_lpuart_configure(IMX9_CONSOLE_BASE, IMX9_CONSOLE_DEVOFF,
+ &g_console_config);
+#endif
+
+#endif /* CONFIG_SUPPRESS_LPUART_CONFIG */
+}
+
+/****************************************************************************
+ * Name: imx9_lpuart_configure
+ *
+ * Description:
+ * Configure a UART for non-interrupt driven operation
+ *
+ ****************************************************************************/
+
+int imx9_lpuart_configure(uint32_t base, int uartnum,
+ const struct uart_config_s *config)
+{
+ int lpuart_freq = 24000000;
+ uint16_t sbr;
+ uint16_t temp_sbr;
+ uint32_t osr;
+ uint32_t temp_osr;
+ int temp_diff;
+ int calculated_baud;
+ int baud_diff;
+ uint32_t regval;
+
+ /* Configure root clock to 24MHz OSC */
+
+ imx9_ccm_configure_root_clock(CCM_CR_LPUART1 + uartnum - 1, OSC_24M, 1);
+
+ /* Enable peripheral clock */
+
+ imx9_ccm_gate_on(CCM_LPCG_LPUART1 + uartnum - 1, true);
+
+ /* This LPUART instantiation uses a slightly different baud rate
+ * calculation. The idea is to use the best OSR (over-sampling rate)
+ * possible.
+ *
+ * NOTE: OSR is typically hard-set to 16 in other LPUART instantiations
+ * loop to find the best OSR value possible, one that generates minimum
+ * baud_diff iterate through the rest of the supported values of OSR
+ */
+
+ baud_diff = config->baud;
+ osr = 0;
+ sbr = 0;
+
+ for (temp_osr = 4; temp_osr <= 32; temp_osr++)
+ {
+ /* Calculate the temporary sbr value */
+
+ temp_sbr = (lpuart_freq / (config->baud * temp_osr));
+
+ /* Set temp_sbr to 1 if the sourceClockInHz can not satisfy the
+ * desired baud rate.
+ */
+
+ if (temp_sbr == 0)
+ {
+ temp_sbr = 1;
+ }
+
+ /* Calculate the baud rate based on the temporary OSR and SBR values */
+
+ calculated_baud = (lpuart_freq / (temp_osr * temp_sbr));
+ temp_diff = ABS(calculated_baud - config->baud);
+
+ /* Select the better value between srb and (sbr + 1) */
+
+ calculated_baud = (lpuart_freq / (temp_osr * (temp_sbr + 1)));
+ if (temp_diff >
+ ABS(calculated_baud - config->baud))
+ {
+ temp_diff = ABS(calculated_baud - config->baud);
+ temp_sbr++;
+ }
+
+ if (temp_diff <= baud_diff)
+ {
+ baud_diff = temp_diff;
+ osr = temp_osr;
+ sbr = temp_sbr;
+ }
+ }
+
+ if (baud_diff > ((config->baud * 3) / 100))
+ {
+ /* Unacceptable baud rate difference of more than 3% */
+
+ return ERROR;
+ }
+
+ /* Reset all internal logic and registers, except the Global Register */
+
+ regval = getreg32(base + IMX9_LPUART_GLOBAL_OFFSET);
+ regval |= LPUART_GLOBAL_RST;
+ putreg32(regval, base + IMX9_LPUART_GLOBAL_OFFSET);
+
+ regval &= ~LPUART_GLOBAL_RST;
+ putreg32(regval, base + IMX9_LPUART_GLOBAL_OFFSET);
+
+ /* Construct MODIR register */
+
+ regval = 0;
+
+ if (config->userts)
+ {
+ regval |= LPUART_MODIR_RXRTSE;
+ }
+ else if (config->users485)
+ {
+ /* Both TX and RX side can't control RTS, so this gives
+ * the RX side precedence. This should have been filtered
+ * in layers above anyway, but it's just a precaution.
+ */
+
+ regval |= LPUART_MODIR_TXRTSE;
+ }
+
+ if (config->usects)
+ {
+ regval |= LPUART_MODIR_TXCTSE;
+ }
+
+ if (config->invrts)
+ {
+ regval |= LPUART_MODIR_TXRTSPOL;
+ }
+
+ putreg32(regval, base + IMX9_LPUART_MODIR_OFFSET);
+
+ regval = 0;
+
+ if ((osr > 3) && (osr < 8))
+ {
+ regval |= LPUART_BAUD_BOTHEDGE;
+ }
+
+ if (config->stopbits2)
+ {
+ regval |= LPUART_BAUD_SBNS;
+ }
+
+ regval |= LPUART_BAUD_OSR(osr) | LPUART_BAUD_SBR(sbr);
+ putreg32(regval, base + IMX9_LPUART_BAUD_OFFSET);
+
+ regval = 0;
+ if (config->parity == 1)
+ {
+ regval |= LPUART_CTRL_PE | LPUART_CTRL_PT_ODD;
+ }
+ else if (config->parity == 2)
+ {
+ regval |= LPUART_CTRL_PE | LPUART_CTRL_PT_EVEN;
+ }
+
+ if (config->bits == 9 || (config->bits == 8 && config->parity != 0))
+ {
+ regval |= LPUART_CTRL_M;
+ }
+ else if ((config->bits == 8))
+ {
+ regval &= ~LPUART_CTRL_M;
+ }
+ else
+ {
+ /* REVISIT: Here should be added support of other bit modes. */
+
+ return -ENOSYS;
+ }
+
+ regval |= LPUART_CTRL_RE | LPUART_CTRL_TE;
+ putreg32(regval, base + IMX9_LPUART_CTRL_OFFSET);
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: arm64_earlyprintinit
+ *
+ * Description:
+ * Configure LPUART1 for non-interrupt driven operation
+ *
+ ****************************************************************************/
+
+void arm64_earlyprintinit(char ch)
+{
+ /* Assume bootloader has already set up the LPUART1 */
+}
+
+/****************************************************************************
+ * Name: arm64_lowputc
+ *
+ * Description:
+ * Output a byte with as few system dependencies as possible. This will
+ * even work BEFORE the console is initialized if we are booting from U-
+ * Boot (and the same UART is used for the console, of course.)
+ *
+ ****************************************************************************/
+
+void arm64_lowputc(char ch)
+{
+#ifdef IMX9_CONSOLE_BASE
+ while ((getreg32(IMX9_CONSOLE_BASE + IMX9_LPUART_STAT_OFFSET) &
+ LPUART_STAT_TDRE) == 0)
+ {
+ }
+
+ /* If the character to output is a newline,
+ * then pre-pend a carriage return
+ */
+
+ if (ch == '\n')
+ {
+ /* Send the carriage return by writing it into the UART_TXD register. */
+
+ putreg32((uint32_t)'\r',
+ IMX9_CONSOLE_BASE + IMX9_LPUART_DATA_OFFSET);
+
+ /* Wait for the transmit register to be emptied. When the TXFE bit is
+ * non-zero, the TX Buffer FIFO is empty.
+ */
+
+ while ((getreg32(IMX9_CONSOLE_BASE + IMX9_LPUART_STAT_OFFSET) &
+ LPUART_STAT_TDRE) == 0)
+ {
+ }
+ }
+
+ /* Send the character by writing it into the UART_TXD register. */
+
+ putreg32((uint32_t)ch, IMX9_CONSOLE_BASE + IMX9_LPUART_DATA_OFFSET);
+
+ /* Wait for the transmit register to be emptied. When the TXFE bit is
+ * non-zero, the TX Buffer FIFO is empty.
+ */
+
+ while ((getreg32(IMX9_CONSOLE_BASE + IMX9_LPUART_STAT_OFFSET) &
+ LPUART_STAT_TDRE) == 0)
+ {
+ }
+#endif
+}
diff --git a/arch/arm64/src/imx9/imx93_lowputc.S b/arch/arm64/src/imx9/imx9_lowputc.h
similarity index 50%
rename from arch/arm64/src/imx9/imx93_lowputc.S
rename to arch/arm64/src/imx9/imx9_lowputc.h
index f3311810e0..30aceed681 100644
--- a/arch/arm64/src/imx9/imx93_lowputc.S
+++ b/arch/arm64/src/imx9/imx9_lowputc.h
@@ -1,5 +1,5 @@
/****************************************************************************
- * arch/arm64/src/imx9/imx93_lowputs.S
+ * arch/arm64/src/imx9/imx9_lowputc.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
@@ -16,70 +16,69 @@
* License for the specific language governing permissions and limitations
* under the License.
*
- ****************************************************************************
- *
- * DESCRIPTION
- * Wrapper for early printk
- *
- ***************************************************************************/
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_IMX9_IMX9_LOWPUTC_H
+#define __ARCH_ARM_SRC_IMX9_IMX9_LOWPUTC_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
#include <nuttx/config.h>
+#include <nuttx/compiler.h>
-#include "arm64_macro.inc"
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
-#include "hardware/imx9_lpuart.h"
-#include "hardware/imx93/imx93_memorymap.h"
+#include "arm64_internal.h"
/****************************************************************************
- * Public Symbols
+ * Public Types
****************************************************************************/
- .file "imx93_lowputc.S"
+/* This structure describes the configuration of an UART */
-/****************************************************************************
- * Assembly Macros
- ****************************************************************************/
+struct uart_config_s
+{
+ uint32_t baud; /* Configured baud */
+ uint8_t parity; /* 0=none, 1=odd, 2=even */
+ uint8_t bits; /* Number of bits (5-9) */
+ bool stopbits2; /* true: Configure with 2 stop bits instead of 1 */
+ bool userts; /* True: Assert RTS when there are data to be sent */
+ bool invrts; /* True: Invert sense of RTS pin (true=active high) */
+ bool usects; /* True: Condition transmission on CTS asserted */
+ bool users485; /* True: Assert RTS while transmission progresses */
+};
/****************************************************************************
- * Private Functions
+ * Public Function Prototypes
****************************************************************************/
/****************************************************************************
- * Public Functions
+ * Name: imx9_lowsetup
+ *
+ * Description:
+ * Called at the very beginning of _start. Performs low level
+ * initialization including setup of the console UART. This UART done
+ * early so that the serial console is available for debugging very early
+ * in the boot sequence.
+ *
****************************************************************************/
-/* PL011 UART initialization */
-
-GTEXT(arm64_earlyprintinit)
-SECTION_FUNC(text, arm64_earlyprintinit)
- /* TODO: Assumes u-boot has set us up, assumption is fine for now */
- ret
+void imx9_lowsetup(void);
-/* i.MX93 wait LPUART to be ready to transmit
- * rb: register which contains the UART base address
- * rc: scratch register
- */
-.macro early_uart_ready rb, rc
-1:
- ldr \rc, [\rb, #UARTSTAT] /* <- Flag register */
- tst \rc, #UARTSTAT_TDRE /* Check FIFO EMPTY bit */
- beq 1b /* Wait for the UART to be ready */
-.endm
+/****************************************************************************
+ * Name: imx9_lpuart_configure
+ *
+ * Description:
+ * Configure a UART for non-interrupt driven operation
+ *
+ ****************************************************************************/
-/* i.MX93 LPUART transmit character
- * rb: register which contains the UART base address
- * rt: register which contains the character to transmit */
-.macro early_uart_transmit rb, rt
- str \rt, [\rb, #UARTDATA] /* -> Data Register */
-.endm
+int imx9_lpuart_configure(uint32_t base,
+ int uartnum,
+ const struct uart_config_s *config);
-/*
- * Print a character on the UART - this function is called by C
- * w0: character to print
- */
-GTEXT(arm64_lowputc)
-SECTION_FUNC(text, arm64_lowputc)
- ldr x15, =IMX9_LPUART1_BASE
- early_uart_ready x15, w2
- early_uart_transmit x15, w0
- ret
+#endif /* __ARCH_ARM_SRC_IMX9_IMX9_LOWPUTC_H */
diff --git a/arch/arm64/src/imx9/imx9_lpuart.c b/arch/arm64/src/imx9/imx9_lpuart.c
index 2fa4307f4c..6743d32ae3 100644
--- a/arch/arm64/src/imx9/imx9_lpuart.c
+++ b/arch/arm64/src/imx9/imx9_lpuart.c
@@ -23,6 +23,7 @@
****************************************************************************/
#include <nuttx/config.h>
+
#include <sys/types.h>
#include <stdint.h>
#include <stdbool.h>
@@ -33,838 +34,2663 @@
#include <debug.h>
#ifdef CONFIG_SERIAL_TERMIOS
-# include <termios.h>
-#endif
+# include <termios.h>
+#endif
+
+#include <nuttx/irq.h>
+#include <nuttx/arch.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/init.h>
+#include <nuttx/power/pm.h>
+#include <nuttx/fs/ioctl.h>
+#include <nuttx/serial/serial.h>
+
+#include <arch/board/board.h>
+
+#include "arm64_internal.h"
+#include "hardware/imx9_lpuart.h"
+#include "hardware/imx9_pinmux.h"
+#include "imx9_lowputc.h"
+#include "imx9_serial.h"
+
+#if defined(SERIAL_HAVE_TXDMA) || defined(SERIAL_HAVE_RXDMA)
+# include "chip.h"
+# include "imx9_edma.h"
+# include "hardware/imx9_dmamux.h"
+#endif
+
+#ifdef USE_SERIALDRIVER
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* The DMA buffer size when using RX DMA to emulate a FIFO.
+ *
+ * When streaming data, the generic serial layer will be called every time
+ * the FIFO receives half this number of bytes.
+ *
+ * This buffer size should be an even multiple of the Cortex-A55 D-Cache line
+ * size, ARMV8M_DCACHE_LINESIZE, so that it can be individually invalidated.
+ */
+
+# if !defined(ARMV8M_DCACHE_LINESIZE) || ARMV8M_DCACHE_LINESIZE == 0
+# undef ARMV8M_DCACHE_LINESIZE
+# define ARMV8M_DCACHE_LINESIZE 64
+# endif
+
+# if !defined(CONFIG_IMX9_SERIAL_RXDMA_BUFFER_SIZE) || \
+ (CONFIG_IMX9_SERIAL_RXDMA_BUFFER_SIZE < ARMV8M_DCACHE_LINESIZE)
+# undef CONFIG_IMX9_SERIAL_RXDMA_BUFFER_SIZE
+# define CONFIG_IMX9_SERIAL_RXDMA_BUFFER_SIZE ARMV8M_DCACHE_LINESIZE
+# endif
+
+# define RXDMA_BUFFER_MASK (ARMV8M_DCACHE_LINESIZE - 1)
+# define RXDMA_BUFFER_SIZE ((CONFIG_IMX9_SERIAL_RXDMA_BUFFER_SIZE \
+ + RXDMA_BUFFER_MASK) & ~RXDMA_BUFFER_MASK)
+
+/* The DMA buffer size when using TX DMA.
+ *
+ * This TX buffer size should be an even multiple of the Cortex-A55 D-Cache
+ * line size, ARMV8M_DCACHE_LINESIZE, so that it can be individually
+ * invalidated.
+ */
+
+#define TXDMA_BUFFER_MASK (ARMV8M_DCACHE_LINESIZE - 1)
+#define TXDMA_BUFFER_SIZE ((CONFIG_IMX9_SERIAL_RXDMA_BUFFER_SIZE \
+ + RXDMA_BUFFER_MASK) & ~RXDMA_BUFFER_MASK)
+
+/* Buffers need to be aligned and multiples of ARMV8M_DCACHE_LINESIZE */
+
+#if defined(CONFIG_ARM64_DCACHE_DISABLE)
+# define TXDMA_BUF_SIZE(b) (b)
+# define TXDMA_BUF_ALIGN
+#else
+# define TXDMA_BUF_SIZE(b) (((b) + TXDMA_BUFFER_MASK) & ~TXDMA_BUFFER_MASK)
+# define TXDMA_BUF_ALIGN aligned_data(ARMV8M_DCACHE_LINESIZE);
+#endif
+
+#if !defined(CONFIG_LPUART1_TXDMA)
+# define LPUART1_TXBUFSIZE_ADJUSTED CONFIG_LPUART1_TXBUFSIZE
+# define LPUART1_TXBUFSIZE_ALGN
+#else
+# define LPUART1_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_LPUART1_TXBUFSIZE)
+# define LPUART1_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN
+#endif
+
+#if !defined(CONFIG_LPUART2_TXDMA)
+# define LPUART2_TXBUFSIZE_ADJUSTED CONFIG_LPUART2_TXBUFSIZE
+# define LPUART2_TXBUFSIZE_ALGN
+#else
+# define LPUART2_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_LPUART2_TXBUFSIZE)
+# define LPUART2_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN
+#endif
+
+#if !defined(CONFIG_LPUART3_TXDMA)
+# define LPUART3_TXBUFSIZE_ADJUSTED CONFIG_LPUART3_TXBUFSIZE
+# define LPUART3_TXBUFSIZE_ALGN
+#else
+# define LPUART3_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_LPUART3_TXBUFSIZE)
+# define LPUART3_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN
+#endif
+
+#if !defined(CONFIG_LPUART4_TXDMA)
+# define LPUART4_TXBUFSIZE_ADJUSTED CONFIG_LPUART4_TXBUFSIZE
+# define LPUART4_TXBUFSIZE_ALGN
+#else
+# define LPUART4_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_LPUART4_TXBUFSIZE)
+# define LPUART4_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN
+#endif
+
+#if !defined(CONFIG_LPUART5_TXDMA)
+# define LPUART5_TXBUFSIZE_ADJUSTED CONFIG_LPUART5_TXBUFSIZE
+# define LPUART5_TXBUFSIZE_ALGN
+#else
+# define LPUART5_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_LPUART5_TXBUFSIZE)
+# define LPUART5_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN
+#endif
+
+#if !defined(CONFIG_LPUART6_TXDMA)
+# define LPUART6_TXBUFSIZE_ADJUSTED CONFIG_LPUART6_TXBUFSIZE
+# define LPUART6_TXBUFSIZE_ALGN
+#else
+# define LPUART6_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_LPUART6_TXBUFSIZE)
+# define LPUART6_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN
+#endif
+
+#if !defined(CONFIG_LPUART7_TXDMA)
+# define LPUART7_TXBUFSIZE_ADJUSTED CONFIG_LPUART7_TXBUFSIZE
+# define LPUART7_TXBUFSIZE_ALGN
+#else
+# define LPUART7_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_LPUART7_TXBUFSIZE)
+# define LPUART7_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN
+#endif
+
+#if !defined(CONFIG_LPUART8_TXDMA)
+# define LPUART8_TXBUFSIZE_ADJUSTED CONFIG_LPUART8_TXBUFSIZE
+# define LPUART8_TXBUFSIZE_ALGN
+#else
+# define LPUART8_TXBUFSIZE_ADJUSTED TXDMA_BUF_SIZE(CONFIG_LPUART8_TXBUFSIZE)
+# define LPUART8_TXBUFSIZE_ALGN TXDMA_BUF_ALIGN
+#endif
+
+/* Which LPUART with be console? */
+
+#if defined(CONFIG_LPUART1_SERIAL_CONSOLE)
+# define CONSOLE_DEV g_lpuart1priv /* LPUART1 is console */
+# if defined(CONFIG_LPUART1_RXDMA)
+# define SERIAL_HAVE_CONSOLE_RXDMA 1
+# endif
+# if defined(CONFIG_LPUART1_TXDMA)
+# define SERIAL_HAVE_CONSOLE_TXDMA 1
+# endif
+#elif defined(CONFIG_LPUART2_SERIAL_CONSOLE)
+# define CONSOLE_DEV g_lpuart2priv /* LPUART2 is console */
+# if defined(CONFIG_LPUART2_RXDMA)
+# define SERIAL_HAVE_CONSOLE_RXDMA 1
+# endif
+# if defined(CONFIG_LPUART2_TXDMA)
+# define SERIAL_HAVE_CONSOLE_TXDMA 1
+# endif
+#elif defined(CONFIG_LPUART3_SERIAL_CONSOLE)
+# define CONSOLE_DEV g_lpuart3priv /* LPUART3 is console */
+# if defined(CONFIG_LPUART3_RXDMA)
+# define SERIAL_HAVE_CONSOLE_RXDMA 1
+# endif
+# if defined(CONFIG_LPUART3_TXDMA)
+# define SERIAL_HAVE_CONSOLE_TXDMA 1
+# endif
+#elif defined(CONFIG_LPUART4_SERIAL_CONSOLE)
+# define CONSOLE_DEV g_lpuart4priv /* LPUART4 is console */
+# if defined(CONFIG_LPUART4_RXDMA)
+# define SERIAL_HAVE_CONSOLE_RXDMA 1
+# endif
+# if defined(CONFIG_LPUART4_TXDMA)
+# define SERIAL_HAVE_CONSOLE_TXDMA 1
+# endif
+#elif defined(CONFIG_LPUART5_SERIAL_CONSOLE)
+# define CONSOLE_DEV g_lpuart5priv /* LPUART5 is console */
+# if defined(CONFIG_LPUART5_RXDMA)
+# define SERIAL_HAVE_CONSOLE_RXDMA 1
+# endif
+# if defined(CONFIG_LPUART5_TXDMA)
+# define SERIAL_HAVE_CONSOLE_TXDMA 1
+# endif
+#elif defined(CONFIG_LPUART6_SERIAL_CONSOLE)
+# define CONSOLE_DEV g_lpuart6priv /* LPUART6 is console */
+# if defined(CONFIG_LPUART6_RXDMA)
+# define SERIAL_HAVE_CONSOLE_RXDMA 1
+# endif
+# if defined(CONFIG_LPUART6_TXDMA)
+# define SERIAL_HAVE_CONSOLE_TXDMA 1
+# endif
+#elif defined(CONFIG_LPUART7_SERIAL_CONSOLE)
+# define CONSOLE_DEV g_lpuart7priv /* LPUART7 is console */
+# if defined(CONFIG_LPUART7_RXDMA)
+# define SERIAL_HAVE_CONSOLE_RXDMA 1
+# endif
+# if defined(CONFIG_LPUART7_TXDMA)
+# define SERIAL_HAVE_CONSOLE_TXDMA 1
+# endif
+#elif defined(CONFIG_LPUART8_SERIAL_CONSOLE)
+# define CONSOLE_DEV g_lpuart8priv /* LPUART8 is console */
+# if defined(CONFIG_LPUART8_RXDMA)
+# define SERIAL_HAVE_CONSOLE_RXDMA 1
+# endif
+# if defined(CONFIG_LPUART8_TXDMA)
+# define SERIAL_HAVE_CONSOLE_TXDMA 1
+# endif
+#endif
+
+#if defined(SERIAL_HAVE_CONSOLE_RXDMA) || defined(SERIAL_HAVE_CONSOLE_TXDMA)
+# define SERIAL_HAVE_CONSOLE_DMA
+#endif
+
+#ifdef CONFIG_IMX9_LPUART1
+#define TTYS0_DEV g_lpuart1priv /* LPUART1 is ttyS0 */
+#endif
+
+#ifdef CONFIG_IMX9_LPUART2
+#define TTYS1_DEV g_lpuart2priv /* LPUART2 is ttyS1 */
+#endif
+
+#ifdef CONFIG_IMX9_LPUART3
+#define TTYS2_DEV g_lpuart3priv /* LPUART3 is ttyS2 */
+#endif
+
+#ifdef CONFIG_IMX9_LPUART4
+#define TTYS3_DEV g_lpuart4priv /* LPUART4 is ttyS3 */
+#endif
+
+#ifdef CONFIG_IMX9_LPUART5
+#define TTYS4_DEV g_lpuart5priv /* LPUART5 is ttyS4 */
+#endif
+
+#ifdef CONFIG_IMX9_LPUART6
+#define TTYS5_DEV g_lpuart6priv /* LPUART6 is ttyS5 */
+#endif
+
+#ifdef CONFIG_IMX9_LPUART7
+#define TTYS6_DEV g_lpuart7priv /* LPUART7 is ttyS6 */
+#endif
+
+#ifdef CONFIG_IMX9_LPUART8
+#define TTYS7_DEV g_lpuart8priv /* LPUART8 is ttyS7 */
+#endif
+
+/* Power management definitions */
+
+#if defined(CONFIG_PM) && !defined(CONFIG_IMX9_PM_SERIAL_ACTIVITY)
+# define CONFIG_IMX9_PM_SERIAL_ACTIVITY 10
+#endif
+
+#if defined(CONFIG_PM)
+# define PM_IDLE_DOMAIN 0 /* Revisit */
+#endif
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct imx9_uart_s
+{
+ struct uart_dev_s dev; /* Generic UART device */
+ const uint32_t uartbase; /* Base address of UART registers */
+ const int uartnum; /* LPUART number 1-8 */
+ uint32_t baud; /* Configured baud */
+ uint32_t ie; /* Saved enabled interrupts */
+ uint8_t irq; /* IRQ associated with this UART */
+ uint8_t parity; /* 0=none, 1=odd, 2=even */
+ uint8_t bits; /* Number of bits (7 or 8) */
+#if defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)
+ uint8_t inviflow:1; /* Invert RTS sense */
+ const uint32_t rts_gpio; /* LPUART RTS GPIO pin configuration */
+#endif
+#ifdef CONFIG_SERIAL_OFLOWCONTROL
+ const uint32_t cts_gpio; /* LPUART CTS GPIO pin configuration */
+#endif
+ uint8_t stopbits2:1; /* 1: Configure with 2 stop bits vs 1 */
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+ uint8_t iflow:1; /* input flow control (RTS) enabled */
+#endif
+#ifdef CONFIG_SERIAL_OFLOWCONTROL
+ uint8_t oflow:1; /* output flow control (CTS) enabled */
+#endif
+#ifdef CONFIG_SERIAL_RS485CONTROL
+ uint8_t rs485mode:1; /* We are in RS485 (RTS on TX) mode */
+#endif
+ /* TX DMA state */
+
+#ifdef SERIAL_HAVE_TXDMA
+ const unsigned int txch; /* DMAMUX source of TX DMA request */
+ DMACH_HANDLE txdma; /* currently-open transmit DMA stream */
+#endif
+
+ /* RX DMA state */
+
+#ifdef SERIAL_HAVE_RXDMA
+ const unsigned int rxch; /* DMAMUX source of RX DMA request */
+ DMACH_HANDLE rxdma; /* currently-open receive DMA stream */
+ bool rxenable; /* DMA-based reception en/disable */
+ uint32_t rxdmanext; /* Next byte in the DMA buffer to be read */
+#ifndef CONFIG_ARM64_DCACHE_DISABLE
+ uint32_t rxdmaavail; /* Number of bytes available without need to
+ * to invalidate the data cache */
+#endif
+ char *const rxfifo; /* Receive DMA buffer */
+#endif
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static inline uint32_t imx9_serialin(struct imx9_uart_s *priv,
+ uint32_t offset);
+static inline void imx9_serialout(struct imx9_uart_s *priv,
+ uint32_t offset, uint32_t value);
+static inline void imx9_disableuartint(struct imx9_uart_s *priv,
+ uint32_t *ie);
+static inline void imx9_restoreuartint(struct imx9_uart_s *priv,
+ uint32_t ie);
+
+static int imx9_setup(struct uart_dev_s *dev);
+static void imx9_shutdown(struct uart_dev_s *dev);
+static int imx9_attach(struct uart_dev_s *dev);
+static void imx9_detach(struct uart_dev_s *dev);
+static int imx9_interrupt(int irq, void *context, void *arg);
+static int imx9_ioctl(struct file *filep, int cmd, unsigned long arg);
+#if !defined(SERIAL_HAVE_ONLY_RXDMA)
+static int imx9_receive(struct uart_dev_s *dev, unsigned int *status);
+static void imx9_rxint(struct uart_dev_s *dev, bool enable);
+static bool imx9_rxavailable(struct uart_dev_s *dev);
+#endif
+#if !defined(SERIAL_HAVE_ONLY_TXDMA)
+static void imx9_txint(struct uart_dev_s *dev, bool enable);
+#endif
+
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+static bool imx9_rxflowcontrol(struct uart_dev_s *dev,
+ unsigned int nbuffered, bool upper);
+#endif
+static void imx9_send(struct uart_dev_s *dev, int ch);
+
+static bool imx9_txready(struct uart_dev_s *dev);
+
+#ifdef SERIAL_HAVE_TXDMA
+static void imx9_dma_send(struct uart_dev_s *dev);
+static void imx9_dma_txint(struct uart_dev_s *dev, bool enable);
+static void imx9_dma_txavailable(struct uart_dev_s *dev);
+static void imx9_dma_txcallback(DMACH_HANDLE handle, void *arg, bool done,
+ int result);
+#endif
+
+#if defined(SERIAL_HAVE_RXDMA) || defined(SERIAL_HAVE_TXDMA)
+static int imx9_dma_setup(struct uart_dev_s *dev);
+static void imx9_dma_shutdown(struct uart_dev_s *dev);
+#endif
+
+#ifdef SERIAL_HAVE_RXDMA
+static int imx9_dma_receive(struct uart_dev_s *dev,
+ unsigned int *status);
+#ifdef CONFIG_PM
+static void imx9_dma_reenable(struct imx9_uart_s *priv);
+#endif
+static void imx9_dma_rxint(struct uart_dev_s *dev, bool enable);
+static bool imx9_dma_rxavailable(struct uart_dev_s *dev);
+
+static void imx9_dma_rxcallback(DMACH_HANDLE handle, void *arg, bool done,
+ int result);
+#endif
+
+static bool imx9_txempty(struct uart_dev_s *dev);
+
+#ifdef CONFIG_PM
+static void up_pm_notify(struct pm_callback_s *cb, int dowmin,
+ enum pm_state_e pmstate);
+static int up_pm_prepare(struct pm_callback_s *cb, int domain,
+ enum pm_state_e pmstate);
+#endif
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* Serial driver UART operations */
+
+#if !defined(SERIAL_HAVE_ONLY_TXDMA) && !defined(SERIAL_HAVE_ONLY_RXDMA)
+static const struct uart_ops_s g_lpuart_ops =
+{
+ .setup = imx9_setup,
+ .shutdown = imx9_shutdown,
+ .attach = imx9_attach,
+ .detach = imx9_detach,
+ .ioctl = imx9_ioctl,
+ .receive = imx9_receive,
+ .rxint = imx9_rxint,
+ .rxavailable = imx9_rxavailable,
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+ .rxflowcontrol = imx9_rxflowcontrol,
+#endif
+ .send = imx9_send,
+ .txint = imx9_txint,
+ .txready = imx9_txready,
+ .txempty = imx9_txempty,
+};
+#endif
+
+#if defined(SERIAL_HAVE_RXDMA) && defined(SERIAL_HAVE_TXDMA)
+static const struct uart_ops_s g_lpuart_rxtxdma_ops =
+{
+ .setup = imx9_dma_setup,
+ .shutdown = imx9_dma_shutdown,
+ .attach = imx9_attach,
+ .detach = imx9_detach,
+ .ioctl = imx9_ioctl,
+ .receive = imx9_dma_receive,
+ .rxint = imx9_dma_rxint,
+ .rxavailable = imx9_dma_rxavailable,
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+ .rxflowcontrol = imx9_rxflowcontrol,
+#endif
+ .send = imx9_send,
+ .txint = imx9_dma_txint,
+ .txready = imx9_txready,
+ .txempty = imx9_txempty,
+ .dmatxavail = imx9_dma_txavailable,
+ .dmasend = imx9_dma_send,
+};
+#endif
+
+#if !defined(SERIAL_HAVE_ONLY_DMA) && defined(SERIAL_HAVE_RXDMA)
+static const struct uart_ops_s g_lpuart_rxdma_ops =
+{
+ .setup = imx9_dma_setup,
+ .shutdown = imx9_dma_shutdown,
+ .attach = imx9_attach,
+ .detach = imx9_detach,
+ .ioctl = imx9_ioctl,
+ .receive = imx9_dma_receive,
+ .rxint = imx9_dma_rxint,
+ .rxavailable = imx9_dma_rxavailable,
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+ .rxflowcontrol = imx9_rxflowcontrol,
+#endif
+ .send = imx9_send,
+ .txint = imx9_txint,
+ .txready = imx9_txready,
+ .txempty = imx9_txempty,
+};
+#endif
+
+#if !defined(SERIAL_HAVE_ONLY_DMA) && defined(SERIAL_HAVE_TXDMA)
+static const struct uart_ops_s g_lpuart_txdma_ops =
+{
+ .setup = imx9_dma_setup,
+ .shutdown = imx9_dma_shutdown,
+ .attach = imx9_attach,
+ .detach = imx9_detach,
+ .ioctl = imx9_ioctl,
+ .receive = imx9_receive,
+ .rxint = imx9_rxint,
+ .rxavailable = imx9_rxavailable,
+ #ifdef CONFIG_SERIAL_IFLOWCONTROL
+ .rxflowcontrol = imx9_rxflowcontrol,
+ #endif
+ .send = imx9_send,
+ .txint = imx9_dma_txint,
+ .txready = imx9_txready,
+ .txempty = imx9_txempty,
+ .dmatxavail = imx9_dma_txavailable,
+ .dmasend = imx9_dma_send,
+};
+#endif
+
+/* Avoid unused warning */
+#if !defined(SERIAL_HAVE_ONLY_DMA) && defined(SERIAL_HAVE_RXDMA)
+const struct uart_ops_s *g_o0 = &g_lpuart_rxdma_ops;
+#endif
+#if !defined(SERIAL_HAVE_ONLY_DMA) && defined(SERIAL_HAVE_TXDMA)
+const struct uart_ops_s *g_o1 = &g_lpuart_txdma_ops;
+#endif
+
+/* I/O buffers */
+
+#ifdef CONFIG_LPUART1_RXDMA
+static char g_lpuart1rxfifo[RXDMA_BUFFER_SIZE]
+ aligned_data(ARMV8M_DCACHE_LINESIZE);
+#endif
+
+# ifdef CONFIG_LPUART2_RXDMA
+static char g_lpuart2rxfifo[RXDMA_BUFFER_SIZE]
+ aligned_data(ARMV8M_DCACHE_LINESIZE);
+#endif
+
+#ifdef CONFIG_LPUART3_RXDMA
+static char g_lpuart3rxfifo[RXDMA_BUFFER_SIZE]
+ aligned_data(ARMV8M_DCACHE_LINESIZE);
+#endif
+
+#ifdef CONFIG_LPUART4_RXDMA
+static char g_lpuart4rxfifo[RXDMA_BUFFER_SIZE]
+ aligned_data(ARMV8M_DCACHE_LINESIZE);
+#endif
+
+#ifdef CONFIG_LPUART5_RXDMA
+static char g_lpuart5rxfifo[RXDMA_BUFFER_SIZE]
+ aligned_data(ARMV8M_DCACHE_LINESIZE);
+#endif
+
+#ifdef CONFIG_LPUART6_RXDMA
+static char g_lpuart6rxfifo[RXDMA_BUFFER_SIZE]
+ aligned_data(ARMV8M_DCACHE_LINESIZE);
+#endif
+
+#ifdef CONFIG_LPUART7_RXDMA
+static char g_lpuart7rxfifo[RXDMA_BUFFER_SIZE]
+ aligned_data(ARMV8M_DCACHE_LINESIZE);
+#endif
+
+#ifdef CONFIG_LPUART8_RXDMA
+static char g_lpuart8rxfifo[RXDMA_BUFFER_SIZE]
+ aligned_data(ARMV8M_DCACHE_LINESIZE);
+#endif
+
+#ifdef CONFIG_IMX9_LPUART1
+static char g_lpuart1rxbuffer[CONFIG_LPUART1_RXBUFSIZE];
+static char g_lpuart1txbuffer[LPUART1_TXBUFSIZE_ADJUSTED]
+ LPUART1_TXBUFSIZE_ALGN;
+#endif
+
+#ifdef CONFIG_IMX9_LPUART2
+static char g_lpuart2rxbuffer[CONFIG_LPUART2_RXBUFSIZE];
+static char g_lpuart2txbuffer[LPUART2_TXBUFSIZE_ADJUSTED]
+ LPUART2_TXBUFSIZE_ALGN;
+#endif
+
+#ifdef CONFIG_IMX9_LPUART3
+static char g_lpuart3rxbuffer[CONFIG_LPUART3_RXBUFSIZE];
+static char g_lpuart3txbuffer[LPUART3_TXBUFSIZE_ADJUSTED]
+ LPUART3_TXBUFSIZE_ALGN;
+#endif
+
+#ifdef CONFIG_IMX9_LPUART4
+static char g_lpuart4rxbuffer[CONFIG_LPUART4_RXBUFSIZE];
+static char g_lpuart4txbuffer[LPUART4_TXBUFSIZE_ADJUSTED]
+ LPUART4_TXBUFSIZE_ALGN;
+#endif
+
+#ifdef CONFIG_IMX9_LPUART5
+static char g_lpuart5rxbuffer[CONFIG_LPUART5_RXBUFSIZE];
+static char g_lpuart5txbuffer[LPUART5_TXBUFSIZE_ADJUSTED]
+ LPUART5_TXBUFSIZE_ALGN;
+#endif
+
+#ifdef CONFIG_IMX9_LPUART6
+static char g_lpuart6rxbuffer[CONFIG_LPUART6_RXBUFSIZE];
+static char g_lpuart6txbuffer[LPUART6_TXBUFSIZE_ADJUSTED]
+ LPUART6_TXBUFSIZE_ALGN;
+#endif
+
+#ifdef CONFIG_IMX9_LPUART7
+static char g_lpuart7rxbuffer[CONFIG_LPUART7_RXBUFSIZE];
+static char g_lpuart7txbuffer[LPUART7_TXBUFSIZE_ADJUSTED]
+ LPUART7_TXBUFSIZE_ALGN;
+#endif
+
+#ifdef CONFIG_IMX9_LPUART8
+static char g_lpuart8rxbuffer[CONFIG_LPUART8_RXBUFSIZE];
+static char g_lpuart8txbuffer[LPUART8_TXBUFSIZE_ADJUSTED] \
+ LPUART8_TXBUFSIZE_ALGN;
+#endif
+
+#ifdef CONFIG_IMX9_LPUART1
+static struct imx9_uart_s g_lpuart1priv =
+{
+ .dev =
+ {
+ .recv =
+ {
+ .size = CONFIG_LPUART1_RXBUFSIZE,
+ .buffer = g_lpuart1rxbuffer,
+ },
+ .xmit =
+ {
+ .size = CONFIG_LPUART1_TXBUFSIZE,
+ .buffer = g_lpuart1txbuffer,
+ },
+# if defined(CONFIG_LPUART1_RXDMA) && defined(CONFIG_LPUART1_TXDMA)
+ .ops = &g_lpuart_rxtxdma_ops,
+# elif defined(CONFIG_LPUART1_RXDMA) && !defined(CONFIG_LPUART1_TXDMA)
+ .ops = &g_lpuart_rxdma_ops,
+# elif !defined(CONFIG_LPUART1_RXDMA) && defined(CONFIG_LPUART1_TXDMA)
+ .ops = &g_lpuart_txdma_ops,
+# else
+ .ops = &g_lpuart_ops,
+# endif
+ },
+
+ .uartbase = IMX9_LPUART1_BASE,
+ .uartnum = 1,
+ .baud = CONFIG_LPUART1_BAUD,
+ .irq = IMX9_IRQ_LPUART1,
+ .parity = CONFIG_LPUART1_PARITY,
+ .bits = CONFIG_LPUART1_BITS,
+ .stopbits2 = CONFIG_LPUART1_2STOP,
+# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART1_OFLOWCONTROL)
+ .oflow = 1,
+ .cts_gpio = GPIO_LPUART1_CTS,
+# endif
+# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART1_IFLOWCONTROL)
+ .iflow = 1,
+# endif
+# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART1_RS485RTSCONTROL)) || \
+ (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART1_IFLOWCONTROL)))
+ .rts_gpio = GPIO_LPUART1_RTS,
+# endif
+
+# if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \
+ defined(CONFIG_LPUART1_INVERTIFLOWCONTROL)
+ .inviflow = 1,
+# endif
+
+# if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART1_RS485RTSCONTROL)
+ .rs485mode = 1,
+# endif
+
+# ifdef CONFIG_LPUART1_TXDMA
+ .txch = DMA_REQUEST_MUXLPUART1TX,
+# endif
+# ifdef CONFIG_LPUART1_RXDMA
+ .rxch = DMA_REQUEST_MUXLPUART1RX,
+ .rxfifo = g_lpuart1rxfifo,
+# endif
+};
+#endif
+
+#ifdef CONFIG_IMX9_LPUART2
+static struct imx9_uart_s g_lpuart2priv =
+{
+ .dev =
+ {
+ .recv =
+ {
+ .size = CONFIG_LPUART2_RXBUFSIZE,
+ .buffer = g_lpuart2rxbuffer,
+ },
+ .xmit =
+ {
+ .size = CONFIG_LPUART2_TXBUFSIZE,
+ .buffer = g_lpuart2txbuffer,
+ },
+# if defined(CONFIG_LPUART2_RXDMA) && defined(CONFIG_LPUART2_TXDMA)
+ .ops = &g_lpuart_rxtxdma_ops,
+# elif defined(CONFIG_LPUART2_RXDMA) && !defined(CONFIG_LPUART2_TXDMA)
+ .ops = &g_lpuart_rxdma_ops,
+# elif !defined(CONFIG_LPUART2_RXDMA) && defined(CONFIG_LPUART2_TXDMA)
+ .ops = &g_lpuart_txdma_ops,
+# else
+ .ops = &g_lpuart_ops,
+# endif
+ },
+
+ .uartbase = IMX9_LPUART2_BASE,
+ .uartnum = 2,
+ .baud = CONFIG_LPUART2_BAUD,
+ .irq = IMX9_IRQ_LPUART2,
+ .parity = CONFIG_LPUART2_PARITY,
+ .bits = CONFIG_LPUART2_BITS,
+ .stopbits2 = CONFIG_LPUART2_2STOP,
+# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART2_OFLOWCONTROL)
+ .oflow = 1,
+ .cts_gpio = GPIO_LPUART2_CTS,
+# endif
+# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART2_IFLOWCONTROL)
+ .iflow = 1,
+# endif
+# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART2_RS485RTSCONTROL)) || \
+ (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART2_IFLOWCONTROL)))
+ .rts_gpio = GPIO_LPUART2_RTS,
+# endif
+
+# if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \
+ defined(CONFIG_LPUART2_INVERTIFLOWCONTROL)
+ .inviflow = 1,
+# endif
+
+# if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART2_RS485RTSCONTROL)
+ .rs485mode = 1,
+# endif
+
+# ifdef CONFIG_LPUART2_TXDMA
+ .txch = DMA_REQUEST_MUXLPUART2TX,
+# endif
+# ifdef CONFIG_LPUART2_RXDMA
+ .rxch = DMA_REQUEST_MUXLPUART2RX,
+ .rxfifo = g_lpuart2rxfifo,
+# endif
+};
+#endif
+
+#ifdef CONFIG_IMX9_LPUART3
+static struct imx9_uart_s g_lpuart3priv =
+{
+ .dev =
+ {
+ .recv =
+ {
+ .size = CONFIG_LPUART3_RXBUFSIZE,
+ .buffer = g_lpuart3rxbuffer,
+ },
+ .xmit =
+ {
+ .size = CONFIG_LPUART3_TXBUFSIZE,
+ .buffer = g_lpuart3txbuffer,
+ },
+# if defined(CONFIG_LPUART3_RXDMA) && defined(CONFIG_LPUART3_TXDMA)
+ .ops = &g_lpuart_rxtxdma_ops,
+# elif defined(CONFIG_LPUART3_RXDMA) && !defined(CONFIG_LPUART3_TXDMA)
+ .ops = &g_lpuart_rxdma_ops,
+# elif !defined(CONFIG_LPUART3_RXDMA) && defined(CONFIG_LPUART3_TXDMA)
+ .ops = &g_lpuart_txdma_ops,
+# else
+ .ops = &g_lpuart_ops,
+# endif
+ },
+
+ .uartbase = IMX9_LPUART3_BASE,
+ .uartnum = 3,
+ .baud = CONFIG_LPUART3_BAUD,
+ .irq = IMX9_IRQ_LPUART3,
+ .parity = CONFIG_LPUART3_PARITY,
+ .bits = CONFIG_LPUART3_BITS,
+ .stopbits2 = CONFIG_LPUART3_2STOP,
+# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART3_OFLOWCONTROL)
+ .oflow = 1,
+ .cts_gpio = GPIO_LPUART3_CTS,
+# endif
+# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART3_IFLOWCONTROL)
+ .iflow = 1,
+# endif
+# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART3_RS485RTSCONTROL)) || \
+ (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART3_IFLOWCONTROL)))
+ .rts_gpio = GPIO_LPUART3_RTS,
+# endif
+
+# if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \
+ defined(CONFIG_LPUART3_INVERTIFLOWCONTROL)
+ .inviflow = 1,
+# endif
+
+# if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART3_RS485RTSCONTROL)
+ .rs485mode = 1,
+# endif
+
+# ifdef CONFIG_LPUART3_TXDMA
+ .txch = DMA_REQUEST_MUXLPUART3TX,
+# endif
+# ifdef CONFIG_LPUART3_RXDMA
+ .rxch = DMA_REQUEST_MUXLPUART3RX,
+ .rxfifo = g_lpuart3rxfifo,
+# endif
+};
+#endif
+
+#ifdef CONFIG_IMX9_LPUART4
+static struct imx9_uart_s g_lpuart4priv =
+{
+ .dev =
+ {
+ .recv =
+ {
+ .size = CONFIG_LPUART4_RXBUFSIZE,
+ .buffer = g_lpuart4rxbuffer,
+ },
+ .xmit =
+ {
+ .size = CONFIG_LPUART4_TXBUFSIZE,
+ .buffer = g_lpuart4txbuffer,
+ },
+# if defined(CONFIG_LPUART4_RXDMA) && defined(CONFIG_LPUART4_TXDMA)
+ .ops = &g_lpuart_rxtxdma_ops,
+# elif defined(CONFIG_LPUART4_RXDMA) && !defined(CONFIG_LPUART4_TXDMA)
+ .ops = &g_lpuart_rxdma_ops,
+# elif !defined(CONFIG_LPUART4_RXDMA) && defined(CONFIG_LPUART4_TXDMA)
+ .ops = &g_lpuart_txdma_ops,
+# else
+ .ops = &g_lpuart_ops,
+# endif
+ },
+
+ .uartbase = IMX9_LPUART4_BASE,
+ .uartnum = 4,
+ .baud = CONFIG_LPUART4_BAUD,
+ .irq = IMX9_IRQ_LPUART4,
+ .parity = CONFIG_LPUART4_PARITY,
+ .bits = CONFIG_LPUART4_BITS,
+ .stopbits2 = CONFIG_LPUART4_2STOP,
+# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART4_OFLOWCONTROL)
+ .oflow = 1,
+ .cts_gpio = GPIO_LPUART4_CTS,
+# endif
+# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART4_IFLOWCONTROL)
+ .iflow = 1,
+# endif
+# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART4_RS485RTSCONTROL)) || \
+ (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART4_IFLOWCONTROL)))
+ .rts_gpio = GPIO_LPUART4_RTS,
+# endif
+
+# if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \
+ defined(CONFIG_LPUART4_INVERTIFLOWCONTROL)
+ .inviflow = 1,
+# endif
+
+# if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART4_RS485RTSCONTROL)
+ .rs485mode = 1,
+# endif
+
+# ifdef CONFIG_LPUART4_TXDMA
+ .txch = DMA_REQUEST_MUXLPUART4TX,
+# endif
+# ifdef CONFIG_LPUART4_RXDMA
+ .rxch = DMA_REQUEST_MUXLPUART4RX,
+ .rxfifo = g_lpuart4rxfifo,
+# endif
+};
+#endif
+
+#ifdef CONFIG_IMX9_LPUART5
+static struct imx9_uart_s g_lpuart5priv =
+{
+ .dev =
+ {
+ .recv =
+ {
+ .size = CONFIG_LPUART5_RXBUFSIZE,
+ .buffer = g_lpuart5rxbuffer,
+ },
+ .xmit =
+ {
+ .size = CONFIG_LPUART5_TXBUFSIZE,
+ .buffer = g_lpuart5txbuffer,
+ },
+# if defined(CONFIG_LPUART5_RXDMA) && defined(CONFIG_LPUART5_TXDMA)
+ .ops = &g_lpuart_rxtxdma_ops,
+# elif defined(CONFIG_LPUART5_RXDMA) && !defined(CONFIG_LPUART5_TXDMA)
+ .ops = &g_lpuart_rxdma_ops,
+# elif !defined(CONFIG_LPUART5_RXDMA) && defined(CONFIG_LPUART5_TXDMA)
+ .ops = &g_lpuart_txdma_ops,
+# else
+ .ops = &g_lpuart_ops,
+# endif
+ },
+
+ .uartbase = IMX9_LPUART5_BASE,
+ .uartnum = 5,
+ .baud = CONFIG_LPUART5_BAUD,
+ .irq = IMX9_IRQ_LPUART5,
+ .parity = CONFIG_LPUART5_PARITY,
+ .bits = CONFIG_LPUART5_BITS,
+ .stopbits2 = CONFIG_LPUART5_2STOP,
+# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART5_OFLOWCONTROL)
+ .oflow = 1,
+ .cts_gpio = GPIO_LPUART5_CTS,
+# endif
+# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART5_IFLOWCONTROL)
+ .iflow = 1,
+# endif
+# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART5_RS485RTSCONTROL)) || \
+ (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART5_IFLOWCONTROL)))
+ .rts_gpio = GPIO_LPUART5_RTS,
+# endif
+
+# if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \
+ defined(CONFIG_LPUART5_INVERTIFLOWCONTROL)
+ .inviflow = 1,
+# endif
+
+# if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART5_RS485RTSCONTROL)
+ .rs485mode = 1,
+# endif
+
+# ifdef CONFIG_LPUART5_TXDMA
+ .txch = DMA_REQUEST_MUXLPUART5TX,
+# endif
+# ifdef CONFIG_LPUART5_RXDMA
+ .rxch = DMA_REQUEST_MUXLPUART5RX,
+ .rxfifo = g_lpuart5rxfifo,
+# endif
+};
+#endif
+
+#ifdef CONFIG_IMX9_LPUART6
+static struct imx9_uart_s g_lpuart6priv =
+{
+ .dev =
+ {
+ .recv =
+ {
+ .size = CONFIG_LPUART6_RXBUFSIZE,
+ .buffer = g_lpuart6rxbuffer,
+ },
+ .xmit =
+ {
+ .size = CONFIG_LPUART6_TXBUFSIZE,
+ .buffer = g_lpuart6txbuffer,
+ },
+# if defined(CONFIG_LPUART6_RXDMA) && defined(CONFIG_LPUART6_TXDMA)
+ .ops = &g_lpuart_rxtxdma_ops,
+# elif defined(CONFIG_LPUART6_RXDMA) && !defined(CONFIG_LPUART6_TXDMA)
+ .ops = &g_lpuart_rxdma_ops,
+# elif !defined(CONFIG_LPUART6_RXDMA) && defined(CONFIG_LPUART6_TXDMA)
+ .ops = &g_lpuart_txdma_ops,
+# else
+ .ops = &g_lpuart_ops,
+# endif
+ },
+
+ .uartbase = IMX9_LPUART6_BASE,
+ .uartnum = 6,
+ .baud = CONFIG_LPUART6_BAUD,
+ .irq = IMX9_IRQ_LPUART6,
+ .parity = CONFIG_LPUART6_PARITY,
+ .bits = CONFIG_LPUART6_BITS,
+ .stopbits2 = CONFIG_LPUART6_2STOP,
+# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART6_OFLOWCONTROL)
+ .oflow = 1,
+ .cts_gpio = GPIO_LPUART6_CTS,
+# endif
+# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART6_IFLOWCONTROL)
+ .iflow = 1,
+# endif
+# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART6_RS485RTSCONTROL)) || \
+ (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART6_IFLOWCONTROL)))
+ .rts_gpio = GPIO_LPUART6_RTS,
+# endif
+
+# if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \
+ defined(CONFIG_LPUART6_INVERTIFLOWCONTROL)
+ .inviflow = 1,
+# endif
+
+# if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART6_RS485RTSCONTROL)
+ .rs485mode = 1,
+# endif
+
+# ifdef CONFIG_LPUART6_TXDMA
+ .txch = DMA_REQUEST_MUXLPUART6TX,
+# endif
+# ifdef CONFIG_LPUART6_RXDMA
+ .rxch = DMA_REQUEST_MUXLPUART6RX,
+ .rxfifo = g_lpuart6rxfifo,
+# endif
+};
+#endif
+
+#ifdef CONFIG_IMX9_LPUART7
+static struct imx9_uart_s g_lpuart7priv =
+{
+ .dev =
+ {
+ .recv =
+ {
+ .size = CONFIG_LPUART7_RXBUFSIZE,
+ .buffer = g_lpuart7rxbuffer,
+ },
+ .xmit =
+ {
+ .size = CONFIG_LPUART7_TXBUFSIZE,
+ .buffer = g_lpuart7txbuffer,
+ },
+# if defined(CONFIG_LPUART7_RXDMA) && defined(CONFIG_LPUART7_TXDMA)
+ .ops = &g_lpuart_rxtxdma_ops,
+# elif defined(CONFIG_LPUART7_RXDMA) && !defined(CONFIG_LPUART7_TXDMA)
+ .ops = &g_lpuart_rxdma_ops,
+# elif !defined(CONFIG_LPUART7_RXDMA) && defined(CONFIG_LPUART7_TXDMA)
+ .ops = &g_lpuart_txdma_ops,
+# else
+ .ops = &g_lpuart_ops,
+# endif
+ },
+
+ .uartbase = IMX9_LPUART7_BASE,
+ .uartnum = 7,
+ .baud = CONFIG_LPUART7_BAUD,
+ .irq = IMX9_IRQ_LPUART7,
+ .parity = CONFIG_LPUART7_PARITY,
+ .bits = CONFIG_LPUART7_BITS,
+ .stopbits2 = CONFIG_LPUART7_2STOP,
+# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART7_OFLOWCONTROL)
+ .oflow = 1,
+ .cts_gpio = GPIO_LPUART7_CTS,
+# endif
+# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART7_IFLOWCONTROL)
+ .iflow = 1,
+# endif
+# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART7_RS485RTSCONTROL)) || \
+ (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART7_IFLOWCONTROL)))
+ .rts_gpio = GPIO_LPUART7_RTS,
+# endif
+
+# if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \
+ defined(CONFIG_LPUART7_INVERTIFLOWCONTROL)
+ .inviflow = 1,
+# endif
+
+# if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART7_RS485RTSCONTROL)
+ .rs485mode = 1,
+# endif
+
+# ifdef CONFIG_LPUART7_TXDMA
+ .txch = DMA_REQUEST_MUXLPUART7TX,
+# endif
+# ifdef CONFIG_LPUART7_RXDMA
+ .rxch = DMA_REQUEST_MUXLPUART7RX,
+ .rxfifo = g_lpuart7rxfifo,
+# endif
+};
+#endif
+
+#ifdef CONFIG_IMX9_LPUART8
+static struct imx9_uart_s g_lpuart8priv =
+{
+ .dev =
+ {
+ .recv =
+ {
+ .size = CONFIG_LPUART8_RXBUFSIZE,
+ .buffer = g_lpuart8rxbuffer,
+ },
+ .xmit =
+ {
+ .size = CONFIG_LPUART8_TXBUFSIZE,
+ .buffer = g_lpuart8txbuffer,
+ },
+ #if defined(CONFIG_LPUART8_RXDMA) && defined(CONFIG_LPUART8_TXDMA)
+ .ops = &g_lpuart_rxtxdma_ops,
+ #elif defined(CONFIG_LPUART8_RXDMA) && !defined(CONFIG_LPUART8_TXDMA)
+ .ops = &g_lpuart_rxdma_ops,
+ #elif !defined(CONFIG_LPUART8_RXDMA) && defined(CONFIG_LPUART8_TXDMA)
+ .ops = &g_lpuart_txdma_ops,
+ #else
+ .ops = &g_lpuart_ops,
+ #endif
+ },
+
+ .uartbase = IMX9_LPUART8_BASE,
+ .uartnum = 8,
+ .baud = CONFIG_LPUART8_BAUD,
+ .irq = IMX9_IRQ_LPUART8,
+ .parity = CONFIG_LPUART8_PARITY,
+ .bits = CONFIG_LPUART8_BITS,
+ .stopbits2 = CONFIG_LPUART8_2STOP,
+# if defined(CONFIG_SERIAL_OFLOWCONTROL) && defined(CONFIG_LPUART8_OFLOWCONTROL)
+ .oflow = 1,
+ .cts_gpio = GPIO_LPUART8_CTS,
+# endif
+# if defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART8_IFLOWCONTROL)
+ .iflow = 1,
+# endif
+# if ((defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART8_RS485RTSCONTROL)) || \
+ (defined(CONFIG_SERIAL_IFLOWCONTROL) && defined(CONFIG_LPUART8_IFLOWCONTROL)))
+ .rts_gpio = GPIO_LPUART8_RTS,
+# endif
+
+# if (defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)) && \
+ defined(CONFIG_LPUART8_INVERTIFLOWCONTROL)
+ .inviflow = 1,
+# endif
+
+# if defined(CONFIG_SERIAL_RS485CONTROL) && defined(CONFIG_LPUART8_RS485RTSCONTROL)
+ .rs485mode = 1,
+# endif
+
+# ifdef CONFIG_LPUART8_TXDMA
+ .txch = DMA_REQUEST_MUXLPUART8TX,
+# endif
+# ifdef CONFIG_LPUART8_RXDMA
+ .rxch = DMA_REQUEST_MUXLPUART8RX,
+ .rxfifo = g_lpuart8rxfifo,
+# endif
+};
+#endif
+
+#ifdef CONFIG_PM
+static struct pm_callback_s g_serial_pmcb =
+{
+ .notify = up_pm_notify,
+ .prepare = up_pm_prepare,
+};
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: imx9_serialin
+ ****************************************************************************/
+
+static inline uint32_t imx9_serialin(struct imx9_uart_s *priv,
+ uint32_t offset)
+{
+ return getreg32(priv->uartbase + offset);
+}
+
+/****************************************************************************
+ * Name: imx9_serialout
+ ****************************************************************************/
+
+static inline void imx9_serialout(struct imx9_uart_s *priv,
+ uint32_t offset, uint32_t value)
+{
+ putreg32(value, priv->uartbase + offset);
+}
+
+/****************************************************************************
+ * Name: imx9_dma_nextrx
+ *
+ * Description:
+ * Returns the index into the RX FIFO where the DMA will place the next
+ * byte that it receives.
+ *
+ ****************************************************************************/
+
+#ifdef SERIAL_HAVE_RXDMA
+static int imx9_dma_nextrx(struct imx9_uart_s *priv)
+{
+ int dmaresidual = imx9_dmach_getcount(priv->rxdma);
+ DEBUGASSERT(dmaresidual <= RXDMA_BUFFER_SIZE);
+
+ return (RXDMA_BUFFER_SIZE - dmaresidual) % RXDMA_BUFFER_SIZE;
+}
+#endif
+
+/****************************************************************************
+ * Name: imx9_disableuartint
+ ****************************************************************************/
+
+static inline void imx9_disableuartint(struct imx9_uart_s *priv,
+ uint32_t *ie)
+{
+ irqstate_t flags;
+ uint32_t regval;
+
+ flags = spin_lock_irqsave(NULL);
+ regval = imx9_serialin(priv, IMX9_LPUART_CTRL_OFFSET);
+
+ /* Return the current Rx and Tx interrupt state */
+
+ if (ie != NULL)
+ {
+ *ie = regval & LPUART_ALL_INTS;
+ }
+
+ regval &= ~LPUART_ALL_INTS;
+ imx9_serialout(priv, IMX9_LPUART_CTRL_OFFSET, regval);
+ spin_unlock_irqrestore(NULL, flags);
+}
+
+/****************************************************************************
+ * Name: imx9_restoreuartint
+ ****************************************************************************/
+
+static inline void imx9_restoreuartint(struct imx9_uart_s *priv,
+ uint32_t ie)
+{
+ irqstate_t flags;
+ uint32_t regval;
+
+ /* Enable/disable any interrupts that are currently disabled but should be
+ * enabled/disabled.
+ */
+
+ flags = spin_lock_irqsave(NULL);
+ regval = imx9_serialin(priv, IMX9_LPUART_CTRL_OFFSET);
+ regval &= ~LPUART_ALL_INTS;
+ regval |= ie;
+ imx9_serialout(priv, IMX9_LPUART_CTRL_OFFSET, regval);
+ spin_unlock_irqrestore(NULL, flags);
+}
+
+/****************************************************************************
+ * Name: imx9_dma_setup
+ *
+ * Description:
+ * Configure the LPUART baud, bits, parity, etc. This method is called the
+ * first time that the serial port is opened.
+ *
+ ****************************************************************************/
+
+#if defined(SERIAL_HAVE_RXDMA) || defined(SERIAL_HAVE_TXDMA)
+static int imx9_dma_setup(struct uart_dev_s *dev)
+{
+ struct imx9_uart_s *priv = (struct imx9_uart_s *)dev;
+#if defined(SERIAL_HAVE_RXDMA)
+ struct imx9_edma_xfrconfig_s config;
+#endif
+ int result;
+
+ /* Do the basic UART setup first, unless we are the console */
+
+ if (!dev->isconsole)
+ {
+ result = imx9_setup(dev);
+ if (result != OK)
+ {
+ return result;
+ }
+ }
+
+#if defined(SERIAL_HAVE_TXDMA)
+ /* Acquire the Tx DMA channel. This should always succeed. */
+
+ if (priv->txch != 0)
+ {
+ if (priv->txdma == NULL)
+ {
+ priv->txdma = imx9_dmach_alloc(priv->txch, 0);
+ if (priv->txdma == NULL)
+ {
+ return -EBUSY;
+ }
+ }
+
+ /* Enable Tx DMA for the UART */
+
+ modifyreg32(priv->uartbase + IMX9_LPUART_BAUD_OFFSET,
+ 0, LPUART_BAUD_TDMAE);
+ }
+#endif
+
+#if defined(SERIAL_HAVE_RXDMA)
+ /* Acquire the Rx DMA channel. This should always succeed. */
+
+ if (priv->rxch != 0)
+ {
+ if (priv->rxdma == NULL)
+ {
+ priv->rxdma = imx9_dmach_alloc(priv->rxch, 0);
+
+ if (priv->rxdma == NULL)
+ {
+ return -EBUSY;
+ }
+ }
+ else
+ {
+ imx9_dmach_stop(priv->rxdma);
+ }
+
+ /* Configure for circular DMA reception into the RX FIFO */
+
+ config.saddr = priv->uartbase + IMX9_LPUART_DATA_OFFSET;
+ config.daddr = (uintptr_t)priv->rxfifo;
+ config.soff = 0;
+ config.doff = 1;
+ config.iter = RXDMA_BUFFER_SIZE;
+ config.flags = EDMA_CONFIG_LINKTYPE_LINKNONE |
+ EDMA_CONFIG_LOOPDEST |
+ EDMA_CONFIG_INTHALF |
+ EDMA_CONFIG_INTMAJOR;
+ config.ssize = EDMA_8BIT;
+ config.dsize = EDMA_8BIT;
+ config.nbytes = 1;
+#ifdef CONFIG_IMX9_EDMA_ELINK
+ config.linkch = 0;
+#endif
+
+ imx9_dmach_xfrsetup(priv->rxdma , &config);
+
+ /* Reset our DMA shadow pointer and Rx data availability count to
+ * match the address just programmed above.
+ */
+
+ priv->rxdmanext = 0;
+
+#ifndef CONFIG_ARM64_DCACHE_DISABLE
+
+ /* Make sure the rx buffer area is all invalid or clean */
+
+ up_invalidate_dcache((uintptr_t)priv->rxfifo,
+ (uintptr_t)priv->rxfifo + RXDMA_BUFFER_SIZE);
+ priv->rxdmaavail = 0;
+#endif
+
+ /* Enable receive Rx DMA for the UART */
+
+ modifyreg32(priv->uartbase + IMX9_LPUART_BAUD_OFFSET,
+ 0, LPUART_BAUD_RDMAE);
+
+ /* Enable interrupt on idle and erros */
+
+ modifyreg32(priv->uartbase + IMX9_LPUART_CTRL_OFFSET, 0,
+ LPUART_CTRL_PEIE |
+ LPUART_CTRL_FEIE |
+ LPUART_CTRL_NEIE |
+ LPUART_CTRL_ILIE);
+
+ /* Start the DMA channel, and arrange for callbacks at the half and
+ * full points in the FIFO. This ensures that we have half a FIFO
+ * worth of time to claim bytes before they are overwritten.
+ */
+
+ imx9_dmach_start(priv->rxdma, imx9_dma_rxcallback, (void *)priv);
+ }
+#endif
+
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: imx9_setup
+ *
+ * Description:
+ * Configure the UART baud, bits, parity, fifos, etc. This
+ * method is called the first time that the serial priv is
+ * opened.
+ *
+ ****************************************************************************/
+
+static int imx9_setup(struct uart_dev_s *dev)
+{
+ struct imx9_uart_s *priv = (struct imx9_uart_s *)dev;
+#ifndef CONFIG_SUPPRESS_LPUART_CONFIG
+ struct uart_config_s config =
+ {
+ 0
+ };
+
+ int ret;
+
+ /* Configure the UART */
+
+ config.baud = priv->baud; /* Configured baud */
+ config.parity = priv->parity; /* 0=none, 1=odd, 2=even */
+ config.bits = priv->bits; /* Number of bits (5-9) */
+ config.stopbits2 = priv->stopbits2; /* true: Configure with 2 stop bits instead of 1 */
+#ifdef CONFIG_SERIAL_OFLOWCONTROL
+ config.usects = priv->oflow; /* Flow control on outbound side */
+#endif
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+ /* Flow control on outbound side if not GPIO based */
+
+ if (priv->rts_gpio == 0)
+ {
+ config.userts = priv->iflow;
+ }
+
+#endif
+#ifdef CONFIG_SERIAL_RS485CONTROL
+ config.users485 = priv->rs485mode; /* Switch into RS485 mode */
+#endif
+#if defined(CONFIG_SERIAL_RS485CONTROL) || defined(CONFIG_SERIAL_IFLOWCONTROL)
+ config.invrts = priv->inviflow; /* Inversion of outbound flow control */
+#endif
+
+ ret = imx9_lpuart_configure(priv->uartbase, priv->uartnum, &config);
+
+ priv->ie = imx9_serialin(priv, IMX9_LPUART_CTRL_OFFSET) & \
+ LPUART_ALL_INTS;
+ return ret;
+
+#else
+ priv->ie = imx9_serialin(priv, IMX9_LPUART_CTRL_OFFSET) & \
+ LPUART_ALL_INTS;
+ return OK;
+#endif
+}
+
+/****************************************************************************
+ * Name: imx9_shutdown
+ *
+ * Description:
+ * Disable the UART. This method is called when the serial
+ * priv is closed
+ *
+ ****************************************************************************/
+
+static void imx9_shutdown(struct uart_dev_s *dev)
+{
+ struct imx9_uart_s *priv = (struct imx9_uart_s *)dev;
+
+ /* Disable the UART */
+
+ imx9_serialout(priv, IMX9_LPUART_GLOBAL_OFFSET, LPUART_GLOBAL_RST);
+}
+
+/****************************************************************************
+ * Name: imx9_dma_shutdown
+ *
+ * Description:
+ * Disable the LPUART. This method is called when the serial
+ * port is closed
+ *
+ ****************************************************************************/
+
+#if defined(SERIAL_HAVE_RXDMA) || defined(SERIAL_HAVE_TXDMA)
+static void imx9_dma_shutdown(struct uart_dev_s *dev)
+{
+ struct imx9_uart_s *priv = (struct imx9_uart_s *)dev;
+
+ /* Perform the normal UART shutdown */
+
+ imx9_shutdown(dev);
+
+#if defined(SERIAL_HAVE_RXDMA)
+ /* Stop the RX DMA channel */
+
+ if (priv->rxch != 0)
+ {
+ imx9_dmach_stop(priv->rxdma);
+
+ /* Release the RX DMA channel */
+
+ imx9_dmach_free(priv->rxdma);
+ priv->rxdma = NULL;
+ }
+#endif
+
+#if defined(SERIAL_HAVE_TXDMA)
+ /* Stop the TX DMA channel */
+
+ if (priv->txch != 0)
+ {
+ imx9_dmach_stop(priv->txdma);
+
+ /* Release the TX DMA channel */
+
+ imx9_dmach_free(priv->txdma);
+ priv->txdma = NULL;
+ }
+#endif
+}
+#endif
+
+/****************************************************************************
+ * Name: imx9_attach
+ *
+ * Description:
+ * Configure the UART to operation in interrupt driven mode. This method
+ * is called when the serial priv 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 supprivs multiple levels of interrupt enabling). The RX
+ * and TX interrupts are not enabled until the txint() and rxint() methods
+ * are called.
+ *
+ ****************************************************************************/
+
+static int imx9_attach(struct uart_dev_s *dev)
+{
+ struct imx9_uart_s *priv = (struct imx9_uart_s *)dev;
+ int ret;
+
+ /* Attach and enable the IRQ */
+
+ ret = irq_attach(priv->irq, imx9_interrupt, dev);
+ if (ret == OK)
+ {
+ /* Enable the interrupt (RX and TX interrupts are still disabled
+ * in the UART
+ */
+
+ up_enable_irq(priv->irq);
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: imx9_detach
+ *
+ * Description:
+ * Detach UART interrupts. This method is called when the serial priv is
+ * closed normally just before the shutdown method is called. The
+ * exception is the serial console which is never shutdown.
+ *
+ ****************************************************************************/
+
+static void imx9_detach(struct uart_dev_s *dev)
+{
+ struct imx9_uart_s *priv = (struct imx9_uart_s *)dev;
+
+ up_disable_irq(priv->irq);
+ irq_detach(priv->irq);
+}
+
+/****************************************************************************
+ * Name: imx9_interrupt (and front-ends)
+ *
+ * Description:
+ * This is the common UART interrupt handler. It will be invoked when an
+ * interrupt is received on the 'irq'. It should call uart_xmitchars or
+ * uart_recvchars to perform the appropriate data transfers. The
+ * interrupt handling logic must be able to map the 'arg' to the
+ * appropriate uart_dev_s structure in order to call these functions.
+ *
+ ****************************************************************************/
+
+static int imx9_interrupt(int irq, void *context, void *arg)
+{
+ struct uart_dev_s *dev = (struct uart_dev_s *)arg;
+ struct imx9_uart_s *priv;
+ uint32_t usr;
+ uint32_t lsr;
+ int passes = 0;
+ bool handled;
+
+ DEBUGASSERT(dev != NULL && dev != NULL);
+ priv = (struct imx9_uart_s *)dev;
+
+#if defined(CONFIG_PM) && CONFIG_IMX9_PM_SERIAL_ACTIVITY > 0
+ /* Repriv serial activity to the power management logic */
+
+ pm_activity(PM_IDLE_DOMAIN, CONFIG_IMX9_PM_SERIAL_ACTIVITY);
+#endif
+
+ /* Loop until there are no characters to be transferred or,
+ * until we have been looping for a long time.
+ */
+
+ handled = true;
+ for (passes = 0; passes < 256 && handled; passes++)
+ {
+ handled = false;
+
+ /* Get the current UART status and check for loop
+ * termination conditions
+ */
+
+ usr = imx9_serialin(priv, IMX9_LPUART_STAT_OFFSET);
+
+ /* Removed all W1C from the last sr */
+
+ lsr = usr & ~(LPUART_STAT_LBKDIF | LPUART_STAT_RXEDGIF |
+ LPUART_STAT_IDLE | LPUART_STAT_OR |
+ LPUART_STAT_NF | LPUART_STAT_FE |
+ LPUART_STAT_PF | LPUART_STAT_MA1F |
+ LPUART_STAT_MA2F);
+
+ /* Keep what we will service */
+
+ usr &= (LPUART_STAT_RDRF | LPUART_STAT_TDRE | LPUART_STAT_OR |
+ LPUART_STAT_FE | LPUART_STAT_NF | LPUART_STAT_PF |
+ LPUART_STAT_IDLE);
+
+ /* Clear serial overrun, parity and framing errors */
+
+ if ((usr & LPUART_STAT_OR) != 0)
+ {
+ imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET,
+ LPUART_STAT_OR | lsr);
+ }
+
+ if ((usr & LPUART_STAT_NF) != 0)
+ {
+ imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET,
+ LPUART_STAT_NF | lsr);
+ }
+
+ if ((usr & LPUART_STAT_PF) != 0)
+ {
+ imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET,
+ LPUART_STAT_PF | lsr);
+ }
+
+ if ((usr & LPUART_STAT_FE) != 0)
+ {
+ imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET,
+ LPUART_STAT_FE | lsr);
+ }
+
+ if ((usr & (LPUART_STAT_FE | LPUART_STAT_PF | LPUART_STAT_NF)) != 0)
+ {
+ /* Discard data */
+
+ imx9_serialin(priv, IMX9_LPUART_DATA_OFFSET);
+ }
+
+#ifdef SERIAL_HAVE_RXDMA
+ /* The line going to idle, deliver any fractions of RX data */
+
+ if ((usr & LPUART_STAT_IDLE) != 0)
+ {
+ imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET,
+ LPUART_STAT_IDLE | lsr);
+ imx9_dma_rxcallback(priv->rxdma, priv, false, LPUART_STAT_IDLE);
+ }
+#endif
+
+ /* Handle incoming, receive bytes */
+
+ if ((usr & LPUART_STAT_RDRF) != 0 &&
+ (priv->ie & LPUART_CTRL_RIE) != 0)
+ {
+ uart_recvchars(dev);
+ handled = true;
+ }
+
+ /* Handle outgoing, transmit bytes */
+
+ if ((usr & LPUART_STAT_TDRE) != 0 &&
+ (priv->ie & LPUART_CTRL_TIE) != 0)
+ {
+ uart_xmitchars(dev);
+ handled = true;
+ }
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: imx9_ioctl
+ *
+ * Description:
+ * All ioctl calls will be routed through this method
+ *
+ ****************************************************************************/
+
+static int imx9_ioctl(struct file *filep, int cmd, unsigned long arg)
+{
+#if defined(CONFIG_SERIAL_TIOCSERGSTRUCT) || defined(CONFIG_SERIAL_TERMIOS)
+ struct inode *inode = filep->f_inode;
+ struct uart_dev_s *dev = inode->i_private;
+ irqstate_t flags;
+#endif
+ int ret = OK;
+
+ switch (cmd)
+ {
+#ifdef CONFIG_SERIAL_TIOCSERGSTRUCT
+ case TIOCSERGSTRUCT:
+ {
+ struct imx9_uart_s *user = (struct imx9_uart_s *)arg;
+ if (!user)
+ {
+ ret = -EINVAL;
+ }
+ else
+ {
+ memcpy(user, dev, sizeof(struct imx9_uart_s));
+ }
+ }
+ break;
+#endif
+
+#ifdef CONFIG_SERIAL_TERMIOS
+ case TCGETS:
+ {
+ struct termios *termiosp = (struct termios *)arg;
+ struct imx9_uart_s *priv = (struct imx9_uart_s *)dev;
-#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>
+ if (!termiosp)
+ {
+ ret = -EINVAL;
+ break;
+ }
-#include "chip.h"
-#include "arm64_arch.h"
-#include "arm64_internal.h"
-#include "arm64_gic.h"
+ /* Return parity */
-#include "imx9_serial.h"
-#include "imx9_boot.h"
+ termiosp->c_cflag = ((priv->parity != 0) ? PARENB : 0) |
+ ((priv->parity == 1) ? PARODD : 0);
-#include "hardware/imx9_lpuart.h"
-#include "hardware/imx9_memorymap.h"
+ /* Return stop bits */
-#ifdef USE_SERIALDRIVER
+ termiosp->c_cflag |= (priv->stopbits2) ? CSTOPB : 0;
-/****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
+ /* Return flow control */
-/* Which UART with be tty0/console and which tty1-4? The console will
- * always be ttyS0. If there is no console then will use the lowest
- * numbered UART.
- */
+#ifdef CONFIG_SERIAL_OFLOWCONTROL
+ termiosp->c_cflag |= ((priv->oflow) ? CCTS_OFLOW : 0);
+#endif
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+ termiosp->c_cflag |= ((priv->iflow) ? CRTS_IFLOW : 0);
+#endif
+ /* Return baud */
-/* First pick the console and ttys0. This could be any of UART1-5 */
+ cfsetispeed(termiosp, priv->baud);
+
+ /* Return number of bits */
+
+ switch (priv->bits)
+ {
+ case 5:
+ termiosp->c_cflag |= CS5;
+ break;
+
+ case 6:
+ termiosp->c_cflag |= CS6;
+ break;
+
+ case 7:
+ termiosp->c_cflag |= CS7;
+ break;
+
+ default:
+ case 8:
+ termiosp->c_cflag |= CS8;
+ break;
+
+#if defined(CS9)
+ case 9:
+ termiosp->c_cflag |= CS9;
+ break;
+#endif
+ }
+ }
+ break;
-#if defined(CONFIG_UART1_SERIAL_CONSOLE)
-# define CONSOLE_DEV g_uart1port /* UART1 is console */
-# define TTYS0_DEV g_uart1port /* UART1 is ttyS0 */
-# define UART1_ASSIGNED 1
+ case TCSETS:
+ {
+ struct termios *termiosp = (struct termios *)arg;
+ struct imx9_uart_s *priv = (struct imx9_uart_s *)dev;
+ uint32_t baud;
+ uint32_t ie;
+ uint8_t parity;
+ uint8_t nbits;
+ bool stop2;
+
+ if ((!termiosp)
+#ifdef CONFIG_SERIAL_OFLOWCONTROL
+ || ((termiosp->c_cflag & CCTS_OFLOW) && (priv->cts_gpio == 0))
+#endif
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+ || ((termiosp->c_cflag & CRTS_IFLOW) && (priv->rts_gpio == 0))
#endif
+ )
+ {
+ ret = -EINVAL;
+ break;
+ }
-/* Rx DMA timeout in ms, which is used to calculate Rx ring buffer size */
-#define DMA_RX_TIMEOUT (10)
-#define UART_AUTOSUSPEND_TIMEOUT 3000
+ /* Decode baud. */
-/****************************************************************************
- * Private Types
- ****************************************************************************/
+ ret = OK;
+ baud = cfgetispeed(termiosp);
-struct imx9_uart_port_s
-{
- unsigned long iobase;
- unsigned int baud; /* Configured baud */
- unsigned int irq_num;
- unsigned int txfifo_size;
- unsigned int rxfifo_size;
- int is_console;
-};
+ /* Decode number of bits */
-static inline uint32_t imx9_read(struct imx9_uart_port_s *port, uint32_t off)
-{
- return getreg32(port->iobase + off);
-}
+ switch (termiosp->c_cflag & CSIZE)
+ {
+ case CS5:
+ nbits = 5;
+ break;
-static inline void imx9_write(struct imx9_uart_port_s *port, uint32_t val,
- uint32_t off)
-{
- putreg32(val, port->iobase + off);
-}
+ case CS6:
+ nbits = 6;
+ break;
-static int imx9_lpuart_stop_tx(struct imx9_uart_port_s *sport)
-{
- unsigned long temp;
+ case CS7:
+ nbits = 7;
+ break;
- temp = imx9_read(sport, UARTCTRL);
- temp &= ~(UARTCTRL_TIE | UARTCTRL_TCIE);
- imx9_write(sport, temp, UARTCTRL);
+ case CS8:
+ nbits = 8;
+ break;
- return 0;
-}
+#if defined(CS9)
+ case CS9:
+ nbits = 9;
+ break;
+#endif
+ default:
+ ret = -EINVAL;
+ break;
+ }
-static int imx9_lpuart_stop_rx(struct imx9_uart_port_s *sport)
-{
- unsigned long temp;
+ /* Decode parity */
- temp = imx9_read(sport, UARTCTRL);
- imx9_write(sport, temp & ~UARTCTRL_RE, UARTCTRL);
+ if ((termiosp->c_cflag & PARENB) != 0)
+ {
+ parity = (termiosp->c_cflag & PARODD) ? 1 : 2;
+ }
+ else
+ {
+ parity = 0;
+ }
- return 0;
-}
+ /* Decode stop bits */
-static int imx9_lpuart_start_tx(struct imx9_uart_port_s *sport)
-{
- unsigned long temp;
+ stop2 = (termiosp->c_cflag & CSTOPB) != 0;
- temp = imx9_read(sport, UARTCTRL);
- imx9_write(sport, temp | UARTCTRL_TIE, UARTCTRL);
+ /* Verify that all settings are valid before committing */
- return 0;
-}
+ if (ret == OK)
+ {
+ /* Commit */
-static int imx9_lpuart_start_rx(struct imx9_uart_port_s *sport)
-{
- unsigned long temp;
+ priv->baud = baud;
+ priv->parity = parity;
+ priv->bits = nbits;
+ priv->stopbits2 = stop2;
+#ifdef CONFIG_SERIAL_OFLOWCONTROL
+ priv->oflow = (termiosp->c_cflag & CCTS_OFLOW) != 0;
+#endif
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+ priv->iflow = (termiosp->c_cflag & CRTS_IFLOW) != 0;
+#endif
+ /* effect the changes immediately - note that we do not
+ * implement TCSADRAIN / TCSAFLUSH
+ */
+
+ flags = spin_lock_irqsave(NULL);
+ imx9_disableuartint(priv, &ie);
+ ret = dev->ops->setup(dev);
+
+ /* Restore the interrupt state */
+
+ imx9_restoreuartint(priv, ie);
+ priv->ie = ie;
+ spin_unlock_irqrestore(NULL, flags);
+ }
+ }
+ break;
+#endif /* CONFIG_SERIAL_TERMIOS */
- temp = imx9_read(sport, UARTCTRL);
- imx9_write(sport, temp | UARTCTRL_RE, UARTCTRL);
+#ifdef CONFIG_IMX9_LPUART_SINGLEWIRE
+ case TIOCSSINGLEWIRE:
+ {
+ uint32_t regval;
+ irqstate_t flags;
+ struct imx9_uart_s *priv = (struct imx9_uart_s *)dev;
+
+ flags = spin_lock_irqsave(NULL);
+ regval = imx9_serialin(priv, IMX9_LPUART_CTRL_OFFSET);
+
+ if ((arg & SER_SINGLEWIRE_ENABLED) != 0)
+ {
+ regval |= LPUART_CTRL_LOOPS | LPUART_CTRL_RSRC;
+ }
+ else
+ {
+ regval &= ~(LPUART_CTRL_LOOPS | LPUART_CTRL_RSRC);
+ }
+
+ imx9_serialout(priv, IMX9_LPUART_CTRL_OFFSET, regval);
+
+ spin_unlock_irqrestore(NULL, flags);
+ }
+ break;
+#endif
+
+#ifdef CONFIG_IMX9_LPUART_INVERT
+ case TIOCSINVERT:
+ {
+ uint32_t ctrl;
+ uint32_t stat;
+ uint32_t regval;
+ irqstate_t flags;
+ struct imx9_uart_s *priv = (struct imx9_uart_s *)dev;
+
+ flags = spin_lock_irqsave(NULL);
+ ctrl = imx9_serialin(priv, IMX9_LPUART_CTRL_OFFSET);
+ stat = imx9_serialin(priv, IMX9_LPUART_STAT_OFFSET);
+ regval = ctrl;
+
+ /* {R|T}XINV bit field can only be written when the receiver is
+ * disabled (RE=0).
+ */
+
+ regval &= ~LPUART_CTRL_RE;
+
+ imx9_serialout(priv, IMX9_LPUART_CTRL_OFFSET, regval);
+
+ /* Enable/disable signal inversion. */
+
+ if (arg & SER_INVERT_ENABLED_RX)
+ {
+ stat |= LPUART_STAT_RXINV;
+ }
+ else
+ {
+ stat &= ~LPUART_STAT_RXINV;
+ }
+
+ /* Do not invert TX when in TIOCSSINGLEWIRE */
+
+ if ((arg & SER_INVERT_ENABLED_TX) &&
+ ((ctrl & LPUART_CTRL_LOOPS) != LPUART_CTRL_LOOPS))
+ {
+ ctrl |= LPUART_CTRL_TXINV;
+ }
+ else
+ {
+ ctrl &= ~LPUART_CTRL_TXINV;
+ }
+
+ imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET, stat);
+ imx9_serialout(priv, IMX9_LPUART_CTRL_OFFSET, ctrl);
+
+ spin_unlock_irqrestore(NULL, flags);
+ }
+ break;
+#endif
+
+ case TIOCSBRK: /* BSD compatibility: Turn break on, unconditionally */
+ case TIOCCBRK: /* BSD compatibility: Turn break off, unconditionally */
+ default:
+ ret = -ENOTTY;
+ break;
+ }
- return 0;
+ return ret;
}
/****************************************************************************
- * Name: imx9_rxint
+ * Name: imx9_receive
*
* Description:
- * Call to enable or disable RX interrupts
+ * 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'.
*
****************************************************************************/
-static void imx9_rxint(struct uart_dev_s *dev, bool enable)
+#ifndef SERIAL_HAVE_ONLY_RXDMA
+static int imx9_receive(struct uart_dev_s *dev, unsigned int *status)
{
- struct imx9_uart_port_s *sport = (struct imx9_uart_port_s *)dev->priv;
+ struct imx9_uart_s *priv = (struct imx9_uart_s *)dev;
+ uint32_t rxd;
- if (enable)
- {
- imx9_lpuart_start_rx(sport);
- }
- else
- {
- imx9_lpuart_stop_rx(sport);
- }
+ rxd = imx9_serialin(priv, IMX9_LPUART_DATA_OFFSET);
+ *status = rxd >> LPUART_DATA_STATUS_SHIFT;
+ return (rxd & LPUART_DATA_MASK) >> LPUART_DATA_SHIFT;
}
+#endif
/****************************************************************************
- * Name: imx9_txint
+ * Name: imx9_rxint
*
* Description:
- * Call to enable or disable TX interrupts
+ * Call to enable or disable RX interrupts
*
****************************************************************************/
-static void imx9_txint(struct uart_dev_s *dev, bool enable)
+#ifndef SERIAL_HAVE_ONLY_RXDMA
+static void imx9_rxint(struct uart_dev_s *dev, bool enable)
{
- struct imx9_uart_port_s *sport = (struct imx9_uart_port_s *)dev->priv;
+ struct imx9_uart_s *priv = (struct imx9_uart_s *)dev;
+ irqstate_t flags;
+ uint32_t regval;
+ /* Enable interrupts for data available at Rx */
+
+ flags = spin_lock_irqsave(NULL);
if (enable)
{
- imx9_lpuart_start_tx(sport);
+#ifndef CONFIG_SUPPRESS_SERIAL_INTS
+ priv->ie |= LPUART_CTRL_RIE | LPUART_CTRL_FEIE | LPUART_CTRL_ORIE;
+#endif
}
else
{
- imx9_lpuart_stop_tx(sport);
+ priv->ie &= ~(LPUART_CTRL_RIE | LPUART_CTRL_FEIE | LPUART_CTRL_ORIE);
}
+
+ regval = imx9_serialin(priv, IMX9_LPUART_CTRL_OFFSET);
+ regval &= ~LPUART_ALL_INTS;
+ regval |= priv->ie;
+ imx9_serialout(priv, IMX9_LPUART_CTRL_OFFSET, regval);
+ spin_unlock_irqrestore(NULL, flags);
}
+#endif
/****************************************************************************
- * Name: imx9_send
+ * Name: imx9_rxavailable
*
* Description:
- * This method will send one byte on the UART
+ * Return true if the receive fifo is not empty
*
****************************************************************************/
-static void imx9_send(struct uart_dev_s *dev, int ch)
+#ifndef SERIAL_HAVE_ONLY_RXDMA
+static bool imx9_rxavailable(struct uart_dev_s *dev)
{
- struct imx9_uart_port_s *sport = (struct imx9_uart_port_s *)dev->priv;
+ struct imx9_uart_s *priv = (struct imx9_uart_s *)dev;
+ uint32_t regval;
- imx9_write(sport, ch, UARTDATA);
+ /* Return true is data is ready in the Rx FIFO */
+
+ regval = imx9_serialin(priv, IMX9_LPUART_STAT_OFFSET);
+ return ((regval & LPUART_STAT_RDRF) != 0);
}
+#endif
/****************************************************************************
- * Name: imx9_receive
+ * Name: imx9_rxflowcontrol
*
* 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'.
+ * Called when Rx buffer is full (or exceeds configured watermark levels
+ * if CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS is defined).
+ * Return true if UART activated RX flow control to block more incoming
+ * data
+ *
+ * Input Parameters:
+ * dev - UART device instance
+ * nbuffered - the number of characters currently buffered
+ * (if CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS is
+ * not defined the value will be 0 for an empty buffer or the
+ * defined buffer size for a full buffer)
+ * upper - true indicates the upper watermark was crossed where
+ * false indicates the lower watermark has been crossed
+ *
+ * Returned Value:
+ * true if RX flow control activated.
*
****************************************************************************/
-static int imx9_receive(struct uart_dev_s *dev, unsigned int *status)
+#ifdef CONFIG_SERIAL_IFLOWCONTROL
+static bool imx9_rxflowcontrol(struct uart_dev_s *dev,
+ unsigned int nbuffered, bool upper)
{
- struct imx9_uart_port_s *sport = (struct imx9_uart_port_s *)dev->priv;
- unsigned int rx;
- unsigned int sr;
+ struct imx9_uart_s *priv = (struct imx9_uart_s *)dev;
- /* to clear the FE, OR, NF, FE, PE flags,
- * read STAT then read DATA reg
- */
+ if (priv->iflow && (priv->rts_gpio != 0))
+ {
+ /* Assert/de-assert nRTS set it high resume/stop sending */
+
+ imx9_gpiowrite(priv->rts_gpio, upper);
+
+ if (upper)
+ {
+ /* With heavy Rx traffic, RXNE might be set and data pending.
+ * Returning 'true' in such case would cause RXNE left unhandled
+ * and causing interrupt storm. Sending end might be also be slow
+ * to react on nRTS, and returning 'true' here would prevent
+ * processing that data.
+ *
+ * Therefore, return 'false' so input data is still being processed
+ * until sending end reacts on nRTS signal and stops sending more.
+ */
+
+ return false;
+ }
+
+ return upper;
+ }
+ else
+ {
+ /* Is the RX buffer full? */
+
+ if (upper)
+ {
+ /* Disable Rx interrupt to prevent more data being from
+ * peripheral. When hardware RTS is enabled, this will
+ * prevent more data from coming in.
+ *
+ * This function is only called when UART recv buffer is full,
+ * that is: "dev->recv.head + 1 == dev->recv.tail".
+ *
+ * Logic in "uart_read" will automatically toggle Rx interrupts
+ * when buffer is read empty and thus we do not have to re-
+ * enable Rx interrupts.
+ */
+
+ uart_disablerxint(dev);
+ return true;
+ }
+
+ /* No.. The RX buffer is empty */
- sr = imx9_read(sport, UARTSTAT);
- rx = imx9_read(sport, UARTDATA);
+ else
+ {
+ /* We might leave Rx interrupt disabled if full recv buffer was
+ * read empty. Enable Rx interrupt to make sure that more input is
+ * received.
+ */
- *status = sr;
+ uart_enablerxint(dev);
+ }
+ }
- return rx;
+ return false;
}
+#endif
/****************************************************************************
- * Name: imx9_rxavailable
+ * Name: imx9_dma_receive
*
* Description:
- * Return true if the receive fifo is not empty
+ * Called (usually) from the interrupt level to receive one
+ * character from the LPUART. Error bits associated with the
+ * receipt are provided in the return 'status'.
*
****************************************************************************/
-static bool imx9_rxavailable(struct uart_dev_s *dev)
+#ifdef SERIAL_HAVE_RXDMA
+static int imx9_dma_receive(struct uart_dev_s *dev, unsigned int *status)
{
- struct imx9_uart_port_s *sport = (struct imx9_uart_port_s *)dev->priv;
- unsigned long sfifo = imx9_read(sport, UARTFIFO);
+ struct imx9_uart_s *priv = (struct imx9_uart_s *)dev;
+ uint32_t nextrx = imx9_dma_nextrx(priv);
+ int c = 0;
- if (sfifo & UARTFIFO_RXEMPT)
- {
- return false;
- }
- else
+ /* Check if more data is available */
+
+ if (nextrx != priv->rxdmanext)
{
- return true;
+#ifndef CONFIG_ARM64_DCACHE_DISABLE
+ /* If the data cache is enabled, then we will also need to manage
+ * cache coherency. Are any bytes available in the currently coherent
+ * region of the data cache?
+ */
+
+ if (priv->rxdmaavail == 0)
+ {
+ uint32_t rxdmaavail;
+ uintptr_t addr;
+
+ /* No.. then we will have to invalidate additional space in the Rx
+ * DMA buffer.
+ */
+
+ if (nextrx > priv->rxdmanext)
+ {
+ /* Number of available bytes */
+
+ rxdmaavail = nextrx - priv->rxdmanext;
+ }
+ else
+ {
+ /* Number of available bytes up to the end of RXDMA buffer */
+
+ rxdmaavail = RXDMA_BUFFER_SIZE - priv->rxdmanext;
+ }
+
+ /* Invalidate the DMA buffer range */
+
+ addr = (uintptr_t)&priv->rxfifo[priv->rxdmanext];
+ up_invalidate_dcache(addr, addr + rxdmaavail);
+
+ /* We don't need to invalidate the data cache for the next
+ * rxdmaavail number of next bytes.
+ */
+
+ priv->rxdmaavail = rxdmaavail;
+ }
+
+ priv->rxdmaavail--;
+#endif
+
+ /* Now read from the DMA buffer */
+
+ c = priv->rxfifo[priv->rxdmanext];
+
+ priv->rxdmanext++;
+
+ if (priv->rxdmanext == RXDMA_BUFFER_SIZE)
+ {
+ priv->rxdmanext = 0;
+ }
}
+
+ /* NOTE: If no data is available, then we would return NULL which is,
+ * of course, valid binary data. The protocol is that the upper half
+ * driver must call imx9_dma_rxavailable prior to calling this
+ * function to assure that this never happens.
+ */
+
+ return c;
}
+#endif
/****************************************************************************
- * Name: imx9_txready
+ * Name: imx9_dma_reenable
*
* Description:
- * Return true if the tranmsit fifo is not full
+ * Call to re-enable RX DMA.
*
****************************************************************************/
-static bool imx9_txready(struct uart_dev_s *dev)
+#if defined(SERIAL_HAVE_RXDMA) && defined(CONFIG_PM)
+static void imx9_dma_reenable(struct imx9_uart_s *priv)
{
- struct imx9_uart_port_s *sport = (struct imx9_uart_port_s *)dev->priv;
- unsigned long txcnt;
+ struct imx9_edma_xfrconfig_s config;
+
+ /* Stop an reset the RX DMA */
+
+ imx9_dmach_stop(priv->rxdma);
+
+ /* Configure for circular DMA reception into the RX FIFO */
+
+ config.saddr = priv->uartbase + IMX9_LPUART_DATA_OFFSET;
+ config.daddr = (uint32_t) priv->rxfifo;
+ config.soff = 0;
+ config.doff = 1;
+ config.iter = RXDMA_BUFFER_SIZE;
+ config.flags = EDMA_CONFIG_LINKTYPE_LINKNONE |
+ EDMA_CONFIG_LOOPDEST |
+ EDMA_CONFIG_INTHALF |
+ EDMA_CONFIG_INTMAJOR;
+ config.ssize = EDMA_8BIT;
+ config.dsize = EDMA_8BIT;
+ config.nbytes = 1;
+#ifdef CONFIG_IMX9_EDMA_ELINK
+ config.linkch = 0;
+#endif
- /* When TXFULL is set, there is no space in the Tx FIFO */
+ imx9_dmach_xfrsetup(priv->rxdma, &config);
- txcnt = imx9_read(sport, UARTWATER);
- txcnt = txcnt >> UARTWATER_TXCNT_OFF;
- txcnt &= UARTWATER_COUNT_MASK;
+ /* Reset our DMA shadow pointer and Rx data availability count to match
+ * the address just programmed above.
+ */
- if (txcnt < sport->txfifo_size)
- {
- return true;
- }
- else
- {
- return false;
- }
+ priv->rxdmanext = 0;
+#ifndef CONFIG_ARM64_DCACHE_DISABLE
+ priv->rxdmaavail = 0;
+#endif
+
+ /* Start the DMA channel, and arrange for callbacks at the half and
+ * full points in the FIFO. This ensures that we have half a FIFO
+ * worth of time to claim bytes before they are overwritten.
+ */
+
+ imx9_dmach_start(priv->rxdma, imx9_dma_rxcallback, (void *)priv);
+
+ /* Clear DMA suspended flag. */
+
+ priv->rxdmasusp = false;
}
+#endif
/****************************************************************************
- * Name: imx9_txempty
+ * Name: imx9_dma_rxint
*
* Description:
- * Return true if the transmit fifo is empty
+ * Call to enable or disable RX interrupts
*
****************************************************************************/
-static bool imx9_txempty(struct uart_dev_s *dev)
+#ifdef SERIAL_HAVE_RXDMA
+static void imx9_dma_rxint(struct uart_dev_s *dev, bool enable)
{
- struct imx9_uart_port_s *sport = (struct imx9_uart_port_s *)dev->priv;
- unsigned long stat = imx9_read(sport, UARTSTAT);
- unsigned long sfifo = imx9_read(sport, UARTFIFO);
+ struct imx9_uart_s *priv = (struct imx9_uart_s *)dev;
+
+ /* Enable/disable DMA reception.
+ *
+ * Note that it is not safe to check for available bytes and immediately
+ * pass them to uart_recvchars as that could potentially recurse back
+ * to us again. Instead, bytes must wait until the next up_dma_poll or
+ * DMA event.
+ */
- if (stat & UARTSTAT_TC && sfifo & UARTFIFO_TXEMPT)
- {
- return true;
- }
- else
- {
- return false;
- }
+ priv->rxenable = enable;
}
+#endif
/****************************************************************************
- * Name: imx9_irq_handler (and front-ends)
+ * Name: imx9_dma_rxavailable
*
* Description:
- * This is the common UART interrupt handler. It should cal
- * uart_transmitchars or uart_receivechar to perform the appropriate data
- * transfers.
+ * Return true if the receive register is not empty
*
****************************************************************************/
-static int imx9_uart_irq_handler(int irq, void *context, void *arg)
+#ifdef SERIAL_HAVE_RXDMA
+static bool imx9_dma_rxavailable(struct uart_dev_s *dev)
{
- struct uart_dev_s *dev = (struct uart_dev_s *)arg;
- struct imx9_uart_port_s *sport;
- unsigned long sts;
- unsigned long rxcount;
-
- DEBUGASSERT(dev != NULL && dev->priv != NULL);
- sport = (struct imx9_uart_port_s *)dev->priv;
-
- sts = imx9_read(sport, UARTSTAT);
- rxcount = imx9_read(sport, UARTWATER);
- rxcount = rxcount >> UARTWATER_RXCNT_OFF;
+ struct imx9_uart_s *priv = (struct imx9_uart_s *)dev;
- if (sts & UARTSTAT_RDRF || rxcount > 0)
- {
- uart_recvchars(dev);
- }
-
- if (sts & UARTSTAT_TDRE)
- {
- uart_xmitchars(dev);
- }
+ /* Compare our receive pointer to the current DMA pointer, if they
+ * do not match, then there are bytes to be received.
+ */
- imx9_write(sport, sts, UARTSTAT);
- return OK;
+ return (imx9_dma_nextrx(priv) != priv->rxdmanext);
}
+#endif
-static int imx9_lpuart_hw_reset(struct imx9_uart_port_s *sport)
-{
- if (sport->is_console)
- {
- return 0;
- }
-
- /* Toggle the reset signal to reset and release the peripheral */
+/****************************************************************************
+ * Name: imx9_dma_txcallback
+ *
+ * Description:
+ * This function clears dma buffer at complete of DMA transfer and wakes up
+ * threads waiting for space in buffer.
+ *
+ ****************************************************************************/
- putreg32(UARTGLOBAL_RST, sport->iobase + UARTGLOBAL);
- putreg32(0, sport->iobase + UARTGLOBAL);
+#ifdef SERIAL_HAVE_TXDMA
+static void imx9_dma_txcallback(DMACH_HANDLE handle, void *arg, bool done,
+ int result)
+{
+ struct imx9_uart_s *priv = (struct imx9_uart_s *)arg;
- return 0;
-}
+ /* Update 'nbytes' indicating number of bytes actually transferred by DMA.
+ * This is important to free TX buffer space by 'uart_xmitchars_done'.
+ */
-static int imx9_setup(struct uart_dev_s *dev)
-{
- irqstate_t i_flags;
- int ret;
- struct imx9_uart_port_s *sport = (struct imx9_uart_port_s *)dev->priv;
+ priv->dev.dmatx.nbytes = priv->dev.dmatx.length;
+#if CONFIG_IMX9_EDMA_NTCD > 1
+ priv->dev.dmatx.nbytes += priv->dev.dmatx.nlength;
+#endif
- i_flags = up_irq_save();
+ /* Adjust the pointers */
- ret = imx9_lpuart_hw_reset(sport);
- if (ret < 0)
- {
- serr("failed to reset hw: %d\n", ret);
- }
+ uart_xmitchars_done(&priv->dev);
- up_irq_restore(i_flags);
+ /* Send more data if available */
- return ret;
+ imx9_dma_txavailable(&priv->dev);
}
+#endif
/****************************************************************************
- * Name: imx9_shutdown
+ * Name: imx9_dma_txavailable
*
* Description:
- * Disable the UART. This method is called when the serial
- * port is closed
+ * Informs DMA that Tx data is available and is ready for transfer.
*
****************************************************************************/
-static void imx9_shutdown(struct uart_dev_s *dev)
+#ifdef SERIAL_HAVE_TXDMA
+static void imx9_dma_txavailable(struct uart_dev_s *dev)
{
- struct imx9_uart_port_s *sport = (struct imx9_uart_port_s *)dev->priv;
- unsigned long temp;
- irqstate_t i_flags;
-
- i_flags = up_irq_save();
-
- /* clear statue */
-
- temp = imx9_read(sport, UARTSTAT);
- imx9_write(sport, temp, UARTSTAT);
-
- /* disable Rx/Tx DMA */
-
- temp = imx9_read(sport, UARTBAUD);
- temp &= ~(UARTBAUD_TDMAE | UARTBAUD_RDMAE | UARTBAUD_RIDMAE);
- imx9_write(sport, temp, UARTBAUD);
+ struct imx9_uart_s *priv = (struct imx9_uart_s *)dev;
- /* disable Rx/Tx and interrupts */
+ /* Only send when the DMA is idle */
- temp = imx9_read(sport, UARTCTRL);
- temp &= ~(UARTCTRL_TE | UARTCTRL_RE | UARTCTRL_TIE |
- UARTCTRL_TCIE | UARTCTRL_RIE | UARTCTRL_ILIE |
- UARTCTRL_LOOPS);
- imx9_write(sport, temp, UARTCTRL);
- imx9_write(sport, 0, UARTMODIR);
-
- up_irq_restore(i_flags);
+ if (imx9_dmach_idle(priv->txdma) == 0)
+ {
+ uart_xmitchars_dma(dev);
+ }
}
+#endif
+
+/****************************************************************************
+ * Name: imx9_dma_send
+ *
+ * Description:
+ * Called (usually) from the interrupt level to start DMA transfer.
+ * (Re-)Configures DMA Stream updating buffer and buffer length.
+ *
+ ****************************************************************************/
-static void imx9_setup_watermark(struct imx9_uart_port_s *sport)
+#ifdef SERIAL_HAVE_TXDMA
+static void imx9_dma_send(struct uart_dev_s *dev)
{
- unsigned long val;
- unsigned long ctrl;
- unsigned long ctrl_saved;
- unsigned long rxiden_cnt;
+ struct imx9_uart_s *priv = (struct imx9_uart_s *)dev;
+ struct imx9_edma_xfrconfig_s config;
- ctrl = imx9_read(sport, UARTCTRL);
- ctrl_saved = ctrl;
- ctrl &= ~(UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_TE |
- UARTCTRL_RIE | UARTCTRL_RE);
- imx9_write(sport, ctrl, UARTCTRL);
+ /* We need to stop DMA before reconfiguration */
- /* enable FIFO mode */
+ imx9_dmach_stop(priv->txdma);
- val = imx9_read(sport, UARTFIFO);
- val |= UARTFIFO_TXFE | UARTFIFO_RXFE;
- val |= UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH;
- val &= ~(UARTFIFO_RXIDEN_MASK << UARTFIFO_RXIDEN_OFF);
- rxiden_cnt = 0;
- val |= ((rxiden_cnt & UARTFIFO_RXIDEN_MASK) << UARTFIFO_RXIDEN_OFF);
+ /* Reset the number sent */
- imx9_write(sport, val, UARTFIFO);
+ dev->dmatx.nbytes = 0;
- /* set the watermark
- * rx_watermark = 1;
+ /* Make use of setup function to update buffer and its length for next
+ * transfer
*/
- val = (1 << UARTWATER_RXWATER_OFF) | (0x0 << UARTWATER_TXWATER_OFF);
- imx9_write(sport, val, UARTWATER);
-
- /* Restore cr2 */
-
- imx9_write(sport, ctrl_saved, UARTCTRL);
-}
-
-static void imx9_setup_watermark_enable(struct imx9_uart_port_s *sport)
-{
- uint32_t temp;
+ config.iter = dev->dmatx.length;
+ config.flags = EDMA_CONFIG_LINKTYPE_LINKNONE;
+ config.ssize = EDMA_8BIT;
+ config.dsize = EDMA_8BIT;
+ config.nbytes = 1;
+ config.saddr = (uintptr_t)dev->dmatx.buffer;
+ config.daddr = priv->uartbase + IMX9_LPUART_DATA_OFFSET;
+ config.soff = 1;
+ config.doff = 0;
+#ifdef CONFIG_IMX9_EDMA_ELINK
+ config.linkch = 0;
+#endif
- imx9_setup_watermark(sport);
+ /* Flush the contents of the TX buffer into physical memory */
- temp = imx9_read(sport, UARTCTRL);
- temp |= UARTCTRL_RE | UARTCTRL_TE;
- temp |= UARTCTRL_IDLECFG << UARTCTRL_IDLECFG_OFF;
- imx9_write(sport, temp, UARTCTRL);
-}
+ up_clean_dcache((uintptr_t)dev->dmatx.buffer,
+ (uintptr_t)dev->dmatx.buffer + dev->dmatx.length);
-static void imx9_hw_disable(struct imx9_uart_port_s *sport)
-{
- unsigned long temp;
+ /* Setup first half */
- temp = imx9_read(sport, UARTCTRL);
- temp &= ~(UARTCTRL_RIE | UARTCTRL_ILIE | UARTCTRL_RE |
- UARTCTRL_TIE | UARTCTRL_TE);
- imx9_write(sport, temp, UARTCTRL);
-}
+ imx9_dmach_xfrsetup(priv->txdma, &config);
-static void imx9_configure(struct imx9_uart_port_s *sport)
-{
- unsigned long temp;
+#if CONFIG_IMX9_EDMA_NTCD > 1
+ /* Is this a split transfer? */
- temp = imx9_read(sport, UARTCTRL);
- temp |= UARTCTRL_RIE | UARTCTRL_ILIE;
- temp |= UARTCTRL_TIE;
- imx9_write(sport, temp, UARTCTRL);
-}
+ if (dev->dmatx.nbuffer)
+ {
+ config.iter = priv->dev.dmatx.nlength;
+ config.saddr = (uintptr_t)priv->dev.dmatx.nbuffer;
-static void imx9_hw_setup(struct imx9_uart_port_s *sport)
-{
- irqstate_t i_flags;
+ /* Flush the contents of the next TX buffer into physical memory */
- i_flags = up_irq_save();
+ up_clean_dcache((uintptr_t)dev->dmatx.nbuffer,
+ (uintptr_t)dev->dmatx.nbuffer + dev->dmatx.nlength);
- imx9_hw_disable(sport);
+ imx9_dmach_xfrsetup(priv->txdma, &config);
+ }
+#endif
- imx9_setup_watermark_enable(sport);
- imx9_configure(sport);
- up_enable_irq(sport->irq_num);
+ /* Start transmission with the callback on DMA completion */
- up_irq_restore(i_flags);
+ imx9_dmach_start(priv->txdma, imx9_dma_txcallback, (void *)priv);
}
+#endif
/****************************************************************************
- * Name: imx9_attach
+ * Name: imx9_send
*
* 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.
+ * This method will send one byte on the UART
*
****************************************************************************/
-static int imx9_attach(struct uart_dev_s *dev)
+static void imx9_send(struct uart_dev_s *dev, int ch)
{
- struct imx9_uart_port_s *sport = (struct imx9_uart_port_s *)dev->priv;
- int ret;
- unsigned long temp;
-
- /* determine FIFO size */
-
- temp = imx9_read(sport, UARTFIFO);
-
- sport->txfifo_size = UARTFIFO_DEPTH(
- (temp >> UARTFIFO_TXSIZE_OFF) & UARTFIFO_FIFOSIZE_MASK);
- sport->rxfifo_size = UARTFIFO_DEPTH(
- (temp >> UARTFIFO_RXSIZE_OFF) & UARTFIFO_FIFOSIZE_MASK);
-
- ret = irq_attach(sport->irq_num, imx9_uart_irq_handler, dev);
+ struct imx9_uart_s *priv = (struct imx9_uart_s *)dev;
- if (ret == OK)
- {
- imx9_hw_setup(sport);
- }
- else
+#ifdef CONSOLE_DEV
+ if (dev == &CONSOLE_DEV.dev && !dev->isconsole)
{
- sinfo("error ret=%d\n", ret);
+ return;
}
+#endif
- return ret;
+ imx9_serialout(priv, IMX9_LPUART_DATA_OFFSET, (uint32_t)ch);
}
/****************************************************************************
- * Name: imx_detach
+ * Name: imx9_dma_txint
*
* 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.
+ * Call to enable or disable TX interrupts from the UART.
*
****************************************************************************/
-static void imx9_detach(struct uart_dev_s *dev)
+#ifdef SERIAL_HAVE_TXDMA
+static void imx9_dma_txint(struct uart_dev_s *dev, bool enable)
{
- struct imx9_uart_port_s *sport = (struct imx9_uart_port_s *)dev->priv;
+ /* Nothing to do. */
- up_disable_irq(sport->irq_num);
- irq_detach(sport->irq_num);
+ /* In case of DMA transfer we do not want to make use of UART interrupts.
+ * Instead, we use DMA interrupts that are activated once during boot
+ * sequence. Furthermore we can use imx9_dma_txcallback() to handle
+ * stuff at half DMA transfer or after transfer completion (depending
+ * on the configuration).
+ */
}
+#endif
/****************************************************************************
- * Name: imx9_ioctl
+ * Name: imx9_txint
*
* Description:
- * All ioctl calls will be routed through this method
- * for current imx9 configure.
+ * Call to enable or disable TX interrupts
*
****************************************************************************/
-static int imx9_ioctl(struct file *filep, int cmd, unsigned long arg)
+#if !defined(SERIAL_HAVE_ONLY_TXDMA)
+static void imx9_txint(struct uart_dev_s *dev, bool enable)
{
-#if defined(CONFIG_SERIAL_TIOCSERGSTRUCT) || defined(CONFIG_SERIAL_TERMIOS)
- struct inode *inode = filep->f_inode;
- struct uart_dev_s *dev = inode->i_private;
- irqstate_t flags;
-#endif
- int ret = OK;
+ struct imx9_uart_s *priv = (struct imx9_uart_s *)dev;
+ irqstate_t flags;
+ uint32_t regval;
- switch (cmd)
- {
-#ifdef CONFIG_SERIAL_TIOCSERGSTRUCT
- case TIOCSERGSTRUCT:
+ /* Enable interrupt for TX complete */
+
+ flags = spin_lock_irqsave(NULL);
+ if (enable)
{
- struct imx_uart_s *user = (struct imx_uart_s *)arg;
- if (!user)
- {
- ret = -EINVAL;
- }
- else
- {
- memcpy(user, dev, sizeof(struct imx_uart_s));
- }
- }
- break;
+#ifndef CONFIG_SUPPRESS_SERIAL_INTS
+ priv->ie |= LPUART_CTRL_TIE;
#endif
-
-#ifdef CONFIG_SERIAL_TERMIOS
- case TCGETS:
+ }
+ else
{
- struct termios *termiosp = (struct termios *)arg;
- struct imx_uart_s *priv = (struct imx_uart_s *)dev->priv;
-
- if (!termiosp)
- {
- ret = -EINVAL;
- break;
- }
-
- /* Return parity */
-
- termiosp->c_cflag = ((priv->parity != 0) ? PARENB : 0) |
- ((priv->parity == 1) ? PARODD : 0);
-
- /* Return stop bits */
-
- termiosp->c_cflag |= (priv->stopbits2) ? CSTOPB : 0;
-
- /* Return flow control */
+ priv->ie &= ~LPUART_CTRL_TIE;
+ }
-#ifdef CONFIG_SERIAL_OFLOWCONTROL
- termiosp->c_cflag |= ((priv->oflow) ? CCTS_OFLOW : 0);
-#endif
-#ifdef CONFIG_SERIAL_IFLOWCONTROL
- termiosp->c_cflag |= ((priv->iflow) ? CRTS_IFLOW : 0);
+ regval = imx9_serialin(priv, IMX9_LPUART_CTRL_OFFSET);
+ regval &= ~LPUART_ALL_INTS;
+ regval |= priv->ie;
+ imx9_serialout(priv, IMX9_LPUART_CTRL_OFFSET, regval);
+ spin_unlock_irqrestore(NULL, flags);
+}
#endif
- /* Return baud */
+/****************************************************************************
+ * Name: imx9_txready
+ *
+ * Description:
+ * Return true if the transmit register is available to be written to
+ *
+ ****************************************************************************/
- cfsetispeed(termiosp, priv->baud);
+static bool imx9_txready(struct uart_dev_s *dev)
+{
+ struct imx9_uart_s *priv = (struct imx9_uart_s *)dev;
+ uint32_t regval;
- /* Return number of bits */
+ regval = imx9_serialin(priv, IMX9_LPUART_STAT_OFFSET);
+ return ((regval & LPUART_STAT_TDRE) != 0);
+}
- switch (priv->bits)
- {
- case 5:
- {
- termiosp->c_cflag |= CS5;
- break;
- }
+/****************************************************************************
+ * Name: imx9_txempty
+ *
+ * Description:
+ * Return true if the transmit reg is empty
+ *
+ ****************************************************************************/
- case 6:
- {
- termiosp->c_cflag |= CS6;
- break;
- }
+static bool imx9_txempty(struct uart_dev_s *dev)
+{
+ struct imx9_uart_s *priv = (struct imx9_uart_s *)dev;
+ uint32_t regval;
- case 7:
- {
- termiosp->c_cflag |= CS7;
- break;
- }
+ regval = imx9_serialin(priv, IMX9_LPUART_STAT_OFFSET);
+ return ((regval & LPUART_STAT_TDRE) != 0);
+}
- default:
- case 8:
- {
- termiosp->c_cflag |= CS8;
- break;
- }
+/****************************************************************************
+ * Name: imx9_dma_rxcallback
+ *
+ * Description:
+ * This function checks the current DMA state and calls the generic
+ * serial stack when bytes appear to be available.
+ *
+ ****************************************************************************/
-#if defined(CS9)
- case 9:
- {
- termiosp->c_cflag |= CS9;
- break;
- }
-#endif
- }
- }
- break;
+#ifdef SERIAL_HAVE_RXDMA
+static void imx9_dma_rxcallback(DMACH_HANDLE handle, void *arg, bool done,
+ int result)
+{
+ struct imx9_uart_s *priv = (struct imx9_uart_s *)arg;
+ uint32_t sr;
- case TCSETS:
+ if (priv->rxenable && imx9_dma_rxavailable(&priv->dev))
{
- struct termios *termiosp = (struct termios *)arg;
- struct imx_uart_s *priv = (struct imx_uart_s *)dev->priv;
- uint32_t baud;
- uint32_t ie;
- uint8_t parity;
- uint8_t nbits;
- bool stop2;
-
- if ((!termiosp)
-#ifdef CONFIG_SERIAL_OFLOWCONTROL
- || ((termiosp->c_cflag & CCTS_OFLOW) && (priv->cts_gpio == 0))
-#endif
-#ifdef CONFIG_SERIAL_IFLOWCONTROL
- || ((termiosp->c_cflag & CRTS_IFLOW) && (priv->rts_gpio == 0))
-#endif
- )
- {
- ret = -EINVAL;
- break;
- }
-
- /* Decode baud. */
-
- ret = OK;
- baud = cfgetispeed(termiosp);
+ uart_recvchars(&priv->dev);
+ }
- /* Decode number of bits */
+ /* Get the masked LPUART status word to check and clear error flags.
+ *
+ * When wake-up from low power mode was not fast enough, UART is resumed
+ * too late and sometimes exactly when character was coming over UART,
+ * resulting to frame error.
+ * If error flag is not cleared, Rx DMA will be stuck. Clearing errors
+ * will release Rx DMA.
+ */
- switch (termiosp->c_cflag & CSIZE)
- {
- case CS5:
- {
- nbits = 5;
- break;
- }
+ sr = imx9_serialin(priv, IMX9_LPUART_STAT_OFFSET);
- case CS6:
- {
- nbits = 6;
- break;
- }
+ if ((sr & (LPUART_STAT_OR | LPUART_STAT_NF | LPUART_STAT_FE)) != 0)
+ {
+ imx9_serialout(priv, IMX9_LPUART_STAT_OFFSET,
+ sr & (LPUART_STAT_OR |
+ LPUART_STAT_NF |
+ LPUART_STAT_FE));
+ }
+}
+#endif
- case CS7:
- {
- nbits = 7;
- break;
- }
+/****************************************************************************
+ * Name: up_pm_notify
+ *
+ * Description:
+ * Notify the driver of new power state. This callback is called after
+ * all drivers have had the opprivunity to prepare for the new power state.
+ *
+ * Input Parameters:
+ *
+ * cb - Returned to the driver. The driver version of the callback
+ * structure may include additional, driver-specific state data at
+ * the end of the structure.
+ *
+ * pmstate - Identifies the new PM state
+ *
+ * Returned Value:
+ * None - The driver already agreed to transition to the low power
+ * consumption state when when it returned OK to the prepare() call.
+ *
+ ****************************************************************************/
- case CS8:
+#ifdef CONFIG_PM
+static void up_pm_notify(struct pm_callback_s *cb, int domain,
+ enum pm_state_e pmstate)
+{
+ switch (pmstate)
+ {
+ case(PM_NORMAL):
{
- nbits = 8;
- break;
+ /* Logic for PM_NORMAL goes here */
}
+ break;
-#if defined(CS9)
- case CS9:
+ case(PM_IDLE):
{
- nbits = 9;
- break;
+ /* Logic for PM_IDLE goes here */
}
+ break;
-#endif
- default:
+ case(PM_STANDBY):
{
- ret = -EINVAL;
- break;
+ /* Logic for PM_STANDBY goes here */
}
- }
-
- /* Decode parity */
+ break;
- if ((termiosp->c_cflag & PARENB) != 0)
+ case(PM_SLEEP):
{
- parity = (termiosp->c_cflag & PARODD) ? 1 : 2;
+ /* Logic for PM_SLEEP goes here */
}
- else
- {
- parity = 0;
- }
-
- /* Decode stop bits */
-
- stop2 = (termiosp->c_cflag & CSTOPB) != 0;
-
- /* Verify that all settings are valid before committing */
-
- if (ret == OK)
- {
- /* Commit */
+ break;
- priv->baud = baud;
- priv->parity = parity;
- priv->bits = nbits;
- priv->stopbits2 = stop2;
-#ifdef CONFIG_SERIAL_OFLOWCONTROL
- priv->oflow = (termiosp->c_cflag & CCTS_OFLOW) != 0;
-#endif
-#ifdef CONFIG_SERIAL_IFLOWCONTROL
- priv->iflow = (termiosp->c_cflag & CRTS_IFLOW) != 0;
-#endif
-
- /* effect the changes immediately - note that we do not
- * implement TCSADRAIN / TCSAFLUSH
- */
-
- flags = spin_lock_irqsave(NULL);
- imx9_disableuartint(priv, &ie);
- ret = imx9_setup(dev);
-
- /* Restore the interrupt state */
+ default:
- imx_restoreuartint(priv, ie);
- priv->ie = ie;
- spin_unlock_irqrestore(NULL, flags);
- }
- }
- break;
-#endif /* CONFIG_SERIAL_TERMIOS */
+ /* Should not get here */
- case TIOCSBRK: /* BSD compatibility: Turn break on, unconditionally */
- case TIOCCBRK: /* BSD compatibility: Turn break off, unconditionally */
- default:
- {
- ret = -ENOTTY;
- break;
- }
+ break;
}
-
- return ret;
}
+#endif
/****************************************************************************
- * Private Data
+ * Name: up_pm_prepare
+ *
+ * Description:
+ * Request the driver to prepare for a new power state. This is a warning
+ * that the system is about to enter into a new power state. The driver
+ * should begin whatever operations that may be required to enter power
+ * state. The driver may abort the state change mode by returning a
+ * non-zero value from the callback function.
+ *
+ * Input Parameters:
+ *
+ * cb - Returned to the driver. The driver version of the callback
+ * structure may include additional, driver-specific state data at
+ * the end of the structure.
+ *
+ * pmstate - Identifies the new PM state
+ *
+ * Returned Value:
+ * Zero - (OK) means the event was successfully processed and that the
+ * driver is prepared for the PM state change.
+ *
+ * Non-zero - means that the driver is not prepared to perform the tasks
+ * needed achieve this power setting and will cause the state
+ * change to be aborted. NOTE: The prepare() method will also
+ * be called when reverting from lower back to higher power
+ * consumption modes (say because another driver refused a
+ * lower power state change). Drivers are not permitted to
+ * return non-zero values when reverting back to higher power
+ * consumption modes!
+ *
+ *
****************************************************************************/
-/* Serial driver UART operations */
-
-static const struct uart_ops_s g_uart_ops =
-{
- .setup = imx9_setup,
- .shutdown = imx9_shutdown,
- .attach = imx9_attach,
- .detach = imx9_detach,
- .ioctl = imx9_ioctl,
- .receive = imx9_receive,
- .rxint = imx9_rxint,
- .rxavailable = imx9_rxavailable,
-#ifdef CONFIG_SERIAL_IFLOWCONTROL
- .rxflowcontrol = NULL,
-#endif
- .send = imx9_send,
- .txint = imx9_txint,
- .txready = imx9_txready,
- .txempty = imx9_txempty,
-};
-
-/* I/O buffers */
-
-#ifdef CONFIG_IMX9_UART1
-static char g_uart1rxbuffer[CONFIG_UART1_RXBUFSIZE];
-static char g_uart1txbuffer[CONFIG_UART1_TXBUFSIZE];
-
-/* This describes the state of the IMX uart1 port. */
-
-static struct imx9_uart_port_s g_uart1priv =
+#ifdef CONFIG_PM
+static int up_pm_prepare(struct pm_callback_s *cb, int domain,
+ enum pm_state_e pmstate)
{
- .iobase = IMX9_LPUART1_BASE,
- .baud = CONFIG_UART1_BAUD,
- .irq_num = IMX9_IRQ_LPUART1,
- .is_console = 1,
-};
-
-static struct uart_dev_s g_uart1port =
-{
- .recv =
- {
- .size = CONFIG_UART1_RXBUFSIZE,
- .buffer = g_uart1rxbuffer,
- },
- .xmit =
- {
- .size = CONFIG_UART1_TXBUFSIZE,
- .buffer = g_uart1txbuffer,
- },
- .ops = &g_uart_ops,
- .priv = &g_uart1priv,
-};
+ /* Logic to prepare for a reduced power state goes here. */
+ return OK;
+}
#endif
/****************************************************************************
@@ -875,9 +2701,9 @@ static struct uart_dev_s g_uart1port =
* Name: arm64_earlyserialinit
*
* Description:
- * Performs the low level UART initialization early in
- * debug so that the serial console will be available
- * during bootup. This must be called before arm64_serialinit.
+ * Performs the low level UART initialization early in debug so that the
+ * serial console will be available during bootup. This must be called
+ * before arm64_serialinit.
*
****************************************************************************/
@@ -891,60 +2717,105 @@ void arm64_earlyserialinit(void)
/* Enable the console UART. The other UARTs will be initialized if and
* when they are first opened.
*/
+
#ifdef CONSOLE_DEV
- CONSOLE_DEV.isconsole = true;
- imx9_setup(&CONSOLE_DEV);
+ CONSOLE_DEV.dev.isconsole = true;
+ imx9_setup(&CONSOLE_DEV.dev);
#endif
}
/****************************************************************************
- * Name: up_putc
+ * Name: arm64_serialinit
*
* Description:
- * Provide priority, low-level access to support OS debug
- * writes
+ * Register serial console and serial privs. This assumes
+ * that imx9_earlyserialinit was called previously.
*
****************************************************************************/
-int up_putc(int ch)
+void arm64_serialinit(void)
{
- /* Check for LF */
+#ifdef CONFIG_PM
+ int ret;
- if (ch == '\n')
- {
- /* Add CR */
+ /* Register to receive power management callbacks */
- arm64_lowputc('\r');
- }
+ ret = pm_register(&g_serial_pmcb);
+ DEBUGASSERT(ret == OK);
+ UNUSED(ret);
+#endif
- arm64_lowputc((uint8_t)ch);
- return ch;
+#ifdef CONSOLE_DEV
+ uart_register("/dev/console", &CONSOLE_DEV.dev);
+#if defined(SERIAL_HAVE_CONSOLE_DMA)
+ imx9_dma_setup(&CONSOLE_DEV.dev);
+#endif
+#endif
+
+ /* Register all UARTs */
+
+#ifdef TTYS0_DEV
+ uart_register("/dev/ttyS0", &TTYS0_DEV.dev);
+#endif
+#ifdef TTYS1_DEV
+ uart_register("/dev/ttyS1", &TTYS1_DEV.dev);
+#endif
+#ifdef TTYS2_DEV
+ uart_register("/dev/ttyS2", &TTYS2_DEV.dev);
+#endif
+#ifdef TTYS3_DEV
+ uart_register("/dev/ttyS3", &TTYS3_DEV.dev);
+#endif
+#ifdef TTYS4_DEV
+ uart_register("/dev/ttyS4", &TTYS4_DEV.dev);
+#endif
+#ifdef TTYS5_DEV
+ uart_register("/dev/ttyS5", &TTYS5_DEV.dev);
+#endif
+#ifdef TTYS6_DEV
+ uart_register("/dev/ttyS6", &TTYS6_DEV.dev);
+#endif
+#ifdef TTYS7_DEV
+ uart_register("/dev/ttyS7", &TTYS7_DEV.dev);
+#endif
}
+#endif /* USE_SERIALDRIVER */
+
/****************************************************************************
- * Name: arm64_serialinit
+ * Name: up_putc
*
* Description:
- * Register serial console and serial ports. This assumes
- * that imx_earlyserialinit was called previously.
+ * Provide priority, low-level access to suppriv OS debug writes
*
****************************************************************************/
-void arm64_serialinit(void)
+int up_putc(int ch)
{
- int ret;
+#ifdef CONSOLE_DEV
+ struct imx9_uart_s *priv = (struct imx9_uart_s *)&CONSOLE_DEV;
+ uint32_t ie;
- ret = uart_register("/dev/console", &CONSOLE_DEV);
- if (ret < 0)
+ if (!CONSOLE_DEV.dev.isconsole)
{
- sinfo("error at register dev/console, ret =%d\n", ret);
+ return ch;
}
- ret = uart_register("/dev/ttyS0", &TTYS0_DEV);
- if (ret < 0)
+ imx9_disableuartint(priv, &ie);
+#endif
+
+ /* Check for LF */
+
+ if (ch == '\n')
{
- sinfo("error at register dev/ttyS0, ret =%d\n", ret);
+ /* Add CR */
+
+ arm64_lowputc('\r');
}
-}
-#endif /* USE_SERIALDRIVER */
+ arm64_lowputc(ch);
+#ifdef CONSOLE_DEV
+ imx9_restoreuartint(priv, ie);
+#endif
+ return ch;
+}
diff --git a/arch/arm64/src/imx9/imx9_serial.h b/arch/arm64/src/imx9/imx9_serial.h
index 854c6367ae..e9c175a8ce 100644
--- a/arch/arm64/src/imx9/imx9_serial.h
+++ b/arch/arm64/src/imx9/imx9_serial.h
@@ -27,70 +27,216 @@
#include <nuttx/config.h>
-#include "arm64_internal.h"
-
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
-/****************************************************************************
- * Public Types
- ****************************************************************************/
+#if defined(CONFIG_IMX9_LPUART1) || defined(CONFIG_IMX9_LPUART2) || \
+ defined(CONFIG_IMX9_LPUART3) || defined(CONFIG_IMX9_LPUART4) || \
+ defined(CONFIG_IMX9_LPUART5) || defined(CONFIG_IMX9_LPUART6) || \
+ defined(CONFIG_IMX9_LPUART7) || defined(CONFIG_IMX9_LPUART8)
+# define HAVE_UART 1
+#endif
-/****************************************************************************
- * Inline Functions
- ****************************************************************************/
+/* Assume DMA is not used on the console UART */
+
+#undef SERIAL_HAVE_CONSOLE_RXDMA
+#undef SERIAL_HAVE_CONSOLE_TXDMA
+
+#if !defined(HAVE_UART) || !defined(CONFIG_ARCH_DMA)
+# undef CONFIG_LPUART1_RXDMA
+# undef CONFIG_LPUART1_TXDMA
+# undef CONFIG_LPUART2_RXDMA
+# undef CONFIG_LPUART2_TXDMA
+# undef CONFIG_LPUART3_RXDMA
+# undef CONFIG_LPUART3_TXDMA
+# undef CONFIG_LPUART4_RXDMA
+# undef CONFIG_LPUART4_TXDMA
+# undef CONFIG_LPUART5_RXDMA
+# undef CONFIG_LPUART5_TXDMA
+# undef CONFIG_LPUART6_RXDMA
+# undef CONFIG_LPUART6_TXDMA
+# undef CONFIG_LPUART7_RXDMA
+# undef CONFIG_LPUART7_TXDMA
+# undef CONFIG_LPUART8_RXDMA
+# undef CONFIG_LPUART8_TXDMA
+#endif
-#ifndef __ASSEMBLY__
+/* Disable the DMA configuration on all unused LPUARTs */
-/****************************************************************************
- * Public Data
- ****************************************************************************/
+#ifndef CONFIG_IMX9_LPUART1
+# undef CONFIG_LPUART1_RXDMA
+# undef CONFIG_LPUART1_TXDMA
+#endif
+
+#ifndef CONFIG_IMX9_LPUART2
+# undef CONFIG_LPUART2_RXDMA
+# undef CONFIG_LPUART2_TXDMA
+#endif
+
+#ifndef CONFIG_IMX9_LPUART3
+# undef CONFIG_LPUART3_RXDMA
+# undef CONFIG_LPUART3_TXDMA
+#endif
+
+#ifndef CONFIG_IMX9_LPUART4
+# undef CONFIG_LPUART4_RXDMA
+# undef CONFIG_LPUART4_TXDMA
+#endif
+
+#ifndef CONFIG_IMX9_LPUART5
+# undef CONFIG_LPUART5_RXDMA
+# undef CONFIG_LPUART5_TXDMA
+#endif
+
+#ifndef CONFIG_IMX9_LPUART6
+# undef CONFIG_LPUART6_RXDMA
+# undef CONFIG_LPUART6_TXDMA
+#endif
+
+#ifndef CONFIG_IMX9_LPUART8
+# undef CONFIG_LPUART7_RXDMA
+# undef CONFIG_LPUART7_TXDMA
+#endif
+
+/* Is RX DMA available on any (enabled) LPUART? */
+
+#undef SERIAL_HAVE_RXDMA
+#if defined(CONFIG_LPUART1_RXDMA) || defined(CONFIG_LPUART2_RXDMA) || \
+ defined(CONFIG_LPUART3_RXDMA) || defined(CONFIG_LPUART4_RXDMA) || \
+ defined(CONFIG_LPUART5_RXDMA) || defined(CONFIG_LPUART6_RXDMA) || \
+ defined(CONFIG_LPUART7_RXDMA) || defined(CONFIG_LPUART8_RXDMA)
+# define SERIAL_HAVE_RXDMA 1
+#endif
+
+/* Is TX DMA available on any (enabled) LPUART? */
+#undef SERIAL_HAVE_TXDMA
+#if defined(CONFIG_LPUART1_TXDMA) || defined(CONFIG_LPUART2_TXDMA) || \
+ defined(CONFIG_LPUART3_TXDMA) || defined(CONFIG_LPUART4_TXDMA) || \
+ defined(CONFIG_LPUART5_TXDMA) || defined(CONFIG_LPUART6_TXDMA) || \
+ defined(CONFIG_LPUART7_TXDMA) || defined(CONFIG_LPUART8_TXDMA)
+# define SERIAL_HAVE_TXDMA 1
+#endif
+
+/* Is RX DMA used on all (enabled) LPUARTs */
+
+#define SERIAL_HAVE_ONLY_RXDMA 1
+#if defined(CONFIG_IMX9_LPUART1) && !defined(CONFIG_LPUART1_RXDMA)
+# undef SERIAL_HAVE_ONLY_RXDMA
+#elif defined(CONFIG_IMX9_LPUART2) && !defined(CONFIG_LPUART2_RXDMA)
+# undef SERIAL_HAVE_ONLY_RXDMA
+#elif defined(CONFIG_IMX9_LPUART3) && !defined(CONFIG_LPUART3_RXDMA)
+# undef SERIAL_HAVE_ONLY_RXDMA
+#elif defined(CONFIG_IMX9_LPUART4) && !defined(CONFIG_LPUART4_RXDMA)
+# undef SERIAL_HAVE_ONLY_RXDMA
+#elif defined(CONFIG_IMX9_LPUART5) && !defined(CONFIG_LPUART5_RXDMA)
+# undef SERIAL_HAVE_ONLY_RXDMA
+#elif defined(CONFIG_IMX9_LPUART6) && !defined(CONFIG_LPUART6_RXDMA)
+# undef SERIAL_HAVE_ONLY_RXDMA
+#elif defined(CONFIG_IMX9_LPUART7) && !defined(CONFIG_LPUART7_RXDMA)
+# undef SERIAL_HAVE_ONLY_RXDMA
+#elif defined(CONFIG_IMX9_LPUART8) && !defined(CONFIG_LPUART8_RXDMA)
+# undef SERIAL_HAVE_ONLY_RXDMA
+#endif
+
+/* Is TX DMA used on all (enabled) LPUARTs */
+
+#define SERIAL_HAVE_ONLY_TXDMA 1
+#if defined(CONFIG_IMX9_LPUART1) && !defined(CONFIG_LPUART1_TXDMA)
+# undef SERIAL_HAVE_ONLY_TXDMA
+#elif defined(CONFIG_IMX9_LPUART2) && !defined(CONFIG_LPUART2_TXDMA)
+# undef SERIAL_HAVE_ONLY_TXDMA
+#elif defined(CONFIG_IMX9_LPUART3) && !defined(CONFIG_LPUART3_TXDMA)
+# undef SERIAL_HAVE_ONLY_TXDMA
+#elif defined(CONFIG_IMX9_LPUART4) && !defined(CONFIG_LPUART4_TXDMA)
+# undef SERIAL_HAVE_ONLY_TXDMA
+#elif defined(CONFIG_IMX9_LPUART5) && !defined(CONFIG_LPUART5_TXDMA)
+# undef SERIAL_HAVE_ONLY_TXDMA
+#elif defined(CONFIG_IMX9_LPUART6) && !defined(CONFIG_LPUART6_TXDMA)
+# undef SERIAL_HAVE_ONLY_TXDMA
+#elif defined(CONFIG_IMX9_LPUART7) && !defined(CONFIG_LPUART7_TXDMA)
+# undef SERIAL_HAVE_ONLY_TXDMA
+#elif defined(CONFIG_IMX9_LPUART8) && !defined(CONFIG_LPUART8_TXDMA)
+# undef SERIAL_HAVE_ONLY_TXDMA
+#endif
+
+#undef SERIAL_HAVE_ONLY_DMA
+#if defined(SERIAL_HAVE_ONLY_RXDMA) && defined(SERIAL_HAVE_ONLY_TXDMA)
+#define SERIAL_HAVE_ONLY_DMA
+#endif
+
+/* Verify that DMA has been enabled and the DMA channel has been defined.
+ */
+
+#if defined(SERIAL_HAVE_TXDMA) || defined(SERIAL_HAVE_RXDMA)
+# ifndef CONFIG_IMX9_EDMA
+# error IMXRT LPUART receive or transmit DMA requires CONFIG_IMX9_EDMA
+# endif
+#endif
+
+#if defined(SERIAL_HAVE_RXDMA)
+/* Currently RS-485 support cannot be enabled when RXDMA is in use due to
+ * lack of testing.
+ */
+
+# if (defined(CONFIG_LPUART1_RXDMA) && defined(CONFIG_LPUART1_RS485)) || \
+ (defined(CONFIG_LPUART2_RXDMA) && defined(CONFIG_LPUART2_RS485)) || \
+ (defined(CONFIG_LPUART3_RXDMA) && defined(CONFIG_LPUART3_RS485)) || \
+ (defined(CONFIG_LPUART4_RXDMA) && defined(CONFIG_LPUART4_RS485)) || \
+ (defined(CONFIG_LPUART5_RXDMA) && defined(CONFIG_LPUART5_RS485)) || \
+ (defined(CONFIG_LPUART6_RXDMA) && defined(CONFIG_LPUART6_RS485)) || \
+ (defined(CONFIG_LPUART7_RXDMA) && defined(CONFIG_LPUART7_RS485)) || \
+ (defined(CONFIG_LPUART8_RXDMA) && defined(CONFIG_LPUART8_RS485))
+# error "RXDMA and RS-485 cannot be enabled at the same time for the same LPUART"
+# endif
+#endif /* SERIAL_HAVE_RXDMA */
+
+/* Currently RS-485 support cannot be enabled when TXDMA is in use due to
+ * lack of testing.
+ */
+
+# if (defined(CONFIG_LPUART1_TXDMA) && defined(CONFIG_LPUART1_RS485)) || \
+ (defined(CONFIG_LPUART2_TXDMA) && defined(CONFIG_LPUART2_RS485)) || \
+ (defined(CONFIG_LPUART3_TXDMA) && defined(CONFIG_LPUART3_RS485)) || \
+ (defined(CONFIG_LPUART4_TXDMA) && defined(CONFIG_LPUART4_RS485)) || \
+ (defined(CONFIG_LPUART5_TXDMA) && defined(CONFIG_LPUART5_RS485)) || \
+ (defined(CONFIG_LPUART6_TXDMA) && defined(CONFIG_LPUART6_RS485)) || \
+ (defined(CONFIG_LPUART7_TXDMA) && defined(CONFIG_LPUART7_RS485)) || \
+ (defined(CONFIG_LPUART8_TXDMA) && defined(CONFIG_LPUART8_RS485))
+# error "TXDMA and RS-485 cannot be enabled at the same time for the same LPUART"
+#endif
/****************************************************************************
- * Public Function Prototypes
+ * Public Types
****************************************************************************/
/****************************************************************************
- * Name: imx_earlyserialinit
- *
- * Description:
- * Performs the low level UART initialization early in debug so that the
- * serial console will be available during bootup. This must be called
- * before arm_serialinit.
- *
+ * Inline Functions
****************************************************************************/
-#ifdef USE_EARLYSERIALINIT
-void imx9_earlyserialinit(void);
-#endif
+#ifndef __ASSEMBLY__
/****************************************************************************
- * Name: uart_earlyserialinit
- *
- * Description:
- * Performs the low level UART initialization early in debug so that the
- * serial console will be available during bootup. This must be called
- * before arm_serialinit.
- *
+ * Public Data
****************************************************************************/
-#if defined(USE_EARLYSERIALINIT) && defined(IMX9_HAVE_UART)
-void uart_earlyserialinit(void);
+#undef EXTERN
+#if defined(__cplusplus)
+#define EXTERN extern "C"
+extern "C"
+{
+#else
+#define EXTERN extern
#endif
/****************************************************************************
- * Name: uart_serialinit
- *
- * Description:
- * Register the UART serial console and serial ports. This assumes that
- * uart_earlyserialinit was called previously.
- *
+ * Public Function Prototypes
****************************************************************************/
-#ifdef IMX9_HAVE_UART
-void uart_serialinit(void);
+#undef EXTERN
+#if defined(__cplusplus)
+}
#endif
#endif /* __ASSEMBLY__ */
-#endif /* __ARCH_ARM_SRC_IMX9_IMX_SERIAL_H */
+#endif /* __ARCH_ARM64_SRC_IMX9_IMX9_SERIAL_H */
diff --git a/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig b/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig
index 64c7f53357..b4ae81e0a0 100644
--- a/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig
+++ b/boards/arm64/imx9/imx93-evk/configs/nsh/defconfig
@@ -36,12 +36,13 @@ CONFIG_IMX9_GPIO_IRQ=y
CONFIG_IMX9_LPI2C1=y
CONFIG_IMX9_LPI2C_DYNTIMEO=y
CONFIG_IMX9_LPI2C_DYNTIMEO_STARTSTOP=10
+CONFIG_IMX9_LPUART1=y
CONFIG_IMX9_TPM3_PWM=y
CONFIG_IMX9_TPM3_PWM_CHMUX=0x00000003
-CONFIG_IMX9_UART1=y
CONFIG_IMX9_USBDEV_USBC1=y
CONFIG_INIT_ENTRYPOINT="nsh_main"
CONFIG_INTELHEX_BINARY=y
+CONFIG_LPUART1_SERIAL_CONSOLE=y
CONFIG_NSH_ARCHINIT=y
CONFIG_NSH_BUILTIN_APPS=y
CONFIG_NSH_FILEIOSIZE=512
@@ -71,4 +72,3 @@ CONFIG_SYSTEM_SYSTEM=y
CONFIG_SYSTEM_TIME64=y
CONFIG_TESTING_GETPRIME=y
CONFIG_TESTING_OSTEST=y
-CONFIG_UART1_SERIAL_CONSOLE=y
diff --git a/boards/arm64/imx9/imx93-evk/include/board.h b/boards/arm64/imx9/imx93-evk/include/board.h
index 6cd4c26e56..37d46536ec 100644
--- a/boards/arm64/imx9/imx93-evk/include/board.h
+++ b/boards/arm64/imx9/imx93-evk/include/board.h
@@ -33,6 +33,11 @@
#define IOMUX_LPI2C_DEFAULT (IOMUXC_PAD_OD_ENABLE | IOMUXC_PAD_FSEL_SFAST | IOMUXC_PAD_DSE_X6)
+/* UART pin muxings */
+
+#define MUX_LPUART1_RX IOMUX_CFG(IOMUXC_PAD_UART1_RXD_LPUART1_RX, 0, IOMUXC_MUX_SION_ON)
+#define MUX_LPUART1_TX IOMUX_CFG(IOMUXC_PAD_UART1_TXD_LPUART1_TX, IOMUXC_PAD_FSEL_SLOW | IOMUXC_PAD_DSE_X4, 0)
+
/* FLEXIO to PWM pin muxings */
/* EVK signals
@@ -47,6 +52,8 @@
#define FLEXIO1_PWM2_MUX IOMUX_CFG(IOMUXC_PAD_GPIO_IO06_FLEXIO1_FLEXIO06, IOMUXC_PAD_FSEL_SFAST | IOMUXC_PAD_DSE_X6, 0)
#define FLEXIO1_PWM3_MUX IOMUX_CFG(IOMUXC_PAD_GPIO_IO07_FLEXIO1_FLEXIO07, IOMUXC_PAD_FSEL_SFAST | IOMUXC_PAD_DSE_X6, 0)
+/* LPI2Cs */
+
/* TPM3 ch3 to PWM pin GPIO_IO24 muxing */
#define TPM3_PWM3_MUX IOMUX_CFG(IOMUXC_PAD_GPIO_IO24_TPM3_CH3, IOMUXC_PAD_FSEL_SFAST | IOMUXC_PAD_DSE_X6, 0)