All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v8 0/2] Add UART driver for Suplus SP7021 SoC
@ 2022-02-15  9:24 Hammer Hsieh
  2022-02-15  9:24 ` [PATCH v8 1/2] dt-bindings:serial:Add bindings doc for Sunplus SoC UART Driver Hammer Hsieh
  2022-02-15  9:24 ` [PATCH v8 2/2] serial:sunplus-uart:Add " Hammer Hsieh
  0 siblings, 2 replies; 8+ messages in thread
From: Hammer Hsieh @ 2022-02-15  9:24 UTC (permalink / raw)
  To: gregkh, robh+dt, linux-serial, devicetree, linux-kernel,
	jirislaby, p.zabel
  Cc: wells.lu, hammer.hsieh, Hammer Hsieh

This is a patch series for UART driver for Suplus SP7021 SoC.

Sunplus SP7021 is an ARM Cortex A7 (4 cores) based SoC. It integrates
many peripherals (ex: UART. I2C, SPI, SDIO, eMMC, USB, SD card and
etc.) into a single chip. It is designed for industrial control.

Refer to:
https://sunplus-tibbo.atlassian.net/wiki/spaces/doc/overview
https://tibbo.com/store/plus1.html

Refer to (UART):
https://sunplus.atlassian.net/wiki/spaces/doc/pages/1873412290/13.+Universal+Asynchronous+Receiver+Transmitter+UART

Hammer Hsieh (2):
  dt-bindings:serial:Add bindings doc for Sunplus SoC UART Driver
  serial:sunplus-uart:Add Sunplus SoC UART Driver

 .../bindings/serial/sunplus,sp7021-uart.yaml       |  56 ++
 MAINTAINERS                                        |   6 +
 drivers/tty/serial/Kconfig                         |  25 +
 drivers/tty/serial/Makefile                        |   1 +
 drivers/tty/serial/sunplus-uart.c                  | 776 +++++++++++++++++++++
 include/uapi/linux/serial_core.h                   |   3 +
 6 files changed, 867 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/serial/sunplus,sp7021-uart.yaml
 create mode 100644 drivers/tty/serial/sunplus-uart.c

-- 
2.7.4


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

* [PATCH v8 1/2] dt-bindings:serial:Add bindings doc for Sunplus SoC UART Driver
  2022-02-15  9:24 [PATCH v8 0/2] Add UART driver for Suplus SP7021 SoC Hammer Hsieh
@ 2022-02-15  9:24 ` Hammer Hsieh
  2022-02-15 14:53   ` Krzysztof Kozlowski
  2022-02-15  9:24 ` [PATCH v8 2/2] serial:sunplus-uart:Add " Hammer Hsieh
  1 sibling, 1 reply; 8+ messages in thread
From: Hammer Hsieh @ 2022-02-15  9:24 UTC (permalink / raw)
  To: gregkh, robh+dt, linux-serial, devicetree, linux-kernel,
	jirislaby, p.zabel
  Cc: wells.lu, hammer.hsieh, Hammer Hsieh

Add bindings doc for Sunplus SoC UART Driver

Reviewed-by: Rob Herring <robh@kernel.org>
Signed-off-by: Hammer Hsieh <hammerh0314@gmail.com>
---
Changes in v8:
 - no change.

 .../bindings/serial/sunplus,sp7021-uart.yaml       | 56 ++++++++++++++++++++++
 MAINTAINERS                                        |  5 ++
 2 files changed, 61 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/serial/sunplus,sp7021-uart.yaml

diff --git a/Documentation/devicetree/bindings/serial/sunplus,sp7021-uart.yaml b/Documentation/devicetree/bindings/serial/sunplus,sp7021-uart.yaml
new file mode 100644
index 0000000..894324c
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/sunplus,sp7021-uart.yaml
@@ -0,0 +1,56 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) Sunplus Co., Ltd. 2021
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/serial/sunplus,sp7021-uart.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Sunplus SoC SP7021 UART Controller Device Tree Bindings
+
+maintainers:
+  - Hammer Hsieh <hammerh0314@gmail.com>
+
+allOf:
+  - $ref: serial.yaml#
+
+properties:
+  compatible:
+    const: sunplus,sp7021-uart
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - resets
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    aliases {
+            serial0 = &uart0;
+    };
+
+    uart0: serial@9c000900 {
+        compatible = "sunplus,sp7021-uart";
+        reg = <0x9c000900 0x80>;
+        interrupt-parent = <&intc>;
+        interrupts = <53 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&clkc 0x28>;
+        resets = <&rstc 0x18>;
+    };
+...
diff --git a/MAINTAINERS b/MAINTAINERS
index 3b79fd4..3c1362e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17945,6 +17945,11 @@ L:	netdev@vger.kernel.org
 S:	Maintained
 F:	drivers/net/ethernet/dlink/sundance.c
 
+SUNPLUS UART DRIVER
+M:	Hammer Hsieh <hammerh0314@gmail.com>
+S:	Maintained
+F:	Documentation/devicetree/bindings/serial/sunplus,sp7021-uart.yaml
+
 SUPERH
 M:	Yoshinori Sato <ysato@users.sourceforge.jp>
 M:	Rich Felker <dalias@libc.org>
-- 
2.7.4


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

* [PATCH v8 2/2] serial:sunplus-uart:Add Sunplus SoC UART Driver
  2022-02-15  9:24 [PATCH v8 0/2] Add UART driver for Suplus SP7021 SoC Hammer Hsieh
  2022-02-15  9:24 ` [PATCH v8 1/2] dt-bindings:serial:Add bindings doc for Sunplus SoC UART Driver Hammer Hsieh
@ 2022-02-15  9:24 ` Hammer Hsieh
  2022-02-15 12:45   ` kernel test robot
  2022-02-16  3:59     ` kernel test robot
  1 sibling, 2 replies; 8+ messages in thread
From: Hammer Hsieh @ 2022-02-15  9:24 UTC (permalink / raw)
  To: gregkh, robh+dt, linux-serial, devicetree, linux-kernel,
	jirislaby, p.zabel
  Cc: wells.lu, hammer.hsieh, Hammer Hsieh

Add Sunplus SoC UART Driver.
SP7021 UART block contains 5 UARTs.
There are UART0~4 that supported in SP7021, the features list as below.
Support Full-duplex communication.
Support data packet length configurable.
Support stop bit number configurable.
Support force break condition.
Support baud rate configurable.
Support error detection and report.
Support RXD Noise Rejection Vote configurable.

UART0 pinout only support TX/RX two pins.
UART1 to UART4 pinout support TX/RX/CTS/RTS four pins.
Normally UART0 used for kernel console, also can be used for normal uart.
Command line set "console=ttySUP0,115200", SUP means Sunplus Uart Port.
UART driver probe will create path named "/dev/ttySUPx".

https://sunplus.atlassian.net/wiki/spaces/doc/pages/1873412290/13.+Universal+Asynchronous+Receiver+Transmitter+UART

Signed-off-by: Hammer Hsieh <hammerh0314@gmail.com>
---
Changes in v8:
 - Addressed all comments from Jiri Slaby and Greg KH.
   Add Note in the top of file about posted write info.
 - Addressed kernel test robot warning issue (gcc 11.2.0 ia64)
   [cannot apply to tty/tty-testing robh/for-next linus/master v5.17-rc3 next-20220207]
   Add sunplus_uart_disable_unprepare and sunplus_uart_reset_control_assert for
    devm_add_action_or_reset function (void(*)(void *))reset_control_assert 
    warning in probe function.
   Add __maybe_unused for suspend/resume function "defined but not used" warning.
 - Addressed kernel test robot error issue (gcc 11.2.0 powerpc)
   [cannot apply to tty/tty-testing robh/for-next linus/master v5.17-rc3 next-20220207]
   Implicit declaration of function 'wait_for_xmitr' while CONFIG_CONSOLE_POLL=y.

 MAINTAINERS                       |   1 +
 drivers/tty/serial/Kconfig        |  25 ++
 drivers/tty/serial/Makefile       |   1 +
 drivers/tty/serial/sunplus-uart.c | 776 ++++++++++++++++++++++++++++++++++++++
 include/uapi/linux/serial_core.h  |   3 +
 5 files changed, 806 insertions(+)
 create mode 100644 drivers/tty/serial/sunplus-uart.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 3c1362e..2dc2fe6 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17949,6 +17949,7 @@ SUNPLUS UART DRIVER
 M:	Hammer Hsieh <hammerh0314@gmail.com>
 S:	Maintained
 F:	Documentation/devicetree/bindings/serial/sunplus,sp7021-uart.yaml
+F:	drivers/tty/serial/sunplus-uart.c
 
 SUPERH
 M:	Yoshinori Sato <ysato@users.sourceforge.jp>
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 131a6a5..0865da3 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1561,6 +1561,31 @@ config SERIAL_LITEUART_CONSOLE
 	  and warnings and which allows logins in single user mode).
 	  Otherwise, say 'N'.
 
+config SERIAL_SUNPLUS
+	tristate "Sunplus UART support"
+	depends on OF || COMPILE_TEST
+	select SERIAL_CORE
+	help
+	  Select this option if you would like to use Sunplus serial port on
+	  Sunplus SoC SP7021.
+	  If you enable this option, Sunplus serial ports in the system will
+	  be registered as ttySUPx.
+	  This driver can also be built as a module. If so, the module will be
+	  called sunplus-uart.
+
+config SERIAL_SUNPLUS_CONSOLE
+	bool "Console on Sunplus UART"
+	depends on SERIAL_SUNPLUS
+	select SERIAL_CORE_CONSOLE
+	select SERIAL_EARLYCON
+	help
+	  Select this option if you would like to use a Sunplus UART as the
+	  system 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=ttySUPx".
+
 endmenu
 
 config SERIAL_MCTRL_GPIO
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 7da0856..61cc8de 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -87,6 +87,7 @@ obj-$(CONFIG_SERIAL_RDA)	+= rda-uart.o
 obj-$(CONFIG_SERIAL_MILBEAUT_USIO) += milbeaut_usio.o
 obj-$(CONFIG_SERIAL_SIFIVE)	+= sifive.o
 obj-$(CONFIG_SERIAL_LITEUART) += liteuart.o
+obj-$(CONFIG_SERIAL_SUNPLUS)	+= sunplus-uart.o
 
 # GPIOLIB helpers for modem control lines
 obj-$(CONFIG_SERIAL_MCTRL_GPIO)	+= serial_mctrl_gpio.o
diff --git a/drivers/tty/serial/sunplus-uart.c b/drivers/tty/serial/sunplus-uart.c
new file mode 100644
index 0000000..d550250
--- /dev/null
+++ b/drivers/tty/serial/sunplus-uart.c
@@ -0,0 +1,776 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Sunplus SoC UART driver
+ *
+ * Author: Hammer Hsieh <hammerh0314@gmail.com>
+ *
+ * Note1: This driver is 8250-like uart, but are not register compatible.
+ *
+ * Note2: On some buses, for preventing data incoherence, must do a read
+ * for ensure write made it to hardware. In this driver, function startup
+ * and shutdown did not do a read but only do a write directly. For what?
+ * In Sunplus bus communication between memory bus and peripheral bus with
+ * posted write, it will send a specific command after last write command
+ * to make sure write done. Then memory bus identify the specific command
+ * and send done signal back to master device. After master device received
+ * done signal, then proceed next write command. It is no need to do a read
+ * before write.
+ */
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+#include <linux/sysrq.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <asm/irq.h>
+
+/* Register offsets */
+#define SUP_UART_DATA			0x00
+#define SUP_UART_LSR			0x04
+#define SUP_UART_MSR			0x08
+#define SUP_UART_LCR			0x0C
+#define SUP_UART_MCR			0x10
+#define SUP_UART_DIV_L			0x14
+#define SUP_UART_DIV_H			0x18
+#define SUP_UART_ISC			0x1C
+#define SUP_UART_TX_RESIDUE		0x20
+#define SUP_UART_RX_RESIDUE		0x24
+
+/* Line Status Register bits */
+#define SUP_UART_LSR_BC			BIT(5) /* break condition status */
+#define SUP_UART_LSR_FE			BIT(4) /* frame error status */
+#define SUP_UART_LSR_OE			BIT(3) /* overrun error status */
+#define SUP_UART_LSR_PE			BIT(2) /* parity error status */
+#define SUP_UART_LSR_RX			BIT(1) /* 1: receive fifo not empty */
+#define SUP_UART_LSR_TX			BIT(0) /* 1: transmit fifo is not full */
+#define SUP_UART_LSR_TX_NOT_FULL	1
+#define SUP_UART_LSR_BRK_ERROR_BITS	GENMASK(5, 2)
+
+/* Line Control Register bits */
+#define SUP_UART_LCR_SBC		BIT(5) /* select break condition */
+
+/* Modem Control Register bits */
+#define SUP_UART_MCR_RI			BIT(3) /* ring indicator */
+#define SUP_UART_MCR_DCD		BIT(2) /* data carrier detect */
+
+/* Interrupt Status/Control Register bits */
+#define SUP_UART_ISC_RXM		BIT(5) /* RX interrupt enable */
+#define SUP_UART_ISC_TXM		BIT(4) /* TX interrupt enable */
+#define SUP_UART_ISC_RX			BIT(1) /* RX interrupt status */
+#define SUP_UART_ISC_TX			BIT(0) /* TX interrupt status */
+
+#define SUP_DUMMY_READ			BIT(16) /* drop bytes received on a !CREAD port */
+#define SUP_UART_NR			5
+
+struct sunplus_uart_port {
+	struct uart_port port;
+	struct clk *clk;
+	struct reset_control *rstc;
+};
+
+static void sp_uart_put_char(struct uart_port *port, unsigned int ch)
+{
+	writel(ch, port->membase + SUP_UART_DATA);
+}
+
+static u32 sunplus_tx_buf_not_full(struct uart_port *port)
+{
+	unsigned int lsr = readl(port->membase + SUP_UART_LSR);
+
+	return (lsr & SUP_UART_LSR_TX) ? SUP_UART_LSR_TX_NOT_FULL : 0;
+}
+
+static unsigned int sunplus_tx_empty(struct uart_port *port)
+{
+	unsigned int lsr = readl(port->membase + SUP_UART_LSR);
+
+	return (lsr & UART_LSR_TEMT) ? TIOCSER_TEMT : 0;
+}
+
+static void sunplus_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	unsigned int mcr = readl(port->membase + SUP_UART_MCR);
+
+	if (mctrl & TIOCM_DTR)
+		mcr |= UART_MCR_DTR;
+	else
+		mcr &= ~UART_MCR_DTR;
+
+	if (mctrl & TIOCM_RTS)
+		mcr |= UART_MCR_RTS;
+	else
+		mcr &= ~UART_MCR_RTS;
+
+	if (mctrl & TIOCM_CAR)
+		mcr |= SUP_UART_MCR_DCD;
+	else
+		mcr &= ~SUP_UART_MCR_DCD;
+
+	if (mctrl & TIOCM_RI)
+		mcr |= SUP_UART_MCR_RI;
+	else
+		mcr &= ~SUP_UART_MCR_RI;
+
+	if (mctrl & TIOCM_LOOP)
+		mcr |= UART_MCR_LOOP;
+	else
+		mcr &= ~UART_MCR_LOOP;
+
+	writel(mcr, port->membase + SUP_UART_MCR);
+}
+
+static unsigned int sunplus_get_mctrl(struct uart_port *port)
+{
+	unsigned int ret, mcr;
+
+	mcr = readl(port->membase + SUP_UART_MCR);
+
+	if (mcr & UART_MCR_DTR)
+		ret |= TIOCM_DTR;
+
+	if (mcr & UART_MCR_RTS)
+		ret |= TIOCM_RTS;
+
+	if (mcr & SUP_UART_MCR_DCD)
+		ret |= TIOCM_CAR;
+
+	if (mcr & SUP_UART_MCR_RI)
+		ret |= TIOCM_RI;
+
+	if (mcr & UART_MCR_LOOP)
+		ret |= TIOCM_LOOP;
+
+	return ret;
+}
+
+static void sunplus_stop_tx(struct uart_port *port)
+{
+	unsigned int isc;
+
+	isc = readl(port->membase + SUP_UART_ISC);
+	isc &= ~SUP_UART_ISC_TXM;
+	writel(isc, port->membase + SUP_UART_ISC);
+}
+
+static void sunplus_start_tx(struct uart_port *port)
+{
+	unsigned int isc;
+
+	isc = readl(port->membase + SUP_UART_ISC);
+	isc |= SUP_UART_ISC_TXM;
+	writel(isc, port->membase + SUP_UART_ISC);
+}
+
+static void sunplus_stop_rx(struct uart_port *port)
+{
+	unsigned int isc;
+
+	isc = readl(port->membase + SUP_UART_ISC);
+	isc &= ~SUP_UART_ISC_RXM;
+	writel(isc, port->membase + SUP_UART_ISC);
+}
+
+static void sunplus_break_ctl(struct uart_port *port, int ctl)
+{
+	unsigned long flags;
+	unsigned int lcr;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	lcr = readl(port->membase + SUP_UART_LCR);
+
+	if (ctl)
+		lcr |= SUP_UART_LCR_SBC; /* start break */
+	else
+		lcr &= ~SUP_UART_LCR_SBC; /* stop break */
+
+	writel(lcr, port->membase + SUP_UART_LCR);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void transmit_chars(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->state->xmit;
+
+	if (port->x_char) {
+		sp_uart_put_char(port, port->x_char);
+		port->icount.tx++;
+		port->x_char = 0;
+		return;
+	}
+
+	if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+		sunplus_stop_tx(port);
+		return;
+	}
+
+	do {
+		sp_uart_put_char(port, xmit->buf[xmit->tail]);
+		xmit->tail = (xmit->tail + 1) % UART_XMIT_SIZE;
+		port->icount.tx++;
+
+		if (uart_circ_empty(xmit))
+			break;
+	} while (sunplus_tx_buf_not_full(port));
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+
+	if (uart_circ_empty(xmit))
+		sunplus_stop_tx(port);
+}
+
+static void receive_chars(struct uart_port *port)
+{
+	unsigned int lsr = readl(port->membase + SUP_UART_LSR);
+	unsigned int ch, flag;
+
+	do {
+		ch = readl(port->membase + SUP_UART_DATA);
+		flag = TTY_NORMAL;
+		port->icount.rx++;
+
+		if (unlikely(lsr & SUP_UART_LSR_BRK_ERROR_BITS)) {
+			if (lsr & SUP_UART_LSR_BC) {
+				lsr &= ~(SUP_UART_LSR_FE | SUP_UART_LSR_PE);
+				port->icount.brk++;
+				flag = TTY_BREAK;
+				if (uart_handle_break(port))
+					goto ignore_char;
+			} else if (lsr & SUP_UART_LSR_PE) {
+				port->icount.parity++;
+				flag = TTY_PARITY;
+			} else if (lsr & SUP_UART_LSR_FE) {
+				port->icount.frame++;
+				flag = TTY_FRAME;
+			}
+
+			if (lsr & SUP_UART_LSR_OE)
+				port->icount.overrun++;
+		}
+
+		if (port->ignore_status_mask & SUP_DUMMY_READ)
+			goto ignore_char;
+
+		if (uart_handle_sysrq_char(port, ch))
+			goto ignore_char;
+
+		uart_insert_char(port, lsr, SUP_UART_LSR_OE, ch, flag);
+
+ignore_char:
+		lsr = readl(port->membase + SUP_UART_LSR);
+	} while (lsr & SUP_UART_LSR_RX);
+
+	tty_flip_buffer_push(&port->state->port);
+}
+
+static irqreturn_t sunplus_uart_irq(int irq, void *args)
+{
+	struct uart_port *port = args;
+	unsigned int isc;
+
+	spin_lock(&port->lock);
+
+	isc = readl(port->membase + SUP_UART_ISC);
+
+	if (isc & SUP_UART_ISC_RX)
+		receive_chars(port);
+
+	if (isc & SUP_UART_ISC_TX)
+		transmit_chars(port);
+
+	spin_unlock(&port->lock);
+
+	return IRQ_HANDLED;
+}
+
+static int sunplus_startup(struct uart_port *port)
+{
+	unsigned long flags;
+	unsigned int isc;
+	int ret;
+
+	ret = request_irq(port->irq, sunplus_uart_irq, 0, "sunplus_uart", port);
+	if (ret)
+		return ret;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	isc |= SUP_UART_ISC_RXM;
+	writel(isc, port->membase + SUP_UART_ISC);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	return 0;
+}
+
+static void sunplus_shutdown(struct uart_port *port)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
+	writel(0, port->membase + SUP_UART_ISC); /* disable all interrupt */
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	free_irq(port->irq, port);
+}
+
+static void sunplus_set_termios(struct uart_port *port,
+				struct ktermios *termios,
+				struct ktermios *oldtermios)
+{
+	u32 ext, div, div_l, div_h, baud, lcr;
+	u32 clk = port->uartclk;
+	unsigned long flags;
+
+	baud = uart_get_baud_rate(port, termios, oldtermios, 0, port->uartclk / 16);
+
+	/* baud rate = uartclk / ((16 * divisor + 1) + divisor_ext) */
+	clk += baud >> 1;
+	div = clk / baud;
+	ext = div & 0x0F;
+	div = (div >> 4) - 1;
+	div_l = (div & 0xFF) | (ext << 12);
+	div_h = div >> 8;
+
+	switch (termios->c_cflag & CSIZE) {
+	case CS5:
+		lcr = UART_LCR_WLEN5;
+		break;
+	case CS6:
+		lcr = UART_LCR_WLEN6;
+		break;
+	case CS7:
+		lcr = UART_LCR_WLEN7;
+		break;
+	default:
+		lcr = UART_LCR_WLEN8;
+		break;
+	}
+
+	if (termios->c_cflag & CSTOPB)
+		lcr |= UART_LCR_STOP;
+
+	if (termios->c_cflag & PARENB) {
+		lcr |= UART_LCR_PARITY;
+
+		if (!(termios->c_cflag & PARODD))
+			lcr |= UART_LCR_EPAR;
+	}
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	uart_update_timeout(port, termios->c_cflag, baud);
+
+	port->read_status_mask = 0;
+	if (termios->c_iflag & INPCK)
+		port->read_status_mask |= SUP_UART_LSR_PE | SUP_UART_LSR_FE;
+
+	if (termios->c_iflag & (BRKINT | PARMRK))
+		port->read_status_mask |= SUP_UART_LSR_BC;
+
+	/* Characters to ignore */
+	port->ignore_status_mask = 0;
+	if (termios->c_iflag & IGNPAR)
+		port->ignore_status_mask |= SUP_UART_LSR_FE | SUP_UART_LSR_PE;
+
+	if (termios->c_iflag & IGNBRK) {
+		port->ignore_status_mask |= SUP_UART_LSR_BC;
+
+		if (termios->c_iflag & IGNPAR)
+			port->ignore_status_mask |= SUP_UART_LSR_OE;
+	}
+
+	/* Ignore all characters if CREAD is not set */
+	if ((termios->c_cflag & CREAD) == 0) {
+		port->ignore_status_mask |= SUP_DUMMY_READ;
+		/* flush rx data FIFO */
+		writel(0, port->membase + SUP_UART_RX_RESIDUE);
+	}
+
+	/* Settings for baud rate divisor and lcr */
+	writel(div_h, port->membase + SUP_UART_DIV_H);
+	writel(div_l, port->membase + SUP_UART_DIV_L);
+	writel(lcr, port->membase + SUP_UART_LCR);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void sunplus_set_ldisc(struct uart_port *port, struct ktermios *termios)
+{
+	int new = termios->c_line;
+
+	if (new == N_PPS)
+		port->flags |= UPF_HARDPPS_CD;
+	else
+		port->flags &= ~UPF_HARDPPS_CD;
+}
+
+static const char *sunplus_type(struct uart_port *port)
+{
+	return port->type == PORT_SUNPLUS ? "sunplus_uart" : NULL;
+}
+
+static void sunplus_config_port(struct uart_port *port, int type)
+{
+	if (type & UART_CONFIG_TYPE)
+		port->type = PORT_SUNPLUS;
+}
+
+static int sunplus_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+	if (ser->type != PORT_UNKNOWN && ser->type != PORT_SUNPLUS)
+		return -EINVAL;
+
+	return 0;
+}
+
+#ifdef CONFIG_SERIAL_SUNPLUS_CONSOLE
+static void wait_for_xmitr(struct uart_port *port)
+{
+	unsigned int val;
+	int ret;
+
+	/* Wait while FIFO is full or timeout */
+	ret = readl_poll_timeout_atomic(port->membase + SUP_UART_LSR, val,
+					(val & SUP_UART_LSR_TX), 1, 10000);
+
+	if (ret == -ETIMEDOUT) {
+		dev_err(port->dev, "Timeout waiting while UART TX FULL\n");
+		return;
+	}
+}
+#endif
+
+#ifdef CONFIG_CONSOLE_POLL
+static void sunplus_poll_put_char(struct uart_port *port, unsigned char data)
+{
+	wait_for_xmitr(port);
+	sp_uart_put_char(port, data);
+}
+
+static int sunplus_poll_get_char(struct uart_port *port)
+{
+	unsigned int lsr = readl(port->membase + SUP_UART_LSR);
+
+	if (!(lsr & SUP_UART_LSR_RX))
+		return NO_POLL_CHAR;
+
+	return readl(port->membase + SUP_UART_DATA);
+}
+#endif
+
+static const struct uart_ops sunplus_uart_ops = {
+	.tx_empty	= sunplus_tx_empty,
+	.set_mctrl	= sunplus_set_mctrl,
+	.get_mctrl	= sunplus_get_mctrl,
+	.stop_tx	= sunplus_stop_tx,
+	.start_tx	= sunplus_start_tx,
+	.stop_rx	= sunplus_stop_rx,
+	.break_ctl	= sunplus_break_ctl,
+	.startup	= sunplus_startup,
+	.shutdown	= sunplus_shutdown,
+	.set_termios	= sunplus_set_termios,
+	.set_ldisc	= sunplus_set_ldisc,
+	.type		= sunplus_type,
+	.config_port	= sunplus_config_port,
+	.verify_port	= sunplus_verify_port,
+#ifdef CONFIG_CONSOLE_POLL
+	.poll_put_char	= sunplus_poll_put_char,
+	.poll_get_char	= sunplus_poll_get_char,
+#endif
+};
+
+#ifdef CONFIG_SERIAL_SUNPLUS_CONSOLE
+struct sunplus_uart_port *sunplus_console_ports[SUP_UART_NR];
+
+static void sunplus_uart_console_putchar(struct uart_port *port, int ch)
+{
+	wait_for_xmitr(port);
+	sp_uart_put_char(port, ch);
+}
+
+static void sunplus_console_write(struct console *co,
+				  const char *s,
+				  unsigned int count)
+{
+	unsigned long flags;
+	int locked = 1;
+
+	local_irq_save(flags);
+
+	if (sunplus_console_ports[co->index]->port.sysrq)
+		locked = 0;
+	else if (oops_in_progress)
+		locked = spin_trylock(&sunplus_console_ports[co->index]->port.lock);
+	else
+		spin_lock(&sunplus_console_ports[co->index]->port.lock);
+
+	uart_console_write(&sunplus_console_ports[co->index]->port, s, count,
+			   sunplus_uart_console_putchar);
+
+	if (locked)
+		spin_unlock(&sunplus_console_ports[co->index]->port.lock);
+
+	local_irq_restore(flags);
+}
+
+static int __init sunplus_console_setup(struct console *co, char *options)
+{
+	struct sunplus_uart_port *sup;
+	int baud = 115200;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
+
+	if (co->index < 0 || co->index >= SUP_UART_NR)
+		return -EINVAL;
+
+	sup = sunplus_console_ports[co->index];
+	if (!sup)
+		return -ENODEV;
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+	return uart_set_options(&sup->port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver sunplus_uart_driver;
+static struct console sunplus_uart_console = {
+	.name		= "ttySUP",
+	.write		= sunplus_console_write,
+	.device		= uart_console_device,
+	.setup		= sunplus_console_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
+	.data		= &sunplus_uart_driver
+};
+
+static int __init sunplus_console_init(void)
+{
+	register_console(&sunplus_uart_console);
+	return 0;
+}
+console_initcall(sunplus_console_init);
+#endif
+
+static struct uart_driver sunplus_uart_driver = {
+	.owner		= THIS_MODULE,
+	.driver_name	= "sunplus_uart",
+	.dev_name	= "ttySUP",
+	.major		= TTY_MAJOR,
+	.minor		= 64,
+	.nr		= SUP_UART_NR,
+	.cons		= NULL,
+};
+
+static void sunplus_uart_disable_unprepare(void *data)
+{
+	clk_disable_unprepare(data);
+}
+
+static void sunplus_uart_reset_control_assert(void *data)
+{
+	reset_control_assert(data);
+}
+
+static int sunplus_uart_probe(struct platform_device *pdev)
+{
+	struct sunplus_uart_port *sup;
+	struct uart_port *port;
+	struct resource *res;
+	int ret, irq;
+
+	pdev->id = of_alias_get_id(pdev->dev.of_node, "serial");
+
+	if (pdev->id < 0 || pdev->id >= SUP_UART_NR)
+		return -EINVAL;
+
+	sup = devm_kzalloc(&pdev->dev, sizeof(*sup), GFP_KERNEL);
+	if (!sup)
+		return -ENOMEM;
+
+	sup->clk = devm_clk_get_optional(&pdev->dev, NULL);
+	if (IS_ERR(sup->clk))
+		return dev_err_probe(&pdev->dev, PTR_ERR(sup->clk), "clk not found\n");
+
+	ret = clk_prepare_enable(sup->clk);
+	if (ret)
+		return ret;
+
+	ret = devm_add_action_or_reset(&pdev->dev, sunplus_uart_disable_unprepare, sup->clk);
+	if (ret)
+		return ret;
+
+	sup->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
+	if (IS_ERR(sup->rstc))
+		return dev_err_probe(&pdev->dev, PTR_ERR(sup->rstc), "rstc not found\n");
+
+	port = &sup->port;
+
+	port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
+	if (IS_ERR(port->membase))
+		return dev_err_probe(&pdev->dev, PTR_ERR(port->membase), "membase not found\n");
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	port->mapbase = res->start;
+	port->uartclk = clk_get_rate(sup->clk);
+	port->line = pdev->id;
+	port->irq = irq;
+	port->dev = &pdev->dev;
+	port->iotype = UPIO_MEM;
+	port->ops = &sunplus_uart_ops;
+	port->flags = UPF_BOOT_AUTOCONF;
+	port->fifosize = 128;
+
+	ret = reset_control_deassert(sup->rstc);
+	if (ret)
+		return ret;
+
+	ret = devm_add_action_or_reset(&pdev->dev, sunplus_uart_reset_control_assert, sup->rstc);
+	if (ret)
+		return ret;
+
+#ifdef CONFIG_SERIAL_SUNPLUS_CONSOLE
+	sunplus_console_ports[sup->port.line] = sup;
+#endif
+
+	platform_set_drvdata(pdev, &sup->port);
+
+	ret = uart_add_one_port(&sunplus_uart_driver, &sup->port);
+#ifdef CONFIG_SERIAL_SUNPLUS_CONSOLE
+	if (ret)
+		sunplus_console_ports[sup->port.line] = NULL;
+#endif
+
+	return ret;
+}
+
+static int sunplus_uart_remove(struct platform_device *pdev)
+{
+	struct sunplus_uart_port *sup = platform_get_drvdata(pdev);
+
+	uart_remove_one_port(&sunplus_uart_driver, &sup->port);
+
+	return 0;
+}
+
+static int __maybe_unused sunplus_uart_suspend(struct device *dev)
+{
+	struct sunplus_uart_port *sup = dev_get_drvdata(dev);
+
+	if (!uart_console(&sup->port))
+		uart_suspend_port(&sunplus_uart_driver, &sup->port);
+
+	return 0;
+}
+
+static int __maybe_unused sunplus_uart_resume(struct device *dev)
+{
+	struct sunplus_uart_port *sup = dev_get_drvdata(dev);
+
+	if (!uart_console(&sup->port))
+		uart_resume_port(&sunplus_uart_driver, &sup->port);
+
+	return 0;
+}
+
+static const struct dev_pm_ops sunplus_uart_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(sunplus_uart_suspend, sunplus_uart_resume)
+};
+
+static const struct of_device_id sp_uart_of_match[] = {
+	{ .compatible = "sunplus,sp7021-uart" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, sp_uart_of_match);
+
+static struct platform_driver sunplus_uart_platform_driver = {
+	.probe		= sunplus_uart_probe,
+	.remove		= sunplus_uart_remove,
+	.driver = {
+		.name	= "sunplus_uart",
+		.of_match_table = sp_uart_of_match,
+		.pm     = &sunplus_uart_pm_ops,
+	}
+};
+
+static int __init sunplus_uart_init(void)
+{
+	int ret;
+
+#ifdef CONFIG_SERIAL_SUNPLUS_CONSOLE
+	sunplus_uart_driver.cons = &sunplus_uart_console;
+#endif
+
+	ret = uart_register_driver(&sunplus_uart_driver);
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&sunplus_uart_platform_driver);
+	if (ret)
+		uart_unregister_driver(&sunplus_uart_driver);
+
+	return ret;
+}
+module_init(sunplus_uart_init);
+
+static void __exit sunplus_uart_exit(void)
+{
+	platform_driver_unregister(&sunplus_uart_platform_driver);
+	uart_unregister_driver(&sunplus_uart_driver);
+}
+module_exit(sunplus_uart_exit);
+
+#ifdef CONFIG_SERIAL_EARLYCON
+static void sunplus_uart_putc(struct uart_port *port, int c)
+{
+	unsigned int val;
+	int ret;
+
+	ret = readl_poll_timeout_atomic(port->membase + SUP_UART_LSR, val,
+					(val & UART_LSR_TEMT), 1, 10000);
+	if (ret)
+		return;
+
+	writel(c, port->membase + SUP_UART_DATA);
+}
+
+static void sunplus_uart_early_write(struct console *con, const char *s, unsigned int n)
+{
+	struct earlycon_device *dev = con->data;
+
+	uart_console_write(&dev->port, s, n, sunplus_uart_putc);
+}
+
+static int __init
+sunplus_uart_early_setup(struct earlycon_device *dev, const char *opt)
+{
+	if (!(dev->port.membase || dev->port.iobase))
+		return -ENODEV;
+
+	dev->con->write = sunplus_uart_early_write;
+
+	return 0;
+}
+OF_EARLYCON_DECLARE(sunplus_uart, "sunplus,sp7021-uart", sunplus_uart_early_setup);
+#endif
+
+MODULE_DESCRIPTION("Sunplus UART driver");
+MODULE_AUTHOR("Hammer Hsieh <hammerh0314@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
index c4042dc..2dfe443 100644
--- a/include/uapi/linux/serial_core.h
+++ b/include/uapi/linux/serial_core.h
@@ -274,4 +274,7 @@
 /* Freescale LINFlexD UART */
 #define PORT_LINFLEXUART	122
 
+/* Sunplus UART */
+#define PORT_SUNPLUS	123
+
 #endif /* _UAPILINUX_SERIAL_CORE_H */
-- 
2.7.4


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

* Re: [PATCH v8 2/2] serial:sunplus-uart:Add Sunplus SoC UART Driver
  2022-02-15  9:24 ` [PATCH v8 2/2] serial:sunplus-uart:Add " Hammer Hsieh
@ 2022-02-15 12:45   ` kernel test robot
  2022-02-16  3:59     ` kernel test robot
  1 sibling, 0 replies; 8+ messages in thread
From: kernel test robot @ 2022-02-15 12:45 UTC (permalink / raw)
  To: kbuild-all

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

Hi Hammer,

I love your patch! Yet something to improve:

[auto build test ERROR on linux/master]
[cannot apply to tty/tty-testing robh/for-next linus/master v5.17-rc4 next-20220215]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Hammer-Hsieh/Add-UART-driver-for-Suplus-SP7021-SoC/20220215-172535
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 2c271fe77d52a0555161926c232cd5bc07178b39
config: sh-allmodconfig (https://download.01.org/0day-ci/archive/20220215/202202152052.4RCALWQy-lkp(a)intel.com/config)
compiler: sh4-linux-gcc (GCC) 11.2.0
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # https://github.com/0day-ci/linux/commit/acb196db041b9bf489d6378ffb63751070deea90
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Hammer-Hsieh/Add-UART-driver-for-Suplus-SP7021-SoC/20220215-172535
        git checkout acb196db041b9bf489d6378ffb63751070deea90
        # save the config file to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=sh SHELL=/bin/bash drivers/tty/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All errors (new ones prefixed by >>):

   In file included from drivers/tty/serial/sunplus-uart.c:25:
>> include/linux/module.h:131:49: error: redefinition of '__inittest'
     131 |         static inline initcall_t __maybe_unused __inittest(void)                \
         |                                                 ^~~~~~~~~~
   drivers/tty/serial/sunplus-uart.c:731:1: note: in expansion of macro 'module_init'
     731 | module_init(sunplus_uart_init);
         | ^~~~~~~~~~~
   include/linux/module.h:131:49: note: previous definition of '__inittest' with type 'int (*(void))(void)'
     131 |         static inline initcall_t __maybe_unused __inittest(void)                \
         |                                                 ^~~~~~~~~~
   include/linux/module.h:127:41: note: in expansion of macro 'module_init'
     127 | #define console_initcall(fn)            module_init(fn)
         |                                         ^~~~~~~~~~~
   drivers/tty/serial/sunplus-uart.c:566:1: note: in expansion of macro 'console_initcall'
     566 | console_initcall(sunplus_console_init);
         | ^~~~~~~~~~~~~~~~
>> include/linux/module.h:133:13: error: redefinition of 'init_module'
     133 |         int init_module(void) __copy(initfn)                    \
         |             ^~~~~~~~~~~
   drivers/tty/serial/sunplus-uart.c:731:1: note: in expansion of macro 'module_init'
     731 | module_init(sunplus_uart_init);
         | ^~~~~~~~~~~
   include/linux/module.h:133:13: note: previous definition of 'init_module' with type 'int(void)'
     133 |         int init_module(void) __copy(initfn)                    \
         |             ^~~~~~~~~~~
   include/linux/module.h:127:41: note: in expansion of macro 'module_init'
     127 | #define console_initcall(fn)            module_init(fn)
         |                                         ^~~~~~~~~~~
   drivers/tty/serial/sunplus-uart.c:566:1: note: in expansion of macro 'console_initcall'
     566 | console_initcall(sunplus_console_init);
         | ^~~~~~~~~~~~~~~~


vim +/__inittest +131 include/linux/module.h

0fd972a7d91d6e Paul Gortmaker 2015-05-01  128  
0fd972a7d91d6e Paul Gortmaker 2015-05-01  129  /* Each module must use one module_init(). */
0fd972a7d91d6e Paul Gortmaker 2015-05-01  130  #define module_init(initfn)					\
1f318a8bafcfba Arnd Bergmann  2017-02-01 @131  	static inline initcall_t __maybe_unused __inittest(void)		\
0fd972a7d91d6e Paul Gortmaker 2015-05-01  132  	{ return initfn; }					\
cf68fffb66d60d Sami Tolvanen  2021-04-08 @133  	int init_module(void) __copy(initfn)			\
cf68fffb66d60d Sami Tolvanen  2021-04-08  134  		__attribute__((alias(#initfn)));		\
cf68fffb66d60d Sami Tolvanen  2021-04-08  135  	__CFI_ADDRESSABLE(init_module, __initdata);
0fd972a7d91d6e Paul Gortmaker 2015-05-01  136  

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

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

* Re: [PATCH v8 1/2] dt-bindings:serial:Add bindings doc for Sunplus SoC UART Driver
  2022-02-15  9:24 ` [PATCH v8 1/2] dt-bindings:serial:Add bindings doc for Sunplus SoC UART Driver Hammer Hsieh
@ 2022-02-15 14:53   ` Krzysztof Kozlowski
  2022-02-16  1:51     ` hammer hsieh
  0 siblings, 1 reply; 8+ messages in thread
From: Krzysztof Kozlowski @ 2022-02-15 14:53 UTC (permalink / raw)
  To: Hammer Hsieh, gregkh, robh+dt, linux-serial, devicetree,
	linux-kernel, jirislaby, p.zabel
  Cc: wells.lu, hammer.hsieh

On 15/02/2022 10:24, Hammer Hsieh wrote:
> Add bindings doc for Sunplus SoC UART Driver
> 
> Reviewed-by: Rob Herring <robh@kernel.org>
> Signed-off-by: Hammer Hsieh <hammerh0314@gmail.com>
> ---
> Changes in v8:
>  - no change.
> 
>  .../bindings/serial/sunplus,sp7021-uart.yaml       | 56 ++++++++++++++++++++++
>  MAINTAINERS                                        |  5 ++
>  2 files changed, 61 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/serial/sunplus,sp7021-uart.yaml
> 
> diff --git a/Documentation/devicetree/bindings/serial/sunplus,sp7021-uart.yaml b/Documentation/devicetree/bindings/serial/sunplus,sp7021-uart.yaml
> new file mode 100644
> index 0000000..894324c
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/serial/sunplus,sp7021-uart.yaml
> @@ -0,0 +1,56 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +# Copyright (C) Sunplus Co., Ltd. 2021
> +%YAML 1.2
> +---
> +$id: "http://devicetree.org/schemas/serial/sunplus,sp7021-uart.yaml#"
> +$schema: "http://devicetree.org/meta-schemas/core.yaml#"
> +
> +title: Sunplus SoC SP7021 UART Controller Device Tree Bindings
> +
> +maintainers:
> +  - Hammer Hsieh <hammerh0314@gmail.com>
> +
> +allOf:
> +  - $ref: serial.yaml#
> +
> +properties:
> +  compatible:
> +    const: sunplus,sp7021-uart
> +
> +  reg:
> +    maxItems: 1
> +
> +  interrupts:
> +    maxItems: 1
> +
> +  clocks:
> +    maxItems: 1
> +
> +  resets:
> +    maxItems: 1
> +
> +required:
> +  - compatible
> +  - reg
> +  - interrupts
> +  - clocks
> +  - resets
> +
> +additionalProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/interrupt-controller/irq.h>
> +    aliases {
> +            serial0 = &uart0;

Incorrect indentation. With this fixed:

Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>


Best regards,
Krzysztof

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

* Re: [PATCH v8 1/2] dt-bindings:serial:Add bindings doc for Sunplus SoC UART Driver
  2022-02-15 14:53   ` Krzysztof Kozlowski
@ 2022-02-16  1:51     ` hammer hsieh
  0 siblings, 0 replies; 8+ messages in thread
From: hammer hsieh @ 2022-02-16  1:51 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: Greg KH, robh+dt, linux-serial, devicetree, linux-kernel,
	Jiri Slaby, p.zabel, wells.lu, hammer.hsieh

Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com> 於 2022年2月15日
週二 下午10:53寫道:
>
> On 15/02/2022 10:24, Hammer Hsieh wrote:
> > Add bindings doc for Sunplus SoC UART Driver
> >
> > Reviewed-by: Rob Herring <robh@kernel.org>
> > Signed-off-by: Hammer Hsieh <hammerh0314@gmail.com>
> > ---
> > Changes in v8:
> >  - no change.
> >
> >  .../bindings/serial/sunplus,sp7021-uart.yaml       | 56 ++++++++++++++++++++++
> >  MAINTAINERS                                        |  5 ++
> >  2 files changed, 61 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/serial/sunplus,sp7021-uart.yaml
> >
> > diff --git a/Documentation/devicetree/bindings/serial/sunplus,sp7021-uart.yaml b/Documentation/devicetree/bindings/serial/sunplus,sp7021-uart.yaml
> > new file mode 100644
> > index 0000000..894324c
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/serial/sunplus,sp7021-uart.yaml
> > @@ -0,0 +1,56 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +# Copyright (C) Sunplus Co., Ltd. 2021
> > +%YAML 1.2
> > +---
> > +$id: "http://devicetree.org/schemas/serial/sunplus,sp7021-uart.yaml#"
> > +$schema: "http://devicetree.org/meta-schemas/core.yaml#"
> > +
> > +title: Sunplus SoC SP7021 UART Controller Device Tree Bindings
> > +
> > +maintainers:
> > +  - Hammer Hsieh <hammerh0314@gmail.com>
> > +
> > +allOf:
> > +  - $ref: serial.yaml#
> > +
> > +properties:
> > +  compatible:
> > +    const: sunplus,sp7021-uart
> > +
> > +  reg:
> > +    maxItems: 1
> > +
> > +  interrupts:
> > +    maxItems: 1
> > +
> > +  clocks:
> > +    maxItems: 1
> > +
> > +  resets:
> > +    maxItems: 1
> > +
> > +required:
> > +  - compatible
> > +  - reg
> > +  - interrupts
> > +  - clocks
> > +  - resets
> > +
> > +additionalProperties: false
> > +
> > +examples:
> > +  - |
> > +    #include <dt-bindings/interrupt-controller/irq.h>
> > +    aliases {
> > +            serial0 = &uart0;
>
> Incorrect indentation. With this fixed:
>
> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
>
>
> Best regards,
> Krzysztof

OK, will modify it. Thanks.

Regards,
Hammer

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

* Re: [PATCH v8 2/2] serial:sunplus-uart:Add Sunplus SoC UART Driver
  2022-02-15  9:24 ` [PATCH v8 2/2] serial:sunplus-uart:Add " Hammer Hsieh
@ 2022-02-16  3:59     ` kernel test robot
  2022-02-16  3:59     ` kernel test robot
  1 sibling, 0 replies; 8+ messages in thread
From: kernel test robot @ 2022-02-16  3:59 UTC (permalink / raw)
  To: Hammer Hsieh; +Cc: llvm, kbuild-all

Hi Hammer,

I love your patch! Perhaps something to improve:

[auto build test WARNING on linux/master]
[cannot apply to tty/tty-testing robh/for-next linus/master v5.17-rc4 next-20220215]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Hammer-Hsieh/Add-UART-driver-for-Suplus-SP7021-SoC/20220215-172535
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 2c271fe77d52a0555161926c232cd5bc07178b39
config: arm64-buildonly-randconfig-r003-20220216 (https://download.01.org/0day-ci/archive/20220216/202202161113.516ledjy-lkp@intel.com/config)
compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project 0e628a783b935c70c80815db6c061ec84f884af5)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install arm64 cross compiling tool for clang build
        # apt-get install binutils-aarch64-linux-gnu
        # https://github.com/0day-ci/linux/commit/acb196db041b9bf489d6378ffb63751070deea90
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Hammer-Hsieh/Add-UART-driver-for-Suplus-SP7021-SoC/20220215-172535
        git checkout acb196db041b9bf489d6378ffb63751070deea90
        # save the config file to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=arm64 SHELL=/bin/bash drivers/tty/serial/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

>> drivers/tty/serial/sunplus-uart.c:139:3: warning: variable 'ret' is uninitialized when used here [-Wuninitialized]
                   ret |= TIOCM_DTR;
                   ^~~
   drivers/tty/serial/sunplus-uart.c:134:18: note: initialize the variable 'ret' to silence this warning
           unsigned int ret, mcr;
                           ^
                            = 0
>> drivers/tty/serial/sunplus-uart.c:310:2: warning: variable 'isc' is uninitialized when used here [-Wuninitialized]
           isc |= SUP_UART_ISC_RXM;
           ^~~
   drivers/tty/serial/sunplus-uart.c:301:18: note: initialize the variable 'isc' to silence this warning
           unsigned int isc;
                           ^
                            = 0
   2 warnings generated.


vim +/ret +139 drivers/tty/serial/sunplus-uart.c

   131	
   132	static unsigned int sunplus_get_mctrl(struct uart_port *port)
   133	{
   134		unsigned int ret, mcr;
   135	
   136		mcr = readl(port->membase + SUP_UART_MCR);
   137	
   138		if (mcr & UART_MCR_DTR)
 > 139			ret |= TIOCM_DTR;
   140	
   141		if (mcr & UART_MCR_RTS)
   142			ret |= TIOCM_RTS;
   143	
   144		if (mcr & SUP_UART_MCR_DCD)
   145			ret |= TIOCM_CAR;
   146	
   147		if (mcr & SUP_UART_MCR_RI)
   148			ret |= TIOCM_RI;
   149	
   150		if (mcr & UART_MCR_LOOP)
   151			ret |= TIOCM_LOOP;
   152	
   153		return ret;
   154	}
   155	
   156	static void sunplus_stop_tx(struct uart_port *port)
   157	{
   158		unsigned int isc;
   159	
   160		isc = readl(port->membase + SUP_UART_ISC);
   161		isc &= ~SUP_UART_ISC_TXM;
   162		writel(isc, port->membase + SUP_UART_ISC);
   163	}
   164	
   165	static void sunplus_start_tx(struct uart_port *port)
   166	{
   167		unsigned int isc;
   168	
   169		isc = readl(port->membase + SUP_UART_ISC);
   170		isc |= SUP_UART_ISC_TXM;
   171		writel(isc, port->membase + SUP_UART_ISC);
   172	}
   173	
   174	static void sunplus_stop_rx(struct uart_port *port)
   175	{
   176		unsigned int isc;
   177	
   178		isc = readl(port->membase + SUP_UART_ISC);
   179		isc &= ~SUP_UART_ISC_RXM;
   180		writel(isc, port->membase + SUP_UART_ISC);
   181	}
   182	
   183	static void sunplus_break_ctl(struct uart_port *port, int ctl)
   184	{
   185		unsigned long flags;
   186		unsigned int lcr;
   187	
   188		spin_lock_irqsave(&port->lock, flags);
   189	
   190		lcr = readl(port->membase + SUP_UART_LCR);
   191	
   192		if (ctl)
   193			lcr |= SUP_UART_LCR_SBC; /* start break */
   194		else
   195			lcr &= ~SUP_UART_LCR_SBC; /* stop break */
   196	
   197		writel(lcr, port->membase + SUP_UART_LCR);
   198	
   199		spin_unlock_irqrestore(&port->lock, flags);
   200	}
   201	
   202	static void transmit_chars(struct uart_port *port)
   203	{
   204		struct circ_buf *xmit = &port->state->xmit;
   205	
   206		if (port->x_char) {
   207			sp_uart_put_char(port, port->x_char);
   208			port->icount.tx++;
   209			port->x_char = 0;
   210			return;
   211		}
   212	
   213		if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
   214			sunplus_stop_tx(port);
   215			return;
   216		}
   217	
   218		do {
   219			sp_uart_put_char(port, xmit->buf[xmit->tail]);
   220			xmit->tail = (xmit->tail + 1) % UART_XMIT_SIZE;
   221			port->icount.tx++;
   222	
   223			if (uart_circ_empty(xmit))
   224				break;
   225		} while (sunplus_tx_buf_not_full(port));
   226	
   227		if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
   228			uart_write_wakeup(port);
   229	
   230		if (uart_circ_empty(xmit))
   231			sunplus_stop_tx(port);
   232	}
   233	
   234	static void receive_chars(struct uart_port *port)
   235	{
   236		unsigned int lsr = readl(port->membase + SUP_UART_LSR);
   237		unsigned int ch, flag;
   238	
   239		do {
   240			ch = readl(port->membase + SUP_UART_DATA);
   241			flag = TTY_NORMAL;
   242			port->icount.rx++;
   243	
   244			if (unlikely(lsr & SUP_UART_LSR_BRK_ERROR_BITS)) {
   245				if (lsr & SUP_UART_LSR_BC) {
   246					lsr &= ~(SUP_UART_LSR_FE | SUP_UART_LSR_PE);
   247					port->icount.brk++;
   248					flag = TTY_BREAK;
   249					if (uart_handle_break(port))
   250						goto ignore_char;
   251				} else if (lsr & SUP_UART_LSR_PE) {
   252					port->icount.parity++;
   253					flag = TTY_PARITY;
   254				} else if (lsr & SUP_UART_LSR_FE) {
   255					port->icount.frame++;
   256					flag = TTY_FRAME;
   257				}
   258	
   259				if (lsr & SUP_UART_LSR_OE)
   260					port->icount.overrun++;
   261			}
   262	
   263			if (port->ignore_status_mask & SUP_DUMMY_READ)
   264				goto ignore_char;
   265	
   266			if (uart_handle_sysrq_char(port, ch))
   267				goto ignore_char;
   268	
   269			uart_insert_char(port, lsr, SUP_UART_LSR_OE, ch, flag);
   270	
   271	ignore_char:
   272			lsr = readl(port->membase + SUP_UART_LSR);
   273		} while (lsr & SUP_UART_LSR_RX);
   274	
   275		tty_flip_buffer_push(&port->state->port);
   276	}
   277	
   278	static irqreturn_t sunplus_uart_irq(int irq, void *args)
   279	{
   280		struct uart_port *port = args;
   281		unsigned int isc;
   282	
   283		spin_lock(&port->lock);
   284	
   285		isc = readl(port->membase + SUP_UART_ISC);
   286	
   287		if (isc & SUP_UART_ISC_RX)
   288			receive_chars(port);
   289	
   290		if (isc & SUP_UART_ISC_TX)
   291			transmit_chars(port);
   292	
   293		spin_unlock(&port->lock);
   294	
   295		return IRQ_HANDLED;
   296	}
   297	
   298	static int sunplus_startup(struct uart_port *port)
   299	{
   300		unsigned long flags;
   301		unsigned int isc;
   302		int ret;
   303	
   304		ret = request_irq(port->irq, sunplus_uart_irq, 0, "sunplus_uart", port);
   305		if (ret)
   306			return ret;
   307	
   308		spin_lock_irqsave(&port->lock, flags);
   309	
 > 310		isc |= SUP_UART_ISC_RXM;
   311		writel(isc, port->membase + SUP_UART_ISC);
   312	
   313		spin_unlock_irqrestore(&port->lock, flags);
   314	
   315		return 0;
   316	}
   317	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

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

* Re: [PATCH v8 2/2] serial:sunplus-uart:Add Sunplus SoC UART Driver
@ 2022-02-16  3:59     ` kernel test robot
  0 siblings, 0 replies; 8+ messages in thread
From: kernel test robot @ 2022-02-16  3:59 UTC (permalink / raw)
  To: kbuild-all

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

Hi Hammer,

I love your patch! Perhaps something to improve:

[auto build test WARNING on linux/master]
[cannot apply to tty/tty-testing robh/for-next linus/master v5.17-rc4 next-20220215]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Hammer-Hsieh/Add-UART-driver-for-Suplus-SP7021-SoC/20220215-172535
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 2c271fe77d52a0555161926c232cd5bc07178b39
config: arm64-buildonly-randconfig-r003-20220216 (https://download.01.org/0day-ci/archive/20220216/202202161113.516ledjy-lkp(a)intel.com/config)
compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project 0e628a783b935c70c80815db6c061ec84f884af5)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install arm64 cross compiling tool for clang build
        # apt-get install binutils-aarch64-linux-gnu
        # https://github.com/0day-ci/linux/commit/acb196db041b9bf489d6378ffb63751070deea90
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Hammer-Hsieh/Add-UART-driver-for-Suplus-SP7021-SoC/20220215-172535
        git checkout acb196db041b9bf489d6378ffb63751070deea90
        # save the config file to linux build tree
        mkdir build_dir
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=arm64 SHELL=/bin/bash drivers/tty/serial/

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

>> drivers/tty/serial/sunplus-uart.c:139:3: warning: variable 'ret' is uninitialized when used here [-Wuninitialized]
                   ret |= TIOCM_DTR;
                   ^~~
   drivers/tty/serial/sunplus-uart.c:134:18: note: initialize the variable 'ret' to silence this warning
           unsigned int ret, mcr;
                           ^
                            = 0
>> drivers/tty/serial/sunplus-uart.c:310:2: warning: variable 'isc' is uninitialized when used here [-Wuninitialized]
           isc |= SUP_UART_ISC_RXM;
           ^~~
   drivers/tty/serial/sunplus-uart.c:301:18: note: initialize the variable 'isc' to silence this warning
           unsigned int isc;
                           ^
                            = 0
   2 warnings generated.


vim +/ret +139 drivers/tty/serial/sunplus-uart.c

   131	
   132	static unsigned int sunplus_get_mctrl(struct uart_port *port)
   133	{
   134		unsigned int ret, mcr;
   135	
   136		mcr = readl(port->membase + SUP_UART_MCR);
   137	
   138		if (mcr & UART_MCR_DTR)
 > 139			ret |= TIOCM_DTR;
   140	
   141		if (mcr & UART_MCR_RTS)
   142			ret |= TIOCM_RTS;
   143	
   144		if (mcr & SUP_UART_MCR_DCD)
   145			ret |= TIOCM_CAR;
   146	
   147		if (mcr & SUP_UART_MCR_RI)
   148			ret |= TIOCM_RI;
   149	
   150		if (mcr & UART_MCR_LOOP)
   151			ret |= TIOCM_LOOP;
   152	
   153		return ret;
   154	}
   155	
   156	static void sunplus_stop_tx(struct uart_port *port)
   157	{
   158		unsigned int isc;
   159	
   160		isc = readl(port->membase + SUP_UART_ISC);
   161		isc &= ~SUP_UART_ISC_TXM;
   162		writel(isc, port->membase + SUP_UART_ISC);
   163	}
   164	
   165	static void sunplus_start_tx(struct uart_port *port)
   166	{
   167		unsigned int isc;
   168	
   169		isc = readl(port->membase + SUP_UART_ISC);
   170		isc |= SUP_UART_ISC_TXM;
   171		writel(isc, port->membase + SUP_UART_ISC);
   172	}
   173	
   174	static void sunplus_stop_rx(struct uart_port *port)
   175	{
   176		unsigned int isc;
   177	
   178		isc = readl(port->membase + SUP_UART_ISC);
   179		isc &= ~SUP_UART_ISC_RXM;
   180		writel(isc, port->membase + SUP_UART_ISC);
   181	}
   182	
   183	static void sunplus_break_ctl(struct uart_port *port, int ctl)
   184	{
   185		unsigned long flags;
   186		unsigned int lcr;
   187	
   188		spin_lock_irqsave(&port->lock, flags);
   189	
   190		lcr = readl(port->membase + SUP_UART_LCR);
   191	
   192		if (ctl)
   193			lcr |= SUP_UART_LCR_SBC; /* start break */
   194		else
   195			lcr &= ~SUP_UART_LCR_SBC; /* stop break */
   196	
   197		writel(lcr, port->membase + SUP_UART_LCR);
   198	
   199		spin_unlock_irqrestore(&port->lock, flags);
   200	}
   201	
   202	static void transmit_chars(struct uart_port *port)
   203	{
   204		struct circ_buf *xmit = &port->state->xmit;
   205	
   206		if (port->x_char) {
   207			sp_uart_put_char(port, port->x_char);
   208			port->icount.tx++;
   209			port->x_char = 0;
   210			return;
   211		}
   212	
   213		if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
   214			sunplus_stop_tx(port);
   215			return;
   216		}
   217	
   218		do {
   219			sp_uart_put_char(port, xmit->buf[xmit->tail]);
   220			xmit->tail = (xmit->tail + 1) % UART_XMIT_SIZE;
   221			port->icount.tx++;
   222	
   223			if (uart_circ_empty(xmit))
   224				break;
   225		} while (sunplus_tx_buf_not_full(port));
   226	
   227		if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
   228			uart_write_wakeup(port);
   229	
   230		if (uart_circ_empty(xmit))
   231			sunplus_stop_tx(port);
   232	}
   233	
   234	static void receive_chars(struct uart_port *port)
   235	{
   236		unsigned int lsr = readl(port->membase + SUP_UART_LSR);
   237		unsigned int ch, flag;
   238	
   239		do {
   240			ch = readl(port->membase + SUP_UART_DATA);
   241			flag = TTY_NORMAL;
   242			port->icount.rx++;
   243	
   244			if (unlikely(lsr & SUP_UART_LSR_BRK_ERROR_BITS)) {
   245				if (lsr & SUP_UART_LSR_BC) {
   246					lsr &= ~(SUP_UART_LSR_FE | SUP_UART_LSR_PE);
   247					port->icount.brk++;
   248					flag = TTY_BREAK;
   249					if (uart_handle_break(port))
   250						goto ignore_char;
   251				} else if (lsr & SUP_UART_LSR_PE) {
   252					port->icount.parity++;
   253					flag = TTY_PARITY;
   254				} else if (lsr & SUP_UART_LSR_FE) {
   255					port->icount.frame++;
   256					flag = TTY_FRAME;
   257				}
   258	
   259				if (lsr & SUP_UART_LSR_OE)
   260					port->icount.overrun++;
   261			}
   262	
   263			if (port->ignore_status_mask & SUP_DUMMY_READ)
   264				goto ignore_char;
   265	
   266			if (uart_handle_sysrq_char(port, ch))
   267				goto ignore_char;
   268	
   269			uart_insert_char(port, lsr, SUP_UART_LSR_OE, ch, flag);
   270	
   271	ignore_char:
   272			lsr = readl(port->membase + SUP_UART_LSR);
   273		} while (lsr & SUP_UART_LSR_RX);
   274	
   275		tty_flip_buffer_push(&port->state->port);
   276	}
   277	
   278	static irqreturn_t sunplus_uart_irq(int irq, void *args)
   279	{
   280		struct uart_port *port = args;
   281		unsigned int isc;
   282	
   283		spin_lock(&port->lock);
   284	
   285		isc = readl(port->membase + SUP_UART_ISC);
   286	
   287		if (isc & SUP_UART_ISC_RX)
   288			receive_chars(port);
   289	
   290		if (isc & SUP_UART_ISC_TX)
   291			transmit_chars(port);
   292	
   293		spin_unlock(&port->lock);
   294	
   295		return IRQ_HANDLED;
   296	}
   297	
   298	static int sunplus_startup(struct uart_port *port)
   299	{
   300		unsigned long flags;
   301		unsigned int isc;
   302		int ret;
   303	
   304		ret = request_irq(port->irq, sunplus_uart_irq, 0, "sunplus_uart", port);
   305		if (ret)
   306			return ret;
   307	
   308		spin_lock_irqsave(&port->lock, flags);
   309	
 > 310		isc |= SUP_UART_ISC_RXM;
   311		writel(isc, port->membase + SUP_UART_ISC);
   312	
   313		spin_unlock_irqrestore(&port->lock, flags);
   314	
   315		return 0;
   316	}
   317	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

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

end of thread, other threads:[~2022-02-16  3:59 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-02-15  9:24 [PATCH v8 0/2] Add UART driver for Suplus SP7021 SoC Hammer Hsieh
2022-02-15  9:24 ` [PATCH v8 1/2] dt-bindings:serial:Add bindings doc for Sunplus SoC UART Driver Hammer Hsieh
2022-02-15 14:53   ` Krzysztof Kozlowski
2022-02-16  1:51     ` hammer hsieh
2022-02-15  9:24 ` [PATCH v8 2/2] serial:sunplus-uart:Add " Hammer Hsieh
2022-02-15 12:45   ` kernel test robot
2022-02-16  3:59   ` kernel test robot
2022-02-16  3:59     ` kernel test robot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.