* [PATCH 00/13] Add DMA support for LINFlexD UART driver
@ 2026-02-16 15:01 Larisa Grigore
2026-02-16 15:01 ` [PATCH 01/13] serial: linflexuart: Fix locking in set_termios Larisa Grigore
` (13 more replies)
0 siblings, 14 replies; 34+ messages in thread
From: Larisa Grigore @ 2026-02-16 15:01 UTC (permalink / raw)
To: gregkh, jirislaby, robh, krzk+dt, conor+dt, sumit.semwal,
christian.koenig, chester62515, cosmin.stoica, adrian.nitu,
stefan-gabriel.mirea, Mihaela.Martinas
Cc: linux-kernel, linux-serial, devicetree, linux-media, dri-devel,
linaro-mm-sig, s32, imx, clizzi, aruizrui, eballetb, echanude,
jkangas, Larisa Grigore
This patchset enhances the LINFlexD UART driver and its device tree bindings to
support DMA transfers, configurable clock inputs, dynamic baudrate changes, and
termios features. It also includes a series of fixes and improvements to ensure
reliable operation across various modes and configurations.
The changes added can be summarized as follows:
1. Fixes with respect to FIFO handling, locking, interrupt related registers and
INITM mode transition.
2. Removal of the earlycon workaround, as proper FIFO handling and INITM
transitions now ensure stable behavior.
3. Support for configurable stop bits and dynamic baudrate changes based on
clock inputs and termios settings.
4. Optional DMA support for RX and TX paths, preventing character loss during
high-throughput operations like copy-paste. Cyclic DMA is used for RX to avoid
gaps between transactions.
Larisa Grigore (8):
serial: linflexuart: Clean SLEEP bit in LINCR1 after suspend
serial: linflexuart: Check FIFO full before writing
serial: linflexuart: Correctly clear UARTSR in buffer mode
serial: linflexuart: Update RXEN/TXEN outside INITM mode
serial: linflexuart: Ensure FIFO is empty when entering INITM
serial: linflexuart: Revert earlycon workaround
serial: linflexuart: Add support for configurable stop bits
serial: linflexuart: Add DMA support
Radu Pirea (5):
serial: linflexuart: Fix locking in set_termios
dt-bindings: serial: fsl-linflexuart: add clock input properties
dt-bindings: serial: fsl-linflexuart: add dma properties
serial: linflexuart: Add support for changing baudrate
serial: linflexuart: Avoid stopping DMA during receive operations
.../bindings/serial/fsl,s32-linflexuart.yaml | 31 +
drivers/tty/serial/fsl_linflexuart.c | 972 +++++++++++++++---
2 files changed, 846 insertions(+), 157 deletions(-)
--
2.47.0
^ permalink raw reply [flat|nested] 34+ messages in thread
* [PATCH 01/13] serial: linflexuart: Fix locking in set_termios
2026-02-16 15:01 [PATCH 00/13] Add DMA support for LINFlexD UART driver Larisa Grigore
@ 2026-02-16 15:01 ` Larisa Grigore
2026-02-16 20:16 ` Frank Li
2026-02-16 15:01 ` [PATCH 02/13] serial: linflexuart: Clean SLEEP bit in LINCR1 after suspend Larisa Grigore
` (12 subsequent siblings)
13 siblings, 1 reply; 34+ messages in thread
From: Larisa Grigore @ 2026-02-16 15:01 UTC (permalink / raw)
To: gregkh, jirislaby, robh, krzk+dt, conor+dt, sumit.semwal,
christian.koenig, chester62515, cosmin.stoica, adrian.nitu,
stefan-gabriel.mirea, Mihaela.Martinas
Cc: linux-kernel, linux-serial, devicetree, linux-media, dri-devel,
linaro-mm-sig, s32, imx, clizzi, aruizrui, eballetb, echanude,
jkangas, Radu Pirea, Larisa Grigore
From: Radu Pirea <radu-nicolae.pirea@nxp.com>
Take the port->lock when set_termios is called, otherwise if characters
are sent while IP is in init mode, the IP will hang in an uncertain
state.
Fixes: 09864c1cdf5c ("tty: serial: Add linflexuart driver for S32V234")
Signed-off-by: Radu Pirea <radu-nicolae.pirea@nxp.com>
Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
---
drivers/tty/serial/fsl_linflexuart.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c
index e70a56de1fce..5a410e2d56ac 100644
--- a/drivers/tty/serial/fsl_linflexuart.c
+++ b/drivers/tty/serial/fsl_linflexuart.c
@@ -407,6 +407,8 @@ linflex_set_termios(struct uart_port *port, struct ktermios *termios,
unsigned long cr, old_cr, cr1;
unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
+ uart_port_lock_irqsave(port, &flags);
+
cr = readl(port->membase + UARTCR);
old_cr = cr;
@@ -475,8 +477,6 @@ linflex_set_termios(struct uart_port *port, struct ktermios *termios,
cr &= ~LINFLEXD_UARTCR_PCE;
}
- uart_port_lock_irqsave(port, &flags);
-
port->read_status_mask = 0;
if (termios->c_iflag & INPCK)
--
2.47.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 02/13] serial: linflexuart: Clean SLEEP bit in LINCR1 after suspend
2026-02-16 15:01 [PATCH 00/13] Add DMA support for LINFlexD UART driver Larisa Grigore
2026-02-16 15:01 ` [PATCH 01/13] serial: linflexuart: Fix locking in set_termios Larisa Grigore
@ 2026-02-16 15:01 ` Larisa Grigore
2026-02-16 20:22 ` Frank Li
2026-02-16 15:01 ` [PATCH 03/13] serial: linflexuart: Check FIFO full before writing Larisa Grigore
` (11 subsequent siblings)
13 siblings, 1 reply; 34+ messages in thread
From: Larisa Grigore @ 2026-02-16 15:01 UTC (permalink / raw)
To: gregkh, jirislaby, robh, krzk+dt, conor+dt, sumit.semwal,
christian.koenig, chester62515, cosmin.stoica, adrian.nitu,
stefan-gabriel.mirea, Mihaela.Martinas
Cc: linux-kernel, linux-serial, devicetree, linux-media, dri-devel,
linaro-mm-sig, s32, imx, clizzi, aruizrui, eballetb, echanude,
jkangas, Larisa Grigore
When coming back from reset, we need to re-initialize LINCR1 register.
SLEEP bit should be cleared, otherwise we can't enter INITM mode.
Fixes: 09864c1cdf5c ("tty: serial: Add linflexuart driver for S32V234")
Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
---
drivers/tty/serial/fsl_linflexuart.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c
index 5a410e2d56ac..016011fd8760 100644
--- a/drivers/tty/serial/fsl_linflexuart.c
+++ b/drivers/tty/serial/fsl_linflexuart.c
@@ -413,8 +413,7 @@ linflex_set_termios(struct uart_port *port, struct ktermios *termios,
old_cr = cr;
/* Enter initialization mode by setting INIT bit */
- cr1 = readl(port->membase + LINCR1);
- cr1 |= LINFLEXD_LINCR1_INIT;
+ cr1 = LINFLEXD_LINCR1_INIT | LINFLEXD_LINCR1_MME;
writel(cr1, port->membase + LINCR1);
/* wait for init mode entry */
--
2.47.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 03/13] serial: linflexuart: Check FIFO full before writing
2026-02-16 15:01 [PATCH 00/13] Add DMA support for LINFlexD UART driver Larisa Grigore
2026-02-16 15:01 ` [PATCH 01/13] serial: linflexuart: Fix locking in set_termios Larisa Grigore
2026-02-16 15:01 ` [PATCH 02/13] serial: linflexuart: Clean SLEEP bit in LINCR1 after suspend Larisa Grigore
@ 2026-02-16 15:01 ` Larisa Grigore
2026-02-16 15:01 ` [PATCH 04/13] serial: linflexuart: Correctly clear UARTSR in buffer mode Larisa Grigore
` (10 subsequent siblings)
13 siblings, 0 replies; 34+ messages in thread
From: Larisa Grigore @ 2026-02-16 15:01 UTC (permalink / raw)
To: gregkh, jirislaby, robh, krzk+dt, conor+dt, sumit.semwal,
christian.koenig, chester62515, cosmin.stoica, adrian.nitu,
stefan-gabriel.mirea, Mihaela.Martinas
Cc: linux-kernel, linux-serial, devicetree, linux-media, dri-devel,
linaro-mm-sig, s32, imx, clizzi, aruizrui, eballetb, echanude,
jkangas, Larisa Grigore
In FIFO mode, the transmitter FIFO should be checked to ensure it is not
full before writing a character.
Fixes: 09864c1cdf5c ("tty: serial: Add linflexuart driver for S32V234")
Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
---
drivers/tty/serial/fsl_linflexuart.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c
index 016011fd8760..9111e7af62ea 100644
--- a/drivers/tty/serial/fsl_linflexuart.c
+++ b/drivers/tty/serial/fsl_linflexuart.c
@@ -555,22 +555,24 @@ static struct uart_port *linflex_ports[UART_NR];
static void linflex_console_putchar(struct uart_port *port, unsigned char ch)
{
unsigned long cr;
+ bool fifo_mode;
cr = readl(port->membase + UARTCR);
+ fifo_mode = cr & LINFLEXD_UARTCR_TFBM;
+
+ if (fifo_mode)
+ while (readl(port->membase + UARTSR) &
+ LINFLEXD_UARTSR_DTFTFF)
+ ;
writeb(ch, port->membase + BDRL);
- if (!(cr & LINFLEXD_UARTCR_TFBM))
+ if (!fifo_mode) {
while ((readl(port->membase + UARTSR) &
LINFLEXD_UARTSR_DTFTFF)
!= LINFLEXD_UARTSR_DTFTFF)
;
- else
- while (readl(port->membase + UARTSR) &
- LINFLEXD_UARTSR_DTFTFF)
- ;
- if (!(cr & LINFLEXD_UARTCR_TFBM)) {
writel((readl(port->membase + UARTSR) |
LINFLEXD_UARTSR_DTFTFF),
port->membase + UARTSR);
--
2.47.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 04/13] serial: linflexuart: Correctly clear UARTSR in buffer mode
2026-02-16 15:01 [PATCH 00/13] Add DMA support for LINFlexD UART driver Larisa Grigore
` (2 preceding siblings ...)
2026-02-16 15:01 ` [PATCH 03/13] serial: linflexuart: Check FIFO full before writing Larisa Grigore
@ 2026-02-16 15:01 ` Larisa Grigore
2026-02-16 15:01 ` [PATCH 05/13] serial: linflexuart: Update RXEN/TXEN outside INITM mode Larisa Grigore
` (9 subsequent siblings)
13 siblings, 0 replies; 34+ messages in thread
From: Larisa Grigore @ 2026-02-16 15:01 UTC (permalink / raw)
To: gregkh, jirislaby, robh, krzk+dt, conor+dt, sumit.semwal,
christian.koenig, chester62515, cosmin.stoica, adrian.nitu,
stefan-gabriel.mirea, Mihaela.Martinas
Cc: linux-kernel, linux-serial, devicetree, linux-media, dri-devel,
linaro-mm-sig, s32, imx, clizzi, aruizrui, eballetb, echanude,
jkangas, Larisa Grigore
The TX interrupt handler should not clear RX-related fields in UARTSR,
and vice versa.
The handler checks UARTSR.DRFRFE before invoking linflex_rxint, and
UARTSR.DTFTFF before invoking linflex_txint.
Incorrectly clearing these bits may cause the interrupt handler to miss
characters.
Same applies to linflex_console_putchar which should clear only
UARTSR.DTFTFF.
Fixes: 09864c1cdf5c ("tty: serial: Add linflexuart driver for S32V234")
Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
---
drivers/tty/serial/fsl_linflexuart.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c
index 9111e7af62ea..a48240b0a5f2 100644
--- a/drivers/tty/serial/fsl_linflexuart.c
+++ b/drivers/tty/serial/fsl_linflexuart.c
@@ -169,7 +169,7 @@ static void linflex_put_char(struct uart_port *sport, unsigned char c)
LINFLEXD_UARTSR_DTFTFF)
;
- writel(status | LINFLEXD_UARTSR_DTFTFF, sport->membase + UARTSR);
+ writel(LINFLEXD_UARTSR_DTFTFF, sport->membase + UARTSR);
}
static inline void linflex_transmit_buffer(struct uart_port *sport)
@@ -255,7 +255,8 @@ static irqreturn_t linflex_rxint(int irq, void *dev_id)
sport->icount.parity++;
}
- writel(status, sport->membase + UARTSR);
+
+ writel(~(u32)LINFLEXD_UARTSR_DTFTFF, sport->membase + UARTSR);
status = readl(sport->membase + UARTSR);
if (brk) {
@@ -573,9 +574,7 @@ static void linflex_console_putchar(struct uart_port *port, unsigned char ch)
!= LINFLEXD_UARTSR_DTFTFF)
;
- writel((readl(port->membase + UARTSR) |
- LINFLEXD_UARTSR_DTFTFF),
- port->membase + UARTSR);
+ writel(LINFLEXD_UARTSR_DTFTFF, port->membase + UARTSR);
}
}
--
2.47.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 05/13] serial: linflexuart: Update RXEN/TXEN outside INITM mode
2026-02-16 15:01 [PATCH 00/13] Add DMA support for LINFlexD UART driver Larisa Grigore
` (3 preceding siblings ...)
2026-02-16 15:01 ` [PATCH 04/13] serial: linflexuart: Correctly clear UARTSR in buffer mode Larisa Grigore
@ 2026-02-16 15:01 ` Larisa Grigore
2026-02-16 15:01 ` [PATCH 06/13] serial: linflexuart: Ensure FIFO is empty when entering INITM Larisa Grigore
` (8 subsequent siblings)
13 siblings, 0 replies; 34+ messages in thread
From: Larisa Grigore @ 2026-02-16 15:01 UTC (permalink / raw)
To: gregkh, jirislaby, robh, krzk+dt, conor+dt, sumit.semwal,
christian.koenig, chester62515, cosmin.stoica, adrian.nitu,
stefan-gabriel.mirea, Mihaela.Martinas
Cc: linux-kernel, linux-serial, devicetree, linux-media, dri-devel,
linaro-mm-sig, s32, imx, clizzi, aruizrui, eballetb, echanude,
jkangas, Larisa Grigore
Reception and transmission should not be enabled or disabled while in
INITM mode.
Although the manual does not explicitly forbid modifying RXEN/TXEN
during INITM, this mode is intended for other types of settings.
Fixes: 09864c1cdf5c ("tty: serial: Add linflexuart driver for S32V234")
Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
---
drivers/tty/serial/fsl_linflexuart.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c
index a48240b0a5f2..768b3c67a614 100644
--- a/drivers/tty/serial/fsl_linflexuart.c
+++ b/drivers/tty/serial/fsl_linflexuart.c
@@ -350,8 +350,7 @@ static void linflex_setup_watermark(struct uart_port *sport)
/* set UART bit to allow writing other bits */
writel(LINFLEXD_UARTCR_UART, sport->membase + UARTCR);
- cr = (LINFLEXD_UARTCR_RXEN | LINFLEXD_UARTCR_TXEN |
- LINFLEXD_UARTCR_WL0 | LINFLEXD_UARTCR_UART);
+ cr = (LINFLEXD_UARTCR_WL0 | LINFLEXD_UARTCR_UART);
writel(cr, sport->membase + UARTCR);
@@ -359,6 +358,9 @@ static void linflex_setup_watermark(struct uart_port *sport)
writel(cr1, sport->membase + LINCR1);
+ cr |= (LINFLEXD_UARTCR_RXEN | LINFLEXD_UARTCR_TXEN);
+ writel(cr, sport->membase + UARTCR);
+
ier = readl(sport->membase + LINIER);
ier |= LINFLEXD_LINIER_DRIE;
ier |= LINFLEXD_LINIER_DTIE;
--
2.47.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 06/13] serial: linflexuart: Ensure FIFO is empty when entering INITM
2026-02-16 15:01 [PATCH 00/13] Add DMA support for LINFlexD UART driver Larisa Grigore
` (4 preceding siblings ...)
2026-02-16 15:01 ` [PATCH 05/13] serial: linflexuart: Update RXEN/TXEN outside INITM mode Larisa Grigore
@ 2026-02-16 15:01 ` Larisa Grigore
2026-02-16 15:01 ` [PATCH 07/13] serial: linflexuart: Revert earlycon workaround Larisa Grigore
` (7 subsequent siblings)
13 siblings, 0 replies; 34+ messages in thread
From: Larisa Grigore @ 2026-02-16 15:01 UTC (permalink / raw)
To: gregkh, jirislaby, robh, krzk+dt, conor+dt, sumit.semwal,
christian.koenig, chester62515, cosmin.stoica, adrian.nitu,
stefan-gabriel.mirea, Mihaela.Martinas
Cc: linux-kernel, linux-serial, devicetree, linux-media, dri-devel,
linaro-mm-sig, s32, imx, clizzi, aruizrui, eballetb, echanude,
jkangas, Larisa Grigore
In FIFO mode, wait until UARTCR.TDFL_TFC(number Tx FIFO) entries reach 0
before entering INITM mode.
Failing to do so may lead to undefined behavior, such as:
- corrupted characters being printed.
- the device is not able to receive or transmit any character.
In linflex_set_termios, transmission and reception should be disabled
before entering INITM mode, as already done in linflex_setup_watermark.
This patch corrects the behavior that was previously addressed by the
earlycon workaround, making that workaround no longer necessary. The
next patch will remove it.
Fixes: 09864c1cdf5c ("tty: serial: Add linflexuart driver for S32V234")
Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
---
drivers/tty/serial/fsl_linflexuart.c | 45 ++++++++++++++++++++++++++--
1 file changed, 42 insertions(+), 3 deletions(-)
diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c
index 768b3c67a614..c1d069dc8089 100644
--- a/drivers/tty/serial/fsl_linflexuart.c
+++ b/drivers/tty/serial/fsl_linflexuart.c
@@ -3,7 +3,7 @@
* Freescale LINFlexD UART serial port driver
*
* Copyright 2012-2016 Freescale Semiconductor, Inc.
- * Copyright 2017-2019 NXP
+ * Copyright 2017-2019, 2021 NXP
*/
#include <linux/console.h>
@@ -74,6 +74,17 @@
#define LINFLEXD_UARTCR_ROSE BIT(23)
+#define LINFLEXD_UARTCR_RDFLRFC_OFFSET 10
+#define LINFLEXD_UARTCR_RDFLRFC_MASK (0x7 << LINFLEXD_UARTCR_RDFLRFC_OFFSET)
+#define LINFLEXD_UARTCR_RDFLRFC(uartcr) (((uartcr) \
+ & LINFLEXD_UARTCR_RDFLRFC_MASK) >> \
+ LINFLEXD_UARTCR_RDFLRFC_OFFSET)
+#define LINFLEXD_UARTCR_TDFLTFC_OFFSET 13
+#define LINFLEXD_UARTCR_TDFLTFC_MASK (0x7 << LINFLEXD_UARTCR_TDFLTFC_OFFSET)
+#define LINFLEXD_UARTCR_TDFLTFC(uartcr) (((uartcr) \
+ & LINFLEXD_UARTCR_TDFLTFC_MASK) >> \
+ LINFLEXD_UARTCR_TDFLTFC_OFFSET)
+
#define LINFLEXD_UARTCR_RFBM BIT(9)
#define LINFLEXD_UARTCR_TFBM BIT(8)
#define LINFLEXD_UARTCR_WL1 BIT(7)
@@ -140,6 +151,17 @@ static struct {
} earlycon_buf;
#endif
+static inline void linflex_wait_tx_fifo_empty(struct uart_port *port)
+{
+ unsigned long cr = readl(port->membase + UARTCR);
+
+ if (!(cr & LINFLEXD_UARTCR_TFBM))
+ return;
+
+ while (LINFLEXD_UARTCR_TDFLTFC(readl(port->membase + UARTCR)))
+ ;
+}
+
static void linflex_stop_tx(struct uart_port *port)
{
unsigned long ier;
@@ -326,6 +348,11 @@ static void linflex_setup_watermark(struct uart_port *sport)
cr &= ~(LINFLEXD_UARTCR_RXEN | LINFLEXD_UARTCR_TXEN);
writel(cr, sport->membase + UARTCR);
+ /* In FIFO mode, we should make sure the fifo is empty
+ * before entering INITM.
+ */
+ linflex_wait_tx_fifo_empty(sport);
+
/* Enter initialization mode by setting INIT bit */
/* set the Linflex in master mode and activate by-pass filter */
@@ -412,8 +439,17 @@ linflex_set_termios(struct uart_port *port, struct ktermios *termios,
uart_port_lock_irqsave(port, &flags);
- cr = readl(port->membase + UARTCR);
- old_cr = cr;
+ old_cr = readl(port->membase + UARTCR) &
+ ~(LINFLEXD_UARTCR_RXEN | LINFLEXD_UARTCR_TXEN);
+ cr = old_cr;
+
+ /* In FIFO mode, we should make sure the fifo is empty
+ * before entering INITM.
+ */
+ linflex_wait_tx_fifo_empty(port);
+
+ /* disable transmit and receive */
+ writel(old_cr, port->membase + UARTCR);
/* Enter initialization mode by setting INIT bit */
cr1 = LINFLEXD_LINCR1_INIT | LINFLEXD_LINCR1_MME;
@@ -510,6 +546,9 @@ linflex_set_termios(struct uart_port *port, struct ktermios *termios,
writel(cr1, port->membase + LINCR1);
+ cr |= (LINFLEXD_UARTCR_TXEN) | (LINFLEXD_UARTCR_RXEN);
+ writel(cr, port->membase + UARTCR);
+
uart_port_unlock_irqrestore(port, flags);
}
--
2.47.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 07/13] serial: linflexuart: Revert earlycon workaround
2026-02-16 15:01 [PATCH 00/13] Add DMA support for LINFlexD UART driver Larisa Grigore
` (5 preceding siblings ...)
2026-02-16 15:01 ` [PATCH 06/13] serial: linflexuart: Ensure FIFO is empty when entering INITM Larisa Grigore
@ 2026-02-16 15:01 ` Larisa Grigore
2026-02-16 15:02 ` [PATCH 08/13] dt-bindings: serial: fsl-linflexuart: add clock input properties Larisa Grigore
` (6 subsequent siblings)
13 siblings, 0 replies; 34+ messages in thread
From: Larisa Grigore @ 2026-02-16 15:01 UTC (permalink / raw)
To: gregkh, jirislaby, robh, krzk+dt, conor+dt, sumit.semwal,
christian.koenig, chester62515, cosmin.stoica, adrian.nitu,
stefan-gabriel.mirea, Mihaela.Martinas
Cc: linux-kernel, linux-serial, devicetree, linux-media, dri-devel,
linaro-mm-sig, s32, imx, clizzi, aruizrui, eballetb, echanude,
jkangas, Larisa Grigore
The workaround is no longer needed, as we now wait for the TX FIFO to be
empty before entering INITM mode.
This ensures proper behavior without requiring the previous earlycon
workaround added in commit
09864c1cdf5c ("tty: serial: Add linflexuart driver for S32V234").
Fixes: 09864c1cdf5c ("tty: serial: Add linflexuart driver for S32V234")
Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
---
drivers/tty/serial/fsl_linflexuart.c | 87 +---------------------------
1 file changed, 1 insertion(+), 86 deletions(-)
diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c
index c1d069dc8089..fb5f325416c0 100644
--- a/drivers/tty/serial/fsl_linflexuart.c
+++ b/drivers/tty/serial/fsl_linflexuart.c
@@ -141,14 +141,6 @@ MODULE_DEVICE_TABLE(of, linflex_dt_ids);
#ifdef CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE
static struct uart_port *earlycon_port;
-static bool linflex_earlycon_same_instance;
-static DEFINE_SPINLOCK(init_lock);
-static bool during_init;
-
-static struct {
- char *content;
- unsigned int len, cap;
-} earlycon_buf;
#endif
static inline void linflex_wait_tx_fifo_empty(struct uart_port *port)
@@ -619,48 +611,6 @@ static void linflex_console_putchar(struct uart_port *port, unsigned char ch)
}
}
-static void linflex_earlycon_putchar(struct uart_port *port, unsigned char ch)
-{
- unsigned long flags;
- char *ret;
-
- if (!linflex_earlycon_same_instance) {
- linflex_console_putchar(port, ch);
- return;
- }
-
- spin_lock_irqsave(&init_lock, flags);
- if (!during_init)
- goto outside_init;
-
- if (earlycon_buf.len >= 1 << CONFIG_LOG_BUF_SHIFT)
- goto init_release;
-
- if (!earlycon_buf.cap) {
- earlycon_buf.content = kmalloc(EARLYCON_BUFFER_INITIAL_CAP,
- GFP_ATOMIC);
- earlycon_buf.cap = earlycon_buf.content ?
- EARLYCON_BUFFER_INITIAL_CAP : 0;
- } else if (earlycon_buf.len == earlycon_buf.cap) {
- ret = krealloc(earlycon_buf.content, earlycon_buf.cap << 1,
- GFP_ATOMIC);
- if (ret) {
- earlycon_buf.content = ret;
- earlycon_buf.cap <<= 1;
- }
- }
-
- if (earlycon_buf.len < earlycon_buf.cap)
- earlycon_buf.content[earlycon_buf.len++] = ch;
-
- goto init_release;
-
-outside_init:
- linflex_console_putchar(port, ch);
-init_release:
- spin_unlock_irqrestore(&init_lock, flags);
-}
-
static void linflex_string_write(struct uart_port *sport, const char *s,
unsigned int count)
{
@@ -739,8 +689,6 @@ static int __init linflex_console_setup(struct console *co, char *options)
int parity = 'n';
int flow = 'n';
int ret;
- int i;
- unsigned long flags;
/*
* check whether an invalid uart number has been specified, and
* if so, search for the first available port that does have
@@ -758,43 +706,10 @@ static int __init linflex_console_setup(struct console *co, char *options)
else
linflex_console_get_options(sport, &parity, &bits);
- if (earlycon_port && sport->mapbase == earlycon_port->mapbase) {
- linflex_earlycon_same_instance = true;
-
- spin_lock_irqsave(&init_lock, flags);
- during_init = true;
- spin_unlock_irqrestore(&init_lock, flags);
-
- /* Workaround for character loss or output of many invalid
- * characters, when INIT mode is entered shortly after a
- * character has just been printed.
- */
- udelay(PREINIT_DELAY);
- }
-
linflex_setup_watermark(sport);
ret = uart_set_options(sport, co, baud, parity, bits, flow);
- if (!linflex_earlycon_same_instance)
- goto done;
-
- spin_lock_irqsave(&init_lock, flags);
-
- /* Emptying buffer */
- if (earlycon_buf.len) {
- for (i = 0; i < earlycon_buf.len; i++)
- linflex_console_putchar(earlycon_port,
- earlycon_buf.content[i]);
-
- kfree(earlycon_buf.content);
- earlycon_buf.len = 0;
- }
-
- during_init = false;
- spin_unlock_irqrestore(&init_lock, flags);
-
-done:
return ret;
}
@@ -814,7 +729,7 @@ static void linflex_earlycon_write(struct console *con, const char *s,
{
struct earlycon_device *dev = con->data;
- uart_console_write(&dev->port, s, n, linflex_earlycon_putchar);
+ uart_console_write(&dev->port, s, n, linflex_console_putchar);
}
static int __init linflex_early_console_setup(struct earlycon_device *device,
--
2.47.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 08/13] dt-bindings: serial: fsl-linflexuart: add clock input properties
2026-02-16 15:01 [PATCH 00/13] Add DMA support for LINFlexD UART driver Larisa Grigore
` (6 preceding siblings ...)
2026-02-16 15:01 ` [PATCH 07/13] serial: linflexuart: Revert earlycon workaround Larisa Grigore
@ 2026-02-16 15:02 ` Larisa Grigore
2026-02-16 15:10 ` Krzysztof Kozlowski
2026-02-16 15:02 ` [PATCH 09/13] dt-bindings: serial: fsl-linflexuart: add dma properties Larisa Grigore
` (5 subsequent siblings)
13 siblings, 1 reply; 34+ messages in thread
From: Larisa Grigore @ 2026-02-16 15:02 UTC (permalink / raw)
To: gregkh, jirislaby, robh, krzk+dt, conor+dt, sumit.semwal,
christian.koenig, chester62515, cosmin.stoica, adrian.nitu,
stefan-gabriel.mirea, Mihaela.Martinas
Cc: linux-kernel, linux-serial, devicetree, linux-media, dri-devel,
linaro-mm-sig, s32, imx, clizzi, aruizrui, eballetb, echanude,
jkangas, Radu Pirea, Larisa Grigore
From: Radu Pirea <radu-nicolae.pirea@nxp.com>
Add optional support for the two clock inputs used by the LINFlexD UART
controller:
- "lin": LIN_BAUD_CLK
- "ipg": LINFLEXD_CLK
The clock inputs are kept optional to maintain compatibility with the
S32V234 platform.
Signed-off-by: Radu Pirea <radu-nicolae.pirea@nxp.com>
Co-developed-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
---
.../bindings/serial/fsl,s32-linflexuart.yaml | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml b/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml
index 4171f524a928..885f0b1b3492 100644
--- a/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml
+++ b/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml
@@ -34,6 +34,14 @@ properties:
interrupts:
maxItems: 1
+ clocks:
+ maxItems: 2
+
+ clock-names:
+ items:
+ - const: lin
+ - const: ipg
+
required:
- compatible
- reg
@@ -48,3 +56,13 @@ examples:
reg = <0x40053000 0x1000>;
interrupts = <0 59 4>;
};
+
+ - |
+ serial@401c8000 {
+ compatible = "nxp,s32g2-linflexuart",
+ "fsl,s32v234-linflexuart";
+ reg = <0x401C8000 0x3000>;
+ interrupts = <0 82 1>;
+ clocks = <&clks 14>, <&clks 13>;
+ clock-names = "lin", "ipg";
+ };
--
2.47.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 09/13] dt-bindings: serial: fsl-linflexuart: add dma properties
2026-02-16 15:01 [PATCH 00/13] Add DMA support for LINFlexD UART driver Larisa Grigore
` (7 preceding siblings ...)
2026-02-16 15:02 ` [PATCH 08/13] dt-bindings: serial: fsl-linflexuart: add clock input properties Larisa Grigore
@ 2026-02-16 15:02 ` Larisa Grigore
2026-02-16 15:10 ` Krzysztof Kozlowski
2026-02-16 15:29 ` Daniel Baluta
2026-02-16 15:02 ` [PATCH 10/13] serial: linflexuart: Add support for changing baudrate Larisa Grigore
` (4 subsequent siblings)
13 siblings, 2 replies; 34+ messages in thread
From: Larisa Grigore @ 2026-02-16 15:02 UTC (permalink / raw)
To: gregkh, jirislaby, robh, krzk+dt, conor+dt, sumit.semwal,
christian.koenig, chester62515, cosmin.stoica, adrian.nitu,
stefan-gabriel.mirea, Mihaela.Martinas
Cc: linux-kernel, linux-serial, devicetree, linux-media, dri-devel,
linaro-mm-sig, s32, imx, clizzi, aruizrui, eballetb, echanude,
jkangas, Radu Pirea, Larisa Grigore
From: Radu Pirea <radu-nicolae.pirea@nxp.com>
Add 'dmas' and 'dma-names' properties to describe optional DMA support
for RX and TX channels in the LINFlexD UART controller.
This allows the device tree to specify DMA channels used for UART data
transfers. If not specified, the driver will fall to interrupt-based
operations.
Signed-off-by: Radu Pirea <radu-nicolae.pirea@nxp.com>
Co-developed-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
---
.../bindings/serial/fsl,s32-linflexuart.yaml | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml b/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml
index 885f0b1b3492..317f9ba41c06 100644
--- a/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml
+++ b/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml
@@ -42,6 +42,16 @@ properties:
- const: lin
- const: ipg
+ dmas:
+ items:
+ - description: DMA controller phandle and request line for RX
+ - description: DMA controller phandle and request line for TX
+
+ dma-names:
+ items:
+ - const: rx
+ - const: tx
+
required:
- compatible
- reg
@@ -65,4 +75,7 @@ examples:
interrupts = <0 82 1>;
clocks = <&clks 14>, <&clks 13>;
clock-names = "lin", "ipg";
+ dmas = <&edma0 0 4>,
+ <&edma0 0 3>;
+ dma-names = "rx", "tx";
};
--
2.47.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 10/13] serial: linflexuart: Add support for changing baudrate
2026-02-16 15:01 [PATCH 00/13] Add DMA support for LINFlexD UART driver Larisa Grigore
` (8 preceding siblings ...)
2026-02-16 15:02 ` [PATCH 09/13] dt-bindings: serial: fsl-linflexuart: add dma properties Larisa Grigore
@ 2026-02-16 15:02 ` Larisa Grigore
2026-02-16 15:02 ` [PATCH 11/13] serial: linflexuart: Add support for configurable stop bits Larisa Grigore
` (3 subsequent siblings)
13 siblings, 0 replies; 34+ messages in thread
From: Larisa Grigore @ 2026-02-16 15:02 UTC (permalink / raw)
To: gregkh, jirislaby, robh, krzk+dt, conor+dt, sumit.semwal,
christian.koenig, chester62515, cosmin.stoica, adrian.nitu,
stefan-gabriel.mirea, Mihaela.Martinas
Cc: linux-kernel, linux-serial, devicetree, linux-media, dri-devel,
linaro-mm-sig, s32, imx, clizzi, aruizrui, eballetb, echanude,
jkangas, Radu Pirea, Larisa Grigore
From: Radu Pirea <radu-nicolae.pirea@nxp.com>
This patch adds support for dynamically configuring the baudrate of the
LINFlexD UART.
It introduces clock handling via clk and clk_ipg, and updates the
linflex_set_termios() function to compute and update the baudrate
related registers (LINIBRR and LINFBRR) based on the selected baudrate
and clock rate.
Baudrate is calculated with the following equation:
- When UARTCR[ROSE] = 1 (reduced oversampling), baudrate = LIN_CLK ÷
(OSR × LDIV).
- When UARTCR[ROSE] = 0, baudrate = LIN_CLK ÷ (16 × LDIV),
where LIN_CLK is the frequency of the baud clock.
LDIV is an unsigned fixed-point number:
- LINIBRR[IBR] stores the mantissa.
- LINFBRR[FBR] stores the fraction. This register isn't used in reduced
oversampling case.
This feature is supported only if the clock properties are present in
the device tree.
Signed-off-by: Radu Pirea <radu-nicolae.pirea@nxp.com>
Co-developed-by: Stefan-Gabriel Mirea <stefan-gabriel.mirea@nxp.com>
Signed-off-by: Stefan-Gabriel Mirea <stefan-gabriel.mirea@nxp.com>
Co-developed-by: Adrian.Nitu <adrian.nitu@freescale.com>
Signed-off-by: Adrian.Nitu <adrian.nitu@freescale.com>
Co-developed-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
---
drivers/tty/serial/fsl_linflexuart.c | 124 +++++++++++++++++++++++++--
1 file changed, 116 insertions(+), 8 deletions(-)
diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c
index fb5f325416c0..36c8f90d975d 100644
--- a/drivers/tty/serial/fsl_linflexuart.c
+++ b/drivers/tty/serial/fsl_linflexuart.c
@@ -3,9 +3,10 @@
* Freescale LINFlexD UART serial port driver
*
* Copyright 2012-2016 Freescale Semiconductor, Inc.
- * Copyright 2017-2019, 2021 NXP
+ * Copyright 2017-2019, 2021-2022 NXP
*/
+#include <linux/clk.h>
#include <linux/console.h>
#include <linux/io.h>
#include <linux/irq.h>
@@ -131,6 +132,22 @@
#define PREINIT_DELAY 2000 /* us */
+enum linflex_clk {
+ LINFLEX_CLK_LIN,
+ LINFLEX_CLK_IPG,
+ LINFLEX_CLK_NUM,
+};
+
+static const char * const linflex_clks_id[] = {
+ "lin",
+ "ipg",
+};
+
+struct linflex_port {
+ struct uart_port port;
+ struct clk_bulk_data clks[LINFLEX_CLK_NUM];
+};
+
static const struct of_device_id linflex_dt_ids[] = {
{
.compatible = "fsl,s32v234-linflexuart",
@@ -421,6 +438,19 @@ static void linflex_shutdown(struct uart_port *port)
devm_free_irq(port->dev, port->irq, port);
}
+static unsigned char
+linflex_ldiv_multiplier(struct uart_port *port)
+{
+ unsigned char mul = LINFLEX_LDIV_MULTIPLIER;
+ unsigned long cr;
+
+ cr = readl(port->membase + UARTCR);
+ if (cr & LINFLEXD_UARTCR_ROSE)
+ mul = LINFLEXD_UARTCR_OSR(cr);
+
+ return mul;
+}
+
static void
linflex_set_termios(struct uart_port *port, struct ktermios *termios,
const struct ktermios *old)
@@ -428,6 +458,9 @@ linflex_set_termios(struct uart_port *port, struct ktermios *termios,
unsigned long flags;
unsigned long cr, old_cr, cr1;
unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
+ unsigned long ibr, fbr, divisr, dividr;
+ unsigned char ldiv_mul;
+ unsigned int baud;
uart_port_lock_irqsave(port, &flags);
@@ -532,6 +565,24 @@ linflex_set_termios(struct uart_port *port, struct ktermios *termios,
port->ignore_status_mask |= LINFLEXD_UARTSR_BOF;
}
+ if (port->uartclk) {
+ ldiv_mul = linflex_ldiv_multiplier(port);
+ baud = uart_get_baud_rate(port, termios, old, 0,
+ port->uartclk / ldiv_mul);
+
+ /* update the per-port timeout */
+ uart_update_timeout(port, termios->c_cflag, baud);
+
+ divisr = port->uartclk;
+ dividr = ((unsigned long)baud * ldiv_mul);
+
+ ibr = divisr / dividr;
+ fbr = ((divisr % dividr) * 16 / dividr) & 0xF;
+
+ writel(ibr, port->membase + LINIBRR);
+ writel(fbr, port->membase + LINFBRR);
+ }
+
writel(cr, port->membase + UARTCR);
cr1 &= ~(LINFLEXD_LINCR1_INIT);
@@ -760,17 +811,52 @@ static struct uart_driver linflex_reg = {
.cons = LINFLEX_CONSOLE,
};
+static int linflex_init_clk(struct linflex_port *lfport)
+{
+ int i, ret;
+
+ for (i = 0; i < LINFLEX_CLK_NUM; i++) {
+ lfport->clks[i].id = linflex_clks_id[i];
+ lfport->clks[i].clk = NULL;
+ }
+
+ ret = devm_clk_bulk_get(lfport->port.dev, LINFLEX_CLK_NUM,
+ lfport->clks);
+ if (ret) {
+ if (ret == -EPROBE_DEFER)
+ return ret;
+
+ lfport->port.uartclk = 0;
+ dev_info(lfport->port.dev,
+ "uart clock is missing, err = %d. Skipping clock setup.\n",
+ ret);
+ return 0;
+ }
+
+ ret = clk_bulk_prepare_enable(LINFLEX_CLK_NUM, lfport->clks);
+ if (ret)
+ return dev_err_probe(lfport->port.dev, ret,
+ "Failed to enable LINFlexD clocks.\n");
+
+ lfport->port.uartclk = clk_get_rate(lfport->clks[LINFLEX_CLK_LIN].clk);
+
+ return 0;
+}
+
static int linflex_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
+ struct linflex_port *lfport;
struct uart_port *sport;
struct resource *res;
int ret;
- sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL);
- if (!sport)
+ lfport = devm_kzalloc(&pdev->dev, sizeof(*lfport), GFP_KERNEL);
+ if (!lfport)
return -ENOMEM;
+ sport = &lfport->port;
+
ret = of_alias_get_id(np, "serial");
if (ret < 0) {
dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
@@ -800,33 +886,55 @@ static int linflex_probe(struct platform_device *pdev)
sport->flags = UPF_BOOT_AUTOCONF;
sport->has_sysrq = IS_ENABLED(CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE);
+ ret = linflex_init_clk(lfport);
+ if (ret)
+ return ret;
+
linflex_ports[sport->line] = sport;
- platform_set_drvdata(pdev, sport);
+ platform_set_drvdata(pdev, lfport);
+
+ ret = uart_add_one_port(&linflex_reg, sport);
+ if (ret)
+ clk_bulk_disable_unprepare(LINFLEX_CLK_NUM, lfport->clks);
- return uart_add_one_port(&linflex_reg, sport);
+ return ret;
}
static void linflex_remove(struct platform_device *pdev)
{
- struct uart_port *sport = platform_get_drvdata(pdev);
+ struct linflex_port *lfport = platform_get_drvdata(pdev);
+ struct uart_port *sport = &lfport->port;
uart_remove_one_port(&linflex_reg, sport);
+ clk_bulk_disable_unprepare(LINFLEX_CLK_NUM, lfport->clks);
}
#ifdef CONFIG_PM_SLEEP
static int linflex_suspend(struct device *dev)
{
- struct uart_port *sport = dev_get_drvdata(dev);
+ struct linflex_port *lfport = dev_get_drvdata(dev);
+ struct uart_port *sport = &lfport->port;
uart_suspend_port(&linflex_reg, sport);
+ clk_bulk_disable_unprepare(LINFLEX_CLK_NUM, lfport->clks);
return 0;
}
static int linflex_resume(struct device *dev)
{
- struct uart_port *sport = dev_get_drvdata(dev);
+ struct linflex_port *lfport = dev_get_drvdata(dev);
+ struct uart_port *sport = &lfport->port;
+ int ret;
+
+ if (lfport->clks[LINFLEX_CLK_LIN].clk) {
+ ret = clk_bulk_prepare_enable(LINFLEX_CLK_NUM, lfport->clks);
+ if (ret) {
+ dev_err(dev, "Failed to enable LINFlexD clocks: %d\n", ret);
+ return ret;
+ }
+ }
uart_resume_port(&linflex_reg, sport);
--
2.47.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 11/13] serial: linflexuart: Add support for configurable stop bits
2026-02-16 15:01 [PATCH 00/13] Add DMA support for LINFlexD UART driver Larisa Grigore
` (9 preceding siblings ...)
2026-02-16 15:02 ` [PATCH 10/13] serial: linflexuart: Add support for changing baudrate Larisa Grigore
@ 2026-02-16 15:02 ` Larisa Grigore
2026-02-16 15:02 ` [PATCH 12/13] serial: linflexuart: Add DMA support Larisa Grigore
` (2 subsequent siblings)
13 siblings, 0 replies; 34+ messages in thread
From: Larisa Grigore @ 2026-02-16 15:02 UTC (permalink / raw)
To: gregkh, jirislaby, robh, krzk+dt, conor+dt, sumit.semwal,
christian.koenig, chester62515, cosmin.stoica, adrian.nitu,
stefan-gabriel.mirea, Mihaela.Martinas
Cc: linux-kernel, linux-serial, devicetree, linux-media, dri-devel,
linaro-mm-sig, s32, imx, clizzi, aruizrui, eballetb, echanude,
jkangas, Larisa Grigore
Updated linflex_set_termios to set the number of stop bits based on
termios->c_cflag.
Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
---
drivers/tty/serial/fsl_linflexuart.c | 31 +++++++++++++++++++++++++---
1 file changed, 28 insertions(+), 3 deletions(-)
diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c
index 36c8f90d975d..a5a34fd81bcf 100644
--- a/drivers/tty/serial/fsl_linflexuart.c
+++ b/drivers/tty/serial/fsl_linflexuart.c
@@ -75,6 +75,10 @@
#define LINFLEXD_UARTCR_ROSE BIT(23)
+#define LINFLEXD_UARTCR_SBUR_MASK GENMASK(18, 17)
+#define LINFLEXD_UARTCR_SBUR_1SBITS (0x0 << 17)
+#define LINFLEXD_UARTCR_SBUR_2SBITS (0x1 << 17)
+
#define LINFLEXD_UARTCR_RDFLRFC_OFFSET 10
#define LINFLEXD_UARTCR_RDFLRFC_MASK (0x7 << LINFLEXD_UARTCR_RDFLRFC_OFFSET)
#define LINFLEXD_UARTCR_RDFLRFC(uartcr) (((uartcr) \
@@ -124,6 +128,10 @@
#define LINFLEX_LDIV_MULTIPLIER (16)
+#define LINFLEXD_GCR_STOP_MASK BIT(1)
+#define LINFLEXD_GCR_STOP_1SBITS (0 << 1)
+#define LINFLEXD_GCR_STOP_2SBITS BIT(1)
+
#define DRIVER_NAME "fsl-linflexuart"
#define DEV_NAME "ttyLF"
#define UART_NR 4
@@ -456,7 +464,7 @@ linflex_set_termios(struct uart_port *port, struct ktermios *termios,
const struct ktermios *old)
{
unsigned long flags;
- unsigned long cr, old_cr, cr1;
+ unsigned long cr, old_cr, cr1, gcr;
unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
unsigned long ibr, fbr, divisr, dividr;
unsigned char ldiv_mul;
@@ -521,8 +529,25 @@ linflex_set_termios(struct uart_port *port, struct ktermios *termios,
cr |= LINFLEXD_UARTCR_WL0;
}
- if (termios->c_cflag & CSTOPB)
- termios->c_cflag &= ~CSTOPB;
+ gcr = readl(port->membase + GCR);
+
+ if (termios->c_cflag & CSTOPB) {
+ /* Use 2 stop bits. */
+ cr = (cr & ~LINFLEXD_UARTCR_SBUR_MASK) |
+ LINFLEXD_UARTCR_SBUR_2SBITS;
+ /* Set STOP in GCR field for 2 stop bits. */
+ gcr = (gcr & ~LINFLEXD_GCR_STOP_MASK) |
+ LINFLEXD_GCR_STOP_2SBITS;
+ } else {
+ /* Use 1 stop bit. */
+ cr = (cr & ~LINFLEXD_UARTCR_SBUR_MASK) |
+ LINFLEXD_UARTCR_SBUR_1SBITS;
+ /* Set STOP in GCR field for 1 stop bit. */
+ gcr = (gcr & ~LINFLEXD_GCR_STOP_MASK) |
+ LINFLEXD_GCR_STOP_1SBITS;
+ }
+ /* Update GCR register. */
+ writel(gcr, port->membase + GCR);
/* parity must be enabled when CS7 to match 8-bits format */
if ((termios->c_cflag & CSIZE) == CS7)
--
2.47.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 12/13] serial: linflexuart: Add DMA support
2026-02-16 15:01 [PATCH 00/13] Add DMA support for LINFlexD UART driver Larisa Grigore
` (10 preceding siblings ...)
2026-02-16 15:02 ` [PATCH 11/13] serial: linflexuart: Add support for configurable stop bits Larisa Grigore
@ 2026-02-16 15:02 ` Larisa Grigore
2026-02-16 15:11 ` Krzysztof Kozlowski
` (3 more replies)
2026-02-16 15:02 ` [PATCH 13/13] serial: linflexuart: Avoid stopping DMA during receive operations Larisa Grigore
2026-02-27 14:03 ` [PATCH 00/13] Add DMA support for LINFlexD UART driver Jared Kangas
13 siblings, 4 replies; 34+ messages in thread
From: Larisa Grigore @ 2026-02-16 15:02 UTC (permalink / raw)
To: gregkh, jirislaby, robh, krzk+dt, conor+dt, sumit.semwal,
christian.koenig, chester62515, cosmin.stoica, adrian.nitu,
stefan-gabriel.mirea, Mihaela.Martinas
Cc: linux-kernel, linux-serial, devicetree, linux-media, dri-devel,
linaro-mm-sig, s32, imx, clizzi, aruizrui, eballetb, echanude,
jkangas, Larisa Grigore, Radu Pirea, Phu Luu An, Js Ha,
Ghennadi Procopciuc
Add support for using DMA to avoid generating one interrupt per
character and losing characters while copy-paste.
In UART mode, the DMA capability can be used only if the UART Tx/Rx
buffers are configured as FIFOs.
If the DMA related properties are missing from the device tree, the
driver will fall back to interrupt + Buffer mode.
On the RX side, a timer is used to periodically poll for received data.
Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
Co-developed-by: Stoica Cosmin-Stefan <cosmin.stoica@nxp.com>
Signed-off-by: Stoica Cosmin-Stefan <cosmin.stoica@nxp.com>
Co-developed-by: Radu Pirea <radu-nicolae.pirea@nxp.com>
Signed-off-by: Radu Pirea <radu-nicolae.pirea@nxp.com>
Co-developed-by: Phu Luu An <phu.luuan@nxp.com>
Signed-off-by: Phu Luu An <phu.luuan@nxp.com>
Co-developed-by: Js Ha <js.ha@nxp.com>
Signed-off-by: Js Ha <js.ha@nxp.com>
Co-developed-by: Ghennadi Procopciuc <ghennadi.procopciuc@nxp.com>
Signed-off-by: Ghennadi Procopciuc <ghennadi.procopciuc@nxp.com>
---
drivers/tty/serial/fsl_linflexuart.c | 642 +++++++++++++++++++++++++--
1 file changed, 597 insertions(+), 45 deletions(-)
diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c
index a5a34fd81bcf..dff37c68cff0 100644
--- a/drivers/tty/serial/fsl_linflexuart.c
+++ b/drivers/tty/serial/fsl_linflexuart.c
@@ -3,19 +3,24 @@
* Freescale LINFlexD UART serial port driver
*
* Copyright 2012-2016 Freescale Semiconductor, Inc.
- * Copyright 2017-2019, 2021-2022 NXP
+ * Copyright 2017-2019, 2021-2022, 2025 NXP
*/
#include <linux/clk.h>
#include <linux/console.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/dmapool.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_dma.h>
#include <linux/platform_device.h>
#include <linux/serial_core.h>
#include <linux/slab.h>
#include <linux/tty_flip.h>
+#include <linux/jiffies.h>
#include <linux/delay.h>
/* All registers are 32-bit width */
@@ -42,6 +47,12 @@
#define GCR 0x004C /* Global control register */
#define UARTPTO 0x0050 /* UART preset timeout register */
#define UARTCTO 0x0054 /* UART current timeout register */
+/* The offsets for DMARXE/DMATXE in master mode only */
+#define DMATXE 0x0058 /* DMA Tx enable register */
+#define DMARXE 0x005C /* DMA Rx enable register */
+
+#define DMATXE_DRE0 BIT(0)
+#define DMARXE_DRE0 BIT(0)
/*
* Register field definitions
@@ -140,6 +151,9 @@
#define PREINIT_DELAY 2000 /* us */
+#define FSL_UART_RX_DMA_BUFFER_SIZE (PAGE_SIZE)
+#define LINFLEXD_UARTCR_FIFO_SIZE (4)
+
enum linflex_clk {
LINFLEX_CLK_LIN,
LINFLEX_CLK_IPG,
@@ -154,6 +168,24 @@ static const char * const linflex_clks_id[] = {
struct linflex_port {
struct uart_port port;
struct clk_bulk_data clks[LINFLEX_CLK_NUM];
+ unsigned int txfifo_size;
+ unsigned int rxfifo_size;
+ bool dma_tx_use;
+ bool dma_rx_use;
+ struct dma_chan *dma_tx_chan;
+ struct dma_chan *dma_rx_chan;
+ struct dma_async_tx_descriptor *dma_tx_desc;
+ struct dma_async_tx_descriptor *dma_rx_desc;
+ dma_addr_t dma_tx_buf_bus;
+ dma_addr_t dma_rx_buf_bus;
+ dma_cookie_t dma_tx_cookie;
+ dma_cookie_t dma_rx_cookie;
+ unsigned char *dma_rx_buf_virt;
+ unsigned int dma_tx_bytes;
+ int dma_tx_in_progress;
+ int dma_rx_in_progress;
+ unsigned long dma_rx_timeout;
+ struct timer_list timer;
};
static const struct of_device_id linflex_dt_ids[] = {
@@ -168,6 +200,76 @@ MODULE_DEVICE_TABLE(of, linflex_dt_ids);
static struct uart_port *earlycon_port;
#endif
+static void linflex_dma_tx_complete(void *arg);
+static void linflex_dma_rx_complete(void *arg);
+static void linflex_console_putchar(struct uart_port *port, unsigned char ch);
+
+static inline struct linflex_port *
+to_linflex_port(struct uart_port *uart)
+{
+ return container_of(uart, struct linflex_port, port);
+}
+
+static void linflex_copy_rx_to_tty(struct linflex_port *lfport,
+ struct tty_port *tty, int count)
+{
+ size_t copied;
+
+ lfport->port.icount.rx += count;
+
+ if (!tty) {
+ dev_err(lfport->port.dev, "No tty port\n");
+ return;
+ }
+
+ dma_sync_single_for_cpu(lfport->port.dev, lfport->dma_rx_buf_bus,
+ FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
+ copied = tty_insert_flip_string(tty,
+ ((unsigned char *)(lfport->dma_rx_buf_virt)),
+ count);
+
+ if (copied != count) {
+ WARN_ON(1);
+ dev_err(lfport->port.dev, "RxData copy to tty layer failed\n");
+ }
+}
+
+static void linflex_enable_dma_rx(struct uart_port *port)
+{
+ unsigned long dmarxe = readl(port->membase + DMARXE);
+
+ writel(dmarxe | DMARXE_DRE0, port->membase + DMARXE);
+ while (!(readl(port->membase + DMARXE) & DMARXE_DRE0))
+ ;
+}
+
+static void linflex_enable_dma_tx(struct uart_port *port)
+{
+ unsigned long dmatxe = readl(port->membase + DMATXE);
+
+ writel(dmatxe | DMATXE_DRE0, port->membase + DMATXE);
+ while (!(readl(port->membase + DMATXE) & DMATXE_DRE0))
+ ;
+}
+
+static void linflex_disable_dma_rx(struct uart_port *port)
+{
+ unsigned long dmarxe = readl(port->membase + DMARXE);
+
+ writel(dmarxe & 0xFFFF0000, port->membase + DMARXE);
+ while (readl(port->membase + DMARXE) & DMARXE_DRE0)
+ ;
+}
+
+static void linflex_disable_dma_tx(struct uart_port *port)
+{
+ unsigned long dmatxe = readl(port->membase + DMATXE);
+
+ writel(dmatxe & 0xFFFF0000, port->membase + DMATXE);
+ while (readl(port->membase + DMATXE) & DMATXE_DRE0)
+ ;
+}
+
static inline void linflex_wait_tx_fifo_empty(struct uart_port *port)
{
unsigned long cr = readl(port->membase + UARTCR);
@@ -179,36 +281,113 @@ static inline void linflex_wait_tx_fifo_empty(struct uart_port *port)
;
}
+static void _linflex_stop_tx(struct uart_port *port)
+{
+ struct linflex_port *lfport = to_linflex_port(port);
+ unsigned long ier;
+
+ if (!lfport->dma_tx_use) {
+ ier = readl(port->membase + LINIER);
+ ier &= ~(LINFLEXD_LINIER_DTIE);
+ writel(ier, port->membase + LINIER);
+ return;
+ }
+
+ linflex_disable_dma_tx(port);
+}
+
static void linflex_stop_tx(struct uart_port *port)
{
+ struct linflex_port *lfport = to_linflex_port(port);
+ struct dma_tx_state state;
+ unsigned int count;
+
+ _linflex_stop_tx(port);
+
+ if (!lfport->dma_tx_in_progress)
+ return;
+
+ dmaengine_pause(lfport->dma_tx_chan);
+ dmaengine_tx_status(lfport->dma_tx_chan,
+ lfport->dma_tx_cookie, &state);
+ dmaengine_terminate_all(lfport->dma_tx_chan);
+ count = lfport->dma_tx_bytes - state.residue;
+ uart_xmit_advance(port, count);
+
+ lfport->dma_tx_in_progress = 0;
+}
+
+static void _linflex_start_rx(struct uart_port *port)
+{
+ struct linflex_port *lfport = to_linflex_port(port);
unsigned long ier;
- ier = readl(port->membase + LINIER);
- ier &= ~(LINFLEXD_LINIER_DTIE);
- writel(ier, port->membase + LINIER);
+ if (!lfport->dma_rx_use) {
+ ier = readl(port->membase + LINIER);
+ writel(ier | LINFLEXD_LINIER_DRIE, port->membase + LINIER);
+ return;
+ }
+
+ linflex_enable_dma_rx(port);
}
-static void linflex_stop_rx(struct uart_port *port)
+static void _linflex_stop_rx(struct uart_port *port)
{
+ struct linflex_port *lfport = to_linflex_port(port);
unsigned long ier;
- ier = readl(port->membase + LINIER);
- writel(ier & ~LINFLEXD_LINIER_DRIE, port->membase + LINIER);
+ if (!lfport->dma_rx_use) {
+ ier = readl(port->membase + LINIER);
+ writel(ier & ~LINFLEXD_LINIER_DRIE, port->membase + LINIER);
+ return;
+ }
+
+ linflex_disable_dma_rx(port);
+}
+
+static void linflex_stop_rx(struct uart_port *port)
+{
+ struct linflex_port *lfport = to_linflex_port(port);
+ struct dma_tx_state state;
+ unsigned int count;
+
+ _linflex_stop_rx(port);
+
+ if (!lfport->dma_rx_in_progress)
+ return;
+
+ dmaengine_pause(lfport->dma_rx_chan);
+ dmaengine_tx_status(lfport->dma_rx_chan,
+ lfport->dma_rx_cookie, &state);
+ dmaengine_terminate_all(lfport->dma_rx_chan);
+ count = FSL_UART_RX_DMA_BUFFER_SIZE - state.residue;
+
+ lfport->dma_rx_in_progress = 0;
+ linflex_copy_rx_to_tty(lfport, &port->state->port, count);
+ tty_flip_buffer_push(&port->state->port);
}
static void linflex_put_char(struct uart_port *sport, unsigned char c)
{
+ struct linflex_port *lfport = to_linflex_port(sport);
unsigned long status;
writeb(c, sport->membase + BDRL);
/* Waiting for data transmission completed. */
- while (((status = readl(sport->membase + UARTSR)) &
- LINFLEXD_UARTSR_DTFTFF) !=
- LINFLEXD_UARTSR_DTFTFF)
- ;
+ if (!lfport->dma_tx_use) {
+ while (((status = readl(sport->membase + UARTSR)) &
+ LINFLEXD_UARTSR_DTFTFF) !=
+ LINFLEXD_UARTSR_DTFTFF)
+ ;
+ } else {
+ while (((status = readl(sport->membase + UARTSR)) &
+ LINFLEXD_UARTSR_DTFTFF))
+ ;
+ }
- writel(LINFLEXD_UARTSR_DTFTFF, sport->membase + UARTSR);
+ if (!lfport->dma_tx_use)
+ writel(LINFLEXD_UARTSR_DTFTFF, sport->membase + UARTSR);
}
static inline void linflex_transmit_buffer(struct uart_port *sport)
@@ -228,18 +407,198 @@ static inline void linflex_transmit_buffer(struct uart_port *sport)
linflex_stop_tx(sport);
}
+static int linflex_dma_tx(struct linflex_port *lfport, unsigned int count,
+ unsigned int tail)
+{
+ struct uart_port *sport = &lfport->port;
+ dma_addr_t tx_bus_addr;
+
+ while ((readl(sport->membase + UARTSR) & LINFLEXD_UARTSR_DTFTFF))
+ ;
+
+ dma_sync_single_for_device(sport->dev, lfport->dma_tx_buf_bus,
+ UART_XMIT_SIZE, DMA_TO_DEVICE);
+ lfport->dma_tx_bytes = count;
+ tx_bus_addr = lfport->dma_tx_buf_bus + tail;
+ lfport->dma_tx_desc =
+ dmaengine_prep_slave_single(lfport->dma_tx_chan, tx_bus_addr,
+ lfport->dma_tx_bytes, DMA_MEM_TO_DEV,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
+
+ if (!lfport->dma_tx_desc) {
+ dev_err(sport->dev, "Not able to get desc for tx\n");
+ return -EIO;
+ }
+
+ lfport->dma_tx_desc->callback = linflex_dma_tx_complete;
+ lfport->dma_tx_desc->callback_param = sport;
+ lfport->dma_tx_in_progress = 1;
+ lfport->dma_tx_cookie = dmaengine_submit(lfport->dma_tx_desc);
+ dma_async_issue_pending(lfport->dma_tx_chan);
+
+ linflex_enable_dma_tx(&lfport->port);
+ return 0;
+}
+
+static void linflex_prepare_tx(struct linflex_port *lfport)
+{
+ struct tty_port *tport = &lfport->port.state->port;
+ unsigned int count, tail;
+
+ count = kfifo_out_linear(&tport->xmit_fifo, &tail, UART_XMIT_SIZE);
+
+ if (!count || lfport->dma_tx_in_progress)
+ return;
+
+ linflex_dma_tx(lfport, count, tail);
+}
+
+static void linflex_restart_dma_tx(struct linflex_port *lfport)
+{
+ struct uart_port *sport = &lfport->port;
+ struct tty_port *tport = &sport->state->port;
+
+ if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS)
+ uart_write_wakeup(sport);
+
+ linflex_prepare_tx(lfport);
+}
+
+static void linflex_dma_tx_complete(void *arg)
+{
+ struct linflex_port *lfport = arg;
+ struct uart_port *sport = &lfport->port;
+ unsigned long flags;
+
+ uart_port_lock_irqsave(sport, &flags);
+
+ /* stopped before? */
+ if (!lfport->dma_tx_in_progress)
+ goto out_tx_callback;
+
+ uart_xmit_advance(sport, lfport->dma_tx_bytes);
+ lfport->dma_tx_in_progress = 0;
+
+ linflex_restart_dma_tx(lfport);
+
+out_tx_callback:
+ uart_port_unlock_irqrestore(sport, flags);
+}
+
+static void linflex_flush_buffer(struct uart_port *port)
+{
+ struct linflex_port *lfport = to_linflex_port(port);
+
+ if (lfport->dma_tx_use) {
+ linflex_disable_dma_tx(port);
+ dmaengine_terminate_async(lfport->dma_tx_chan);
+ lfport->dma_tx_in_progress = 0;
+ }
+}
+
+static int linflex_dma_rx(struct linflex_port *lfport)
+{
+ dma_sync_single_for_device(lfport->port.dev, lfport->dma_rx_buf_bus,
+ FSL_UART_RX_DMA_BUFFER_SIZE,
+ DMA_FROM_DEVICE);
+ lfport->dma_rx_desc = dmaengine_prep_slave_single(lfport->dma_rx_chan,
+ lfport->dma_rx_buf_bus,
+ FSL_UART_RX_DMA_BUFFER_SIZE,
+ DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT |
+ DMA_CTRL_ACK);
+
+ if (!lfport->dma_rx_desc) {
+ dev_err(lfport->port.dev, "Not able to get desc for rx\n");
+ return -EIO;
+ }
+
+ lfport->dma_rx_desc->callback = linflex_dma_rx_complete;
+ lfport->dma_rx_desc->callback_param = lfport;
+ lfport->dma_rx_in_progress = 1;
+ lfport->dma_rx_cookie = dmaengine_submit(lfport->dma_rx_desc);
+ dma_async_issue_pending(lfport->dma_rx_chan);
+
+ linflex_enable_dma_rx(&lfport->port);
+ return 0;
+}
+
+static void linflex_dma_rx_complete(void *arg)
+{
+ struct linflex_port *lfport = arg;
+ struct tty_port *port = &lfport->port.state->port;
+ unsigned long flags;
+
+ timer_delete_sync(&lfport->timer);
+
+ uart_port_lock_irqsave(&lfport->port, &flags);
+
+ /* stopped before? */
+ if (!lfport->dma_rx_in_progress) {
+ uart_port_unlock_irqrestore(&lfport->port, flags);
+ return;
+ }
+
+ lfport->dma_rx_in_progress = 0;
+ linflex_copy_rx_to_tty(lfport, port, FSL_UART_RX_DMA_BUFFER_SIZE);
+ tty_flip_buffer_push(port);
+ linflex_dma_rx(lfport);
+
+ uart_port_unlock_irqrestore(&lfport->port, flags);
+
+ mod_timer(&lfport->timer, jiffies + lfport->dma_rx_timeout);
+}
+
+static void linflex_timer_func(struct timer_list *t)
+{
+ struct linflex_port *lfport = timer_container_of(lfport, t, timer);
+ unsigned long flags;
+
+ uart_port_lock_irqsave(&lfport->port, &flags);
+
+ /* stopped before? */
+ if (!lfport->dma_rx_in_progress) {
+ uart_port_unlock_irqrestore(&lfport->port, flags);
+ return;
+ }
+
+ linflex_stop_rx(&lfport->port);
+ linflex_dma_rx(lfport);
+
+ uart_port_unlock_irqrestore(&lfport->port, flags);
+ mod_timer(&lfport->timer, jiffies + lfport->dma_rx_timeout);
+}
+
+static void _linflex_start_tx(struct uart_port *port)
+{
+ struct linflex_port *lfport = to_linflex_port(port);
+ unsigned long ier;
+
+ if (lfport->dma_tx_use) {
+ linflex_enable_dma_tx(&lfport->port);
+ } else {
+ ier = readl(port->membase + LINIER);
+ writel(ier | LINFLEXD_LINIER_DTIE, port->membase + LINIER);
+ }
+}
+
static void linflex_start_tx(struct uart_port *port)
{
+ struct linflex_port *lfport = to_linflex_port(port);
unsigned long ier;
- linflex_transmit_buffer(port);
- ier = readl(port->membase + LINIER);
- writel(ier | LINFLEXD_LINIER_DTIE, port->membase + LINIER);
+ if (lfport->dma_tx_use) {
+ linflex_prepare_tx(lfport);
+ } else {
+ linflex_transmit_buffer(port);
+ ier = readl(port->membase + LINIER);
+ writel(ier | LINFLEXD_LINIER_DTIE, port->membase + LINIER);
+ }
}
static irqreturn_t linflex_txint(int irq, void *dev_id)
{
- struct uart_port *sport = dev_id;
+ struct linflex_port *lfport = dev_id;
+ struct uart_port *sport = &lfport->port;
struct tty_port *tport = &sport->state->port;
unsigned long flags;
@@ -263,7 +622,8 @@ static irqreturn_t linflex_txint(int irq, void *dev_id)
static irqreturn_t linflex_rxint(int irq, void *dev_id)
{
- struct uart_port *sport = dev_id;
+ struct linflex_port *lfport = dev_id;
+ struct uart_port *sport = &lfport->port;
unsigned int flg;
struct tty_port *port = &sport->state->port;
unsigned long flags, status;
@@ -316,14 +676,14 @@ static irqreturn_t linflex_rxint(int irq, void *dev_id)
static irqreturn_t linflex_int(int irq, void *dev_id)
{
- struct uart_port *sport = dev_id;
+ struct linflex_port *lfport = dev_id;
unsigned long status;
- status = readl(sport->membase + UARTSR);
+ status = readl(lfport->port.membase + UARTSR);
- if (status & LINFLEXD_UARTSR_DRFRFE)
+ if (status & LINFLEXD_UARTSR_DRFRFE && !lfport->dma_rx_use)
linflex_rxint(irq, dev_id);
- if (status & LINFLEXD_UARTSR_DTFTFF)
+ if (status & LINFLEXD_UARTSR_DTFTFF && !lfport->dma_rx_use)
linflex_txint(irq, dev_id);
return IRQ_HANDLED;
@@ -332,11 +692,15 @@ static irqreturn_t linflex_int(int irq, void *dev_id)
/* return TIOCSER_TEMT when transmitter is not busy */
static unsigned int linflex_tx_empty(struct uart_port *port)
{
+ struct linflex_port *lfport = to_linflex_port(port);
unsigned long status;
status = readl(port->membase + UARTSR) & LINFLEXD_UARTSR_DTFTFF;
- return status ? TIOCSER_TEMT : 0;
+ if (!lfport->dma_tx_use)
+ return status ? TIOCSER_TEMT : 0;
+ else
+ return status ? 0 : TIOCSER_TEMT;
}
static unsigned int linflex_get_mctrl(struct uart_port *port)
@@ -354,6 +718,7 @@ static void linflex_break_ctl(struct uart_port *port, int break_state)
static void linflex_setup_watermark(struct uart_port *sport)
{
+ struct linflex_port *lfport = to_linflex_port(sport);
unsigned long cr, ier, cr1;
/* Disable transmission/reception */
@@ -396,6 +761,14 @@ static void linflex_setup_watermark(struct uart_port *sport)
cr = (LINFLEXD_UARTCR_WL0 | LINFLEXD_UARTCR_UART);
+ /* FIFO mode enabled for DMA Rx mode. */
+ if (lfport->dma_rx_use)
+ cr |= LINFLEXD_UARTCR_RFBM;
+
+ /* FIFO mode enabled for DMA Tx mode. */
+ if (lfport->dma_tx_use)
+ cr |= LINFLEXD_UARTCR_TFBM;
+
writel(cr, sport->membase + UARTCR);
cr1 &= ~(LINFLEXD_LINCR1_INIT);
@@ -406,44 +779,169 @@ static void linflex_setup_watermark(struct uart_port *sport)
writel(cr, sport->membase + UARTCR);
ier = readl(sport->membase + LINIER);
- ier |= LINFLEXD_LINIER_DRIE;
- ier |= LINFLEXD_LINIER_DTIE;
+ if (!lfport->dma_rx_use)
+ ier |= LINFLEXD_LINIER_DRIE;
+
+ if (!lfport->dma_tx_use)
+ ier |= LINFLEXD_LINIER_DTIE;
writel(ier, sport->membase + LINIER);
}
+static int linflex_dma_tx_request(struct uart_port *port)
+{
+ struct linflex_port *lfport = to_linflex_port(port);
+ struct tty_port *tport = &port->state->port;
+ struct dma_slave_config dma_tx_sconfig;
+ dma_addr_t dma_bus;
+ int ret;
+
+ dma_bus = dma_map_single(port->dev, tport->xmit_buf,
+ UART_XMIT_SIZE, DMA_TO_DEVICE);
+
+ if (dma_mapping_error(port->dev, dma_bus)) {
+ dev_err(port->dev, "dma_map_single tx failed\n");
+ return -ENOMEM;
+ }
+
+ memset(&dma_tx_sconfig, 0, sizeof(dma_tx_sconfig));
+ dma_tx_sconfig.dst_addr = port->mapbase + BDRL;
+ dma_tx_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ dma_tx_sconfig.dst_maxburst = 1;
+ dma_tx_sconfig.direction = DMA_MEM_TO_DEV;
+ ret = dmaengine_slave_config(lfport->dma_tx_chan, &dma_tx_sconfig);
+
+ if (ret < 0) {
+ dev_err(port->dev, "Dma slave config failed, err = %d\n",
+ ret);
+ return ret;
+ }
+
+ lfport->dma_tx_buf_bus = dma_bus;
+ lfport->dma_tx_in_progress = 0;
+
+ return 0;
+}
+
+static int linflex_dma_rx_request(struct uart_port *port)
+{
+ struct linflex_port *lfport = to_linflex_port(port);
+ struct dma_slave_config dma_rx_sconfig;
+ unsigned char *dma_buf;
+ dma_addr_t dma_bus;
+ int ret;
+
+ dma_buf = devm_kmalloc(port->dev, FSL_UART_RX_DMA_BUFFER_SIZE,
+ GFP_KERNEL);
+
+ if (!dma_buf) {
+ dev_err(port->dev, "Dma rx alloc failed\n");
+ return -ENOMEM;
+ }
+
+ dma_bus = dma_map_single(port->dev, dma_buf,
+ FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
+
+ if (dma_mapping_error(port->dev, dma_bus)) {
+ dev_err(port->dev, "dma_map_single rx failed\n");
+ return -ENOMEM;
+ }
+
+ memset(&dma_rx_sconfig, 0, sizeof(dma_rx_sconfig));
+ dma_rx_sconfig.src_addr = port->mapbase + BDRM;
+ dma_rx_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ dma_rx_sconfig.src_maxburst = 1;
+ dma_rx_sconfig.direction = DMA_DEV_TO_MEM;
+ ret = dmaengine_slave_config(lfport->dma_rx_chan, &dma_rx_sconfig);
+
+ if (ret < 0) {
+ dev_err(port->dev, "Dma slave config failed, err = %d\n",
+ ret);
+ return ret;
+ }
+
+ lfport->dma_rx_buf_virt = dma_buf;
+ lfport->dma_rx_buf_bus = dma_bus;
+ lfport->dma_rx_in_progress = 0;
+
+ return 0;
+}
+
+static void linflex_dma_tx_free(struct uart_port *port)
+{
+ struct linflex_port *lfport = to_linflex_port(port);
+
+ dma_unmap_single(lfport->port.dev, lfport->dma_tx_buf_bus, UART_XMIT_SIZE,
+ DMA_TO_DEVICE);
+
+ lfport->dma_tx_buf_bus = 0;
+}
+
+static void linflex_dma_rx_free(struct uart_port *port)
+{
+ struct linflex_port *lfport = to_linflex_port(port);
+
+ dma_unmap_single(lfport->port.dev, lfport->dma_rx_buf_bus,
+ FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
+ devm_kfree(lfport->port.dev, lfport->dma_rx_buf_virt);
+
+ lfport->dma_rx_buf_bus = 0;
+ lfport->dma_rx_buf_virt = NULL;
+}
+
static int linflex_startup(struct uart_port *port)
{
+ struct linflex_port *lfport = to_linflex_port(port);
int ret = 0;
unsigned long flags;
+ bool dma_rx_use, dma_tx_use;
+
+ dma_rx_use = lfport->dma_rx_chan && !linflex_dma_rx_request(port);
+ dma_tx_use = lfport->dma_tx_chan && !linflex_dma_tx_request(port);
uart_port_lock_irqsave(port, &flags);
+ lfport->dma_rx_use = dma_rx_use;
+ lfport->dma_tx_use = dma_tx_use;
+ lfport->port.fifosize = LINFLEXD_UARTCR_FIFO_SIZE;
+
linflex_setup_watermark(port);
+ if (lfport->dma_rx_use && !linflex_dma_rx(lfport)) {
+ timer_setup(&lfport->timer, linflex_timer_func, 0);
+ mod_timer(&lfport->timer, jiffies + lfport->dma_rx_timeout);
+ }
uart_port_unlock_irqrestore(port, flags);
- ret = devm_request_irq(port->dev, port->irq, linflex_int, 0,
- DRIVER_NAME, port);
-
+ if (!lfport->dma_rx_use || !lfport->dma_tx_use) {
+ ret = devm_request_irq(port->dev, port->irq, linflex_int, 0,
+ DRIVER_NAME, lfport);
+ }
return ret;
}
static void linflex_shutdown(struct uart_port *port)
{
- unsigned long ier;
+ struct linflex_port *lfport = to_linflex_port(port);
unsigned long flags;
+ timer_delete_sync(&lfport->timer);
+
uart_port_lock_irqsave(port, &flags);
- /* disable interrupts */
- ier = readl(port->membase + LINIER);
- ier &= ~(LINFLEXD_LINIER_DRIE | LINFLEXD_LINIER_DTIE);
- writel(ier, port->membase + LINIER);
+ linflex_stop_tx(port);
+ linflex_stop_rx(port);
uart_port_unlock_irqrestore(port, flags);
- devm_free_irq(port->dev, port->irq, port);
+ if (!lfport->dma_rx_use || !lfport->dma_tx_use)
+ devm_free_irq(port->dev, port->irq, lfport);
+
+ if (lfport->dma_rx_use)
+ linflex_dma_rx_free(port);
+
+ if (lfport->dma_tx_use)
+ linflex_dma_tx_free(port);
}
static unsigned char
@@ -463,6 +961,7 @@ static void
linflex_set_termios(struct uart_port *port, struct ktermios *termios,
const struct ktermios *old)
{
+ struct linflex_port *lfport = to_linflex_port(port);
unsigned long flags;
unsigned long cr, old_cr, cr1, gcr;
unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
@@ -472,6 +971,9 @@ linflex_set_termios(struct uart_port *port, struct ktermios *termios,
uart_port_lock_irqsave(port, &flags);
+ _linflex_stop_rx(port);
+ _linflex_stop_tx(port);
+
old_cr = readl(port->membase + UARTCR) &
~(LINFLEXD_UARTCR_RXEN | LINFLEXD_UARTCR_TXEN);
cr = old_cr;
@@ -608,6 +1110,8 @@ linflex_set_termios(struct uart_port *port, struct ktermios *termios,
writel(fbr, port->membase + LINFBRR);
}
+ lfport->dma_rx_timeout = msecs_to_jiffies(DIV_ROUND_UP(10000000, baud));
+
writel(cr, port->membase + UARTCR);
cr1 &= ~(LINFLEXD_LINCR1_INIT);
@@ -617,6 +1121,9 @@ linflex_set_termios(struct uart_port *port, struct ktermios *termios,
cr |= (LINFLEXD_UARTCR_TXEN) | (LINFLEXD_UARTCR_RXEN);
writel(cr, port->membase + UARTCR);
+ _linflex_start_rx(port);
+ _linflex_start_tx(port);
+
uart_port_unlock_irqrestore(port, flags);
}
@@ -657,6 +1164,7 @@ static const struct uart_ops linflex_pops = {
.request_port = linflex_request_port,
.release_port = linflex_release_port,
.config_port = linflex_config_port,
+ .flush_buffer = linflex_flush_buffer,
};
static struct uart_port *linflex_ports[UART_NR];
@@ -690,18 +1198,16 @@ static void linflex_console_putchar(struct uart_port *port, unsigned char ch)
static void linflex_string_write(struct uart_port *sport, const char *s,
unsigned int count)
{
- unsigned long cr, ier = 0;
-
- ier = readl(sport->membase + LINIER);
- linflex_stop_tx(sport);
+ unsigned long cr;
+ _linflex_stop_tx(sport);
cr = readl(sport->membase + UARTCR);
cr |= (LINFLEXD_UARTCR_TXEN);
writel(cr, sport->membase + UARTCR);
uart_console_write(sport, s, count, linflex_console_putchar);
- writel(ier, sport->membase + LINIER);
+ _linflex_start_tx(sport);
}
static void
@@ -881,30 +1387,59 @@ static int linflex_probe(struct platform_device *pdev)
return -ENOMEM;
sport = &lfport->port;
+ sport->dev = &pdev->dev;
+
+ lfport->dma_tx_chan = dma_request_chan(sport->dev, "tx");
+ if (IS_ERR(lfport->dma_tx_chan)) {
+ ret = PTR_ERR(lfport->dma_tx_chan);
+ if (ret == -EPROBE_DEFER)
+ return ret;
+
+ dev_info(sport->dev,
+ "DMA tx channel request failed, operating without tx DMA %ld\n",
+ PTR_ERR(lfport->dma_tx_chan));
+ lfport->dma_tx_chan = NULL;
+ }
+
+ lfport->dma_rx_chan = dma_request_chan(sport->dev, "rx");
+ if (IS_ERR(lfport->dma_rx_chan)) {
+ ret = PTR_ERR(lfport->dma_rx_chan);
+ if (ret == -EPROBE_DEFER) {
+ dma_release_channel(lfport->dma_tx_chan);
+ return ret;
+ }
+
+ dev_info(sport->dev,
+ "DMA rx channel request failed, operating without rx DMA %ld\n",
+ PTR_ERR(lfport->dma_rx_chan));
+ lfport->dma_rx_chan = NULL;
+ }
ret = of_alias_get_id(np, "serial");
if (ret < 0) {
dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
- return ret;
+ goto linflex_probe_free_dma;
}
if (ret >= UART_NR) {
dev_err(&pdev->dev, "driver limited to %d serial ports\n",
UART_NR);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto linflex_probe_free_dma;
}
sport->line = ret;
sport->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
- if (IS_ERR(sport->membase))
- return PTR_ERR(sport->membase);
+ if (IS_ERR(sport->membase)) {
+ ret = PTR_ERR(sport->membase);
+ goto linflex_probe_free_dma;
+ }
sport->mapbase = res->start;
ret = platform_get_irq(pdev, 0);
if (ret < 0)
return ret;
- sport->dev = &pdev->dev;
sport->iotype = UPIO_MEM;
sport->irq = ret;
sport->ops = &linflex_pops;
@@ -913,15 +1448,25 @@ static int linflex_probe(struct platform_device *pdev)
ret = linflex_init_clk(lfport);
if (ret)
- return ret;
+ goto linflex_probe_free_dma;
linflex_ports[sport->line] = sport;
platform_set_drvdata(pdev, lfport);
ret = uart_add_one_port(&linflex_reg, sport);
- if (ret)
+ if (ret) {
clk_bulk_disable_unprepare(LINFLEX_CLK_NUM, lfport->clks);
+ goto linflex_probe_free_dma;
+ }
+
+ return 0;
+
+linflex_probe_free_dma:
+ if (lfport->dma_tx_chan)
+ dma_release_channel(lfport->dma_tx_chan);
+ if (lfport->dma_rx_chan)
+ dma_release_channel(lfport->dma_rx_chan);
return ret;
}
@@ -933,6 +1478,13 @@ static void linflex_remove(struct platform_device *pdev)
uart_remove_one_port(&linflex_reg, sport);
clk_bulk_disable_unprepare(LINFLEX_CLK_NUM, lfport->clks);
+
+ if (lfport->dma_tx_chan)
+ dma_release_channel(lfport->dma_tx_chan);
+
+ if (lfport->dma_rx_chan)
+ dma_release_channel(lfport->dma_rx_chan);
+
}
#ifdef CONFIG_PM_SLEEP
--
2.47.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* [PATCH 13/13] serial: linflexuart: Avoid stopping DMA during receive operations
2026-02-16 15:01 [PATCH 00/13] Add DMA support for LINFlexD UART driver Larisa Grigore
` (11 preceding siblings ...)
2026-02-16 15:02 ` [PATCH 12/13] serial: linflexuart: Add DMA support Larisa Grigore
@ 2026-02-16 15:02 ` Larisa Grigore
2026-02-27 14:03 ` [PATCH 00/13] Add DMA support for LINFlexD UART driver Jared Kangas
13 siblings, 0 replies; 34+ messages in thread
From: Larisa Grigore @ 2026-02-16 15:02 UTC (permalink / raw)
To: gregkh, jirislaby, robh, krzk+dt, conor+dt, sumit.semwal,
christian.koenig, chester62515, cosmin.stoica, adrian.nitu,
stefan-gabriel.mirea, Mihaela.Martinas
Cc: linux-kernel, linux-serial, devicetree, linux-media, dri-devel,
linaro-mm-sig, s32, imx, clizzi, aruizrui, eballetb, echanude,
jkangas, Radu Pirea, Larisa Grigore
From: Radu Pirea <radu-nicolae.pirea@nxp.com>
Replace DMA single transactions with DMA cyclic transactions. Characters
may be lost between two single DMA transactions if the CPU is running at
lower frequencies.
Signed-off-by: Radu Pirea <radu-nicolae.pirea@nxp.com>
Co-developed-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
---
drivers/tty/serial/fsl_linflexuart.c | 119 +++++++++++++++------------
1 file changed, 68 insertions(+), 51 deletions(-)
diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c
index dff37c68cff0..4598c7ff669e 100644
--- a/drivers/tty/serial/fsl_linflexuart.c
+++ b/drivers/tty/serial/fsl_linflexuart.c
@@ -6,6 +6,7 @@
* Copyright 2017-2019, 2021-2022, 2025 NXP
*/
+#include <linux/circ_buf.h>
#include <linux/clk.h>
#include <linux/console.h>
#include <linux/dma-mapping.h>
@@ -180,7 +181,7 @@ struct linflex_port {
dma_addr_t dma_rx_buf_bus;
dma_cookie_t dma_tx_cookie;
dma_cookie_t dma_rx_cookie;
- unsigned char *dma_rx_buf_virt;
+ struct circ_buf dma_rx_ring_buf;
unsigned int dma_tx_bytes;
int dma_tx_in_progress;
int dma_rx_in_progress;
@@ -210,28 +211,63 @@ to_linflex_port(struct uart_port *uart)
return container_of(uart, struct linflex_port, port);
}
-static void linflex_copy_rx_to_tty(struct linflex_port *lfport,
- struct tty_port *tty, int count)
+static void linflex_copy_rx_to_tty(struct linflex_port *lfport)
{
- size_t copied;
-
- lfport->port.icount.rx += count;
+ struct circ_buf *ring_buf = &lfport->dma_rx_ring_buf;
+ struct tty_port *port = &lfport->port.state->port;
+ size_t count, received = 0, copied = 0;
+ struct dma_tx_state state;
+ enum dma_status dmastat;
+ int new_head;
- if (!tty) {
+ if (!port) {
dev_err(lfport->port.dev, "No tty port\n");
return;
}
+ dmastat = dmaengine_tx_status(lfport->dma_rx_chan, lfport->dma_rx_cookie, &state);
+ if (dmastat == DMA_ERROR) {
+ dev_err(lfport->port.dev, "Rx DMA transfer failed!\n");
+ return;
+ }
+
+ new_head = FSL_UART_RX_DMA_BUFFER_SIZE - state.residue;
+ if (ring_buf->head == new_head)
+ return;
+
+ ring_buf->head = new_head;
dma_sync_single_for_cpu(lfport->port.dev, lfport->dma_rx_buf_bus,
FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
- copied = tty_insert_flip_string(tty,
- ((unsigned char *)(lfport->dma_rx_buf_virt)),
- count);
- if (copied != count) {
- WARN_ON(1);
- dev_err(lfport->port.dev, "RxData copy to tty layer failed\n");
+ if (ring_buf->head > FSL_UART_RX_DMA_BUFFER_SIZE)
+ dev_err_once(lfport->port.dev,
+ "Circular buffer head bigger than the buffer size\n");
+
+ if (ring_buf->head < ring_buf->tail) {
+ count = FSL_UART_RX_DMA_BUFFER_SIZE - ring_buf->tail;
+ received += count;
+ copied += tty_insert_flip_string(port, ring_buf->buf + ring_buf->tail, count);
+ ring_buf->tail = 0;
+ lfport->port.icount.rx += count;
}
+
+ if (ring_buf->head > ring_buf->tail) {
+ count = ring_buf->head - ring_buf->tail;
+ received += count;
+ copied += tty_insert_flip_string(port, ring_buf->buf + ring_buf->tail, count);
+ if (ring_buf->head >= FSL_UART_RX_DMA_BUFFER_SIZE)
+ ring_buf->head = 0;
+ ring_buf->tail = ring_buf->head;
+ lfport->port.icount.rx += count;
+ }
+
+ if (copied != received)
+ dev_err_once(lfport->port.dev, "RxData copy to tty layer failed\n");
+
+ dma_sync_single_for_device(lfport->port.dev, lfport->dma_rx_buf_bus,
+ FSL_UART_RX_DMA_BUFFER_SIZE,
+ DMA_FROM_DEVICE);
+ tty_flip_buffer_push(port);
}
static void linflex_enable_dma_rx(struct uart_port *port)
@@ -348,8 +384,6 @@ static void _linflex_stop_rx(struct uart_port *port)
static void linflex_stop_rx(struct uart_port *port)
{
struct linflex_port *lfport = to_linflex_port(port);
- struct dma_tx_state state;
- unsigned int count;
_linflex_stop_rx(port);
@@ -357,14 +391,12 @@ static void linflex_stop_rx(struct uart_port *port)
return;
dmaengine_pause(lfport->dma_rx_chan);
- dmaengine_tx_status(lfport->dma_rx_chan,
- lfport->dma_rx_cookie, &state);
+ linflex_copy_rx_to_tty(lfport);
+ lfport->dma_rx_ring_buf.head = 0;
+ lfport->dma_rx_ring_buf.tail = 0;
dmaengine_terminate_all(lfport->dma_rx_chan);
- count = FSL_UART_RX_DMA_BUFFER_SIZE - state.residue;
lfport->dma_rx_in_progress = 0;
- linflex_copy_rx_to_tty(lfport, &port->state->port, count);
- tty_flip_buffer_push(&port->state->port);
}
static void linflex_put_char(struct uart_port *sport, unsigned char c)
@@ -501,11 +533,12 @@ static int linflex_dma_rx(struct linflex_port *lfport)
dma_sync_single_for_device(lfport->port.dev, lfport->dma_rx_buf_bus,
FSL_UART_RX_DMA_BUFFER_SIZE,
DMA_FROM_DEVICE);
- lfport->dma_rx_desc = dmaengine_prep_slave_single(lfport->dma_rx_chan,
- lfport->dma_rx_buf_bus,
- FSL_UART_RX_DMA_BUFFER_SIZE,
- DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT |
- DMA_CTRL_ACK);
+ lfport->dma_rx_desc =
+ dmaengine_prep_dma_cyclic(lfport->dma_rx_chan,
+ lfport->dma_rx_buf_bus,
+ FSL_UART_RX_DMA_BUFFER_SIZE,
+ FSL_UART_RX_DMA_BUFFER_SIZE / 2,
+ DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
if (!lfport->dma_rx_desc) {
dev_err(lfport->port.dev, "Not able to get desc for rx\n");
@@ -525,11 +558,8 @@ static int linflex_dma_rx(struct linflex_port *lfport)
static void linflex_dma_rx_complete(void *arg)
{
struct linflex_port *lfport = arg;
- struct tty_port *port = &lfport->port.state->port;
unsigned long flags;
- timer_delete_sync(&lfport->timer);
-
uart_port_lock_irqsave(&lfport->port, &flags);
/* stopped before? */
@@ -538,34 +568,17 @@ static void linflex_dma_rx_complete(void *arg)
return;
}
- lfport->dma_rx_in_progress = 0;
- linflex_copy_rx_to_tty(lfport, port, FSL_UART_RX_DMA_BUFFER_SIZE);
- tty_flip_buffer_push(port);
- linflex_dma_rx(lfport);
+ linflex_copy_rx_to_tty(lfport);
uart_port_unlock_irqrestore(&lfport->port, flags);
-
mod_timer(&lfport->timer, jiffies + lfport->dma_rx_timeout);
}
static void linflex_timer_func(struct timer_list *t)
{
struct linflex_port *lfport = timer_container_of(lfport, t, timer);
- unsigned long flags;
-
- uart_port_lock_irqsave(&lfport->port, &flags);
- /* stopped before? */
- if (!lfport->dma_rx_in_progress) {
- uart_port_unlock_irqrestore(&lfport->port, flags);
- return;
- }
-
- linflex_stop_rx(&lfport->port);
- linflex_dma_rx(lfport);
-
- uart_port_unlock_irqrestore(&lfport->port, flags);
- mod_timer(&lfport->timer, jiffies + lfport->dma_rx_timeout);
+ linflex_dma_rx_complete(lfport);
}
static void _linflex_start_tx(struct uart_port *port)
@@ -827,8 +840,8 @@ static int linflex_dma_rx_request(struct uart_port *port)
{
struct linflex_port *lfport = to_linflex_port(port);
struct dma_slave_config dma_rx_sconfig;
- unsigned char *dma_buf;
dma_addr_t dma_bus;
+ char *dma_buf;
int ret;
dma_buf = devm_kmalloc(port->dev, FSL_UART_RX_DMA_BUFFER_SIZE,
@@ -860,7 +873,9 @@ static int linflex_dma_rx_request(struct uart_port *port)
return ret;
}
- lfport->dma_rx_buf_virt = dma_buf;
+ lfport->dma_rx_ring_buf.buf = dma_buf;
+ lfport->dma_rx_ring_buf.head = 0;
+ lfport->dma_rx_ring_buf.tail = 0;
lfport->dma_rx_buf_bus = dma_bus;
lfport->dma_rx_in_progress = 0;
@@ -883,10 +898,12 @@ static void linflex_dma_rx_free(struct uart_port *port)
dma_unmap_single(lfport->port.dev, lfport->dma_rx_buf_bus,
FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
- devm_kfree(lfport->port.dev, lfport->dma_rx_buf_virt);
+ devm_kfree(lfport->port.dev, lfport->dma_rx_ring_buf.buf);
lfport->dma_rx_buf_bus = 0;
- lfport->dma_rx_buf_virt = NULL;
+ lfport->dma_rx_ring_buf.buf = NULL;
+ lfport->dma_rx_ring_buf.head = 0;
+ lfport->dma_rx_ring_buf.tail = 0;
}
static int linflex_startup(struct uart_port *port)
--
2.47.0
^ permalink raw reply related [flat|nested] 34+ messages in thread
* Re: [PATCH 08/13] dt-bindings: serial: fsl-linflexuart: add clock input properties
2026-02-16 15:02 ` [PATCH 08/13] dt-bindings: serial: fsl-linflexuart: add clock input properties Larisa Grigore
@ 2026-02-16 15:10 ` Krzysztof Kozlowski
2026-02-18 13:26 ` Larisa Ileana Grigore
0 siblings, 1 reply; 34+ messages in thread
From: Krzysztof Kozlowski @ 2026-02-16 15:10 UTC (permalink / raw)
To: Larisa Grigore, gregkh, jirislaby, robh, krzk+dt, conor+dt,
sumit.semwal, christian.koenig, chester62515, cosmin.stoica,
adrian.nitu, stefan-gabriel.mirea, Mihaela.Martinas
Cc: linux-kernel, linux-serial, devicetree, linux-media, dri-devel,
linaro-mm-sig, s32, imx, clizzi, aruizrui, eballetb, echanude,
jkangas, Radu Pirea
On 16/02/2026 16:02, Larisa Grigore wrote:
> From: Radu Pirea <radu-nicolae.pirea@nxp.com>
>
> Add optional support for the two clock inputs used by the LINFlexD UART
> controller:
> - "lin": LIN_BAUD_CLK
> - "ipg": LINFLEXD_CLK
>
> The clock inputs are kept optional to maintain compatibility with the
> S32V234 platform.
Does S32V234 have the clocks? I don't understand the "maintain
compatibility" in this context. Either you have or you have not clocks,
which should be expressed in schema (: false, see example schema).
>
> Signed-off-by: Radu Pirea <radu-nicolae.pirea@nxp.com>
> Co-developed-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
> Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
> ---
> .../bindings/serial/fsl,s32-linflexuart.yaml | 18 ++++++++++++++++++
> 1 file changed, 18 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml b/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml
> index 4171f524a928..885f0b1b3492 100644
> --- a/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml
> +++ b/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml
> @@ -34,6 +34,14 @@ properties:
> interrupts:
> maxItems: 1
>
> + clocks:
> + maxItems: 2
> +
> + clock-names:
> + items:
> + - const: lin
> + - const: ipg
> +
> required:
> - compatible
> - reg
> @@ -48,3 +56,13 @@ examples:
> reg = <0x40053000 0x1000>;
> interrupts = <0 59 4>;
> };
> +
> + - |
> + serial@401c8000 {
> + compatible = "nxp,s32g2-linflexuart",
> + "fsl,s32v234-linflexuart";
> + reg = <0x401C8000 0x3000>;
> + interrupts = <0 82 1>;
> + clocks = <&clks 14>, <&clks 13>;
> + clock-names = "lin", "ipg";
Just add the clocks to existing example. No need for new example for
each new property.
> + };
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 09/13] dt-bindings: serial: fsl-linflexuart: add dma properties
2026-02-16 15:02 ` [PATCH 09/13] dt-bindings: serial: fsl-linflexuart: add dma properties Larisa Grigore
@ 2026-02-16 15:10 ` Krzysztof Kozlowski
2026-02-18 14:44 ` Larisa Ileana Grigore
2026-02-16 15:29 ` Daniel Baluta
1 sibling, 1 reply; 34+ messages in thread
From: Krzysztof Kozlowski @ 2026-02-16 15:10 UTC (permalink / raw)
To: Larisa Grigore, gregkh, jirislaby, robh, krzk+dt, conor+dt,
sumit.semwal, christian.koenig, chester62515, cosmin.stoica,
adrian.nitu, stefan-gabriel.mirea, Mihaela.Martinas
Cc: linux-kernel, linux-serial, devicetree, linux-media, dri-devel,
linaro-mm-sig, s32, imx, clizzi, aruizrui, eballetb, echanude,
jkangas, Radu Pirea
On 16/02/2026 16:02, Larisa Grigore wrote:
> From: Radu Pirea <radu-nicolae.pirea@nxp.com>
>
> Add 'dmas' and 'dma-names' properties to describe optional DMA support
> for RX and TX channels in the LINFlexD UART controller.
Same question as in other patch about existing devices.
>
> This allows the device tree to specify DMA channels used for UART data
> transfers. If not specified, the driver will fall to interrupt-based
> operations.
>
> Signed-off-by: Radu Pirea <radu-nicolae.pirea@nxp.com>
> Co-developed-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
> Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
> ---
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 12/13] serial: linflexuart: Add DMA support
2026-02-16 15:02 ` [PATCH 12/13] serial: linflexuart: Add DMA support Larisa Grigore
@ 2026-02-16 15:11 ` Krzysztof Kozlowski
2026-02-16 20:48 ` kernel test robot
` (2 subsequent siblings)
3 siblings, 0 replies; 34+ messages in thread
From: Krzysztof Kozlowski @ 2026-02-16 15:11 UTC (permalink / raw)
To: Larisa Grigore, gregkh, jirislaby, robh, krzk+dt, conor+dt,
sumit.semwal, christian.koenig, chester62515, cosmin.stoica,
adrian.nitu, stefan-gabriel.mirea, Mihaela.Martinas
Cc: linux-kernel, linux-serial, devicetree, linux-media, dri-devel,
linaro-mm-sig, s32, imx, clizzi, aruizrui, eballetb, echanude,
jkangas, Radu Pirea, Phu Luu An, Js Ha, Ghennadi Procopciuc
On 16/02/2026 16:02, Larisa Grigore wrote:
> Add support for using DMA to avoid generating one interrupt per
> character and losing characters while copy-paste.
> In UART mode, the DMA capability can be used only if the UART Tx/Rx
> buffers are configured as FIFOs.
> If the DMA related properties are missing from the device tree, the
> driver will fall back to interrupt + Buffer mode.
> On the RX side, a timer is used to periodically poll for received data.
>
> Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
> Co-developed-by: Stoica Cosmin-Stefan <cosmin.stoica@nxp.com>
> Signed-off-by: Stoica Cosmin-Stefan <cosmin.stoica@nxp.com>
> Co-developed-by: Radu Pirea <radu-nicolae.pirea@nxp.com>
> Signed-off-by: Radu Pirea <radu-nicolae.pirea@nxp.com>
> Co-developed-by: Phu Luu An <phu.luuan@nxp.com>
> Signed-off-by: Phu Luu An <phu.luuan@nxp.com>
> Co-developed-by: Js Ha <js.ha@nxp.com>
> Signed-off-by: Js Ha <js.ha@nxp.com>
> Co-developed-by: Ghennadi Procopciuc <ghennadi.procopciuc@nxp.com>
> Signed-off-by: Ghennadi Procopciuc <ghennadi.procopciuc@nxp.com>
Incorrect DCO chain. Please read submitting patches document.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 09/13] dt-bindings: serial: fsl-linflexuart: add dma properties
2026-02-16 15:02 ` [PATCH 09/13] dt-bindings: serial: fsl-linflexuart: add dma properties Larisa Grigore
2026-02-16 15:10 ` Krzysztof Kozlowski
@ 2026-02-16 15:29 ` Daniel Baluta
2026-02-17 8:10 ` Krzysztof Kozlowski
1 sibling, 1 reply; 34+ messages in thread
From: Daniel Baluta @ 2026-02-16 15:29 UTC (permalink / raw)
To: Larisa Grigore, gregkh, jirislaby, robh, krzk+dt, conor+dt,
sumit.semwal, christian.koenig, chester62515, cosmin.stoica,
adrian.nitu, stefan-gabriel.mirea, Mihaela.Martinas
Cc: linux-kernel, linux-serial, devicetree, linux-media, dri-devel,
linaro-mm-sig, s32, imx, clizzi, aruizrui, eballetb, echanude,
jkangas, Radu Pirea
On 2/16/26 17:02, Larisa Grigore wrote:
> [You don't often get email from larisa.grigore@oss.nxp.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
>
> From: Radu Pirea <radu-nicolae.pirea@nxp.com>
>
> Add 'dmas' and 'dma-names' properties to describe optional DMA support
> for RX and TX channels in the LINFlexD UART controller.
>
> This allows the device tree to specify DMA channels used for UART data
> transfers. If not specified, the driver will fall to interrupt-based
> operations.
>
> Signed-off-by: Radu Pirea <radu-nicolae.pirea@nxp.com>
> Co-developed-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
> Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
If both of you worked on this patch then the last lines must read:
Co-developed-by: Radu Pirea <radu-nicolae.pirea@nxp.com>
Signed-off-by: Radu Pirea <radu-nicolae.pirea@nxp.com>
Co-developed-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
See: https://docs.kernel.org/process/submitting-patches.html
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 01/13] serial: linflexuart: Fix locking in set_termios
2026-02-16 15:01 ` [PATCH 01/13] serial: linflexuart: Fix locking in set_termios Larisa Grigore
@ 2026-02-16 20:16 ` Frank Li
2026-02-18 11:58 ` Larisa Ileana Grigore
0 siblings, 1 reply; 34+ messages in thread
From: Frank Li @ 2026-02-16 20:16 UTC (permalink / raw)
To: Larisa Grigore
Cc: gregkh, jirislaby, robh, krzk+dt, conor+dt, sumit.semwal,
christian.koenig, chester62515, cosmin.stoica, adrian.nitu,
stefan-gabriel.mirea, Mihaela.Martinas, linux-kernel,
linux-serial, devicetree, linux-media, dri-devel, linaro-mm-sig,
s32, imx, clizzi, aruizrui, eballetb, echanude, jkangas,
Radu Pirea
On Mon, Feb 16, 2026 at 04:01:53PM +0100, Larisa Grigore wrote:
> From: Radu Pirea <radu-nicolae.pirea@nxp.com>
>
> Take the port->lock when set_termios is called, otherwise if characters
> are sent while IP is in init mode, the IP will hang in an uncertain
> state.
According to patch, you move it before read(UARTCR). can explain why hang?
Frank
>
> Fixes: 09864c1cdf5c ("tty: serial: Add linflexuart driver for S32V234")
> Signed-off-by: Radu Pirea <radu-nicolae.pirea@nxp.com>
> Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
> ---
> drivers/tty/serial/fsl_linflexuart.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c
> index e70a56de1fce..5a410e2d56ac 100644
> --- a/drivers/tty/serial/fsl_linflexuart.c
> +++ b/drivers/tty/serial/fsl_linflexuart.c
> @@ -407,6 +407,8 @@ linflex_set_termios(struct uart_port *port, struct ktermios *termios,
> unsigned long cr, old_cr, cr1;
> unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
>
> + uart_port_lock_irqsave(port, &flags);
> +
> cr = readl(port->membase + UARTCR);
> old_cr = cr;
>
> @@ -475,8 +477,6 @@ linflex_set_termios(struct uart_port *port, struct ktermios *termios,
> cr &= ~LINFLEXD_UARTCR_PCE;
> }
>
> - uart_port_lock_irqsave(port, &flags);
> -
> port->read_status_mask = 0;
>
> if (termios->c_iflag & INPCK)
> --
> 2.47.0
>
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 02/13] serial: linflexuart: Clean SLEEP bit in LINCR1 after suspend
2026-02-16 15:01 ` [PATCH 02/13] serial: linflexuart: Clean SLEEP bit in LINCR1 after suspend Larisa Grigore
@ 2026-02-16 20:22 ` Frank Li
2026-02-18 12:09 ` Larisa Ileana Grigore
0 siblings, 1 reply; 34+ messages in thread
From: Frank Li @ 2026-02-16 20:22 UTC (permalink / raw)
To: Larisa Grigore
Cc: gregkh, jirislaby, robh, krzk+dt, conor+dt, sumit.semwal,
christian.koenig, chester62515, cosmin.stoica, adrian.nitu,
stefan-gabriel.mirea, Mihaela.Martinas, linux-kernel,
linux-serial, devicetree, linux-media, dri-devel, linaro-mm-sig,
s32, imx, clizzi, aruizrui, eballetb, echanude, jkangas
On Mon, Feb 16, 2026 at 04:01:54PM +0100, Larisa Grigore wrote:
> When coming back from reset, we need to re-initialize LINCR1 register.
> SLEEP bit should be cleared, otherwise we can't enter INITM mode.
serial: linflexuart: Clean SLEEP bit in LINCR1 at linflex_set_termios()
Re-initialize LINCR1 register (Clear the SLEEP bit) at
linflex_set_termios(), otherwise the controller cannot enter INITM mode
after suspend/resume.
Frank
>
> Fixes: 09864c1cdf5c ("tty: serial: Add linflexuart driver for S32V234")
> Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
> ---
> drivers/tty/serial/fsl_linflexuart.c | 3 +--
> 1 file changed, 1 insertion(+), 2 deletions(-)
>
> diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c
> index 5a410e2d56ac..016011fd8760 100644
> --- a/drivers/tty/serial/fsl_linflexuart.c
> +++ b/drivers/tty/serial/fsl_linflexuart.c
> @@ -413,8 +413,7 @@ linflex_set_termios(struct uart_port *port, struct ktermios *termios,
> old_cr = cr;
>
> /* Enter initialization mode by setting INIT bit */
> - cr1 = readl(port->membase + LINCR1);
> - cr1 |= LINFLEXD_LINCR1_INIT;
> + cr1 = LINFLEXD_LINCR1_INIT | LINFLEXD_LINCR1_MME;
> writel(cr1, port->membase + LINCR1);
>
> /* wait for init mode entry */
> --
> 2.47.0
>
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 12/13] serial: linflexuart: Add DMA support
2026-02-16 15:02 ` [PATCH 12/13] serial: linflexuart: Add DMA support Larisa Grigore
2026-02-16 15:11 ` Krzysztof Kozlowski
@ 2026-02-16 20:48 ` kernel test robot
2026-02-17 3:26 ` kernel test robot
2026-02-19 8:22 ` Dan Carpenter
3 siblings, 0 replies; 34+ messages in thread
From: kernel test robot @ 2026-02-16 20:48 UTC (permalink / raw)
To: Larisa Grigore, gregkh, jirislaby, robh, krzk+dt, conor+dt,
sumit.semwal, christian.koenig, chester62515, cosmin.stoica,
adrian.nitu, stefan-gabriel.mirea, Mihaela.Martinas
Cc: oe-kbuild-all, linux-kernel, linux-serial, devicetree,
linux-media, dri-devel, linaro-mm-sig, s32, imx, clizzi, aruizrui,
eballetb, echanude, jkangas, Larisa Grigore, Radu Pirea,
Phu Luu An, Js Ha, Ghennadi Procopciuc
Hi Larisa,
kernel test robot noticed the following build warnings:
[auto build test WARNING on tty/tty-testing]
[also build test WARNING on tty/tty-next tty/tty-linus usb/usb-testing usb/usb-next usb/usb-linus robh/for-next linus/master v6.19 next-20260216]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Larisa-Grigore/serial-linflexuart-Fix-locking-in-set_termios/20260216-231403
base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tty-testing
patch link: https://lore.kernel.org/r/20260216150205.212318-13-larisa.grigore%40oss.nxp.com
patch subject: [PATCH 12/13] serial: linflexuart: Add DMA support
config: parisc-randconfig-001-20260217 (https://download.01.org/0day-ci/archive/20260217/202602170428.SOCWu0Wb-lkp@intel.com/config)
compiler: hppa-linux-gcc (GCC) 15.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260217/202602170428.SOCWu0Wb-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202602170428.SOCWu0Wb-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> drivers/tty/serial/fsl_linflexuart.c:205:13: warning: 'linflex_console_putchar' declared 'static' but never defined [-Wunused-function]
205 | static void linflex_console_putchar(struct uart_port *port, unsigned char ch);
| ^~~~~~~~~~~~~~~~~~~~~~~
vim +205 drivers/tty/serial/fsl_linflexuart.c
202
203 static void linflex_dma_tx_complete(void *arg);
204 static void linflex_dma_rx_complete(void *arg);
> 205 static void linflex_console_putchar(struct uart_port *port, unsigned char ch);
206
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 12/13] serial: linflexuart: Add DMA support
2026-02-16 15:02 ` [PATCH 12/13] serial: linflexuart: Add DMA support Larisa Grigore
2026-02-16 15:11 ` Krzysztof Kozlowski
2026-02-16 20:48 ` kernel test robot
@ 2026-02-17 3:26 ` kernel test robot
2026-02-19 8:22 ` Dan Carpenter
3 siblings, 0 replies; 34+ messages in thread
From: kernel test robot @ 2026-02-17 3:26 UTC (permalink / raw)
To: Larisa Grigore, gregkh, jirislaby, robh, krzk+dt, conor+dt,
sumit.semwal, christian.koenig, chester62515, cosmin.stoica,
adrian.nitu, stefan-gabriel.mirea, Mihaela.Martinas
Cc: llvm, oe-kbuild-all, linux-kernel, linux-serial, devicetree,
linux-media, dri-devel, linaro-mm-sig, s32, imx, clizzi, aruizrui,
eballetb, echanude, jkangas, Larisa Grigore, Radu Pirea,
Phu Luu An, Js Ha, Ghennadi Procopciuc
Hi Larisa,
kernel test robot noticed the following build warnings:
[auto build test WARNING on tty/tty-testing]
[also build test WARNING on tty/tty-next tty/tty-linus usb/usb-testing usb/usb-next usb/usb-linus robh/for-next linus/master v6.19 next-20260216]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Larisa-Grigore/serial-linflexuart-Fix-locking-in-set_termios/20260216-231403
base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tty-testing
patch link: https://lore.kernel.org/r/20260216150205.212318-13-larisa.grigore%40oss.nxp.com
patch subject: [PATCH 12/13] serial: linflexuart: Add DMA support
config: i386-buildonly-randconfig-002-20260217 (https://download.01.org/0day-ci/archive/20260217/202602171112.rMhRspEp-lkp@intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260217/202602171112.rMhRspEp-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202602171112.rMhRspEp-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> drivers/tty/serial/fsl_linflexuart.c:1095:6: warning: variable 'baud' is used uninitialized whenever 'if' condition is false [-Wsometimes-uninitialized]
1095 | if (port->uartclk) {
| ^~~~~~~~~~~~~
drivers/tty/serial/fsl_linflexuart.c:1113:67: note: uninitialized use occurs here
1113 | lfport->dma_rx_timeout = msecs_to_jiffies(DIV_ROUND_UP(10000000, baud));
| ^~~~
include/linux/math.h:49:22: note: expanded from macro 'DIV_ROUND_UP'
49 | #define DIV_ROUND_UP __KERNEL_DIV_ROUND_UP
| ^
include/uapi/linux/const.h:51:46: note: expanded from macro '__KERNEL_DIV_ROUND_UP'
51 | #define __KERNEL_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
| ^
drivers/tty/serial/fsl_linflexuart.c:1095:2: note: remove the 'if' if its condition is always true
1095 | if (port->uartclk) {
| ^~~~~~~~~~~~~~~~~~
drivers/tty/serial/fsl_linflexuart.c:970:19: note: initialize the variable 'baud' to silence this warning
970 | unsigned int baud;
| ^
| = 0
drivers/tty/serial/fsl_linflexuart.c:205:13: warning: unused function 'linflex_console_putchar' [-Wunused-function]
205 | static void linflex_console_putchar(struct uart_port *port, unsigned char ch);
| ^~~~~~~~~~~~~~~~~~~~~~~
2 warnings generated.
vim +1095 drivers/tty/serial/fsl_linflexuart.c
1d3f5f07fafc712 Radu Pirea 2026-02-16 959
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 960 static void
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 961 linflex_set_termios(struct uart_port *port, struct ktermios *termios,
bec5b814d46c2a7 Ilpo Järvinen 2022-08-16 962 const struct ktermios *old)
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 963 {
0b34325c5f79f1f Larisa Grigore 2026-02-16 964 struct linflex_port *lfport = to_linflex_port(port);
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 965 unsigned long flags;
1312e6586227421 Larisa Grigore 2026-02-16 966 unsigned long cr, old_cr, cr1, gcr;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 967 unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
1d3f5f07fafc712 Radu Pirea 2026-02-16 968 unsigned long ibr, fbr, divisr, dividr;
1d3f5f07fafc712 Radu Pirea 2026-02-16 969 unsigned char ldiv_mul;
1d3f5f07fafc712 Radu Pirea 2026-02-16 970 unsigned int baud;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 971
a75137a58feb092 Radu Pirea 2026-02-16 972 uart_port_lock_irqsave(port, &flags);
a75137a58feb092 Radu Pirea 2026-02-16 973
0b34325c5f79f1f Larisa Grigore 2026-02-16 974 _linflex_stop_rx(port);
0b34325c5f79f1f Larisa Grigore 2026-02-16 975 _linflex_stop_tx(port);
0b34325c5f79f1f Larisa Grigore 2026-02-16 976
fb1da4d7f0bec28 Larisa Grigore 2026-02-16 977 old_cr = readl(port->membase + UARTCR) &
fb1da4d7f0bec28 Larisa Grigore 2026-02-16 978 ~(LINFLEXD_UARTCR_RXEN | LINFLEXD_UARTCR_TXEN);
fb1da4d7f0bec28 Larisa Grigore 2026-02-16 979 cr = old_cr;
fb1da4d7f0bec28 Larisa Grigore 2026-02-16 980
fb1da4d7f0bec28 Larisa Grigore 2026-02-16 981 /* In FIFO mode, we should make sure the fifo is empty
fb1da4d7f0bec28 Larisa Grigore 2026-02-16 982 * before entering INITM.
fb1da4d7f0bec28 Larisa Grigore 2026-02-16 983 */
fb1da4d7f0bec28 Larisa Grigore 2026-02-16 984 linflex_wait_tx_fifo_empty(port);
fb1da4d7f0bec28 Larisa Grigore 2026-02-16 985
fb1da4d7f0bec28 Larisa Grigore 2026-02-16 986 /* disable transmit and receive */
fb1da4d7f0bec28 Larisa Grigore 2026-02-16 987 writel(old_cr, port->membase + UARTCR);
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 988
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 989 /* Enter initialization mode by setting INIT bit */
5e8e1ccacae0470 Larisa Grigore 2026-02-16 990 cr1 = LINFLEXD_LINCR1_INIT | LINFLEXD_LINCR1_MME;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 991 writel(cr1, port->membase + LINCR1);
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 992
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 993 /* wait for init mode entry */
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 994 while ((readl(port->membase + LINSR)
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 995 & LINFLEXD_LINSR_LINS_MASK)
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 996 != LINFLEXD_LINSR_LINS_INITMODE)
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 997 ;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 998
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 999 /*
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1000 * only support CS8 and CS7, and for CS7 must enable PE.
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1001 * supported mode:
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1002 * - (7,e/o,1)
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1003 * - (8,n,1)
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1004 * - (8,e/o,1)
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1005 */
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1006 /* enter the UART into configuration mode */
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1007
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1008 while ((termios->c_cflag & CSIZE) != CS8 &&
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1009 (termios->c_cflag & CSIZE) != CS7) {
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1010 termios->c_cflag &= ~CSIZE;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1011 termios->c_cflag |= old_csize;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1012 old_csize = CS8;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1013 }
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1014
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1015 if ((termios->c_cflag & CSIZE) == CS7) {
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1016 /* Word length: WL1WL0:00 */
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1017 cr = old_cr & ~LINFLEXD_UARTCR_WL1 & ~LINFLEXD_UARTCR_WL0;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1018 }
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1019
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1020 if ((termios->c_cflag & CSIZE) == CS8) {
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1021 /* Word length: WL1WL0:01 */
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1022 cr = (old_cr | LINFLEXD_UARTCR_WL0) & ~LINFLEXD_UARTCR_WL1;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1023 }
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1024
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1025 if (termios->c_cflag & CMSPAR) {
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1026 if ((termios->c_cflag & CSIZE) != CS8) {
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1027 termios->c_cflag &= ~CSIZE;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1028 termios->c_cflag |= CS8;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1029 }
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1030 /* has a space/sticky bit */
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1031 cr |= LINFLEXD_UARTCR_WL0;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1032 }
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1033
1312e6586227421 Larisa Grigore 2026-02-16 1034 gcr = readl(port->membase + GCR);
1312e6586227421 Larisa Grigore 2026-02-16 1035
1312e6586227421 Larisa Grigore 2026-02-16 1036 if (termios->c_cflag & CSTOPB) {
1312e6586227421 Larisa Grigore 2026-02-16 1037 /* Use 2 stop bits. */
1312e6586227421 Larisa Grigore 2026-02-16 1038 cr = (cr & ~LINFLEXD_UARTCR_SBUR_MASK) |
1312e6586227421 Larisa Grigore 2026-02-16 1039 LINFLEXD_UARTCR_SBUR_2SBITS;
1312e6586227421 Larisa Grigore 2026-02-16 1040 /* Set STOP in GCR field for 2 stop bits. */
1312e6586227421 Larisa Grigore 2026-02-16 1041 gcr = (gcr & ~LINFLEXD_GCR_STOP_MASK) |
1312e6586227421 Larisa Grigore 2026-02-16 1042 LINFLEXD_GCR_STOP_2SBITS;
1312e6586227421 Larisa Grigore 2026-02-16 1043 } else {
1312e6586227421 Larisa Grigore 2026-02-16 1044 /* Use 1 stop bit. */
1312e6586227421 Larisa Grigore 2026-02-16 1045 cr = (cr & ~LINFLEXD_UARTCR_SBUR_MASK) |
1312e6586227421 Larisa Grigore 2026-02-16 1046 LINFLEXD_UARTCR_SBUR_1SBITS;
1312e6586227421 Larisa Grigore 2026-02-16 1047 /* Set STOP in GCR field for 1 stop bit. */
1312e6586227421 Larisa Grigore 2026-02-16 1048 gcr = (gcr & ~LINFLEXD_GCR_STOP_MASK) |
1312e6586227421 Larisa Grigore 2026-02-16 1049 LINFLEXD_GCR_STOP_1SBITS;
1312e6586227421 Larisa Grigore 2026-02-16 1050 }
1312e6586227421 Larisa Grigore 2026-02-16 1051 /* Update GCR register. */
1312e6586227421 Larisa Grigore 2026-02-16 1052 writel(gcr, port->membase + GCR);
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1053
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1054 /* parity must be enabled when CS7 to match 8-bits format */
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1055 if ((termios->c_cflag & CSIZE) == CS7)
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1056 termios->c_cflag |= PARENB;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1057
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1058 if ((termios->c_cflag & PARENB)) {
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1059 cr |= LINFLEXD_UARTCR_PCE;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1060 if (termios->c_cflag & PARODD)
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1061 cr = (cr | LINFLEXD_UARTCR_PC0) &
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1062 (~LINFLEXD_UARTCR_PC1);
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1063 else
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1064 cr = cr & (~LINFLEXD_UARTCR_PC1 &
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1065 ~LINFLEXD_UARTCR_PC0);
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1066 } else {
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1067 cr &= ~LINFLEXD_UARTCR_PCE;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1068 }
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1069
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1070 port->read_status_mask = 0;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1071
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1072 if (termios->c_iflag & INPCK)
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1073 port->read_status_mask |= (LINFLEXD_UARTSR_FEF |
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1074 LINFLEXD_UARTSR_PE0 |
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1075 LINFLEXD_UARTSR_PE1 |
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1076 LINFLEXD_UARTSR_PE2 |
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1077 LINFLEXD_UARTSR_PE3);
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1078 if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1079 port->read_status_mask |= LINFLEXD_UARTSR_FEF;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1080
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1081 /* characters to ignore */
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1082 port->ignore_status_mask = 0;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1083 if (termios->c_iflag & IGNPAR)
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1084 port->ignore_status_mask |= LINFLEXD_UARTSR_PE;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1085 if (termios->c_iflag & IGNBRK) {
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1086 port->ignore_status_mask |= LINFLEXD_UARTSR_PE;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1087 /*
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1088 * if we're ignoring parity and break indicators,
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1089 * ignore overruns too (for real raw support).
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1090 */
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1091 if (termios->c_iflag & IGNPAR)
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1092 port->ignore_status_mask |= LINFLEXD_UARTSR_BOF;
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1093 }
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1094
1d3f5f07fafc712 Radu Pirea 2026-02-16 @1095 if (port->uartclk) {
1d3f5f07fafc712 Radu Pirea 2026-02-16 1096 ldiv_mul = linflex_ldiv_multiplier(port);
1d3f5f07fafc712 Radu Pirea 2026-02-16 1097 baud = uart_get_baud_rate(port, termios, old, 0,
1d3f5f07fafc712 Radu Pirea 2026-02-16 1098 port->uartclk / ldiv_mul);
1d3f5f07fafc712 Radu Pirea 2026-02-16 1099
1d3f5f07fafc712 Radu Pirea 2026-02-16 1100 /* update the per-port timeout */
1d3f5f07fafc712 Radu Pirea 2026-02-16 1101 uart_update_timeout(port, termios->c_cflag, baud);
1d3f5f07fafc712 Radu Pirea 2026-02-16 1102
1d3f5f07fafc712 Radu Pirea 2026-02-16 1103 divisr = port->uartclk;
1d3f5f07fafc712 Radu Pirea 2026-02-16 1104 dividr = ((unsigned long)baud * ldiv_mul);
1d3f5f07fafc712 Radu Pirea 2026-02-16 1105
1d3f5f07fafc712 Radu Pirea 2026-02-16 1106 ibr = divisr / dividr;
1d3f5f07fafc712 Radu Pirea 2026-02-16 1107 fbr = ((divisr % dividr) * 16 / dividr) & 0xF;
1d3f5f07fafc712 Radu Pirea 2026-02-16 1108
1d3f5f07fafc712 Radu Pirea 2026-02-16 1109 writel(ibr, port->membase + LINIBRR);
1d3f5f07fafc712 Radu Pirea 2026-02-16 1110 writel(fbr, port->membase + LINFBRR);
1d3f5f07fafc712 Radu Pirea 2026-02-16 1111 }
1d3f5f07fafc712 Radu Pirea 2026-02-16 1112
0b34325c5f79f1f Larisa Grigore 2026-02-16 1113 lfport->dma_rx_timeout = msecs_to_jiffies(DIV_ROUND_UP(10000000, baud));
0b34325c5f79f1f Larisa Grigore 2026-02-16 1114
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1115 writel(cr, port->membase + UARTCR);
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1116
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1117 cr1 &= ~(LINFLEXD_LINCR1_INIT);
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1118
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1119 writel(cr1, port->membase + LINCR1);
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1120
fb1da4d7f0bec28 Larisa Grigore 2026-02-16 1121 cr |= (LINFLEXD_UARTCR_TXEN) | (LINFLEXD_UARTCR_RXEN);
fb1da4d7f0bec28 Larisa Grigore 2026-02-16 1122 writel(cr, port->membase + UARTCR);
fb1da4d7f0bec28 Larisa Grigore 2026-02-16 1123
0b34325c5f79f1f Larisa Grigore 2026-02-16 1124 _linflex_start_rx(port);
0b34325c5f79f1f Larisa Grigore 2026-02-16 1125 _linflex_start_tx(port);
0b34325c5f79f1f Larisa Grigore 2026-02-16 1126
7c6725ffd581335 Thomas Gleixner 2023-09-14 1127 uart_port_unlock_irqrestore(port, flags);
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1128 }
09864c1cdf5c537 Stefan-gabriel Mirea 2019-08-09 1129
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 09/13] dt-bindings: serial: fsl-linflexuart: add dma properties
2026-02-16 15:29 ` Daniel Baluta
@ 2026-02-17 8:10 ` Krzysztof Kozlowski
2026-02-17 8:39 ` Daniel Baluta
0 siblings, 1 reply; 34+ messages in thread
From: Krzysztof Kozlowski @ 2026-02-17 8:10 UTC (permalink / raw)
To: Daniel Baluta
Cc: Larisa Grigore, gregkh, jirislaby, robh, krzk+dt, conor+dt,
sumit.semwal, christian.koenig, chester62515, cosmin.stoica,
adrian.nitu, stefan-gabriel.mirea, Mihaela.Martinas, linux-kernel,
linux-serial, devicetree, linux-media, dri-devel, linaro-mm-sig,
s32, imx, clizzi, aruizrui, eballetb, echanude, jkangas,
Radu Pirea
On Mon, Feb 16, 2026 at 05:29:57PM +0200, Daniel Baluta wrote:
>
> On 2/16/26 17:02, Larisa Grigore wrote:
> > [You don't often get email from larisa.grigore@oss.nxp.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
> >
> > From: Radu Pirea <radu-nicolae.pirea@nxp.com>
> >
> > Add 'dmas' and 'dma-names' properties to describe optional DMA support
> > for RX and TX channels in the LINFlexD UART controller.
> >
> > This allows the device tree to specify DMA channels used for UART data
> > transfers. If not specified, the driver will fall to interrupt-based
> > operations.
> >
> > Signed-off-by: Radu Pirea <radu-nicolae.pirea@nxp.com>
> > Co-developed-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
> > Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
>
> If both of you worked on this patch then the last lines must read:
>
> Co-developed-by: Radu Pirea <radu-nicolae.pirea@nxp.com>
>
> Signed-off-by: Radu Pirea <radu-nicolae.pirea@nxp.com>
>
> Co-developed-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
>
> Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
No, the DCO with this authorship is correct if they both worked. Nothing
has to be changed here.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 09/13] dt-bindings: serial: fsl-linflexuart: add dma properties
2026-02-17 8:10 ` Krzysztof Kozlowski
@ 2026-02-17 8:39 ` Daniel Baluta
0 siblings, 0 replies; 34+ messages in thread
From: Daniel Baluta @ 2026-02-17 8:39 UTC (permalink / raw)
To: Krzysztof Kozlowski
Cc: Larisa Grigore, gregkh, jirislaby, robh, krzk+dt, conor+dt,
sumit.semwal, christian.koenig, chester62515, cosmin.stoica,
adrian.nitu, stefan-gabriel.mirea, Mihaela.Martinas, linux-kernel,
linux-serial, devicetree, linux-media, dri-devel, linaro-mm-sig,
s32, imx, clizzi, aruizrui, eballetb, echanude, jkangas,
Radu Pirea
On 2/17/26 10:10, Krzysztof Kozlowski wrote:
> On Mon, Feb 16, 2026 at 05:29:57PM +0200, Daniel Baluta wrote:
>> On 2/16/26 17:02, Larisa Grigore wrote:
>>> [You don't often get email from larisa.grigore@oss.nxp.com. Learn why this is important at https://aka.ms/LearnAboutSenderIdentification ]
>>>
>>> From: Radu Pirea <radu-nicolae.pirea@nxp.com>
>>>
>>> Add 'dmas' and 'dma-names' properties to describe optional DMA support
>>> for RX and TX channels in the LINFlexD UART controller.
>>>
>>> This allows the device tree to specify DMA channels used for UART data
>>> transfers. If not specified, the driver will fall to interrupt-based
>>> operations.
>>>
>>> Signed-off-by: Radu Pirea <radu-nicolae.pirea@nxp.com>
>>> Co-developed-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
>>> Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
>> If both of you worked on this patch then the last lines must read:
>>
>> Co-developed-by: Radu Pirea <radu-nicolae.pirea@nxp.com>
>>
>> Signed-off-by: Radu Pirea <radu-nicolae.pirea@nxp.com>
>>
>> Co-developed-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
>>
>> Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
> No, the DCO with this authorship is correct if they both worked. Nothing
> has to be changed here.
Got it now. There is no need to add C-d-by for the people listed as 'main' author
via the 'From' tag.
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 01/13] serial: linflexuart: Fix locking in set_termios
2026-02-16 20:16 ` Frank Li
@ 2026-02-18 11:58 ` Larisa Ileana Grigore
0 siblings, 0 replies; 34+ messages in thread
From: Larisa Ileana Grigore @ 2026-02-18 11:58 UTC (permalink / raw)
To: Frank Li
Cc: gregkh, jirislaby, robh, krzk+dt, conor+dt, sumit.semwal,
christian.koenig, chester62515, cosmin.stoica, adrian.nitu,
stefan-gabriel.mirea, Mihaela.Martinas, linux-kernel,
linux-serial, devicetree, linux-media, dri-devel, linaro-mm-sig,
s32, imx, clizzi, aruizrui, eballetb, echanude, jkangas,
Radu Pirea
On 2/16/2026 10:16 PM, Frank Li wrote:
> On Mon, Feb 16, 2026 at 04:01:53PM +0100, Larisa Grigore wrote:
>> From: Radu Pirea <radu-nicolae.pirea@nxp.com>
>>
>> Take the port->lock when set_termios is called, otherwise if characters
>> are sent while IP is in init mode, the IP will hang in an uncertain
>> state.
>
> According to patch, you move it before read(UARTCR). can explain why hang?
>
> Frank
Hello Frank,
Thanks for the review! This change was made to not let anyone send
characters (for example calling `linflex_console_putchar`) while
LINFlexD is entering INIT mode. The INIT mode is entered when setting
LINFLEXD_LINCR1_INIT in LINCR1. UARTCR should also be protected with a
lock since it can be modified from different other places.
I will update the commit description.
Regards,
Larisa
>>
>> Fixes: 09864c1cdf5c ("tty: serial: Add linflexuart driver for S32V234")
>> Signed-off-by: Radu Pirea <radu-nicolae.pirea@nxp.com>
>> Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
>> ---
>> drivers/tty/serial/fsl_linflexuart.c | 4 ++--
>> 1 file changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c
>> index e70a56de1fce..5a410e2d56ac 100644
>> --- a/drivers/tty/serial/fsl_linflexuart.c
>> +++ b/drivers/tty/serial/fsl_linflexuart.c
>> @@ -407,6 +407,8 @@ linflex_set_termios(struct uart_port *port, struct ktermios *termios,
>> unsigned long cr, old_cr, cr1;
>> unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
>>
>> + uart_port_lock_irqsave(port, &flags);
>> +
>> cr = readl(port->membase + UARTCR);
>> old_cr = cr;
>>
>> @@ -475,8 +477,6 @@ linflex_set_termios(struct uart_port *port, struct ktermios *termios,
>> cr &= ~LINFLEXD_UARTCR_PCE;
>> }
>>
>> - uart_port_lock_irqsave(port, &flags);
>> -
>> port->read_status_mask = 0;
>>
>> if (termios->c_iflag & INPCK)
>> --
>> 2.47.0
>>
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 02/13] serial: linflexuart: Clean SLEEP bit in LINCR1 after suspend
2026-02-16 20:22 ` Frank Li
@ 2026-02-18 12:09 ` Larisa Ileana Grigore
0 siblings, 0 replies; 34+ messages in thread
From: Larisa Ileana Grigore @ 2026-02-18 12:09 UTC (permalink / raw)
To: Frank Li
Cc: gregkh, jirislaby, robh, krzk+dt, conor+dt, sumit.semwal,
christian.koenig, chester62515, cosmin.stoica, adrian.nitu,
stefan-gabriel.mirea, Mihaela.Martinas, linux-kernel,
linux-serial, devicetree, linux-media, dri-devel, linaro-mm-sig,
s32, imx, clizzi, aruizrui, eballetb, echanude, jkangas
On 2/16/2026 10:22 PM, Frank Li wrote:
> On Mon, Feb 16, 2026 at 04:01:54PM +0100, Larisa Grigore wrote:
>> When coming back from reset, we need to re-initialize LINCR1 register.
>> SLEEP bit should be cleared, otherwise we can't enter INITM mode.
>
> serial: linflexuart: Clean SLEEP bit in LINCR1 at linflex_set_termios()
>
> Re-initialize LINCR1 register (Clear the SLEEP bit) at
> linflex_set_termios(), otherwise the controller cannot enter INITM mode
> after suspend/resume.
>
> Frank
>>
Thanks!
>> Fixes: 09864c1cdf5c ("tty: serial: Add linflexuart driver for S32V234")
>> Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
>> ---
>> drivers/tty/serial/fsl_linflexuart.c | 3 +--
>> 1 file changed, 1 insertion(+), 2 deletions(-)
>>
>> diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c
>> index 5a410e2d56ac..016011fd8760 100644
>> --- a/drivers/tty/serial/fsl_linflexuart.c
>> +++ b/drivers/tty/serial/fsl_linflexuart.c
>> @@ -413,8 +413,7 @@ linflex_set_termios(struct uart_port *port, struct ktermios *termios,
>> old_cr = cr;
>>
>> /* Enter initialization mode by setting INIT bit */
>> - cr1 = readl(port->membase + LINCR1);
>> - cr1 |= LINFLEXD_LINCR1_INIT;
>> + cr1 = LINFLEXD_LINCR1_INIT | LINFLEXD_LINCR1_MME;
>> writel(cr1, port->membase + LINCR1);
>>
>> /* wait for init mode entry */
>> --
>> 2.47.0
>>
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 08/13] dt-bindings: serial: fsl-linflexuart: add clock input properties
2026-02-16 15:10 ` Krzysztof Kozlowski
@ 2026-02-18 13:26 ` Larisa Ileana Grigore
2026-02-18 13:29 ` Krzysztof Kozlowski
0 siblings, 1 reply; 34+ messages in thread
From: Larisa Ileana Grigore @ 2026-02-18 13:26 UTC (permalink / raw)
To: Krzysztof Kozlowski, gregkh, jirislaby, robh, krzk+dt, conor+dt,
sumit.semwal, christian.koenig, chester62515, cosmin.stoica,
adrian.nitu, stefan-gabriel.mirea, Mihaela.Martinas
Cc: linux-kernel, linux-serial, devicetree, linux-media, dri-devel,
linaro-mm-sig, s32, imx, clizzi, aruizrui, eballetb, echanude,
jkangas, Radu Pirea
On 2/16/2026 5:10 PM, Krzysztof Kozlowski wrote:
> On 16/02/2026 16:02, Larisa Grigore wrote:
>> From: Radu Pirea <radu-nicolae.pirea@nxp.com>
>>
>> Add optional support for the two clock inputs used by the LINFlexD UART
>> controller:
>> - "lin": LIN_BAUD_CLK
>> - "ipg": LINFLEXD_CLK
>>
>> The clock inputs are kept optional to maintain compatibility with the
>> S32V234 platform.
>
> Does S32V234 have the clocks? I don't understand the "maintain
> compatibility" in this context. Either you have or you have not clocks,
> which should be expressed in schema (: false, see example schema).
>
Hello Krzysztof,
Thanks for pointing this out! I will update both the schema and the
commit description.
S32V234 does not expose these clocks in its device tree—on this platform
the LINFlexD clocks are set up and enabled by U‑Boot, so they are not
available to the kernel.
The changes in this patch are intended specifically for S32G2/G3, where
the clocks are provided in the DT and required by the driver.
>>
>> Signed-off-by: Radu Pirea <radu-nicolae.pirea@nxp.com>
>> Co-developed-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
>> Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
>> ---
>> .../bindings/serial/fsl,s32-linflexuart.yaml | 18 ++++++++++++++++++
>> 1 file changed, 18 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml b/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml
>> index 4171f524a928..885f0b1b3492 100644
>> --- a/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml
>> +++ b/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml
>> @@ -34,6 +34,14 @@ properties:
>> interrupts:
>> maxItems: 1
>>
>> + clocks:
>> + maxItems: 2
>> +
>> + clock-names:
>> + items:
>> + - const: lin
>> + - const: ipg
>> +
>> required:
>> - compatible
>> - reg
>> @@ -48,3 +56,13 @@ examples:
>> reg = <0x40053000 0x1000>;
>> interrupts = <0 59 4>;
>> };
>> +
>> + - |
>> + serial@401c8000 {
>> + compatible = "nxp,s32g2-linflexuart",
>> + "fsl,s32v234-linflexuart";
>> + reg = <0x401C8000 0x3000>;
>> + interrupts = <0 82 1>;
>> + clocks = <&clks 14>, <&clks 13>;
>> + clock-names = "lin", "ipg";
>
> Just add the clocks to existing example. No need for new example for
> each new property.
>
>> + };
The existing node refers to S32V234 which does not expose any clock
properties in its device tree. Because of this, I couldn’t extend that
example with clocks and clock-names. The additional example is there
only to illustrate the S32G2 case, where the clocks are required and
actually present in the device tree. Should I remove it?
Best regards,
Larisa
>
> Best regards,
> Krzysztof
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 08/13] dt-bindings: serial: fsl-linflexuart: add clock input properties
2026-02-18 13:26 ` Larisa Ileana Grigore
@ 2026-02-18 13:29 ` Krzysztof Kozlowski
2026-02-18 13:57 ` Larisa Ileana Grigore
0 siblings, 1 reply; 34+ messages in thread
From: Krzysztof Kozlowski @ 2026-02-18 13:29 UTC (permalink / raw)
To: Larisa Ileana Grigore, gregkh, jirislaby, robh, krzk+dt, conor+dt,
sumit.semwal, christian.koenig, chester62515, cosmin.stoica,
adrian.nitu, stefan-gabriel.mirea, Mihaela.Martinas
Cc: linux-kernel, linux-serial, devicetree, linux-media, dri-devel,
linaro-mm-sig, s32, imx, clizzi, aruizrui, eballetb, echanude,
jkangas, Radu Pirea
On 18/02/2026 14:26, Larisa Ileana Grigore wrote:
> On 2/16/2026 5:10 PM, Krzysztof Kozlowski wrote:
>> On 16/02/2026 16:02, Larisa Grigore wrote:
>>> From: Radu Pirea <radu-nicolae.pirea@nxp.com>
>>>
>>> Add optional support for the two clock inputs used by the LINFlexD UART
>>> controller:
>>> - "lin": LIN_BAUD_CLK
>>> - "ipg": LINFLEXD_CLK
>>>
>>> The clock inputs are kept optional to maintain compatibility with the
>>> S32V234 platform.
>>
>> Does S32V234 have the clocks? I don't understand the "maintain
>> compatibility" in this context. Either you have or you have not clocks,
>> which should be expressed in schema (: false, see example schema).
>>
> Hello Krzysztof,
>
> Thanks for pointing this out! I will update both the schema and the
> commit description.
> S32V234 does not expose these clocks in its device tree—on this platform
> the LINFlexD clocks are set up and enabled by U‑Boot, so they are not
> available to the kernel.
So there are clocks. DTS is being used by bootloader, so how bootloader
is going to set up clocks for S32V234 if no one provides them?
This looks like buggy/incomplete approach, although I understand that
the original binding had the issue.
> The changes in this patch are intended specifically for S32G2/G3, where
> the clocks are provided in the DT and required by the driver.
>
>>>
>>> Signed-off-by: Radu Pirea <radu-nicolae.pirea@nxp.com>
>>> Co-developed-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
>>> Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
>>> ---
>>> .../bindings/serial/fsl,s32-linflexuart.yaml | 18 ++++++++++++++++++
>>> 1 file changed, 18 insertions(+)
>>>
>>> diff --git a/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml b/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml
>>> index 4171f524a928..885f0b1b3492 100644
>>> --- a/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml
>>> +++ b/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml
>>> @@ -34,6 +34,14 @@ properties:
>>> interrupts:
>>> maxItems: 1
>>>
>>> + clocks:
>>> + maxItems: 2
>>> +
>>> + clock-names:
>>> + items:
>>> + - const: lin
>>> + - const: ipg
>>> +
>>> required:
>>> - compatible
>>> - reg
>>> @@ -48,3 +56,13 @@ examples:
>>> reg = <0x40053000 0x1000>;
>>> interrupts = <0 59 4>;
>>> };
>>> +
>>> + - |
>>> + serial@401c8000 {
>>> + compatible = "nxp,s32g2-linflexuart",
>>> + "fsl,s32v234-linflexuart";
>>> + reg = <0x401C8000 0x3000>;
>>> + interrupts = <0 82 1>;
>>> + clocks = <&clks 14>, <&clks 13>;
>>> + clock-names = "lin", "ipg";
>>
>> Just add the clocks to existing example. No need for new example for
>> each new property.
>>
>>> + };
>
> The existing node refers to S32V234 which does not expose any clock
> properties in its device tree. Because of this, I couldn’t extend that
You just said S32V234 has clocks...
> example with clocks and clock-names. The additional example is there
> only to illustrate the S32G2 case, where the clocks are required and
> actually present in the device tree. Should I remove it?
>
> Best regards,
> Larisa
>>
>> Best regards,
>> Krzysztof
>
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 08/13] dt-bindings: serial: fsl-linflexuart: add clock input properties
2026-02-18 13:29 ` Krzysztof Kozlowski
@ 2026-02-18 13:57 ` Larisa Ileana Grigore
2026-02-18 19:48 ` Krzysztof Kozlowski
0 siblings, 1 reply; 34+ messages in thread
From: Larisa Ileana Grigore @ 2026-02-18 13:57 UTC (permalink / raw)
To: Krzysztof Kozlowski, gregkh, jirislaby, robh, krzk+dt, conor+dt,
sumit.semwal, christian.koenig, chester62515, cosmin.stoica,
adrian.nitu, stefan-gabriel.mirea, Mihaela.Martinas
Cc: linux-kernel, linux-serial, devicetree, linux-media, dri-devel,
linaro-mm-sig, s32, imx, clizzi, aruizrui, eballetb, echanude,
jkangas, Radu Pirea
On 2/18/2026 3:29 PM, Krzysztof Kozlowski wrote:
> On 18/02/2026 14:26, Larisa Ileana Grigore wrote:
>> On 2/16/2026 5:10 PM, Krzysztof Kozlowski wrote:
>>> On 16/02/2026 16:02, Larisa Grigore wrote:
>>>> From: Radu Pirea <radu-nicolae.pirea@nxp.com>
>>>>
>>>> Add optional support for the two clock inputs used by the LINFlexD UART
>>>> controller:
>>>> - "lin": LIN_BAUD_CLK
>>>> - "ipg": LINFLEXD_CLK
>>>>
>>>> The clock inputs are kept optional to maintain compatibility with the
>>>> S32V234 platform.
>>>
>>> Does S32V234 have the clocks? I don't understand the "maintain
>>> compatibility" in this context. Either you have or you have not clocks,
>>> which should be expressed in schema (: false, see example schema).
>>>
>> Hello Krzysztof,
>>
>> Thanks for pointing this out! I will update both the schema and the
>> commit description.
>> S32V234 does not expose these clocks in its device tree—on this platform
>> the LINFlexD clocks are set up and enabled by U‑Boot, so they are not
>> available to the kernel.
>
> So there are clocks. DTS is being used by bootloader, so how bootloader
> is going to set up clocks for S32V234 if no one provides them?
>
> This looks like buggy/incomplete approach, although I understand that
> the original binding had the issue.
>
Indeed, I also believe the binding is not fully accurate on S32V234. As
I mentioned earlier, the LINFlexD clocks are not managed by Linux on
this platform. They, along with several other clocks, are usually
initialized by U‑Boot, and Linux does not handle them. That is likely
the reason they were omitted from the S32V234 binding.
I’m willing to correct this for the S32V234 compatible by making that
property optional, so we don’t break compatibility.
For S32G, I would prefer to avoid repeating the same oversight we had on
S32V234 and make the property required, since the IP, as you correctly
pointed out, does have dedicated clock inputs.
How would you approach this?
Thank you,
Larisa
>
>> The changes in this patch are intended specifically for S32G2/G3, where
>> the clocks are provided in the DT and required by the driver.
>>
>>>>
>>>> Signed-off-by: Radu Pirea <radu-nicolae.pirea@nxp.com>
>>>> Co-developed-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
>>>> Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
>>>> ---
>>>> .../bindings/serial/fsl,s32-linflexuart.yaml | 18 ++++++++++++++++++
>>>> 1 file changed, 18 insertions(+)
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml b/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml
>>>> index 4171f524a928..885f0b1b3492 100644
>>>> --- a/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml
>>>> +++ b/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.yaml
>>>> @@ -34,6 +34,14 @@ properties:
>>>> interrupts:
>>>> maxItems: 1
>>>>
>>>> + clocks:
>>>> + maxItems: 2
>>>> +
>>>> + clock-names:
>>>> + items:
>>>> + - const: lin
>>>> + - const: ipg
>>>> +
>>>> required:
>>>> - compatible
>>>> - reg
>>>> @@ -48,3 +56,13 @@ examples:
>>>> reg = <0x40053000 0x1000>;
>>>> interrupts = <0 59 4>;
>>>> };
>>>> +
>>>> + - |
>>>> + serial@401c8000 {
>>>> + compatible = "nxp,s32g2-linflexuart",
>>>> + "fsl,s32v234-linflexuart";
>>>> + reg = <0x401C8000 0x3000>;
>>>> + interrupts = <0 82 1>;
>>>> + clocks = <&clks 14>, <&clks 13>;
>>>> + clock-names = "lin", "ipg";
>>>
>>> Just add the clocks to existing example. No need for new example for
>>> each new property.
>>>
>>>> + };
>>
>> The existing node refers to S32V234 which does not expose any clock
>> properties in its device tree. Because of this, I couldn’t extend that
>
> You just said S32V234 has clocks...
>
>> example with clocks and clock-names. The additional example is there
>> only to illustrate the S32G2 case, where the clocks are required and
>> actually present in the device tree. Should I remove it?
>>
>> Best regards,
>> Larisa
>>>
>>> Best regards,
>>> Krzysztof
>>
>
>
> Best regards,
> Krzysztof
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 09/13] dt-bindings: serial: fsl-linflexuart: add dma properties
2026-02-16 15:10 ` Krzysztof Kozlowski
@ 2026-02-18 14:44 ` Larisa Ileana Grigore
2026-02-18 19:49 ` Krzysztof Kozlowski
0 siblings, 1 reply; 34+ messages in thread
From: Larisa Ileana Grigore @ 2026-02-18 14:44 UTC (permalink / raw)
To: Krzysztof Kozlowski, gregkh, jirislaby, robh, krzk+dt, conor+dt,
sumit.semwal, christian.koenig, chester62515, cosmin.stoica,
adrian.nitu, stefan-gabriel.mirea, Mihaela.Martinas
Cc: linux-kernel, linux-serial, devicetree, linux-media, dri-devel,
linaro-mm-sig, s32, imx, clizzi, aruizrui, eballetb, echanude,
jkangas, Radu Pirea
On 2/16/2026 5:10 PM, Krzysztof Kozlowski wrote:
> On 16/02/2026 16:02, Larisa Grigore wrote:
>> From: Radu Pirea <radu-nicolae.pirea@nxp.com>
>>
>> Add 'dmas' and 'dma-names' properties to describe optional DMA support
>> for RX and TX channels in the LINFlexD UART controller.
>
> Same question as in other patch about existing devices.
>
I will update the bindings so that `dmas`/`dma-names` are optional for
S32G and not present on S32V234. Would this be acceptable?
Thanks,
Larisa
>>
>> This allows the device tree to specify DMA channels used for UART data
>> transfers. If not specified, the driver will fall to interrupt-based
>> operations.
>>
>> Signed-off-by: Radu Pirea <radu-nicolae.pirea@nxp.com>
>> Co-developed-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
>> Signed-off-by: Larisa Grigore <larisa.grigore@oss.nxp.com>
>> ---
>
>
> Best regards,
> Krzysztof
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 08/13] dt-bindings: serial: fsl-linflexuart: add clock input properties
2026-02-18 13:57 ` Larisa Ileana Grigore
@ 2026-02-18 19:48 ` Krzysztof Kozlowski
0 siblings, 0 replies; 34+ messages in thread
From: Krzysztof Kozlowski @ 2026-02-18 19:48 UTC (permalink / raw)
To: Larisa Ileana Grigore, gregkh, jirislaby, robh, krzk+dt, conor+dt,
sumit.semwal, christian.koenig, chester62515, cosmin.stoica,
adrian.nitu, stefan-gabriel.mirea, Mihaela.Martinas
Cc: linux-kernel, linux-serial, devicetree, linux-media, dri-devel,
linaro-mm-sig, s32, imx, clizzi, aruizrui, eballetb, echanude,
jkangas, Radu Pirea
On 18/02/2026 14:57, Larisa Ileana Grigore wrote:
> On 2/18/2026 3:29 PM, Krzysztof Kozlowski wrote:
>> On 18/02/2026 14:26, Larisa Ileana Grigore wrote:
>>> On 2/16/2026 5:10 PM, Krzysztof Kozlowski wrote:
>>>> On 16/02/2026 16:02, Larisa Grigore wrote:
>>>>> From: Radu Pirea <radu-nicolae.pirea@nxp.com>
>>>>>
>>>>> Add optional support for the two clock inputs used by the LINFlexD UART
>>>>> controller:
>>>>> - "lin": LIN_BAUD_CLK
>>>>> - "ipg": LINFLEXD_CLK
>>>>>
>>>>> The clock inputs are kept optional to maintain compatibility with the
>>>>> S32V234 platform.
>>>>
>>>> Does S32V234 have the clocks? I don't understand the "maintain
>>>> compatibility" in this context. Either you have or you have not clocks,
>>>> which should be expressed in schema (: false, see example schema).
>>>>
>>> Hello Krzysztof,
>>>
>>> Thanks for pointing this out! I will update both the schema and the
>>> commit description.
>>> S32V234 does not expose these clocks in its device tree—on this platform
>>> the LINFlexD clocks are set up and enabled by U‑Boot, so they are not
>>> available to the kernel.
>>
>> So there are clocks. DTS is being used by bootloader, so how bootloader
>> is going to set up clocks for S32V234 if no one provides them?
>>
>> This looks like buggy/incomplete approach, although I understand that
>> the original binding had the issue.
>>
> Indeed, I also believe the binding is not fully accurate on S32V234. As
> I mentioned earlier, the LINFlexD clocks are not managed by Linux on
> this platform. They, along with several other clocks, are usually
> initialized by U‑Boot, and Linux does not handle them. That is likely
> the reason they were omitted from the S32V234 binding.
> I’m willing to correct this for the S32V234 compatible by making that
> property optional, so we don’t break compatibility.
> For S32G, I would prefer to avoid repeating the same oversight we had on
> S32V234 and make the property required, since the IP, as you correctly
> pointed out, does have dedicated clock inputs.
>
> How would you approach this?
So the new device should require clocks, which can be left optional for
the old one with explanation in the commit msg. Linux is not the only
consumer of bindings and DTS.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 09/13] dt-bindings: serial: fsl-linflexuart: add dma properties
2026-02-18 14:44 ` Larisa Ileana Grigore
@ 2026-02-18 19:49 ` Krzysztof Kozlowski
0 siblings, 0 replies; 34+ messages in thread
From: Krzysztof Kozlowski @ 2026-02-18 19:49 UTC (permalink / raw)
To: Larisa Ileana Grigore, gregkh, jirislaby, robh, krzk+dt, conor+dt,
sumit.semwal, christian.koenig, chester62515, cosmin.stoica,
adrian.nitu, stefan-gabriel.mirea, Mihaela.Martinas
Cc: linux-kernel, linux-serial, devicetree, linux-media, dri-devel,
linaro-mm-sig, s32, imx, clizzi, aruizrui, eballetb, echanude,
jkangas, Radu Pirea
On 18/02/2026 15:44, Larisa Ileana Grigore wrote:
> On 2/16/2026 5:10 PM, Krzysztof Kozlowski wrote:
>> On 16/02/2026 16:02, Larisa Grigore wrote:
>>> From: Radu Pirea <radu-nicolae.pirea@nxp.com>
>>>
>>> Add 'dmas' and 'dma-names' properties to describe optional DMA support
>>> for RX and TX channels in the LINFlexD UART controller.
>>
>> Same question as in other patch about existing devices.
>>
> I will update the bindings so that `dmas`/`dma-names` are optional for
> S32G and not present on S32V234. Would this be acceptable?
>
Yes, with reason in the commit msg.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 12/13] serial: linflexuart: Add DMA support
2026-02-16 15:02 ` [PATCH 12/13] serial: linflexuart: Add DMA support Larisa Grigore
` (2 preceding siblings ...)
2026-02-17 3:26 ` kernel test robot
@ 2026-02-19 8:22 ` Dan Carpenter
3 siblings, 0 replies; 34+ messages in thread
From: Dan Carpenter @ 2026-02-19 8:22 UTC (permalink / raw)
To: oe-kbuild, Larisa Grigore, gregkh, jirislaby, robh, krzk+dt,
conor+dt, sumit.semwal, christian.koenig, chester62515,
cosmin.stoica, adrian.nitu, stefan-gabriel.mirea,
Mihaela.Martinas
Cc: lkp, oe-kbuild-all, linux-kernel, linux-serial, devicetree,
linux-media, dri-devel, linaro-mm-sig, s32, imx, clizzi, aruizrui,
eballetb, echanude, jkangas, Larisa Grigore, Radu Pirea,
Phu Luu An, Js Ha, Ghennadi Procopciuc
Hi Larisa,
kernel test robot noticed the following build warnings:
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Larisa-Grigore/serial-linflexuart-Fix-locking-in-set_termios/20260216-231403
base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tty-testing
patch link: https://lore.kernel.org/r/20260216150205.212318-13-larisa.grigore%40oss.nxp.com
patch subject: [PATCH 12/13] serial: linflexuart: Add DMA support
config: i386-randconfig-141-20260217 (https://download.01.org/0day-ci/archive/20260217/202602171109.6YSFXcJ3-lkp@intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
smatch version: v0.5.0-8994-gd50c5a4c
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
| Closes: https://lore.kernel.org/r/202602171109.6YSFXcJ3-lkp@intel.com/
smatch warnings:
drivers/tty/serial/fsl_linflexuart.c:1441 linflex_probe() warn: missing unwind goto?
vim +1441 drivers/tty/serial/fsl_linflexuart.c
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09 1377 static int linflex_probe(struct platform_device *pdev)
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09 1378 {
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09 1379 struct device_node *np = pdev->dev.of_node;
1d3f5f07fafc71 Radu Pirea 2026-02-16 1380 struct linflex_port *lfport;
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09 1381 struct uart_port *sport;
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09 1382 struct resource *res;
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09 1383 int ret;
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09 1384
1d3f5f07fafc71 Radu Pirea 2026-02-16 1385 lfport = devm_kzalloc(&pdev->dev, sizeof(*lfport), GFP_KERNEL);
1d3f5f07fafc71 Radu Pirea 2026-02-16 1386 if (!lfport)
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09 1387 return -ENOMEM;
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09 1388
1d3f5f07fafc71 Radu Pirea 2026-02-16 1389 sport = &lfport->port;
0b34325c5f79f1 Larisa Grigore 2026-02-16 1390 sport->dev = &pdev->dev;
0b34325c5f79f1 Larisa Grigore 2026-02-16 1391
0b34325c5f79f1 Larisa Grigore 2026-02-16 1392 lfport->dma_tx_chan = dma_request_chan(sport->dev, "tx");
0b34325c5f79f1 Larisa Grigore 2026-02-16 1393 if (IS_ERR(lfport->dma_tx_chan)) {
0b34325c5f79f1 Larisa Grigore 2026-02-16 1394 ret = PTR_ERR(lfport->dma_tx_chan);
0b34325c5f79f1 Larisa Grigore 2026-02-16 1395 if (ret == -EPROBE_DEFER)
0b34325c5f79f1 Larisa Grigore 2026-02-16 1396 return ret;
0b34325c5f79f1 Larisa Grigore 2026-02-16 1397
0b34325c5f79f1 Larisa Grigore 2026-02-16 1398 dev_info(sport->dev,
0b34325c5f79f1 Larisa Grigore 2026-02-16 1399 "DMA tx channel request failed, operating without tx DMA %ld\n",
0b34325c5f79f1 Larisa Grigore 2026-02-16 1400 PTR_ERR(lfport->dma_tx_chan));
0b34325c5f79f1 Larisa Grigore 2026-02-16 1401 lfport->dma_tx_chan = NULL;
0b34325c5f79f1 Larisa Grigore 2026-02-16 1402 }
0b34325c5f79f1 Larisa Grigore 2026-02-16 1403
0b34325c5f79f1 Larisa Grigore 2026-02-16 1404 lfport->dma_rx_chan = dma_request_chan(sport->dev, "rx");
0b34325c5f79f1 Larisa Grigore 2026-02-16 1405 if (IS_ERR(lfport->dma_rx_chan)) {
0b34325c5f79f1 Larisa Grigore 2026-02-16 1406 ret = PTR_ERR(lfport->dma_rx_chan);
0b34325c5f79f1 Larisa Grigore 2026-02-16 1407 if (ret == -EPROBE_DEFER) {
0b34325c5f79f1 Larisa Grigore 2026-02-16 1408 dma_release_channel(lfport->dma_tx_chan);
0b34325c5f79f1 Larisa Grigore 2026-02-16 1409 return ret;
0b34325c5f79f1 Larisa Grigore 2026-02-16 1410 }
0b34325c5f79f1 Larisa Grigore 2026-02-16 1411
0b34325c5f79f1 Larisa Grigore 2026-02-16 1412 dev_info(sport->dev,
0b34325c5f79f1 Larisa Grigore 2026-02-16 1413 "DMA rx channel request failed, operating without rx DMA %ld\n",
0b34325c5f79f1 Larisa Grigore 2026-02-16 1414 PTR_ERR(lfport->dma_rx_chan));
0b34325c5f79f1 Larisa Grigore 2026-02-16 1415 lfport->dma_rx_chan = NULL;
0b34325c5f79f1 Larisa Grigore 2026-02-16 1416 }
1d3f5f07fafc71 Radu Pirea 2026-02-16 1417
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09 1418 ret = of_alias_get_id(np, "serial");
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09 1419 if (ret < 0) {
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09 1420 dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
0b34325c5f79f1 Larisa Grigore 2026-02-16 1421 goto linflex_probe_free_dma;
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09 1422 }
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09 1423 if (ret >= UART_NR) {
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09 1424 dev_err(&pdev->dev, "driver limited to %d serial ports\n",
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09 1425 UART_NR);
0b34325c5f79f1 Larisa Grigore 2026-02-16 1426 ret = -ENOMEM;
0b34325c5f79f1 Larisa Grigore 2026-02-16 1427 goto linflex_probe_free_dma;
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09 1428 }
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09 1429
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09 1430 sport->line = ret;
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09 1431
8c6d7e5fd50b45 Yangtao Li 2023-07-12 1432 sport->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
0b34325c5f79f1 Larisa Grigore 2026-02-16 1433 if (IS_ERR(sport->membase)) {
0b34325c5f79f1 Larisa Grigore 2026-02-16 1434 ret = PTR_ERR(sport->membase);
0b34325c5f79f1 Larisa Grigore 2026-02-16 1435 goto linflex_probe_free_dma;
0b34325c5f79f1 Larisa Grigore 2026-02-16 1436 }
8c6d7e5fd50b45 Yangtao Li 2023-07-12 1437 sport->mapbase = res->start;
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09 1438
4e8da86fc1f767 Zhang Shurong 2023-08-26 1439 ret = platform_get_irq(pdev, 0);
4e8da86fc1f767 Zhang Shurong 2023-08-26 1440 if (ret < 0)
4e8da86fc1f767 Zhang Shurong 2023-08-26 @1441 return ret;
No clean up?
4e8da86fc1f767 Zhang Shurong 2023-08-26 1442
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09 1443 sport->iotype = UPIO_MEM;
4e8da86fc1f767 Zhang Shurong 2023-08-26 1444 sport->irq = ret;
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09 1445 sport->ops = &linflex_pops;
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09 1446 sport->flags = UPF_BOOT_AUTOCONF;
4151bbed79f98b Dmitry Safonov 2019-12-13 1447 sport->has_sysrq = IS_ENABLED(CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE);
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09 1448
1d3f5f07fafc71 Radu Pirea 2026-02-16 1449 ret = linflex_init_clk(lfport);
1d3f5f07fafc71 Radu Pirea 2026-02-16 1450 if (ret)
0b34325c5f79f1 Larisa Grigore 2026-02-16 1451 goto linflex_probe_free_dma;
1d3f5f07fafc71 Radu Pirea 2026-02-16 1452
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09 1453 linflex_ports[sport->line] = sport;
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09 1454
1d3f5f07fafc71 Radu Pirea 2026-02-16 1455 platform_set_drvdata(pdev, lfport);
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09 1456
1d3f5f07fafc71 Radu Pirea 2026-02-16 1457 ret = uart_add_one_port(&linflex_reg, sport);
0b34325c5f79f1 Larisa Grigore 2026-02-16 1458 if (ret) {
1d3f5f07fafc71 Radu Pirea 2026-02-16 1459 clk_bulk_disable_unprepare(LINFLEX_CLK_NUM, lfport->clks);
0b34325c5f79f1 Larisa Grigore 2026-02-16 1460 goto linflex_probe_free_dma;
0b34325c5f79f1 Larisa Grigore 2026-02-16 1461 }
0b34325c5f79f1 Larisa Grigore 2026-02-16 1462
0b34325c5f79f1 Larisa Grigore 2026-02-16 1463 return 0;
0b34325c5f79f1 Larisa Grigore 2026-02-16 1464
0b34325c5f79f1 Larisa Grigore 2026-02-16 1465 linflex_probe_free_dma:
0b34325c5f79f1 Larisa Grigore 2026-02-16 1466 if (lfport->dma_tx_chan)
0b34325c5f79f1 Larisa Grigore 2026-02-16 1467 dma_release_channel(lfport->dma_tx_chan);
0b34325c5f79f1 Larisa Grigore 2026-02-16 1468 if (lfport->dma_rx_chan)
0b34325c5f79f1 Larisa Grigore 2026-02-16 1469 dma_release_channel(lfport->dma_rx_chan);
1d3f5f07fafc71 Radu Pirea 2026-02-16 1470
1d3f5f07fafc71 Radu Pirea 2026-02-16 1471 return ret;
09864c1cdf5c53 Stefan-gabriel Mirea 2019-08-09 1472 }
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 34+ messages in thread
* Re: [PATCH 00/13] Add DMA support for LINFlexD UART driver
2026-02-16 15:01 [PATCH 00/13] Add DMA support for LINFlexD UART driver Larisa Grigore
` (12 preceding siblings ...)
2026-02-16 15:02 ` [PATCH 13/13] serial: linflexuart: Avoid stopping DMA during receive operations Larisa Grigore
@ 2026-02-27 14:03 ` Jared Kangas
13 siblings, 0 replies; 34+ messages in thread
From: Jared Kangas @ 2026-02-27 14:03 UTC (permalink / raw)
To: Larisa Grigore
Cc: gregkh, jirislaby, robh, krzk+dt, conor+dt, sumit.semwal,
christian.koenig, chester62515, cosmin.stoica, adrian.nitu,
stefan-gabriel.mirea, Mihaela.Martinas, linux-kernel,
linux-serial, devicetree, linux-media, dri-devel, linaro-mm-sig,
s32, imx, clizzi, aruizrui, eballetb, echanude
Hi Larisa,
On Mon, Feb 16, 2026 at 04:01:52PM +0100, Larisa Grigore wrote:
> This patchset enhances the LINFlexD UART driver and its device tree bindings to
> support DMA transfers, configurable clock inputs, dynamic baudrate changes, and
> termios features. It also includes a series of fixes and improvements to ensure
> reliable operation across various modes and configurations.
>
> The changes added can be summarized as follows:
> 1. Fixes with respect to FIFO handling, locking, interrupt related registers and
> INITM mode transition.
Tested this series with the default devicetree configuration by booting
the board to a login prompt about 200 times. Without the series applied,
I was seeing a bug roughly every 30-50 boots where the kernel would
would hang in linflex_console_putchar() waiting for DTFTFF. In my tests
with the series applied, I didn't see any regressions and the bug no
longer appeared. Thanks for the fix!
Tested-by: Jared Kangas <jkangas@redhat.com> # S32G3, interrupt-driven
> 2. Removal of the earlycon workaround, as proper FIFO handling and INITM
> transitions now ensure stable behavior.
> 3. Support for configurable stop bits and dynamic baudrate changes based on
> clock inputs and termios settings.
> 4. Optional DMA support for RX and TX paths, preventing character loss during
> high-throughput operations like copy-paste. Cyclic DMA is used for RX to avoid
> gaps between transactions.
>
> Larisa Grigore (8):
> serial: linflexuart: Clean SLEEP bit in LINCR1 after suspend
> serial: linflexuart: Check FIFO full before writing
> serial: linflexuart: Correctly clear UARTSR in buffer mode
> serial: linflexuart: Update RXEN/TXEN outside INITM mode
> serial: linflexuart: Ensure FIFO is empty when entering INITM
> serial: linflexuart: Revert earlycon workaround
> serial: linflexuart: Add support for configurable stop bits
> serial: linflexuart: Add DMA support
>
> Radu Pirea (5):
> serial: linflexuart: Fix locking in set_termios
> dt-bindings: serial: fsl-linflexuart: add clock input properties
> dt-bindings: serial: fsl-linflexuart: add dma properties
> serial: linflexuart: Add support for changing baudrate
> serial: linflexuart: Avoid stopping DMA during receive operations
>
> .../bindings/serial/fsl,s32-linflexuart.yaml | 31 +
> drivers/tty/serial/fsl_linflexuart.c | 972 +++++++++++++++---
> 2 files changed, 846 insertions(+), 157 deletions(-)
>
> --
> 2.47.0
>
^ permalink raw reply [flat|nested] 34+ messages in thread
end of thread, other threads:[~2026-02-27 14:03 UTC | newest]
Thread overview: 34+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-16 15:01 [PATCH 00/13] Add DMA support for LINFlexD UART driver Larisa Grigore
2026-02-16 15:01 ` [PATCH 01/13] serial: linflexuart: Fix locking in set_termios Larisa Grigore
2026-02-16 20:16 ` Frank Li
2026-02-18 11:58 ` Larisa Ileana Grigore
2026-02-16 15:01 ` [PATCH 02/13] serial: linflexuart: Clean SLEEP bit in LINCR1 after suspend Larisa Grigore
2026-02-16 20:22 ` Frank Li
2026-02-18 12:09 ` Larisa Ileana Grigore
2026-02-16 15:01 ` [PATCH 03/13] serial: linflexuart: Check FIFO full before writing Larisa Grigore
2026-02-16 15:01 ` [PATCH 04/13] serial: linflexuart: Correctly clear UARTSR in buffer mode Larisa Grigore
2026-02-16 15:01 ` [PATCH 05/13] serial: linflexuart: Update RXEN/TXEN outside INITM mode Larisa Grigore
2026-02-16 15:01 ` [PATCH 06/13] serial: linflexuart: Ensure FIFO is empty when entering INITM Larisa Grigore
2026-02-16 15:01 ` [PATCH 07/13] serial: linflexuart: Revert earlycon workaround Larisa Grigore
2026-02-16 15:02 ` [PATCH 08/13] dt-bindings: serial: fsl-linflexuart: add clock input properties Larisa Grigore
2026-02-16 15:10 ` Krzysztof Kozlowski
2026-02-18 13:26 ` Larisa Ileana Grigore
2026-02-18 13:29 ` Krzysztof Kozlowski
2026-02-18 13:57 ` Larisa Ileana Grigore
2026-02-18 19:48 ` Krzysztof Kozlowski
2026-02-16 15:02 ` [PATCH 09/13] dt-bindings: serial: fsl-linflexuart: add dma properties Larisa Grigore
2026-02-16 15:10 ` Krzysztof Kozlowski
2026-02-18 14:44 ` Larisa Ileana Grigore
2026-02-18 19:49 ` Krzysztof Kozlowski
2026-02-16 15:29 ` Daniel Baluta
2026-02-17 8:10 ` Krzysztof Kozlowski
2026-02-17 8:39 ` Daniel Baluta
2026-02-16 15:02 ` [PATCH 10/13] serial: linflexuart: Add support for changing baudrate Larisa Grigore
2026-02-16 15:02 ` [PATCH 11/13] serial: linflexuart: Add support for configurable stop bits Larisa Grigore
2026-02-16 15:02 ` [PATCH 12/13] serial: linflexuart: Add DMA support Larisa Grigore
2026-02-16 15:11 ` Krzysztof Kozlowski
2026-02-16 20:48 ` kernel test robot
2026-02-17 3:26 ` kernel test robot
2026-02-19 8:22 ` Dan Carpenter
2026-02-16 15:02 ` [PATCH 13/13] serial: linflexuart: Avoid stopping DMA during receive operations Larisa Grigore
2026-02-27 14:03 ` [PATCH 00/13] Add DMA support for LINFlexD UART driver Jared Kangas
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox