Linux Serial subsystem development
 help / color / mirror / Atom feed
* Re: [PATCH 02/13] serial: linflexuart: Clean SLEEP bit in LINCR1 after suspend
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
In-Reply-To: <aZN8hKJSsnnYhy1m@lizhi-Precision-Tower-5810>

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

* Re: [PATCH 01/13] serial: linflexuart: Fix locking in set_termios
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
In-Reply-To: <aZN7Hx_aK4ta1ksL@lizhi-Precision-Tower-5810>

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

* Re: printk, vt: sleep from invalid context bug
From: Nam Cao @ 2026-02-18  0:51 UTC (permalink / raw)
  To: Petr Mladek
  Cc: Greg Kroah-Hartman, Jiri Slaby, Nicolas Pitre, Calixte Pernot,
	Steven Rostedt, John Ogness, Sergey Senozhatsky,
	Sebastian Andrzej Siewior, Clark Williams, linux-serial,
	linux-kernel, linux-rt-devel
In-Reply-To: <aZQs0WYk262ZNybc@pathway.suse.cz>

Petr Mladek <pmladek@suse.com> writes:
> Sebastian has recently sent a patch which should remove the
> cond_resched(), see
> https://lore.kernel.org/all/20260126180836.SNCdMW2f@linutronix.de
>
> It seems that the patch has made it upstream in this merge window
> for 7.0, see the commit 8e9bf8b9e8c0 ("printk, vt, fbcon: Remove
> console_conditional_schedule()").

Pulled and the problem goes away. Thanks Sebastian.

Nam

^ permalink raw reply

* Re: [PATCH] serial: 8250_ni: use kzalloc_obj() for allocation
From: Chaitanya Vadrevu @ 2026-02-17 21:48 UTC (permalink / raw)
  To: Pete Connor, Greg Kroah-Hartman, Jiri Slaby, linux-serial,
	linux-kernel
In-Reply-To: <20260217031913.1166949-1-pete.connor@pythcoiner.dev>

> Replace kzalloc() with the preferred kzalloc_obj() helper
> to address a checkpatch warning.
> 
> Signed-off-by: Pete Connor <pete.connor@pythcoiner.dev>
> ---
>  drivers/tty/serial/8250/8250_ni.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/tty/serial/8250/8250_ni.c b/drivers/tty/serial/8250/8250_ni.c
> index cb5b42b3609c..3f3dac694e20 100644
> --- a/drivers/tty/serial/8250/8250_ni.c
> +++ b/drivers/tty/serial/8250/8250_ni.c
> @@ -285,7 +285,7 @@ static int ni16550_probe(struct platform_device *pdev)
>  	bool rs232_property;
>  	int ret;
>  
> -	uart = kzalloc(sizeof(*uart), GFP_KERNEL);
> +	uart = kzalloc_obj(*uart, GFP_KERNEL);

tty-next doesn't yet have the commit that defines kzalloc_obj so this
fails to build. Will have to wait until tty-next has kzalloc_obj.

>  	if (!uart)
>  		return -ENOMEM;

Regards,
Chaitanya


^ permalink raw reply

* Re: [GIT PULL] TTY/Serial driver updates for 7.0-rc1
From: pr-tracker-bot @ 2026-02-17 17:55 UTC (permalink / raw)
  To: Greg KH
  Cc: Linus Torvalds, Jiri Slaby, Andrew Morton, linux-kernel,
	linux-serial
In-Reply-To: <aZR7VPj-GDiNMcX9@kroah.com>

The pull request you sent on Tue, 17 Feb 2026 15:29:40 +0100:

> git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tags/tty-7.0-rc1

has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/3ad7945754000d868ed86315d33085a914c422c1

Thank you!

-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/prtracker.html

^ permalink raw reply

* [GIT PULL] TTY/Serial driver updates for 7.0-rc1
From: Greg KH @ 2026-02-17 14:29 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: Jiri Slaby, Andrew Morton, linux-kernel, linux-serial

The following changes since commit f8f9c1f4d0c7a64600e2ca312dec824a0bc2f1da:

  Linux 6.19-rc3 (2025-12-28 13:24:26 -0800)

are available in the Git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tags/tty-7.0-rc1

for you to fetch changes up to 0a15f43b92ddaa2fdb476891a12ac2e207c7fcd2:

  Revert "tty: tty_port: add workqueue to flip TTY buffer" (2026-01-27 13:58:21 +0100)

----------------------------------------------------------------
TTY / Serial driver updates for 7.0-rc1

Here is the small amount of tty and serial driver updates for 7.0-rc1.
Nothing major in here at all, just some driver updates and minor tweaks
and cleanups including:
  - sh-sci serial driver updates
  - 8250 driver updates
  - attempt to make the tty ports have their own workqueue, but was
    reverted after testing found it to have problems on some platforms.
    This will probably come back for 7.1 after it has been reworked and
    resubmitted
  - other tiny tty driver changes

All of these have been in linux-next for a while with no reported
problems.

Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

----------------------------------------------------------------
Andy Shevchenko (2):
      serial: 8250_omap: Remove custom deprecated baud setting routine
      serial: 8250_pci: Remove custom deprecated baud setting routine

Artem Shimko (2):
      serial: 8250_dw: handle clock enable errors in runtime_resume
      serial: 8250_dw: fix runtime PM initialization sequence

Bartlomiej Kubik (1):
      tty/n_hdlc: Fix struct n_hdlc kernel-doc warnings

Biju Das (18):
      dt-bindings: serial: renesas,rsci: Document RZ/G3E support
      serial: sh-sci: Update rx_trigger size for RZ/T2H RSCI
      serial: rsci: Add set_rtrg() callback
      serial: sh-sci: Drop checking port type for device file{create, remove}
      serial: rsci: Drop rsci_clear_SCxSR()
      serial: sh-sci: Drop extra lines
      serial: rsci: Drop unused macro DCR
      serial: rsci: Drop unused TDR register
      serial: sh-sci: Use devm_reset_control_array_get_exclusive()
      serial: sh-sci: Add sci_is_rsci_type()
      serial: sh-sci: Rename port SCI_PORT_RSCI->RSCI_PORT_SCIF16
      serial: sh-sci: Add RSCI_PORT_SCIF32 port ID
      serial: sh-sci: Add support for RZ/G3E RSCI clks
      serial: sh-sci: Make sci_scbrr_calc() public
      serial: sh-sci: Add finish_console_write() callback
      serial: rsci: Rename early_console data, port_params and callback() names
      serial: sh-sci: Add support for RZ/G3E RSCI
      dt-bindings: serial: renesas,scif: Document RZ/G3L SoC

Filip Jensen (1):
      serial: 8250_men_mcb: Clean defines

Geert Uytterhoeven (1):
      serial: rsci: Convert to FIELD_MODIFY()

Gerhard Engleder (3):
      serial: 8250_keba: Add missing includes
      serial: 8250_keba: Add ICR defines
      serial: 8250_keba: Use dev_err_probe()

Greg Kroah-Hartman (2):
      Merge 6.19-rc3 into tty-next
      Revert "tty: tty_port: add workqueue to flip TTY buffer"

Guodong Xu (1):
      dt-bindings: serial: 8250: add SpacemiT K3 UART compatible

Heiko Carstens (1):
      tty: hvc-iucv: Remove KMSG_COMPONENT macro

Jose Javier Rodriguez Barbarin (2):
      serial: men_z135_uart: drop unneeded MODULE_ALIAS
      8250_men_mcb: drop unneeded MODULE_ALIAS

Kendall Willis (1):
      serial: 8250: omap: set out-of-band wakeup if wakeup pinctrl exists

Kuan-Wei Chiu (1):
      dt-bindings: serial: google,goldfish-tty: Convert to DT schema

Lad Prabhakar (2):
      dt-bindings: serial: renesas,rsci: Document RZ/V2H(P) and RZ/V2N SoCs
      dt-bindings: serial: sh-sci: Fold single-entry compatibles into enum

Moteen Shah (2):
      serial: 8250: 8250_omap.c: Add support for handling UART error conditions
      serial: 8250: 8250_omap.c: Clear DMA RX running status only after DMA termination is done

Nathan Chancellor (1):
      tty: vt/keyboard: Split apart vt_do_diacrit()

Randy Dunlap (4):
      serial: imx: change SERIAL_IMX_CONSOLE to bool
      serial: 8250: fix ordering of entries for menu display
      serial: Kconfig: fix ordering of entries for menu display
      serial: SH_SCI: improve "DMA support" prompt

Uwe Kleine-König (4):
      serdev: Provide a bustype shutdown function
      Bluetooth: hci_aml: Migrate to serdev specific shutdown function
      Bluetooth: hci_qca: Migrate to serdev specific shutdown function
      platform/surface: Migrate to serdev specific shutdown function

Xin Zhao (1):
      tty: tty_port: add workqueue to flip TTY buffer

 Documentation/devicetree/bindings/goldfish/tty.txt |  17 --
 Documentation/devicetree/bindings/serial/8250.yaml |   1 +
 .../bindings/serial/google,goldfish-tty.yaml       |  41 +++
 .../devicetree/bindings/serial/renesas,rsci.yaml   | 105 ++++++-
 .../devicetree/bindings/serial/renesas,scif.yaml   |  16 +-
 Documentation/misc-devices/oxsemi-tornado.rst      |  26 +-
 drivers/bluetooth/hci_aml.c                        |  16 +-
 drivers/bluetooth/hci_qca.c                        |   5 +-
 drivers/platform/surface/aggregator/core.c         |   6 +-
 drivers/tty/hvc/hvc_iucv.c                         |   5 +-
 drivers/tty/n_hdlc.c                               |   2 +
 drivers/tty/serdev/core.c                          |  21 ++
 drivers/tty/serial/8250/8250_dw.c                  |  23 +-
 drivers/tty/serial/8250/8250_keba.c                |  27 +-
 drivers/tty/serial/8250/8250_men_mcb.c             |  15 +-
 drivers/tty/serial/8250/8250_omap.c                |  43 +--
 drivers/tty/serial/8250/8250_pci.c                 |  85 +++---
 drivers/tty/serial/8250/Kconfig                    |  95 +++----
 drivers/tty/serial/Kconfig                         |  34 +--
 drivers/tty/serial/men_z135_uart.c                 |   1 -
 drivers/tty/serial/rsci.c                          | 309 ++++++++++++++++++---
 drivers/tty/serial/rsci.h                          |   3 +-
 drivers/tty/serial/sh-sci-common.h                 |  10 +-
 drivers/tty/serial/sh-sci.c                        |  80 +++---
 drivers/tty/vt/keyboard.c                          | 233 ++++++++--------
 include/linux/serdev.h                             |   1 +
 26 files changed, 801 insertions(+), 419 deletions(-)
 delete mode 100644 Documentation/devicetree/bindings/goldfish/tty.txt
 create mode 100644 Documentation/devicetree/bindings/serial/google,goldfish-tty.yaml

^ permalink raw reply

* Re: printk, vt: sleep from invalid context bug
From: Petr Mladek @ 2026-02-17  8:54 UTC (permalink / raw)
  To: Nam Cao
  Cc: Greg Kroah-Hartman, Jiri Slaby, Nicolas Pitre, Calixte Pernot,
	Steven Rostedt, John Ogness, Sergey Senozhatsky,
	Sebastian Andrzej Siewior, Clark Williams, linux-serial,
	linux-kernel, linux-rt-devel
In-Reply-To: <87v7fwdsln.fsf@yellow.woof>

On Tue 2026-02-17 09:14:12, Nam Cao wrote:
> Hi,
> 
> Since commit 1bc9a28f076f ("printk: Use console_flush_one_record for
> legacy printer kthread"), I see this warning:
> 
> BUG: sleeping function called from invalid context at kernel/printk/printk.c:3431
> in_atomic(): 0, irqs_disabled(): 0, non_block: 0, pid: 14, name: pr/legacy
> preempt_count: 0, expected: 0
> RCU nest depth: 1, expected: 0
> 4 locks held by pr/legacy/14:
>  #0: ffffffff807dcdf0 (console_lock){+.+.}-{0:0}, at: legacy_kthread_func+0x40/0x114
>  #1: ffffffff807dce30 (console_srcu){....}-{0:0}, at: console_flush_one_record+0x0/0x3c8
>  #2: ffffffff8083af88 (printing_lock){+.+.}-{3:3}, at: vt_console_print+0x48/0x330
>  #3: ffffffff807df2e8 (rcu_read_lock){....}-{1:3}, at: rt_spin_trylock+0x24/0x138
> CPU: 0 UID: 0 PID: 14 Comm: pr/legacy Not tainted 6.19.0-rvvm-09292-g7449f86bafcd #79 PREEMPT_RT 
> Hardware name: RVVM v0.7-git-g8c45ccf (DT)
> Call Trace:
>     walk_stackframe+0x0/0x80
>     dump_stack_lvl+0x4e/0x74
>     rt_spin_trylock+0x9e/0x138
>     __might_resched+0x19e/0x1e0
>     fbcon_redraw+0x74/0x1a0
>     fbcon_scroll+0xf2/0x13c
>     con_scroll+0x122/0x188
>     lf+0x6a/0x74
>     vt_console_print+0x2ac/0x330
>     console_flush_one_record+0x208/0x3c8
>     console_flush_one_record+0x3c4/0x3c8
>     kthread+0xc6/0x100
>     legacy_kthread_func+0x4c/0x114
>     prio_changed_stop+0xc/0x10
>     kthread+0xc6/0x100
>     ret_from_fork_kernel_asm+0x12/0x18
>     ret_from_fork_kernel+0xe/0x3fc
>     rt_spin_unlock+0x56/0x128
>     kthread_affine_node+0x88/0x8c
>     ret_from_fork_kernel_asm+0x12/0x18
> 
> If I understand it correctly, vt_console_print() grabs the spin lock
> "printing_lock", and then calls fbcon_redraw() which does
> console_conditional_schedule(), triggering the warning.

Sebastian has recently sent a patch which should remove the
cond_resched(), see
https://lore.kernel.org/all/20260126180836.SNCdMW2f@linutronix.de

It seems that the patch has made it upstream in this merge window
for 7.0, see the commit 8e9bf8b9e8c0 ("printk, vt, fbcon: Remove
console_conditional_schedule()").

Best Regards,
Petr


^ permalink raw reply

* Re: [PATCH 09/13] dt-bindings: serial: fsl-linflexuart: add dma properties
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
In-Reply-To: <20260217-stirring-warping-partridge-dd9531@quoll>

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

* Re: [PATCH 09/13] dt-bindings: serial: fsl-linflexuart: add dma properties
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
In-Reply-To: <5c0251b6-5228-4077-a21f-4da179949b90@oss.nxp.com>

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

* Re: [PATCH] tty: ipwireless: Fix use-after-free in tasklet during device removal
From: Jiri Slaby @ 2026-02-17  8:03 UTC (permalink / raw)
  To: dsterba, Jiri Kosina
  Cc: Greg KH, duoming, linux-serial, linux-kernel, dsterba, kuba,
	alexander.deucher, akpm, pkshih, tglx, mingo
In-Reply-To: <20260209102117.GZ26902@suse.cz>

Hi,

On 09. 02. 26, 11:21, David Sterba wrote:
> On Sun, Feb 08, 2026 at 06:25:38PM +0100, Jiri Kosina wrote:
>> On Sun, 8 Feb 2026, Greg KH wrote:
>>
>>>> I don't have the real hardware. In order to reproduce the bug, I simulate
>>>> the IPWireless PCMCIA card in the qemu by allocating and configuring the
>>>> necessary resources(I/O ports, memory regions, interrupts and so on) to
>>>> correspond with the hardware expected by the driver in the initialization
>>>> code of the virtual device.
>>>
>>> I wonder if this device even is still around, given that pcmcia is all
>>> but dead for a very long time.
>>
>> I doubt that this device is still around anywhere where reasonably new
>> kernels (including LTS) would matter.
>>
>> I don't think I've seen this device (which was back then donated to me by
>> T-Mobile CZ in order to get it supported in Linux, and I am not sure how
>> much global adoption it got afterwards) for, let's say, past 15 years :)
>>
>> I think (let's see what David, ho took the maintainership over for me
>> afterwards, has to say) we'd better deprecate and drop the whole thing,
>> rather than trying to pretend that it's still actively being taken care
>> of.
> 
> https://lore.kernel.org/all/20230223172403.GW10580@suse.cz/ last time
> the question of keeping the driver was asked (2023). Back then I was
> able to find the cards on second hand market but now I can't on a local
> market and there's exactly one hit on global eBay.
> 
> Local linux related or telco support forums seem to mention the driver
> until 2011 (root.cz, abclinuxu.cz, t-mobile.cz). It does not prove
> nobody is using it but I think the chances are quite low to justify
> keeping the driver.  It is simple enough to be built as an external
> module eventually, I can help with that in case somebody really needs
> that.

So, would you want to submit the removal? Or anyone else, if you don't 
want to lose time with this? (I can do that, if noone wants to.)

thanks,
-- 
js
suse labs

^ permalink raw reply

* Re: printk, vt: sleep from invalid context bug
From: Sebastian Andrzej Siewior @ 2026-02-17  7:07 UTC (permalink / raw)
  To: Nam Cao
  Cc: Greg Kroah-Hartman, Jiri Slaby, Nicolas Pitre, Calixte Pernot,
	Petr Mladek, Steven Rostedt, John Ogness, Sergey Senozhatsky,
	Clark Williams, linux-serial, linux-kernel, linux-rt-devel
In-Reply-To: <87v7fwdsln.fsf@yellow.woof>

On 2026-02-17 09:14:12 [+0700], Nam Cao wrote:
> Hi,

Hi,

> Since commit 1bc9a28f076f ("printk: Use console_flush_one_record for
> legacy printer kthread"), I see this warning:

https://lore.kernel.org/all/20260126180836.SNCdMW2f@linutronix.de/T/#u

Sebastian

^ permalink raw reply

* [PATCH] serial: 8250_ni: use kzalloc_obj() for allocation
From: Pete Connor @ 2026-02-17  3:19 UTC (permalink / raw)
  To: Chaitanya Vadrevu, Greg Kroah-Hartman, Jiri Slaby, linux-serial,
	linux-kernel
  Cc: Pete Connor

  Replace kzalloc() with the preferred kzalloc_obj() helper
  to address a checkpatch warning.

  Signed-off-by: Pete Connor <pete.connor@pythcoiner.dev>
---
 drivers/tty/serial/8250/8250_ni.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/tty/serial/8250/8250_ni.c b/drivers/tty/serial/8250/8250_ni.c
index cb5b42b3609c..3f3dac694e20 100644
--- a/drivers/tty/serial/8250/8250_ni.c
+++ b/drivers/tty/serial/8250/8250_ni.c
@@ -285,7 +285,7 @@ static int ni16550_probe(struct platform_device *pdev)
 	bool rs232_property;
 	int ret;
 
-	uart = kzalloc(sizeof(*uart), GFP_KERNEL);
+	uart = kzalloc_obj(*uart, GFP_KERNEL);
 	if (!uart)
 		return -ENOMEM;
 
-- 
2.47.3


^ permalink raw reply related

* Re: [PATCH 12/13] serial: linflexuart: Add DMA support
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
In-Reply-To: <20260216150205.212318-13-larisa.grigore@oss.nxp.com>

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

* printk, vt: sleep from invalid context bug
From: Nam Cao @ 2026-02-17  2:14 UTC (permalink / raw)
  To: Greg Kroah-Hartman, Jiri Slaby, Nicolas Pitre, Calixte Pernot,
	Petr Mladek, Steven Rostedt, John Ogness, Sergey Senozhatsky,
	Sebastian Andrzej Siewior, Clark Williams
  Cc: linux-serial, linux-kernel, linux-rt-devel

Hi,

Since commit 1bc9a28f076f ("printk: Use console_flush_one_record for
legacy printer kthread"), I see this warning:

BUG: sleeping function called from invalid context at kernel/printk/printk.c:3431
in_atomic(): 0, irqs_disabled(): 0, non_block: 0, pid: 14, name: pr/legacy
preempt_count: 0, expected: 0
RCU nest depth: 1, expected: 0
4 locks held by pr/legacy/14:
 #0: ffffffff807dcdf0 (console_lock){+.+.}-{0:0}, at: legacy_kthread_func+0x40/0x114
 #1: ffffffff807dce30 (console_srcu){....}-{0:0}, at: console_flush_one_record+0x0/0x3c8
 #2: ffffffff8083af88 (printing_lock){+.+.}-{3:3}, at: vt_console_print+0x48/0x330
 #3: ffffffff807df2e8 (rcu_read_lock){....}-{1:3}, at: rt_spin_trylock+0x24/0x138
CPU: 0 UID: 0 PID: 14 Comm: pr/legacy Not tainted 6.19.0-rvvm-09292-g7449f86bafcd #79 PREEMPT_RT 
Hardware name: RVVM v0.7-git-g8c45ccf (DT)
Call Trace:
    walk_stackframe+0x0/0x80
    dump_stack_lvl+0x4e/0x74
    rt_spin_trylock+0x9e/0x138
    __might_resched+0x19e/0x1e0
    fbcon_redraw+0x74/0x1a0
    fbcon_scroll+0xf2/0x13c
    con_scroll+0x122/0x188
    lf+0x6a/0x74
    vt_console_print+0x2ac/0x330
    console_flush_one_record+0x208/0x3c8
    console_flush_one_record+0x3c4/0x3c8
    kthread+0xc6/0x100
    legacy_kthread_func+0x4c/0x114
    prio_changed_stop+0xc/0x10
    kthread+0xc6/0x100
    ret_from_fork_kernel_asm+0x12/0x18
    ret_from_fork_kernel+0xe/0x3fc
    rt_spin_unlock+0x56/0x128
    kthread_affine_node+0x88/0x8c
    ret_from_fork_kernel_asm+0x12/0x18

If I understand it correctly, vt_console_print() grabs the spin lock
"printing_lock", and then calls fbcon_redraw() which does
console_conditional_schedule(), triggering the warning.

Nam

^ permalink raw reply

* Re: [PATCH 12/13] serial: linflexuart: Add DMA support
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
In-Reply-To: <20260216150205.212318-13-larisa.grigore@oss.nxp.com>

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

* Re: [PATCH 02/13] serial: linflexuart: Clean SLEEP bit in LINCR1 after suspend
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
In-Reply-To: <20260216150205.212318-3-larisa.grigore@oss.nxp.com>

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

* Re: [PATCH 01/13] serial: linflexuart: Fix locking in set_termios
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
In-Reply-To: <20260216150205.212318-2-larisa.grigore@oss.nxp.com>

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

* Re: [PATCH 09/13] dt-bindings: serial: fsl-linflexuart: add dma properties
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
In-Reply-To: <20260216150205.212318-10-larisa.grigore@oss.nxp.com>


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

* Re: [PATCH 12/13] serial: linflexuart: Add DMA support
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
In-Reply-To: <20260216150205.212318-13-larisa.grigore@oss.nxp.com>

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

* Re: [PATCH 09/13] dt-bindings: serial: fsl-linflexuart: add dma properties
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
In-Reply-To: <20260216150205.212318-10-larisa.grigore@oss.nxp.com>

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

* Re: [PATCH 08/13] dt-bindings: serial: fsl-linflexuart: add clock input properties
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
In-Reply-To: <20260216150205.212318-9-larisa.grigore@oss.nxp.com>

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

* [PATCH 13/13] serial: linflexuart: Avoid stopping DMA during receive operations
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
In-Reply-To: <20260216150205.212318-1-larisa.grigore@oss.nxp.com>

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

* [PATCH 12/13] serial: linflexuart: Add DMA support
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
In-Reply-To: <20260216150205.212318-1-larisa.grigore@oss.nxp.com>

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

* [PATCH 11/13] serial: linflexuart: Add support for configurable stop bits
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
In-Reply-To: <20260216150205.212318-1-larisa.grigore@oss.nxp.com>

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

* [PATCH 10/13] serial: linflexuart: Add support for changing baudrate
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
In-Reply-To: <20260216150205.212318-1-larisa.grigore@oss.nxp.com>

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


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox