linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC 00/11] ARM: Initial Sunplus Plus1 SP7021 and BPI-F2S support
@ 2020-03-08 16:32 Andreas Färber
  2020-03-08 16:32 ` [RFC 01/11] dt-bindings: vendor-prefixes: Add Sunplus Andreas Färber
                   ` (11 more replies)
  0 siblings, 12 replies; 16+ messages in thread
From: Andreas Färber @ 2020-03-08 16:32 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Wells Lu 呂芳騰,
	Dvorkin Dmitry, linux-kernel, Andreas Färber, devicetree,
	Rob Herring, Greg Kroah-Hartman, linux-serial, Thomas Gleixner,
	Jason Cooper, Marc Zyngier

Hello,

This patch series adds initial drivers and Device Trees for Sunplus Plus1
series (codename Pentagram) SP7021 SoC and Banana Pi BPI-F2S SBC.

First, minimal Kconfig, DT and earlycon driver are prepared to get serial
output at all. Next, interrupt controller and full serial driver are added
that allow to boot into an initrd with interactive serial console.

Device Tree files added are for the CPU-Chip (aka A-Chip) with quad Cortex-A7,
but the file split prepares for also adding the Peripheral-Chip (B-Chip) with
ARM9 later. However, for now this is not reflected in the .dts filename; this
corresponds to the vf610- vs. vf610m4- naming scheme, whereas an alternative
would be to use sp7021-cchip- vs. -pchip- prefix (as sp7021-cpu- looks weird).
It is assumed we can reuse the same SoC and board bindings for CA7 and ARM9
and only differ for IP blocks where needed.

My inquiry to Sunplus about their GIC (anticipating complaints from Marc)
remained unanswered, so I've added the two extra regions and irq myself,
without being able to test KVM due to BSP U-Boot not booting in HYP mode.
According to Sunplus the mode can be changed in U-Boot (but where/how?).

Similarly, the architectural timer is not properly initialized in BSP U-Boot,
so that I currently have a mach- hack in my tree below. Unlike RTD1195,
we do have U-Boot sources (v2019.04 based), so should be able to fix this
in the bootloader rather than in the kernel, thus not included as patch here.

Based on SoC online manual [1] and downstream BPI-F2S BSP tree [2] as well as
my previous Actions serial and Realtek irqchip drivers and DTs.

More details at:
https://en.opensuse.org/HCL:BananaPi_F2S

Latest experimental patches at:
https://github.com/afaerber/linux/commits/f2s-next

Have a lot of fun!

Cheers,
Andreas

[1] https://sunplus-tibbo.atlassian.net/wiki/spaces/doc/pages/470450252/SP7021+Technical+Manual
[2] https://github.com/BPI-SINOVOIP/BPI-F2S-bsp

Cc: devicetree@vger.kernel.org
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: linux-serial@vger.kernel.org
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Marc Zyngier <maz@kernel.org>
Cc: Wells Lu 呂芳騰 <wells.lu@sunplus.com>
Cc: Dvorkin Dmitry <dvorkin@tibbo.com>

Andreas Färber (11):
  dt-bindings: vendor-prefixes: Add Sunplus
  dt-bindings: arm: Add Sunplus SP7021 and Banana Pi BPI-F2S
  ARM: Prepare Sunplus Plus1 SoC family
  dt-bindings: interrupt-controller: Add Sunplus SP7021 mux
  dt-bindings: serial: Add Sunplus SP7021 UART
  tty: serial: Add Sunplus Plus1 UART earlycon
  ARM: dts: Add Sunplus Plus1 SP7021 and Banana Pi F2S
  tty: serial: sunplus: Implement full UART driver
  irqchip: Add Sunplus SP7021 interrupt (mux) controller
  ARM: dts: sp7021-cpu: Add interrupt controller node
  ARM: dts: sp7021-cpu: Add dummy UART0 clock and interrupt

 Documentation/devicetree/bindings/arm/sunplus.yaml |  22 +
 .../sunplus,pentagram-intc.yaml                    |  50 ++
 .../bindings/serial/sunplus,pentagram-uart.yaml    |  24 +
 .../devicetree/bindings/vendor-prefixes.yaml       |   2 +
 arch/arm/Kconfig                                   |   2 +
 arch/arm/Makefile                                  |   1 +
 arch/arm/boot/dts/Makefile                         |   2 +
 arch/arm/boot/dts/pentagram-sp7021-bpi-f2s.dts     |  29 +
 arch/arm/boot/dts/pentagram-sp7021-cpu.dtsi        |  93 +++
 arch/arm/boot/dts/pentagram-sp7021.dtsi            |  61 ++
 arch/arm/mach-sunplus/Kconfig                      |  10 +
 drivers/irqchip/Makefile                           |   1 +
 drivers/irqchip/irq-sp7021.c                       | 285 ++++++++
 drivers/tty/serial/Kconfig                         |  19 +
 drivers/tty/serial/Makefile                        |   1 +
 drivers/tty/serial/sunplus-uart.c                  | 770 +++++++++++++++++++++
 include/uapi/linux/serial_core.h                   |   3 +
 17 files changed, 1375 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/sunplus.yaml
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/sunplus,pentagram-intc.yaml
 create mode 100644 Documentation/devicetree/bindings/serial/sunplus,pentagram-uart.yaml
 create mode 100644 arch/arm/boot/dts/pentagram-sp7021-bpi-f2s.dts
 create mode 100644 arch/arm/boot/dts/pentagram-sp7021-cpu.dtsi
 create mode 100644 arch/arm/boot/dts/pentagram-sp7021.dtsi
 create mode 100644 arch/arm/mach-sunplus/Kconfig
 create mode 100644 drivers/irqchip/irq-sp7021.c
 create mode 100644 drivers/tty/serial/sunplus-uart.c

-- 
2.16.4


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

* [RFC 01/11] dt-bindings: vendor-prefixes: Add Sunplus
  2020-03-08 16:32 [RFC 00/11] ARM: Initial Sunplus Plus1 SP7021 and BPI-F2S support Andreas Färber
@ 2020-03-08 16:32 ` Andreas Färber
  2020-03-08 16:32 ` [RFC 02/11] dt-bindings: arm: Add Sunplus SP7021 and Banana Pi BPI-F2S Andreas Färber
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Andreas Färber @ 2020-03-08 16:32 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Wells Lu 呂芳騰,
	Dvorkin Dmitry, linux-kernel, Andreas Färber, Rob Herring,
	devicetree

Sunplus Technology Co., Ltd. is a Taiwanese IC vendor.
Assign vendor prefix "sunplus".

Cc: Wells Lu 呂芳騰 <wells.lu@sunplus.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
---
 Documentation/devicetree/bindings/vendor-prefixes.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index 6e09fc7362d5..2c764b0941b4 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -955,6 +955,8 @@ patternProperties:
     description: Summit microelectronics
   "^sunchip,.*":
     description: Shenzhen Sunchip Technology Co., Ltd
+  "^sunplus,.*":
+    description: Sunplus Technology Co., Ltd.
   "^SUNW,.*":
     description: Sun Microsystems, Inc
   "^swir,.*":
-- 
2.16.4


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

* [RFC 02/11] dt-bindings: arm: Add Sunplus SP7021 and Banana Pi BPI-F2S
  2020-03-08 16:32 [RFC 00/11] ARM: Initial Sunplus Plus1 SP7021 and BPI-F2S support Andreas Färber
  2020-03-08 16:32 ` [RFC 01/11] dt-bindings: vendor-prefixes: Add Sunplus Andreas Färber
@ 2020-03-08 16:32 ` Andreas Färber
  2020-03-08 16:32 ` [RFC 03/11] ARM: Prepare Sunplus Plus1 SoC family Andreas Färber
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Andreas Färber @ 2020-03-08 16:32 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Wells Lu 呂芳騰,
	Dvorkin Dmitry, linux-kernel, Andreas Färber, Rob Herring,
	devicetree

Cc: Wells Lu 呂芳騰 <wells.lu@sunplus.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
---
 Documentation/devicetree/bindings/arm/sunplus.yaml | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/sunplus.yaml

diff --git a/Documentation/devicetree/bindings/arm/sunplus.yaml b/Documentation/devicetree/bindings/arm/sunplus.yaml
new file mode 100644
index 000000000000..c88856a00983
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/sunplus.yaml
@@ -0,0 +1,22 @@
+# SPDX-License-Identifier: GPL-2.0-or-later OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/arm/sunplus.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sunplus platforms device tree bindings
+
+maintainers:
+  - Andreas Färber <afaerber@suse.de>
+
+properties:
+  $nodename:
+    const: '/'
+  compatible:
+    oneOf:
+      # SP7021 SoC based boards
+      - items:
+          - enum:
+              - bananapi,bpi-f2s # Banana Pi BPI-F2S
+          - const: sunplus,sp7021
+...
-- 
2.16.4


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

* [RFC 03/11] ARM: Prepare Sunplus Plus1 SoC family
  2020-03-08 16:32 [RFC 00/11] ARM: Initial Sunplus Plus1 SP7021 and BPI-F2S support Andreas Färber
  2020-03-08 16:32 ` [RFC 01/11] dt-bindings: vendor-prefixes: Add Sunplus Andreas Färber
  2020-03-08 16:32 ` [RFC 02/11] dt-bindings: arm: Add Sunplus SP7021 and Banana Pi BPI-F2S Andreas Färber
@ 2020-03-08 16:32 ` Andreas Färber
  2020-03-08 16:32 ` [RFC 04/11] dt-bindings: interrupt-controller: Add Sunplus SP7021 mux Andreas Färber
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Andreas Färber @ 2020-03-08 16:32 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Wells Lu 呂芳騰,
	Dvorkin Dmitry, linux-kernel, Andreas Färber, Russell King

Signed-off-by: Andreas Färber <afaerber@suse.de>
---
 arch/arm/Kconfig              |  2 ++
 arch/arm/Makefile             |  1 +
 arch/arm/mach-sunplus/Kconfig | 10 ++++++++++
 3 files changed, 13 insertions(+)
 create mode 100644 arch/arm/mach-sunplus/Kconfig

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 1dcc64bd3621..f946140952b6 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -722,6 +722,8 @@ source "arch/arm/mach-sti/Kconfig"
 
 source "arch/arm/mach-stm32/Kconfig"
 
+source "arch/arm/mach-sunplus/Kconfig"
+
 source "arch/arm/mach-sunxi/Kconfig"
 
 source "arch/arm/mach-tango/Kconfig"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 9397fe766b31..f050eca6b3b6 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -158,6 +158,7 @@ textofs-$(CONFIG_ARCH_MSM8X60) := 0x00208000
 textofs-$(CONFIG_ARCH_MSM8960) := 0x00208000
 textofs-$(CONFIG_ARCH_MESON) := 0x00208000
 textofs-$(CONFIG_ARCH_AXXIA) := 0x00308000
+textofs-$(CONFIG_ARCH_SUNPLUS) := 0x00308000
 
 # Machine directory name.  This list is sorted alphanumerically
 # by CONFIG_* macro name.
diff --git a/arch/arm/mach-sunplus/Kconfig b/arch/arm/mach-sunplus/Kconfig
new file mode 100644
index 000000000000..c20b338e50c8
--- /dev/null
+++ b/arch/arm/mach-sunplus/Kconfig
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0
+menuconfig ARCH_SUNPLUS
+	bool "Sunplus SoCs"
+	depends on ARCH_MULTI_V7
+	select ARM_GIC
+	select ARM_GLOBAL_TIMER
+	select CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
+	select GENERIC_IRQ_CHIP
+	help
+	  This enables support for the Sunplus Plus1 (SP7021) SoC family.
-- 
2.16.4


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

* [RFC 04/11] dt-bindings: interrupt-controller: Add Sunplus SP7021 mux
  2020-03-08 16:32 [RFC 00/11] ARM: Initial Sunplus Plus1 SP7021 and BPI-F2S support Andreas Färber
                   ` (2 preceding siblings ...)
  2020-03-08 16:32 ` [RFC 03/11] ARM: Prepare Sunplus Plus1 SoC family Andreas Färber
@ 2020-03-08 16:32 ` Andreas Färber
  2020-03-23 19:48   ` Rob Herring
  2020-03-08 16:32 ` [RFC 05/11] dt-bindings: serial: Add Sunplus SP7021 UART Andreas Färber
                   ` (7 subsequent siblings)
  11 siblings, 1 reply; 16+ messages in thread
From: Andreas Färber @ 2020-03-08 16:32 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Wells Lu 呂芳騰,
	Dvorkin Dmitry, linux-kernel, Andreas Färber,
	Thomas Gleixner, Jason Cooper, Marc Zyngier, Rob Herring,
	devicetree

The Sunplus SP7021 SoC has an interrupt mux.

Cc: Wells Lu 呂芳騰 <wells.lu@sunplus.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
---
 .../sunplus,pentagram-intc.yaml                    | 50 ++++++++++++++++++++++
 1 file changed, 50 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/sunplus,pentagram-intc.yaml

diff --git a/Documentation/devicetree/bindings/interrupt-controller/sunplus,pentagram-intc.yaml b/Documentation/devicetree/bindings/interrupt-controller/sunplus,pentagram-intc.yaml
new file mode 100644
index 000000000000..baaf7bcd4a71
--- /dev/null
+++ b/Documentation/devicetree/bindings/interrupt-controller/sunplus,pentagram-intc.yaml
@@ -0,0 +1,50 @@
+# SPDX-License-Identifier: GPL-2.0-or-later OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/interrupt-controller/sunplus,pentagram-intc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sunplus Pentagram SoC Interrupt Controller
+
+maintainers:
+  - Andreas Färber <afaerber@suse.de>
+
+allOf:
+  - $ref: /schemas/interrupt-controller.yaml#
+
+properties:
+  compatible:
+    const: sunplus,sp7021-intc
+
+  reg:
+    maxItems: 2
+
+  interrupts:
+    maxItems: 2
+
+  interrupt-controller: true
+
+  "#interrupt-cells":
+    const: 2
+
+required:
+  - compatible
+  - reg
+  - interrupt-controller
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    interrupt-controller@9c000780 {
+        compatible = "sunplus,sp7021-intc";
+        reg = <0x9c000780 0x80>,
+              <0x9c000a80 0x80>;
+        interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>,
+                     <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+        interrupt-controller;
+        #interrupt-cells = <2>;
+    };
+...
-- 
2.16.4


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

* [RFC 05/11] dt-bindings: serial: Add Sunplus SP7021 UART
  2020-03-08 16:32 [RFC 00/11] ARM: Initial Sunplus Plus1 SP7021 and BPI-F2S support Andreas Färber
                   ` (3 preceding siblings ...)
  2020-03-08 16:32 ` [RFC 04/11] dt-bindings: interrupt-controller: Add Sunplus SP7021 mux Andreas Färber
@ 2020-03-08 16:32 ` Andreas Färber
  2020-03-23 19:50   ` Rob Herring
  2020-03-08 16:32 ` [RFC 06/11] tty: serial: Add Sunplus Plus1 UART earlycon Andreas Färber
                   ` (6 subsequent siblings)
  11 siblings, 1 reply; 16+ messages in thread
From: Andreas Färber @ 2020-03-08 16:32 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Wells Lu 呂芳騰,
	Dvorkin Dmitry, linux-kernel, Andreas Färber,
	Greg Kroah-Hartman, Rob Herring, linux-serial, devicetree

The Sunplus Plus1 (aka Pentagram) SP7021 SoC has five UARTs.

Cc: Wells Lu 呂芳騰 <wells.lu@sunplus.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
---
 .../bindings/serial/sunplus,pentagram-uart.yaml    | 24 ++++++++++++++++++++++
 1 file changed, 24 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/serial/sunplus,pentagram-uart.yaml

diff --git a/Documentation/devicetree/bindings/serial/sunplus,pentagram-uart.yaml b/Documentation/devicetree/bindings/serial/sunplus,pentagram-uart.yaml
new file mode 100644
index 000000000000..9d1641232a4c
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/sunplus,pentagram-uart.yaml
@@ -0,0 +1,24 @@
+# SPDX-License-Identifier: GPL-2.0-or-later OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/serial/sunplus,pentagram-uart.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sunplus Pentagram SoC UART Serial Interface
+
+maintainers:
+  - Andreas Färber <afaerber@suse.de>
+
+properties:
+  compatible:
+    const: sunplus,sp7021-uart
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+...
-- 
2.16.4


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

* [RFC 06/11] tty: serial: Add Sunplus Plus1 UART earlycon
  2020-03-08 16:32 [RFC 00/11] ARM: Initial Sunplus Plus1 SP7021 and BPI-F2S support Andreas Färber
                   ` (4 preceding siblings ...)
  2020-03-08 16:32 ` [RFC 05/11] dt-bindings: serial: Add Sunplus SP7021 UART Andreas Färber
@ 2020-03-08 16:32 ` Andreas Färber
  2020-03-08 16:32 ` [RFC 07/11] ARM: dts: Add Sunplus Plus1 SP7021 and Banana Pi F2S Andreas Färber
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Andreas Färber @ 2020-03-08 16:32 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Wells Lu 呂芳騰,
	Dvorkin Dmitry, linux-kernel, Andreas Färber,
	Greg Kroah-Hartman, Jiri Slaby, linux-serial

Prepare an earlycon driver for Sunplus Plus1 SP7021 SoC.

Based on BPI-F2S-bsp tree.

Signed-off-by: Andreas Färber <afaerber@suse.de>
---
 drivers/tty/serial/Kconfig        | 19 +++++++++
 drivers/tty/serial/Makefile       |  1 +
 drivers/tty/serial/sunplus-uart.c | 90 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 110 insertions(+)
 create mode 100644 drivers/tty/serial/sunplus-uart.c

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 880b96201530..ac6dce75c2f3 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1562,6 +1562,25 @@ config SERIAL_MILBEAUT_USIO_CONSOLE
 	  receives all kernel messages and warnings and which allows logins in
 	  single user mode).
 
+config SERIAL_PLUS1
+	bool "Sunplus Plus1 serial port support"
+	depends on ARCH_SUNPLUS || COMPILE_TEST
+	select SERIAL_CORE
+	help
+	  This driver is for Sunplus Plus1 SP7021 SoC's UART.
+	  Say 'Y' here if you wish to use the on-board serial port.
+	  Otherwise, say 'N'.
+
+config SERIAL_PLUS1_CONSOLE
+	bool "Console on Sunplus Plus1 serial port"
+	depends on SERIAL_PLUS1=y
+	select SERIAL_CORE_CONSOLE
+	select SERIAL_EARLYCON
+	default y
+	help
+	  Say 'Y' here if you wish to use Sunplus SP7021 UART
+	  as the system console. Only earlycon is implemented currently.
+
 endmenu
 
 config SERIAL_MCTRL_GPIO
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index d056ee6cca33..fed40fb19ed0 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -89,6 +89,7 @@ obj-$(CONFIG_SERIAL_OWL)	+= owl-uart.o
 obj-$(CONFIG_SERIAL_RDA)	+= rda-uart.o
 obj-$(CONFIG_SERIAL_MILBEAUT_USIO) += milbeaut_usio.o
 obj-$(CONFIG_SERIAL_SIFIVE)	+= sifive.o
+obj-$(CONFIG_SERIAL_PLUS1)	+= 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 000000000000..959dfab5e07b
--- /dev/null
+++ b/drivers/tty/serial/sunplus-uart.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2020 Andreas Färber
+ */
+
+#include <linux/bitops.h>
+#include <linux/console.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+
+#define REG_DATA		0x00
+#define REG_LSR			0x04
+
+#define PLUS1_UART_LSR_TX	BIT(0)
+
+static inline void plus1_uart_write(struct uart_port *port, unsigned int off, u32 val)
+{
+	writel_relaxed(val, port->membase + off);
+}
+
+static inline u32 plus1_uart_read(struct uart_port *port, unsigned int off)
+{
+	return readl_relaxed(port->membase + off);
+}
+
+#ifdef CONFIG_SERIAL_PLUS1_CONSOLE
+
+static void plus1_console_putchar(struct uart_port *port, int ch)
+{
+	if (!port->membase)
+		return;
+
+	while (!(plus1_uart_read(port, REG_LSR) & PLUS1_UART_LSR_TX))
+		cpu_relax();
+
+	plus1_uart_write(port, REG_DATA, ch);
+}
+
+static void plus1_uart_port_write(struct uart_port *port, const char *s,
+				  u_int count)
+{
+	unsigned long flags;
+	int locked;
+
+	local_irq_save(flags);
+
+	if (port->sysrq)
+		locked = 0;
+	else if (oops_in_progress)
+		locked = spin_trylock(&port->lock);
+	else {
+		spin_lock(&port->lock);
+		locked = 1;
+	}
+
+	uart_console_write(port, s, count, plus1_console_putchar);
+
+	if (locked)
+		spin_unlock(&port->lock);
+
+	local_irq_restore(flags);
+}
+
+static void plus1_uart_early_console_write(struct console *co,
+					   const char *s,
+					   u_int count)
+{
+	struct earlycon_device *dev = co->data;
+
+	plus1_uart_port_write(&dev->port, s, count);
+}
+
+static int __init
+plus1_uart_early_console_setup(struct earlycon_device *device, const char *opt)
+{
+	if (!device->port.membase)
+		return -ENODEV;
+
+	device->con->write = plus1_uart_early_console_write;
+
+	return 0;
+}
+OF_EARLYCON_DECLARE(sunplus, "sunplus,sp7021-uart",
+		    plus1_uart_early_console_setup);
+
+#endif
-- 
2.16.4


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

* [RFC 07/11] ARM: dts: Add Sunplus Plus1 SP7021 and Banana Pi F2S
  2020-03-08 16:32 [RFC 00/11] ARM: Initial Sunplus Plus1 SP7021 and BPI-F2S support Andreas Färber
                   ` (5 preceding siblings ...)
  2020-03-08 16:32 ` [RFC 06/11] tty: serial: Add Sunplus Plus1 UART earlycon Andreas Färber
@ 2020-03-08 16:32 ` Andreas Färber
  2020-03-08 16:32 ` [RFC 08/11] tty: serial: sunplus: Implement full UART driver Andreas Färber
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Andreas Färber @ 2020-03-08 16:32 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Wells Lu 呂芳騰,
	Dvorkin Dmitry, linux-kernel, Andreas Färber, Rob Herring,
	devicetree

Prepare Device Trees for Sunplus Plus1 (aka Pentagram) SP7021's
CPU-Chip aka A-Chip (Cortex-A7) as well as the Banana Pi BPI-F2S SBC.

Cc: Wells Lu 呂芳騰 <wells.lu@sunplus.com>
Signed-off-by: Andreas Färber <afaerber@suse.de>
---
 arch/arm/boot/dts/Makefile                     |  2 +
 arch/arm/boot/dts/pentagram-sp7021-bpi-f2s.dts | 22 ++++++++
 arch/arm/boot/dts/pentagram-sp7021-cpu.dtsi    | 75 ++++++++++++++++++++++++++
 arch/arm/boot/dts/pentagram-sp7021.dtsi        | 61 +++++++++++++++++++++
 4 files changed, 160 insertions(+)
 create mode 100644 arch/arm/boot/dts/pentagram-sp7021-bpi-f2s.dts
 create mode 100644 arch/arm/boot/dts/pentagram-sp7021-cpu.dtsi
 create mode 100644 arch/arm/boot/dts/pentagram-sp7021.dtsi

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 566c6d1cfc46..b514ead139f3 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -846,6 +846,8 @@ dtb-$(CONFIG_ARCH_ACTIONS) += \
 	owl-s500-cubieboard6.dtb \
 	owl-s500-guitar-bb-rev-b.dtb \
 	owl-s500-sparky.dtb
+dtb-$(CONFIG_ARCH_SUNPLUS) += \
+	pentagram-sp7021-bpi-f2s.dtb
 dtb-$(CONFIG_ARCH_PRIMA2) += \
 	prima2-evb.dtb
 dtb-$(CONFIG_ARCH_PXA) += \
diff --git a/arch/arm/boot/dts/pentagram-sp7021-bpi-f2s.dts b/arch/arm/boot/dts/pentagram-sp7021-bpi-f2s.dts
new file mode 100644
index 000000000000..3c25b6e79fe2
--- /dev/null
+++ b/arch/arm/boot/dts/pentagram-sp7021-bpi-f2s.dts
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-2-Clause
+
+/dts-v1/;
+
+#include "pentagram-sp7021-cpu.dtsi"
+
+/ {
+	compatible = "bananapi,bpi-f2s", "sunplus,sp7021";
+	model = "Banana Pi BPI-F2S";
+
+	aliases {
+		serial0 = &uart0;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
diff --git a/arch/arm/boot/dts/pentagram-sp7021-cpu.dtsi b/arch/arm/boot/dts/pentagram-sp7021-cpu.dtsi
new file mode 100644
index 000000000000..ae58bf5ffadf
--- /dev/null
+++ b/arch/arm/boot/dts/pentagram-sp7021-cpu.dtsi
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-2-Clause
+/*
+ * SunPlus Plus1 (Pentagram) SP7021 CPU-Chip a.k.a. A-Chip (CA7)
+ *
+ * Copyright (c) 2020 Andreas Färber
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+#include "pentagram-sp7021.dtsi"
+
+/ {
+	interrupt-parent = <&gic>;
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu0: cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a7";
+			reg = <0>;
+		};
+
+		cpu1: cpu@1{
+			device_type = "cpu";
+			compatible = "arm,cortex-a7";
+			reg = <1>;
+		};
+
+		cpu2: cpu@2 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a7";
+			reg = <2>;
+		};
+
+		cpu3: cpu@3 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a7";
+			reg = <3>;
+		};
+	};
+
+	arm-pmu {
+		compatible = "arm,cortex-a7-pmu";
+		interrupts = <GIC_SPI 219 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 221 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 222 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-affinity = <&cpu0>, <&cpu1>, <&cpu2>, <&cpu3>;
+	};
+
+	timer: timer {
+		compatible = "arm,armv7-timer";
+		interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+			     <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+			     <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+			     <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+		clock-frequency = <27000000>;
+		arm,cpu-registers-not-fw-configured;
+	};
+
+	soc {
+		gic: interrupt-controller@9f101000 {
+			compatible = "arm,cortex-a7-gic";
+			reg = <0x9f101000 0x1000>,
+			      <0x9f102000 0x2000>,
+			      <0x9f104000 0x2000>,
+			      <0x9f106000 0x2000>;
+			interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+			interrupt-controller;
+			#interrupt-cells = <3>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/pentagram-sp7021.dtsi b/arch/arm/boot/dts/pentagram-sp7021.dtsi
new file mode 100644
index 000000000000..7dd44901cf4a
--- /dev/null
+++ b/arch/arm/boot/dts/pentagram-sp7021.dtsi
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-2-Clause
+/*
+ * Copyright (c) 2020 Andreas Färber
+ */
+
+/ {
+	compatible = "sunplus,sp7021";
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	soc {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges = <0x20000000 0x20000000 0xe0000000>;
+
+		rgst: bus@9c000000 {
+			compatible = "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x0 0x9c000000 0x00100000>;
+
+			uart2: serial@800 {
+				compatible = "sunplus,sp7021-uart";
+				reg = <0x800 0x80>;
+				status = "disabled";
+			};
+
+			uart3: serial@880 {
+				compatible = "sunplus,sp7021-uart";
+				reg = <0x880 0x80>;
+				status = "disabled";
+			};
+
+			uart0: serial@900 {
+				compatible = "sunplus,sp7021-uart";
+				reg = <0x900 0x80>;
+				status = "disabled";
+			};
+
+			uart1: serial@980 {
+				compatible = "sunplus,sp7021-uart";
+				reg = <0x980 0x80>;
+				status = "disabled";
+			};
+
+			uart4: serial@8780 {
+				compatible = "sunplus,sp7021-uart";
+				reg = <0x8780 0x80>;
+				status = "disabled";
+			};
+		};
+
+		amba: bus@9c100000 {
+			compatible = "simple-bus";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0x0 0x9c100000 0x01ef0000>;
+		};
+	};
+};
-- 
2.16.4


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

* [RFC 08/11] tty: serial: sunplus: Implement full UART driver
  2020-03-08 16:32 [RFC 00/11] ARM: Initial Sunplus Plus1 SP7021 and BPI-F2S support Andreas Färber
                   ` (6 preceding siblings ...)
  2020-03-08 16:32 ` [RFC 07/11] ARM: dts: Add Sunplus Plus1 SP7021 and Banana Pi F2S Andreas Färber
@ 2020-03-08 16:32 ` Andreas Färber
  2020-03-08 16:32 ` [RFC 09/11] irqchip: Add Sunplus SP7021 interrupt (mux) controller Andreas Färber
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 16+ messages in thread
From: Andreas Färber @ 2020-03-08 16:32 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Wells Lu 呂芳騰,
	Dvorkin Dmitry, linux-kernel, Andreas Färber,
	Greg Kroah-Hartman, Jiri Slaby, linux-serial

Signed-off-by: Andreas Färber <afaerber@suse.de>
---
 drivers/tty/serial/Kconfig        |   4 +-
 drivers/tty/serial/sunplus-uart.c | 680 ++++++++++++++++++++++++++++++++++++++
 include/uapi/linux/serial_core.h  |   3 +
 3 files changed, 685 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index ac6dce75c2f3..a178500a6bb5 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1563,7 +1563,7 @@ config SERIAL_MILBEAUT_USIO_CONSOLE
 	  single user mode).
 
 config SERIAL_PLUS1
-	bool "Sunplus Plus1 serial port support"
+	tristate "Sunplus Plus1 serial port support"
 	depends on ARCH_SUNPLUS || COMPILE_TEST
 	select SERIAL_CORE
 	help
@@ -1579,7 +1579,7 @@ config SERIAL_PLUS1_CONSOLE
 	default y
 	help
 	  Say 'Y' here if you wish to use Sunplus SP7021 UART
-	  as the system console. Only earlycon is implemented currently.
+	  as the system console.
 
 endmenu
 
diff --git a/drivers/tty/serial/sunplus-uart.c b/drivers/tty/serial/sunplus-uart.c
index 959dfab5e07b..9b9442acde9a 100644
--- a/drivers/tty/serial/sunplus-uart.c
+++ b/drivers/tty/serial/sunplus-uart.c
@@ -4,6 +4,7 @@
  */
 
 #include <linux/bitops.h>
+#include <linux/clk.h>
 #include <linux/console.h>
 #include <linux/io.h>
 #include <linux/module.h>
@@ -11,11 +12,71 @@
 #include <linux/platform_device.h>
 #include <linux/serial.h>
 #include <linux/serial_core.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+
+#define PLUS1_UART_PORT_NUM 5
+#define PLUS1_UART_DEV_NAME "ttySP"
 
 #define REG_DATA		0x00
 #define REG_LSR			0x04
+#define REG_MSR			0x08
+#define REG_LCR			0x0c
+#define REG_MCR			0x10
+#define REG_DIV_L		0x14
+#define REG_DIV_H		0x18
+#define REG_ISC			0x1c
+#define REG_TX_RESIDUE		0x20
+#define REG_RX_RESIDUE		0x24
+#define REG_RX_THRESHOLD	0x28
+#define REG_CLK_SRC		0x2c
 
 #define PLUS1_UART_LSR_TX	BIT(0)
+#define PLUS1_UART_LSR_RX	BIT(1)
+#define PLUS1_UART_LSR_PE	BIT(2)
+#define PLUS1_UART_LSR_OE	BIT(3)
+#define PLUS1_UART_LSR_FE	BIT(4)
+#define PLUS1_UART_LSR_BC	BIT(5)
+#define PLUS1_UART_LSR_TXE	BIT(6)
+
+#define PLUS1_UART_LCR_WL_MASK	GENMASK(1, 0)
+#define PLUS1_UART_LCR_WL5	(0x0 << 0)
+#define PLUS1_UART_LCR_WL6	(0x1 << 0)
+#define PLUS1_UART_LCR_WL7	(0x2 << 0)
+#define PLUS1_UART_LCR_WL8	(0x3 << 0)
+#define PLUS1_UART_LCR_ST	BIT(2)
+#define PLUS1_UART_LCR_PE	BIT(3)
+#define PLUS1_UART_LCR_PR	BIT(4)
+#define PLUS1_UART_LCR_BC	BIT(5)
+
+#define PLUS1_UART_MCR_DTS	BIT(0)
+#define PLUS1_UART_MCR_RTS	BIT(1)
+#define PLUS1_UART_MCR_DCD	BIT(2)
+#define PLUS1_UART_MCR_RI	BIT(3)
+#define PLUS1_UART_MCR_LB	BIT(4)
+#define PLUS1_UART_MCR_AR	BIT(5)
+#define PLUS1_UART_MCR_AC	BIT(6)
+#define PLUS1_UART_MCR_AT	BIT(7)
+
+#define PLUS1_UART_ISC_TX	BIT(0)
+#define PLUS1_UART_ISC_RX	BIT(1)
+#define PLUS1_UART_ISC_LS	BIT(2)
+#define PLUS1_UART_ISC_MS	BIT(3)
+#define PLUS1_UART_ISC_TXM	BIT(4)
+#define PLUS1_UART_ISC_RXM	BIT(5)
+#define PLUS1_UART_ISC_LSM	BIT(6)
+#define PLUS1_UART_ISC_MSM	BIT(7)
+
+static struct uart_driver plus1_uart_driver;
+
+struct plus1_uart_port {
+	struct uart_port port;
+	struct clk *clk;
+};
+
+#define to_plus1_uart_port(prt) container_of(prt, struct plus1_uart_port, prt)
+
+static struct plus1_uart_port *plus1_uart_ports[PLUS1_UART_PORT_NUM];
 
 static inline void plus1_uart_write(struct uart_port *port, unsigned int off, u32 val)
 {
@@ -27,6 +88,447 @@ static inline u32 plus1_uart_read(struct uart_port *port, unsigned int off)
 	return readl_relaxed(port->membase + off);
 }
 
+static void plus1_uart_break_ctl(struct uart_port *port, int ctl)
+{
+	unsigned long flags;
+	u32 lcr;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	lcr = plus1_uart_read(port, REG_LCR);
+	if (ctl)
+		lcr |= PLUS1_UART_LCR_BC;
+	else
+		lcr &= ~PLUS1_UART_LCR_BC;
+	plus1_uart_write(port, REG_LCR, lcr);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void plus1_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	u32 mcr;
+
+	mcr = plus1_uart_read(port, REG_MCR);
+
+	if (mctrl & TIOCM_DTR)
+		mcr |= PLUS1_UART_MCR_DTS;
+	else
+		mcr &= ~PLUS1_UART_MCR_DTS;
+
+	if (mctrl & TIOCM_RTS)
+		mcr |= PLUS1_UART_MCR_RTS;
+	else
+		mcr &= ~PLUS1_UART_MCR_RTS;
+
+	if (mctrl & TIOCM_CAR)
+		mcr |= PLUS1_UART_MCR_DCD;
+	else
+		mcr &= ~PLUS1_UART_MCR_DCD;
+
+	if (mctrl & TIOCM_RI)
+		mcr |= PLUS1_UART_MCR_RI;
+	else
+		mcr &= ~PLUS1_UART_MCR_RI;
+
+	if (mctrl & TIOCM_LOOP)
+		mcr |= PLUS1_UART_MCR_LB;
+	else
+		mcr &= ~PLUS1_UART_MCR_LB;
+
+	plus1_uart_write(port, REG_MCR, mcr);
+}
+
+static unsigned int plus1_uart_get_mctrl(struct uart_port *port)
+{
+	unsigned int mctrl = 0;
+	u32 mcr;
+
+	mcr = plus1_uart_read(port, REG_MCR);
+	if (mcr & PLUS1_UART_MCR_DTS)
+		mctrl |= TIOCM_DTR;
+	if (mcr & PLUS1_UART_MCR_RTS)
+		mctrl |= TIOCM_RTS;
+	if (mcr & PLUS1_UART_MCR_DCD)
+		mctrl |= TIOCM_CAR;
+	if (mcr & PLUS1_UART_MCR_RI)
+		mctrl |= TIOCM_RI;
+	if (mcr & PLUS1_UART_MCR_LB)
+		mctrl |= TIOCM_LOOP;
+	if (mcr & PLUS1_UART_MCR_AC)
+		mctrl |= TIOCM_CTS;
+	return mctrl;
+}
+
+static unsigned int plus1_uart_tx_empty(struct uart_port *port)
+{
+	unsigned long flags;
+	unsigned int ret;
+	u32 lsr;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	lsr = plus1_uart_read(port, REG_LSR);
+	ret = (lsr & PLUS1_UART_LSR_TXE) ? TIOCSER_TEMT : 0;
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	return ret;
+}
+
+static void plus1_uart_stop_rx(struct uart_port *port)
+{
+	u32 isc;
+
+	isc = plus1_uart_read(port, REG_ISC);
+	isc &= ~PLUS1_UART_ISC_RXM;
+	plus1_uart_write(port, REG_ISC, isc);
+}
+
+static void plus1_uart_stop_tx(struct uart_port *port)
+{
+	u32 isc;
+
+	isc = plus1_uart_read(port, REG_ISC);
+	isc &= ~PLUS1_UART_ISC_TXM;
+	plus1_uart_write(port, REG_ISC, isc);
+}
+
+static void plus1_uart_start_tx(struct uart_port *port)
+{
+	u32 isc;
+
+	if (uart_tx_stopped(port)) {
+		plus1_uart_stop_tx(port);
+		return;
+	}
+
+	isc = plus1_uart_read(port, REG_ISC);
+	isc |= PLUS1_UART_ISC_TXM;
+	plus1_uart_write(port, REG_ISC, isc);
+}
+
+static void plus1_uart_send_chars(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->state->xmit;
+	unsigned int ch;
+
+	if (uart_tx_stopped(port))
+		return;
+
+	if (port->x_char) {
+		//while (!(plus1_uart_read(port, REG_LSR) & PLUS1_UART_LSR_TX))
+		//	cpu_relax();
+		plus1_uart_write(port, REG_DATA, port->x_char);
+		port->icount.tx++;
+		port->x_char = 0;
+	}
+
+	while (plus1_uart_read(port, REG_LSR) & PLUS1_UART_LSR_TX) {
+		if (uart_circ_empty(xmit))
+			break;
+
+		ch = xmit->buf[xmit->tail];
+		plus1_uart_write(port, REG_DATA, ch);
+		xmit->tail = (xmit->tail + 1) & (SERIAL_XMIT_SIZE - 1);
+		port->icount.tx++;
+	}
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+
+	if (uart_circ_empty(xmit))
+		plus1_uart_stop_tx(port);
+}
+
+static void plus1_uart_receive_chars(struct uart_port *port)
+{
+	u32 lsr, val;
+
+	lsr = plus1_uart_read(port, REG_LSR);
+	while (lsr & PLUS1_UART_LSR_RX) {
+		char flag = TTY_NORMAL;
+
+		if (lsr & PLUS1_UART_LSR_OE)
+			port->icount.overrun++;
+
+		if (lsr & PLUS1_UART_LSR_BC) {
+			port->icount.brk++;
+			flag = TTY_BREAK;
+		} else if (lsr & PLUS1_UART_LSR_PE) {
+			port->icount.parity++;
+			flag = TTY_PARITY;
+		} else if (lsr & PLUS1_UART_LSR_FE) {
+			port->icount.frame++;
+
+			lsr &= port->read_status_mask;
+			if (lsr & PLUS1_UART_LSR_FE)
+				flag = TTY_PARITY;
+		} else
+			port->icount.rx++;
+
+		val = plus1_uart_read(port, REG_DATA);
+		val &= 0xff;
+
+		if ((lsr & port->ignore_status_mask) == 0)
+			tty_insert_flip_char(&port->state->port, val, flag);
+
+		lsr = plus1_uart_read(port, REG_LSR);
+	}
+
+	spin_unlock(&port->lock);
+	tty_flip_buffer_push(&port->state->port);
+	spin_lock(&port->lock);
+}
+
+static irqreturn_t plus1_uart_irq(int irq, void *dev_id)
+{
+	struct uart_port *port = dev_id;
+	unsigned long flags;
+	u32 isc;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	isc = plus1_uart_read(port, REG_ISC);
+	if (isc & PLUS1_UART_ISC_RX)
+		plus1_uart_receive_chars(port);
+
+	isc = plus1_uart_read(port, REG_ISC);
+	if (isc & PLUS1_UART_ISC_TX)
+		plus1_uart_send_chars(port);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+static void plus1_uart_shutdown(struct uart_port *port)
+{
+	unsigned long flags;
+	u32 mcr;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	plus1_uart_write(port, REG_ISC, 0);
+
+	mcr = plus1_uart_read(port, REG_MCR);
+	mcr &= ~PLUS1_UART_MCR_AC;
+	plus1_uart_write(port, REG_MCR, mcr);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	free_irq(port->irq, port);
+}
+
+static int plus1_uart_startup(struct uart_port *port)
+{
+	unsigned long flags;
+	int ret;
+
+	ret = request_irq(port->irq, plus1_uart_irq, IRQF_TRIGGER_NONE,
+			  "plus1-uart", port);
+	if (ret)
+		return ret;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	plus1_uart_write(port, REG_ISC, PLUS1_UART_ISC_RXM);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	return 0;
+}
+
+static void plus1_uart_change_baudrate(struct plus1_uart_port *sp_port,
+				       unsigned long baud)
+{
+	struct uart_port *port = &sp_port->port;
+	unsigned int clk;
+	unsigned int div, ext;
+
+	plus1_uart_write(port, REG_CLK_SRC, (baud > 115200) ? 0 : BIT(0));
+	if (baud > 115200)
+		clk = 202500000;
+	else
+		clk = port->uartclk;
+	clk += baud >> 1;
+	div = clk / baud;
+	ext = div & 0xf;
+	div >>= 4;
+	div--;
+	plus1_uart_write(port, REG_DIV_L, (ext << 12) | (div & 0xff));
+	plus1_uart_write(port, REG_DIV_H, div >> 8);
+}
+
+static void plus1_uart_set_termios(struct uart_port *port,
+				   struct ktermios *termios,
+				   struct ktermios *old)
+{
+	struct plus1_uart_port *sp_port = to_plus1_uart_port(port);
+	unsigned int baud;
+	u32 lcr, mcr;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	lcr = plus1_uart_read(port, REG_LCR);
+
+	lcr &= ~PLUS1_UART_LCR_WL_MASK;
+	switch (termios->c_cflag & CSIZE) {
+	case CS5:
+		lcr |= PLUS1_UART_LCR_WL5;
+		break;
+	case CS6:
+		lcr |= PLUS1_UART_LCR_WL6;
+		break;
+	case CS7:
+		lcr |= PLUS1_UART_LCR_WL7;
+		break;
+	case CS8:
+	default:
+		lcr |= PLUS1_UART_LCR_WL8;
+		break;
+	}
+
+	if (termios->c_cflag & CSTOPB)
+		lcr |= PLUS1_UART_LCR_ST;
+	else
+		lcr &= ~PLUS1_UART_LCR_ST;
+
+	if (termios->c_cflag & PARENB) {
+		lcr |= PLUS1_UART_LCR_PE;
+	} else
+		lcr &= ~PLUS1_UART_LCR_PE;
+
+	if ((termios->c_cflag & PARENB) && !(termios->c_cflag & PARODD))
+		lcr |= PLUS1_UART_LCR_PR;
+	else
+		lcr &= ~PLUS1_UART_LCR_PR;
+
+	plus1_uart_write(port, REG_LCR, lcr);
+
+	mcr = plus1_uart_read(port, REG_MCR);
+
+	if (termios->c_cflag & CRTSCTS)
+		mcr |= PLUS1_UART_MCR_AC | PLUS1_UART_MCR_AR;
+	else
+		mcr &= ~(PLUS1_UART_MCR_AC | PLUS1_UART_MCR_AR);
+
+	plus1_uart_write(port, REG_MCR, mcr);
+
+	baud = uart_get_baud_rate(port, termios, old, 0, 202500000 >> 4);
+	plus1_uart_change_baudrate(sp_port, baud);
+
+	/* Don't rewrite B0 */
+	if (tty_termios_baud_rate(termios))
+		tty_termios_encode_baud_rate(termios, baud, baud);
+
+	port->read_status_mask = 0;
+	if (termios->c_iflag & INPCK)
+		port->read_status_mask |= PLUS1_UART_LSR_PE | PLUS1_UART_LSR_FE;
+	if ((termios->c_iflag & BRKINT) || (termios->c_iflag & PARMRK))
+		port->read_status_mask |= PLUS1_UART_LSR_BC;
+
+	port->ignore_status_mask = 0;
+	if (termios->c_iflag & IGNPAR)
+		port->ignore_status_mask |= PLUS1_UART_LSR_PE | PLUS1_UART_LSR_FE;
+	if (termios->c_iflag & IGNBRK) {
+		port->ignore_status_mask |= PLUS1_UART_LSR_BC;
+		if (termios->c_iflag & IGNPAR)
+			port->ignore_status_mask |= PLUS1_UART_LSR_OE;
+	}
+
+	if (!(termios->c_cflag & CREAD))
+		plus1_uart_write(port, REG_RX_RESIDUE, 0);
+
+	uart_update_timeout(port, termios->c_cflag, baud);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void plus1_uart_release_port(struct uart_port *port)
+{
+	struct platform_device *pdev = to_platform_device(port->dev);
+	struct resource *res;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return;
+
+	if (port->flags & UPF_IOREMAP) {
+		devm_release_mem_region(port->dev, port->mapbase,
+			resource_size(res));
+		devm_iounmap(port->dev, port->membase);
+		port->membase = NULL;
+	}
+}
+
+static int plus1_uart_request_port(struct uart_port *port)
+{
+	struct platform_device *pdev = to_platform_device(port->dev);
+	struct resource *res;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENXIO;
+
+	if (!devm_request_mem_region(port->dev, port->mapbase,
+			resource_size(res), dev_name(port->dev)))
+		return -EBUSY;
+
+	if (port->flags & UPF_IOREMAP) {
+		port->membase = devm_ioremap(port->dev, port->mapbase,
+				resource_size(res));
+		if (!port->membase)
+			return -EBUSY;
+	}
+
+	return 0;
+}
+
+static const char *plus1_uart_type(struct uart_port *port)
+{
+	return (port->type == PORT_PLUS1) ? "plus1-uart" : NULL;
+}
+
+static int plus1_uart_verify_port(struct uart_port *port,
+				  struct serial_struct *ser)
+{
+	if (port->type != PORT_PLUS1)
+		return -EINVAL;
+
+	if (port->irq != ser->irq)
+		return -EINVAL;
+
+	return 0;
+}
+
+static void plus1_uart_config_port(struct uart_port *port, int flags)
+{
+	if (flags & UART_CONFIG_TYPE) {
+		port->type = PORT_PLUS1;
+		plus1_uart_request_port(port);
+	}
+}
+
+static const struct uart_ops plus1_uart_ops = {
+	.break_ctl	= plus1_uart_break_ctl,
+	.set_mctrl	= plus1_uart_set_mctrl,
+	.get_mctrl	= plus1_uart_get_mctrl,
+	.tx_empty	= plus1_uart_tx_empty,
+	.start_tx	= plus1_uart_start_tx,
+	.stop_rx	= plus1_uart_stop_rx,
+	.stop_tx	= plus1_uart_stop_tx,
+	.startup	= plus1_uart_startup,
+	.shutdown	= plus1_uart_shutdown,
+	.set_termios	= plus1_uart_set_termios,
+	.type		= plus1_uart_type,
+	.config_port	= plus1_uart_config_port,
+	.request_port	= plus1_uart_request_port,
+	.release_port	= plus1_uart_release_port,
+	.verify_port	= plus1_uart_verify_port,
+};
+
 #ifdef CONFIG_SERIAL_PLUS1_CONSOLE
 
 static void plus1_console_putchar(struct uart_port *port, int ch)
@@ -65,6 +567,57 @@ static void plus1_uart_port_write(struct uart_port *port, const char *s,
 	local_irq_restore(flags);
 }
 
+static void plus1_uart_console_write(struct console *co, const char *s,
+				     u_int count)
+{
+	struct plus1_uart_port *sp_port;
+
+	sp_port = plus1_uart_ports[co->index];
+	if (!sp_port)
+		return;
+
+	plus1_uart_port_write(&sp_port->port, s, count);
+}
+
+static int plus1_uart_console_setup(struct console *co, char *options)
+{
+	struct plus1_uart_port *sp_port;
+	int baud = 115200;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
+
+	if (co->index < 0 || co->index >= PLUS1_UART_PORT_NUM)
+		return -EINVAL;
+
+	sp_port = plus1_uart_ports[co->index];
+	if (!sp_port || !sp_port->port.membase)
+		return -ENODEV;
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+	return uart_set_options(&sp_port->port, co, baud, parity, bits, flow);
+}
+
+static struct console plus1_uart_console = {
+	.name = PLUS1_UART_DEV_NAME,
+	.write = plus1_uart_console_write,
+	.device = uart_console_device,
+	.setup = plus1_uart_console_setup,
+	.flags = CON_PRINTBUFFER,
+	.index = -1,
+	.data = &plus1_uart_driver,
+};
+
+static int __init plus1_uart_console_init(void)
+{
+	register_console(&plus1_uart_console);
+
+	return 0;
+}
+console_initcall(plus1_uart_console_init);
+
 static void plus1_uart_early_console_write(struct console *co,
 					   const char *s,
 					   u_int count)
@@ -87,4 +640,131 @@ plus1_uart_early_console_setup(struct earlycon_device *device, const char *opt)
 OF_EARLYCON_DECLARE(sunplus, "sunplus,sp7021-uart",
 		    plus1_uart_early_console_setup);
 
+#define PLUS1_UART_CONSOLE (&plus1_uart_console)
+#else
+#define PLUS1_UART_CONSOLE NULL
 #endif
+
+static struct uart_driver plus1_uart_driver = {
+	.owner = THIS_MODULE,
+	.driver_name = "plus1-uart",
+	.dev_name = PLUS1_UART_DEV_NAME,
+	.nr = PLUS1_UART_PORT_NUM,
+	.cons = PLUS1_UART_CONSOLE,
+};
+
+static int plus1_uart_probe(struct platform_device *pdev)
+{
+	struct resource *res_mem;
+	struct plus1_uart_port *sp_port;
+	int ret, irq;
+
+	if (pdev->dev.of_node)
+		pdev->id = of_alias_get_id(pdev->dev.of_node, "serial");
+
+	if (pdev->id < 0 || pdev->id >= PLUS1_UART_PORT_NUM) {
+		dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
+		return -EINVAL;
+	}
+
+	res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res_mem) {
+		dev_err(&pdev->dev, "could not get mem\n");
+		return -ENODEV;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	if (plus1_uart_ports[pdev->id]) {
+		dev_err(&pdev->dev, "port %d already allocated\n", pdev->id);
+		return -EBUSY;
+	}
+
+	sp_port = devm_kzalloc(&pdev->dev, sizeof(*sp_port), GFP_KERNEL);
+	if (!sp_port)
+		return -ENOMEM;
+
+	sp_port->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(sp_port->clk)) {
+		dev_err(&pdev->dev, "could not get clk\n");
+		return PTR_ERR(sp_port->clk);
+	}
+
+	sp_port->port.dev = &pdev->dev;
+	sp_port->port.line = pdev->id;
+	sp_port->port.type = PORT_PLUS1;
+	sp_port->port.iotype = UPIO_MEM;
+	sp_port->port.mapbase = res_mem->start;
+	sp_port->port.irq = irq;
+	sp_port->port.uartclk = clk_get_rate(sp_port->clk);
+	if (sp_port->port.uartclk == 0) {
+		dev_err(&pdev->dev, "clock rate is zero\n");
+		return -EINVAL;
+	}
+	sp_port->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_LOW_LATENCY;
+	sp_port->port.x_char = 0;
+	sp_port->port.fifosize = 16;
+	sp_port->port.ops = &plus1_uart_ops;
+
+	plus1_uart_ports[pdev->id] = sp_port;
+	platform_set_drvdata(pdev, sp_port);
+
+	ret = uart_add_one_port(&plus1_uart_driver, &sp_port->port);
+	if (ret)
+		plus1_uart_ports[pdev->id] = NULL;
+
+	return ret;
+}
+
+static int plus1_uart_remove(struct platform_device *pdev)
+{
+	struct plus1_uart_port *sp_port = platform_get_drvdata(pdev);
+
+	uart_remove_one_port(&plus1_uart_driver, &sp_port->port);
+	plus1_uart_ports[pdev->id] = NULL;
+
+	return 0;
+}
+
+static const struct of_device_id plus1_uart_dt_matches[] = {
+	{ .compatible = "sunplus,sp7021-uart" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, plus1_uart_dt_matches);
+
+static struct platform_driver plus1_uart_platform_driver = {
+	.probe = plus1_uart_probe,
+	.remove = plus1_uart_remove,
+	.driver = {
+		.name = "plus1-uart",
+		.of_match_table = plus1_uart_dt_matches,
+	},
+};
+
+static int __init plus1_uart_init(void)
+{
+	int ret;
+
+	ret = uart_register_driver(&plus1_uart_driver);
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&plus1_uart_platform_driver);
+	if (ret)
+		uart_unregister_driver(&plus1_uart_driver);
+
+	return ret;
+}
+
+static void __exit plus1_uart_exit(void)
+{
+	platform_driver_unregister(&plus1_uart_platform_driver);
+	uart_unregister_driver(&plus1_uart_driver);
+}
+
+module_init(plus1_uart_init);
+module_exit(plus1_uart_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
index 8ec3dd742ea4..54c611b06735 100644
--- a/include/uapi/linux/serial_core.h
+++ b/include/uapi/linux/serial_core.h
@@ -293,4 +293,7 @@
 /* Freescale LINFlexD UART */
 #define PORT_LINFLEXUART	122
 
+/* SunPlus Plus1 UART */
+#define PORT_PLUS1	123
+
 #endif /* _UAPILINUX_SERIAL_CORE_H */
-- 
2.16.4


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

* [RFC 09/11] irqchip: Add Sunplus SP7021 interrupt (mux) controller
  2020-03-08 16:32 [RFC 00/11] ARM: Initial Sunplus Plus1 SP7021 and BPI-F2S support Andreas Färber
                   ` (7 preceding siblings ...)
  2020-03-08 16:32 ` [RFC 08/11] tty: serial: sunplus: Implement full UART driver Andreas Färber
@ 2020-03-08 16:32 ` Andreas Färber
  2020-03-08 17:57   ` Marc Zyngier
  2020-03-08 16:32 ` [RFC 10/11] ARM: dts: sp7021-cpu: Add interrupt controller node Andreas Färber
                   ` (2 subsequent siblings)
  11 siblings, 1 reply; 16+ messages in thread
From: Andreas Färber @ 2020-03-08 16:32 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Wells Lu 呂芳騰,
	Dvorkin Dmitry, linux-kernel, Andreas Färber,
	Thomas Gleixner, Jason Cooper, Marc Zyngier

Signed-off-by: Andreas Färber <afaerber@suse.de>
---
 drivers/irqchip/Makefile     |   1 +
 drivers/irqchip/irq-sp7021.c | 285 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 286 insertions(+)
 create mode 100644 drivers/irqchip/irq-sp7021.c

diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index eae0d78cbf22..a6b70d666739 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -105,3 +105,4 @@ obj-$(CONFIG_MADERA_IRQ)		+= irq-madera.o
 obj-$(CONFIG_LS1X_IRQ)			+= irq-ls1x.o
 obj-$(CONFIG_TI_SCI_INTR_IRQCHIP)	+= irq-ti-sci-intr.o
 obj-$(CONFIG_TI_SCI_INTA_IRQCHIP)	+= irq-ti-sci-inta.o
+obj-$(CONFIG_ARCH_SUNPLUS)		+= irq-sp7021.o
diff --git a/drivers/irqchip/irq-sp7021.c b/drivers/irqchip/irq-sp7021.c
new file mode 100644
index 000000000000..a0b7972f2abb
--- /dev/null
+++ b/drivers/irqchip/irq-sp7021.c
@@ -0,0 +1,285 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Sunplus Plus1 SP7021 SoC interrupt controller
+ *
+ * Copyright (c) 2020 Andreas Färber
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irqdomain.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#define REG_INTC_INTR_TYPE(i)		(0x0 + (i) * 4)
+#define REG_INTC_INTR_POLARITY(i)	(0x1c + (i) * 4)
+#define REG_INTC_INTR_PRIO(i)		(0x38 + (i) * 4)
+#define REG_INTC_INTR_MASK(i)		(0x54 + (i) * 4)
+
+#define REG_INTC_INTR_CLR(i)		(0x0 + (i) * 4)
+#define REG_INTC_MASKED_FIQS(i)		(0x1c + (i) * 4)
+#define REG_INTC_MASKED_IRQS(i)		(0x38 + (i) * 4)
+#define REG_INTC_INTR_GROUP		0x7c
+
+#define INTC_INTR_GROUP_FIQ	GENMASK(6, 0)
+#define INTC_INTR_GROUP_IRQ	GENMASK(14, 8)
+
+struct sp7021_intc_data {
+	void __iomem		*base0;
+	void __iomem		*base1;
+	int			ext0_irq;
+	int			ext1_irq;
+	struct irq_chip		chip;
+	struct irq_domain	*domain;
+	raw_spinlock_t		lock;
+};
+
+static void sp7021_intc_ext0_irq_handle(struct irq_desc *desc)
+{
+	struct sp7021_intc_data *s = irq_desc_get_handler_data(desc);
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	u32 mask, masked;
+	int i, j;
+
+	chained_irq_enter(chip, desc);
+
+	mask = readl_relaxed(s->base1 + REG_INTC_INTR_GROUP);
+	mask = FIELD_GET(INTC_INTR_GROUP_IRQ, mask);
+	while (mask) {
+		i = fls(mask) - 1;
+		mask &= ~BIT(i);
+
+		masked = readl_relaxed(s->base1 + REG_INTC_MASKED_IRQS(i));
+		while (masked) {
+			j = fls(masked) - 1;
+			masked &= ~BIT(j);
+
+			generic_handle_irq(irq_find_mapping(s->domain,
+							    i * 32 + j));
+		}
+	}
+
+	chained_irq_exit(chip, desc);
+}
+
+static void sp7021_intc_ext1_irq_handle(struct irq_desc *desc)
+{
+	struct sp7021_intc_data *s = irq_desc_get_handler_data(desc);
+	struct irq_chip *chip = irq_desc_get_chip(desc);
+	u32 mask, masked;
+	int i, j;
+
+	chained_irq_enter(chip, desc);
+
+	mask = readl_relaxed(s->base1 + REG_INTC_INTR_GROUP);
+	mask = FIELD_GET(INTC_INTR_GROUP_FIQ, mask);
+	while (mask) {
+		i = fls(mask) - 1;
+		mask &= ~BIT(i);
+
+		masked = readl_relaxed(s->base1 + REG_INTC_MASKED_FIQS(i));
+		while (masked) {
+			j = fls(masked) - 1;
+			masked &= ~BIT(j);
+
+			generic_handle_irq(irq_find_mapping(s->domain,
+							    i * 32 + j));
+		}
+	}
+
+	chained_irq_exit(chip, desc);
+}
+
+static void sp7021_intc_ack_irq(struct irq_data *data)
+{
+	struct sp7021_intc_data *s = irq_data_get_irq_chip_data(data);
+	unsigned int idx;
+	u32 mask;
+
+	idx = data->hwirq / 32;
+
+	mask = BIT(data->hwirq % 32);
+	writel_relaxed(mask, s->base1 + REG_INTC_INTR_CLR(idx));
+}
+
+static void sp7021_intc_mask_irq(struct irq_data *data)
+{
+	struct sp7021_intc_data *s = irq_data_get_irq_chip_data(data);
+	unsigned long flags;
+	unsigned int idx;
+	u32 mask;
+
+	idx = data->hwirq / 32;
+
+	raw_spin_lock_irqsave(&s->lock, flags);
+
+	mask = readl_relaxed(s->base0 + REG_INTC_INTR_MASK(idx));
+	mask &= ~BIT(data->hwirq % 32);
+	writel_relaxed(mask, s->base0 + REG_INTC_INTR_MASK(idx));
+
+	raw_spin_unlock_irqrestore(&s->lock, flags);
+}
+
+static void sp7021_intc_unmask_irq(struct irq_data *data)
+{
+	struct sp7021_intc_data *s = irq_data_get_irq_chip_data(data);
+	unsigned long flags;
+	unsigned int idx;
+	u32 mask;
+
+	idx = data->hwirq / 32;
+
+	raw_spin_lock_irqsave(&s->lock, flags);
+
+	mask = readl_relaxed(s->base0 + REG_INTC_INTR_MASK(idx));
+	mask |= BIT(data->hwirq % 32);
+	writel_relaxed(mask, s->base0 + REG_INTC_INTR_MASK(idx));
+
+	raw_spin_unlock_irqrestore(&s->lock, flags);
+}
+
+static int sp7021_intc_set_irq_type(struct irq_data *data, unsigned int flow_type)
+{
+	struct sp7021_intc_data *s = irq_data_get_irq_chip_data(data);
+	unsigned long flags;
+	unsigned int idx;
+	u32 mask, type, polarity;
+
+	idx = data->hwirq / 32;
+	mask = BIT(data->hwirq % 32);
+
+	if (flow_type & IRQ_TYPE_LEVEL_MASK)
+		irq_set_chip_handler_name_locked(data, &s->chip, handle_level_irq, NULL);
+	else
+		irq_set_chip_handler_name_locked(data, &s->chip, handle_edge_irq, NULL);
+
+	raw_spin_lock_irqsave(&s->lock, flags);
+
+	type = readl_relaxed(s->base0 + REG_INTC_INTR_TYPE(idx));
+	polarity = readl_relaxed(s->base0 + REG_INTC_INTR_POLARITY(idx));
+
+	switch (flow_type) {
+	case IRQ_TYPE_EDGE_RISING:
+		type |= mask;
+		polarity &= ~mask;
+		break;
+	case IRQ_TYPE_EDGE_FALLING:
+		type |= mask;
+		polarity |= mask;
+		break;
+	case IRQ_TYPE_LEVEL_HIGH:
+		type &= ~mask;
+		polarity &= ~mask;
+		break;
+	case IRQ_TYPE_LEVEL_LOW:
+		type &= ~mask;
+		polarity |= mask;
+		break;
+	default:
+		raw_spin_unlock_irqrestore(&s->lock, flags);
+		return -EBADR;
+	}
+
+	writel_relaxed(type, s->base0 + REG_INTC_INTR_TYPE(idx));
+	writel_relaxed(polarity, s->base0 + REG_INTC_INTR_POLARITY(idx));
+
+	raw_spin_unlock_irqrestore(&s->lock, flags);
+
+	return IRQ_SET_MASK_OK;
+}
+
+static const struct irq_chip sp7021_intc_irq_chip = {
+	.name			= "SP7021-A",
+	.irq_ack		= sp7021_intc_ack_irq,
+	.irq_mask		= sp7021_intc_mask_irq,
+	.irq_unmask		= sp7021_intc_unmask_irq,
+	.irq_set_type		= sp7021_intc_set_irq_type,
+};
+
+static int sp7021_intc_irq_domain_map(struct irq_domain *d,
+		unsigned int irq, irq_hw_number_t hw)
+{
+	struct sp7021_intc_data *s = d->host_data;
+	unsigned int idx;
+	u32 mask, type;
+
+	idx = hw / 32;
+	mask = BIT(hw % 32);
+
+	type = readl_relaxed(s->base0 + REG_INTC_INTR_TYPE(idx));
+
+	irq_set_chip_and_handler(irq, &s->chip, (type & mask) ? handle_edge_irq : handle_level_irq);
+	irq_set_chip_data(irq, s);
+	irq_set_probe(irq);
+
+	return 0;
+}
+
+static const struct irq_domain_ops sp7021_intc_domain_ops = {
+	.xlate	= irq_domain_xlate_onecell,
+	.map	= sp7021_intc_irq_domain_map,
+};
+
+int __init sp7021_intc_init(struct device_node *node, struct device_node *parent)
+{
+	struct sp7021_intc_data *s;
+	void __iomem *base0, *base1;
+	int i;
+
+	base0 = of_iomap(node, 0);
+	if (!base0)
+		return -EIO;
+
+	base1 = of_iomap(node, 1);
+	if (!base1)
+		return -EIO;
+
+	s = kzalloc(sizeof(*s), GFP_KERNEL);
+	if (!s)
+		return -ENOMEM;
+
+	s->base0 = base0;
+	s->base1 = base1;
+	s->chip = sp7021_intc_irq_chip;
+
+	s->ext0_irq = irq_of_parse_and_map(node, 0);
+	if (s->ext0_irq <= 0) {
+		kfree(s);
+		return -EINVAL;
+	}
+
+	s->ext1_irq = irq_of_parse_and_map(node, 1);
+	if (s->ext1_irq <= 0) {
+		kfree(s);
+		return -EINVAL;
+	}
+
+	raw_spin_lock_init(&s->lock);
+
+	for (i = 0; i < 7; i++) {
+		writel_relaxed(0, s->base0 + REG_INTC_INTR_MASK(i));
+		writel_relaxed(~0, s->base0 + REG_INTC_INTR_TYPE(i));
+		writel_relaxed(0, s->base0 + REG_INTC_INTR_POLARITY(i));
+
+		/* irq, not fiq */
+		writel_relaxed(~0, s->base0 + REG_INTC_INTR_PRIO(i));
+
+		writel_relaxed(~0, s->base1 + REG_INTC_INTR_CLR(i));
+	}
+
+	s->domain = irq_domain_add_linear(node, 200, &sp7021_intc_domain_ops,
+					  s);
+	if (!s->domain) {
+		kfree(s);
+		return -ENOMEM;
+	}
+
+	irq_set_chained_handler_and_data(s->ext0_irq, sp7021_intc_ext0_irq_handle, s);
+	irq_set_chained_handler_and_data(s->ext1_irq, sp7021_intc_ext1_irq_handle, s);
+
+	return 0;
+}
+IRQCHIP_DECLARE(sp7021_intc, "sunplus,sp7021-intc", sp7021_intc_init);
-- 
2.16.4


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

* [RFC 10/11] ARM: dts: sp7021-cpu: Add interrupt controller node
  2020-03-08 16:32 [RFC 00/11] ARM: Initial Sunplus Plus1 SP7021 and BPI-F2S support Andreas Färber
                   ` (8 preceding siblings ...)
  2020-03-08 16:32 ` [RFC 09/11] irqchip: Add Sunplus SP7021 interrupt (mux) controller Andreas Färber
@ 2020-03-08 16:32 ` Andreas Färber
  2020-03-08 16:32 ` [RFC 11/11] ARM: dts: sp7021-cpu: Add dummy UART0 clock and interrupt Andreas Färber
  2020-03-09  5:32 ` [RFC 00/11] ARM: Initial Sunplus Plus1 SP7021 and BPI-F2S support Wells Lu 呂芳騰
  11 siblings, 0 replies; 16+ messages in thread
From: Andreas Färber @ 2020-03-08 16:32 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Wells Lu 呂芳騰,
	Dvorkin Dmitry, linux-kernel, Andreas Färber, Rob Herring,
	devicetree

Signed-off-by: Andreas Färber <afaerber@suse.de>
---
 arch/arm/boot/dts/pentagram-sp7021-cpu.dtsi | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/arch/arm/boot/dts/pentagram-sp7021-cpu.dtsi b/arch/arm/boot/dts/pentagram-sp7021-cpu.dtsi
index ae58bf5ffadf..7e424baa9214 100644
--- a/arch/arm/boot/dts/pentagram-sp7021-cpu.dtsi
+++ b/arch/arm/boot/dts/pentagram-sp7021-cpu.dtsi
@@ -73,3 +73,16 @@
 		};
 	};
 };
+
+&rgst {
+	intc: interrupt-controller@780 {
+		compatible = "sunplus,sp7021-intc";
+		reg = <0x780 0x80>, /* G15 */
+		      <0xa80 0x80>; /* G21 */
+		interrupt-parent = <&gic>;
+		interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>,
+			     <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+};
-- 
2.16.4


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

* [RFC 11/11] ARM: dts: sp7021-cpu: Add dummy UART0 clock and interrupt
  2020-03-08 16:32 [RFC 00/11] ARM: Initial Sunplus Plus1 SP7021 and BPI-F2S support Andreas Färber
                   ` (9 preceding siblings ...)
  2020-03-08 16:32 ` [RFC 10/11] ARM: dts: sp7021-cpu: Add interrupt controller node Andreas Färber
@ 2020-03-08 16:32 ` Andreas Färber
  2020-03-09  5:32 ` [RFC 00/11] ARM: Initial Sunplus Plus1 SP7021 and BPI-F2S support Wells Lu 呂芳騰
  11 siblings, 0 replies; 16+ messages in thread
From: Andreas Färber @ 2020-03-08 16:32 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Wells Lu 呂芳騰,
	Dvorkin Dmitry, linux-kernel, Andreas Färber, Rob Herring,
	devicetree

Signed-off-by: Andreas Färber <afaerber@suse.de>
---
 arch/arm/boot/dts/pentagram-sp7021-bpi-f2s.dts | 7 +++++++
 arch/arm/boot/dts/pentagram-sp7021-cpu.dtsi    | 5 +++++
 2 files changed, 12 insertions(+)

diff --git a/arch/arm/boot/dts/pentagram-sp7021-bpi-f2s.dts b/arch/arm/boot/dts/pentagram-sp7021-bpi-f2s.dts
index 3c25b6e79fe2..455416ce9d82 100644
--- a/arch/arm/boot/dts/pentagram-sp7021-bpi-f2s.dts
+++ b/arch/arm/boot/dts/pentagram-sp7021-bpi-f2s.dts
@@ -15,8 +15,15 @@
 	chosen {
 		stdout-path = "serial0:115200n8";
 	};
+
+	uart0_clk: clk {
+		compatible = "fixed-clock";
+		clock-frequency = <27000000>;
+		#clock-cells = <0>;
+	};
 };
 
 &uart0 {
 	status = "okay";
+	clocks = <&uart0_clk>;
 };
diff --git a/arch/arm/boot/dts/pentagram-sp7021-cpu.dtsi b/arch/arm/boot/dts/pentagram-sp7021-cpu.dtsi
index 7e424baa9214..48c5986a31ed 100644
--- a/arch/arm/boot/dts/pentagram-sp7021-cpu.dtsi
+++ b/arch/arm/boot/dts/pentagram-sp7021-cpu.dtsi
@@ -86,3 +86,8 @@
 		#interrupt-cells = <2>;
 	};
 };
+
+&uart0 {
+	interrupt-parent = <&intc>;
+	interrupts = <53 IRQ_TYPE_LEVEL_HIGH>;
+};
-- 
2.16.4


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

* Re: [RFC 09/11] irqchip: Add Sunplus SP7021 interrupt (mux) controller
  2020-03-08 16:32 ` [RFC 09/11] irqchip: Add Sunplus SP7021 interrupt (mux) controller Andreas Färber
@ 2020-03-08 17:57   ` Marc Zyngier
  0 siblings, 0 replies; 16+ messages in thread
From: Marc Zyngier @ 2020-03-08 17:57 UTC (permalink / raw)
  To: Andreas Färber
  Cc: linux-arm-kernel, Wells Lu 呂芳騰,
	Dvorkin Dmitry, linux-kernel, Thomas Gleixner, Jason Cooper

On Sun, 08 Mar 2020 16:32:27 +0000,
Andreas Färber <afaerber@suse.de> wrote:
> 
> Signed-off-by: Andreas Färber <afaerber@suse.de>

Since you've now given me full permission to complain, can I trouble
you for a meaningful commit message. It's not like it is the first
time you write a patch...

> ---
>  drivers/irqchip/Makefile     |   1 +
>  drivers/irqchip/irq-sp7021.c | 285 +++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 286 insertions(+)
>  create mode 100644 drivers/irqchip/irq-sp7021.c
> 
> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
> index eae0d78cbf22..a6b70d666739 100644
> --- a/drivers/irqchip/Makefile
> +++ b/drivers/irqchip/Makefile
> @@ -105,3 +105,4 @@ obj-$(CONFIG_MADERA_IRQ)		+= irq-madera.o
>  obj-$(CONFIG_LS1X_IRQ)			+= irq-ls1x.o
>  obj-$(CONFIG_TI_SCI_INTR_IRQCHIP)	+= irq-ti-sci-intr.o
>  obj-$(CONFIG_TI_SCI_INTA_IRQCHIP)	+= irq-ti-sci-inta.o
> +obj-$(CONFIG_ARCH_SUNPLUS)		+= irq-sp7021.o
> diff --git a/drivers/irqchip/irq-sp7021.c b/drivers/irqchip/irq-sp7021.c
> new file mode 100644
> index 000000000000..a0b7972f2abb
> --- /dev/null
> +++ b/drivers/irqchip/irq-sp7021.c
> @@ -0,0 +1,285 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Sunplus Plus1 SP7021 SoC interrupt controller
> + *
> + * Copyright (c) 2020 Andreas Färber
> + */
> +
> +#include <linux/bitfield.h>
> +#include <linux/bitops.h>
> +#include <linux/irq.h>
> +#include <linux/irqchip.h>
> +#include <linux/irqchip/chained_irq.h>
> +#include <linux/irqdomain.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +
> +#define REG_INTC_INTR_TYPE(i)		(0x0 + (i) * 4)
> +#define REG_INTC_INTR_POLARITY(i)	(0x1c + (i) * 4)
> +#define REG_INTC_INTR_PRIO(i)		(0x38 + (i) * 4)
> +#define REG_INTC_INTR_MASK(i)		(0x54 + (i) * 4)
> +
> +#define REG_INTC_INTR_CLR(i)		(0x0 + (i) * 4)
> +#define REG_INTC_MASKED_FIQS(i)		(0x1c + (i) * 4)
> +#define REG_INTC_MASKED_IRQS(i)		(0x38 + (i) * 4)
> +#define REG_INTC_INTR_GROUP		0x7c
> +
> +#define INTC_INTR_GROUP_FIQ	GENMASK(6, 0)
> +#define INTC_INTR_GROUP_IRQ	GENMASK(14, 8)
> +
> +struct sp7021_intc_data {
> +	void __iomem		*base0;
> +	void __iomem		*base1;
> +	int			ext0_irq;
> +	int			ext1_irq;
> +	struct irq_chip		chip;

Why do you need this irq_chip on a per instance basis?

> +	struct irq_domain	*domain;
> +	raw_spinlock_t		lock;
> +};
> +
> +static void sp7021_intc_ext0_irq_handle(struct irq_desc *desc)
> +{
> +	struct sp7021_intc_data *s = irq_desc_get_handler_data(desc);
> +	struct irq_chip *chip = irq_desc_get_chip(desc);
> +	u32 mask, masked;
> +	int i, j;
> +
> +	chained_irq_enter(chip, desc);
> +
> +	mask = readl_relaxed(s->base1 + REG_INTC_INTR_GROUP);
> +	mask = FIELD_GET(INTC_INTR_GROUP_IRQ, mask);
> +	while (mask) {
> +		i = fls(mask) - 1;
> +		mask &= ~BIT(i);
> +
> +		masked = readl_relaxed(s->base1 + REG_INTC_MASKED_IRQS(i));
> +		while (masked) {
> +			j = fls(masked) - 1;
> +			masked &= ~BIT(j);
> +
> +			generic_handle_irq(irq_find_mapping(s->domain,
> +							    i * 32 + j));
> +		}
> +	}
> +
> +	chained_irq_exit(chip, desc);
> +}
> +
> +static void sp7021_intc_ext1_irq_handle(struct irq_desc *desc)
> +{
> +	struct sp7021_intc_data *s = irq_desc_get_handler_data(desc);
> +	struct irq_chip *chip = irq_desc_get_chip(desc);
> +	u32 mask, masked;
> +	int i, j;
> +
> +	chained_irq_enter(chip, desc);
> +
> +	mask = readl_relaxed(s->base1 + REG_INTC_INTR_GROUP);
> +	mask = FIELD_GET(INTC_INTR_GROUP_FIQ, mask);
> +	while (mask) {
> +		i = fls(mask) - 1;
> +		mask &= ~BIT(i);
> +
> +		masked = readl_relaxed(s->base1 + REG_INTC_MASKED_FIQS(i));
> +		while (masked) {
> +			j = fls(masked) - 1;
> +			masked &= ~BIT(j);
> +
> +			generic_handle_irq(irq_find_mapping(s->domain,
> +							    i * 32 + j));
> +		}
> +	}
> +
> +	chained_irq_exit(chip, desc);
> +}

Given that the only difference between these two functions is
INTC_INTR_GROUP_IRQ vs INTC_INTR_GROUP_FIQ (whatever that means for
something connected to SPIs...), surely you can devise a way to make
this common code.

> +
> +static void sp7021_intc_ack_irq(struct irq_data *data)
> +{
> +	struct sp7021_intc_data *s = irq_data_get_irq_chip_data(data);
> +	unsigned int idx;
> +	u32 mask;
> +
> +	idx = data->hwirq / 32;

You have this construct everywhere. How about making all your offset
helpers take a hwirq number instead? It would certainly make the whole
thing look a little less fragile.

> +
> +	mask = BIT(data->hwirq % 32);
> +	writel_relaxed(mask, s->base1 + REG_INTC_INTR_CLR(idx));
> +}
> +
> +static void sp7021_intc_mask_irq(struct irq_data *data)
> +{
> +	struct sp7021_intc_data *s = irq_data_get_irq_chip_data(data);
> +	unsigned long flags;
> +	unsigned int idx;
> +	u32 mask;
> +
> +	idx = data->hwirq / 32;
> +
> +	raw_spin_lock_irqsave(&s->lock, flags);
> +
> +	mask = readl_relaxed(s->base0 + REG_INTC_INTR_MASK(idx));
> +	mask &= ~BIT(data->hwirq % 32);
> +	writel_relaxed(mask, s->base0 + REG_INTC_INTR_MASK(idx));
> +
> +	raw_spin_unlock_irqrestore(&s->lock, flags);
> +}
> +
> +static void sp7021_intc_unmask_irq(struct irq_data *data)
> +{
> +	struct sp7021_intc_data *s = irq_data_get_irq_chip_data(data);
> +	unsigned long flags;
> +	unsigned int idx;
> +	u32 mask;
> +
> +	idx = data->hwirq / 32;
> +
> +	raw_spin_lock_irqsave(&s->lock, flags);
> +
> +	mask = readl_relaxed(s->base0 + REG_INTC_INTR_MASK(idx));
> +	mask |= BIT(data->hwirq % 32);
> +	writel_relaxed(mask, s->base0 + REG_INTC_INTR_MASK(idx));
> +
> +	raw_spin_unlock_irqrestore(&s->lock, flags);
> +}
> +
> +static int sp7021_intc_set_irq_type(struct irq_data *data, unsigned int flow_type)
> +{
> +	struct sp7021_intc_data *s = irq_data_get_irq_chip_data(data);
> +	unsigned long flags;
> +	unsigned int idx;
> +	u32 mask, type, polarity;
> +
> +	idx = data->hwirq / 32;
> +	mask = BIT(data->hwirq % 32);
> +
> +	if (flow_type & IRQ_TYPE_LEVEL_MASK)
> +		irq_set_chip_handler_name_locked(data, &s->chip, handle_level_irq, NULL);
> +	else
> +		irq_set_chip_handler_name_locked(data, &s->chip, handle_edge_irq, NULL);

Now you've changed the flow type even if the checks below end-up
failing. Don't do that. Also, please use irq_set_chip_handler_locked()
instead. You don't need to change the irqchip.

> +
> +	raw_spin_lock_irqsave(&s->lock, flags);
> +
> +	type = readl_relaxed(s->base0 + REG_INTC_INTR_TYPE(idx));
> +	polarity = readl_relaxed(s->base0 + REG_INTC_INTR_POLARITY(idx));
> +
> +	switch (flow_type) {
> +	case IRQ_TYPE_EDGE_RISING:
> +		type |= mask;
> +		polarity &= ~mask;
> +		break;
> +	case IRQ_TYPE_EDGE_FALLING:
> +		type |= mask;
> +		polarity |= mask;
> +		break;
> +	case IRQ_TYPE_LEVEL_HIGH:
> +		type &= ~mask;
> +		polarity &= ~mask;
> +		break;
> +	case IRQ_TYPE_LEVEL_LOW:
> +		type &= ~mask;
> +		polarity |= mask;
> +		break;
> +	default:
> +		raw_spin_unlock_irqrestore(&s->lock, flags);
> +		return -EBADR;

The canonical error to use is -EINVAL.

> +	}
> +
> +	writel_relaxed(type, s->base0 + REG_INTC_INTR_TYPE(idx));
> +	writel_relaxed(polarity, s->base0 + REG_INTC_INTR_POLARITY(idx));
> +
> +	raw_spin_unlock_irqrestore(&s->lock, flags);
> +
> +	return IRQ_SET_MASK_OK;
> +}
> +
> +static const struct irq_chip sp7021_intc_irq_chip = {
> +	.name			= "SP7021-A",
> +	.irq_ack		= sp7021_intc_ack_irq,
> +	.irq_mask		= sp7021_intc_mask_irq,
> +	.irq_unmask		= sp7021_intc_unmask_irq,
> +	.irq_set_type		= sp7021_intc_set_irq_type,

I assume this SoC is SMP. You need a set_affinity method that returns
-EINVAL.

> +};
> +
> +static int sp7021_intc_irq_domain_map(struct irq_domain *d,
> +		unsigned int irq, irq_hw_number_t hw)
> +{
> +	struct sp7021_intc_data *s = d->host_data;
> +	unsigned int idx;
> +	u32 mask, type;
> +
> +	idx = hw / 32;
> +	mask = BIT(hw % 32);
> +
> +	type = readl_relaxed(s->base0 + REG_INTC_INTR_TYPE(idx));
> +
> +	irq_set_chip_and_handler(irq, &s->chip, (type & mask) ? handle_edge_irq : handle_level_irq);
> +	irq_set_chip_data(irq, s);
> +	irq_set_probe(irq);
> +
> +	return 0;
> +}
> +
> +static const struct irq_domain_ops sp7021_intc_domain_ops = {
> +	.xlate	= irq_domain_xlate_onecell,

If it is a single cell, how do you express the interrupt polarity in
the DT? Specially when the DT binding says that #interrupt-cells = <2>.
Clearly, you have never tested this.

> +	.map	= sp7021_intc_irq_domain_map,
> +};
> +
> +int __init sp7021_intc_init(struct device_node *node, struct device_node *parent)
> +{
> +	struct sp7021_intc_data *s;
> +	void __iomem *base0, *base1;
> +	int i;
> +
> +	base0 = of_iomap(node, 0);
> +	if (!base0)
> +		return -EIO;

-ENOMEM.

> +
> +	base1 = of_iomap(node, 1);
> +	if (!base1)
> +		return -EIO;

Leaking mapping.

> +
> +	s = kzalloc(sizeof(*s), GFP_KERNEL);
> +	if (!s)
> +		return -ENOMEM;

Again.

> +
> +	s->base0 = base0;
> +	s->base1 = base1;
> +	s->chip = sp7021_intc_irq_chip;

That's exactly what I was complaining about earlier: pointlessly
storing a copy of a static const data structure that never gets
updated. Drop this.

> +
> +	s->ext0_irq = irq_of_parse_and_map(node, 0);
> +	if (s->ext0_irq <= 0) {
> +		kfree(s);
> +		return -EINVAL;
> +	}
> +
> +	s->ext1_irq = irq_of_parse_and_map(node, 1);
> +	if (s->ext1_irq <= 0) {
> +		kfree(s);
> +		return -EINVAL;
> +	}
> +
> +	raw_spin_lock_init(&s->lock);
> +
> +	for (i = 0; i < 7; i++) {
> +		writel_relaxed(0, s->base0 + REG_INTC_INTR_MASK(i));
> +		writel_relaxed(~0, s->base0 + REG_INTC_INTR_TYPE(i));
> +		writel_relaxed(0, s->base0 + REG_INTC_INTR_POLARITY(i));
> +
> +		/* irq, not fiq */
> +		writel_relaxed(~0, s->base0 + REG_INTC_INTR_PRIO(i));
> +
> +		writel_relaxed(~0, s->base1 + REG_INTC_INTR_CLR(i));
> +	}
> +
> +	s->domain = irq_domain_add_linear(node, 200, &sp7021_intc_domain_ops,

Magic numbers.

> +					  s);
> +	if (!s->domain) {
> +		kfree(s);
> +		return -ENOMEM;
> +	}
> +
> +	irq_set_chained_handler_and_data(s->ext0_irq, sp7021_intc_ext0_irq_handle, s);
> +	irq_set_chained_handler_and_data(s->ext1_irq, sp7021_intc_ext1_irq_handle, s);
> +
> +	return 0;
> +}
> +IRQCHIP_DECLARE(sp7021_intc, "sunplus,sp7021-intc", sp7021_intc_init);

So yes, I complained a lot. Thanks for giving me the opportunity.

	M.

-- 
Jazz is not dead, it just smells funny.

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

* RE: [RFC 00/11] ARM: Initial Sunplus Plus1 SP7021 and BPI-F2S support
  2020-03-08 16:32 [RFC 00/11] ARM: Initial Sunplus Plus1 SP7021 and BPI-F2S support Andreas Färber
                   ` (10 preceding siblings ...)
  2020-03-08 16:32 ` [RFC 11/11] ARM: dts: sp7021-cpu: Add dummy UART0 clock and interrupt Andreas Färber
@ 2020-03-09  5:32 ` Wells Lu 呂芳騰
  11 siblings, 0 replies; 16+ messages in thread
From: Wells Lu 呂芳騰 @ 2020-03-09  5:32 UTC (permalink / raw)
  To: Andreas Färber, linux-arm-kernel
  Cc: Dvorkin Dmitry, linux-kernel, devicetree, Rob Herring,
	Greg Kroah-Hartman, linux-serial, Thomas Gleixner, Jason Cooper,
	Marc Zyngier, 张杰, 覃健

Added Jie Zhang and Jian Qin in to cc list.

Jie Zhang is software leader of Sunplus Plus 1 (SP7021) platform.


-----Original Message-----
From: Andreas Färber <afaerber@suse.de> 
Sent: Monday, March 09, 2020 12:32 AM
To: linux-arm-kernel@lists.infradead.org
Cc: Wells Lu 呂芳騰 <wells.lu@sunplus.com>; Dvorkin Dmitry <dvorkin@tibbo.com>; linux-kernel@vger.kernel.org; Andreas Färber <afaerber@suse.de>; devicetree@vger.kernel.org; Rob Herring <robh+dt@kernel.org>; Greg Kroah-Hartman <gregkh@linuxfoundation.org>; linux-serial@vger.kernel.org; Thomas Gleixner <tglx@linutronix.de>; Jason Cooper <jason@lakedaemon.net>; Marc Zyngier <maz@kernel.org>
Subject: [RFC 00/11] ARM: Initial Sunplus Plus1 SP7021 and BPI-F2S support

Hello,

This patch series adds initial drivers and Device Trees for Sunplus Plus1 series (codename Pentagram) SP7021 SoC and Banana Pi BPI-F2S SBC.

First, minimal Kconfig, DT and earlycon driver are prepared to get serial output at all. Next, interrupt controller and full serial driver are added that allow to boot into an initrd with interactive serial console.

Device Tree files added are for the CPU-Chip (aka A-Chip) with quad Cortex-A7, but the file split prepares for also adding the Peripheral-Chip (B-Chip) with
ARM9 later. However, for now this is not reflected in the .dts filename; this corresponds to the vf610- vs. vf610m4- naming scheme, whereas an alternative would be to use sp7021-cchip- vs. -pchip- prefix (as sp7021-cpu- looks weird).
It is assumed we can reuse the same SoC and board bindings for CA7 and ARM9 and only differ for IP blocks where needed.

My inquiry to Sunplus about their GIC (anticipating complaints from Marc) remained unanswered, so I've added the two extra regions and irq myself, without being able to test KVM due to BSP U-Boot not booting in HYP mode.
According to Sunplus the mode can be changed in U-Boot (but where/how?).

Similarly, the architectural timer is not properly initialized in BSP U-Boot, so that I currently have a mach- hack in my tree below. Unlike RTD1195, we do have U-Boot sources (v2019.04 based), so should be able to fix this in the bootloader rather than in the kernel, thus not included as patch here.

Based on SoC online manual [1] and downstream BPI-F2S BSP tree [2] as well as my previous Actions serial and Realtek irqchip drivers and DTs.

More details at:
https://en.opensuse.org/HCL:BananaPi_F2S

Latest experimental patches at:
https://github.com/afaerber/linux/commits/f2s-next

Have a lot of fun!

Cheers,
Andreas

[1] https://sunplus-tibbo.atlassian.net/wiki/spaces/doc/pages/470450252/SP7021+Technical+Manual
[2] https://github.com/BPI-SINOVOIP/BPI-F2S-bsp

Cc: devicetree@vger.kernel.org
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: linux-serial@vger.kernel.org
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Marc Zyngier <maz@kernel.org>
Cc: Wells Lu 呂芳騰 <wells.lu@sunplus.com>
Cc: Dvorkin Dmitry <dvorkin@tibbo.com>

Andreas Färber (11):
  dt-bindings: vendor-prefixes: Add Sunplus
  dt-bindings: arm: Add Sunplus SP7021 and Banana Pi BPI-F2S
  ARM: Prepare Sunplus Plus1 SoC family
  dt-bindings: interrupt-controller: Add Sunplus SP7021 mux
  dt-bindings: serial: Add Sunplus SP7021 UART
  tty: serial: Add Sunplus Plus1 UART earlycon
  ARM: dts: Add Sunplus Plus1 SP7021 and Banana Pi F2S
  tty: serial: sunplus: Implement full UART driver
  irqchip: Add Sunplus SP7021 interrupt (mux) controller
  ARM: dts: sp7021-cpu: Add interrupt controller node
  ARM: dts: sp7021-cpu: Add dummy UART0 clock and interrupt

 Documentation/devicetree/bindings/arm/sunplus.yaml |  22 +
 .../sunplus,pentagram-intc.yaml                    |  50 ++
 .../bindings/serial/sunplus,pentagram-uart.yaml    |  24 +
 .../devicetree/bindings/vendor-prefixes.yaml       |   2 +
 arch/arm/Kconfig                                   |   2 +
 arch/arm/Makefile                                  |   1 +
 arch/arm/boot/dts/Makefile                         |   2 +
 arch/arm/boot/dts/pentagram-sp7021-bpi-f2s.dts     |  29 +
 arch/arm/boot/dts/pentagram-sp7021-cpu.dtsi        |  93 +++
 arch/arm/boot/dts/pentagram-sp7021.dtsi            |  61 ++
 arch/arm/mach-sunplus/Kconfig                      |  10 +
 drivers/irqchip/Makefile                           |   1 +
 drivers/irqchip/irq-sp7021.c                       | 285 ++++++++
 drivers/tty/serial/Kconfig                         |  19 +
 drivers/tty/serial/Makefile                        |   1 +
 drivers/tty/serial/sunplus-uart.c                  | 770 +++++++++++++++++++++
 include/uapi/linux/serial_core.h                   |   3 +
 17 files changed, 1375 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/sunplus.yaml
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/sunplus,pentagram-intc.yaml
 create mode 100644 Documentation/devicetree/bindings/serial/sunplus,pentagram-uart.yaml
 create mode 100644 arch/arm/boot/dts/pentagram-sp7021-bpi-f2s.dts
 create mode 100644 arch/arm/boot/dts/pentagram-sp7021-cpu.dtsi
 create mode 100644 arch/arm/boot/dts/pentagram-sp7021.dtsi
 create mode 100644 arch/arm/mach-sunplus/Kconfig  create mode 100644 drivers/irqchip/irq-sp7021.c  create mode 100644 drivers/tty/serial/sunplus-uart.c

--
2.16.4


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

* Re: [RFC 04/11] dt-bindings: interrupt-controller: Add Sunplus SP7021 mux
  2020-03-08 16:32 ` [RFC 04/11] dt-bindings: interrupt-controller: Add Sunplus SP7021 mux Andreas Färber
@ 2020-03-23 19:48   ` Rob Herring
  0 siblings, 0 replies; 16+ messages in thread
From: Rob Herring @ 2020-03-23 19:48 UTC (permalink / raw)
  To: Andreas Färber
  Cc: linux-arm-kernel, Wells Lu 呂芳騰,
	Dvorkin Dmitry, linux-kernel, Thomas Gleixner, Jason Cooper,
	Marc Zyngier, devicetree

On Sun, Mar 08, 2020 at 05:32:22PM +0100, Andreas Färber wrote:
> The Sunplus SP7021 SoC has an interrupt mux.
> 
> Cc: Wells Lu 呂芳騰 <wells.lu@sunplus.com>
> Signed-off-by: Andreas Färber <afaerber@suse.de>
> ---
>  .../sunplus,pentagram-intc.yaml                    | 50 ++++++++++++++++++++++
>  1 file changed, 50 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/interrupt-controller/sunplus,pentagram-intc.yaml
> 
> diff --git a/Documentation/devicetree/bindings/interrupt-controller/sunplus,pentagram-intc.yaml b/Documentation/devicetree/bindings/interrupt-controller/sunplus,pentagram-intc.yaml
> new file mode 100644
> index 000000000000..baaf7bcd4a71
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/interrupt-controller/sunplus,pentagram-intc.yaml
> @@ -0,0 +1,50 @@
> +# SPDX-License-Identifier: GPL-2.0-or-later OR BSD-2-Clause
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/interrupt-controller/sunplus,pentagram-intc.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Sunplus Pentagram SoC Interrupt Controller
> +
> +maintainers:
> +  - Andreas Färber <afaerber@suse.de>
> +
> +allOf:
> +  - $ref: /schemas/interrupt-controller.yaml#

No need for this. It's applied based on the node name.

> +
> +properties:
> +  compatible:
> +    const: sunplus,sp7021-intc
> +
> +  reg:
> +    maxItems: 2

Need to define what each one is.

> +
> +  interrupts:
> +    maxItems: 2

Same here.

> +
> +  interrupt-controller: true
> +
> +  "#interrupt-cells":
> +    const: 2
> +
> +required:
> +  - compatible
> +  - reg
> +  - interrupt-controller
> +
> +unevaluatedProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/interrupt-controller/arm-gic.h>
> +
> +    interrupt-controller@9c000780 {
> +        compatible = "sunplus,sp7021-intc";
> +        reg = <0x9c000780 0x80>,
> +              <0x9c000a80 0x80>;
> +        interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>,
> +                     <GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
> +        interrupt-controller;
> +        #interrupt-cells = <2>;
> +    };
> +...
> -- 
> 2.16.4
> 

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

* Re: [RFC 05/11] dt-bindings: serial: Add Sunplus SP7021 UART
  2020-03-08 16:32 ` [RFC 05/11] dt-bindings: serial: Add Sunplus SP7021 UART Andreas Färber
@ 2020-03-23 19:50   ` Rob Herring
  0 siblings, 0 replies; 16+ messages in thread
From: Rob Herring @ 2020-03-23 19:50 UTC (permalink / raw)
  To: Andreas Färber
  Cc: linux-arm-kernel, Wells Lu 呂芳騰,
	Dvorkin Dmitry, linux-kernel, Greg Kroah-Hartman, linux-serial,
	devicetree

On Sun, Mar 08, 2020 at 05:32:23PM +0100, Andreas Färber wrote:
> The Sunplus Plus1 (aka Pentagram) SP7021 SoC has five UARTs.
> 
> Cc: Wells Lu 呂芳騰 <wells.lu@sunplus.com>
> Signed-off-by: Andreas Färber <afaerber@suse.de>
> ---
>  .../bindings/serial/sunplus,pentagram-uart.yaml    | 24 ++++++++++++++++++++++
>  1 file changed, 24 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/serial/sunplus,pentagram-uart.yaml
> 
> diff --git a/Documentation/devicetree/bindings/serial/sunplus,pentagram-uart.yaml b/Documentation/devicetree/bindings/serial/sunplus,pentagram-uart.yaml
> new file mode 100644
> index 000000000000..9d1641232a4c
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/serial/sunplus,pentagram-uart.yaml
> @@ -0,0 +1,24 @@
> +# SPDX-License-Identifier: GPL-2.0-or-later OR BSD-2-Clause
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/serial/sunplus,pentagram-uart.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: Sunplus Pentagram SoC UART Serial Interface
> +
> +maintainers:
> +  - Andreas Färber <afaerber@suse.de>
> +

Soon this will need to reference serial.yaml which is getting added to 
5.7.

> +properties:
> +  compatible:
> +    const: sunplus,sp7021-uart
> +
> +  reg:
> +    maxItems: 1
> +
> +  interrupts:
> +    maxItems: 1
> +
> +  clocks:
> +    maxItems: 1
> +...
> -- 
> 2.16.4
> 

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

end of thread, other threads:[~2020-03-23 19:50 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-03-08 16:32 [RFC 00/11] ARM: Initial Sunplus Plus1 SP7021 and BPI-F2S support Andreas Färber
2020-03-08 16:32 ` [RFC 01/11] dt-bindings: vendor-prefixes: Add Sunplus Andreas Färber
2020-03-08 16:32 ` [RFC 02/11] dt-bindings: arm: Add Sunplus SP7021 and Banana Pi BPI-F2S Andreas Färber
2020-03-08 16:32 ` [RFC 03/11] ARM: Prepare Sunplus Plus1 SoC family Andreas Färber
2020-03-08 16:32 ` [RFC 04/11] dt-bindings: interrupt-controller: Add Sunplus SP7021 mux Andreas Färber
2020-03-23 19:48   ` Rob Herring
2020-03-08 16:32 ` [RFC 05/11] dt-bindings: serial: Add Sunplus SP7021 UART Andreas Färber
2020-03-23 19:50   ` Rob Herring
2020-03-08 16:32 ` [RFC 06/11] tty: serial: Add Sunplus Plus1 UART earlycon Andreas Färber
2020-03-08 16:32 ` [RFC 07/11] ARM: dts: Add Sunplus Plus1 SP7021 and Banana Pi F2S Andreas Färber
2020-03-08 16:32 ` [RFC 08/11] tty: serial: sunplus: Implement full UART driver Andreas Färber
2020-03-08 16:32 ` [RFC 09/11] irqchip: Add Sunplus SP7021 interrupt (mux) controller Andreas Färber
2020-03-08 17:57   ` Marc Zyngier
2020-03-08 16:32 ` [RFC 10/11] ARM: dts: sp7021-cpu: Add interrupt controller node Andreas Färber
2020-03-08 16:32 ` [RFC 11/11] ARM: dts: sp7021-cpu: Add dummy UART0 clock and interrupt Andreas Färber
2020-03-09  5:32 ` [RFC 00/11] ARM: Initial Sunplus Plus1 SP7021 and BPI-F2S support Wells Lu 呂芳騰

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