* 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
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox