devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v5 0/3] uart: Introduce uart driver for the Loongson family
@ 2025-09-24  6:29 Binbin Zhou
  2025-09-24  6:29 ` [PATCH v5 1/3] dt-bindings: serial: 8250: Add Loongson uart compatible Binbin Zhou
                   ` (2 more replies)
  0 siblings, 3 replies; 16+ messages in thread
From: Binbin Zhou @ 2025-09-24  6:29 UTC (permalink / raw)
  To: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Greg Kroah-Hartman, Jiri Slaby, Haowei Zheng
  Cc: Huacai Chen, Xuerui Wang, loongarch, devicetree, linux-serial,
	Binbin Zhou

Hi all:

For various reasons, I will be taking over from Haowei and continuing to
push forward with this patch set. Thanks to Haowei for his efforts so
far.

This patchset introduce a generic UART framework driver for Loongson family.
It can be found on Loongson3 series cpus, Loongson-2K series cpus and Loongson 
LS7A bridge chips.

Thanks.

------
V5:
Patch-1:
 - Since the Loongson UART is NS8250A-compatible, simply add ls2k* compatible
   to 8250.yaml.

Sorry for the DTS{i} check error that appeared in the V3 patchset. I've fixed
this issue. Thanks to Krzysztof.

Link to V4:
https://lore.kernel.org/all/cover.1757318368.git.zhoubinbin@loongson.cn/

V4:
Patch-1:
  - Rename binding name from loongson,uart.yaml to
    loongson,ls2k0500-uart.yaml;
  - Drop ls7a compatible;
  - According to the manual, ls3a and ls2k uart are the same, so merge their
    compatible.

Patch-2:
  - Format code;
  - Add the LOONGSON_UART_DLF macro definition to avoid magic numbers;
  - Simplify the code, merge flags and quirks, and remove struct
    loongson_uart_config;
  - Use DEFINE_SIMPLE_DEV_PM_OPS;
  - Drop loongson,ls7a-uart compatible.

Patch-3:
  - Add ls2k* compatible string, and ns16550a as the fallback
    compatible.

Link to V3:
https://lore.kernel.org/all/20240826024705.55474-1-zhenghaowei@loongson.cn/

Binbin Zhou (3):
  dt-bindings: serial: 8250: Add Loongson uart compatible
  serial: 8250: Add Loongson uart driver support
  LoongArch: dts: Add uart new compatible string

 .../devicetree/bindings/serial/8250.yaml      |  14 ++
 arch/loongarch/boot/dts/loongson-2k0500.dtsi  |   2 +-
 arch/loongarch/boot/dts/loongson-2k1000.dtsi  |   2 +-
 arch/loongarch/boot/dts/loongson-2k2000.dtsi  |   2 +-
 drivers/tty/serial/8250/8250_loongson.c       | 202 ++++++++++++++++++
 drivers/tty/serial/8250/8250_port.c           |   8 +
 drivers/tty/serial/8250/Kconfig               |  10 +
 drivers/tty/serial/8250/Makefile              |   1 +
 include/uapi/linux/serial_core.h              |   1 +
 9 files changed, 239 insertions(+), 3 deletions(-)
 create mode 100644 drivers/tty/serial/8250/8250_loongson.c


base-commit: f4abab350840d58d69814c6993736f03ac27df83
-- 
2.47.3


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH v5 1/3] dt-bindings: serial: 8250: Add Loongson uart compatible
  2025-09-24  6:29 [PATCH v5 0/3] uart: Introduce uart driver for the Loongson family Binbin Zhou
@ 2025-09-24  6:29 ` Binbin Zhou
  2025-09-24 19:19   ` Conor Dooley
  2025-09-24  6:29 ` [PATCH v5 2/3] serial: 8250: Add Loongson uart driver support Binbin Zhou
  2025-09-24  6:29 ` [PATCH v5 3/3] LoongArch: dts: Add uart new compatible string Binbin Zhou
  2 siblings, 1 reply; 16+ messages in thread
From: Binbin Zhou @ 2025-09-24  6:29 UTC (permalink / raw)
  To: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Greg Kroah-Hartman, Jiri Slaby, Haowei Zheng
  Cc: Huacai Chen, Xuerui Wang, loongarch, devicetree, linux-serial,
	Binbin Zhou

The Loongson family have a mostly NS16550A-compatible UART and
High-Speed UART hardware with the exception of custom frequency divider
latch settings register.

Co-developed-by: Haowei Zheng <zhenghaowei@loongson.cn>
Signed-off-by: Haowei Zheng <zhenghaowei@loongson.cn>
Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
---
 Documentation/devicetree/bindings/serial/8250.yaml | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/Documentation/devicetree/bindings/serial/8250.yaml b/Documentation/devicetree/bindings/serial/8250.yaml
index b243afa69a1a..167ddcbd8800 100644
--- a/Documentation/devicetree/bindings/serial/8250.yaml
+++ b/Documentation/devicetree/bindings/serial/8250.yaml
@@ -125,6 +125,8 @@ properties:
               - nxp,lpc1850-uart
               - opencores,uart16550-rtlsvn105
               - ti,da830-uart
+              - loongson,ls2k0500-uart
+              - loongson,ls2k1500-uart
           - const: ns16550a
       - items:
           - enum:
@@ -169,6 +171,18 @@ properties:
               - nvidia,tegra194-uart
               - nvidia,tegra234-uart
           - const: nvidia,tegra20-uart
+      - items:
+          - enum:
+              - loongson,ls2k1000-uart
+          - const: loongson,ls2k0500-uart
+          - const: ns16550a
+      - items:
+          - enum:
+              - loongson,ls3a5000-uart
+              - loongson,ls3a6000-uart
+              - loongson,ls2k2000-uart
+          - const: loongson,ls2k1500-uart
+          - const: ns16550a
 
   reg:
     maxItems: 1
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v5 2/3] serial: 8250: Add Loongson uart driver support
  2025-09-24  6:29 [PATCH v5 0/3] uart: Introduce uart driver for the Loongson family Binbin Zhou
  2025-09-24  6:29 ` [PATCH v5 1/3] dt-bindings: serial: 8250: Add Loongson uart compatible Binbin Zhou
@ 2025-09-24  6:29 ` Binbin Zhou
  2025-09-24 10:22   ` Greg Kroah-Hartman
                     ` (2 more replies)
  2025-09-24  6:29 ` [PATCH v5 3/3] LoongArch: dts: Add uart new compatible string Binbin Zhou
  2 siblings, 3 replies; 16+ messages in thread
From: Binbin Zhou @ 2025-09-24  6:29 UTC (permalink / raw)
  To: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Greg Kroah-Hartman, Jiri Slaby, Haowei Zheng
  Cc: Huacai Chen, Xuerui Wang, loongarch, devicetree, linux-serial,
	Binbin Zhou

Add the driver for on-chip UART used on Loongson family chips.

The hardware is similar to 8250, but there are the following
differences:
 - Some chips (such as Loongson-2K2000) have added a fractional division
   register to obtain the required baud rate accurately, so the
   {get,set}_divisor callback is overridden.
 - Due to hardware defects, quirk handling is required for
   UART_MCR/UART_MSR.

Co-developed-by: Haowei Zheng <zhenghaowei@loongson.cn>
Signed-off-by: Haowei Zheng <zhenghaowei@loongson.cn>
Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
---
 drivers/tty/serial/8250/8250_loongson.c | 202 ++++++++++++++++++++++++
 drivers/tty/serial/8250/8250_port.c     |   8 +
 drivers/tty/serial/8250/Kconfig         |  10 ++
 drivers/tty/serial/8250/Makefile        |   1 +
 include/uapi/linux/serial_core.h        |   1 +
 5 files changed, 222 insertions(+)
 create mode 100644 drivers/tty/serial/8250/8250_loongson.c

diff --git a/drivers/tty/serial/8250/8250_loongson.c b/drivers/tty/serial/8250/8250_loongson.c
new file mode 100644
index 000000000000..a114b4e6d5c3
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_loongson.c
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Serial Port driver for Loongson family chips
+ *
+ * Copyright (C) 2020-2025 Loongson Technology Corporation Limited
+ */
+
+#include <linux/bitfield.h>
+#include <linux/module.h>
+#include <linux/property.h>
+#include <linux/mod_devicetable.h>
+#include <linux/reset.h>
+
+#include "8250.h"
+
+/* Divisor Latch Fraction Register */
+#define LOONGSON_UART_DLF		0x2
+
+/* Flags */
+#define LOONGSON_UART_HAS_FRAC		BIT(0)
+#define LOONGSON_UART_QUIRK_MCR		BIT(1)
+#define LOONGSON_UART_QUIRK_MSR		BIT(2)
+
+#define LS2K0500_UART_FLAG	(LOONGSON_UART_QUIRK_MCR | LOONGSON_UART_QUIRK_MSR)
+#define LS2K1500_UART_FLAG	(LOONGSON_UART_HAS_FRAC | LOONGSON_UART_QUIRK_MCR)
+
+struct loongson_uart_data {
+	int line;
+	int mcr_invert;
+	int msr_invert;
+	struct reset_control *rst;
+};
+
+static unsigned int serial_fixup(struct uart_port *p, unsigned int offset, unsigned int val)
+{
+	struct loongson_uart_data *ddata = p->private_data;
+
+	if (offset == UART_MCR)
+		val ^= ddata->mcr_invert;
+
+	if (offset == UART_MSR)
+		val ^= ddata->msr_invert;
+
+	return val;
+}
+
+static u32 loongson_serial_in(struct uart_port *p, unsigned int offset)
+{
+	unsigned int val;
+
+	val = readb(p->membase + (offset << p->regshift));
+
+	return serial_fixup(p, offset, val);
+}
+
+static void loongson_serial_out(struct uart_port *p, unsigned int offset, unsigned int value)
+{
+	offset <<= p->regshift;
+	writeb(serial_fixup(p, offset, value), p->membase + offset);
+}
+
+static unsigned int loongson_frac_get_divisor(struct uart_port *port, unsigned int baud,
+					      unsigned int *frac)
+{
+	unsigned int quot;
+
+	quot = DIV_ROUND_CLOSEST((port->uartclk << 4), baud);
+	*frac = FIELD_GET(GENMASK(7, 0), quot);
+
+	return FIELD_GET(GENMASK(15, 8), quot);
+}
+
+static void loongson_frac_set_divisor(struct uart_port *port, unsigned int baud,
+				      unsigned int quot, unsigned int quot_frac)
+{
+	struct uart_8250_port *up = up_to_u8250p(port);
+
+	serial_port_out(port, UART_LCR, up->lcr | UART_LCR_DLAB);
+	serial_dl_write(up, quot);
+	serial_port_out(port, LOONGSON_UART_DLF, quot_frac);
+}
+
+static int loongson_uart_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct uart_8250_port uart = {};
+	struct loongson_uart_data *ddata;
+	struct resource *res;
+	unsigned int flags;
+	int ret;
+
+	ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
+	if (!ddata)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	uart.port.irq = platform_get_irq(pdev, 0);
+	if (uart.port.irq < 0)
+		return -EINVAL;
+
+	device_property_read_u32(dev, "clock-frequency", &uart.port.uartclk);
+
+	spin_lock_init(&uart.port.lock);
+	uart.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_IOREMAP;
+	uart.port.iotype = UPIO_MEM;
+	uart.port.regshift = 0;
+	uart.port.dev = dev;
+	uart.port.type = PORT_LOONGSON;
+	uart.port.private_data = ddata;
+
+	uart.port.mapbase = res->start;
+	uart.port.mapsize = resource_size(res);
+	uart.port.serial_in = loongson_serial_in;
+	uart.port.serial_out = loongson_serial_out;
+
+	flags = (uintptr_t)device_get_match_data(dev);
+
+	if (flags & LOONGSON_UART_HAS_FRAC) {
+		uart.port.get_divisor = loongson_frac_get_divisor;
+		uart.port.set_divisor = loongson_frac_set_divisor;
+	}
+
+	if (flags & LOONGSON_UART_QUIRK_MCR)
+		ddata->mcr_invert |= (UART_MCR_RTS | UART_MCR_DTR);
+
+	if (flags & LOONGSON_UART_QUIRK_MSR)
+		ddata->msr_invert |= (UART_MSR_CTS | UART_MSR_DSR);
+
+	ddata->rst = devm_reset_control_get_optional_shared(dev, NULL);
+	if (IS_ERR(ddata->rst))
+		return PTR_ERR(ddata->rst);
+
+	ret = reset_control_deassert(ddata->rst);
+	if (ret)
+		return ret;
+
+	ret = serial8250_register_8250_port(&uart);
+	if (ret < 0) {
+		reset_control_assert(ddata->rst);
+		return ret;
+	}
+
+	ddata->line = ret;
+	platform_set_drvdata(pdev, ddata);
+
+	return 0;
+}
+
+static void loongson_uart_remove(struct platform_device *pdev)
+{
+	struct loongson_uart_data *ddata = platform_get_drvdata(pdev);
+
+	serial8250_unregister_port(ddata->line);
+	reset_control_assert(ddata->rst);
+}
+
+static int loongson_uart_suspend(struct device *dev)
+{
+	struct loongson_uart_data *ddata = dev_get_drvdata(dev);
+
+	serial8250_suspend_port(ddata->line);
+
+	return 0;
+}
+
+static int loongson_uart_resume(struct device *dev)
+{
+	struct loongson_uart_data *data = dev_get_drvdata(dev);
+
+	serial8250_resume_port(data->line);
+
+	return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(loongson_uart_pm_ops, loongson_uart_suspend,
+				loongson_uart_resume);
+
+static const struct of_device_id loongson_uart_of_ids[] = {
+	{ .compatible = "loongson,ls2k0500-uart", .data = (void *)LS2K0500_UART_FLAG },
+	{ .compatible = "loongson,ls2k1500-uart", .data = (void *)LS2K1500_UART_FLAG },
+	{ /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, loongson_uart_of_ids);
+
+static struct platform_driver loongson_uart_driver = {
+	.probe = loongson_uart_probe,
+	.remove = loongson_uart_remove,
+	.driver = {
+		.name = "loongson-uart",
+		.pm = pm_ptr(&loongson_uart_pm_ops),
+		.of_match_table = loongson_uart_of_ids,
+	},
+};
+
+module_platform_driver(loongson_uart_driver);
+
+MODULE_DESCRIPTION("Loongson UART driver");
+MODULE_AUTHOR("Loongson Technology Corporation Limited.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 719faf92aa8a..53efe841656f 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -310,6 +310,14 @@ static const struct serial8250_config uart_config[] = {
 		.rxtrig_bytes	= {1, 8, 16, 30},
 		.flags		= UART_CAP_FIFO | UART_CAP_AFE,
 	},
+	[PORT_LOONGSON] = {
+		.name		= "Loongson",
+		.fifo_size	= 16,
+		.tx_loadsz	= 16,
+		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+		.rxtrig_bytes   = {1, 4, 8, 14},
+		.flags		= UART_CAP_FIFO,
+	},
 };
 
 /* Uart divisor latch read */
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index f64ef0819cd4..98236b3bec10 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -468,6 +468,16 @@ config SERIAL_8250_OMAP_TTYO_FIXUP
 	  not booting kernel because the serial console remains silent in case
 	  they forgot to update the command line.
 
+config SERIAL_8250_LOONGSON
+	tristate "Loongson 8250 based serial port"
+	depends on SERIAL_8250
+	depends on LOONGARCH || COMPILE_TEST
+	help
+	  If you have a machine based on LoongArch CPU you can enable
+	  its onboard serial ports by enabling this option. The option
+	  is applicable to both devicetree and ACPI, say Y to this option.
+	  If unsure, say N.
+
 config SERIAL_8250_LPC18XX
 	tristate "NXP LPC18xx/43xx serial port support"
 	depends on SERIAL_8250 && OF && (ARCH_LPC18XX || COMPILE_TEST)
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index 513a0941c284..e318a3240789 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_SERIAL_8250_HP300)		+= 8250_hp300.o
 obj-$(CONFIG_SERIAL_8250_HUB6)		+= 8250_hub6.o
 obj-$(CONFIG_SERIAL_8250_INGENIC)	+= 8250_ingenic.o
 obj-$(CONFIG_SERIAL_8250_IOC3)		+= 8250_ioc3.o
+obj-$(CONFIG_SERIAL_8250_LOONGSON)	+= 8250_loongson.o
 obj-$(CONFIG_SERIAL_8250_LPC18XX)	+= 8250_lpc18xx.o
 obj-$(CONFIG_SERIAL_8250_LPSS)		+= 8250_lpss.o
 obj-$(CONFIG_SERIAL_8250_MEN_MCB)	+= 8250_men_mcb.o
diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
index 9c007a106330..607cf060a72a 100644
--- a/include/uapi/linux/serial_core.h
+++ b/include/uapi/linux/serial_core.h
@@ -31,6 +31,7 @@
 #define PORT_ALTR_16550_F128 28 /* Altera 16550 UART with 128 FIFOs */
 #define PORT_RT2880	29	/* Ralink RT2880 internal UART */
 #define PORT_16550A_FSL64 30	/* Freescale 16550 UART with 64 FIFOs */
+#define PORT_LOONGSON	31	/* Loongson 16550 UART */
 
 /*
  * ARM specific type numbers.  These are not currently guaranteed
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH v5 3/3] LoongArch: dts: Add uart new compatible string
  2025-09-24  6:29 [PATCH v5 0/3] uart: Introduce uart driver for the Loongson family Binbin Zhou
  2025-09-24  6:29 ` [PATCH v5 1/3] dt-bindings: serial: 8250: Add Loongson uart compatible Binbin Zhou
  2025-09-24  6:29 ` [PATCH v5 2/3] serial: 8250: Add Loongson uart driver support Binbin Zhou
@ 2025-09-24  6:29 ` Binbin Zhou
  2 siblings, 0 replies; 16+ messages in thread
From: Binbin Zhou @ 2025-09-24  6:29 UTC (permalink / raw)
  To: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Greg Kroah-Hartman, Jiri Slaby, Haowei Zheng
  Cc: Huacai Chen, Xuerui Wang, loongarch, devicetree, linux-serial,
	Binbin Zhou

Add loongson,ls2k*-uart compatible string on uarts.

Co-developed-by: Haowei Zheng <zhenghaowei@loongson.cn>
Signed-off-by: Haowei Zheng <zhenghaowei@loongson.cn>
Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
---
 arch/loongarch/boot/dts/loongson-2k0500.dtsi | 2 +-
 arch/loongarch/boot/dts/loongson-2k1000.dtsi | 2 +-
 arch/loongarch/boot/dts/loongson-2k2000.dtsi | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/loongarch/boot/dts/loongson-2k0500.dtsi b/arch/loongarch/boot/dts/loongson-2k0500.dtsi
index 588ebc3bded4..357de4ca7555 100644
--- a/arch/loongarch/boot/dts/loongson-2k0500.dtsi
+++ b/arch/loongarch/boot/dts/loongson-2k0500.dtsi
@@ -380,7 +380,7 @@ tsensor: thermal-sensor@1fe11500 {
 		};
 
 		uart0: serial@1ff40800 {
-			compatible = "ns16550a";
+			compatible = "loongson,ls2k0500-uart", "ns16550a";
 			reg = <0x0 0x1ff40800 0x0 0x10>;
 			clock-frequency = <100000000>;
 			interrupt-parent = <&eiointc>;
diff --git a/arch/loongarch/boot/dts/loongson-2k1000.dtsi b/arch/loongarch/boot/dts/loongson-2k1000.dtsi
index d8e01e2534dd..60ab425f793f 100644
--- a/arch/loongarch/boot/dts/loongson-2k1000.dtsi
+++ b/arch/loongarch/boot/dts/loongson-2k1000.dtsi
@@ -297,7 +297,7 @@ dma-controller@1fe00c40 {
 		};
 
 		uart0: serial@1fe20000 {
-			compatible = "ns16550a";
+			compatible = "loongson,ls2k1000-uart", "loongson,ls2k0500-uart", "ns16550a";
 			reg = <0x0 0x1fe20000 0x0 0x10>;
 			clock-frequency = <125000000>;
 			interrupt-parent = <&liointc0>;
diff --git a/arch/loongarch/boot/dts/loongson-2k2000.dtsi b/arch/loongarch/boot/dts/loongson-2k2000.dtsi
index 00cc485b753b..6c77b86ee06c 100644
--- a/arch/loongarch/boot/dts/loongson-2k2000.dtsi
+++ b/arch/loongarch/boot/dts/loongson-2k2000.dtsi
@@ -250,7 +250,7 @@ i2c@1fe00130 {
 		};
 
 		uart0: serial@1fe001e0 {
-			compatible = "ns16550a";
+			compatible = "loongson,ls2k2000-uart", "loongson,ls2k1500-uart", "ns16550a";
 			reg = <0x0 0x1fe001e0 0x0 0x10>;
 			clock-frequency = <100000000>;
 			interrupt-parent = <&liointc>;
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH v5 2/3] serial: 8250: Add Loongson uart driver support
  2025-09-24  6:29 ` [PATCH v5 2/3] serial: 8250: Add Loongson uart driver support Binbin Zhou
@ 2025-09-24 10:22   ` Greg Kroah-Hartman
  2025-09-28  2:48     ` Binbin Zhou
  2025-09-29  6:26   ` Jiri Slaby
  2025-09-30 11:58   ` Ilpo Järvinen
  2 siblings, 1 reply; 16+ messages in thread
From: Greg Kroah-Hartman @ 2025-09-24 10:22 UTC (permalink / raw)
  To: Binbin Zhou
  Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Jiri Slaby, Haowei Zheng, Huacai Chen, Xuerui Wang,
	loongarch, devicetree, linux-serial

On Wed, Sep 24, 2025 at 02:29:37PM +0800, Binbin Zhou wrote:
> --- a/include/uapi/linux/serial_core.h
> +++ b/include/uapi/linux/serial_core.h
> @@ -31,6 +31,7 @@
>  #define PORT_ALTR_16550_F128 28 /* Altera 16550 UART with 128 FIFOs */
>  #define PORT_RT2880	29	/* Ralink RT2880 internal UART */
>  #define PORT_16550A_FSL64 30	/* Freescale 16550 UART with 64 FIFOs */
> +#define PORT_LOONGSON	31	/* Loongson 16550 UART */

Why does userspace need to have this value exported?

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v5 1/3] dt-bindings: serial: 8250: Add Loongson uart compatible
  2025-09-24  6:29 ` [PATCH v5 1/3] dt-bindings: serial: 8250: Add Loongson uart compatible Binbin Zhou
@ 2025-09-24 19:19   ` Conor Dooley
  0 siblings, 0 replies; 16+ messages in thread
From: Conor Dooley @ 2025-09-24 19:19 UTC (permalink / raw)
  To: Binbin Zhou
  Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Greg Kroah-Hartman, Jiri Slaby, Haowei Zheng,
	Huacai Chen, Xuerui Wang, loongarch, devicetree, linux-serial

[-- Attachment #1: Type: text/plain, Size: 52 bytes --]

Acked-by: Conor Dooley <conor.dooley@microchip.com>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v5 2/3] serial: 8250: Add Loongson uart driver support
  2025-09-24 10:22   ` Greg Kroah-Hartman
@ 2025-09-28  2:48     ` Binbin Zhou
  2025-09-29  6:19       ` Jiri Slaby
  0 siblings, 1 reply; 16+ messages in thread
From: Binbin Zhou @ 2025-09-28  2:48 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Jiri Slaby, Haowei Zheng, Huacai Chen, Xuerui Wang,
	loongarch, devicetree, linux-serial

Hi Greg:

Thanks for your reply.

On Wed, Sep 24, 2025 at 6:22 PM Greg Kroah-Hartman
<gregkh@linuxfoundation.org> wrote:
>
> On Wed, Sep 24, 2025 at 02:29:37PM +0800, Binbin Zhou wrote:
> > --- a/include/uapi/linux/serial_core.h
> > +++ b/include/uapi/linux/serial_core.h
> > @@ -31,6 +31,7 @@
> >  #define PORT_ALTR_16550_F128 28 /* Altera 16550 UART with 128 FIFOs */
> >  #define PORT_RT2880  29      /* Ralink RT2880 internal UART */
> >  #define PORT_16550A_FSL64 30 /* Freescale 16550 UART with 64 FIFOs */
> > +#define PORT_LOONGSON        31      /* Loongson 16550 UART */
>
> Why does userspace need to have this value exported?

Sorry, this was a cheap mistake.
It should follow the existing latest macro definition as follows:

diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
index 9c007a106330..5221d86d592a 100644
--- a/include/uapi/linux/serial_core.h
+++ b/include/uapi/linux/serial_core.h
@@ -231,6 +231,9 @@
 /* Sunplus UART */
 #define PORT_SUNPLUS   123

+/* Loongson UART */
+#define PORT_LOONGSON  124

I'll double-check and test it again in the next version.

>
> thanks,
>
> greg k-h

--
Thanks.
Binbin

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH v5 2/3] serial: 8250: Add Loongson uart driver support
  2025-09-28  2:48     ` Binbin Zhou
@ 2025-09-29  6:19       ` Jiri Slaby
  2025-09-30  3:03         ` Binbin Zhou
  0 siblings, 1 reply; 16+ messages in thread
From: Jiri Slaby @ 2025-09-29  6:19 UTC (permalink / raw)
  To: Binbin Zhou, Greg Kroah-Hartman
  Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Haowei Zheng, Huacai Chen, Xuerui Wang, loongarch,
	devicetree, linux-serial

Hi,

On 28. 09. 25, 4:48, Binbin Zhou wrote:
> Hi Greg:
> 
> Thanks for your reply.
> 
> On Wed, Sep 24, 2025 at 6:22 PM Greg Kroah-Hartman
> <gregkh@linuxfoundation.org> wrote:
>>
>> On Wed, Sep 24, 2025 at 02:29:37PM +0800, Binbin Zhou wrote:
>>> --- a/include/uapi/linux/serial_core.h
>>> +++ b/include/uapi/linux/serial_core.h
>>> @@ -31,6 +31,7 @@
>>>   #define PORT_ALTR_16550_F128 28 /* Altera 16550 UART with 128 FIFOs */
>>>   #define PORT_RT2880  29      /* Ralink RT2880 internal UART */
>>>   #define PORT_16550A_FSL64 30 /* Freescale 16550 UART with 64 FIFOs */
>>> +#define PORT_LOONGSON        31      /* Loongson 16550 UART */
>>
>> Why does userspace need to have this value exported?
> 
> Sorry, this was a cheap mistake.
> It should follow the existing latest macro definition as follows:

That was not the point. The point was why do you need that at all?

-- 
js
suse labs

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v5 2/3] serial: 8250: Add Loongson uart driver support
  2025-09-24  6:29 ` [PATCH v5 2/3] serial: 8250: Add Loongson uart driver support Binbin Zhou
  2025-09-24 10:22   ` Greg Kroah-Hartman
@ 2025-09-29  6:26   ` Jiri Slaby
  2025-09-30  3:07     ` Binbin Zhou
  2025-09-30 12:01     ` Ilpo Järvinen
  2025-09-30 11:58   ` Ilpo Järvinen
  2 siblings, 2 replies; 16+ messages in thread
From: Jiri Slaby @ 2025-09-29  6:26 UTC (permalink / raw)
  To: Binbin Zhou, Binbin Zhou, Huacai Chen, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Greg Kroah-Hartman,
	Haowei Zheng
  Cc: Huacai Chen, Xuerui Wang, loongarch, devicetree, linux-serial

On 24. 09. 25, 8:29, Binbin Zhou wrote:
> Add the driver for on-chip UART used on Loongson family chips.
> 
> The hardware is similar to 8250, but there are the following
> differences:
>   - Some chips (such as Loongson-2K2000) have added a fractional division
>     register to obtain the required baud rate accurately, so the
>     {get,set}_divisor callback is overridden.
>   - Due to hardware defects, quirk handling is required for
>     UART_MCR/UART_MSR.

So how hard would be to implement this in 8250 using existing (or new) 
callbacks+quirks?

> --- /dev/null
> +++ b/drivers/tty/serial/8250/8250_loongson.c
> @@ -0,0 +1,202 @@
...
> +struct loongson_uart_data {
> +	int line;
> +	int mcr_invert;
> +	int msr_invert;

These two should be unsigned. They should be u8, actually.

> +	struct reset_control *rst;
> +};
> +
> +static unsigned int serial_fixup(struct uart_port *p, unsigned int offset, unsigned int val)

Both 'val' and ret type should be u8.

> +{
> +	struct loongson_uart_data *ddata = p->private_data;
> +
> +	if (offset == UART_MCR)
> +		val ^= ddata->mcr_invert;
> +
> +	if (offset == UART_MSR)
> +		val ^= ddata->msr_invert;
> +
> +	return val;
> +}
> +
> +static u32 loongson_serial_in(struct uart_port *p, unsigned int offset)
> +{
> +	unsigned int val;

u8

> +
> +	val = readb(p->membase + (offset << p->regshift));
> +
> +	return serial_fixup(p, offset, val);
> +}

thanks,
-- 
js
suse labs

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v5 2/3] serial: 8250: Add Loongson uart driver support
  2025-09-29  6:19       ` Jiri Slaby
@ 2025-09-30  3:03         ` Binbin Zhou
  2025-10-08 12:16           ` Greg Kroah-Hartman
  0 siblings, 1 reply; 16+ messages in thread
From: Binbin Zhou @ 2025-09-30  3:03 UTC (permalink / raw)
  To: Jiri Slaby
  Cc: Greg Kroah-Hartman, Binbin Zhou, Huacai Chen, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Haowei Zheng, Huacai Chen,
	Xuerui Wang, loongarch, devicetree, linux-serial

Hi Jiri:

Thanks for your reply.

On Mon, Sep 29, 2025 at 2:19 PM Jiri Slaby <jirislaby@kernel.org> wrote:
>
> Hi,
>
> On 28. 09. 25, 4:48, Binbin Zhou wrote:
> > Hi Greg:
> >
> > Thanks for your reply.
> >
> > On Wed, Sep 24, 2025 at 6:22 PM Greg Kroah-Hartman
> > <gregkh@linuxfoundation.org> wrote:
> >>
> >> On Wed, Sep 24, 2025 at 02:29:37PM +0800, Binbin Zhou wrote:
> >>> --- a/include/uapi/linux/serial_core.h
> >>> +++ b/include/uapi/linux/serial_core.h
> >>> @@ -31,6 +31,7 @@
> >>>   #define PORT_ALTR_16550_F128 28 /* Altera 16550 UART with 128 FIFOs */
> >>>   #define PORT_RT2880  29      /* Ralink RT2880 internal UART */
> >>>   #define PORT_16550A_FSL64 30 /* Freescale 16550 UART with 64 FIFOs */
> >>> +#define PORT_LOONGSON        31      /* Loongson 16550 UART */
> >>
> >> Why does userspace need to have this value exported?
> >
> > Sorry, this was a cheap mistake.
> > It should follow the existing latest macro definition as follows:
>
> That was not the point. The point was why do you need that at all?

Emm...
We attempted to define Loongson UART as a new `uart_config` entry.
Therefore, `PORT_LOONGSON` is referenced as follows:

diff --git a/drivers/tty/serial/8250/8250_port.c
b/drivers/tty/serial/8250/8250_port.c
index 719faf92aa8a..53efe841656f 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -310,6 +310,14 @@ static const struct serial8250_config uart_config[] = {
                .rxtrig_bytes   = {1, 8, 16, 30},
                .flags          = UART_CAP_FIFO | UART_CAP_AFE,
        },
+       [PORT_LOONGSON] = {
+               .name           = "Loongson",
+               .fifo_size      = 16,
+               .tx_loadsz      = 16,
+               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+               .rxtrig_bytes   = {1, 4, 8, 14},
+               .flags          = UART_CAP_FIFO,
+       },
 };

 /* Uart divisor latch read */

Additionally, `uart.port.type` will also be assigned the value `PORT_LOONGSON`.
>
> --
> js
> suse labs

-- 
Thanks.
Binbin

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH v5 2/3] serial: 8250: Add Loongson uart driver support
  2025-09-29  6:26   ` Jiri Slaby
@ 2025-09-30  3:07     ` Binbin Zhou
  2025-09-30 12:01     ` Ilpo Järvinen
  1 sibling, 0 replies; 16+ messages in thread
From: Binbin Zhou @ 2025-09-30  3:07 UTC (permalink / raw)
  To: Jiri Slaby
  Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Greg Kroah-Hartman, Haowei Zheng, Huacai Chen,
	Xuerui Wang, loongarch, devicetree, linux-serial

Hi Jiri:

Thanks for your review.

On Mon, Sep 29, 2025 at 2:27 PM Jiri Slaby <jirislaby@kernel.org> wrote:
>
> On 24. 09. 25, 8:29, Binbin Zhou wrote:
> > Add the driver for on-chip UART used on Loongson family chips.
> >
> > The hardware is similar to 8250, but there are the following
> > differences:
> >   - Some chips (such as Loongson-2K2000) have added a fractional division
> >     register to obtain the required baud rate accurately, so the
> >     {get,set}_divisor callback is overridden.
> >   - Due to hardware defects, quirk handling is required for
> >     UART_MCR/UART_MSR.
>
> So how hard would be to implement this in 8250 using existing (or new)
> callbacks+quirks?

Initially, we attempted to directly add Loongson UART support to the
existing 8250 driver. The critical section is as follows:

diff --git a/drivers/tty/serial/8250/8250_port.c
b/drivers/tty/serial/8250/8250_port.c
index aa4de6907f77..6754f496a95c 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -395,14 +404,36 @@ static void hub6_serial_out(struct uart_port *p,
int offset, int value)
        outb(value, p->iobase + 1);
 }

 static unsigned int mem_serial_in(struct uart_port *p, int offset)
 {
+       unsigned int val, offset0 = offset;
        offset = offset << p->regshift;
-       return readb(p->membase + offset);
+       val = readb(p->membase + offset);
+       if (p->type == PORT_LOONGSON)
+               val = serial_in_fixup(p, offset0, val);
+       return val;
 }

 static void mem_serial_out(struct uart_port *p, int offset, int value)
 {
+       if (p->type == PORT_LOONGSON)
+               value = serial_out_fixup(p, offset, value);
        offset = offset << p->regshift;
        writeb(value, p->membase + offset);
 }

This made the code difficult to read, so I concluded it was not a good
solution. Therefore, I separated it into a standalone driver.

>
> > --- /dev/null
> > +++ b/drivers/tty/serial/8250/8250_loongson.c
> > @@ -0,0 +1,202 @@
> ...
> > +struct loongson_uart_data {
> > +     int line;
> > +     int mcr_invert;
> > +     int msr_invert;
>
> These two should be unsigned. They should be u8, actually.

OK....
>
> > +     struct reset_control *rst;
> > +};
> > +
> > +static unsigned int serial_fixup(struct uart_port *p, unsigned int offset, unsigned int val)
>
> Both 'val' and ret type should be u8.

OK... I will check twice.
>
> > +{
> > +     struct loongson_uart_data *ddata = p->private_data;
> > +
> > +     if (offset == UART_MCR)
> > +             val ^= ddata->mcr_invert;
> > +
> > +     if (offset == UART_MSR)
> > +             val ^= ddata->msr_invert;
> > +
> > +     return val;
> > +}
> > +
> > +static u32 loongson_serial_in(struct uart_port *p, unsigned int offset)
> > +{
> > +     unsigned int val;
>
> u8
>
> > +
> > +     val = readb(p->membase + (offset << p->regshift));
> > +
> > +     return serial_fixup(p, offset, val);
> > +}
>
> thanks,
> --
> js
> suse labs


--
Thanks.
Binbin

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH v5 2/3] serial: 8250: Add Loongson uart driver support
  2025-09-24  6:29 ` [PATCH v5 2/3] serial: 8250: Add Loongson uart driver support Binbin Zhou
  2025-09-24 10:22   ` Greg Kroah-Hartman
  2025-09-29  6:26   ` Jiri Slaby
@ 2025-09-30 11:58   ` Ilpo Järvinen
  2025-10-09  2:52     ` Binbin Zhou
  2 siblings, 1 reply; 16+ messages in thread
From: Ilpo Järvinen @ 2025-09-30 11:58 UTC (permalink / raw)
  To: Binbin Zhou
  Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Greg Kroah-Hartman, Jiri Slaby, Haowei Zheng,
	Huacai Chen, Xuerui Wang, loongarch, devicetree, linux-serial

On Wed, 24 Sep 2025, Binbin Zhou wrote:

> Add the driver for on-chip UART used on Loongson family chips.
> 
> The hardware is similar to 8250, but there are the following
> differences:
>  - Some chips (such as Loongson-2K2000) have added a fractional division
>    register to obtain the required baud rate accurately, so the
>    {get,set}_divisor callback is overridden.
>  - Due to hardware defects, quirk handling is required for
>    UART_MCR/UART_MSR.
> 
> Co-developed-by: Haowei Zheng <zhenghaowei@loongson.cn>
> Signed-off-by: Haowei Zheng <zhenghaowei@loongson.cn>
> Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
> ---
>  drivers/tty/serial/8250/8250_loongson.c | 202 ++++++++++++++++++++++++
>  drivers/tty/serial/8250/8250_port.c     |   8 +
>  drivers/tty/serial/8250/Kconfig         |  10 ++
>  drivers/tty/serial/8250/Makefile        |   1 +
>  include/uapi/linux/serial_core.h        |   1 +
>  5 files changed, 222 insertions(+)
>  create mode 100644 drivers/tty/serial/8250/8250_loongson.c
> 
> diff --git a/drivers/tty/serial/8250/8250_loongson.c b/drivers/tty/serial/8250/8250_loongson.c
> new file mode 100644
> index 000000000000..a114b4e6d5c3
> --- /dev/null
> +++ b/drivers/tty/serial/8250/8250_loongson.c
> @@ -0,0 +1,202 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Serial Port driver for Loongson family chips
> + *
> + * Copyright (C) 2020-2025 Loongson Technology Corporation Limited
> + */
> +
> +#include <linux/bitfield.h>
> +#include <linux/module.h>
> +#include <linux/property.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/reset.h>
> +
> +#include "8250.h"
> +
> +/* Divisor Latch Fraction Register */
> +#define LOONGSON_UART_DLF		0x2
> +
> +/* Flags */
> +#define LOONGSON_UART_HAS_FRAC		BIT(0)
> +#define LOONGSON_UART_QUIRK_MCR		BIT(1)
> +#define LOONGSON_UART_QUIRK_MSR		BIT(2)
> +
> +#define LS2K0500_UART_FLAG	(LOONGSON_UART_QUIRK_MCR | LOONGSON_UART_QUIRK_MSR)
> +#define LS2K1500_UART_FLAG	(LOONGSON_UART_HAS_FRAC | LOONGSON_UART_QUIRK_MCR)
> +
> +struct loongson_uart_data {
> +	int line;
> +	int mcr_invert;
> +	int msr_invert;
> +	struct reset_control *rst;
> +};
> +
> +static unsigned int serial_fixup(struct uart_port *p, unsigned int offset, unsigned int val)
> +{
> +	struct loongson_uart_data *ddata = p->private_data;
> +
> +	if (offset == UART_MCR)
> +		val ^= ddata->mcr_invert;
> +
> +	if (offset == UART_MSR)
> +		val ^= ddata->msr_invert;
> +
> +	return val;
> +}
> +
> +static u32 loongson_serial_in(struct uart_port *p, unsigned int offset)
> +{
> +	unsigned int val;
> +
> +	val = readb(p->membase + (offset << p->regshift));
> +
> +	return serial_fixup(p, offset, val);
> +}
> +
> +static void loongson_serial_out(struct uart_port *p, unsigned int offset, unsigned int value)
> +{
> +	offset <<= p->regshift;
> +	writeb(serial_fixup(p, offset, value), p->membase + offset);

This would be cleaner if you do that serial_fixup() on a preceeding line.

Include for writeb()?

> +}
> +
> +static unsigned int loongson_frac_get_divisor(struct uart_port *port, unsigned int baud,
> +					      unsigned int *frac)
> +{
> +	unsigned int quot;
> +
> +	quot = DIV_ROUND_CLOSEST((port->uartclk << 4), baud);

Missing include.

> +	*frac = FIELD_GET(GENMASK(7, 0), quot);
> +
> +	return FIELD_GET(GENMASK(15, 8), quot);

Please name the fields properly with defines.

You're also missing #include for GENMASK().

> +}
> +
> +static void loongson_frac_set_divisor(struct uart_port *port, unsigned int baud,
> +				      unsigned int quot, unsigned int quot_frac)
> +{
> +	struct uart_8250_port *up = up_to_u8250p(port);
> +
> +	serial_port_out(port, UART_LCR, up->lcr | UART_LCR_DLAB);
> +	serial_dl_write(up, quot);
> +	serial_port_out(port, LOONGSON_UART_DLF, quot_frac);
> +}
> +
> +static int loongson_uart_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct uart_8250_port uart = {};
> +	struct loongson_uart_data *ddata;
> +	struct resource *res;
> +	unsigned int flags;
> +	int ret;
> +
> +	ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
> +	if (!ddata)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	if (!res)
> +		return -ENODEV;
> +
> +	uart.port.irq = platform_get_irq(pdev, 0);
> +	if (uart.port.irq < 0)
> +		return -EINVAL;
> +
> +	device_property_read_u32(dev, "clock-frequency", &uart.port.uartclk);
> +
> +	spin_lock_init(&uart.port.lock);
> +	uart.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_IOREMAP;
> +	uart.port.iotype = UPIO_MEM;
> +	uart.port.regshift = 0;
> +	uart.port.dev = dev;
> +	uart.port.type = PORT_LOONGSON;
> +	uart.port.private_data = ddata;
> +
> +	uart.port.mapbase = res->start;
> +	uart.port.mapsize = resource_size(res);
> +	uart.port.serial_in = loongson_serial_in;
> +	uart.port.serial_out = loongson_serial_out;
> +
> +	flags = (uintptr_t)device_get_match_data(dev);

Perhaps flags should be unsigned long?

> +	if (flags & LOONGSON_UART_HAS_FRAC) {
> +		uart.port.get_divisor = loongson_frac_get_divisor;
> +		uart.port.set_divisor = loongson_frac_set_divisor;
> +	}
> +
> +	if (flags & LOONGSON_UART_QUIRK_MCR)
> +		ddata->mcr_invert |= (UART_MCR_RTS | UART_MCR_DTR);
> +
> +	if (flags & LOONGSON_UART_QUIRK_MSR)
> +		ddata->msr_invert |= (UART_MSR_CTS | UART_MSR_DSR);

I think it would be better to put these invert masks directly into a 
struct which is then put into .data. LOONGSON_UART_HAS_FRAC can be bool 
in that struct.

> +	ddata->rst = devm_reset_control_get_optional_shared(dev, NULL);
> +	if (IS_ERR(ddata->rst))
> +		return PTR_ERR(ddata->rst);
> +
> +	ret = reset_control_deassert(ddata->rst);
> +	if (ret)
> +		return ret;
> +
> +	ret = serial8250_register_8250_port(&uart);
> +	if (ret < 0) {
> +		reset_control_assert(ddata->rst);
> +		return ret;
> +	}
> +
> +	ddata->line = ret;
> +	platform_set_drvdata(pdev, ddata);
> +
> +	return 0;
> +}
> +
> +static void loongson_uart_remove(struct platform_device *pdev)
> +{
> +	struct loongson_uart_data *ddata = platform_get_drvdata(pdev);
> +
> +	serial8250_unregister_port(ddata->line);
> +	reset_control_assert(ddata->rst);
> +}
> +
> +static int loongson_uart_suspend(struct device *dev)
> +{
> +	struct loongson_uart_data *ddata = dev_get_drvdata(dev);
> +
> +	serial8250_suspend_port(ddata->line);
> +
> +	return 0;
> +}
> +
> +static int loongson_uart_resume(struct device *dev)
> +{
> +	struct loongson_uart_data *data = dev_get_drvdata(dev);
> +
> +	serial8250_resume_port(data->line);
> +
> +	return 0;
> +}
> +
> +static DEFINE_SIMPLE_DEV_PM_OPS(loongson_uart_pm_ops, loongson_uart_suspend,
> +				loongson_uart_resume);

Include? Please check if you miss even more includes beyond those I've 
highlighted here.

> +static const struct of_device_id loongson_uart_of_ids[] = {
> +	{ .compatible = "loongson,ls2k0500-uart", .data = (void *)LS2K0500_UART_FLAG },
> +	{ .compatible = "loongson,ls2k1500-uart", .data = (void *)LS2K1500_UART_FLAG },
> +	{ /* sentinel */ },

Nit, no need for comma in the terminator entry.

> +};
> +MODULE_DEVICE_TABLE(of, loongson_uart_of_ids);
> +
> +static struct platform_driver loongson_uart_driver = {
> +	.probe = loongson_uart_probe,
> +	.remove = loongson_uart_remove,
> +	.driver = {
> +		.name = "loongson-uart",
> +		.pm = pm_ptr(&loongson_uart_pm_ops),
> +		.of_match_table = loongson_uart_of_ids,
> +	},
> +};
> +
> +module_platform_driver(loongson_uart_driver);
> +
> +MODULE_DESCRIPTION("Loongson UART driver");
> +MODULE_AUTHOR("Loongson Technology Corporation Limited.");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
> index 719faf92aa8a..53efe841656f 100644
> --- a/drivers/tty/serial/8250/8250_port.c
> +++ b/drivers/tty/serial/8250/8250_port.c
> @@ -310,6 +310,14 @@ static const struct serial8250_config uart_config[] = {
>  		.rxtrig_bytes	= {1, 8, 16, 30},
>  		.flags		= UART_CAP_FIFO | UART_CAP_AFE,
>  	},
> +	[PORT_LOONGSON] = {
> +		.name		= "Loongson",
> +		.fifo_size	= 16,
> +		.tx_loadsz	= 16,
> +		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
> +		.rxtrig_bytes   = {1, 4, 8, 14},
> +		.flags		= UART_CAP_FIFO,
> +	},

This is exactly identical to PORT_16550A. Just use PORT_16550A instead of 
adding a new one unnecessarily.

--
 i.

>  };
>  
>  /* Uart divisor latch read */
> diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
> index f64ef0819cd4..98236b3bec10 100644
> --- a/drivers/tty/serial/8250/Kconfig
> +++ b/drivers/tty/serial/8250/Kconfig
> @@ -468,6 +468,16 @@ config SERIAL_8250_OMAP_TTYO_FIXUP
>  	  not booting kernel because the serial console remains silent in case
>  	  they forgot to update the command line.
>  
> +config SERIAL_8250_LOONGSON
> +	tristate "Loongson 8250 based serial port"
> +	depends on SERIAL_8250
> +	depends on LOONGARCH || COMPILE_TEST
> +	help
> +	  If you have a machine based on LoongArch CPU you can enable
> +	  its onboard serial ports by enabling this option. The option
> +	  is applicable to both devicetree and ACPI, say Y to this option.
> +	  If unsure, say N.
> +
>  config SERIAL_8250_LPC18XX
>  	tristate "NXP LPC18xx/43xx serial port support"
>  	depends on SERIAL_8250 && OF && (ARCH_LPC18XX || COMPILE_TEST)
> diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
> index 513a0941c284..e318a3240789 100644
> --- a/drivers/tty/serial/8250/Makefile
> +++ b/drivers/tty/serial/8250/Makefile
> @@ -38,6 +38,7 @@ obj-$(CONFIG_SERIAL_8250_HP300)		+= 8250_hp300.o
>  obj-$(CONFIG_SERIAL_8250_HUB6)		+= 8250_hub6.o
>  obj-$(CONFIG_SERIAL_8250_INGENIC)	+= 8250_ingenic.o
>  obj-$(CONFIG_SERIAL_8250_IOC3)		+= 8250_ioc3.o
> +obj-$(CONFIG_SERIAL_8250_LOONGSON)	+= 8250_loongson.o
>  obj-$(CONFIG_SERIAL_8250_LPC18XX)	+= 8250_lpc18xx.o
>  obj-$(CONFIG_SERIAL_8250_LPSS)		+= 8250_lpss.o
>  obj-$(CONFIG_SERIAL_8250_MEN_MCB)	+= 8250_men_mcb.o
> diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
> index 9c007a106330..607cf060a72a 100644
> --- a/include/uapi/linux/serial_core.h
> +++ b/include/uapi/linux/serial_core.h
> @@ -31,6 +31,7 @@
>  #define PORT_ALTR_16550_F128 28 /* Altera 16550 UART with 128 FIFOs */
>  #define PORT_RT2880	29	/* Ralink RT2880 internal UART */
>  #define PORT_16550A_FSL64 30	/* Freescale 16550 UART with 64 FIFOs */
> +#define PORT_LOONGSON	31	/* Loongson 16550 UART */
>  
>  /*
>   * ARM specific type numbers.  These are not currently guaranteed
> 

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v5 2/3] serial: 8250: Add Loongson uart driver support
  2025-09-29  6:26   ` Jiri Slaby
  2025-09-30  3:07     ` Binbin Zhou
@ 2025-09-30 12:01     ` Ilpo Järvinen
  1 sibling, 0 replies; 16+ messages in thread
From: Ilpo Järvinen @ 2025-09-30 12:01 UTC (permalink / raw)
  To: Jiri Slaby
  Cc: Binbin Zhou, Binbin Zhou, Huacai Chen, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Greg Kroah-Hartman,
	Haowei Zheng, Huacai Chen, Xuerui Wang, loongarch, devicetree,
	linux-serial

On Mon, 29 Sep 2025, Jiri Slaby wrote:

> On 24. 09. 25, 8:29, Binbin Zhou wrote:
> > Add the driver for on-chip UART used on Loongson family chips.
> > 
> > The hardware is similar to 8250, but there are the following
> > differences:
> >   - Some chips (such as Loongson-2K2000) have added a fractional division
> >     register to obtain the required baud rate accurately, so the
> >     {get,set}_divisor callback is overridden.
> >   - Due to hardware defects, quirk handling is required for
> >     UART_MCR/UART_MSR.
> 
> So how hard would be to implement this in 8250 using existing (or new)
> callbacks+quirks?

??

Isn't it exactly what this submission did? It implements custom in/out 
functions which handle the xor for the relevant bits?

-- 
 i.

> > --- /dev/null
> > +++ b/drivers/tty/serial/8250/8250_loongson.c
> > @@ -0,0 +1,202 @@
> ...
> > +struct loongson_uart_data {
> > +	int line;
> > +	int mcr_invert;
> > +	int msr_invert;
> 
> These two should be unsigned. They should be u8, actually.
> 
> > +	struct reset_control *rst;
> > +};
> > +
> > +static unsigned int serial_fixup(struct uart_port *p, unsigned int offset,
> > unsigned int val)
> 
> Both 'val' and ret type should be u8.
> 
> > +{
> > +	struct loongson_uart_data *ddata = p->private_data;
> > +
> > +	if (offset == UART_MCR)
> > +		val ^= ddata->mcr_invert;
> > +
> > +	if (offset == UART_MSR)
> > +		val ^= ddata->msr_invert;
> > +
> > +	return val;
> > +}
> > +
> > +static u32 loongson_serial_in(struct uart_port *p, unsigned int offset)
> > +{
> > +	unsigned int val;
> 
> u8
> 
> > +
> > +	val = readb(p->membase + (offset << p->regshift));
> > +
> > +	return serial_fixup(p, offset, val);
> > +}
> 
> thanks,
> 

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v5 2/3] serial: 8250: Add Loongson uart driver support
  2025-09-30  3:03         ` Binbin Zhou
@ 2025-10-08 12:16           ` Greg Kroah-Hartman
  0 siblings, 0 replies; 16+ messages in thread
From: Greg Kroah-Hartman @ 2025-10-08 12:16 UTC (permalink / raw)
  To: Binbin Zhou
  Cc: Jiri Slaby, Binbin Zhou, Huacai Chen, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Haowei Zheng, Huacai Chen,
	Xuerui Wang, loongarch, devicetree, linux-serial

On Tue, Sep 30, 2025 at 11:03:29AM +0800, Binbin Zhou wrote:
> Hi Jiri:
> 
> Thanks for your reply.
> 
> On Mon, Sep 29, 2025 at 2:19 PM Jiri Slaby <jirislaby@kernel.org> wrote:
> >
> > Hi,
> >
> > On 28. 09. 25, 4:48, Binbin Zhou wrote:
> > > Hi Greg:
> > >
> > > Thanks for your reply.
> > >
> > > On Wed, Sep 24, 2025 at 6:22 PM Greg Kroah-Hartman
> > > <gregkh@linuxfoundation.org> wrote:
> > >>
> > >> On Wed, Sep 24, 2025 at 02:29:37PM +0800, Binbin Zhou wrote:
> > >>> --- a/include/uapi/linux/serial_core.h
> > >>> +++ b/include/uapi/linux/serial_core.h
> > >>> @@ -31,6 +31,7 @@
> > >>>   #define PORT_ALTR_16550_F128 28 /* Altera 16550 UART with 128 FIFOs */
> > >>>   #define PORT_RT2880  29      /* Ralink RT2880 internal UART */
> > >>>   #define PORT_16550A_FSL64 30 /* Freescale 16550 UART with 64 FIFOs */
> > >>> +#define PORT_LOONGSON        31      /* Loongson 16550 UART */
> > >>
> > >> Why does userspace need to have this value exported?
> > >
> > > Sorry, this was a cheap mistake.
> > > It should follow the existing latest macro definition as follows:
> >
> > That was not the point. The point was why do you need that at all?
> 
> Emm...
> We attempted to define Loongson UART as a new `uart_config` entry.
> Therefore, `PORT_LOONGSON` is referenced as follows:
> 
> diff --git a/drivers/tty/serial/8250/8250_port.c
> b/drivers/tty/serial/8250/8250_port.c
> index 719faf92aa8a..53efe841656f 100644
> --- a/drivers/tty/serial/8250/8250_port.c
> +++ b/drivers/tty/serial/8250/8250_port.c
> @@ -310,6 +310,14 @@ static const struct serial8250_config uart_config[] = {
>                 .rxtrig_bytes   = {1, 8, 16, 30},
>                 .flags          = UART_CAP_FIFO | UART_CAP_AFE,
>         },
> +       [PORT_LOONGSON] = {
> +               .name           = "Loongson",
> +               .fifo_size      = 16,
> +               .tx_loadsz      = 16,
> +               .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
> +               .rxtrig_bytes   = {1, 4, 8, 14},
> +               .flags          = UART_CAP_FIFO,
> +       },
>  };
> 
>  /* Uart divisor latch read */
> 
> Additionally, `uart.port.type` will also be assigned the value `PORT_LOONGSON`.

Yes, but that is the same exact value as PORT_PXA, which means this code
will not really work properly, right?  You can not just redefine an
already used user/kernel value.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v5 2/3] serial: 8250: Add Loongson uart driver support
  2025-09-30 11:58   ` Ilpo Järvinen
@ 2025-10-09  2:52     ` Binbin Zhou
  2025-10-09 11:46       ` Ilpo Järvinen
  0 siblings, 1 reply; 16+ messages in thread
From: Binbin Zhou @ 2025-10-09  2:52 UTC (permalink / raw)
  To: Ilpo Järvinen
  Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Greg Kroah-Hartman, Jiri Slaby, Haowei Zheng,
	Huacai Chen, Xuerui Wang, loongarch, devicetree, linux-serial

Hi Ilpo:

Sorry for the late reply and thanks for your detailed review.

On Tue, Sep 30, 2025 at 7:58 PM Ilpo Järvinen
<ilpo.jarvinen@linux.intel.com> wrote:
>
> On Wed, 24 Sep 2025, Binbin Zhou wrote:
>
> > Add the driver for on-chip UART used on Loongson family chips.
> >
> > The hardware is similar to 8250, but there are the following
> > differences:
> >  - Some chips (such as Loongson-2K2000) have added a fractional division
> >    register to obtain the required baud rate accurately, so the
> >    {get,set}_divisor callback is overridden.
> >  - Due to hardware defects, quirk handling is required for
> >    UART_MCR/UART_MSR.
> >
> > Co-developed-by: Haowei Zheng <zhenghaowei@loongson.cn>
> > Signed-off-by: Haowei Zheng <zhenghaowei@loongson.cn>
> > Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
> > ---
> >  drivers/tty/serial/8250/8250_loongson.c | 202 ++++++++++++++++++++++++
> >  drivers/tty/serial/8250/8250_port.c     |   8 +
> >  drivers/tty/serial/8250/Kconfig         |  10 ++
> >  drivers/tty/serial/8250/Makefile        |   1 +
> >  include/uapi/linux/serial_core.h        |   1 +
> >  5 files changed, 222 insertions(+)
> >  create mode 100644 drivers/tty/serial/8250/8250_loongson.c
> >
> > diff --git a/drivers/tty/serial/8250/8250_loongson.c b/drivers/tty/serial/8250/8250_loongson.c
> > new file mode 100644
> > index 000000000000..a114b4e6d5c3
> > --- /dev/null
> > +++ b/drivers/tty/serial/8250/8250_loongson.c
> > @@ -0,0 +1,202 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +/*
> > + * Serial Port driver for Loongson family chips
> > + *
> > + * Copyright (C) 2020-2025 Loongson Technology Corporation Limited
> > + */
> > +
> > +#include <linux/bitfield.h>
> > +#include <linux/module.h>
> > +#include <linux/property.h>
> > +#include <linux/mod_devicetable.h>
> > +#include <linux/reset.h>
> > +
> > +#include "8250.h"
> > +
> > +/* Divisor Latch Fraction Register */
> > +#define LOONGSON_UART_DLF            0x2
> > +
> > +/* Flags */
> > +#define LOONGSON_UART_HAS_FRAC               BIT(0)
> > +#define LOONGSON_UART_QUIRK_MCR              BIT(1)
> > +#define LOONGSON_UART_QUIRK_MSR              BIT(2)
> > +
> > +#define LS2K0500_UART_FLAG   (LOONGSON_UART_QUIRK_MCR | LOONGSON_UART_QUIRK_MSR)
> > +#define LS2K1500_UART_FLAG   (LOONGSON_UART_HAS_FRAC | LOONGSON_UART_QUIRK_MCR)
> > +
> > +struct loongson_uart_data {
> > +     int line;
> > +     int mcr_invert;
> > +     int msr_invert;
> > +     struct reset_control *rst;
> > +};
> > +
> > +static unsigned int serial_fixup(struct uart_port *p, unsigned int offset, unsigned int val)
> > +{
> > +     struct loongson_uart_data *ddata = p->private_data;
> > +
> > +     if (offset == UART_MCR)
> > +             val ^= ddata->mcr_invert;
> > +
> > +     if (offset == UART_MSR)
> > +             val ^= ddata->msr_invert;
> > +
> > +     return val;
> > +}
> > +
> > +static u32 loongson_serial_in(struct uart_port *p, unsigned int offset)
> > +{
> > +     unsigned int val;
> > +
> > +     val = readb(p->membase + (offset << p->regshift));
> > +
> > +     return serial_fixup(p, offset, val);
> > +}
> > +
> > +static void loongson_serial_out(struct uart_port *p, unsigned int offset, unsigned int value)
> > +{
> > +     offset <<= p->regshift;
> > +     writeb(serial_fixup(p, offset, value), p->membase + offset);
>
> This would be cleaner if you do that serial_fixup() on a preceeding line.

ok. I will split serial_fixup() on a preceding line.
>
> Include for writeb()?

#include <linux/io.h>
>
> > +}
> > +
> > +static unsigned int loongson_frac_get_divisor(struct uart_port *port, unsigned int baud,
> > +                                           unsigned int *frac)
> > +{
> > +     unsigned int quot;
> > +
> > +     quot = DIV_ROUND_CLOSEST((port->uartclk << 4), baud);
>
> Missing include.

#include <linux/math.h>
>
> > +     *frac = FIELD_GET(GENMASK(7, 0), quot);
> > +
> > +     return FIELD_GET(GENMASK(15, 8), quot);
>
> Please name the fields properly with defines.
>
> You're also missing #include for GENMASK().

#include <linux/bits.h>
>
> > +}
> > +
> > +static void loongson_frac_set_divisor(struct uart_port *port, unsigned int baud,
> > +                                   unsigned int quot, unsigned int quot_frac)
> > +{
> > +     struct uart_8250_port *up = up_to_u8250p(port);
> > +
> > +     serial_port_out(port, UART_LCR, up->lcr | UART_LCR_DLAB);
> > +     serial_dl_write(up, quot);
> > +     serial_port_out(port, LOONGSON_UART_DLF, quot_frac);
> > +}
> > +
> > +static int loongson_uart_probe(struct platform_device *pdev)
> > +{
> > +     struct device *dev = &pdev->dev;
> > +     struct uart_8250_port uart = {};
> > +     struct loongson_uart_data *ddata;
> > +     struct resource *res;
> > +     unsigned int flags;
> > +     int ret;
> > +
> > +     ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL);
> > +     if (!ddata)
> > +             return -ENOMEM;
> > +
> > +     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> > +     if (!res)
> > +             return -ENODEV;
> > +
> > +     uart.port.irq = platform_get_irq(pdev, 0);
> > +     if (uart.port.irq < 0)
> > +             return -EINVAL;
> > +
> > +     device_property_read_u32(dev, "clock-frequency", &uart.port.uartclk);
> > +
> > +     spin_lock_init(&uart.port.lock);
> > +     uart.port.flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_IOREMAP;
> > +     uart.port.iotype = UPIO_MEM;
> > +     uart.port.regshift = 0;
> > +     uart.port.dev = dev;
> > +     uart.port.type = PORT_LOONGSON;
> > +     uart.port.private_data = ddata;
> > +
> > +     uart.port.mapbase = res->start;
> > +     uart.port.mapsize = resource_size(res);
> > +     uart.port.serial_in = loongson_serial_in;
> > +     uart.port.serial_out = loongson_serial_out;
> > +
> > +     flags = (uintptr_t)device_get_match_data(dev);
>
> Perhaps flags should be unsigned long?
>
> > +     if (flags & LOONGSON_UART_HAS_FRAC) {
> > +             uart.port.get_divisor = loongson_frac_get_divisor;
> > +             uart.port.set_divisor = loongson_frac_set_divisor;
> > +     }
> > +
> > +     if (flags & LOONGSON_UART_QUIRK_MCR)
> > +             ddata->mcr_invert |= (UART_MCR_RTS | UART_MCR_DTR);
> > +
> > +     if (flags & LOONGSON_UART_QUIRK_MSR)
> > +             ddata->msr_invert |= (UART_MSR_CTS | UART_MSR_DSR);
>
> I think it would be better to put these invert masks directly into a
> struct which is then put into .data. LOONGSON_UART_HAS_FRAC can be bool
> in that struct.

I attempted the following refactoring:

struct loongson_uart_ddata {
        bool has_frac;
        u8 mcr_invert;
        u8 msr_invert;
};

static const struct loongson_uart_ddata ls2k0500_uart_data {
        .has_frac = false,
        .mcr_invert = UART_MCR_RTS | UART_MCR_DTR,
        .msr_invert = UART_MSR_CTS | UART_MSR_DSR,
};

static const struct loongson_uart_ddata ls2k1500_uart_data {
        .has_frac = true,
        .mcr_invert = UART_MCR_RTS | UART_MCR_DTR,
        .msr_invert = 0,
};

struct loongson_uart_priv {
        int line;
        struct clk *clk;
        struct resource *res;
        struct reset_control *rst;
        struct loongson_uart_ddata *ddata;
};

.............
In loongson_uart_probe():
       priv->ddata = device_get_match_data(dev);

        if (priv->ddata->has_frac) {
                port->get_divisor = loongson_frac_get_divisor;
                port->set_divisor = loongson_frac_set_divisor;
        }


.............
static const struct of_device_id loongson_uart_of_ids[] = {
        { .compatible = "loongson,ls2k0500-uart", .data = ls2k0500_uart_data },
        { .compatible = "loongson,ls2k1500-uart", .data = ls2k1500_uart_data },
        { },
};
>
> > +     ddata->rst = devm_reset_control_get_optional_shared(dev, NULL);
> > +     if (IS_ERR(ddata->rst))
> > +             return PTR_ERR(ddata->rst);
> > +
> > +     ret = reset_control_deassert(ddata->rst);
> > +     if (ret)
> > +             return ret;
> > +
> > +     ret = serial8250_register_8250_port(&uart);
> > +     if (ret < 0) {
> > +             reset_control_assert(ddata->rst);
> > +             return ret;
> > +     }
> > +
> > +     ddata->line = ret;
> > +     platform_set_drvdata(pdev, ddata);
> > +
> > +     return 0;
> > +}
> > +
> > +static void loongson_uart_remove(struct platform_device *pdev)
> > +{
> > +     struct loongson_uart_data *ddata = platform_get_drvdata(pdev);
> > +
> > +     serial8250_unregister_port(ddata->line);
> > +     reset_control_assert(ddata->rst);
> > +}
> > +
> > +static int loongson_uart_suspend(struct device *dev)
> > +{
> > +     struct loongson_uart_data *ddata = dev_get_drvdata(dev);
> > +
> > +     serial8250_suspend_port(ddata->line);
> > +
> > +     return 0;
> > +}
> > +
> > +static int loongson_uart_resume(struct device *dev)
> > +{
> > +     struct loongson_uart_data *data = dev_get_drvdata(dev);
> > +
> > +     serial8250_resume_port(data->line);
> > +
> > +     return 0;
> > +}
> > +
> > +static DEFINE_SIMPLE_DEV_PM_OPS(loongson_uart_pm_ops, loongson_uart_suspend,
> > +                             loongson_uart_resume);
>
> Include? Please check if you miss even more includes beyond those I've
> highlighted here.

#include <linux/pm.h>

I will check all missed include files.
>
> > +static const struct of_device_id loongson_uart_of_ids[] = {
> > +     { .compatible = "loongson,ls2k0500-uart", .data = (void *)LS2K0500_UART_FLAG },
> > +     { .compatible = "loongson,ls2k1500-uart", .data = (void *)LS2K1500_UART_FLAG },
> > +     { /* sentinel */ },
>
> Nit, no need for comma in the terminator entry.

ok..
>
> > +};
> > +MODULE_DEVICE_TABLE(of, loongson_uart_of_ids);
> > +
> > +static struct platform_driver loongson_uart_driver = {
> > +     .probe = loongson_uart_probe,
> > +     .remove = loongson_uart_remove,
> > +     .driver = {
> > +             .name = "loongson-uart",
> > +             .pm = pm_ptr(&loongson_uart_pm_ops),
> > +             .of_match_table = loongson_uart_of_ids,
> > +     },
> > +};
> > +
> > +module_platform_driver(loongson_uart_driver);
> > +
> > +MODULE_DESCRIPTION("Loongson UART driver");
> > +MODULE_AUTHOR("Loongson Technology Corporation Limited.");
> > +MODULE_LICENSE("GPL");
> > diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
> > index 719faf92aa8a..53efe841656f 100644
> > --- a/drivers/tty/serial/8250/8250_port.c
> > +++ b/drivers/tty/serial/8250/8250_port.c
> > @@ -310,6 +310,14 @@ static const struct serial8250_config uart_config[] = {
> >               .rxtrig_bytes   = {1, 8, 16, 30},
> >               .flags          = UART_CAP_FIFO | UART_CAP_AFE,
> >       },
> > +     [PORT_LOONGSON] = {
> > +             .name           = "Loongson",
> > +             .fifo_size      = 16,
> > +             .tx_loadsz      = 16,
> > +             .fcr            = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
> > +             .rxtrig_bytes   = {1, 4, 8, 14},
> > +             .flags          = UART_CAP_FIFO,
> > +     },
>
> This is exactly identical to PORT_16550A. Just use PORT_16550A instead of
> adding a new one unnecessarily.

OK. I will drop this part and use PORT_16550A in 8250_loongson driver.
>
> --
>  i.
>
> >  };
> >
> >  /* Uart divisor latch read */
> > diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
> > index f64ef0819cd4..98236b3bec10 100644
> > --- a/drivers/tty/serial/8250/Kconfig
> > +++ b/drivers/tty/serial/8250/Kconfig
> > @@ -468,6 +468,16 @@ config SERIAL_8250_OMAP_TTYO_FIXUP
> >         not booting kernel because the serial console remains silent in case
> >         they forgot to update the command line.
> >
> > +config SERIAL_8250_LOONGSON
> > +     tristate "Loongson 8250 based serial port"
> > +     depends on SERIAL_8250
> > +     depends on LOONGARCH || COMPILE_TEST
> > +     help
> > +       If you have a machine based on LoongArch CPU you can enable
> > +       its onboard serial ports by enabling this option. The option
> > +       is applicable to both devicetree and ACPI, say Y to this option.
> > +       If unsure, say N.
> > +
> >  config SERIAL_8250_LPC18XX
> >       tristate "NXP LPC18xx/43xx serial port support"
> >       depends on SERIAL_8250 && OF && (ARCH_LPC18XX || COMPILE_TEST)
> > diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
> > index 513a0941c284..e318a3240789 100644
> > --- a/drivers/tty/serial/8250/Makefile
> > +++ b/drivers/tty/serial/8250/Makefile
> > @@ -38,6 +38,7 @@ obj-$(CONFIG_SERIAL_8250_HP300)             += 8250_hp300.o
> >  obj-$(CONFIG_SERIAL_8250_HUB6)               += 8250_hub6.o
> >  obj-$(CONFIG_SERIAL_8250_INGENIC)    += 8250_ingenic.o
> >  obj-$(CONFIG_SERIAL_8250_IOC3)               += 8250_ioc3.o
> > +obj-$(CONFIG_SERIAL_8250_LOONGSON)   += 8250_loongson.o
> >  obj-$(CONFIG_SERIAL_8250_LPC18XX)    += 8250_lpc18xx.o
> >  obj-$(CONFIG_SERIAL_8250_LPSS)               += 8250_lpss.o
> >  obj-$(CONFIG_SERIAL_8250_MEN_MCB)    += 8250_men_mcb.o
> > diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
> > index 9c007a106330..607cf060a72a 100644
> > --- a/include/uapi/linux/serial_core.h
> > +++ b/include/uapi/linux/serial_core.h
> > @@ -31,6 +31,7 @@
> >  #define PORT_ALTR_16550_F128 28 /* Altera 16550 UART with 128 FIFOs */
> >  #define PORT_RT2880  29      /* Ralink RT2880 internal UART */
> >  #define PORT_16550A_FSL64 30 /* Freescale 16550 UART with 64 FIFOs */
> > +#define PORT_LOONGSON        31      /* Loongson 16550 UART */
> >
> >  /*
> >   * ARM specific type numbers.  These are not currently guaranteed
> >


-- 
Thanks.
Binbin

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v5 2/3] serial: 8250: Add Loongson uart driver support
  2025-10-09  2:52     ` Binbin Zhou
@ 2025-10-09 11:46       ` Ilpo Järvinen
  0 siblings, 0 replies; 16+ messages in thread
From: Ilpo Järvinen @ 2025-10-09 11:46 UTC (permalink / raw)
  To: Binbin Zhou
  Cc: Binbin Zhou, Huacai Chen, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Greg Kroah-Hartman, Jiri Slaby, Haowei Zheng,
	Huacai Chen, Xuerui Wang, loongarch, devicetree, linux-serial

[-- Attachment #1: Type: text/plain, Size: 3608 bytes --]

On Thu, 9 Oct 2025, Binbin Zhou wrote:

> Hi Ilpo:
> 
> Sorry for the late reply and thanks for your detailed review.
> 
> On Tue, Sep 30, 2025 at 7:58 PM Ilpo Järvinen
> <ilpo.jarvinen@linux.intel.com> wrote:
> >
> > On Wed, 24 Sep 2025, Binbin Zhou wrote:
> >
> > > Add the driver for on-chip UART used on Loongson family chips.
> > >
> > > The hardware is similar to 8250, but there are the following
> > > differences:
> > >  - Some chips (such as Loongson-2K2000) have added a fractional division
> > >    register to obtain the required baud rate accurately, so the
> > >    {get,set}_divisor callback is overridden.
> > >  - Due to hardware defects, quirk handling is required for
> > >    UART_MCR/UART_MSR.
> > >
> > > Co-developed-by: Haowei Zheng <zhenghaowei@loongson.cn>
> > > Signed-off-by: Haowei Zheng <zhenghaowei@loongson.cn>
> > > Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn>
> > > ---

> > > +static unsigned int serial_fixup(struct uart_port *p, unsigned int offset, unsigned int val)
> > > +{
> > > +     struct loongson_uart_data *ddata = p->private_data;
> > > +
> > > +     if (offset == UART_MCR)
> > > +             val ^= ddata->mcr_invert;
> > > +
> > > +     if (offset == UART_MSR)
> > > +             val ^= ddata->msr_invert;

One additional thing, this could use switch/case.

I'd just do:

	...
	case UART_MSR:
		return val ^ ddata->msr_invert;
	default:
		return val;
	}

That way you don't need to use breaks.

> > > +     if (flags & LOONGSON_UART_HAS_FRAC) {
> > > +             uart.port.get_divisor = loongson_frac_get_divisor;
> > > +             uart.port.set_divisor = loongson_frac_set_divisor;
> > > +     }
> > > +
> > > +     if (flags & LOONGSON_UART_QUIRK_MCR)
> > > +             ddata->mcr_invert |= (UART_MCR_RTS | UART_MCR_DTR);
> > > +
> > > +     if (flags & LOONGSON_UART_QUIRK_MSR)
> > > +             ddata->msr_invert |= (UART_MSR_CTS | UART_MSR_DSR);
> >
> > I think it would be better to put these invert masks directly into a
> > struct which is then put into .data. LOONGSON_UART_HAS_FRAC can be bool
> > in that struct.
> 
> I attempted the following refactoring:
> 
> struct loongson_uart_ddata {
>         bool has_frac;
>         u8 mcr_invert;
>         u8 msr_invert;
> };
> 
> static const struct loongson_uart_ddata ls2k0500_uart_data {
>         .has_frac = false,
>         .mcr_invert = UART_MCR_RTS | UART_MCR_DTR,
>         .msr_invert = UART_MSR_CTS | UART_MSR_DSR,
> };
> 
> static const struct loongson_uart_ddata ls2k1500_uart_data {
>         .has_frac = true,
>         .mcr_invert = UART_MCR_RTS | UART_MCR_DTR,
>         .msr_invert = 0,
> };
> 
> struct loongson_uart_priv {
>         int line;
>         struct clk *clk;
>         struct resource *res;
>         struct reset_control *rst;
>         struct loongson_uart_ddata *ddata;

This can and should be const struct as well as those underlying data 
structs are const too.

> };
> 
> .............
> In loongson_uart_probe():
>        priv->ddata = device_get_match_data(dev);
> 
>         if (priv->ddata->has_frac) {
>                 port->get_divisor = loongson_frac_get_divisor;
>                 port->set_divisor = loongson_frac_set_divisor;
>         }
> 
> 
> .............
> static const struct of_device_id loongson_uart_of_ids[] = {
>         { .compatible = "loongson,ls2k0500-uart", .data = ls2k0500_uart_data },
>         { .compatible = "loongson,ls2k1500-uart", .data = ls2k1500_uart_data },
>         { },
> };


-- 
 i.

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2025-10-09 11:46 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-24  6:29 [PATCH v5 0/3] uart: Introduce uart driver for the Loongson family Binbin Zhou
2025-09-24  6:29 ` [PATCH v5 1/3] dt-bindings: serial: 8250: Add Loongson uart compatible Binbin Zhou
2025-09-24 19:19   ` Conor Dooley
2025-09-24  6:29 ` [PATCH v5 2/3] serial: 8250: Add Loongson uart driver support Binbin Zhou
2025-09-24 10:22   ` Greg Kroah-Hartman
2025-09-28  2:48     ` Binbin Zhou
2025-09-29  6:19       ` Jiri Slaby
2025-09-30  3:03         ` Binbin Zhou
2025-10-08 12:16           ` Greg Kroah-Hartman
2025-09-29  6:26   ` Jiri Slaby
2025-09-30  3:07     ` Binbin Zhou
2025-09-30 12:01     ` Ilpo Järvinen
2025-09-30 11:58   ` Ilpo Järvinen
2025-10-09  2:52     ` Binbin Zhou
2025-10-09 11:46       ` Ilpo Järvinen
2025-09-24  6:29 ` [PATCH v5 3/3] LoongArch: dts: Add uart new compatible string Binbin Zhou

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).