* [PATCH v3 1/3] dt-bindings: serial: Add Loongson UART controller
2024-08-26 2:47 [PATCH v3 0/3] uart: Introduce uart driver for the Loongson family chips zhenghaowei
@ 2024-08-26 2:47 ` zhenghaowei
2024-08-26 5:59 ` Krzysztof Kozlowski
2024-08-26 2:47 ` [PATCH v3 2/3] tty: serial: 8250: Add loongson uart driver support zhenghaowei
2024-08-26 2:47 ` [PATCH v3 3/3] LoongArch: Update dts to support Loongson UART driver zhenghaowei
2 siblings, 1 reply; 10+ messages in thread
From: zhenghaowei @ 2024-08-26 2:47 UTC (permalink / raw)
To: zhenghaowei, gregkh, jirislaby, robh, krzk+dt, conor+dt,
chenhuacai, kernel, p.zabel
Cc: linux-serial, linux-kernel, devicetree, loongarch
From: Haowei Zheng <zhenghaowei@loongson.cn>
Add Loongson UART controller binding with DT schema format using
json-schema.
Signed-off-by: Haowei Zheng <zhenghaowei@loongson.cn>
---
.../bindings/serial/loongson,uart.yaml | 63 +++++++++++++++++++
1 file changed, 63 insertions(+)
create mode 100644 Documentation/devicetree/bindings/serial/loongson,uart.yaml
Changes in V2:
- Correct the schema formatting errors.
- file name changed from 'loongson-uart.yaml' to 'loongson,ls7a-uart.yaml'
- Replace 'loongson,loongson-uart' with 'loongson,ls7a-uart'.
Changes in V3:
- Change the filename from 'loongson,ls7a-uart.yaml' to 'loongson,uart.yaml'.
- Drop newly defined features: fractional-division, rts-invert, dtr-invert,
cts-invert and dsr-invert.
- Add three specific SoC: 'loongson,ls7a-uart', 'loongson,ls3a5000-uart' and
'loongson,ls2k2000-uart'.
- Drop 'LOONGSON UART DRIVER' description in MAINTAINERS.
diff --git a/Documentation/devicetree/bindings/serial/loongson,uart.yaml b/Documentation/devicetree/bindings/serial/loongson,uart.yaml
new file mode 100644
index 000000000000..19a65dd5be9f
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/loongson,uart.yaml
@@ -0,0 +1,63 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/loongson,uart.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Loongson UART
+
+maintainers:
+ - Haowei Zheng <zhenghaowei@loongson.cn>
+
+allOf:
+ - $ref: serial.yaml
+
+properties:
+ compatible:
+ oneOf:
+ - enum:
+ - loongson,ls7a-uart
+ - loongson,ls3a5000-uart
+ - loongson,ls2k2000-uart
+ - items:
+ - enum:
+ - loongson,ls2k1000-uart
+ - loongson,ls2k0500-uart
+ - const: loongson,ls7a-uart
+ - items:
+ - enum:
+ - loongson,ls2k1500-uart
+ - const: loongson,ls2k2000-uart
+ - items:
+ - enum:
+ - loongson,ls3a6000-uart
+ - const: loongson,ls3a5000-uart
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ clock-frequency: true
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - clock-frequency
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/irq.h>
+ #include <dt-bindings/clock/loongson,ls2k-clk.h>
+
+ serial@1fe20000 {
+ compatible = "loongson,ls2k1000-uart", "loongson,ls7a-uart";
+ reg = <0x1fe20000 0x10>;
+ clock-frequency = <125000000>;
+ interrupt-parent = <&liointc0>;
+ interrupts = <0x0 IRQ_TYPE_LEVEL_HIGH>;
+ };
--
2.43.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v3 2/3] tty: serial: 8250: Add loongson uart driver support
2024-08-26 2:47 [PATCH v3 0/3] uart: Introduce uart driver for the Loongson family chips zhenghaowei
2024-08-26 2:47 ` [PATCH v3 1/3] dt-bindings: serial: Add Loongson UART controller zhenghaowei
@ 2024-08-26 2:47 ` zhenghaowei
2024-08-26 2:47 ` [PATCH v3 3/3] LoongArch: Update dts to support Loongson UART driver zhenghaowei
2 siblings, 0 replies; 10+ messages in thread
From: zhenghaowei @ 2024-08-26 2:47 UTC (permalink / raw)
To: zhenghaowei, gregkh, jirislaby, robh, krzk+dt, conor+dt,
chenhuacai, kernel, p.zabel
Cc: linux-serial, linux-kernel, devicetree, loongarch
From: Haowei Zheng <zhenghaowei@loongson.cn>
Due to certain hardware design challenges, we have opted to
utilize a dedicated UART driver to probe the UART interface.
Signed-off-by: Haowei Zheng <zhenghaowei@loongson.cn>
---
MAINTAINERS | 7 +
drivers/tty/serial/8250/8250_loongson.c | 228 ++++++++++++++++++++++++
drivers/tty/serial/8250/8250_port.c | 8 +
drivers/tty/serial/8250/Kconfig | 9 +
drivers/tty/serial/8250/Makefile | 1 +
include/uapi/linux/serial_core.h | 1 +
6 files changed, 254 insertions(+)
create mode 100644 drivers/tty/serial/8250/8250_loongson.c
Changes in V2:
- Correct the schema formatting errors.
- file name changed from 'loongson-uart.yaml' to 'loongson,ls7a-uart.yaml'
- Replace 'loongson,loongson-uart' with 'loongson,ls7a-uart'.
Changes in V3:
- Add 'LOONGSON UART DRIVER' description in MAINTAINERS.
- Use 'UPF_IOREMAP' instead of 'devm_ioremap()'.
- Use 'loongson_uart_config' to distinguish specific SoC.
- Call reset_control_assert() when err_unprepare occurs.
- Handle compilation errors.
diff --git a/MAINTAINERS b/MAINTAINERS
index 878dcd23b331..03024e9589bc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13191,6 +13191,13 @@ S: Maintained
F: Documentation/devicetree/bindings/i2c/loongson,ls2x-i2c.yaml
F: drivers/i2c/busses/i2c-ls2x.c
+LOONGSON UART DRIVER
+M: Haowei Zheng <zhenghaowei@loongson.cn>
+L: linux-serial@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/serial/loongson,uart.yaml
+F: drivers/tty/serial/8250/8250_loongson.c
+
LOONGSON-2 SOC SERIES CLOCK DRIVER
M: Yinbo Zhu <zhuyinbo@loongson.cn>
L: linux-clk@vger.kernel.org
diff --git a/drivers/tty/serial/8250/8250_loongson.c b/drivers/tty/serial/8250/8250_loongson.c
new file mode 100644
index 000000000000..88205fed4fd3
--- /dev/null
+++ b/drivers/tty/serial/8250/8250_loongson.c
@@ -0,0 +1,228 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2020-2024 Loongson Technology Corporation Limited
+ */
+
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/reset.h>
+
+#include "8250.h"
+
+/* Flags */
+#define LOONGSON_UART_FRAC BIT(0)
+
+/* Quirks */
+#define LOONGSON_UART_QUIRK_MCR BIT(0)
+#define LOONGSON_UART_QUIRK_MSR BIT(1)
+
+struct loongson_uart_config {
+ unsigned int flags;
+ unsigned int quirks;
+};
+
+struct loongson_uart_data {
+ struct reset_control *rst;
+ int line;
+ int mcr_invert;
+ int msr_invert;
+ const struct loongson_uart_config *config;
+};
+
+static const struct loongson_uart_config ls3a5000_uart_config = {
+ .flags = 0,
+ .quirks = LOONGSON_UART_QUIRK_MCR
+};
+
+static const struct loongson_uart_config ls7a_uart_config = {
+ .flags = 0,
+ .quirks = LOONGSON_UART_QUIRK_MCR | LOONGSON_UART_QUIRK_MSR
+};
+
+static const struct loongson_uart_config ls2k2000_uart_config = {
+ .flags = LOONGSON_UART_FRAC,
+ .quirks = LOONGSON_UART_QUIRK_MCR
+};
+
+static unsigned int serial_fixup(struct uart_port *p, unsigned int offset, unsigned int val)
+{
+ struct loongson_uart_data *data = p->private_data;
+
+ if (offset == UART_MCR)
+ val ^= data->mcr_invert;
+ if (offset == UART_MSR)
+ val ^= data->msr_invert;
+
+ return val;
+}
+
+static unsigned int loongson_serial_in(struct uart_port *p, int offset)
+{
+ unsigned int val, offset0 = offset;
+
+ offset = offset << p->regshift;
+ val = readb(p->membase + offset);
+
+ return serial_fixup(p, offset0, val);
+}
+
+static void loongson_serial_out(struct uart_port *p, int offset, int value)
+{
+ offset = 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 = quot & 0xff;
+
+ return quot >> 8;
+}
+
+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, 0x2, quot_frac);
+}
+
+static int loongson_uart_probe(struct platform_device *pdev)
+{
+ struct uart_8250_port uart = {};
+ struct loongson_uart_data *data;
+ struct uart_port *port;
+ struct resource *res;
+ int ret;
+
+ port = &uart.port;
+ spin_lock_init(&port->lock);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ port->flags = UPF_SHARE_IRQ | UPF_FIXED_PORT | UPF_FIXED_TYPE | UPF_IOREMAP;
+ port->iotype = UPIO_MEM;
+ port->regshift = 0;
+ port->dev = &pdev->dev;
+ port->type = PORT_LOONGSON;
+ port->mapbase = res->start;
+ port->mapsize = resource_size(res);
+ port->serial_in = loongson_serial_in;
+ port->serial_out = loongson_serial_out;
+
+ port->irq = platform_get_irq(pdev, 0);
+ if (port->irq < 0)
+ return -EINVAL;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->config = device_get_match_data(&pdev->dev);
+
+ port->private_data = data;
+
+ if (data->config->flags & LOONGSON_UART_FRAC) {
+ port->get_divisor = loongson_frac_get_divisor;
+ port->set_divisor = loongson_frac_set_divisor;
+ }
+
+ if (data->config->quirks & LOONGSON_UART_QUIRK_MCR)
+ data->mcr_invert |= (UART_MCR_RTS | UART_MCR_DTR);
+
+ if (data->config->quirks & LOONGSON_UART_QUIRK_MSR)
+ data->msr_invert |= (UART_MSR_CTS | UART_MSR_DSR);
+
+ data->rst = devm_reset_control_get_optional_shared(&pdev->dev, NULL);
+ if (IS_ERR(data->rst))
+ return PTR_ERR(data->rst);
+
+ device_property_read_u32(&pdev->dev, "clock-frequency", &port->uartclk);
+
+ ret = reset_control_deassert(data->rst);
+ if (ret)
+ goto err_unprepare;
+
+ ret = serial8250_register_8250_port(&uart);
+ if (ret < 0)
+ goto err_unprepare;
+
+ platform_set_drvdata(pdev, data);
+ data->line = ret;
+
+ return 0;
+
+err_unprepare:
+ reset_control_assert(data->rst);
+
+ return ret;
+}
+
+static void loongson_uart_remove(struct platform_device *pdev)
+{
+ struct loongson_uart_data *data = platform_get_drvdata(pdev);
+
+ serial8250_unregister_port(data->line);
+ reset_control_assert(data->rst);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int loongson_uart_suspend(struct device *dev)
+{
+ struct loongson_uart_data *data = dev_get_drvdata(dev);
+
+ serial8250_suspend_port(data->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;
+}
+#endif
+
+static const struct dev_pm_ops loongson_uart_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(loongson_uart_suspend, loongson_uart_resume)
+};
+
+static const struct of_device_id of_platform_serial_table[] = {
+ {.compatible = "loongson,ls7a-uart", .data = &ls7a_uart_config},
+ {.compatible = "loongson,ls3a5000-uart", .data = &ls3a5000_uart_config},
+ {.compatible = "loongson,ls2k2000-uart", .data = &ls2k2000_uart_config},
+ {},
+};
+MODULE_DEVICE_TABLE(of, of_platform_serial_table);
+
+static struct platform_driver loongson_uart_driver = {
+ .probe = loongson_uart_probe,
+ .remove = loongson_uart_remove,
+ .driver = {
+ .name = "loongson-uart",
+ .pm = &loongson_uart_pm_ops,
+ .of_match_table = of_platform_serial_table,
+ },
+};
+
+module_platform_driver(loongson_uart_driver);
+
+MODULE_DESCRIPTION("LOONGSON 8250 Driver");
+MODULE_AUTHOR("Haowei Zheng <zhenghaowei@loongson.cn>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 2786918aea98..60b72c785028 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -319,6 +319,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 47ff50763c04..ca828e94719a 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -568,6 +568,15 @@ config SERIAL_8250_BCM7271
including DMA support and high accuracy BAUD rates, say
Y to this option. If unsure, say N.
+config SERIAL_8250_LOONGSON
+ tristate "Loongson 8250 serial port support"
+ default SERIAL_8250
+ depends on SERIAL_8250
+ depends on LOONGARCH
+ help
+ If you have machine with Loongson and want to use this serial driver,
+ say Y to this option. If unsure, say N.
+
config SERIAL_OF_PLATFORM
tristate "Devicetree based probing for 8250 ports"
depends on SERIAL_8250 && OF
diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile
index 1516de629b61..e9587bf69f65 100644
--- a/drivers/tty/serial/8250/Makefile
+++ b/drivers/tty/serial/8250/Makefile
@@ -51,5 +51,6 @@ obj-$(CONFIG_SERIAL_8250_RT288X) += 8250_rt288x.o
obj-$(CONFIG_SERIAL_8250_CS) += serial_cs.o
obj-$(CONFIG_SERIAL_8250_UNIPHIER) += 8250_uniphier.o
obj-$(CONFIG_SERIAL_8250_TEGRA) += 8250_tegra.o
+obj-$(CONFIG_SERIAL_8250_LOONGSON) += 8250_loongson.o
CFLAGS_8250_ingenic.o += -I$(srctree)/scripts/dtc/libfdt
diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
index 9c007a106330..9e316b9295e5 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.43.0
^ permalink raw reply related [flat|nested] 10+ messages in thread* [PATCH v3 3/3] LoongArch: Update dts to support Loongson UART driver.
2024-08-26 2:47 [PATCH v3 0/3] uart: Introduce uart driver for the Loongson family chips zhenghaowei
2024-08-26 2:47 ` [PATCH v3 1/3] dt-bindings: serial: Add Loongson UART controller zhenghaowei
2024-08-26 2:47 ` [PATCH v3 2/3] tty: serial: 8250: Add loongson uart driver support zhenghaowei
@ 2024-08-26 2:47 ` zhenghaowei
2024-08-26 6:00 ` Krzysztof Kozlowski
2 siblings, 1 reply; 10+ messages in thread
From: zhenghaowei @ 2024-08-26 2:47 UTC (permalink / raw)
To: zhenghaowei, gregkh, jirislaby, robh, krzk+dt, conor+dt,
chenhuacai, kernel, p.zabel
Cc: linux-serial, linux-kernel, devicetree, loongarch
From: Haowei Zheng <zhenghaowei@loongson.cn>
Change to use the Loongson UART driver for Loongson-2K2000,
Loongson-2K1000 and Loongson-2K0500.
Signed-off-by: Haowei Zheng <zhenghaowei@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(-)
Changes in V2:
- The compatible property for the UART is changed from "ns16650,loongson"
to "loongson,ls7a-uart".
Changes in V3:
- Compatible has been modified for a specific SoC.
diff --git a/arch/loongarch/boot/dts/loongson-2k0500.dtsi b/arch/loongarch/boot/dts/loongson-2k0500.dtsi
index 3b38ff8853a7..63c77d70639c 100644
--- a/arch/loongarch/boot/dts/loongson-2k0500.dtsi
+++ b/arch/loongarch/boot/dts/loongson-2k0500.dtsi
@@ -220,7 +220,7 @@ tsensor: thermal-sensor@1fe11500 {
};
uart0: serial@1ff40800 {
- compatible = "ns16550a";
+ compatible = "loongson,ls2k0500-uart", "loongson,ls7a-uart";
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 92180140eb56..cafb8d13c065 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,ls7a-uart";
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 0953c5707825..d4fe91af8c07 100644
--- a/arch/loongarch/boot/dts/loongson-2k2000.dtsi
+++ b/arch/loongarch/boot/dts/loongson-2k2000.dtsi
@@ -174,7 +174,7 @@ rtc0: rtc@100d0100 {
};
uart0: serial@1fe001e0 {
- compatible = "ns16550a";
+ compatible = "loongson,ls2k2000-uart";
reg = <0x0 0x1fe001e0 0x0 0x10>;
clock-frequency = <100000000>;
interrupt-parent = <&liointc>;
--
2.43.0
^ permalink raw reply related [flat|nested] 10+ messages in thread