From d31228143a489ba6ba797896a07541ce06828c09 Mon Sep 17 00:00:00 2001 From: Artem Shimko Date: Tue, 4 Nov 2025 17:54:25 +0300 Subject: [PATCH 01/49] serial: 8250_dw: handle clock enable errors in runtime_resume Add error checking for clk_prepare_enable() calls in dw8250_runtime_resume(). Currently if either clock fails to enable, the function returns success while leaving clocks in inconsistent state. This change implements comprehensive error handling by checking the return values of both clk_prepare_enable() calls. If the second clock enable operation fails after the first clock has already been successfully enabled, the code now properly cleans up by disabling and unpreparing the first clock before returning. The error code is then propagated to the caller, ensuring that clock enable failures are properly reported rather than being silently ignored. Signed-off-by: Artem Shimko Link: https://patch.msgid.link/20251104145433.2316165-2-a.shimko.dev@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 27af83f0ff46..0f8207652efe 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -741,11 +741,18 @@ static int dw8250_runtime_suspend(struct device *dev) static int dw8250_runtime_resume(struct device *dev) { + int ret; struct dw8250_data *data = dev_get_drvdata(dev); - clk_prepare_enable(data->pclk); + ret = clk_prepare_enable(data->pclk); + if (ret) + return ret; - clk_prepare_enable(data->clk); + ret = clk_prepare_enable(data->clk); + if (ret) { + clk_disable_unprepare(data->pclk); + return ret; + } return 0; } From 485c13d9bc7a83532c038757c2f155728bb4bb38 Mon Sep 17 00:00:00 2001 From: Artem Shimko Date: Tue, 4 Nov 2025 17:54:26 +0300 Subject: [PATCH 02/49] serial: 8250_dw: fix runtime PM initialization sequence Move pm_runtime_set_active() call earlier in probe to simplify error handling and add proper error checking to ensure the device is marked as active before any runtime PM operations can occur. Additionally, replace the const struct dev_pm_ops declaration with _DEFINE_DEV_PM_OPS macro for better consistency with modern kernel PM patterns. Signed-off-by: Artem Shimko Link: https://patch.msgid.link/20251104145433.2316165-3-a.shimko.dev@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 0f8207652efe..db73b2ae17fa 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -643,6 +643,10 @@ static int dw8250_probe(struct platform_device *pdev) if (err) return err; + err = pm_runtime_set_active(dev); + if (err) + return dev_err_probe(dev, err, "Failed to set the runtime suspend as active\n"); + data->uart_16550_compatible = device_property_read_bool(dev, "snps,uart-16550-compatible"); data->pdata = device_get_match_data(p->dev); @@ -685,7 +689,6 @@ static int dw8250_probe(struct platform_device *pdev) platform_set_drvdata(pdev, data); - pm_runtime_set_active(dev); pm_runtime_enable(dev); return 0; @@ -757,10 +760,9 @@ static int dw8250_runtime_resume(struct device *dev) return 0; } -static const struct dev_pm_ops dw8250_pm_ops = { - SYSTEM_SLEEP_PM_OPS(dw8250_suspend, dw8250_resume) - RUNTIME_PM_OPS(dw8250_runtime_suspend, dw8250_runtime_resume, NULL) -}; +static _DEFINE_DEV_PM_OPS(dw8250_pm_ops, dw8250_suspend, dw8250_resume, + dw8250_runtime_suspend, dw8250_runtime_resume, + NULL); static const struct dw8250_platform_data dw8250_dw_apb = { .usr_reg = DW_UART_USR, From 0a76a17238f805b231d97b118232a5185bbb7a18 Mon Sep 17 00:00:00 2001 From: Nathan Chancellor Date: Tue, 25 Nov 2025 15:54:37 -0700 Subject: [PATCH 03/49] tty: vt/keyboard: Split apart vt_do_diacrit() After commit bfb24564b5fd ("tty: vt/keyboard: use __free()"), builds using asm goto for put_user() and get_user() with a version of clang older than 17 error with: drivers/tty/vt/keyboard.c:1709:7: error: cannot jump from this asm goto statement to one of its possible targets if (put_user(asize, &a->kb_cnt)) ^ ... arch/arm64/include/asm/uaccess.h:298:2: note: expanded from macro '__put_mem_asm' asm goto( \ ^ drivers/tty/vt/keyboard.c:1687:7: note: possible target of asm goto statement if (put_user(asize, &a->kb_cnt)) ^ ... arch/arm64/include/asm/uaccess.h:342:2: note: expanded from macro '__raw_put_user' __rpu_failed: \ ^ drivers/tty/vt/keyboard.c:1697:23: note: jump exits scope of variable with __attribute__((cleanup)) void __free(kfree) *buf = kmalloc_array(MAX_DIACR, sizeof(struct kbdiacruc), ^ drivers/tty/vt/keyboard.c:1671:33: note: jump bypasses initialization of variable with __attribute__((cleanup)) struct kbdiacr __free(kfree) *dia = kmalloc_array(MAX_DIACR, sizeof(struct kbdiacr), ^ Prior to a fix to clang's scope checker in clang 17 [1], all labels in a function were validated as potential targets of all asm gotos in a function, regardless of whether they actually were a target of an asm goto call, resulting in false positive errors about skipping over variables marked with the cleanup attribute. To workaround this error, split up the bodies of the case statements in vt_do_diacrit() into their own functions so that the scope checker does not trip up on the multiple instances of __free(). Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202509091702.Oc7eCRDw-lkp@intel.com/ Closes: https://lore.kernel.org/oe-kbuild-all/202511241835.EA8lShgH-lkp@intel.com/ Link: https://github.com/llvm/llvm-project/commit/f023f5cdb2e6c19026f04a15b5a935c041835d14 [1] Signed-off-by: Nathan Chancellor Link: https://patch.msgid.link/20251125-tty-vt-keyboard-wa-clang-scope-check-error-v1-1-f5a5ea55c578@kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/vt/keyboard.c | 233 ++++++++++++++++++++------------------ 1 file changed, 121 insertions(+), 112 deletions(-) diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index d65fc60dd7be..3538d54d6a6a 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c @@ -1649,6 +1649,123 @@ int __init kbd_init(void) /* Ioctl support code */ +static int vt_do_kdgkbdiacr(void __user *udp) +{ + struct kbdiacrs __user *a = udp; + int i, asize; + + struct kbdiacr __free(kfree) *dia = kmalloc_array(MAX_DIACR, sizeof(struct kbdiacr), + GFP_KERNEL); + if (!dia) + return -ENOMEM; + + /* Lock the diacriticals table, make a copy and then + copy it after we unlock */ + scoped_guard(spinlock_irqsave, &kbd_event_lock) { + asize = accent_table_size; + for (i = 0; i < asize; i++) { + dia[i].diacr = conv_uni_to_8bit(accent_table[i].diacr); + dia[i].base = conv_uni_to_8bit(accent_table[i].base); + dia[i].result = conv_uni_to_8bit(accent_table[i].result); + } + } + + if (put_user(asize, &a->kb_cnt)) + return -EFAULT; + if (copy_to_user(a->kbdiacr, dia, asize * sizeof(struct kbdiacr))) + return -EFAULT; + return 0; +} + +static int vt_do_kdgkbdiacruc(void __user *udp) +{ + struct kbdiacrsuc __user *a = udp; + int asize; + + void __free(kfree) *buf = kmalloc_array(MAX_DIACR, sizeof(struct kbdiacruc), + GFP_KERNEL); + if (buf == NULL) + return -ENOMEM; + + /* Lock the diacriticals table, make a copy and then + copy it after we unlock */ + scoped_guard(spinlock_irqsave, &kbd_event_lock) { + asize = accent_table_size; + memcpy(buf, accent_table, asize * sizeof(struct kbdiacruc)); + } + + if (put_user(asize, &a->kb_cnt)) + return -EFAULT; + if (copy_to_user(a->kbdiacruc, buf, asize * sizeof(struct kbdiacruc))) + return -EFAULT; + + return 0; +} + +static int vt_do_kdskbdiacr(void __user *udp, int perm) +{ + struct kbdiacrs __user *a = udp; + struct kbdiacr __free(kfree) *dia = NULL; + unsigned int ct; + int i; + + if (!perm) + return -EPERM; + if (get_user(ct, &a->kb_cnt)) + return -EFAULT; + if (ct >= MAX_DIACR) + return -EINVAL; + + if (ct) { + dia = memdup_array_user(a->kbdiacr, + ct, sizeof(struct kbdiacr)); + if (IS_ERR(dia)) + return PTR_ERR(dia); + } + + guard(spinlock_irqsave)(&kbd_event_lock); + accent_table_size = ct; + for (i = 0; i < ct; i++) { + accent_table[i].diacr = + conv_8bit_to_uni(dia[i].diacr); + accent_table[i].base = + conv_8bit_to_uni(dia[i].base); + accent_table[i].result = + conv_8bit_to_uni(dia[i].result); + } + + return 0; +} + +static int vt_do_kdskbdiacruc(void __user *udp, int perm) +{ + struct kbdiacrsuc __user *a = udp; + unsigned int ct; + void __free(kfree) *buf = NULL; + + if (!perm) + return -EPERM; + + if (get_user(ct, &a->kb_cnt)) + return -EFAULT; + + if (ct >= MAX_DIACR) + return -EINVAL; + + if (ct) { + buf = memdup_array_user(a->kbdiacruc, + ct, sizeof(struct kbdiacruc)); + if (IS_ERR(buf)) + return PTR_ERR(buf); + } + guard(spinlock_irqsave)(&kbd_event_lock); + if (ct) + memcpy(accent_table, buf, + ct * sizeof(struct kbdiacruc)); + accent_table_size = ct; + return 0; +} + /** * vt_do_diacrit - diacritical table updates * @cmd: ioctl request @@ -1660,123 +1777,15 @@ int __init kbd_init(void) */ int vt_do_diacrit(unsigned int cmd, void __user *udp, int perm) { - int asize; - switch (cmd) { case KDGKBDIACR: - { - struct kbdiacrs __user *a = udp; - int i; - - struct kbdiacr __free(kfree) *dia = kmalloc_array(MAX_DIACR, sizeof(struct kbdiacr), - GFP_KERNEL); - if (!dia) - return -ENOMEM; - - /* Lock the diacriticals table, make a copy and then - copy it after we unlock */ - scoped_guard(spinlock_irqsave, &kbd_event_lock) { - asize = accent_table_size; - for (i = 0; i < asize; i++) { - dia[i].diacr = conv_uni_to_8bit(accent_table[i].diacr); - dia[i].base = conv_uni_to_8bit(accent_table[i].base); - dia[i].result = conv_uni_to_8bit(accent_table[i].result); - } - } - - if (put_user(asize, &a->kb_cnt)) - return -EFAULT; - if (copy_to_user(a->kbdiacr, dia, asize * sizeof(struct kbdiacr))) - return -EFAULT; - return 0; - } + return vt_do_kdgkbdiacr(udp); case KDGKBDIACRUC: - { - struct kbdiacrsuc __user *a = udp; - - void __free(kfree) *buf = kmalloc_array(MAX_DIACR, sizeof(struct kbdiacruc), - GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - /* Lock the diacriticals table, make a copy and then - copy it after we unlock */ - scoped_guard(spinlock_irqsave, &kbd_event_lock) { - asize = accent_table_size; - memcpy(buf, accent_table, asize * sizeof(struct kbdiacruc)); - } - - if (put_user(asize, &a->kb_cnt)) - return -EFAULT; - if (copy_to_user(a->kbdiacruc, buf, asize * sizeof(struct kbdiacruc))) - return -EFAULT; - - return 0; - } - + return vt_do_kdgkbdiacruc(udp); case KDSKBDIACR: - { - struct kbdiacrs __user *a = udp; - struct kbdiacr __free(kfree) *dia = NULL; - unsigned int ct; - int i; - - if (!perm) - return -EPERM; - if (get_user(ct, &a->kb_cnt)) - return -EFAULT; - if (ct >= MAX_DIACR) - return -EINVAL; - - if (ct) { - dia = memdup_array_user(a->kbdiacr, - ct, sizeof(struct kbdiacr)); - if (IS_ERR(dia)) - return PTR_ERR(dia); - } - - guard(spinlock_irqsave)(&kbd_event_lock); - accent_table_size = ct; - for (i = 0; i < ct; i++) { - accent_table[i].diacr = - conv_8bit_to_uni(dia[i].diacr); - accent_table[i].base = - conv_8bit_to_uni(dia[i].base); - accent_table[i].result = - conv_8bit_to_uni(dia[i].result); - } - - return 0; - } - + return vt_do_kdskbdiacr(udp, perm); case KDSKBDIACRUC: - { - struct kbdiacrsuc __user *a = udp; - unsigned int ct; - void __free(kfree) *buf = NULL; - - if (!perm) - return -EPERM; - - if (get_user(ct, &a->kb_cnt)) - return -EFAULT; - - if (ct >= MAX_DIACR) - return -EINVAL; - - if (ct) { - buf = memdup_array_user(a->kbdiacruc, - ct, sizeof(struct kbdiacruc)); - if (IS_ERR(buf)) - return PTR_ERR(buf); - } - guard(spinlock_irqsave)(&kbd_event_lock); - if (ct) - memcpy(accent_table, buf, - ct * sizeof(struct kbdiacruc)); - accent_table_size = ct; - return 0; - } + return vt_do_kdskbdiacruc(udp, perm); } return 0; } From 230c33a81e7967791ed75bc3936e94a8b5403617 Mon Sep 17 00:00:00 2001 From: Filip Jensen Date: Wed, 10 Dec 2025 17:48:03 +0100 Subject: [PATCH 04/49] serial: 8250_men_mcb: Clean defines The Z125 define is not used anywhere, thus removed. Also used a more specific name for the maximum number of ports per unit and removed the duplicated define MAX_PORTS Reviewed-by: Jose Javier Rodriguez Barbarin Signed-off-by: Filip Jensen Link: https://patch.msgid.link/20251210164804.94801-2-dev-Felipe.Jensen@duagon.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_men_mcb.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/tty/serial/8250/8250_men_mcb.c b/drivers/tty/serial/8250/8250_men_mcb.c index a78ef35c8187..6ba7464bb2dd 100644 --- a/drivers/tty/serial/8250/8250_men_mcb.c +++ b/drivers/tty/serial/8250/8250_men_mcb.c @@ -28,8 +28,6 @@ #define MEN_UART3_MASK 0x04 #define MEN_UART4_MASK 0x08 -#define MEN_Z125_UARTS_AVAILABLE 0x01 - #define MEN_Z025_MAX_UARTS 4 #define MEN_UART_MEM_SIZE 0x10 #define MEM_UART_REGISTER_SIZE 0x01 @@ -42,12 +40,10 @@ #define MEN_READ_REGISTER(addr) readb(addr) -#define MAX_PORTS 4 - struct serial_8250_men_mcb_data { int num_ports; - int line[MAX_PORTS]; - unsigned int offset[MAX_PORTS]; + int line[MEN_Z025_MAX_UARTS]; + unsigned int offset[MEN_Z025_MAX_UARTS]; }; /* @@ -126,7 +122,7 @@ static int read_serial_data(struct mcb_device *mdev, if (res < 0) return res; - for (i = 0; i < MAX_PORTS; i++) { + for (i = 0; i < MEN_Z025_MAX_UARTS; i++) { mask = 0x1 << i; switch (uarts_available & mask) { case MEN_UART1_MASK: @@ -150,7 +146,7 @@ static int read_serial_data(struct mcb_device *mdev, } } - if (count <= 0 || count > MAX_PORTS) { + if (count <= 0 || count > MEN_Z025_MAX_UARTS) { dev_err(&mdev->dev, "unexpected number of ports: %u\n", count); return -ENODEV; From d84400dc43a7cc62030c367677f7fd34237a8d80 Mon Sep 17 00:00:00 2001 From: Gerhard Engleder Date: Tue, 16 Dec 2025 20:37:24 +0100 Subject: [PATCH 05/49] serial: 8250_keba: Add missing includes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Andy and Ilpo suggested to add missing includes, because the code shall not rely on indirect includes. Add missing includes and remove one include, which only enabled indirect includes. Suggested-by: Andy Shevchenko Suggested-by: Ilpo Järvinen Signed-off-by: Gerhard Engleder Link: https://patch.msgid.link/20251216193726.55449-2-gerhard@engleder-embedded.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_keba.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_keba.c b/drivers/tty/serial/8250/8250_keba.c index c05b89551b12..e9e59ce79138 100644 --- a/drivers/tty/serial/8250/8250_keba.c +++ b/drivers/tty/serial/8250/8250_keba.c @@ -6,10 +6,18 @@ */ #include -#include +#include +#include +#include +#include +#include #include #include +#include #include +#include +#include +#include #include "8250.h" From ee086a69c3ba24bad01a9307b44dc58d1a22ad4e Mon Sep 17 00:00:00 2001 From: Gerhard Engleder Date: Tue, 16 Dec 2025 20:37:25 +0100 Subject: [PATCH 06/49] serial: 8250_keba: Add ICR defines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add defines for better readability of the Indexed Control Register (ICR) access. In enhanced mode SCR and LSR registers are used for ICR access. The behavior of these register is different in this mode and that shall be documented with dedicated defines. Suggested-by: Ilpo Järvinen Signed-off-by: Gerhard Engleder Link: https://patch.msgid.link/20251216193726.55449-3-gerhard@engleder-embedded.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_keba.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/8250/8250_keba.c b/drivers/tty/serial/8250/8250_keba.c index e9e59ce79138..149953c6a288 100644 --- a/drivers/tty/serial/8250/8250_keba.c +++ b/drivers/tty/serial/8250/8250_keba.c @@ -51,6 +51,10 @@ enum kuart_mode { #define KUART_CAPABILITY_RS232 BIT(KUART_MODE_RS232) #define KUART_CAPABILITY_MASK GENMASK(3, 0) +/* registers for Indexed Control Register access in enhanced mode */ +#define KUART_EMODE_ICR_OFFSET UART_SCR +#define KUART_EMODE_ICR_VALUE UART_LSR + /* Additional Control Register DTR line configuration */ #define UART_ACR_DTRLC_MASK 0x18 #define UART_ACR_DTRLC_COMPAT 0x00 @@ -98,13 +102,13 @@ static void kuart_dtr_line_config(struct uart_8250_port *up, u8 dtrlc) u8 acr; /* set index register to 0 to access ACR register */ - serial_out(up, UART_SCR, UART_ACR); + serial_out(up, KUART_EMODE_ICR_OFFSET, UART_ACR); /* set value register to 0x10 writing DTR mode (1,0) */ - acr = serial_in(up, UART_LSR); + acr = serial_in(up, KUART_EMODE_ICR_VALUE); acr &= ~UART_ACR_DTRLC_MASK; acr |= dtrlc; - serial_out(up, UART_LSR, acr); + serial_out(up, KUART_EMODE_ICR_VALUE, acr); } static int kuart_rs485_config(struct uart_port *port, struct ktermios *termios, From e5484745c4c0c3046d8446484f1e663131ba3ec2 Mon Sep 17 00:00:00 2001 From: Gerhard Engleder Date: Tue, 16 Dec 2025 20:37:26 +0100 Subject: [PATCH 07/49] serial: 8250_keba: Use dev_err_probe() Simplify the probe() code by using dev_err_probe(). Suggested-by: Andy Shevchenko Signed-off-by: Gerhard Engleder Link: https://patch.msgid.link/20251216193726.55449-4-gerhard@engleder-embedded.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_keba.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/8250/8250_keba.c b/drivers/tty/serial/8250/8250_keba.c index 149953c6a288..f94d97e69dc5 100644 --- a/drivers/tty/serial/8250/8250_keba.c +++ b/drivers/tty/serial/8250/8250_keba.c @@ -252,10 +252,9 @@ static int kuart_probe(struct auxiliary_device *auxdev, } retval = serial8250_register_8250_port(&uart); - if (retval < 0) { - dev_err(&auxdev->dev, "UART registration failed!\n"); - return retval; - } + if (retval < 0) + return dev_err_probe(&auxdev->dev, retval, + "UART registration failed!\n"); kuart->line = retval; return 0; From 695f986155d9dd95aef4acfca6dd31bf4b83282d Mon Sep 17 00:00:00 2001 From: Bartlomiej Kubik Date: Tue, 2 Dec 2025 07:37:48 +0100 Subject: [PATCH 08/49] tty/n_hdlc: Fix struct n_hdlc kernel-doc warnings Add missing descriptions for write_work and tty_for_write_work members in struct n_hdlc. This fixes the following warnings: drivers/tty/n_hdlc.c: warning: Function parameter or member 'write_work' not described in 'n_hdlc' drivers/tty/n_hdlc.c: warning: Function parameter or member 'tty_for_write_work' not described in 'n_hdlc' Signed-off-by: Bartlomiej Kubik Link: https://patch.msgid.link/20251202063748.1210359-1-kubik.bartlomiej@gmail.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_hdlc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index 3c9dcb0928c6..f242d73ee4e0 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -127,6 +127,8 @@ struct n_hdlc_buf_list { * @rx_buf_list: list of received frame buffers * @tx_free_buf_list: list unused transmit frame buffers * @rx_free_buf_list: list unused received frame buffers + * @write_work: work struct for deferred frame transmission + * @tty_for_write_work: pointer to tty instance used by the @write_work */ struct n_hdlc { bool tbusy; From 0774c43c006bf6e411514920cc57a42abe9374c1 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 29 Nov 2025 16:42:57 +0000 Subject: [PATCH 09/49] dt-bindings: serial: renesas,rsci: Document RZ/G3E support Add documentation for the serial communication interface (RSCI) found on the Renesas RZ/G3E (R9A09G047) SoC. The RSCI IP on this SoC is identical to that on the RZ/T2H (R9A09G077) SoC, but it has a 32-stage FIFO compared to 16 on RZ/T2H. It supports both FIFO and non-FIFO mode operation. RZ/G3E has 6 clocks(5 module clocks + 1 external clock) compared to 3 clocks (2 module clocks + 1 external clock) on RZ/T2H, and it has multiple resets. It has 6 interrupts compared to 4 on RZ/T2H. Signed-off-by: Biju Das Tested-by: Lad Prabhakar Link: https://patch.msgid.link/20251129164325.209213-2-biju.das.jz@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- .../bindings/serial/renesas,rsci.yaml | 99 ++++++++++++++++--- 1 file changed, 88 insertions(+), 11 deletions(-) diff --git a/Documentation/devicetree/bindings/serial/renesas,rsci.yaml b/Documentation/devicetree/bindings/serial/renesas,rsci.yaml index 6b1f827a335b..1f8cee8171de 100644 --- a/Documentation/devicetree/bindings/serial/renesas,rsci.yaml +++ b/Documentation/devicetree/bindings/serial/renesas,rsci.yaml @@ -10,46 +10,72 @@ maintainers: - Geert Uytterhoeven - Lad Prabhakar -allOf: - - $ref: serial.yaml# - properties: compatible: oneOf: - - items: - - const: renesas,r9a09g087-rsci # RZ/N2H - - const: renesas,r9a09g077-rsci # RZ/T2H + - enum: + - renesas,r9a09g047-rsci # RZ/G3E + - renesas,r9a09g077-rsci # RZ/T2H - items: + - const: renesas,r9a09g087-rsci # RZ/N2H - const: renesas,r9a09g077-rsci # RZ/T2H reg: maxItems: 1 interrupts: + minItems: 4 items: - description: Error interrupt - description: Receive buffer full interrupt - description: Transmit buffer empty interrupt - description: Transmit end interrupt + - description: Active edge detection interrupt + - description: Break field detection interrupt interrupt-names: + minItems: 4 items: - const: eri - const: rxi - const: txi - const: tei + - const: aed + - const: bfd clocks: minItems: 2 - maxItems: 3 + maxItems: 6 clock-names: - minItems: 2 + oneOf: + - items: + - const: operation + - const: bus + - const: sck # optional external clock input + + minItems: 2 + + - items: + - const: pclk + - const: tclk + - const: tclk_div4 + - const: tclk_div16 + - const: tclk_div64 + - const: sck # optional external clock input + + minItems: 5 + + resets: items: - - const: operation - - const: bus - - const: sck # optional external clock input + - description: Input for resetting the APB clock + - description: Input for resetting TCLK + + reset-names: + items: + - const: presetn + - const: tresetn power-domains: maxItems: 1 @@ -62,6 +88,57 @@ required: - clock-names - power-domains +allOf: + - $ref: serial.yaml# + + - if: + properties: + compatible: + contains: + const: renesas,r9a09g077-rsci + then: + properties: + interrupts: + maxItems: 4 + + interrupt-names: + maxItems: 4 + + clocks: + minItems: 2 + maxItems: 3 + + clock-names: + minItems: 2 + maxItems: 3 + + resets: false + + - if: + properties: + compatible: + contains: + const: renesas,r9a09g047-rsci + then: + properties: + interrupts: + minItems: 6 + + interrupt-names: + minItems: 6 + + clocks: + minItems: 5 + maxItems: 6 + + clock-names: + minItems: 5 + maxItems: 6 + + required: + - resets + - reset-names + unevaluatedProperties: false examples: From 3a3ab10245b6779e32114bc70052ec7a8a380152 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 29 Nov 2025 16:42:58 +0000 Subject: [PATCH 10/49] serial: sh-sci: Update rx_trigger size for RZ/T2H RSCI The RZ/T2H RSCI has 16-stage FIFO. Like other SoCs, set the default rx_trigger as the fifosize. Signed-off-by: Biju Das Tested-by: Lad Prabhakar Link: https://patch.msgid.link/20251129164325.209213-3-biju.das.jz@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 53edbf1d8963..28d665a9861a 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -3330,7 +3330,7 @@ static int sci_init_single(struct platform_device *dev, sci_port->rx_trigger = 8; break; case SCI_PORT_RSCI: - sci_port->rx_trigger = 15; + sci_port->rx_trigger = 16; break; default: sci_port->rx_trigger = 1; From b346e5d7dbf6696176417923c49838a1beb1d785 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 29 Nov 2025 16:42:59 +0000 Subject: [PATCH 11/49] serial: rsci: Add set_rtrg() callback The rtrg variable is populated in sci_init_single() for RZ/T2H. Add set_rtrg() callback for setting the rtrg value. Signed-off-by: Biju Das Tested-by: Lad Prabhakar Link: https://patch.msgid.link/20251129164325.209213-4-biju.das.jz@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/rsci.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/tty/serial/rsci.c b/drivers/tty/serial/rsci.c index b3c48dc1e07d..0533a4bb1d03 100644 --- a/drivers/tty/serial/rsci.c +++ b/drivers/tty/serial/rsci.c @@ -151,6 +151,22 @@ static void rsci_start_rx(struct uart_port *port) rsci_serial_out(port, CCR0, ctrl); } +static int rsci_scif_set_rtrg(struct uart_port *port, int rx_trig) +{ + u32 fcr = rsci_serial_in(port, FCR); + + if (rx_trig >= port->fifosize) + rx_trig = port->fifosize - 1; + else if (rx_trig < 1) + rx_trig = 0; + + fcr &= ~FCR_RTRG4_0; + fcr |= field_prep(FCR_RTRG4_0, rx_trig); + rsci_serial_out(port, FCR, fcr); + + return rx_trig; +} + static void rsci_set_termios(struct uart_port *port, struct ktermios *termios, const struct ktermios *old) { @@ -454,6 +470,7 @@ static const struct sci_port_ops rsci_port_ops = { .poll_put_char = rsci_poll_put_char, .prepare_console_write = rsci_prepare_console_write, .suspend_regs_size = rsci_suspend_regs_size, + .set_rtrg = rsci_scif_set_rtrg, .shutdown_complete = rsci_shutdown_complete, }; From 42f7303c5f668403f06d9b938d3de2bda3736530 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 29 Nov 2025 16:43:00 +0000 Subject: [PATCH 12/49] serial: sh-sci: Drop checking port type for device file{create, remove} Ports that support FIFO has fifosize > 1. Replace checking the port type with fifosize for device file{create, remove}. Signed-off-by: Biju Das Tested-by: Lad Prabhakar Link: https://patch.msgid.link/20251129164325.209213-5-biju.das.jz@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 28d665a9861a..ff5459c449fb 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -3549,16 +3549,14 @@ static struct uart_driver sci_uart_driver = { static void sci_remove(struct platform_device *dev) { struct sci_port *s = platform_get_drvdata(dev); - unsigned int type = s->type; /* uart_remove_... clears it */ sci_ports_in_use &= ~BIT(s->port.line); uart_remove_one_port(&sci_uart_driver, &s->port); - if (s->port.fifosize > 1) + if (s->port.fifosize > 1) { device_remove_file(&dev->dev, &dev_attr_rx_fifo_trigger); - if (type == PORT_SCIFA || type == PORT_SCIFB || type == PORT_HSCIF || - type == SCI_PORT_RSCI) device_remove_file(&dev->dev, &dev_attr_rx_fifo_timeout); + } } static const struct sci_of_data of_sci_scif_sh2 = { @@ -3917,15 +3915,10 @@ static int sci_probe(struct platform_device *dev) ret = device_create_file(&dev->dev, &dev_attr_rx_fifo_trigger); if (ret) return ret; - } - if (sp->type == PORT_SCIFA || sp->type == PORT_SCIFB || - sp->type == PORT_HSCIF || sp->type == SCI_PORT_RSCI) { + ret = device_create_file(&dev->dev, &dev_attr_rx_fifo_timeout); if (ret) { - if (sp->port.fifosize > 1) { - device_remove_file(&dev->dev, - &dev_attr_rx_fifo_trigger); - } + device_remove_file(&dev->dev, &dev_attr_rx_fifo_trigger); return ret; } } From 450bd399c8797d2783c73aa6c83f382ac8d5f630 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 29 Nov 2025 16:43:01 +0000 Subject: [PATCH 13/49] serial: rsci: Drop rsci_clear_SCxSR() Drop rsci_clear_SCxSR by reusing rsci_clear_CFC() as the contents of both functions are the same. Reviewed-by: Geert Uytterhoeven Signed-off-by: Biju Das Tested-by: Lad Prabhakar Link: https://patch.msgid.link/20251129164325.209213-6-biju.das.jz@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/rsci.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/rsci.c b/drivers/tty/serial/rsci.c index 0533a4bb1d03..158173077c2f 100644 --- a/drivers/tty/serial/rsci.c +++ b/drivers/tty/serial/rsci.c @@ -137,10 +137,6 @@ static void rsci_clear_DRxC(struct uart_port *port) rsci_serial_out(port, FFCLR, FFCLR_DRC); } -static void rsci_clear_SCxSR(struct uart_port *port, unsigned int mask) -{ - rsci_serial_out(port, CFCLR, mask); -} static void rsci_start_rx(struct uart_port *port) { @@ -391,7 +387,7 @@ static void rsci_poll_put_char(struct uart_port *port, unsigned char c) } rsci_serial_out(port, TDR, c); done: - rsci_clear_SCxSR(port, CFCLR_TDREC); + rsci_clear_CFC(port, CFCLR_TDREC); } static void rsci_prepare_console_write(struct uart_port *port, u32 ctrl) @@ -464,7 +460,7 @@ static const struct uart_ops rsci_uart_ops = { static const struct sci_port_ops rsci_port_ops = { .read_reg = rsci_serial_in, .write_reg = rsci_serial_out, - .clear_SCxSR = rsci_clear_SCxSR, + .clear_SCxSR = rsci_clear_CFC, .transmit_chars = rsci_transmit_chars, .receive_chars = rsci_receive_chars, .poll_put_char = rsci_poll_put_char, From c17db4d06cabc7746d48d99c6245d19bd55077d4 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 29 Nov 2025 16:43:02 +0000 Subject: [PATCH 14/49] serial: sh-sci: Drop extra lines Shorten the number lines in sci_init_clocks() by fitting the error messages within an 100-character length limit. Reviewed-by: Geert Uytterhoeven Signed-off-by: Biju Das Tested-by: Lad Prabhakar Link: https://patch.msgid.link/20251129164325.209213-7-biju.das.jz@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index ff5459c449fb..7ca94fa84a40 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -3186,11 +3186,8 @@ static int sci_init_clocks(struct sci_port *sci_port, struct device *dev) return PTR_ERR(clk); if (!clk && sci_port->type == SCI_PORT_RSCI && - (i == SCI_FCK || i == SCI_BRG_INT)) { - return dev_err_probe(dev, -ENODEV, - "failed to get %s\n", - name); - } + (i == SCI_FCK || i == SCI_BRG_INT)) + return dev_err_probe(dev, -ENODEV, "failed to get %s\n", name); if (!clk && i == SCI_FCK) { /* @@ -3200,16 +3197,13 @@ static int sci_init_clocks(struct sci_port *sci_port, struct device *dev) */ clk = devm_clk_get(dev, "peripheral_clk"); if (IS_ERR(clk)) - return dev_err_probe(dev, PTR_ERR(clk), - "failed to get %s\n", - name); + return dev_err_probe(dev, PTR_ERR(clk), "failed to get %s\n", name); } if (!clk) dev_dbg(dev, "failed to get %s\n", name); else - dev_dbg(dev, "clk %s is %pC rate %lu\n", name, - clk, clk_get_rate(clk)); + dev_dbg(dev, "clk %s is %pC rate %lu\n", name, clk, clk_get_rate(clk)); sci_port->clks[i] = clk; } return 0; From 36816a033dd41fda415ae0696931d6bfe87671a2 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 29 Nov 2025 16:43:03 +0000 Subject: [PATCH 15/49] serial: rsci: Drop unused macro DCR Drop unused macro DCR and its bit definition. Reviewed-by: Geert Uytterhoeven Signed-off-by: Biju Das Tested-by: Lad Prabhakar Link: https://patch.msgid.link/20251129164325.209213-8-biju.das.jz@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/rsci.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/tty/serial/rsci.c b/drivers/tty/serial/rsci.c index 158173077c2f..15ed6cf5c6c5 100644 --- a/drivers/tty/serial/rsci.c +++ b/drivers/tty/serial/rsci.c @@ -24,7 +24,6 @@ MODULE_IMPORT_NS("SH_SCI"); #define CCR3 0x14 #define CCR4 0x18 #define FCR 0x24 -#define DCR 0x30 #define CSR 0x48 #define FRSR 0x50 #define FTSR 0x54 @@ -119,8 +118,6 @@ MODULE_IMPORT_NS("SH_SCI"); /* FFCLR (FIFO Flag CLear Register) */ #define FFCLR_DRC BIT(0) /* DR Clear */ -#define DCR_DEPOL BIT(0) - static u32 rsci_serial_in(struct uart_port *p, int offset) { return readl(p->membase + offset); From 507a7ba917cd7ae043ba05db02089b152ae0aaa8 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 29 Nov 2025 16:43:04 +0000 Subject: [PATCH 16/49] serial: rsci: Drop unused TDR register Drop the unused TDR register-related macros. Reviewed-by: Geert Uytterhoeven Signed-off-by: Biju Das Tested-by: Lad Prabhakar Link: https://patch.msgid.link/20251129164325.209213-9-biju.das.jz@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/rsci.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/tty/serial/rsci.c b/drivers/tty/serial/rsci.c index 15ed6cf5c6c5..5a58c783fe8c 100644 --- a/drivers/tty/serial/rsci.c +++ b/drivers/tty/serial/rsci.c @@ -35,12 +35,6 @@ MODULE_IMPORT_NS("SH_SCI"); #define RDR_FPER BIT(11) /* FIFO Parity Error */ #define RDR_RDAT_MSK GENMASK(8, 0) -/* TDR (Transmit Data Register) */ -#define TDR_MPBT BIT(9) /* Multiprocessor Transfer */ -#define TDR_TDAT_9BIT_LSHIFT 0 -#define TDR_TDAT_9BIT_VAL 0x1FF -#define TDR_TDAT_9BIT_MSK (TDR_TDAT_9BIT_VAL << TDR_TDAT_9BIT_LSHIFT) - /* CCR0 (Common Control Register 0) */ #define CCR0_SSE BIT(24) /* SSn# Pin Function Enable */ #define CCR0_TEIE BIT(21) /* Transmit End Interrupt Enable */ From 850ec928922fb819c28eb175bf85b01e28afdea7 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 29 Nov 2025 16:43:05 +0000 Subject: [PATCH 17/49] serial: sh-sci: Use devm_reset_control_array_get_exclusive() Replace devm_*_get_exclusive()->devm_*_array_get_exclusive() to support existing SoCs along with RZ/G3E as RZ/G3E has 2 resets. Reviewed-by: Geert Uytterhoeven Signed-off-by: Biju Das Tested-by: Lad Prabhakar Link: https://patch.msgid.link/20251129164325.209213-10-biju.das.jz@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 7ca94fa84a40..704f175b14e4 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -3708,7 +3708,7 @@ static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev, data = of_device_get_match_data(&pdev->dev); - rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); + rstc = devm_reset_control_array_get_optional_exclusive(&pdev->dev); if (IS_ERR(rstc)) return ERR_PTR(dev_err_probe(&pdev->dev, PTR_ERR(rstc), "failed to get reset ctrl\n")); From 7d8b226bf95cd2b49f15da4f4d40e05932c0d4cc Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 29 Nov 2025 16:43:06 +0000 Subject: [PATCH 18/49] serial: sh-sci: Add sci_is_rsci_type() Add sci_is_rsci_type() for RSCI port type. This will simplify the code when the support added for RSCI_PORT_SCIF32 private PORT type. Reviewed-by: Geert Uytterhoeven Signed-off-by: Biju Das Tested-by: Lad Prabhakar Link: https://patch.msgid.link/20251129164325.209213-11-biju.das.jz@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 704f175b14e4..b7fef518a2b8 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1182,6 +1182,11 @@ static int sci_handle_errors(struct uart_port *port) return copied; } +static bool sci_is_rsci_type(u8 type) +{ + return (type == SCI_PORT_RSCI); +} + static int sci_handle_fifo_overrun(struct uart_port *port) { struct tty_port *tport = &port->state->port; @@ -1190,7 +1195,7 @@ static int sci_handle_fifo_overrun(struct uart_port *port) int copied = 0; u32 status; - if (s->type != SCI_PORT_RSCI) { + if (!sci_is_rsci_type(s->type)) { reg = sci_getreg(port, s->params->overrun_reg); if (!reg->size) return 0; @@ -1198,7 +1203,7 @@ static int sci_handle_fifo_overrun(struct uart_port *port) status = s->ops->read_reg(port, s->params->overrun_reg); if (status & s->params->overrun_mask) { - if (s->type == SCI_PORT_RSCI) { + if (sci_is_rsci_type(s->type)) { /* * All of the CFCLR_*C clearing bits match the corresponding * CSR_*status bits. So, reuse the overrun mask for clearing. @@ -2015,7 +2020,7 @@ static irqreturn_t sci_tx_end_interrupt(int irq, void *ptr) unsigned long flags; u32 ctrl; - if (s->type != PORT_SCI && s->type != SCI_PORT_RSCI) + if (s->type != PORT_SCI && !sci_is_rsci_type(s->type)) return sci_tx_interrupt(irq, ptr); uart_port_lock_irqsave(port, &flags); @@ -3289,7 +3294,7 @@ static int sci_init_single(struct platform_device *dev, * The fourth interrupt on SCI and RSCI port is transmit end interrupt, so * shuffle the interrupts. */ - if (p->type == PORT_SCI || p->type == SCI_PORT_RSCI) + if (p->type == PORT_SCI || sci_is_rsci_type(p->type)) swap(sci_port->irqs[SCIx_BRI_IRQ], sci_port->irqs[SCIx_TEI_IRQ]); /* The SCI generates several interrupts. They can be muxed together or From d53f4aa9edaafda28e426d8e5eda7dc50f7ca94e Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 29 Nov 2025 16:43:07 +0000 Subject: [PATCH 19/49] serial: sh-sci: Rename port SCI_PORT_RSCI->RSCI_PORT_SCIF16 Rename port SCI_PORT_RSCI->RSCI_PORT_SCIF16 to differentiate it from RZ/G3E port that has 32-stage FIFO. Signed-off-by: Biju Das Tested-by: Lad Prabhakar Link: https://patch.msgid.link/20251129164325.209213-12-biju.das.jz@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/rsci.c | 2 +- drivers/tty/serial/sh-sci-common.h | 2 +- drivers/tty/serial/sh-sci.c | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/rsci.c b/drivers/tty/serial/rsci.c index 5a58c783fe8c..7f4cb04daeeb 100644 --- a/drivers/tty/serial/rsci.c +++ b/drivers/tty/serial/rsci.c @@ -462,7 +462,7 @@ static const struct sci_port_ops rsci_port_ops = { }; struct sci_of_data of_sci_rsci_data = { - .type = SCI_PORT_RSCI, + .type = RSCI_PORT_SCIF16, .ops = &rsci_port_ops, .uart_ops = &rsci_uart_ops, .params = &rsci_port_params, diff --git a/drivers/tty/serial/sh-sci-common.h b/drivers/tty/serial/sh-sci-common.h index e3c028df14f1..1b9480c7f4cb 100644 --- a/drivers/tty/serial/sh-sci-common.h +++ b/drivers/tty/serial/sh-sci-common.h @@ -7,7 +7,7 @@ /* Private port IDs */ enum SCI_PORT_TYPE { - SCI_PORT_RSCI = BIT(7) | 0, + RSCI_PORT_SCIF16 = BIT(7) | 0, }; enum SCI_CLKS { diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index b7fef518a2b8..624ef41701f2 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1184,7 +1184,7 @@ static int sci_handle_errors(struct uart_port *port) static bool sci_is_rsci_type(u8 type) { - return (type == SCI_PORT_RSCI); + return (type == RSCI_PORT_SCIF16); } static int sci_handle_fifo_overrun(struct uart_port *port) @@ -3178,7 +3178,7 @@ static int sci_init_clocks(struct sci_port *sci_port, struct device *dev) if (sci_port->type == PORT_HSCIF) { clk_names[SCI_SCK] = "hsck"; - } else if (sci_port->type == SCI_PORT_RSCI) { + } else if (sci_port->type == RSCI_PORT_SCIF16) { clk_names[SCI_FCK] = "operation"; clk_names[SCI_BRG_INT] = "bus"; } @@ -3190,7 +3190,7 @@ static int sci_init_clocks(struct sci_port *sci_port, struct device *dev) if (IS_ERR(clk)) return PTR_ERR(clk); - if (!clk && sci_port->type == SCI_PORT_RSCI && + if (!clk && sci_port->type == RSCI_PORT_SCIF16 && (i == SCI_FCK || i == SCI_BRG_INT)) return dev_err_probe(dev, -ENODEV, "failed to get %s\n", name); @@ -3328,7 +3328,7 @@ static int sci_init_single(struct platform_device *dev, else sci_port->rx_trigger = 8; break; - case SCI_PORT_RSCI: + case RSCI_PORT_SCIF16: sci_port->rx_trigger = 16; break; default: From 4cb2bd1bf41a0d6dbe1fc4bf8d8f83f40b914572 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 29 Nov 2025 16:43:08 +0000 Subject: [PATCH 20/49] serial: sh-sci: Add RSCI_PORT_SCIF32 port ID The RZ/G3E RSCI IP has 32-stage FIFO compared to 16-stage FIFO on RZ/T2H. Add RSCI_PORT_SCIF32 port ID to differentiate it from RZ/T2H RSCI and update sci_is_rsci_type() and sci_is_fifo_type() Signed-off-by: Biju Das Tested-by: Lad Prabhakar Link: https://patch.msgid.link/20251129164325.209213-13-biju.das.jz@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci-common.h | 1 + drivers/tty/serial/sh-sci.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/sh-sci-common.h b/drivers/tty/serial/sh-sci-common.h index 1b9480c7f4cb..abcd5bcc7c36 100644 --- a/drivers/tty/serial/sh-sci-common.h +++ b/drivers/tty/serial/sh-sci-common.h @@ -8,6 +8,7 @@ /* Private port IDs */ enum SCI_PORT_TYPE { RSCI_PORT_SCIF16 = BIT(7) | 0, + RSCI_PORT_SCIF32 = BIT(7) | 1, }; enum SCI_CLKS { diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 624ef41701f2..a63370f22574 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -1184,7 +1184,7 @@ static int sci_handle_errors(struct uart_port *port) static bool sci_is_rsci_type(u8 type) { - return (type == RSCI_PORT_SCIF16); + return (type == RSCI_PORT_SCIF16 || type == RSCI_PORT_SCIF32); } static int sci_handle_fifo_overrun(struct uart_port *port) From 83c405ec3a340a334c46bb59b07e5799f6d205a4 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 29 Nov 2025 16:43:09 +0000 Subject: [PATCH 21/49] serial: sh-sci: Add support for RZ/G3E RSCI clks RZ/G3E RSCI has 6 clocks (5 module clocks + 1 external clock). Add support for the module clocks. Signed-off-by: Biju Das Tested-by: Lad Prabhakar Link: https://patch.msgid.link/20251129164325.209213-14-biju.das.jz@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci-common.h | 3 +++ drivers/tty/serial/sh-sci.c | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/drivers/tty/serial/sh-sci-common.h b/drivers/tty/serial/sh-sci-common.h index abcd5bcc7c36..5d30771278b4 100644 --- a/drivers/tty/serial/sh-sci-common.h +++ b/drivers/tty/serial/sh-sci-common.h @@ -16,6 +16,9 @@ enum SCI_CLKS { SCI_SCK, /* Optional External Clock */ SCI_BRG_INT, /* Optional BRG Internal Clock Source */ SCI_SCIF_CLK, /* Optional BRG External Clock Source */ + SCI_FCK_DIV4, /* Optional Functional Clock frequency-divided by 4 */ + SCI_FCK_DIV16, /* Optional Functional Clock frequency-divided by 16 */ + SCI_FCK_DIV64, /* Optional Functional Clock frequency-divided by 64 */ SCI_NUM_CLKS }; diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index a63370f22574..5d7e78f95c70 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -3172,6 +3172,9 @@ static int sci_init_clocks(struct sci_port *sci_port, struct device *dev) [SCI_SCK] = "sck", [SCI_BRG_INT] = "brg_int", [SCI_SCIF_CLK] = "scif_clk", + [SCI_FCK_DIV4] = "tclk_div4", + [SCI_FCK_DIV16] = "tclk_div16", + [SCI_FCK_DIV64] = "tclk_div64", }; struct clk *clk; unsigned int i; @@ -3181,6 +3184,9 @@ static int sci_init_clocks(struct sci_port *sci_port, struct device *dev) } else if (sci_port->type == RSCI_PORT_SCIF16) { clk_names[SCI_FCK] = "operation"; clk_names[SCI_BRG_INT] = "bus"; + } else if (sci_port->type == RSCI_PORT_SCIF32) { + clk_names[SCI_FCK] = "tclk"; + clk_names[SCI_BRG_INT] = "pclk"; } for (i = 0; i < SCI_NUM_CLKS; i++) { @@ -3194,6 +3200,10 @@ static int sci_init_clocks(struct sci_port *sci_port, struct device *dev) (i == SCI_FCK || i == SCI_BRG_INT)) return dev_err_probe(dev, -ENODEV, "failed to get %s\n", name); + if (!clk && sci_port->type == RSCI_PORT_SCIF32 && + (i != SCI_SCK && i != SCI_SCIF_CLK)) + return dev_err_probe(dev, -ENODEV, "failed to get %s\n", name); + if (!clk && i == SCI_FCK) { /* * Not all SH platforms declare a clock lookup entry From 5632bda5e848c4592eefa4451092beb4ce29ab76 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 29 Nov 2025 16:43:10 +0000 Subject: [PATCH 22/49] serial: sh-sci: Make sci_scbrr_calc() public Make the function sci_scbrr_calc() public for code reuse to support RZ/G3E RSCI IP. Reviewed-by: Geert Uytterhoeven Signed-off-by: Biju Das Tested-by: Lad Prabhakar Link: https://patch.msgid.link/20251129164325.209213-15-biju.das.jz@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci-common.h | 3 +++ drivers/tty/serial/sh-sci.c | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/sh-sci-common.h b/drivers/tty/serial/sh-sci-common.h index 5d30771278b4..976e394ab968 100644 --- a/drivers/tty/serial/sh-sci-common.h +++ b/drivers/tty/serial/sh-sci-common.h @@ -169,6 +169,9 @@ void sci_port_enable(struct sci_port *sci_port); int sci_startup(struct uart_port *port); void sci_shutdown(struct uart_port *port); +int sci_scbrr_calc(struct sci_port *s, unsigned int bps, unsigned int *brr, + unsigned int *srr, unsigned int *cks); + #define min_sr(_port) ffs((_port)->sampling_rate_mask) #define max_sr(_port) fls((_port)->sampling_rate_mask) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 5d7e78f95c70..e2ba752f9c16 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -2573,9 +2573,8 @@ static int sci_brg_calc(struct sci_port *s, unsigned int bps, } /* calculate sample rate, BRR, and clock select */ -static int sci_scbrr_calc(struct sci_port *s, unsigned int bps, - unsigned int *brr, unsigned int *srr, - unsigned int *cks) +int sci_scbrr_calc(struct sci_port *s, unsigned int bps, unsigned int *brr, + unsigned int *srr, unsigned int *cks) { unsigned long freq = s->clk_rates[SCI_FCK]; unsigned int sr, br, prediv, scrate, c; @@ -2639,6 +2638,7 @@ found: min_err, *brr, *srr + 1, *cks); return min_err; } +EXPORT_SYMBOL_NS_GPL(sci_scbrr_calc, "SH_SCI"); static void sci_reset(struct uart_port *port) { From bbcd508c84d4884c620f4f4bb7d382539466b9a3 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 29 Nov 2025 16:43:11 +0000 Subject: [PATCH 23/49] serial: sh-sci: Add finish_console_write() callback Add finish_console_write() callback as RZ/G3E RSCI IP needs special handling compared to other SoCs. Signed-off-by: Biju Das Tested-by: Lad Prabhakar Link: https://patch.msgid.link/20251129164325.209213-16-biju.das.jz@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci-common.h | 1 + drivers/tty/serial/sh-sci.c | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/sh-sci-common.h b/drivers/tty/serial/sh-sci-common.h index 976e394ab968..f363a659c46a 100644 --- a/drivers/tty/serial/sh-sci-common.h +++ b/drivers/tty/serial/sh-sci-common.h @@ -93,6 +93,7 @@ struct sci_port_ops { void (*shutdown_complete)(struct uart_port *port); void (*prepare_console_write)(struct uart_port *port, u32 ctrl); + void (*finish_console_write)(struct uart_port *port, u32 ctrl); void (*console_save)(struct uart_port *port); void (*console_restore)(struct uart_port *port); size_t (*suspend_regs_size)(void); diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index e2ba752f9c16..8f3314b258d6 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -3431,7 +3431,10 @@ static void serial_console_write(struct console *co, const char *s, cpu_relax(); /* restore the SCSCR */ - sci_port->ops->write_reg(port, regs->control, ctrl); + if (sci_port->ops->finish_console_write) + sci_port->ops->finish_console_write(port, ctrl); + else + sci_port->ops->write_reg(port, regs->control, ctrl); if (locked) uart_port_unlock_irqrestore(port, flags); From 068b862f5025920e3e10228e9904c2560e08b855 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 29 Nov 2025 16:43:12 +0000 Subject: [PATCH 24/49] serial: rsci: Rename early_console data, port_params and callback() names Rename rsci_early_console_setup()->rsci_rzt2h_early_console_setup(), the early_console data of_sci_rsci_data->of_rsci_rzt2h_data and the port_params rsci_port_params->rsci_rzt2h_port_params to support RZ/G3E RSCI that uses different data and callback(). Signed-off-by: Biju Das Tested-by: Lad Prabhakar Link: https://patch.msgid.link/20251129164325.209213-17-biju.das.jz@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/rsci.c | 14 +++++++------- drivers/tty/serial/rsci.h | 2 +- drivers/tty/serial/sh-sci.c | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/tty/serial/rsci.c b/drivers/tty/serial/rsci.c index 7f4cb04daeeb..70ff81fdc027 100644 --- a/drivers/tty/serial/rsci.c +++ b/drivers/tty/serial/rsci.c @@ -419,7 +419,7 @@ static const struct sci_port_params_bits rsci_port_param_bits = { .poll_sent_bits = CSR_TDRE | CSR_TEND, }; -static const struct sci_port_params rsci_port_params = { +static const struct sci_port_params rsci_rzt2h_port_params = { .fifosize = 16, .overrun_reg = CSR, .overrun_mask = CSR_ORER, @@ -461,22 +461,22 @@ static const struct sci_port_ops rsci_port_ops = { .shutdown_complete = rsci_shutdown_complete, }; -struct sci_of_data of_sci_rsci_data = { +struct sci_of_data of_rsci_rzt2h_data = { .type = RSCI_PORT_SCIF16, .ops = &rsci_port_ops, .uart_ops = &rsci_uart_ops, - .params = &rsci_port_params, + .params = &rsci_rzt2h_port_params, }; #ifdef CONFIG_SERIAL_SH_SCI_EARLYCON -static int __init rsci_early_console_setup(struct earlycon_device *device, - const char *opt) +static int __init rsci_rzt2h_early_console_setup(struct earlycon_device *device, + const char *opt) { - return scix_early_console_setup(device, &of_sci_rsci_data); + return scix_early_console_setup(device, &of_rsci_rzt2h_data); } -OF_EARLYCON_DECLARE(rsci, "renesas,r9a09g077-rsci", rsci_early_console_setup); +OF_EARLYCON_DECLARE(rsci, "renesas,r9a09g077-rsci", rsci_rzt2h_early_console_setup); #endif /* CONFIG_SERIAL_SH_SCI_EARLYCON */ diff --git a/drivers/tty/serial/rsci.h b/drivers/tty/serial/rsci.h index 2af3f28b465a..9547148e8bd1 100644 --- a/drivers/tty/serial/rsci.h +++ b/drivers/tty/serial/rsci.h @@ -5,6 +5,6 @@ #include "sh-sci-common.h" -extern struct sci_of_data of_sci_rsci_data; +extern struct sci_of_data of_rsci_rzt2h_data; #endif /* __RSCI_H__ */ diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 8f3314b258d6..677293115f1e 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -3664,7 +3664,7 @@ static const struct of_device_id of_sci_match[] __maybe_unused = { #ifdef CONFIG_SERIAL_RSCI { .compatible = "renesas,r9a09g077-rsci", - .data = &of_sci_rsci_data, + .data = &of_rsci_rzt2h_data, }, #endif /* CONFIG_SERIAL_RSCI */ /* Family-specific types */ From 42eeed6d9f31e6063bf98d71212a6de3aac8cdd3 Mon Sep 17 00:00:00 2001 From: Biju Das Date: Sat, 29 Nov 2025 16:43:13 +0000 Subject: [PATCH 25/49] serial: sh-sci: Add support for RZ/G3E RSCI Add support for RZ/G3E RSCI. RSCI IP found on the RZ/G3E SoC is similar to RZ/T2H, but it has a 32-stage FIFO. It has 6 clocks(5 module clocks + 1 external clock) instead of 3 clocks(2 module clocks + 1 external clock) on T2H, has 6 irqs compared to 4 on RZ/T2H and has multiple resets. Add support for the hardware flow control. Signed-off-by: Biju Das Tested-by: Lad Prabhakar Link: https://patch.msgid.link/20251129164325.209213-18-biju.das.jz@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/rsci.c | 260 ++++++++++++++++++++++++++++++++++-- drivers/tty/serial/rsci.h | 1 + drivers/tty/serial/sh-sci.c | 5 + 3 files changed, 257 insertions(+), 9 deletions(-) diff --git a/drivers/tty/serial/rsci.c b/drivers/tty/serial/rsci.c index 70ff81fdc027..1ef7c6d61707 100644 --- a/drivers/tty/serial/rsci.c +++ b/drivers/tty/serial/rsci.c @@ -11,6 +11,8 @@ #include #include #include + +#include "serial_mctrl_gpio.h" #include "rsci.h" MODULE_IMPORT_NS("SH_SCI"); @@ -59,6 +61,41 @@ MODULE_IMPORT_NS("SH_SCI"); #define CCR1_CTSPEN BIT(1) /* CTS External Pin Enable */ #define CCR1_CTSE BIT(0) /* CTS Enable */ +/* CCR2 (Common Control Register 2) */ +#define CCR2_INIT 0xFF000004 +#define CCR2_CKS_TCLK (0) /* TCLK clock */ +#define CCR2_CKS_TCLK_DIV4 BIT(20) /* TCLK/4 clock */ +#define CCR2_CKS_TCLK_DIV16 BIT(21) /* TCLK16 clock */ +#define CCR2_CKS_TCLK_DIV64 (BIT(21) | BIT(20)) /* TCLK/64 clock */ +#define CCR2_BRME BIT(16) /* Bitrate Modulation Enable */ +#define CCR2_ABCSE BIT(6) /* Asynchronous Mode Extended Base Clock Select */ +#define CCR2_ABCS BIT(5) /* Asynchronous Mode Base Clock Select */ +#define CCR2_BGDM BIT(4) /* Baud Rate Generator Double-Speed Mode Select */ + +/* CCR3 (Common Control Register 3) */ +#define CCR3_INIT 0x1203 +#define CCR3_BLK BIT(29) /* Block Transfer Mode */ +#define CCR3_GM BIT(28) /* GSM Mode */ +#define CCR3_CKE1 BIT(25) /* Clock Enable 1 */ +#define CCR3_CKE0 BIT(24) /* Clock Enable 0 */ +#define CCR3_DEN BIT(21) /* Driver Enabled */ +#define CCR3_FM BIT(20) /* FIFO Mode Select */ +#define CCR3_MP BIT(19) /* Multi-Processor Mode */ +#define CCR3_MOD_ASYNC 0 /* Asynchronous mode (Multi-processor mode) */ +#define CCR3_MOD_IRDA BIT(16) /* Smart card interface mode */ +#define CCR3_MOD_CLK_SYNC BIT(17) /* Clock synchronous mode */ +#define CCR3_MOD_SPI (BIT(17) | BIT(16)) /* Simple SPI mode */ +#define CCR3_MOD_I2C BIT(18) /* Simple I2C mode */ +#define CCR3_RXDESEL BIT(15) /* Asynchronous Start Bit Edge Detection Select */ +#define CCR3_STP BIT(14) /* Stop bit Length */ +#define CCR3_SINV BIT(13) /* Transmitted/Received Data Invert */ +#define CCR3_LSBF BIT(12) /* LSB First select */ +#define CCR3_CHR1 BIT(9) /* Character Length */ +#define CCR3_CHR0 BIT(8) /* Character Length */ +#define CCR3_BPEN BIT(7) /* Synchronizer Bypass Enable */ +#define CCR3_CPOL BIT(1) /* Clock Polarity Select */ +#define CCR3_CPHA BIT(0) /* Clock Phase Select */ + /* FCR (FIFO Control Register) */ #define FCR_RFRST BIT(23) /* Receive FIFO Data Register Reset */ #define FCR_TFRST BIT(15) /* Transmit FIFO Data Register Reset */ @@ -138,6 +175,29 @@ static void rsci_start_rx(struct uart_port *port) rsci_serial_out(port, CCR0, ctrl); } +static void rsci_enable_ms(struct uart_port *port) +{ + mctrl_gpio_enable_ms(to_sci_port(port)->gpios); +} + +static void rsci_init_pins(struct uart_port *port, unsigned int cflag) +{ + struct sci_port *s = to_sci_port(port); + + /* Use port-specific handler if provided */ + if (s->cfg->ops && s->cfg->ops->init_pins) { + s->cfg->ops->init_pins(port, cflag); + return; + } + + if (!s->has_rtscts) + return; + + if (s->autorts) + rsci_serial_out(port, CCR1, rsci_serial_in(port, CCR1) | + CCR1_CTSE | CCR1_CTSPEN); +} + static int rsci_scif_set_rtrg(struct uart_port *port, int rx_trig) { u32 fcr = rsci_serial_in(port, FCR); @@ -157,18 +217,119 @@ static int rsci_scif_set_rtrg(struct uart_port *port, int rx_trig) static void rsci_set_termios(struct uart_port *port, struct ktermios *termios, const struct ktermios *old) { + unsigned int ccr2_val = CCR2_INIT, ccr3_val = CCR3_INIT; + unsigned int ccr0_val = 0, ccr1_val = 0, ccr4_val = 0; + unsigned int brr1 = 255, cks1 = 0, srr1 = 15; struct sci_port *s = to_sci_port(port); + unsigned int brr = 255, cks = 0; + int min_err = INT_MAX, err; + unsigned long max_freq = 0; + unsigned int baud, i; unsigned long flags; + unsigned int ctrl; + int best_clk = -1; + + if ((termios->c_cflag & CSIZE) == CS7) { + ccr3_val |= CCR3_CHR0; + } else { + termios->c_cflag &= ~CSIZE; + termios->c_cflag |= CS8; + } + + if (termios->c_cflag & PARENB) + ccr1_val |= CCR1_PE; + + if (termios->c_cflag & PARODD) + ccr1_val |= (CCR1_PE | CCR1_PM); + + if (termios->c_cflag & CSTOPB) + ccr3_val |= CCR3_STP; + + /* Enable noise filter function */ + ccr1_val |= CCR1_NFEN; + + /* + * earlyprintk comes here early on with port->uartclk set to zero. + * the clock framework is not up and running at this point so here + * we assume that 115200 is the maximum baud rate. please note that + * the baud rate is not programmed during earlyprintk - it is assumed + * that the previous boot loader has enabled required clocks and + * setup the baud rate generator hardware for us already. + */ + if (!port->uartclk) { + max_freq = 115200; + } else { + for (i = 0; i < SCI_NUM_CLKS; i++) + max_freq = max(max_freq, s->clk_rates[i]); + + max_freq /= min_sr(s); + } + + baud = uart_get_baud_rate(port, termios, old, 0, max_freq); + if (!baud) + goto done; + + /* Divided Functional Clock using standard Bit Rate Register */ + err = sci_scbrr_calc(s, baud, &brr1, &srr1, &cks1); + if (abs(err) < abs(min_err)) { + best_clk = SCI_FCK; + ccr0_val = 0; + min_err = err; + brr = brr1; + cks = cks1; + } + +done: + if (best_clk >= 0) + dev_dbg(port->dev, "Using clk %pC for %u%+d bps\n", + s->clks[best_clk], baud, min_err); sci_port_enable(s); uart_port_lock_irqsave(port, &flags); - /* For now, only RX enabling is supported */ - if (termios->c_cflag & CREAD) + uart_update_timeout(port, termios->c_cflag, baud); + + rsci_serial_out(port, CCR0, ccr0_val); + + ccr3_val |= CCR3_FM; + rsci_serial_out(port, CCR3, ccr3_val); + + ccr2_val |= (cks << 20) | (brr << 8); + rsci_serial_out(port, CCR2, ccr2_val); + + rsci_serial_out(port, CCR1, ccr1_val); + rsci_serial_out(port, CCR4, ccr4_val); + + ctrl = rsci_serial_in(port, FCR); + ctrl |= (FCR_RFRST | FCR_TFRST); + rsci_serial_out(port, FCR, ctrl); + + if (s->rx_trigger > 1) + rsci_scif_set_rtrg(port, s->rx_trigger); + + port->status &= ~UPSTAT_AUTOCTS; + s->autorts = false; + + if ((port->flags & UPF_HARD_FLOW) && (termios->c_cflag & CRTSCTS)) { + port->status |= UPSTAT_AUTOCTS; + s->autorts = true; + } + + rsci_init_pins(port, termios->c_cflag); + rsci_serial_out(port, CFCLR, CFCLR_CLRFLAG); + rsci_serial_out(port, FFCLR, FFCLR_DRC); + + ccr0_val |= CCR0_RE; + rsci_serial_out(port, CCR0, ccr0_val); + + if ((termios->c_cflag & CREAD) != 0) rsci_start_rx(port); uart_port_unlock_irqrestore(port, flags); sci_port_disable(s); + + if (UART_ENABLE_MS(port, termios->c_cflag)) + rsci_enable_ms(port); } static int rsci_txfill(struct uart_port *port) @@ -193,13 +354,34 @@ static unsigned int rsci_tx_empty(struct uart_port *port) static void rsci_set_mctrl(struct uart_port *port, unsigned int mctrl) { - /* Not supported yet */ + if (mctrl & TIOCM_LOOP) { + /* Standard loopback mode */ + rsci_serial_out(port, CCR1, rsci_serial_in(port, CCR1) | CCR1_SPLP); + } } static unsigned int rsci_get_mctrl(struct uart_port *port) { - /* Not supported yet */ - return 0; + struct sci_port *s = to_sci_port(port); + struct mctrl_gpios *gpios = s->gpios; + unsigned int mctrl = 0; + + mctrl_gpio_get(gpios, &mctrl); + + /* + * CTS/RTS is handled in hardware when supported, while nothing + * else is wired up. + */ + if (!mctrl_gpio_to_gpiod(gpios, UART_GPIO_CTS)) + mctrl |= TIOCM_CTS; + + if (!mctrl_gpio_to_gpiod(gpios, UART_GPIO_DSR)) + mctrl |= TIOCM_DSR; + + if (!mctrl_gpio_to_gpiod(gpios, UART_GPIO_DCD)) + mctrl |= TIOCM_CAR; + + return mctrl; } static void rsci_clear_CFC(struct uart_port *port, unsigned int mask) @@ -329,7 +511,8 @@ static void rsci_receive_chars(struct uart_port *port) continue; } - /* Store data and status. + /* + * Store data and status. * Non FIFO mode is not supported */ if (rdat & RDR_FFER) { @@ -363,6 +546,28 @@ static void rsci_receive_chars(struct uart_port *port) } } +static void rsci_break_ctl(struct uart_port *port, int break_state) +{ + unsigned short ccr0_val, ccr1_val; + unsigned long flags; + + uart_port_lock_irqsave(port, &flags); + ccr1_val = rsci_serial_in(port, CCR1); + ccr0_val = rsci_serial_in(port, CCR0); + + if (break_state == -1) { + ccr1_val = (ccr1_val | CCR1_SPB2IO) & ~CCR1_SPB2DT; + ccr0_val &= ~CCR0_TE; + } else { + ccr1_val = (ccr1_val | CCR1_SPB2DT) & ~CCR1_SPB2IO; + ccr0_val |= CCR0_TE; + } + + rsci_serial_out(port, CCR1, ccr1_val); + rsci_serial_out(port, CCR0, ccr0_val); + uart_port_unlock_irqrestore(port, flags); +} + static void rsci_poll_put_char(struct uart_port *port, unsigned char c) { u32 status; @@ -384,12 +589,21 @@ done: static void rsci_prepare_console_write(struct uart_port *port, u32 ctrl) { struct sci_port *s = to_sci_port(port); - u32 ctrl_temp = - s->params->param_bits->rxtx_enable | CCR0_TIE | - s->hscif_tot; + u32 ctrl_temp = s->params->param_bits->rxtx_enable; + + if (s->type == RSCI_PORT_SCIF16) + ctrl_temp |= CCR0_TIE | s->hscif_tot; + rsci_serial_out(port, CCR0, ctrl_temp); } +static void rsci_finish_console_write(struct uart_port *port, u32 ctrl) +{ + /* First set TE = 0 and then restore the CCR0 value */ + rsci_serial_out(port, CCR0, ctrl & ~CCR0_TE); + rsci_serial_out(port, CCR0, ctrl); +} + static const char *rsci_type(struct uart_port *port) { return "rsci"; @@ -419,6 +633,17 @@ static const struct sci_port_params_bits rsci_port_param_bits = { .poll_sent_bits = CSR_TDRE | CSR_TEND, }; +static const struct sci_port_params rsci_rzg3e_port_params = { + .fifosize = 32, + .overrun_reg = CSR, + .overrun_mask = CSR_ORER, + .sampling_rate_mask = SCI_SR(32), + .error_mask = RSCI_DEFAULT_ERROR_MASK, + .error_clear = RSCI_ERROR_CLEAR, + .param_bits = &rsci_port_param_bits, + .common_regs = &rsci_common_regs, +}; + static const struct sci_port_params rsci_rzt2h_port_params = { .fifosize = 16, .overrun_reg = CSR, @@ -437,6 +662,8 @@ static const struct uart_ops rsci_uart_ops = { .start_tx = rsci_start_tx, .stop_tx = rsci_stop_tx, .stop_rx = rsci_stop_rx, + .enable_ms = rsci_enable_ms, + .break_ctl = rsci_break_ctl, .startup = sci_startup, .shutdown = sci_shutdown, .set_termios = rsci_set_termios, @@ -456,11 +683,19 @@ static const struct sci_port_ops rsci_port_ops = { .receive_chars = rsci_receive_chars, .poll_put_char = rsci_poll_put_char, .prepare_console_write = rsci_prepare_console_write, + .finish_console_write = rsci_finish_console_write, .suspend_regs_size = rsci_suspend_regs_size, .set_rtrg = rsci_scif_set_rtrg, .shutdown_complete = rsci_shutdown_complete, }; +struct sci_of_data of_rsci_rzg3e_data = { + .type = RSCI_PORT_SCIF32, + .ops = &rsci_port_ops, + .uart_ops = &rsci_uart_ops, + .params = &rsci_rzg3e_port_params, +}; + struct sci_of_data of_rsci_rzt2h_data = { .type = RSCI_PORT_SCIF16, .ops = &rsci_port_ops, @@ -470,12 +705,19 @@ struct sci_of_data of_rsci_rzt2h_data = { #ifdef CONFIG_SERIAL_SH_SCI_EARLYCON +static int __init rsci_rzg3e_early_console_setup(struct earlycon_device *device, + const char *opt) +{ + return scix_early_console_setup(device, &of_rsci_rzg3e_data); +} + static int __init rsci_rzt2h_early_console_setup(struct earlycon_device *device, const char *opt) { return scix_early_console_setup(device, &of_rsci_rzt2h_data); } +OF_EARLYCON_DECLARE(rsci, "renesas,r9a09g047-rsci", rsci_rzg3e_early_console_setup); OF_EARLYCON_DECLARE(rsci, "renesas,r9a09g077-rsci", rsci_rzt2h_early_console_setup); #endif /* CONFIG_SERIAL_SH_SCI_EARLYCON */ diff --git a/drivers/tty/serial/rsci.h b/drivers/tty/serial/rsci.h index 9547148e8bd1..2aa2ba3973ee 100644 --- a/drivers/tty/serial/rsci.h +++ b/drivers/tty/serial/rsci.h @@ -5,6 +5,7 @@ #include "sh-sci-common.h" +extern struct sci_of_data of_rsci_rzg3e_data; extern struct sci_of_data of_rsci_rzt2h_data; #endif /* __RSCI_H__ */ diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 677293115f1e..a75d2113752b 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -3329,6 +3329,7 @@ static int sci_init_single(struct platform_device *dev, sci_port->rx_trigger = 64; break; case PORT_SCIFA: + case RSCI_PORT_SCIF32: sci_port->rx_trigger = 32; break; case PORT_SCIF: @@ -3662,6 +3663,10 @@ static const struct of_device_id of_sci_match[] __maybe_unused = { .data = &of_sci_scif_rzv2h, }, #ifdef CONFIG_SERIAL_RSCI + { + .compatible = "renesas,r9a09g047-rsci", + .data = &of_rsci_rzg3e_data, + }, { .compatible = "renesas,r9a09g077-rsci", .data = &of_rsci_rzt2h_data, From 6d71c62b13c33ea858ab298fe20beaec5736edc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 12 Dec 2025 09:09:06 +0100 Subject: [PATCH 26/49] serdev: Provide a bustype shutdown function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To prepare serdev driver to migrate away from struct device_driver::shutdown (and then eventually remove that callback) create a serdev driver shutdown callback and migration code to keep the existing behaviour. Note this introduces a warning for each driver at register time that isn't converted yet to that callback. Signed-off-by: Uwe Kleine-König Link: https://patch.msgid.link/ab518883e3ed0976a19cb5b5b5faf42bd3a655b7.1765526117.git.u.kleine-koenig@baylibre.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serdev/core.c | 21 +++++++++++++++++++++ include/linux/serdev.h | 1 + 2 files changed, 22 insertions(+) diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c index b33e708cb245..40eedc15277c 100644 --- a/drivers/tty/serdev/core.c +++ b/drivers/tty/serdev/core.c @@ -414,11 +414,21 @@ static void serdev_drv_remove(struct device *dev) sdrv->remove(to_serdev_device(dev)); } +static void serdev_drv_shutdown(struct device *dev) +{ + const struct serdev_device_driver *sdrv = + to_serdev_device_driver(dev->driver); + + if (dev->driver && sdrv->shutdown) + sdrv->shutdown(to_serdev_device(dev)); +} + static const struct bus_type serdev_bus_type = { .name = "serial", .match = serdev_device_match, .probe = serdev_drv_probe, .remove = serdev_drv_remove, + .shutdown = serdev_drv_shutdown, }; /** @@ -814,6 +824,14 @@ void serdev_controller_remove(struct serdev_controller *ctrl) } EXPORT_SYMBOL_GPL(serdev_controller_remove); +static void serdev_legacy_shutdown(struct serdev_device *serdev) +{ + struct device *dev = &serdev->dev; + struct device_driver *driver = dev->driver; + + driver->shutdown(dev); +} + /** * __serdev_device_driver_register() - Register client driver with serdev core * @sdrv: client driver to be associated with client-device. @@ -830,6 +848,9 @@ int __serdev_device_driver_register(struct serdev_device_driver *sdrv, struct mo /* force drivers to async probe so I/O is possible in probe */ sdrv->driver.probe_type = PROBE_PREFER_ASYNCHRONOUS; + if (!sdrv->shutdown && sdrv->driver.shutdown) + sdrv->shutdown = serdev_legacy_shutdown; + return driver_register(&sdrv->driver); } EXPORT_SYMBOL_GPL(__serdev_device_driver_register); diff --git a/include/linux/serdev.h b/include/linux/serdev.h index 34562eb99931..5654c58eb73c 100644 --- a/include/linux/serdev.h +++ b/include/linux/serdev.h @@ -65,6 +65,7 @@ struct serdev_device_driver { struct device_driver driver; int (*probe)(struct serdev_device *); void (*remove)(struct serdev_device *); + void (*shutdown)(struct serdev_device *); }; static inline struct serdev_device_driver *to_serdev_device_driver(struct device_driver *d) From 673a674c52f01b714316087dd07500e681457912 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 12 Dec 2025 09:09:07 +0100 Subject: [PATCH 27/49] Bluetooth: hci_aml: Migrate to serdev specific shutdown function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This saves a cast in the driver. The motivation is stop using the callback .shutdown in qca_serdev_driver.driver to make it possible to drop that. Signed-off-by: Uwe Kleine-König Link: https://patch.msgid.link/42ae20ba70ff6fbbbd9b846ac9acd0f7d58451b0.1765526117.git.u.kleine-koenig@baylibre.com Signed-off-by: Greg Kroah-Hartman --- drivers/bluetooth/hci_aml.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/bluetooth/hci_aml.c b/drivers/bluetooth/hci_aml.c index b1f32c5a8a3f..4981c82d634d 100644 --- a/drivers/bluetooth/hci_aml.c +++ b/drivers/bluetooth/hci_aml.c @@ -677,13 +677,6 @@ static const struct hci_uart_proto aml_hci_proto = { .dequeue = aml_dequeue, }; -static void aml_device_driver_shutdown(struct device *dev) -{ - struct aml_serdev *amldev = dev_get_drvdata(dev); - - aml_power_off(amldev); -} - static int aml_serdev_probe(struct serdev_device *serdev) { struct aml_serdev *amldev; @@ -714,6 +707,13 @@ static void aml_serdev_remove(struct serdev_device *serdev) hci_uart_unregister_device(&amldev->serdev_hu); } +static void aml_serdev_shutdown(struct serdev_device *serdev) +{ + struct aml_serdev *amldev = serdev_device_get_drvdata(serdev); + + aml_power_off(amldev); +} + static const struct aml_device_data data_w155s2 = { .iccm_offset = 256 * 1024, }; @@ -732,10 +732,10 @@ MODULE_DEVICE_TABLE(of, aml_bluetooth_of_match); static struct serdev_device_driver aml_serdev_driver = { .probe = aml_serdev_probe, .remove = aml_serdev_remove, + .shutdown = aml_serdev_shutdown, .driver = { .name = "hci_uart_aml", .of_match_table = aml_bluetooth_of_match, - .shutdown = aml_device_driver_shutdown, }, }; From 12a6a5726c515455935982429ac35dee2307233d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 12 Dec 2025 09:09:08 +0100 Subject: [PATCH 28/49] Bluetooth: hci_qca: Migrate to serdev specific shutdown function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This saves a cast in the driver. The motivation is stop using the callback .shutdown in qca_serdev_driver.driver to make it possible to drop that. Signed-off-by: Uwe Kleine-König Link: https://patch.msgid.link/261a3384e25c4837d4efee87958805f15d7d4e3c.1765526117.git.u.kleine-koenig@baylibre.com Signed-off-by: Greg Kroah-Hartman --- drivers/bluetooth/hci_qca.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c index 888176b0faa9..6d54f747fde4 100644 --- a/drivers/bluetooth/hci_qca.c +++ b/drivers/bluetooth/hci_qca.c @@ -2530,11 +2530,10 @@ static void qca_serdev_remove(struct serdev_device *serdev) hci_uart_unregister_device(&qcadev->serdev_hu); } -static void qca_serdev_shutdown(struct device *dev) +static void qca_serdev_shutdown(struct serdev_device *serdev) { int ret; int timeout = msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS); - struct serdev_device *serdev = to_serdev_device(dev); struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev); struct hci_uart *hu = &qcadev->serdev_hu; struct hci_dev *hdev = hu->hdev; @@ -2756,11 +2755,11 @@ static void hciqca_coredump(struct device *dev) static struct serdev_device_driver qca_serdev_driver = { .probe = qca_serdev_probe, .remove = qca_serdev_remove, + .shutdown = qca_serdev_shutdown, .driver = { .name = "hci_uart_qca", .of_match_table = of_match_ptr(qca_bluetooth_of_match), .acpi_match_table = ACPI_PTR(qca_bluetooth_acpi_match), - .shutdown = qca_serdev_shutdown, .pm = &qca_pm_ops, #ifdef CONFIG_DEV_COREDUMP .coredump = hciqca_coredump, From 284da5de616aaebf9c2c62e5fc7cb464a064eff7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 12 Dec 2025 09:09:09 +0100 Subject: [PATCH 29/49] platform/surface: Migrate to serdev specific shutdown function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The motivation is stop using the callback .shutdown in qca_serdev_driver.driver to make it possible to drop that. Signed-off-by: Uwe Kleine-König Link: https://patch.msgid.link/9682d206a1f375cd98e7dbfce4f1a83b4b345178.1765526117.git.u.kleine-koenig@baylibre.com Signed-off-by: Greg Kroah-Hartman --- drivers/platform/surface/aggregator/core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/platform/surface/aggregator/core.c b/drivers/platform/surface/aggregator/core.c index c7e05f7bc199..82e531023911 100644 --- a/drivers/platform/surface/aggregator/core.c +++ b/drivers/platform/surface/aggregator/core.c @@ -380,9 +380,9 @@ static int ssam_serdev_setup(struct acpi_device *ssh, struct serdev_device *serd /* -- Power management. ----------------------------------------------------- */ -static void ssam_serial_hub_shutdown(struct device *dev) +static void ssam_serial_hub_shutdown(struct serdev_device *serdev) { - struct ssam_controller *c = dev_get_drvdata(dev); + struct ssam_controller *c = dev_get_drvdata(&serdev->dev); int status; /* @@ -834,12 +834,12 @@ MODULE_DEVICE_TABLE(of, ssam_serial_hub_of_match); static struct serdev_device_driver ssam_serial_hub = { .probe = ssam_serial_hub_probe, .remove = ssam_serial_hub_remove, + .shutdown = ssam_serial_hub_shutdown, .driver = { .name = "surface_serial_hub", .acpi_match_table = ACPI_PTR(ssam_serial_hub_acpi_match), .of_match_table = of_match_ptr(ssam_serial_hub_of_match), .pm = &ssam_serial_hub_pm_ops, - .shutdown = ssam_serial_hub_shutdown, .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, }; From b5024e804ee06330486caf3087e1b0d91e3797a5 Mon Sep 17 00:00:00 2001 From: Guodong Xu Date: Mon, 22 Dec 2025 21:04:15 +0800 Subject: [PATCH 30/49] dt-bindings: serial: 8250: add SpacemiT K3 UART compatible The SpacemiT K3 UART controller is compatible with the Intel XScale UART. Add K3 UART binding and allow describing it with a fixed clock-frequency for now. The clocks and clock-names properties will be made mandatory in a future patch, once the K3 clock driver and device tree are merged. Acked-by: Conor Dooley Signed-off-by: Guodong Xu Link: https://patch.msgid.link/20251222-k3-basic-dt-v2-5-3af3f3cd0f8a@riscstar.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/8250.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/serial/8250.yaml b/Documentation/devicetree/bindings/serial/8250.yaml index 167ddcbd8800..73851f19330d 100644 --- a/Documentation/devicetree/bindings/serial/8250.yaml +++ b/Documentation/devicetree/bindings/serial/8250.yaml @@ -160,6 +160,7 @@ properties: - enum: - mrvl,mmp-uart - spacemit,k1-uart + - spacemit,k3-uart - const: intel,xscale-uart - items: - enum: From c14afba60a61bc80403a571a67db956aa9800dbb Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 22 Dec 2025 15:02:09 +0100 Subject: [PATCH 31/49] serial: rsci: Convert to FIELD_MODIFY() Use the FIELD_MODIFY() helper instead of open-coding the same operation. Signed-off-by: Geert Uytterhoeven Link: https://patch.msgid.link/ada3faf4698155a618ae6371b35eab121eb8b19c.1766411924.git.geert+renesas@glider.be Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/rsci.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/tty/serial/rsci.c b/drivers/tty/serial/rsci.c index 1ef7c6d61707..c3f12df693ad 100644 --- a/drivers/tty/serial/rsci.c +++ b/drivers/tty/serial/rsci.c @@ -207,8 +207,7 @@ static int rsci_scif_set_rtrg(struct uart_port *port, int rx_trig) else if (rx_trig < 1) rx_trig = 0; - fcr &= ~FCR_RTRG4_0; - fcr |= field_prep(FCR_RTRG4_0, rx_trig); + FIELD_MODIFY(FCR_RTRG4_0, &fcr, rx_trig); rsci_serial_out(port, FCR, fcr); return rx_trig; From 21566457614fc52b5799f96b996618709f74e419 Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Mon, 22 Dec 2025 16:29:09 +0000 Subject: [PATCH 32/49] dt-bindings: serial: renesas,rsci: Document RZ/V2H(P) and RZ/V2N SoCs Document the serial communication interface (RSCI) used on the Renesas RZ/V2H(P) (R9A09G057) and RZ/V2N (R9A09G056) SoCs. These SoCs integrate the same RSCI IP block as the RZ/G3E (R9A09G047), so the RZ/G3E compatible is used as a fallback for both. Signed-off-by: Lad Prabhakar Reviewed-by: Krzysztof Kozlowski Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20251222162909.155279-1-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/renesas,rsci.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/serial/renesas,rsci.yaml b/Documentation/devicetree/bindings/serial/renesas,rsci.yaml index 1f8cee8171de..e059b14775eb 100644 --- a/Documentation/devicetree/bindings/serial/renesas,rsci.yaml +++ b/Documentation/devicetree/bindings/serial/renesas,rsci.yaml @@ -17,6 +17,12 @@ properties: - renesas,r9a09g047-rsci # RZ/G3E - renesas,r9a09g077-rsci # RZ/T2H + - items: + - enum: + - renesas,r9a09g056-rsci # RZ/V2N + - renesas,r9a09g057-rsci # RZ/V2H(P) + - const: renesas,r9a09g047-rsci + - items: - const: renesas,r9a09g087-rsci # RZ/N2H - const: renesas,r9a09g077-rsci # RZ/T2H From afc57d096f897bd5244ed8e81700d5ad7c829a27 Mon Sep 17 00:00:00 2001 From: Jose Javier Rodriguez Barbarin Date: Thu, 8 Jan 2026 14:41:09 +0100 Subject: [PATCH 33/49] serial: men_z135_uart: drop unneeded MODULE_ALIAS Since commit 1f4ea4838b13 ("mcb: Add missing modpost build support") the MODULE_ALIAS() is redundant as the module alias is now automatically generated from the MODULE_DEVICE_TABLE(). Remove the explicit alias. No functional change intended. Reviewed-by: Jorge Sanjuan Garcia Signed-off-by: Jose Javier Rodriguez Barbarin Link: https://patch.msgid.link/20260108134110.25278-2-dev-josejavier.rodriguez@duagon.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/men_z135_uart.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/tty/serial/men_z135_uart.c b/drivers/tty/serial/men_z135_uart.c index 9cc15449b673..6fad57fee912 100644 --- a/drivers/tty/serial/men_z135_uart.c +++ b/drivers/tty/serial/men_z135_uart.c @@ -919,5 +919,4 @@ module_exit(men_z135_exit); MODULE_AUTHOR("Johannes Thumshirn "); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("MEN 16z135 High Speed UART"); -MODULE_ALIAS("mcb:16z135"); MODULE_IMPORT_NS("MCB"); From 79dd246c6eb305f13566739f9b1f34e092fec5e5 Mon Sep 17 00:00:00 2001 From: Jose Javier Rodriguez Barbarin Date: Thu, 8 Jan 2026 14:41:10 +0100 Subject: [PATCH 34/49] 8250_men_mcb: drop unneeded MODULE_ALIAS Since commit 1f4ea4838b13 ("mcb: Add missing modpost build support") the MODULE_ALIAS() is redundant as the module alias is now automatically generated from the MODULE_DEVICE_TABLE(). Remove the explicit alias. No functional change intended. Reviewed-by: Jorge Sanjuan Garcia Signed-off-by: Jose Javier Rodriguez Barbarin Link: https://patch.msgid.link/20260108134110.25278-3-dev-josejavier.rodriguez@duagon.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_men_mcb.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/tty/serial/8250/8250_men_mcb.c b/drivers/tty/serial/8250/8250_men_mcb.c index 6ba7464bb2dd..6373234da03d 100644 --- a/drivers/tty/serial/8250/8250_men_mcb.c +++ b/drivers/tty/serial/8250/8250_men_mcb.c @@ -264,7 +264,4 @@ module_mcb_driver(mcb_driver); MODULE_LICENSE("GPL v2"); MODULE_DESCRIPTION("MEN 8250 UART driver"); MODULE_AUTHOR("Michael Moese Date: Sat, 10 Jan 2026 15:26:40 -0800 Subject: [PATCH 35/49] serial: imx: change SERIAL_IMX_CONSOLE to bool SERIAL_IMX_CONSOLE is a build option for the imx driver (SERIAL_IMX). It does not build a separate console driver file, so it can't be built as a module since it isn't built at all. Change the Kconfig symbol from tristate to bool and update the help text accordingly. Fixes: 0db4f9b91c86 ("tty: serial: imx: enable imx serial console port as module") Signed-off-by: Randy Dunlap Link: https://patch.msgid.link/20260110232643.3533351-2-rdunlap@infradead.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 59221cce0028..98a946096be3 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -486,14 +486,14 @@ config SERIAL_IMX can enable its onboard serial port by enabling this option. config SERIAL_IMX_CONSOLE - tristate "Console on IMX serial port" + bool "Console on IMX serial port" depends on SERIAL_IMX select SERIAL_CORE_CONSOLE help If you have enabled the serial port on the Freescale IMX - CPU you can make it the console by answering Y/M to this option. + CPU you can make it the console by answering Y to this option. - Even if you say Y/M here, the currently visible virtual console + Even if you say Y here, the currently visible virtual console (/dev/tty0) will still be used as the system console by default, but you can alter that using a kernel command line option such as "console=ttymxc0". (Try "man bootparam" or see the documentation of From 1ec8891402a6f755e2750a9be39434702d616146 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 10 Jan 2026 15:26:41 -0800 Subject: [PATCH 36/49] serial: 8250: fix ordering of entries for menu display Improve the "8250/16550 serial support" menu so that entries in it are displayed in a better order (reorder a few symbols) and so that intervening symbols don't break up the dependency list, allowing menu entries to be displayed with proper indentation. Signed-off-by: Randy Dunlap Link: https://patch.msgid.link/20260110232643.3533351-3-rdunlap@infradead.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/Kconfig | 95 +++++++++++++++++---------------- 1 file changed, 48 insertions(+), 47 deletions(-) diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index c488ff6f2865..fd4e8b6ab60d 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -116,6 +116,7 @@ config SERIAL_8250_DMA config SERIAL_8250_PCILIB bool + depends on SERIAL_8250 && PCI config SERIAL_8250_PCI tristate "8250/16550 PCI device support" @@ -205,6 +206,37 @@ config SERIAL_8250_EXTENDED kernel: saying N will just cause the configurator to skip all the questions about serial driver options. If unsure, say N. +config SERIAL_8250_SHARE_IRQ + bool "Support for sharing serial interrupts" + depends on SERIAL_8250_EXTENDED + help + Some serial boards have hardware support which allows multiple dumb + serial ports on the same board to share a single IRQ. To enable + support for this in the serial driver, say Y here. + +config SERIAL_8250_DETECT_IRQ + bool "Autodetect IRQ on standard ports (unsafe)" + depends on SERIAL_8250_EXTENDED + help + Say Y here if you want the kernel to try to guess which IRQ + to use for your serial port. + + This is considered unsafe; it is far better to configure the IRQ in + a boot script using the setserial command. + + If unsure, say N. + +config SERIAL_8250_RSA + bool "Support RSA serial ports" + depends on SERIAL_8250_EXTENDED + help + Say Y here if you have a IODATA RSA-DV II/S ISA card and + would like to use its >115kbps speeds. + You will need to provide module parameter "probe_rsa", or boot-time + parameter 8250.probe_rsa with I/O addresses of this card then. + + If you don't have such card, or if unsure, say N. + config SERIAL_8250_MANY_PORTS bool "Support more than 4 legacy serial ports" depends on SERIAL_8250_EXTENDED @@ -240,19 +272,6 @@ config SERIAL_8250_ACCENT To compile this driver as a module, choose M here: the module will be called 8250_accent. -config SERIAL_8250_ASPEED_VUART - tristate "Aspeed Virtual UART" - depends on SERIAL_8250 - depends on OF - depends on MFD_SYSCON - depends on ARCH_ASPEED || COMPILE_TEST - select REGMAP - help - If you want to use the virtual UART (VUART) device on Aspeed - BMC platforms, enable this option. This enables the 16550A- - compatible device on the local LPC bus, giving a UART device - with no physical RS232 connections. - config SERIAL_8250_BOCA tristate "Support Boca cards" depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS @@ -293,44 +312,23 @@ config SERIAL_8250_PCI1XXXX serial driver for the serial interface. This driver support will ensure to support baud rates upto 1.5Mpbs. +config SERIAL_8250_ASPEED_VUART + tristate "Aspeed Virtual UART" + depends on SERIAL_8250 + depends on OF + depends on MFD_SYSCON + depends on ARCH_ASPEED || COMPILE_TEST + select REGMAP + help + If you want to use the virtual UART (VUART) device on Aspeed + BMC platforms, enable this option. This enables the 16550A- + compatible device on the local LPC bus, giving a UART device + with no physical RS232 connections. + # # Misc. options/drivers. # -config SERIAL_8250_SHARE_IRQ - bool "Support for sharing serial interrupts" - depends on SERIAL_8250_EXTENDED - help - Some serial boards have hardware support which allows multiple dumb - serial ports on the same board to share a single IRQ. To enable - support for this in the serial driver, say Y here. - -config SERIAL_8250_DETECT_IRQ - bool "Autodetect IRQ on standard ports (unsafe)" - depends on SERIAL_8250_EXTENDED - help - Say Y here if you want the kernel to try to guess which IRQ - to use for your serial port. - - This is considered unsafe; it is far better to configure the IRQ in - a boot script using the setserial command. - - If unsure, say N. - -config SERIAL_8250_RSA - bool "Support RSA serial ports" - depends on SERIAL_8250_EXTENDED - help - Say Y here if you have a IODATA RSA-DV II/S ISA card and - would like to use its >115kbps speeds. - You will need to provide module parameter "probe_rsa", or boot-time - parameter 8250.probe_rsa with I/O addresses of this card then. - - If you don't have such card, or if unsure, say N. - -config SERIAL_8250_DWLIB - bool - config SERIAL_8250_ACORN tristate "Acorn expansion card serial port support" depends on ARCH_ACORN && SERIAL_8250 @@ -596,3 +594,6 @@ config SERIAL_OF_PLATFORM are probed through devicetree, including Open Firmware based PowerPC systems and embedded systems on architectures using the flattened device tree format. + +config SERIAL_8250_DWLIB + bool From 2c468edb6b19ad00c247fc52dc6074e4012b46ed Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 10 Jan 2026 15:26:42 -0800 Subject: [PATCH 37/49] serial: Kconfig: fix ordering of entries for menu display Improve the "Non-8250 serial port support" menu so that entries in it are displayed in a better order (_CONSOLE after its driver) and so that intervening symbols don't break up the dependency list, allowing menu entries to be displayed with proper indentation. Signed-off-by: Randy Dunlap Link: https://patch.msgid.link/20260110232643.3533351-4-rdunlap@infradead.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 98a946096be3..c73057d80bb1 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -413,6 +413,10 @@ config SERIAL_21285_CONSOLE your boot loader (lilo or loadlin) about how to pass options to the kernel at boot time.) +config SERIAL_PXA_NON8250 + bool + depends on !SERIAL_8250 || COMPILE_TEST + config SERIAL_PXA bool "PXA serial port support (DEPRECATED)" depends on ARCH_PXA || ARCH_MMP @@ -426,10 +430,6 @@ config SERIAL_PXA Unless you have a specific need, you should use SERIAL_8250_PXA instead of this. -config SERIAL_PXA_NON8250 - bool - depends on !SERIAL_8250 || COMPILE_TEST - config SERIAL_PXA_CONSOLE bool "Console on PXA serial port (DEPRECATED)" depends on SERIAL_PXA @@ -863,15 +863,15 @@ config SERIAL_ICOM This driver can also be built as a module. If so, the module will be called icom. +config HAS_TXX9_SERIAL + bool + config SERIAL_TXX9 bool "TMPTX39XX/49XX SIO support" depends on HAS_TXX9_SERIAL select SERIAL_CORE default y -config HAS_TXX9_SERIAL - bool - config SERIAL_TXX9_NR_UARTS int "Maximum number of TMPTX39XX/49XX SIO ports" depends on SERIAL_TXX9 @@ -1251,12 +1251,6 @@ config SERIAL_AR933X_NR_UARTS Set this to the number of serial ports you want the driver to support. -config SERIAL_MPS2_UART_CONSOLE - bool "MPS2 UART console support" - depends on SERIAL_MPS2_UART - select SERIAL_CORE_CONSOLE - select SERIAL_EARLYCON - config SERIAL_MPS2_UART bool "MPS2 UART port" depends on ARCH_MPS2 || COMPILE_TEST @@ -1264,6 +1258,12 @@ config SERIAL_MPS2_UART help This driver support the UART ports on ARM MPS2. +config SERIAL_MPS2_UART_CONSOLE + bool "MPS2 UART console support" + depends on SERIAL_MPS2_UART + select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON + config SERIAL_ARC tristate "ARC UART driver support" select SERIAL_CORE From 93bb95a11238d66a4c9aa6eabf9774b073a5895c Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 10 Jan 2026 15:26:43 -0800 Subject: [PATCH 38/49] serial: SH_SCI: improve "DMA support" prompt Having a prompt of "DMA support" suddenly appear during a "make oldconfig" can be confusing. Add a little helpful text to the prompt message. Fixes: 73a19e4c0301 ("serial: sh-sci: Add DMA support.") Signed-off-by: Randy Dunlap Reviewed-by: Geert Uytterhoeven Link: https://patch.msgid.link/20260110232643.3533351-5-rdunlap@infradead.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index c73057d80bb1..f86775cfdcc9 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -671,7 +671,7 @@ config SERIAL_SH_SCI_EARLYCON default ARCH_RENESAS config SERIAL_SH_SCI_DMA - bool "DMA support" if EXPERT + bool "Support for DMA on SuperH SCI(F)" if EXPERT depends on SERIAL_SH_SCI && DMA_ENGINE default ARCH_RENESAS From 623b07b370e9963122d167e04fdc1dc713ebfbaf Mon Sep 17 00:00:00 2001 From: Moteen Shah Date: Mon, 12 Jan 2026 13:48:28 +0530 Subject: [PATCH 39/49] serial: 8250: 8250_omap.c: Add support for handling UART error conditions The DMA IRQ handler does not accounts for the overrun(OE) or any other errors being reported by the IP before triggering a DMA transaction which leads to the interrupts not being handled resulting into an IRQ storm. The way to handle OE is to: 1. Reset the RX FIFO. 2. Read the UART_RESUME register, which clears the internal flag Earlier, the driver issued DMA transations even in case of OE which shouldn't be done according to the OE handling mechanism mentioned above, as we are resetting the FIFO's, refer section: "12.1.6.4.8.1.3.6 Overrun During Receive" [0]. [0] https://www.ti.com/lit/pdf/spruiu1 Signed-off-by: Moteen Shah Link: https://patch.msgid.link/20260112081829.63049-2-m-shah@ti.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_omap.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 9e49ef48b851..e26bae0a6488 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -100,6 +100,9 @@ #define OMAP_UART_REV_52 0x0502 #define OMAP_UART_REV_63 0x0603 +/* Resume register */ +#define UART_OMAP_RESUME 0x0B + /* Interrupt Enable Register 2 */ #define UART_OMAP_IER2 0x1B #define UART_OMAP_IER2_RHR_IT_DIS BIT(2) @@ -119,7 +122,6 @@ /* Timeout low and High */ #define UART_OMAP_TO_L 0x26 #define UART_OMAP_TO_H 0x27 - struct omap8250_priv { void __iomem *membase; int line; @@ -1256,6 +1258,20 @@ static u16 omap_8250_handle_rx_dma(struct uart_8250_port *up, u8 iir, u16 status return status; } +static void am654_8250_handle_uart_errors(struct uart_8250_port *up, u8 iir, u16 status) +{ + if (status & UART_LSR_OE) { + serial8250_clear_and_reinit_fifos(up); + serial_in(up, UART_LSR); + serial_in(up, UART_OMAP_RESUME); + } else { + if (status & (UART_LSR_FE | UART_LSR_PE | UART_LSR_BI)) + serial_in(up, UART_RX); + if (iir & UART_IIR_XOFF) + serial_in(up, UART_IIR); + } +} + static void am654_8250_handle_rx_dma(struct uart_8250_port *up, u8 iir, u16 status) { @@ -1266,7 +1282,8 @@ static void am654_8250_handle_rx_dma(struct uart_8250_port *up, u8 iir, * Queue a new transfer if FIFO has data. */ if ((status & (UART_LSR_DR | UART_LSR_BI)) && - (up->ier & UART_IER_RDI)) { + (up->ier & UART_IER_RDI) && !(status & UART_LSR_OE)) { + am654_8250_handle_uart_errors(up, iir, status); omap_8250_rx_dma(up); serial_out(up, UART_OMAP_EFR2, UART_OMAP_EFR2_TIMEOUT_BEHAVE); } else if ((iir & 0x3f) == UART_IIR_RX_TIMEOUT) { @@ -1282,6 +1299,8 @@ static void am654_8250_handle_rx_dma(struct uart_8250_port *up, u8 iir, serial_out(up, UART_OMAP_EFR2, 0x0); up->ier |= UART_IER_RLSI | UART_IER_RDI; serial_out(up, UART_IER, up->ier); + } else { + am654_8250_handle_uart_errors(up, iir, status); } } From a5fd8945a478ff9be14812693891d7c9b4185a50 Mon Sep 17 00:00:00 2001 From: Moteen Shah Date: Mon, 12 Jan 2026 13:48:29 +0530 Subject: [PATCH 40/49] serial: 8250: 8250_omap.c: Clear DMA RX running status only after DMA termination is done Clear rx_running flag only after DMA teardown polling completes. In the previous implementation the flag was being cleared while hardware teardown was still in progress, creating a mismatch between software state (flag = 0, "ready") and hardware state (still terminating). Signed-off-by: Moteen Shah Link: https://patch.msgid.link/20260112081829.63049-3-m-shah@ti.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index e26bae0a6488..272bc07c9a6b 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -931,7 +931,6 @@ static void __dma_rx_do_complete(struct uart_8250_port *p) goto out; cookie = dma->rx_cookie; - dma->rx_running = 0; /* Re-enable RX FIFO interrupt now that transfer is complete */ if (priv->habit & UART_HAS_RHR_IT_DIS) { @@ -965,6 +964,7 @@ static void __dma_rx_do_complete(struct uart_8250_port *p) goto out; ret = tty_insert_flip_string(tty_port, dma->rx_buf, count); + dma->rx_running = 0; p->port.icount.rx += ret; p->port.icount.buf_overrun += count - ret; out: From 9e0313435c2d077f9eb432439228e57c36e6422d Mon Sep 17 00:00:00 2001 From: Lad Prabhakar Date: Mon, 12 Jan 2026 09:57:22 +0000 Subject: [PATCH 41/49] dt-bindings: serial: sh-sci: Fold single-entry compatibles into enum Group single compatibles into enum. Signed-off-by: Lad Prabhakar Reviewed-by: Geert Uytterhoeven Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260112095722.25556-1-prabhakar.mahadev-lad.rj@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/serial/renesas,scif.yaml | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/Documentation/devicetree/bindings/serial/renesas,scif.yaml b/Documentation/devicetree/bindings/serial/renesas,scif.yaml index 72483bc3274d..a6ef02327be8 100644 --- a/Documentation/devicetree/bindings/serial/renesas,scif.yaml +++ b/Documentation/devicetree/bindings/serial/renesas,scif.yaml @@ -12,15 +12,16 @@ maintainers: properties: compatible: oneOf: + - enum: + - renesas,scif-r7s9210 # RZ/A2 + - renesas,scif-r9a07g044 # RZ/G2{L,LC} + - renesas,scif-r9a09g057 # RZ/V2H(P) + - items: - enum: - renesas,scif-r7s72100 # RZ/A1H - const: renesas,scif # generic SCIF compatible UART - - items: - - enum: - - renesas,scif-r7s9210 # RZ/A2 - - items: - enum: - renesas,scif-r8a7778 # R-Car M1 @@ -76,10 +77,6 @@ properties: - const: renesas,rcar-gen5-scif # R-Car Gen5 - const: renesas,scif # generic SCIF compatible UART - - items: - - enum: - - renesas,scif-r9a07g044 # RZ/G2{L,LC} - - items: - enum: - renesas,scif-r9a07g043 # RZ/G2UL and RZ/Five @@ -87,8 +84,6 @@ properties: - renesas,scif-r9a08g045 # RZ/G3S - const: renesas,scif-r9a07g044 # RZ/G2{L,LC} fallback - - const: renesas,scif-r9a09g057 # RZ/V2H(P) - - items: - enum: - renesas,scif-r9a09g047 # RZ/G3E From c7d8b85b98f749725ac1d0575f7a44007fde0c94 Mon Sep 17 00:00:00 2001 From: Kuan-Wei Chiu Date: Tue, 13 Jan 2026 09:25:57 +0000 Subject: [PATCH 42/49] dt-bindings: serial: google,goldfish-tty: Convert to DT schema Convert the Google Goldfish TTY binding to DT schema format. Move the file to the serial directory to match the subsystem. Update the example node name to 'serial' to comply with generic node naming standards. Signed-off-by: Kuan-Wei Chiu Reviewed-by: Krzysztof Kozlowski Link: https://patch.msgid.link/20260113092602.3197681-2-visitorckw@gmail.com Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/goldfish/tty.txt | 17 -------- .../bindings/serial/google,goldfish-tty.yaml | 41 +++++++++++++++++++ 2 files changed, 41 insertions(+), 17 deletions(-) delete mode 100644 Documentation/devicetree/bindings/goldfish/tty.txt create mode 100644 Documentation/devicetree/bindings/serial/google,goldfish-tty.yaml diff --git a/Documentation/devicetree/bindings/goldfish/tty.txt b/Documentation/devicetree/bindings/goldfish/tty.txt deleted file mode 100644 index 82648278da77..000000000000 --- a/Documentation/devicetree/bindings/goldfish/tty.txt +++ /dev/null @@ -1,17 +0,0 @@ -Android Goldfish TTY - -Android goldfish tty device generated by android emulator. - -Required properties: - -- compatible : should contain "google,goldfish-tty" to match emulator -- reg : -- interrupts : - -Example: - - goldfish_tty@1f004000 { - compatible = "google,goldfish-tty"; - reg = <0x1f004000 0x1000>; - interrupts = <0xc>; - }; diff --git a/Documentation/devicetree/bindings/serial/google,goldfish-tty.yaml b/Documentation/devicetree/bindings/serial/google,goldfish-tty.yaml new file mode 100644 index 000000000000..0626ce58740c --- /dev/null +++ b/Documentation/devicetree/bindings/serial/google,goldfish-tty.yaml @@ -0,0 +1,41 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/serial/google,goldfish-tty.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Google Goldfish TTY + +maintainers: + - Kuan-Wei Chiu + +allOf: + - $ref: /schemas/serial/serial.yaml# + +description: + Android goldfish TTY device generated by Android emulator. + +properties: + compatible: + const: google,goldfish-tty + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + +required: + - compatible + - reg + - interrupts + +unevaluatedProperties: false + +examples: + - | + serial@1f004000 { + compatible = "google,goldfish-tty"; + reg = <0x1f004000 0x1000>; + interrupts = <12>; + }; From 0e19f73ffde187458fadfff60eb4771bff704296 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Wed, 26 Nov 2025 15:29:09 +0100 Subject: [PATCH 43/49] tty: hvc-iucv: Remove KMSG_COMPONENT macro The KMSG_COMPONENT macro is a leftover of the s390 specific "kernel message catalog" from 2008 [1] which never made it upstream. The macro was added to s390 code to allow for an out-of-tree patch which used this to generate unique message ids. Also this out-of-tree doesn't exist anymore. Remove the macro in order to get rid of a pointless indirection. [1] https://lwn.net/Articles/292650/ Acked-by: Hendrik Brueckner Signed-off-by: Heiko Carstens Link: https://patch.msgid.link/20251126142909.2140015-1-hca@linux.ibm.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/hvc/hvc_iucv.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c index 4ca7472c38e0..a7939c49c9cf 100644 --- a/drivers/tty/hvc/hvc_iucv.c +++ b/drivers/tty/hvc/hvc_iucv.c @@ -9,8 +9,7 @@ * * Author(s): Hendrik Brueckner */ -#define KMSG_COMPONENT "hvc_iucv" -#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt +#define pr_fmt(fmt) "hvc_iucv: " fmt #include #include @@ -1344,7 +1343,7 @@ static int __init hvc_iucv_init(void) } } - hvc_iucv_buffer_cache = kmem_cache_create(KMSG_COMPONENT, + hvc_iucv_buffer_cache = kmem_cache_create("hvc_iucv", sizeof(struct iucv_tty_buffer), 0, 0, NULL); if (!hvc_iucv_buffer_cache) { From b64da5b16ab3c5dcc6e95180891d1c10eda83ffd Mon Sep 17 00:00:00 2001 From: Kendall Willis Date: Fri, 16 Jan 2026 13:55:49 -0600 Subject: [PATCH 44/49] serial: 8250: omap: set out-of-band wakeup if wakeup pinctrl exists In TI K3 SoCs, I/O daisy chaining is used to allow wakeup from UART when the UART controller is off. Set UART device as wakeup capable using out-of-band wakeup if the 'wakeup' pinctrl state exists and the device may wakeup. Reviewed-by: Dhruva Gole Signed-off-by: Kendall Willis Link: https://patch.msgid.link/20260116-uart-wakeup-v2-1-0078ae9996e4@ti.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_omap.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 272bc07c9a6b..8c88e0f47cd9 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -1382,6 +1382,8 @@ static int omap8250_select_wakeup_pinctrl(struct device *dev, if (!device_may_wakeup(dev)) return 0; + device_set_out_band_wakeup(dev); + return pinctrl_select_state(priv->pinctrl, priv->pinctrl_wakeup); } From b05bebaa60e4e58f36631f41a73716edd8c56d3e Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 20 Jan 2026 12:52:12 +0000 Subject: [PATCH 45/49] dt-bindings: serial: renesas,scif: Document RZ/G3L SoC Add SCIF binding documentation for Renesas RZ/G3L SoC. SCIF block on the RZ/G3L is identical to one found on the RZ/G3S SoC. Signed-off-by: Biju Das Acked-by: Conor Dooley Reviewed-by: Fabrizio Castro Link: https://patch.msgid.link/20260120125232.349708-2-biju.das.jz@bp.renesas.com Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/renesas,scif.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/serial/renesas,scif.yaml b/Documentation/devicetree/bindings/serial/renesas,scif.yaml index a6ef02327be8..82f54446835e 100644 --- a/Documentation/devicetree/bindings/serial/renesas,scif.yaml +++ b/Documentation/devicetree/bindings/serial/renesas,scif.yaml @@ -82,6 +82,7 @@ properties: - renesas,scif-r9a07g043 # RZ/G2UL and RZ/Five - renesas,scif-r9a07g054 # RZ/V2L - renesas,scif-r9a08g045 # RZ/G3S + - renesas,scif-r9a08g046 # RZ/G3L - const: renesas,scif-r9a07g044 # RZ/G2{L,LC} fallback - items: From 1250ebacd4cc59ede613f95e16aba309f364c0f6 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 22 Jan 2026 11:19:47 +0100 Subject: [PATCH 46/49] serial: 8250_omap: Remove custom deprecated baud setting routine As comments mentioned this is old (and actually deprecated) interface to set custom baud rates. This interface has limitations as it only allows to set a single opaque value called "custom_divisor". If the HW needs more complex settings (like fractional divisor) it must somehow encode this. This is horrid interface that is very driver specific and not flexible. Meanwhile Linux has established way to set free baud rate settings via BOTHER [1]. With all this being said, remove deprecated interface for good. Link: https://stackoverflow.com/questions/12646324/how-can-i-set-a-custom-baud-rate-on-linux [1] Signed-off-by: Andy Shevchenko Link: https://patch.msgid.link/20260122102349.2395423-2-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_omap.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 8c88e0f47cd9..c552c6b9a037 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -243,22 +243,6 @@ static void omap_8250_get_divisor(struct uart_port *port, unsigned int baud, unsigned int div_13, div_16; unsigned int abs_d13, abs_d16; - /* - * Old custom speed handling. - */ - if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) { - priv->quot = port->custom_divisor & UART_DIV_MAX; - /* - * I assume that nobody is using this. But hey, if somebody - * would like to specify the divisor _and_ the mode then the - * driver is ready and waiting for it. - */ - if (port->custom_divisor & (1 << 16)) - priv->mdr1 = UART_OMAP_MDR1_13X_MODE; - else - priv->mdr1 = UART_OMAP_MDR1_16X_MODE; - return; - } div_13 = DIV_ROUND_CLOSEST(uartclk, 13 * baud); div_16 = DIV_ROUND_CLOSEST(uartclk, 16 * baud); From 3f0716c604e81d8440b16d0d8f5420c4a6f3c17a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 22 Jan 2026 11:19:48 +0100 Subject: [PATCH 47/49] serial: 8250_pci: Remove custom deprecated baud setting routine As comments mentioned this is old (and actually deprecated) interface to set custom baud rates. This interface has limitations as it only allows to set a single opaque value called "custom_divisor". If the HW needs more complex settings (like fractional divisor) it must somehow encode this. This is horrid interface that is very driver specific and not flexible. Meanwhile Linux has established way to set free baud rate settings via BOTHER [1]. With all this being said, remove deprecated interface for good. Link: https://stackoverflow.com/questions/12646324/how-can-i-set-a-custom-baud-rate-on-linux [1] Signed-off-by: Andy Shevchenko Link: https://patch.msgid.link/20260122102349.2395423-3-andriy.shevchenko@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- Documentation/misc-devices/oxsemi-tornado.rst | 26 +----- drivers/tty/serial/8250/8250_pci.c | 85 ++++++++----------- 2 files changed, 38 insertions(+), 73 deletions(-) diff --git a/Documentation/misc-devices/oxsemi-tornado.rst b/Documentation/misc-devices/oxsemi-tornado.rst index b33351bef6cf..fe2e5f726c2b 100644 --- a/Documentation/misc-devices/oxsemi-tornado.rst +++ b/Documentation/misc-devices/oxsemi-tornado.rst @@ -89,31 +89,7 @@ With the baud base set to 15625000 and the unsigned 16-bit UART_DIV_MAX limitation imposed by ``serial8250_get_baud_rate`` standard baud rates below 300bps become unavailable in the regular way, e.g. the rate of 200bps requires the baud base to be divided by 78125 and that is beyond -the unsigned 16-bit range. The historic spd_cust feature can still be -used by encoding the values for, the prescaler, the oversampling rate -and the clock divisor (DLM/DLL) as follows to obtain such rates if so -required: - -:: - - 31 29 28 20 19 16 15 0 - +-----+-----------------+-------+-------------------------------+ - |0 0 0| CPR2:CPR | TCR | DLM:DLL | - +-----+-----------------+-------+-------------------------------+ - -Use a value such encoded for the ``custom_divisor`` field along with the -ASYNC_SPD_CUST flag set in the ``flags`` field in ``struct serial_struct`` -passed with the TIOCSSERIAL ioctl(2), such as with the setserial(8) -utility and its ``divisor`` and ``spd_cust`` parameters, and then select -the baud rate of 38400bps. Note that the value of 0 in TCR sets the -oversampling rate to 16 and prescaler values below 1 in CPR2/CPR are -clamped by the driver to 1. - -For example the value of 0x1f4004e2 will set CPR2/CPR, TCR and DLM/DLL -respectively to 0x1f4, 0x0 and 0x04e2, choosing the prescaler value, -the oversampling rate and the clock divisor of 62.500, 16 and 1250 -respectively. These parameters will set the baud rate for the serial -port to 62500000 / 62.500 / 1250 / 16 = 50bps. +the unsigned 16-bit range. Maciej W. Rozycki diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index c5a932f48f74..8da725cdf9a9 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1205,60 +1205,49 @@ static unsigned int pci_oxsemi_tornado_get_divisor(struct uart_port *port, u8 tcr; int i; - /* Old custom speed handling. */ - if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) { - unsigned int cust_div = port->custom_divisor; + best_squot = quot_scale; + for (i = 0; i < ARRAY_SIZE(p); i++) { + unsigned int spre; + unsigned int srem; + u8 cp; + u8 tc; - quot = cust_div & UART_DIV_MAX; - tcr = (cust_div >> 16) & OXSEMI_TORNADO_TCR_MASK; - cpr = (cust_div >> 20) & OXSEMI_TORNADO_CPR_MASK; - if (cpr < OXSEMI_TORNADO_CPR_MIN) - cpr = OXSEMI_TORNADO_CPR_DEF; - } else { - best_squot = quot_scale; - for (i = 0; i < ARRAY_SIZE(p); i++) { - unsigned int spre; - unsigned int srem; - u8 cp; - u8 tc; + tc = p[i][0]; + cp = p[i][1]; + spre = tc * cp; - tc = p[i][0]; - cp = p[i][1]; - spre = tc * cp; + srem = sdiv % spre; + if (srem > spre / 2) + srem = spre - srem; + squot = DIV_ROUND_CLOSEST(srem * quot_scale, spre); - srem = sdiv % spre; - if (srem > spre / 2) - srem = spre - srem; - squot = DIV_ROUND_CLOSEST(srem * quot_scale, spre); - - if (srem == 0) { - tcr = tc; - cpr = cp; - quot = sdiv / spre; - break; - } else if (squot < best_squot) { - best_squot = squot; - tcr = tc; - cpr = cp; - quot = DIV_ROUND_CLOSEST(sdiv, spre); - } + if (srem == 0) { + tcr = tc; + cpr = cp; + quot = sdiv / spre; + break; + } else if (squot < best_squot) { + best_squot = squot; + tcr = tc; + cpr = cp; + quot = DIV_ROUND_CLOSEST(sdiv, spre); } - while (tcr <= (OXSEMI_TORNADO_TCR_MASK + 1) >> 1 && - quot % 2 == 0) { + } + while (tcr <= (OXSEMI_TORNADO_TCR_MASK + 1) >> 1 && + quot % 2 == 0) { + quot >>= 1; + tcr <<= 1; + } + while (quot > UART_DIV_MAX) { + if (tcr <= (OXSEMI_TORNADO_TCR_MASK + 1) >> 1) { quot >>= 1; tcr <<= 1; - } - while (quot > UART_DIV_MAX) { - if (tcr <= (OXSEMI_TORNADO_TCR_MASK + 1) >> 1) { - quot >>= 1; - tcr <<= 1; - } else if (cpr <= OXSEMI_TORNADO_CPR_MASK >> 1) { - quot >>= 1; - cpr <<= 1; - } else { - quot = quot * cpr / OXSEMI_TORNADO_CPR_MASK; - cpr = OXSEMI_TORNADO_CPR_MASK; - } + } else if (cpr <= OXSEMI_TORNADO_CPR_MASK >> 1) { + quot >>= 1; + cpr <<= 1; + } else { + quot = quot * cpr / OXSEMI_TORNADO_CPR_MASK; + cpr = OXSEMI_TORNADO_CPR_MASK; } } From d000422a46aad32217cf1be747eb61d641baae2f Mon Sep 17 00:00:00 2001 From: Xin Zhao Date: Tue, 23 Dec 2025 11:48:36 +0800 Subject: [PATCH 48/49] tty: tty_port: add workqueue to flip TTY buffer On the embedded platform, certain critical data, such as IMU data, is transmitted through UART. The tty_flip_buffer_push() interface in the TTY layer uses system_dfl_wq to handle the flipping of the TTY buffer. Although the unbound workqueue can create new threads on demand and wake up the kworker thread on an idle CPU, it may be preempted by real-time tasks or other high-prio tasks. flush_to_ldisc() needs to wake up the relevant data handle thread. When executing __wake_up_common_lock(), it calls spin_lock_irqsave(), which does not disable preemption but disables migration in RT-Linux. This prevents the kworker thread from being migrated to other cores by CPU's balancing logic, resulting in long delays. The call trace is as follows: __wake_up_common_lock __wake_up ep_poll_callback __wake_up_common __wake_up_common_lock __wake_up n_tty_receive_buf_common n_tty_receive_buf2 tty_ldisc_receive_buf tty_port_default_receive_buf flush_to_ldisc In our system, the processing interval for each frame of IMU data transmitted via UART can experience significant jitter due to this issue. Instead of the expected 10 to 15 ms frame processing interval, we see spikes up to 30 to 35 ms. Moreover, in just one or two hours, there can be 2 to 3 occurrences of such high jitter, which is quite frequent. This jitter exceeds the software's tolerable limit of 20 ms. Introduce flip_wq in tty_port which can be set by tty_port_link_wq() or as default linked to default workqueue allocated when tty_register_driver(). The default workqueue is allocated with flag WQ_SYSFS, so that cpumask and nice can be set dynamically. The execution timing of tty_port_link_wq() is not clearly restricted. The newly added function tty_port_link_driver_wq() checks whether the flip_wq of the tty_port has already been assigned when linking the default tty_driver's workqueue to the port. After the user has set a custom workqueue for a certain tty_port using tty_port_link_wq(), the system will only use this custom workqueue, even if tty_driver does not have %TTY_DRIVER_CUSTOM_WORKQUEUE flag. Introduce %TTY_DRIVER_CUSTOM_WORKQUEUE flag meaning not to create the default single tty_driver workqueue. Two reasons why need to introduce the %TTY_DRIVER_CUSTOM_WORKQUEUE flag: 1. If the WQ_SYSFS parameter is enabled, workqueue_sysfs_register() will fail when trying to create a workqueue with the same name. The pty is an example of this; if both CONFIG_LEGACY_PTYS and CONFIG_UNIX98_PTYS are enabled, the call to tty_register_driver() in unix98_pty_init() will fail. 2. Different tty ports may be used for different tasks, which may require separate core binding control via workqueues. In this case, the workqueue created by default in the tty driver is unnecessary. Enabling this flag prevents the creation of this redundant workqueue. After applying this patch, we can set the related UART TTY flip buffer workqueue by sysfs. We set the cpumask to CPU cores associated with the IMU tasks, and set the nice to -20. Testing has shown significant improvement in the previously described issue, with almost no stuttering occurring anymore. Signed-off-by: Xin Zhao Reviewed-by: Jiri Slaby Link: https://patch.msgid.link/20251223034836.2625547-1-jackzxcui1989@163.com Signed-off-by: Greg Kroah-Hartman --- drivers/tty/pty.c | 14 ++++++++++---- drivers/tty/tty_buffer.c | 8 ++++---- drivers/tty/tty_io.c | 21 ++++++++++++++++++++- drivers/tty/tty_port.c | 23 +++++++++++++++++++++++ include/linux/tty_buffer.h | 1 + include/linux/tty_driver.h | 7 +++++++ include/linux/tty_port.h | 13 +++++++++++++ 7 files changed, 78 insertions(+), 9 deletions(-) diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 6120d827a797..1f17575f8fe0 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -403,6 +403,8 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty, o_tty->link = tty; tty_port_init(ports[0]); tty_port_init(ports[1]); + tty_port_link_wq(ports[0], system_dfl_wq); + tty_port_link_wq(ports[1], system_dfl_wq); tty_buffer_set_limit(ports[0], 8192); tty_buffer_set_limit(ports[1], 8192); o_tty->port = ports[0]; @@ -532,14 +534,16 @@ static void __init legacy_pty_init(void) pty_driver = tty_alloc_driver(legacy_count, TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | - TTY_DRIVER_DYNAMIC_ALLOC); + TTY_DRIVER_DYNAMIC_ALLOC | + TTY_DRIVER_CUSTOM_WORKQUEUE); if (IS_ERR(pty_driver)) panic("Couldn't allocate pty driver"); pty_slave_driver = tty_alloc_driver(legacy_count, TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | - TTY_DRIVER_DYNAMIC_ALLOC); + TTY_DRIVER_DYNAMIC_ALLOC | + TTY_DRIVER_CUSTOM_WORKQUEUE); if (IS_ERR(pty_slave_driver)) panic("Couldn't allocate pty slave driver"); @@ -849,7 +853,8 @@ static void __init unix98_pty_init(void) TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM | - TTY_DRIVER_DYNAMIC_ALLOC); + TTY_DRIVER_DYNAMIC_ALLOC | + TTY_DRIVER_CUSTOM_WORKQUEUE); if (IS_ERR(ptm_driver)) panic("Couldn't allocate Unix98 ptm driver"); pts_driver = tty_alloc_driver(NR_UNIX98_PTY_MAX, @@ -857,7 +862,8 @@ static void __init unix98_pty_init(void) TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM | - TTY_DRIVER_DYNAMIC_ALLOC); + TTY_DRIVER_DYNAMIC_ALLOC | + TTY_DRIVER_CUSTOM_WORKQUEUE); if (IS_ERR(pts_driver)) panic("Couldn't allocate Unix98 pts driver"); diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 1a5673acd9b1..86e1e7178e90 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -76,7 +76,7 @@ void tty_buffer_unlock_exclusive(struct tty_port *port) mutex_unlock(&buf->lock); if (restart) - queue_work(system_dfl_wq, &buf->work); + queue_work(buf->flip_wq, &buf->work); } EXPORT_SYMBOL_GPL(tty_buffer_unlock_exclusive); @@ -530,7 +530,7 @@ void tty_flip_buffer_push(struct tty_port *port) struct tty_bufhead *buf = &port->buf; tty_flip_buffer_commit(buf->tail); - queue_work(system_dfl_wq, &buf->work); + queue_work(buf->flip_wq, &buf->work); } EXPORT_SYMBOL(tty_flip_buffer_push); @@ -560,7 +560,7 @@ int tty_insert_flip_string_and_push_buffer(struct tty_port *port, tty_flip_buffer_commit(buf->tail); spin_unlock_irqrestore(&port->lock, flags); - queue_work(system_dfl_wq, &buf->work); + queue_work(buf->flip_wq, &buf->work); return size; } @@ -613,7 +613,7 @@ void tty_buffer_set_lock_subclass(struct tty_port *port) bool tty_buffer_restart_work(struct tty_port *port) { - return queue_work(system_dfl_wq, &port->buf.work); + return queue_work(port->buf.flip_wq, &port->buf.work); } bool tty_buffer_cancel_work(struct tty_port *port) diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index e2d92cf70eb7..d64fb08baa17 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -3446,10 +3446,23 @@ int tty_register_driver(struct tty_driver *driver) if (error < 0) goto err; + if (!(driver->flags & TTY_DRIVER_CUSTOM_WORKQUEUE)) { + driver->flip_wq = alloc_workqueue("%s-flip-wq", WQ_UNBOUND | WQ_SYSFS, + 0, driver->name); + if (!driver->flip_wq) { + error = -ENOMEM; + goto err_unreg_char; + } + for (i = 0; i < driver->num; i++) { + if (driver->ports[i]) + tty_port_link_driver_wq(driver->ports[i], driver); + } + } + if (driver->flags & TTY_DRIVER_DYNAMIC_ALLOC) { error = tty_cdev_add(driver, dev, 0, driver->num); if (error) - goto err_unreg_char; + goto err_destroy_wq; } scoped_guard(mutex, &tty_mutex) @@ -3475,6 +3488,10 @@ err_unreg_devs: scoped_guard(mutex, &tty_mutex) list_del(&driver->tty_drivers); +err_destroy_wq: + if (!(driver->flags & TTY_DRIVER_CUSTOM_WORKQUEUE)) + destroy_workqueue(driver->flip_wq); + err_unreg_char: unregister_chrdev_region(dev, driver->num); err: @@ -3494,6 +3511,8 @@ void tty_unregister_driver(struct tty_driver *driver) driver->num); scoped_guard(mutex, &tty_mutex) list_del(&driver->tty_drivers); + if (!(driver->flags & TTY_DRIVER_CUSTOM_WORKQUEUE)) + destroy_workqueue(driver->flip_wq); } EXPORT_SYMBOL(tty_unregister_driver); diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index fe67c5cb0a3f..611f878149f8 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -99,6 +99,26 @@ void tty_port_init(struct tty_port *port) } EXPORT_SYMBOL(tty_port_init); +/** + * tty_port_link_wq - link tty_port and flip workqueue + * @port: tty_port of the device + * @flip_wq: workqueue to queue flip buffer work on + * + * When %TTY_DRIVER_CUSTOM_WORKQUEUE is used, every tty_port shall be linked to + * a workqueue manually by this function, otherwise tty_flip_buffer_push() will + * see %NULL flip_wq pointer on queue_work. + * When %TTY_DRIVER_CUSTOM_WORKQUEUE is NOT used, the function can be used to + * link a certain port to a specific workqueue, instead of using the workqueue + * allocated in tty_register_driver(). + * + * Note that TTY port API will NOT destroy the workqueue. + */ +void tty_port_link_wq(struct tty_port *port, struct workqueue_struct *flip_wq) +{ + port->buf.flip_wq = flip_wq; +} +EXPORT_SYMBOL_GPL(tty_port_link_wq); + /** * tty_port_link_device - link tty and tty_port * @port: tty_port of the device @@ -157,6 +177,7 @@ struct device *tty_port_register_device_attr(struct tty_port *port, const struct attribute_group **attr_grp) { tty_port_link_device(port, driver, index); + tty_port_link_driver_wq(port, driver); return tty_register_device_attr(driver, index, device, drvdata, attr_grp); } @@ -183,6 +204,7 @@ struct device *tty_port_register_device_attr_serdev(struct tty_port *port, struct device *dev; tty_port_link_device(port, driver, index); + tty_port_link_driver_wq(port, driver); dev = serdev_tty_port_register(port, host, parent, driver, index); if (PTR_ERR(dev) != -ENODEV) { @@ -703,6 +725,7 @@ int tty_port_install(struct tty_port *port, struct tty_driver *driver, struct tty_struct *tty) { tty->port = port; + tty_port_link_driver_wq(port, driver); return tty_standard_install(driver, tty); } EXPORT_SYMBOL_GPL(tty_port_install); diff --git a/include/linux/tty_buffer.h b/include/linux/tty_buffer.h index 31125e3be3c5..48adcb0e8ff3 100644 --- a/include/linux/tty_buffer.h +++ b/include/linux/tty_buffer.h @@ -34,6 +34,7 @@ static inline u8 *flag_buf_ptr(struct tty_buffer *b, unsigned int ofs) struct tty_bufhead { struct tty_buffer *head; /* Queue head */ + struct workqueue_struct *flip_wq; struct work_struct work; struct mutex lock; atomic_t priority; diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index 188ee9b768eb..9c65854f7d94 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h @@ -69,6 +69,10 @@ struct serial_struct; * Do not create numbered ``/dev`` nodes. For example, create * ``/dev/ttyprintk`` and not ``/dev/ttyprintk0``. Applicable only when a * driver for a single tty device is being allocated. + * + * @TTY_DRIVER_CUSTOM_WORKQUEUE: + * Do not create workqueue when tty_register_driver(). When set, flip + * buffer workqueue shall be set by tty_port_link_wq() for every port. */ enum tty_driver_flag { TTY_DRIVER_INSTALLED = BIT(0), @@ -79,6 +83,7 @@ enum tty_driver_flag { TTY_DRIVER_HARDWARE_BREAK = BIT(5), TTY_DRIVER_DYNAMIC_ALLOC = BIT(6), TTY_DRIVER_UNNUMBERED_NODE = BIT(7), + TTY_DRIVER_CUSTOM_WORKQUEUE = BIT(8), }; enum tty_driver_type { @@ -506,6 +511,7 @@ struct tty_operations { * @flags: tty driver flags (%TTY_DRIVER_) * @proc_entry: proc fs entry, used internally * @other: driver of the linked tty; only used for the PTY driver + * @flip_wq: workqueue to queue flip buffer work on * @ttys: array of active &struct tty_struct, set by tty_standard_install() * @ports: array of &struct tty_port; can be set during initialization by * tty_port_link_device() and similar @@ -539,6 +545,7 @@ struct tty_driver { unsigned long flags; struct proc_dir_entry *proc_entry; struct tty_driver *other; + struct workqueue_struct *flip_wq; /* * Pointer to the tty data structures diff --git a/include/linux/tty_port.h b/include/linux/tty_port.h index 660c254f1efe..c1b87f3c5603 100644 --- a/include/linux/tty_port.h +++ b/include/linux/tty_port.h @@ -138,6 +138,7 @@ struct tty_port { kernel */ void tty_port_init(struct tty_port *port); +void tty_port_link_wq(struct tty_port *port, struct workqueue_struct *flip_wq); void tty_port_link_device(struct tty_port *port, struct tty_driver *driver, unsigned index); struct device *tty_port_register_device(struct tty_port *port, @@ -165,6 +166,18 @@ static inline struct tty_port *tty_port_get(struct tty_port *port) return NULL; } +/* + * Never overwrite the workqueue set by tty_port_link_wq(). + * No effect when %TTY_DRIVER_CUSTOM_WORKQUEUE is set, as driver->flip_wq is + * %NULL. + */ +static inline void tty_port_link_driver_wq(struct tty_port *port, + struct tty_driver *driver) +{ + if (!port->buf.flip_wq) + port->buf.flip_wq = driver->flip_wq; +} + /* If the cts flow control is enabled, return true. */ static inline bool tty_port_cts_enabled(const struct tty_port *port) { From 0a15f43b92ddaa2fdb476891a12ac2e207c7fcd2 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 27 Jan 2026 13:58:21 +0100 Subject: [PATCH 49/49] Revert "tty: tty_port: add workqueue to flip TTY buffer" This reverts commit d000422a46aad32217cf1be747eb61d641baae2f. It is reported by many to cause boot failures, so must be reverted. Cc: Xin Zhao Cc: Jiri Slaby Link: https://lore.kernel.org/r/d1942304-ee30-478d-90fb-279519f3ae81@samsung.com Reported-by: Marek Szyprowski Reported-by: Tommaso Merciai Reported-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/tty/pty.c | 14 ++++---------- drivers/tty/tty_buffer.c | 8 ++++---- drivers/tty/tty_io.c | 21 +-------------------- drivers/tty/tty_port.c | 23 ----------------------- include/linux/tty_buffer.h | 1 - include/linux/tty_driver.h | 7 ------- include/linux/tty_port.h | 13 ------------- 7 files changed, 9 insertions(+), 78 deletions(-) diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 1f17575f8fe0..6120d827a797 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -403,8 +403,6 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty, o_tty->link = tty; tty_port_init(ports[0]); tty_port_init(ports[1]); - tty_port_link_wq(ports[0], system_dfl_wq); - tty_port_link_wq(ports[1], system_dfl_wq); tty_buffer_set_limit(ports[0], 8192); tty_buffer_set_limit(ports[1], 8192); o_tty->port = ports[0]; @@ -534,16 +532,14 @@ static void __init legacy_pty_init(void) pty_driver = tty_alloc_driver(legacy_count, TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | - TTY_DRIVER_DYNAMIC_ALLOC | - TTY_DRIVER_CUSTOM_WORKQUEUE); + TTY_DRIVER_DYNAMIC_ALLOC); if (IS_ERR(pty_driver)) panic("Couldn't allocate pty driver"); pty_slave_driver = tty_alloc_driver(legacy_count, TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | - TTY_DRIVER_DYNAMIC_ALLOC | - TTY_DRIVER_CUSTOM_WORKQUEUE); + TTY_DRIVER_DYNAMIC_ALLOC); if (IS_ERR(pty_slave_driver)) panic("Couldn't allocate pty slave driver"); @@ -853,8 +849,7 @@ static void __init unix98_pty_init(void) TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM | - TTY_DRIVER_DYNAMIC_ALLOC | - TTY_DRIVER_CUSTOM_WORKQUEUE); + TTY_DRIVER_DYNAMIC_ALLOC); if (IS_ERR(ptm_driver)) panic("Couldn't allocate Unix98 ptm driver"); pts_driver = tty_alloc_driver(NR_UNIX98_PTY_MAX, @@ -862,8 +857,7 @@ static void __init unix98_pty_init(void) TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV | TTY_DRIVER_DEVPTS_MEM | - TTY_DRIVER_DYNAMIC_ALLOC | - TTY_DRIVER_CUSTOM_WORKQUEUE); + TTY_DRIVER_DYNAMIC_ALLOC); if (IS_ERR(pts_driver)) panic("Couldn't allocate Unix98 pts driver"); diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 86e1e7178e90..1a5673acd9b1 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -76,7 +76,7 @@ void tty_buffer_unlock_exclusive(struct tty_port *port) mutex_unlock(&buf->lock); if (restart) - queue_work(buf->flip_wq, &buf->work); + queue_work(system_dfl_wq, &buf->work); } EXPORT_SYMBOL_GPL(tty_buffer_unlock_exclusive); @@ -530,7 +530,7 @@ void tty_flip_buffer_push(struct tty_port *port) struct tty_bufhead *buf = &port->buf; tty_flip_buffer_commit(buf->tail); - queue_work(buf->flip_wq, &buf->work); + queue_work(system_dfl_wq, &buf->work); } EXPORT_SYMBOL(tty_flip_buffer_push); @@ -560,7 +560,7 @@ int tty_insert_flip_string_and_push_buffer(struct tty_port *port, tty_flip_buffer_commit(buf->tail); spin_unlock_irqrestore(&port->lock, flags); - queue_work(buf->flip_wq, &buf->work); + queue_work(system_dfl_wq, &buf->work); return size; } @@ -613,7 +613,7 @@ void tty_buffer_set_lock_subclass(struct tty_port *port) bool tty_buffer_restart_work(struct tty_port *port) { - return queue_work(port->buf.flip_wq, &port->buf.work); + return queue_work(system_dfl_wq, &port->buf.work); } bool tty_buffer_cancel_work(struct tty_port *port) diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index d64fb08baa17..e2d92cf70eb7 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -3446,23 +3446,10 @@ int tty_register_driver(struct tty_driver *driver) if (error < 0) goto err; - if (!(driver->flags & TTY_DRIVER_CUSTOM_WORKQUEUE)) { - driver->flip_wq = alloc_workqueue("%s-flip-wq", WQ_UNBOUND | WQ_SYSFS, - 0, driver->name); - if (!driver->flip_wq) { - error = -ENOMEM; - goto err_unreg_char; - } - for (i = 0; i < driver->num; i++) { - if (driver->ports[i]) - tty_port_link_driver_wq(driver->ports[i], driver); - } - } - if (driver->flags & TTY_DRIVER_DYNAMIC_ALLOC) { error = tty_cdev_add(driver, dev, 0, driver->num); if (error) - goto err_destroy_wq; + goto err_unreg_char; } scoped_guard(mutex, &tty_mutex) @@ -3488,10 +3475,6 @@ err_unreg_devs: scoped_guard(mutex, &tty_mutex) list_del(&driver->tty_drivers); -err_destroy_wq: - if (!(driver->flags & TTY_DRIVER_CUSTOM_WORKQUEUE)) - destroy_workqueue(driver->flip_wq); - err_unreg_char: unregister_chrdev_region(dev, driver->num); err: @@ -3511,8 +3494,6 @@ void tty_unregister_driver(struct tty_driver *driver) driver->num); scoped_guard(mutex, &tty_mutex) list_del(&driver->tty_drivers); - if (!(driver->flags & TTY_DRIVER_CUSTOM_WORKQUEUE)) - destroy_workqueue(driver->flip_wq); } EXPORT_SYMBOL(tty_unregister_driver); diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index 611f878149f8..fe67c5cb0a3f 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -99,26 +99,6 @@ void tty_port_init(struct tty_port *port) } EXPORT_SYMBOL(tty_port_init); -/** - * tty_port_link_wq - link tty_port and flip workqueue - * @port: tty_port of the device - * @flip_wq: workqueue to queue flip buffer work on - * - * When %TTY_DRIVER_CUSTOM_WORKQUEUE is used, every tty_port shall be linked to - * a workqueue manually by this function, otherwise tty_flip_buffer_push() will - * see %NULL flip_wq pointer on queue_work. - * When %TTY_DRIVER_CUSTOM_WORKQUEUE is NOT used, the function can be used to - * link a certain port to a specific workqueue, instead of using the workqueue - * allocated in tty_register_driver(). - * - * Note that TTY port API will NOT destroy the workqueue. - */ -void tty_port_link_wq(struct tty_port *port, struct workqueue_struct *flip_wq) -{ - port->buf.flip_wq = flip_wq; -} -EXPORT_SYMBOL_GPL(tty_port_link_wq); - /** * tty_port_link_device - link tty and tty_port * @port: tty_port of the device @@ -177,7 +157,6 @@ struct device *tty_port_register_device_attr(struct tty_port *port, const struct attribute_group **attr_grp) { tty_port_link_device(port, driver, index); - tty_port_link_driver_wq(port, driver); return tty_register_device_attr(driver, index, device, drvdata, attr_grp); } @@ -204,7 +183,6 @@ struct device *tty_port_register_device_attr_serdev(struct tty_port *port, struct device *dev; tty_port_link_device(port, driver, index); - tty_port_link_driver_wq(port, driver); dev = serdev_tty_port_register(port, host, parent, driver, index); if (PTR_ERR(dev) != -ENODEV) { @@ -725,7 +703,6 @@ int tty_port_install(struct tty_port *port, struct tty_driver *driver, struct tty_struct *tty) { tty->port = port; - tty_port_link_driver_wq(port, driver); return tty_standard_install(driver, tty); } EXPORT_SYMBOL_GPL(tty_port_install); diff --git a/include/linux/tty_buffer.h b/include/linux/tty_buffer.h index 48adcb0e8ff3..31125e3be3c5 100644 --- a/include/linux/tty_buffer.h +++ b/include/linux/tty_buffer.h @@ -34,7 +34,6 @@ static inline u8 *flag_buf_ptr(struct tty_buffer *b, unsigned int ofs) struct tty_bufhead { struct tty_buffer *head; /* Queue head */ - struct workqueue_struct *flip_wq; struct work_struct work; struct mutex lock; atomic_t priority; diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index 9c65854f7d94..188ee9b768eb 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h @@ -69,10 +69,6 @@ struct serial_struct; * Do not create numbered ``/dev`` nodes. For example, create * ``/dev/ttyprintk`` and not ``/dev/ttyprintk0``. Applicable only when a * driver for a single tty device is being allocated. - * - * @TTY_DRIVER_CUSTOM_WORKQUEUE: - * Do not create workqueue when tty_register_driver(). When set, flip - * buffer workqueue shall be set by tty_port_link_wq() for every port. */ enum tty_driver_flag { TTY_DRIVER_INSTALLED = BIT(0), @@ -83,7 +79,6 @@ enum tty_driver_flag { TTY_DRIVER_HARDWARE_BREAK = BIT(5), TTY_DRIVER_DYNAMIC_ALLOC = BIT(6), TTY_DRIVER_UNNUMBERED_NODE = BIT(7), - TTY_DRIVER_CUSTOM_WORKQUEUE = BIT(8), }; enum tty_driver_type { @@ -511,7 +506,6 @@ struct tty_operations { * @flags: tty driver flags (%TTY_DRIVER_) * @proc_entry: proc fs entry, used internally * @other: driver of the linked tty; only used for the PTY driver - * @flip_wq: workqueue to queue flip buffer work on * @ttys: array of active &struct tty_struct, set by tty_standard_install() * @ports: array of &struct tty_port; can be set during initialization by * tty_port_link_device() and similar @@ -545,7 +539,6 @@ struct tty_driver { unsigned long flags; struct proc_dir_entry *proc_entry; struct tty_driver *other; - struct workqueue_struct *flip_wq; /* * Pointer to the tty data structures diff --git a/include/linux/tty_port.h b/include/linux/tty_port.h index c1b87f3c5603..660c254f1efe 100644 --- a/include/linux/tty_port.h +++ b/include/linux/tty_port.h @@ -138,7 +138,6 @@ struct tty_port { kernel */ void tty_port_init(struct tty_port *port); -void tty_port_link_wq(struct tty_port *port, struct workqueue_struct *flip_wq); void tty_port_link_device(struct tty_port *port, struct tty_driver *driver, unsigned index); struct device *tty_port_register_device(struct tty_port *port, @@ -166,18 +165,6 @@ static inline struct tty_port *tty_port_get(struct tty_port *port) return NULL; } -/* - * Never overwrite the workqueue set by tty_port_link_wq(). - * No effect when %TTY_DRIVER_CUSTOM_WORKQUEUE is set, as driver->flip_wq is - * %NULL. - */ -static inline void tty_port_link_driver_wq(struct tty_port *port, - struct tty_driver *driver) -{ - if (!port->buf.flip_wq) - port->buf.flip_wq = driver->flip_wq; -} - /* If the cts flow control is enabled, return true. */ static inline bool tty_port_cts_enabled(const struct tty_port *port) {