All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6 0/2] Add UART driver for Suplus SP7021 SoC
@ 2022-01-12  9:24 Hammer Hsieh
  2022-01-12  9:24 ` [PATCH v6 1/2] dt-bindings:serial:Add bindings doc for Sunplus SoC UART Driver Hammer Hsieh
  2022-01-12  9:24 ` [PATCH v6 2/2] serial:sunplus-uart:Add " Hammer Hsieh
  0 siblings, 2 replies; 13+ messages in thread
From: Hammer Hsieh @ 2022-01-12  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                  | 756 +++++++++++++++++++++
 include/uapi/linux/serial_core.h                   |   3 +
 6 files changed, 847 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] 13+ messages in thread

* [PATCH v6 1/2] dt-bindings:serial:Add bindings doc for Sunplus SoC UART Driver
  2022-01-12  9:24 [PATCH v6 0/2] Add UART driver for Suplus SP7021 SoC Hammer Hsieh
@ 2022-01-12  9:24 ` Hammer Hsieh
  2022-01-12  9:24 ` [PATCH v6 2/2] serial:sunplus-uart:Add " Hammer Hsieh
  1 sibling, 0 replies; 13+ messages in thread
From: Hammer Hsieh @ 2022-01-12  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 v6:
 - modify author mail match Signed-off-by.

 .../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] 13+ messages in thread

* [PATCH v6 2/2] serial:sunplus-uart:Add Sunplus SoC UART Driver
  2022-01-12  9:24 [PATCH v6 0/2] Add UART driver for Suplus SP7021 SoC Hammer Hsieh
  2022-01-12  9:24 ` [PATCH v6 1/2] dt-bindings:serial:Add bindings doc for Sunplus SoC UART Driver Hammer Hsieh
@ 2022-01-12  9:24 ` Hammer Hsieh
  2022-01-12 10:51   ` kernel test robot
                     ` (2 more replies)
  1 sibling, 3 replies; 13+ messages in thread
From: Hammer Hsieh @ 2022-01-12  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

Signed-off-by: Hammer Hsieh <hammerh0314@gmail.com>
---
Changes in v6:
 - Addressed all comments from Jiri Slaby and Greg KH.

 MAINTAINERS                       |   1 +
 drivers/tty/serial/Kconfig        |  25 ++
 drivers/tty/serial/Makefile       |   1 +
 drivers/tty/serial/sunplus-uart.c | 756 ++++++++++++++++++++++++++++++++++++++
 include/uapi/linux/serial_core.h  |   3 +
 5 files changed, 786 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..8b7306d
--- /dev/null
+++ b/drivers/tty/serial/sunplus-uart.c
@@ -0,0 +1,756 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Sunplus SoC UART driver
+ *
+ * Author: Hammer Hsieh <hammerh0314@gmail.com>
+ */
+#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);
+	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_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 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;
+	}
+}
+
+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 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,
+				       (void(*)(void *))clk_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,
+				       (void(*)(void *))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 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 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] 13+ messages in thread

* Re: [PATCH v6 2/2] serial:sunplus-uart:Add Sunplus SoC UART Driver
  2022-01-12  9:24 ` [PATCH v6 2/2] serial:sunplus-uart:Add " Hammer Hsieh
@ 2022-01-12 10:51   ` kernel test robot
  2022-01-12 11:31   ` kernel test robot
  2022-01-13  7:06   ` Jiri Slaby
  2 siblings, 0 replies; 13+ messages in thread
From: kernel test robot @ 2022-01-12 10:51 UTC (permalink / raw)
  To: kbuild-all

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

Hi Hammer,

I love your patch! Yet something to improve:

[auto build test ERROR on tty/tty-testing]
[also build test ERROR on robh/for-next linux/master linus/master v5.16]
[cannot apply to next-20220112]
[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/20220112-172542
base:   https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tty-testing
config: nios2-randconfig-m031-20220112 (https://download.01.org/0day-ci/archive/20220112/202201121800.PmWf0zhj-lkp(a)intel.com/config)
compiler: nios2-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/359e5930a7804fbe8d313226cfec1ff484c16d11
        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/20220112-172542
        git checkout 359e5930a7804fbe8d313226cfec1ff484c16d11
        # 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=nios2 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 error/warnings (new ones prefixed by >>):

   drivers/tty/serial/sunplus-uart.c: In function 'sunplus_poll_put_char':
>> drivers/tty/serial/sunplus-uart.c:430:9: error: implicit declaration of function 'wait_for_xmitr'; did you mean 'wait_on_bit'? [-Werror=implicit-function-declaration]
     430 |         wait_for_xmitr(port);
         |         ^~~~~~~~~~~~~~
         |         wait_on_bit
   drivers/tty/serial/sunplus-uart.c: In function 'sunplus_uart_probe':
>> drivers/tty/serial/sunplus-uart.c:624:40: warning: cast between incompatible function types from 'int (*)(struct reset_control *)' to 'void (*)(void *)' [-Wcast-function-type]
     624 |                                        (void(*)(void *))reset_control_assert,
         |                                        ^
   At top level:
   drivers/tty/serial/sunplus-uart.c:663:12: warning: 'sunplus_uart_resume' defined but not used [-Wunused-function]
     663 | static int sunplus_uart_resume(struct device *dev)
         |            ^~~~~~~~~~~~~~~~~~~
   drivers/tty/serial/sunplus-uart.c:653:12: warning: 'sunplus_uart_suspend' defined but not used [-Wunused-function]
     653 | static int sunplus_uart_suspend(struct device *dev)
         |            ^~~~~~~~~~~~~~~~~~~~
   cc1: some warnings being treated as errors


vim +430 drivers/tty/serial/sunplus-uart.c

   426	
   427	#ifdef CONFIG_CONSOLE_POLL
   428	static void sunplus_poll_put_char(struct uart_port *port, unsigned char data)
   429	{
 > 430		wait_for_xmitr(port);
   431		sp_uart_put_char(port, data);
   432	}
   433	
   434	static int sunplus_poll_get_char(struct uart_port *port)
   435	{
   436		unsigned int lsr = readl(port->membase + SUP_UART_LSR);
   437	
   438		if (!(lsr & SUP_UART_LSR_RX))
   439			return NO_POLL_CHAR;
   440	
   441		return readl(port->membase + SUP_UART_DATA);
   442	}
   443	#endif
   444	
   445	static const struct uart_ops sunplus_uart_ops = {
   446		.tx_empty	= sunplus_tx_empty,
   447		.set_mctrl	= sunplus_set_mctrl,
   448		.get_mctrl	= sunplus_get_mctrl,
   449		.stop_tx	= sunplus_stop_tx,
   450		.start_tx	= sunplus_start_tx,
   451		.stop_rx	= sunplus_stop_rx,
   452		.break_ctl	= sunplus_break_ctl,
   453		.startup	= sunplus_startup,
   454		.shutdown	= sunplus_shutdown,
   455		.set_termios	= sunplus_set_termios,
   456		.set_ldisc	= sunplus_set_ldisc,
   457		.type		= sunplus_type,
   458		.config_port	= sunplus_config_port,
   459		.verify_port	= sunplus_verify_port,
   460	#ifdef CONFIG_CONSOLE_POLL
   461		.poll_put_char	= sunplus_poll_put_char,
   462		.poll_get_char	= sunplus_poll_get_char,
   463	#endif
   464	};
   465	
   466	#ifdef CONFIG_SERIAL_SUNPLUS_CONSOLE
   467	struct sunplus_uart_port *sunplus_console_ports[SUP_UART_NR];
   468	
   469	static void wait_for_xmitr(struct uart_port *port)
   470	{
   471		unsigned int val;
   472		int ret;
   473	
   474		/* Wait while FIFO is full or timeout */
   475		ret = readl_poll_timeout_atomic(port->membase + SUP_UART_LSR, val,
   476						(val & SUP_UART_LSR_TX), 1, 10000);
   477	
   478		if (ret == -ETIMEDOUT) {
   479			dev_err(port->dev, "Timeout waiting while UART TX FULL\n");
   480			return;
   481		}
   482	}
   483	
   484	static void sunplus_uart_console_putchar(struct uart_port *port, int ch)
   485	{
   486		wait_for_xmitr(port);
   487		sp_uart_put_char(port, ch);
   488	}
   489	
   490	static void sunplus_console_write(struct console *co,
   491					  const char *s,
   492					  unsigned int count)
   493	{
   494		unsigned long flags;
   495		int locked = 1;
   496	
   497		local_irq_save(flags);
   498	
   499		if (sunplus_console_ports[co->index]->port.sysrq)
   500			locked = 0;
   501		else if (oops_in_progress)
   502			locked = spin_trylock(&sunplus_console_ports[co->index]->port.lock);
   503		else
   504			spin_lock(&sunplus_console_ports[co->index]->port.lock);
   505	
   506		uart_console_write(&sunplus_console_ports[co->index]->port, s, count,
   507				   sunplus_uart_console_putchar);
   508	
   509		if (locked)
   510			spin_unlock(&sunplus_console_ports[co->index]->port.lock);
   511	
   512		local_irq_restore(flags);
   513	}
   514	
   515	static int __init sunplus_console_setup(struct console *co, char *options)
   516	{
   517		struct sunplus_uart_port *sup;
   518		int baud = 115200;
   519		int bits = 8;
   520		int parity = 'n';
   521		int flow = 'n';
   522	
   523		if (co->index < 0 || co->index >= SUP_UART_NR)
   524			return -EINVAL;
   525	
   526		sup = sunplus_console_ports[co->index];
   527		if (!sup)
   528			return -ENODEV;
   529	
   530		if (options)
   531			uart_parse_options(options, &baud, &parity, &bits, &flow);
   532	
   533		return uart_set_options(&sup->port, co, baud, parity, bits, flow);
   534	}
   535	
   536	static struct uart_driver sunplus_uart_driver;
   537	static struct console sunplus_uart_console = {
   538		.name		= "ttySUP",
   539		.write		= sunplus_console_write,
   540		.device		= uart_console_device,
   541		.setup		= sunplus_console_setup,
   542		.flags		= CON_PRINTBUFFER,
   543		.index		= -1,
   544		.data		= &sunplus_uart_driver
   545	};
   546	
   547	static int __init sunplus_console_init(void)
   548	{
   549		register_console(&sunplus_uart_console);
   550		return 0;
   551	}
   552	console_initcall(sunplus_console_init);
   553	#endif
   554	
   555	static struct uart_driver sunplus_uart_driver = {
   556		.owner		= THIS_MODULE,
   557		.driver_name	= "sunplus_uart",
   558		.dev_name	= "ttySUP",
   559		.major		= TTY_MAJOR,
   560		.minor		= 64,
   561		.nr		= SUP_UART_NR,
   562		.cons		= NULL,
   563	};
   564	
   565	static int sunplus_uart_probe(struct platform_device *pdev)
   566	{
   567		struct sunplus_uart_port *sup;
   568		struct uart_port *port;
   569		struct resource *res;
   570		int ret, irq;
   571	
   572		pdev->id = of_alias_get_id(pdev->dev.of_node, "serial");
   573	
   574		if (pdev->id < 0 || pdev->id >= SUP_UART_NR)
   575			return -EINVAL;
   576	
   577		sup = devm_kzalloc(&pdev->dev, sizeof(*sup), GFP_KERNEL);
   578		if (!sup)
   579			return -ENOMEM;
   580	
   581		sup->clk = devm_clk_get_optional(&pdev->dev, NULL);
   582		if (IS_ERR(sup->clk))
   583			return dev_err_probe(&pdev->dev, PTR_ERR(sup->clk), "clk not found\n");
   584	
   585		ret = clk_prepare_enable(sup->clk);
   586		if (ret)
   587			return ret;
   588	
   589		ret = devm_add_action_or_reset(&pdev->dev,
   590					       (void(*)(void *))clk_disable_unprepare,
   591					       sup->clk);
   592		if (ret)
   593			return ret;
   594	
   595		sup->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL);
   596		if (IS_ERR(sup->rstc))
   597			return dev_err_probe(&pdev->dev, PTR_ERR(sup->rstc), "rstc not found\n");
   598	
   599		port = &sup->port;
   600	
   601		port->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
   602		if (IS_ERR(port->membase))
   603			return dev_err_probe(&pdev->dev, PTR_ERR(port->membase), "membase not found\n");
   604	
   605		irq = platform_get_irq(pdev, 0);
   606		if (irq < 0)
   607			return irq;
   608	
   609		port->mapbase = res->start;
   610		port->uartclk = clk_get_rate(sup->clk);
   611		port->line = pdev->id;
   612		port->irq = irq;
   613		port->dev = &pdev->dev;
   614		port->iotype = UPIO_MEM;
   615		port->ops = &sunplus_uart_ops;
   616		port->flags = UPF_BOOT_AUTOCONF;
   617		port->fifosize = 128;
   618	
   619		ret = reset_control_deassert(sup->rstc);
   620		if (ret)
   621			return ret;
   622	
   623		ret = devm_add_action_or_reset(&pdev->dev,
 > 624					       (void(*)(void *))reset_control_assert,
   625					       sup->rstc);
   626		if (ret)
   627			return ret;
   628	

---
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] 13+ messages in thread

* Re: [PATCH v6 2/2] serial:sunplus-uart:Add Sunplus SoC UART Driver
  2022-01-12  9:24 ` [PATCH v6 2/2] serial:sunplus-uart:Add " Hammer Hsieh
  2022-01-12 10:51   ` kernel test robot
@ 2022-01-12 11:31   ` kernel test robot
  2022-01-13  7:06   ` Jiri Slaby
  2 siblings, 0 replies; 13+ messages in thread
From: kernel test robot @ 2022-01-12 11:31 UTC (permalink / raw)
  To: kbuild-all

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

Hi Hammer,

I love your patch! Perhaps something to improve:

[auto build test WARNING on tty/tty-testing]
[also build test WARNING on robh/for-next linux/master linus/master v5.16]
[cannot apply to next-20220112]
[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/20220112-172542
base:   https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tty-testing
config: mips-allyesconfig (https://download.01.org/0day-ci/archive/20220112/202201121943.u8vGs7ty-lkp(a)intel.com/config)
compiler: mips-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/359e5930a7804fbe8d313226cfec1ff484c16d11
        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/20220112-172542
        git checkout 359e5930a7804fbe8d313226cfec1ff484c16d11
        # 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=mips 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: In function 'sunplus_poll_put_char':
   drivers/tty/serial/sunplus-uart.c:430:9: error: implicit declaration of function 'wait_for_xmitr'; did you mean 'wait_on_bit'? [-Werror=implicit-function-declaration]
     430 |         wait_for_xmitr(port);
         |         ^~~~~~~~~~~~~~
         |         wait_on_bit
   drivers/tty/serial/sunplus-uart.c: At top level:
>> drivers/tty/serial/sunplus-uart.c:469:13: warning: conflicting types for 'wait_for_xmitr'; have 'void(struct uart_port *)'
     469 | static void wait_for_xmitr(struct uart_port *port)
         |             ^~~~~~~~~~~~~~
   drivers/tty/serial/sunplus-uart.c:469:13: error: static declaration of 'wait_for_xmitr' follows non-static declaration
   drivers/tty/serial/sunplus-uart.c:430:9: note: previous implicit declaration of 'wait_for_xmitr' with type 'void(struct uart_port *)'
     430 |         wait_for_xmitr(port);
         |         ^~~~~~~~~~~~~~
   drivers/tty/serial/sunplus-uart.c: In function 'sunplus_uart_probe':
   drivers/tty/serial/sunplus-uart.c:624:40: warning: cast between incompatible function types from 'int (*)(struct reset_control *)' to 'void (*)(void *)' [-Wcast-function-type]
     624 |                                        (void(*)(void *))reset_control_assert,
         |                                        ^
   cc1: some warnings being treated as errors


vim +469 drivers/tty/serial/sunplus-uart.c

   468	
 > 469	static void wait_for_xmitr(struct uart_port *port)
   470	{
   471		unsigned int val;
   472		int ret;
   473	
   474		/* Wait while FIFO is full or timeout */
   475		ret = readl_poll_timeout_atomic(port->membase + SUP_UART_LSR, val,
   476						(val & SUP_UART_LSR_TX), 1, 10000);
   477	
   478		if (ret == -ETIMEDOUT) {
   479			dev_err(port->dev, "Timeout waiting while UART TX FULL\n");
   480			return;
   481		}
   482	}
   483	

---
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] 13+ messages in thread

* Re: [PATCH v6 2/2] serial:sunplus-uart:Add Sunplus SoC UART Driver
  2022-01-12  9:24 ` [PATCH v6 2/2] serial:sunplus-uart:Add " Hammer Hsieh
  2022-01-12 10:51   ` kernel test robot
  2022-01-12 11:31   ` kernel test robot
@ 2022-01-13  7:06   ` Jiri Slaby
  2022-01-13  8:54     ` hammer hsieh
  2 siblings, 1 reply; 13+ messages in thread
From: Jiri Slaby @ 2022-01-13  7:06 UTC (permalink / raw)
  To: Hammer Hsieh, gregkh, robh+dt, linux-serial, devicetree,
	linux-kernel, p.zabel
  Cc: wells.lu, hammer.hsieh

Hi,

On 12. 01. 22, 10:24, Hammer Hsieh wrote:
> Add Sunplus SoC UART Driver
...
> --- /dev/null
> +++ b/drivers/tty/serial/sunplus-uart.c
> @@ -0,0 +1,756 @@
...
> +/* 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 */

I just wonder why do the HW creators feel so creative to redefine the 
world...

> +static void sunplus_shutdown(struct uart_port *port)
> +{
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&port->lock, flags);
> +	writel(0, port->membase + SUP_UART_ISC);
> +	spin_unlock_irqrestore(&port->lock, flags);

I asked last time:
* What bus is this -- posting?

You replied:
* Here just clear interrupt.
* Not really understand your comment?

So I am asking again:
What bus is this? Isn't a posted write a problem here? I mean, shouldn't 
you read from the register so that the write hits the device? That 
depends on the bus this sits on, so just asking.

Other than that the driver looks much better now, i.e. LGTM.

thanks,
-- 
js
suse labs

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

* Re: [PATCH v6 2/2] serial:sunplus-uart:Add Sunplus SoC UART Driver
  2022-01-13  7:06   ` Jiri Slaby
@ 2022-01-13  8:54     ` hammer hsieh
  2022-01-13  9:08       ` Jiri Slaby
  0 siblings, 1 reply; 13+ messages in thread
From: hammer hsieh @ 2022-01-13  8:54 UTC (permalink / raw)
  To: Jiri Slaby
  Cc: Greg KH, robh+dt, linux-serial, devicetree, linux-kernel,
	p.zabel, wells.lu, hammer.hsieh

Jiri Slaby <jirislaby@kernel.org> 於 2022年1月13日 週四 下午3:06寫道:
>
> Hi,
>
> On 12. 01. 22, 10:24, Hammer Hsieh wrote:
> > Add Sunplus SoC UART Driver
> ...
> > --- /dev/null
> > +++ b/drivers/tty/serial/sunplus-uart.c
> > @@ -0,0 +1,756 @@
> ...
> > +/* 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 */
>
> I just wonder why do the HW creators feel so creative to redefine the
> world...
>

Our IC designer create it, I just try to make it work.
Indeed, before Greg KH mentioned 8250-like, I didn't realize our uart
so much like 8250.
Thanks for your review.

> > +static void sunplus_shutdown(struct uart_port *port)
> > +{
> > +     unsigned long flags;
> > +
> > +     spin_lock_irqsave(&port->lock, flags);
> > +     writel(0, port->membase + SUP_UART_ISC);
> > +     spin_unlock_irqrestore(&port->lock, flags);
>
> I asked last time:
> * What bus is this -- posting?
>
> You replied:
> * Here just clear interrupt.
> * Not really understand your comment?
>
> So I am asking again:
> What bus is this? Isn't a posted write a problem here? I mean, shouldn't
> you read from the register so that the write hits the device? That
> depends on the bus this sits on, so just asking.
>

Each UART has its own ISC register.
Ex.
dev/ttySUP0 base_adr = 0x9C00-0000 , isc_addr = 0x9C00-001C
dev/ttySUP1 base_adr = 0x9C00-0080 , isc_addr = 0x9C00-009C
dev/ttySUP2 base_adr = 0x9C00-0100 , isc_addr = 0x9C00-011C
dev/ttySUP3 base_adr = 0x9C00-0180 , isc_addr = 0x9C00-019C
dev/ttySUP4 base_adr = 0x9C00-0200 , isc_addr = 0x9C00-021C
So sunplus_shutdown() just simply turn off its own device isc only.
That's why I didn't read register value, just write 0 for it.

> Other than that the driver looks much better now, i.e. LGTM.
>
> thanks,
> --
> js
> suse labs

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

* Re: [PATCH v6 2/2] serial:sunplus-uart:Add Sunplus SoC UART Driver
  2022-01-13  8:54     ` hammer hsieh
@ 2022-01-13  9:08       ` Jiri Slaby
  2022-01-13 10:56         ` hammer hsieh
  0 siblings, 1 reply; 13+ messages in thread
From: Jiri Slaby @ 2022-01-13  9:08 UTC (permalink / raw)
  To: hammer hsieh
  Cc: Greg KH, robh+dt, linux-serial, devicetree, linux-kernel,
	p.zabel, wells.lu, hammer.hsieh

On 13. 01. 22, 9:54, hammer hsieh wrote:
>>> +static void sunplus_shutdown(struct uart_port *port)
>>> +{
>>> +     unsigned long flags;
>>> +
>>> +     spin_lock_irqsave(&port->lock, flags);
>>> +     writel(0, port->membase + SUP_UART_ISC);
>>> +     spin_unlock_irqrestore(&port->lock, flags);
>>
>> I asked last time:
>> * What bus is this -- posting?
>>
>> You replied:
>> * Here just clear interrupt.
>> * Not really understand your comment?
>>
>> So I am asking again:
>> What bus is this? Isn't a posted write a problem here? I mean, shouldn't
>> you read from the register so that the write hits the device? That
>> depends on the bus this sits on, so just asking.
>>
> 
> Each UART has its own ISC register.
> Ex.
> dev/ttySUP0 base_adr = 0x9C00-0000 , isc_addr = 0x9C00-001C
> dev/ttySUP1 base_adr = 0x9C00-0080 , isc_addr = 0x9C00-009C
> dev/ttySUP2 base_adr = 0x9C00-0100 , isc_addr = 0x9C00-011C
> dev/ttySUP3 base_adr = 0x9C00-0180 , isc_addr = 0x9C00-019C
> dev/ttySUP4 base_adr = 0x9C00-0200 , isc_addr = 0x9C00-021C
> So sunplus_shutdown() just simply turn off its own device isc only.
> That's why I didn't read register value, just write 0 for it.

Could you explain me what posted write is and how does it not matter in 
this case?

thanks,
-- 
js
suse labs

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

* Re: [PATCH v6 2/2] serial:sunplus-uart:Add Sunplus SoC UART Driver
  2022-01-13  9:08       ` Jiri Slaby
@ 2022-01-13 10:56         ` hammer hsieh
  2022-01-13 11:12           ` Jiri Slaby
  0 siblings, 1 reply; 13+ messages in thread
From: hammer hsieh @ 2022-01-13 10:56 UTC (permalink / raw)
  To: Jiri Slaby
  Cc: Greg KH, robh+dt, linux-serial, devicetree, linux-kernel,
	p.zabel, wells.lu, hammer.hsieh

Jiri Slaby <jirislaby@kernel.org> 於 2022年1月13日 週四 下午5:08寫道:
>
> On 13. 01. 22, 9:54, hammer hsieh wrote:
> >>> +static void sunplus_shutdown(struct uart_port *port)
> >>> +{
> >>> +     unsigned long flags;
> >>> +
> >>> +     spin_lock_irqsave(&port->lock, flags);
> >>> +     writel(0, port->membase + SUP_UART_ISC);
> >>> +     spin_unlock_irqrestore(&port->lock, flags);
> >>
> >> I asked last time:
> >> * What bus is this -- posting?
> >>
> >> You replied:
> >> * Here just clear interrupt.
> >> * Not really understand your comment?
> >>
> >> So I am asking again:
> >> What bus is this? Isn't a posted write a problem here? I mean, shouldn't
> >> you read from the register so that the write hits the device? That
> >> depends on the bus this sits on, so just asking.
> >>
> >
> > Each UART has its own ISC register.
> > Ex.
> > dev/ttySUP0 base_adr = 0x9C00-0000 , isc_addr = 0x9C00-001C
> > dev/ttySUP1 base_adr = 0x9C00-0080 , isc_addr = 0x9C00-009C
> > dev/ttySUP2 base_adr = 0x9C00-0100 , isc_addr = 0x9C00-011C
> > dev/ttySUP3 base_adr = 0x9C00-0180 , isc_addr = 0x9C00-019C
> > dev/ttySUP4 base_adr = 0x9C00-0200 , isc_addr = 0x9C00-021C
> > So sunplus_shutdown() just simply turn off its own device isc only.
> > That's why I didn't read register value, just write 0 for it.
>
> Could you explain me what posted write is and how does it not matter in
> this case?
>

Each UART ISC register contains

Bit7 MSM(Modem Status) INT enable / disable (Access type RW) not use
now (0: default)
Bit6 LSM(Line Status) INT  enable / disable  (Access type RW) not use
now(0: default)
Bit5 RXM INT enable / disable  (Access type RW) set this
Bit4 TXM INT enable / disable  (Access type RW) set this

Bit3 MS(Modem Status) INT flag (Access type Read only) not use now (0: default)
Bit2 LS(Line Status) INT flag (Access type Read only) not use now (0: default)
Bit1 RX INT flag (Access type Read only) read this
Bit0 TX INT flag (Access type Read only) read this

sunplus_shutdown()
main purpose is to turn off TX INT(bit4) and RX INT(bit5)
bit7 and bit6 not used, should be 0.
bit3 ~ bit0 read only, no effect while writing 0 to them.

> thanks,
> --
> js
> suse labs

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

* Re: [PATCH v6 2/2] serial:sunplus-uart:Add Sunplus SoC UART Driver
  2022-01-13 10:56         ` hammer hsieh
@ 2022-01-13 11:12           ` Jiri Slaby
  2022-01-14  2:22             ` hammer hsieh
  0 siblings, 1 reply; 13+ messages in thread
From: Jiri Slaby @ 2022-01-13 11:12 UTC (permalink / raw)
  To: hammer hsieh
  Cc: Greg KH, robh+dt, linux-serial, devicetree, linux-kernel,
	p.zabel, wells.lu, hammer.hsieh

On 13. 01. 22, 11:56, hammer hsieh wrote:
>> Could you explain me what posted write is and how does it not matter in
>> this case?
>>
> 
> Each UART ISC register contains

No, you still don't follow what I write. Use your favorite web search 
for "posted write" and/or consult with your HW team.

-- 
js
suse labs

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

* Re: [PATCH v6 2/2] serial:sunplus-uart:Add Sunplus SoC UART Driver
  2022-01-13 11:12           ` Jiri Slaby
@ 2022-01-14  2:22             ` hammer hsieh
  2022-01-26 13:47               ` Greg KH
  0 siblings, 1 reply; 13+ messages in thread
From: hammer hsieh @ 2022-01-14  2:22 UTC (permalink / raw)
  To: Jiri Slaby
  Cc: Greg KH, robh+dt, linux-serial, devicetree, linux-kernel,
	p.zabel, wells.lu, hammer.hsieh

Jiri Slaby <jirislaby@kernel.org> 於 2022年1月13日 週四 下午7:12寫道:
>
> On 13. 01. 22, 11:56, hammer hsieh wrote:
> >> Could you explain me what posted write is and how does it not matter in
> >> this case?
> >>
> >
> > Each UART ISC register contains
>
> No, you still don't follow what I write. Use your favorite web search
> for "posted write" and/or consult with your HW team.
>

Maybe this time, we are on the same page.
Our SP7021 chipset is designed on ARM Cortex-A7 Quad core.
Register Access through AMBA(AXI bus), and it is non-cached.

Did you mean
case1 have concern about "posted write", and you want to know why it not matter?
case2 will be safer?

Case1 :
spin_lock_irq_save()
writel(0, target register)
spin_unlock_irqrestore()
Case2 :
spin_lock_irq_save()
tmp = readl(target register)
tmp &= ~(bit4 | bit5)
writel(tmp, target register)
spin_unlock_irqrestore()

I test uart port with linux-serial-test tool.
Ex. send char
linux-serial-test -y 0x55 -z 0x31 -p /dev/ttySUPx -b 115200
driver will call from uart startup till uart shutdown.
And it works fine, so I didn't think about "posted write" on Register bus.

> --
> js
> suse labs

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

* Re: [PATCH v6 2/2] serial:sunplus-uart:Add Sunplus SoC UART Driver
  2022-01-14  2:22             ` hammer hsieh
@ 2022-01-26 13:47               ` Greg KH
  2022-01-28  3:36                 ` hammer hsieh
  0 siblings, 1 reply; 13+ messages in thread
From: Greg KH @ 2022-01-26 13:47 UTC (permalink / raw)
  To: hammer hsieh
  Cc: Jiri Slaby, robh+dt, linux-serial, devicetree, linux-kernel,
	p.zabel, wells.lu, hammer.hsieh

On Fri, Jan 14, 2022 at 10:22:56AM +0800, hammer hsieh wrote:
> Jiri Slaby <jirislaby@kernel.org> 於 2022年1月13日 週四 下午7:12寫道:
> >
> > On 13. 01. 22, 11:56, hammer hsieh wrote:
> > >> Could you explain me what posted write is and how does it not matter in
> > >> this case?
> > >>
> > >
> > > Each UART ISC register contains
> >
> > No, you still don't follow what I write. Use your favorite web search
> > for "posted write" and/or consult with your HW team.
> >
> 
> Maybe this time, we are on the same page.
> Our SP7021 chipset is designed on ARM Cortex-A7 Quad core.
> Register Access through AMBA(AXI bus), and it is non-cached.
> 
> Did you mean
> case1 have concern about "posted write", and you want to know why it not matter?
> case2 will be safer?
> 
> Case1 :
> spin_lock_irq_save()
> writel(0, target register)
> spin_unlock_irqrestore()

A lock does not mean that your write made it to the device.  Please talk
to the hardware designers to properly determine how to correctly write
to the hardware and "know" that the write succeeded or not.  This driver
does not seem to take that into consideration at all.

thanks,

greg k-h

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

* Re: [PATCH v6 2/2] serial:sunplus-uart:Add Sunplus SoC UART Driver
  2022-01-26 13:47               ` Greg KH
@ 2022-01-28  3:36                 ` hammer hsieh
  0 siblings, 0 replies; 13+ messages in thread
From: hammer hsieh @ 2022-01-28  3:36 UTC (permalink / raw)
  To: Greg KH
  Cc: Jiri Slaby, robh+dt, linux-serial, devicetree, linux-kernel,
	p.zabel, wells.lu, hammer.hsieh

Hi, Greg KH:

I review all driver again.
I think only startup and shutdown not good.
I will modify like below.
If you are ok, I will submit next patch.

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 = readl(port->membase + SUP_UART_ISC); //add this line
        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;
        unsigned int isc;

        spin_lock_irqsave(&port->lock, flags);

        isc = readl(port->membase + SUP_UART_ISC); //add this line
        isc &= ~(SUP_UART_ISC_RXM | SUP_UART_ISC_TXM); //add this line
        writel(isc, port->membase + SUP_UART_ISC); //modify this line

        spin_unlock_irqrestore(&port->lock, flags);

        free_irq(port->irq, port);
}

Greg KH <gregkh@linuxfoundation.org> 於 2022年1月26日 週三 下午9:47寫道:
>
> On Fri, Jan 14, 2022 at 10:22:56AM +0800, hammer hsieh wrote:
> > Jiri Slaby <jirislaby@kernel.org> 於 2022年1月13日 週四 下午7:12寫道:
> > >
> > > On 13. 01. 22, 11:56, hammer hsieh wrote:
> > > >> Could you explain me what posted write is and how does it not matter in
> > > >> this case?
> > > >>
> > > >
> > > > Each UART ISC register contains
> > >
> > > No, you still don't follow what I write. Use your favorite web search
> > > for "posted write" and/or consult with your HW team.
> > >
> >
> > Maybe this time, we are on the same page.
> > Our SP7021 chipset is designed on ARM Cortex-A7 Quad core.
> > Register Access through AMBA(AXI bus), and it is non-cached.
> >
> > Did you mean
> > case1 have concern about "posted write", and you want to know why it not matter?
> > case2 will be safer?
> >
> > Case1 :
> > spin_lock_irq_save()
> > writel(0, target register)
> > spin_unlock_irqrestore()
>
> A lock does not mean that your write made it to the device.  Please talk
> to the hardware designers to properly determine how to correctly write
> to the hardware and "know" that the write succeeded or not.  This driver
> does not seem to take that into consideration at all.
>
> thanks,
>
> greg k-h

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

end of thread, other threads:[~2022-01-28  3:36 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-01-12  9:24 [PATCH v6 0/2] Add UART driver for Suplus SP7021 SoC Hammer Hsieh
2022-01-12  9:24 ` [PATCH v6 1/2] dt-bindings:serial:Add bindings doc for Sunplus SoC UART Driver Hammer Hsieh
2022-01-12  9:24 ` [PATCH v6 2/2] serial:sunplus-uart:Add " Hammer Hsieh
2022-01-12 10:51   ` kernel test robot
2022-01-12 11:31   ` kernel test robot
2022-01-13  7:06   ` Jiri Slaby
2022-01-13  8:54     ` hammer hsieh
2022-01-13  9:08       ` Jiri Slaby
2022-01-13 10:56         ` hammer hsieh
2022-01-13 11:12           ` Jiri Slaby
2022-01-14  2:22             ` hammer hsieh
2022-01-26 13:47               ` Greg KH
2022-01-28  3:36                 ` hammer hsieh

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.