public inbox for linux-serial@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 00/28] ARM: Initial Actions Semi S500 and S900 enablement
@ 2017-06-06  0:53 Andreas Färber
  2017-06-06  0:54 ` [PATCH v4 08/28] dt-bindings: serial: Document Actions Semi Owl UARTs Andreas Färber
                   ` (2 more replies)
  0 siblings, 3 replies; 15+ messages in thread
From: Andreas Färber @ 2017-06-06  0:53 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Mark Rutland, Ulf Hansson, linux-doc, 刘炜,
	devicetree, mp-cs, 96boards, Rob Herring, Kevin Hilman,
	Daniel Lezcano, linux-serial, support, Arnd Bergmann, linux-pm,
	Thomas Gleixner, 张天益, Greg Kroah-Hartman,
	Jonathan Corbet, Rafael J . Wysocki, linux-kernel, Thomas Liau,
	张东风, Olof Johansson

Hello,

This patch series adds initial support for Actions Semiconductor S500 (ARMv7)
and S900 (ARMv8) SoCs.

v4 refactors the clocksource driver again and fixes power-gating for CPU2/CPU3.

With this v4 I would like to start applying initial patches to my tree for 4.13.

@Actions:    Last call for comments on vendor prefix and SoC bindings!
@uCRobotics: Last call for comments on vendor prefix and board bindings!
@LeMaker:    Last call for comments on module and board bindings!

Work branch for testing:
https://github.com/afaerber/linux/commits/bg96-next

Booting from U-Boot to initrd is straightforward on both boards:

https://en.opensuse.org/HCL:Guitar
https://en.opensuse.org/HCL:Bubblegum-96

Have a lot of fun!

Cheers,
Andreas

v3 -> v4:
* Revert to hardcoded TIMER0/1 in clocksource (Daniel)
* Make power domains CPU2 and CPU3 always-on
* Clean up SMP vs. PM domains code duplication
* Extend earlycon documentation (Jonathan)
* Update MAINTAINERS with SPS files

v2 -> v3:
* Clocksource fix
* Clocksource cleanups (Daniel)
* Serial cleanups
* Add S500 CPU enable-method
* Add power domain driver
* Rework clocksource for S900 compatibility

v1 -> v2:
* S900 DT fixes (Mark)
* Kconfig name changes (Arnd)
* Bubblegum-96 .dts rename
* Vendor prefix rename
* Minor cleanups
* Add serial driver
* Add MAINTAINERS section
* Use SPDX-License-Identifier in DT (Rob)
* Add clocksource driver

Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Olof Johansson <olof@lixom.net>
Cc: Rob Herring <robh@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Daniel Lezcano <daniel.lezcano@linaro.org>
Cc: Thomas Gleixner <tglx@linutronix.de>

Cc: mp-cs@actions-semi.com
Cc: Thomas Liau <thomas.liau@actions-semi.com>
Cc: 96boards@ucrobotics.com
Cc: support@lemaker.org

Cc: linux-serial@vger.kernel.org
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

Cc: linux-pm@vger.kernel.org
Cc: Rafael J. Wysocki <rjw@rjwysocki.net>
Cc: Kevin Hilman <khilman@kernel.org>
Cc: Ulf Hansson <ulf.hansson@linaro.org>

Cc: linux-doc@vger.kernel.org
Cc: Jonathan Corbet <corbet@lwn.net>

Cc: devicetree@vger.kernel.org

Andreas Färber (28):
  dt-bindings: Add vendor prefix for Actions Semi
  dt-bindings: arm: Document Actions Semi S500
  dt-bindings: timer: Document Owl timer
  clocksource: Add Owl timer
  clocksource: owl: Add S900 support
  ARM: Prepare Actions Semi S500
  ARM64: Prepare Actions Semi S900
  dt-bindings: serial: Document Actions Semi Owl UARTs
  tty: serial: Add Actions Semi Owl UART earlycon
  Documentation: kernel-parameters: Document owl earlycon
  ARM: dts: Add Actions Semi S500 and LeMaker Guitar
  dt-bindings: Add vendor prefix for uCRobotics
  dt-bindings: arm: Document Actions Semi S900
  ARM64: dts: Add Actions Semi S900 and Bubblegum-96
  MAINTAINERS: Add Actions Semi Owl section
  tty: serial: owl: Implement console driver
  ARM64: dts: actions: s900-bubblegum-96: Add fake uart5 clock
  ARM: dts: s500-guitar-bb-rev-b: Add fake uart3 clock
  dt-bindings: arm: cpus: Add S500 enable-method
  ARM: owl: Implement CPU enable-method for S500
  ARM: dts: s500: Set CPU enable-method
  dt-bindings: power: Add Owl SPS power domains
  soc: actions: Add Owl SPS
  MAINTAINERS: Update Actions Semi section with SPS
  ARM: dts: s500: Add SPS node
  ARM: dts: s500: Set power domains for CPU2 and CPU3
  soc: actions: owl-sps: Factor out owl_sps_set_pg() for power-gating
  ARM: owl: smp: Implement SPS power-gating for CPU2 and CPU3

 Documentation/admin-guide/kernel-parameters.txt    |   6 +
 Documentation/devicetree/bindings/arm/actions.txt  |  39 ++
 Documentation/devicetree/bindings/arm/cpus.txt     |   1 +
 .../devicetree/bindings/power/actions,owl-sps.txt  |  17 +
 .../bindings/serial/actions,owl-uart.txt           |  16 +
 .../bindings/timer/actions,owl-timer.txt           |  20 +
 .../devicetree/bindings/vendor-prefixes.txt        |   2 +
 MAINTAINERS                                        |  13 +
 arch/arm/Kconfig                                   |   2 +
 arch/arm/Makefile                                  |   1 +
 arch/arm/boot/dts/Makefile                         |   2 +
 arch/arm/boot/dts/s500-guitar-bb-rev-b.dts         |  33 +
 arch/arm/boot/dts/s500-guitar.dtsi                 |  22 +
 arch/arm/boot/dts/s500.dtsi                        | 189 ++++++
 arch/arm/mach-actions/Kconfig                      |  16 +
 arch/arm/mach-actions/Makefile                     |   4 +
 arch/arm/mach-actions/headsmp.S                    |  68 ++
 arch/arm/mach-actions/owl.c                        |  28 +
 arch/arm/mach-actions/platsmp.c                    | 198 ++++++
 arch/arm64/Kconfig.platforms                       |   6 +
 arch/arm64/boot/dts/Makefile                       |   1 +
 arch/arm64/boot/dts/actions/Makefile               |   5 +
 arch/arm64/boot/dts/actions/s900-bubblegum-96.dts  |  42 ++
 arch/arm64/boot/dts/actions/s900.dtsi              | 164 +++++
 drivers/clocksource/Kconfig                        |   7 +
 drivers/clocksource/Makefile                       |   1 +
 drivers/clocksource/owl-timer.c                    | 172 +++++
 drivers/soc/Kconfig                                |   1 +
 drivers/soc/Makefile                               |   1 +
 drivers/soc/actions/Kconfig                        |  16 +
 drivers/soc/actions/Makefile                       |   2 +
 drivers/soc/actions/owl-sps-helper.c               |  51 ++
 drivers/soc/actions/owl-sps.c                      | 224 +++++++
 drivers/tty/serial/Kconfig                         |  19 +
 drivers/tty/serial/Makefile                        |   1 +
 drivers/tty/serial/owl-uart.c                      | 724 +++++++++++++++++++++
 include/dt-bindings/power/s500-powergate.h         |  19 +
 include/linux/soc/actions/owl-sps.h                |  11 +
 include/uapi/linux/serial_core.h                   |   3 +
 39 files changed, 2147 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/actions.txt
 create mode 100644 Documentation/devicetree/bindings/power/actions,owl-sps.txt
 create mode 100644 Documentation/devicetree/bindings/serial/actions,owl-uart.txt
 create mode 100644 Documentation/devicetree/bindings/timer/actions,owl-timer.txt
 create mode 100644 arch/arm/boot/dts/s500-guitar-bb-rev-b.dts
 create mode 100644 arch/arm/boot/dts/s500-guitar.dtsi
 create mode 100644 arch/arm/boot/dts/s500.dtsi
 create mode 100644 arch/arm/mach-actions/Kconfig
 create mode 100644 arch/arm/mach-actions/Makefile
 create mode 100644 arch/arm/mach-actions/headsmp.S
 create mode 100644 arch/arm/mach-actions/owl.c
 create mode 100644 arch/arm/mach-actions/platsmp.c
 create mode 100644 arch/arm64/boot/dts/actions/Makefile
 create mode 100644 arch/arm64/boot/dts/actions/s900-bubblegum-96.dts
 create mode 100644 arch/arm64/boot/dts/actions/s900.dtsi
 create mode 100644 drivers/clocksource/owl-timer.c
 create mode 100644 drivers/soc/actions/Kconfig
 create mode 100644 drivers/soc/actions/Makefile
 create mode 100644 drivers/soc/actions/owl-sps-helper.c
 create mode 100644 drivers/soc/actions/owl-sps.c
 create mode 100644 drivers/tty/serial/owl-uart.c
 create mode 100644 include/dt-bindings/power/s500-powergate.h
 create mode 100644 include/linux/soc/actions/owl-sps.h

-- 
2.12.3


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v4 08/28] dt-bindings: serial: Document Actions Semi Owl UARTs
  2017-06-06  0:53 [PATCH v4 00/28] ARM: Initial Actions Semi S500 and S900 enablement Andreas Färber
@ 2017-06-06  0:54 ` Andreas Färber
  2017-06-06  0:54 ` [PATCH v4 09/28] tty: serial: Add Actions Semi Owl UART earlycon Andreas Färber
  2017-06-06  0:54 ` [PATCH v4 16/28] tty: serial: owl: Implement console driver Andreas Färber
  2 siblings, 0 replies; 15+ messages in thread
From: Andreas Färber @ 2017-06-06  0:54 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Mark Rutland, support, 张天益, devicetree,
	Greg Kroah-Hartman, 96boards, linux-kernel, Thomas Liau,
	Rob Herring, mp-cs, linux-serial, 刘炜,
	Andreas Färber, 张东风

This UART is found on S500 and S900 SoCs.

Acked-by: Rob Herring <robh@kernel.org>
Signed-off-by: Andreas Färber <afaerber@suse.de>
---
 v3 -> v4: Unchanged
 
 v2 -> v3: unchanged
 
 v1 -> v2:
 * Adopted "actions" vendor prefix
 
 .../devicetree/bindings/serial/actions,owl-uart.txt      | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/serial/actions,owl-uart.txt

diff --git a/Documentation/devicetree/bindings/serial/actions,owl-uart.txt b/Documentation/devicetree/bindings/serial/actions,owl-uart.txt
new file mode 100644
index 000000000000..aa873eada02d
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/actions,owl-uart.txt
@@ -0,0 +1,16 @@
+Actions Semi Owl UART
+
+Required properties:
+- compatible :  "actions,s500-uart", "actions,owl-uart" for S500
+                "actions,s900-uart", "actions,owl-uart" for S900
+- reg        :  Offset and length of the register set for the device.
+- interrupts :  Should contain UART interrupt.
+
+
+Example:
+
+		uart3: serial@b0126000 {
+			compatible = "actions,s500-uart", "actions,owl-uart";
+			reg = <0xb0126000 0x1000>;
+			interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+		};
-- 
2.12.3


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v4 09/28] tty: serial: Add Actions Semi Owl UART earlycon
  2017-06-06  0:53 [PATCH v4 00/28] ARM: Initial Actions Semi S500 and S900 enablement Andreas Färber
  2017-06-06  0:54 ` [PATCH v4 08/28] dt-bindings: serial: Document Actions Semi Owl UARTs Andreas Färber
@ 2017-06-06  0:54 ` Andreas Färber
  2017-06-18 21:45   ` Andreas Färber
  2017-06-06  0:54 ` [PATCH v4 16/28] tty: serial: owl: Implement console driver Andreas Färber
  2 siblings, 1 reply; 15+ messages in thread
From: Andreas Färber @ 2017-06-06  0:54 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: support, 张天益, Greg Kroah-Hartman, 96boards,
	linux-kernel, Thomas Liau, mp-cs, linux-serial, 刘炜,
	Jiri Slaby, Andreas Färber, 张东风

This implements an earlycon for Actions Semi S500/S900 SoCs.

Based on LeMaker linux-actions tree.

Signed-off-by: Andreas Färber <afaerber@suse.de>
---
 v3 -> v4: Unchanged
 
 v2 -> v3:
 * Adopted BIT() macro
 
 v1 -> v2:
 * Extended Kconfig help to mention earlycon (Arnd)
 * Spelled out Actions Semiconductor in Kconfig help
 * Adopted "actions" vendor prefix
 
 drivers/tty/serial/Kconfig    |  19 ++++++
 drivers/tty/serial/Makefile   |   1 +
 drivers/tty/serial/owl-uart.c | 135 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 155 insertions(+)
 create mode 100644 drivers/tty/serial/owl-uart.c

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 5c8850f7a2a0..38f90ea45cf7 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1688,6 +1688,25 @@ config SERIAL_MVEBU_CONSOLE
 	  and warnings and which allows logins in single user mode)
 	  Otherwise, say 'N'.
 
+config SERIAL_OWL
+	bool "Actions Semi Owl serial port support"
+	depends on ARCH_ACTIONS || COMPILE_TEST
+	select SERIAL_CORE
+	help
+	  This driver is for Actions Semiconductor S500/S900 SoC's UART.
+	  Say 'Y' here if you wish to use the on-board serial port.
+	  Otherwise, say 'N'.
+
+config SERIAL_OWL_CONSOLE
+	bool "Console on Actions Semi Owl serial port"
+	depends on SERIAL_OWL=y
+	select SERIAL_CORE_CONSOLE
+	select SERIAL_EARLYCON
+	default y
+	help
+	  Say 'Y' here if you wish to use Actions Semiconductor S500/S900 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 53c03e005132..fe88a75d9a59 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -92,6 +92,7 @@ obj-$(CONFIG_SERIAL_STM32)	+= stm32-usart.o
 obj-$(CONFIG_SERIAL_MVEBU_UART)	+= mvebu-uart.o
 obj-$(CONFIG_SERIAL_PIC32)	+= pic32_uart.o
 obj-$(CONFIG_SERIAL_MPS2_UART)	+= mps2-uart.o
+obj-$(CONFIG_SERIAL_OWL)	+= owl-uart.o
 
 # GPIOLIB helpers for modem control lines
 obj-$(CONFIG_SERIAL_MCTRL_GPIO)	+= serial_mctrl_gpio.o
diff --git a/drivers/tty/serial/owl-uart.c b/drivers/tty/serial/owl-uart.c
new file mode 100644
index 000000000000..1b8008797a1b
--- /dev/null
+++ b/drivers/tty/serial/owl-uart.c
@@ -0,0 +1,135 @@
+/*
+ * Actions Semi Owl family serial console
+ *
+ * Copyright 2013 Actions Semi Inc.
+ * Author: Actions Semi, Inc.
+ *
+ * Copyright (c) 2016-2017 Andreas Färber
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/console.h>
+#include <linux/delay.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 OWL_UART_CTL	0x000
+#define OWL_UART_TXDAT	0x008
+#define OWL_UART_STAT	0x00c
+
+#define OWL_UART_CTL_TRFS_TX		BIT(14)
+#define OWL_UART_CTL_EN			BIT(15)
+#define OWL_UART_CTL_RXIE		BIT(18)
+#define OWL_UART_CTL_TXIE		BIT(19)
+
+#define OWL_UART_STAT_RIP		BIT(0)
+#define OWL_UART_STAT_TIP		BIT(1)
+#define OWL_UART_STAT_TFFU		BIT(6)
+#define OWL_UART_STAT_TRFL_MASK		(0x1f << 11)
+#define OWL_UART_STAT_UTBB		BIT(17)
+
+static inline void owl_uart_write(struct uart_port *port, u32 val, unsigned int off)
+{
+	writel(val, port->membase + off);
+}
+
+static inline u32 owl_uart_read(struct uart_port *port, unsigned int off)
+{
+	return readl(port->membase + off);
+}
+
+#ifdef CONFIG_SERIAL_OWL_CONSOLE
+
+static void owl_console_putchar(struct uart_port *port, int ch)
+{
+	if (!port->membase)
+		return;
+
+	while (owl_uart_read(port, OWL_UART_STAT) & OWL_UART_STAT_TFFU)
+		cpu_relax();
+
+	owl_uart_write(port, ch, OWL_UART_TXDAT);
+}
+
+static void owl_uart_port_write(struct uart_port *port, const char *s,
+				u_int count)
+{
+	u32 old_ctl, val;
+	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;
+	}
+
+	old_ctl = owl_uart_read(port, OWL_UART_CTL);
+	val = old_ctl | OWL_UART_CTL_TRFS_TX;
+	/* disable IRQ */
+	val &= ~(OWL_UART_CTL_RXIE | OWL_UART_CTL_TXIE);
+	owl_uart_write(port, val, OWL_UART_CTL);
+
+	uart_console_write(port, s, count, owl_console_putchar);
+
+	/* wait until all contents have been sent out */
+	while (owl_uart_read(port, OWL_UART_STAT) & OWL_UART_STAT_TRFL_MASK)
+		cpu_relax();
+
+	/* clear IRQ pending */
+	val = owl_uart_read(port, OWL_UART_STAT);
+	val |= OWL_UART_STAT_TIP | OWL_UART_STAT_RIP;
+	owl_uart_write(port, val, OWL_UART_STAT);
+
+	owl_uart_write(port, old_ctl, OWL_UART_CTL);
+
+	if (locked)
+		spin_unlock(&port->lock);
+
+	local_irq_restore(flags);
+}
+
+static void owl_uart_early_console_write(struct console *co,
+					 const char *s,
+					 u_int count)
+{
+	struct earlycon_device *dev = co->data;
+
+	owl_uart_port_write(&dev->port, s, count);
+}
+
+static int __init
+owl_uart_early_console_setup(struct earlycon_device *device, const char *opt)
+{
+	if (!device->port.membase)
+		return -ENODEV;
+
+	device->con->write = owl_uart_early_console_write;
+
+	return 0;
+}
+OF_EARLYCON_DECLARE(owl, "actions,owl-uart",
+		    owl_uart_early_console_setup);
+
+#endif /* CONFIG_SERIAL_OWL_CONSOLE */
-- 
2.12.3


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH v4 16/28] tty: serial: owl: Implement console driver
  2017-06-06  0:53 [PATCH v4 00/28] ARM: Initial Actions Semi S500 and S900 enablement Andreas Färber
  2017-06-06  0:54 ` [PATCH v4 08/28] dt-bindings: serial: Document Actions Semi Owl UARTs Andreas Färber
  2017-06-06  0:54 ` [PATCH v4 09/28] tty: serial: Add Actions Semi Owl UART earlycon Andreas Färber
@ 2017-06-06  0:54 ` Andreas Färber
  2017-06-06 13:34   ` Alan Cox
  2017-06-07 14:37   ` Andy Shevchenko
  2 siblings, 2 replies; 15+ messages in thread
From: Andreas Färber @ 2017-06-06  0:54 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: mp-cs, Thomas Liau, 张东风, 刘炜,
	张天益, 96boards, support, linux-kernel,
	Andreas Färber, Greg Kroah-Hartman, Jiri Slaby, linux-serial

Implement serial console driver to complement earlycon.

Based on LeMaker linux-actions tree.

Signed-off-by: Andreas Färber <afaerber@suse.de>
---
 v3 -> v4: Unchanged
 
 v2 -> v3:
 * Adopted BIT() macro
 * Implemented baudrate setting
 
 v2: new
 
 drivers/tty/serial/Kconfig       |   4 +-
 drivers/tty/serial/owl-uart.c    | 591 ++++++++++++++++++++++++++++++++++++++-
 include/uapi/linux/serial_core.h |   3 +
 3 files changed, 595 insertions(+), 3 deletions(-)

diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 38f90ea45cf7..b0cddfbd8d74 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1689,7 +1689,7 @@ config SERIAL_MVEBU_CONSOLE
 	  Otherwise, say 'N'.
 
 config SERIAL_OWL
-	bool "Actions Semi Owl serial port support"
+	tristate "Actions Semi Owl serial port support"
 	depends on ARCH_ACTIONS || COMPILE_TEST
 	select SERIAL_CORE
 	help
@@ -1705,7 +1705,7 @@ config SERIAL_OWL_CONSOLE
 	default y
 	help
 	  Say 'Y' here if you wish to use Actions Semiconductor S500/S900 UART
-	  as the system console. Only earlycon is implemented currently.
+	  as the system console.
 
 endmenu
 
diff --git a/drivers/tty/serial/owl-uart.c b/drivers/tty/serial/owl-uart.c
index 1b8008797a1b..14e0324144cf 100644
--- a/drivers/tty/serial/owl-uart.c
+++ b/drivers/tty/serial/owl-uart.c
@@ -20,6 +20,7 @@
  * along with this program. If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <linux/clk.h>
 #include <linux/console.h>
 #include <linux/delay.h>
 #include <linux/io.h>
@@ -28,22 +29,59 @@
 #include <linux/platform_device.h>
 #include <linux/serial.h>
 #include <linux/serial_core.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+
+#define OWL_UART_PORT_NUM 7
+#define OWL_UART_DEV_NAME "ttyOWL"
 
 #define OWL_UART_CTL	0x000
+#define OWL_UART_RXDAT	0x004
 #define OWL_UART_TXDAT	0x008
 #define OWL_UART_STAT	0x00c
 
+#define OWL_UART_CTL_DWLS_MASK		(0x3 << 0)
+#define OWL_UART_CTL_DWLS_5BITS		(0x0 << 0)
+#define OWL_UART_CTL_DWLS_6BITS		(0x1 << 0)
+#define OWL_UART_CTL_DWLS_7BITS		(0x2 << 0)
+#define OWL_UART_CTL_DWLS_8BITS		(0x3 << 0)
+#define OWL_UART_CTL_STPS_2BITS		BIT(2)
+#define OWL_UART_CTL_PRS_MASK		(0x7 << 4)
+#define OWL_UART_CTL_PRS_NONE		(0x0 << 4)
+#define OWL_UART_CTL_PRS_ODD		(0x4 << 4)
+#define OWL_UART_CTL_PRS_MARK		(0x5 << 4)
+#define OWL_UART_CTL_PRS_EVEN		(0x6 << 4)
+#define OWL_UART_CTL_PRS_SPACE		(0x7 << 4)
+#define OWL_UART_CTL_AFE		BIT(12)
 #define OWL_UART_CTL_TRFS_TX		BIT(14)
 #define OWL_UART_CTL_EN			BIT(15)
+#define OWL_UART_CTL_RXDE		BIT(16)
+#define OWL_UART_CTL_TXDE		BIT(17)
 #define OWL_UART_CTL_RXIE		BIT(18)
 #define OWL_UART_CTL_TXIE		BIT(19)
 
 #define OWL_UART_STAT_RIP		BIT(0)
 #define OWL_UART_STAT_TIP		BIT(1)
+#define OWL_UART_STAT_RXER		BIT(2)
+#define OWL_UART_STAT_TFER		BIT(3)
+#define OWL_UART_STAT_RXST		BIT(4)
+#define OWL_UART_STAT_RFEM		BIT(5)
 #define OWL_UART_STAT_TFFU		BIT(6)
+#define OWL_UART_STAT_TFES		BIT(10)
 #define OWL_UART_STAT_TRFL_MASK		(0x1f << 11)
 #define OWL_UART_STAT_UTBB		BIT(17)
 
+static struct uart_driver owl_uart_driver;
+
+struct owl_uart_port {
+	struct uart_port port;
+	struct clk *clk;
+};
+
+#define to_owl_uart_port(prt) container_of(prt, struct owl_uart_port, prt)
+
+static struct owl_uart_port *owl_uart_ports[OWL_UART_PORT_NUM];
+
 static inline void owl_uart_write(struct uart_port *port, u32 val, unsigned int off)
 {
 	writel(val, port->membase + off);
@@ -54,6 +92,380 @@ static inline u32 owl_uart_read(struct uart_port *port, unsigned int off)
 	return readl(port->membase + off);
 }
 
+static void owl_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+static unsigned int owl_uart_get_mctrl(struct uart_port *port)
+{
+	return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS;
+}
+
+static unsigned int owl_uart_tx_empty(struct uart_port *port)
+{
+	unsigned long flags;
+	u32 val;
+	unsigned int ret;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	val = owl_uart_read(port, OWL_UART_STAT);
+	ret = (val & OWL_UART_STAT_TFES) ? TIOCSER_TEMT : 0;
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	return ret;
+}
+
+static void owl_uart_stop_rx(struct uart_port *port)
+{
+	u32 val;
+
+	val = owl_uart_read(port, OWL_UART_CTL);
+	val &= ~(OWL_UART_CTL_RXIE | OWL_UART_CTL_RXDE);
+	owl_uart_write(port, val, OWL_UART_CTL);
+
+	val = owl_uart_read(port, OWL_UART_STAT);
+	val |= OWL_UART_STAT_RIP;
+	owl_uart_write(port, val, OWL_UART_STAT);
+}
+
+static void owl_uart_stop_tx(struct uart_port *port)
+{
+	u32 val;
+
+	val = owl_uart_read(port, OWL_UART_CTL);
+	val &= ~(OWL_UART_CTL_TXIE | OWL_UART_CTL_TXDE);
+	owl_uart_write(port, val, OWL_UART_CTL);
+
+	val = owl_uart_read(port, OWL_UART_STAT);
+	val |= OWL_UART_STAT_TIP;
+	owl_uart_write(port, val, OWL_UART_STAT);
+}
+
+static void owl_uart_start_tx(struct uart_port *port)
+{
+	u32 val;
+
+	if (uart_tx_stopped(port)) {
+		owl_uart_stop_tx(port);
+		return;
+	}
+
+	val = owl_uart_read(port, OWL_UART_STAT);
+	val |= OWL_UART_STAT_TIP;
+	owl_uart_write(port, val, OWL_UART_STAT);
+
+	val = owl_uart_read(port, OWL_UART_CTL);
+	val |= OWL_UART_CTL_TXIE;
+	owl_uart_write(port, val, OWL_UART_CTL);
+}
+
+static void owl_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 (!(owl_uart_read(port, OWL_UART_STAT) & OWL_UART_STAT_TFFU))
+			cpu_relax();
+		owl_uart_write(port, port->x_char, OWL_UART_TXDAT);
+		port->icount.tx++;
+		port->x_char = 0;
+	}
+
+	while (!(owl_uart_read(port, OWL_UART_STAT) & OWL_UART_STAT_TFFU)) {
+		if (uart_circ_empty(xmit))
+			break;
+
+		ch = xmit->buf[xmit->tail];
+		owl_uart_write(port, ch, OWL_UART_TXDAT);
+		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))
+		owl_uart_stop_tx(port);
+}
+
+static void owl_uart_receive_chars(struct uart_port *port)
+{
+	u32 stat, val;
+
+	val = owl_uart_read(port, OWL_UART_CTL);
+	val &= ~OWL_UART_CTL_TRFS_TX;
+	owl_uart_write(port, val, OWL_UART_CTL);
+
+	stat = owl_uart_read(port, OWL_UART_STAT);
+	while (!(stat & OWL_UART_STAT_RFEM)) {
+		char flag = TTY_NORMAL;
+
+		if (stat & OWL_UART_STAT_RXER)
+			port->icount.overrun++;
+
+		if (stat & OWL_UART_STAT_RXST) {
+			/* We are not able to distinguish the error type. */
+			port->icount.brk++;
+			port->icount.frame++;
+
+			stat &= port->read_status_mask;
+			if (stat & OWL_UART_STAT_RXST)
+				flag = TTY_PARITY;
+		} else
+			port->icount.rx++;
+
+		val = owl_uart_read(port, OWL_UART_RXDAT);
+		val &= 0xff;
+
+		if ((stat & port->ignore_status_mask) == 0)
+			tty_insert_flip_char(&port->state->port, val, flag);
+
+		stat = owl_uart_read(port, OWL_UART_STAT);
+	}
+
+	spin_unlock(&port->lock);
+	tty_flip_buffer_push(&port->state->port);
+	spin_lock(&port->lock);
+}
+
+static irqreturn_t owl_uart_irq(int irq, void *dev_id)
+{
+	struct uart_port *port = (struct uart_port *)dev_id;
+	u32 stat;
+
+	spin_lock(&port->lock);
+
+	stat = owl_uart_read(port, OWL_UART_STAT);
+
+	if (stat & OWL_UART_STAT_RIP)
+		owl_uart_receive_chars(port);
+
+	if (stat & OWL_UART_STAT_TIP)
+		owl_uart_send_chars(port);
+
+	stat = owl_uart_read(port, OWL_UART_STAT);
+	stat |= OWL_UART_STAT_RIP | OWL_UART_STAT_TIP;
+	owl_uart_write(port, stat, OWL_UART_STAT);
+
+	spin_unlock(&port->lock);
+
+	return IRQ_HANDLED;
+}
+
+static void owl_uart_shutdown(struct uart_port *port)
+{
+	u32 val;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	val = owl_uart_read(port, OWL_UART_CTL);
+	val &= ~(OWL_UART_CTL_TXIE | OWL_UART_CTL_RXIE
+		| OWL_UART_CTL_TXDE | OWL_UART_CTL_RXDE | OWL_UART_CTL_EN);
+	owl_uart_write(port, val, OWL_UART_CTL);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	free_irq(port->irq, port);
+}
+
+static int owl_uart_startup(struct uart_port *port)
+{
+	u32 val;
+	unsigned long flags;
+	int ret;
+
+	ret = request_irq(port->irq, owl_uart_irq, IRQF_TRIGGER_HIGH,
+			"owl-uart", port);
+	if (ret)
+		return ret;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	val = owl_uart_read(port, OWL_UART_STAT);
+	val |= OWL_UART_STAT_RIP | OWL_UART_STAT_TIP
+		| OWL_UART_STAT_RXER | OWL_UART_STAT_TFER | OWL_UART_STAT_RXST;
+	owl_uart_write(port, val, OWL_UART_STAT);
+
+	val = owl_uart_read(port, OWL_UART_CTL);
+	val |= OWL_UART_CTL_RXIE | OWL_UART_CTL_TXIE;
+	val |= OWL_UART_CTL_EN;
+	owl_uart_write(port, val, OWL_UART_CTL);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	return 0;
+}
+
+static void owl_uart_change_baudrate(struct owl_uart_port *owl_port,
+				     unsigned long baud)
+{
+	clk_set_rate(owl_port->clk, baud * 8);
+}
+
+static void owl_uart_set_termios(struct uart_port *port,
+				 struct ktermios *termios,
+				 struct ktermios *old)
+{
+	struct owl_uart_port *owl_port = to_owl_uart_port(port);
+	unsigned int baud;
+	u32 ctl;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	/* We don't support modem control lines. */
+	termios->c_cflag &= ~(HUPCL | CMSPAR);
+	termios->c_cflag |= CLOCAL;
+
+	/* We don't support BREAK character recognition. */
+	termios->c_iflag &= ~(IGNBRK | BRKINT);
+
+	ctl = owl_uart_read(port, OWL_UART_CTL);
+
+	ctl &= ~OWL_UART_CTL_DWLS_MASK;
+	switch (termios->c_cflag & CSIZE) {
+	case CS5:
+		ctl |= OWL_UART_CTL_DWLS_5BITS;
+		break;
+	case CS6:
+		ctl |= OWL_UART_CTL_DWLS_6BITS;
+		break;
+	case CS7:
+		ctl |= OWL_UART_CTL_DWLS_7BITS;
+		break;
+	case CS8:
+	default:
+		ctl |= OWL_UART_CTL_DWLS_8BITS;
+		break;
+	}
+
+	if (termios->c_cflag & CSTOPB)
+		ctl |= OWL_UART_CTL_STPS_2BITS;
+	else
+		ctl &= ~OWL_UART_CTL_STPS_2BITS;
+
+	ctl &= ~OWL_UART_CTL_PRS_MASK;
+	if (termios->c_cflag & PARENB) {
+		if (termios->c_cflag & CMSPAR) {
+			if (termios->c_cflag & PARODD)
+				ctl |= OWL_UART_CTL_PRS_MARK;
+			else
+				ctl |= OWL_UART_CTL_PRS_SPACE;
+		} else if (termios->c_cflag & PARODD)
+			ctl |= OWL_UART_CTL_PRS_ODD;
+		else
+			ctl |= OWL_UART_CTL_PRS_EVEN;
+	} else
+		ctl |= OWL_UART_CTL_PRS_NONE;
+
+	if (termios->c_cflag & CRTSCTS)
+		ctl |= OWL_UART_CTL_AFE;
+	else
+		ctl &= ~OWL_UART_CTL_AFE;
+
+	owl_uart_write(port, ctl, OWL_UART_CTL);
+
+	baud = uart_get_baud_rate(port, termios, old, 9600, 3200000);
+	owl_uart_change_baudrate(owl_port, baud);
+
+	port->read_status_mask |= OWL_UART_STAT_RXER;
+	if (termios->c_iflag & INPCK)
+		port->read_status_mask |= OWL_UART_STAT_RXST;
+
+	uart_update_timeout(port, termios->c_cflag, baud);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void owl_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 owl_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_nocache(port->dev, port->mapbase,
+				resource_size(res));
+		if (!port->membase)
+			return -EBUSY;
+	}
+
+	return 0;
+}
+
+static const char *owl_uart_type(struct uart_port *port)
+{
+	return (port->type == PORT_OWL) ? "owl-uart" : NULL;
+}
+
+static int owl_uart_verify_port(struct uart_port *port,
+				struct serial_struct *ser)
+{
+	if (port->type != PORT_OWL)
+		return -EINVAL;
+
+	if (port->irq != ser->irq)
+		return -EINVAL;
+
+	return 0;
+}
+
+static void owl_uart_config_port(struct uart_port *port, int flags)
+{
+	if (flags & UART_CONFIG_TYPE) {
+		port->type = PORT_OWL;
+		owl_uart_request_port(port);
+	}
+}
+
+static struct uart_ops owl_uart_ops = {
+	.set_mctrl = owl_uart_set_mctrl,
+	.get_mctrl = owl_uart_get_mctrl,
+	.tx_empty = owl_uart_tx_empty,
+	.start_tx = owl_uart_start_tx,
+	.stop_rx = owl_uart_stop_rx,
+	.stop_tx = owl_uart_stop_tx,
+	.startup = owl_uart_startup,
+	.shutdown = owl_uart_shutdown,
+	.set_termios = owl_uart_set_termios,
+	.type = owl_uart_type,
+	.config_port = owl_uart_config_port,
+	.request_port = owl_uart_request_port,
+	.release_port = owl_uart_release_port,
+	.verify_port = owl_uart_verify_port,
+};
+
 #ifdef CONFIG_SERIAL_OWL_CONSOLE
 
 static void owl_console_putchar(struct uart_port *port, int ch)
@@ -110,6 +522,57 @@ static void owl_uart_port_write(struct uart_port *port, const char *s,
 	local_irq_restore(flags);
 }
 
+static void owl_uart_console_write(struct console *co, const char *s,
+				   u_int count)
+{
+	struct owl_uart_port *owl_port;
+
+	owl_port = owl_uart_ports[co->index];
+	if (!owl_port)
+		return;
+
+	owl_uart_port_write(&owl_port->port, s, count);
+}
+
+static int owl_uart_console_setup(struct console *co, char *options)
+{
+	struct owl_uart_port *owl_port;
+	int baud = 115200;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
+
+	if (co->index < 0 || co->index >= OWL_UART_PORT_NUM)
+		return -EINVAL;
+
+	owl_port = owl_uart_ports[co->index];
+	if (!owl_port || !owl_port->port.membase)
+		return -ENODEV;
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+	return uart_set_options(&owl_port->port, co, baud, parity, bits, flow);
+}
+
+static struct console owl_uart_console = {
+	.name = OWL_UART_DEV_NAME,
+	.write = owl_uart_console_write,
+	.device = uart_console_device,
+	.setup = owl_uart_console_setup,
+	.flags = CON_PRINTBUFFER,
+	.index = -1,
+	.data = &owl_uart_driver,
+};
+
+static int __init owl_uart_console_init(void)
+{
+	register_console(&owl_uart_console);
+
+	return 0;
+}
+console_initcall(owl_uart_console_init);
+
 static void owl_uart_early_console_write(struct console *co,
 					 const char *s,
 					 u_int count)
@@ -132,4 +595,130 @@ owl_uart_early_console_setup(struct earlycon_device *device, const char *opt)
 OF_EARLYCON_DECLARE(owl, "actions,owl-uart",
 		    owl_uart_early_console_setup);
 
-#endif /* CONFIG_SERIAL_OWL_CONSOLE */
+#define OWL_UART_CONSOLE (&owl_uart_console)
+#else
+#define OWL_UART_CONSOLE NULL
+#endif
+
+static struct uart_driver owl_uart_driver = {
+	.owner = THIS_MODULE,
+	.driver_name = "owl-uart",
+	.dev_name = OWL_UART_DEV_NAME,
+	.nr = OWL_UART_PORT_NUM,
+	.cons = OWL_UART_CONSOLE,
+};
+
+static int owl_uart_probe(struct platform_device *pdev)
+{
+	struct resource *res_mem, *res_irq;
+	struct owl_uart_port *owl_port;
+	int ret;
+
+	if (pdev->dev.of_node)
+		pdev->id = of_alias_get_id(pdev->dev.of_node, "serial");
+
+	if (pdev->id < 0 || pdev->id >= OWL_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;
+	}
+
+	res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!res_irq) {
+		dev_err(&pdev->dev, "could not get irq\n");
+		return -ENODEV;
+	}
+
+	if (owl_uart_ports[pdev->id]) {
+		dev_err(&pdev->dev, "port %d already allocated\n", pdev->id);
+		return -EBUSY;
+	}
+
+	owl_port = devm_kzalloc(&pdev->dev, sizeof(*owl_port), GFP_KERNEL);
+	if (!owl_port)
+		return -ENOMEM;
+
+	owl_port->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(owl_port->clk)) {
+		dev_err(&pdev->dev, "could not get clk\n");
+		return PTR_ERR(owl_port->clk);
+	}
+
+	owl_port->port.dev = &pdev->dev;
+	owl_port->port.line = pdev->id;
+	owl_port->port.type = PORT_OWL;
+	owl_port->port.iotype = UPIO_MEM;
+	owl_port->port.mapbase = res_mem->start;
+	owl_port->port.irq = res_irq->start;
+	owl_port->port.uartclk = clk_get_rate(owl_port->clk);
+	owl_port->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_LOW_LATENCY;
+	owl_port->port.x_char = 0;
+	owl_port->port.fifosize = 16;
+	owl_port->port.ops = &owl_uart_ops;
+
+	owl_uart_ports[pdev->id] = owl_port;
+	platform_set_drvdata(pdev, owl_port);
+
+	ret = uart_add_one_port(&owl_uart_driver, &owl_port->port);
+	if (ret)
+		owl_uart_ports[pdev->id] = NULL;
+
+	return ret;
+}
+
+static int owl_uart_remove(struct platform_device *pdev)
+{
+	struct owl_uart_port *owl_port;
+
+	owl_port = platform_get_drvdata(pdev);
+	uart_remove_one_port(&owl_uart_driver, &owl_port->port);
+	owl_uart_ports[pdev->id] = NULL;
+
+	return 0;
+}
+
+static const struct of_device_id owl_uart_dt_matches[] = {
+	{ .compatible = "actions,owl-uart" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, owl_uart_dt_matches);
+
+static struct platform_driver owl_uart_platform_driver = {
+	.probe = owl_uart_probe,
+	.remove = owl_uart_remove,
+	.driver = {
+		.name = "owl-uart",
+		.of_match_table = owl_uart_dt_matches,
+	},
+};
+
+static int __init owl_uart_init(void)
+{
+	int ret;
+
+	ret = uart_register_driver(&owl_uart_driver);
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&owl_uart_platform_driver);
+	if (ret)
+		uart_unregister_driver(&owl_uart_driver);
+
+	return ret;
+}
+
+static void __init owl_uart_exit(void)
+{
+	platform_driver_unregister(&owl_uart_platform_driver);
+	uart_unregister_driver(&owl_uart_driver);
+}
+
+module_init(owl_uart_init);
+module_exit(owl_uart_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
index 9ec741b133fe..5e850e68930d 100644
--- a/include/uapi/linux/serial_core.h
+++ b/include/uapi/linux/serial_core.h
@@ -271,4 +271,7 @@
 /* MPS2 UART */
 #define PORT_MPS2UART	116
 
+/* Actions Semi Owl UART */
+#define PORT_OWL	117
+
 #endif /* _UAPILINUX_SERIAL_CORE_H */
-- 
2.12.3

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

* Re: [PATCH v4 16/28] tty: serial: owl: Implement console driver
  2017-06-06  0:54 ` [PATCH v4 16/28] tty: serial: owl: Implement console driver Andreas Färber
@ 2017-06-06 13:34   ` Alan Cox
  2017-07-02 20:27     ` Andreas Färber
  2017-06-07 14:37   ` Andy Shevchenko
  1 sibling, 1 reply; 15+ messages in thread
From: Alan Cox @ 2017-06-06 13:34 UTC (permalink / raw)
  To: Andreas Färber
  Cc: support, 张天益, Greg Kroah-Hartman, 96boards,
	linux-kernel, Thomas Liau, mp-cs, linux-serial, 刘炜,
	Jiri Slaby, linux-arm-kernel, 张东风

> +
> +static void owl_uart_set_termios(struct uart_port *port,
> +				 struct ktermios *termios,
> +				 struct ktermios *old)
> +{
> +	struct owl_uart_port *owl_port = to_owl_uart_port(port);
> +	unsigned int baud;
> +	u32 ctl;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&port->lock, flags);
> +
> +	/* We don't support modem control lines. */
> +	termios->c_cflag &= ~(HUPCL | CMSPAR);
> +	termios->c_cflag |= CLOCAL;

CLOCAL and HUPCL are software not hardware properties so are probably
best not forced (it'll confuse some apps if you do)
> +
> +	/* We don't support BREAK character recognition. */
> +	termios->c_iflag &= ~(IGNBRK | BRKINT);

Ditto these


You do clear CMSPAR which is right if not supported but then later on we
have:

> +	if (termios->c_cflag & PARENB) {
> +		if (termios->c_cflag & CMSPAR) {
> +			if (termios->c_cflag & PARODD)
> +				ctl |= OWL_UART_CTL_PRS_MARK;
> +			else
> +				ctl |= OWL_UART_CTL_PRS_SPACE;
> +		} else if (termios->c_cflag & PARODD)
> +			ctl |= OWL_UART_CTL_PRS_ODD;
> +		else
> +			ctl |= OWL_UART_CTL_PRS_EVEN;
> +	} else
> +		ctl |= OWL_UART_CTL_PRS_NONE;


Which seems to indicate you do support CMSPAR so shouldn't be clearing it.

> +
> +	if (termios->c_cflag & CRTSCTS)
> +		ctl |= OWL_UART_CTL_AFE;
> +	else
> +		ctl &= ~OWL_UART_CTL_AFE;
> +
> +	owl_uart_write(port, ctl, OWL_UART_CTL);
> +
> +	baud = uart_get_baud_rate(port, termios, old, 9600, 3200000);
> +	owl_uart_change_baudrate(owl_port, baud);

You should re-encode the resulting baud rate into the termios

        /* Don't rewrite B0 */
        if (tty_termios_baud_rate(termios))
                tty_termios_encode_baud_rate(termios, baud, baud);

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

* Re: [PATCH v4 16/28] tty: serial: owl: Implement console driver
  2017-06-06  0:54 ` [PATCH v4 16/28] tty: serial: owl: Implement console driver Andreas Färber
  2017-06-06 13:34   ` Alan Cox
@ 2017-06-07 14:37   ` Andy Shevchenko
  2017-07-02 22:36     ` Andreas Färber
  1 sibling, 1 reply; 15+ messages in thread
From: Andy Shevchenko @ 2017-06-07 14:37 UTC (permalink / raw)
  To: Andreas Färber
  Cc: support, 张天益, Greg Kroah-Hartman, 96boards,
	linux-kernel@vger.kernel.org, Thomas Liau, mp-cs,
	linux-serial@vger.kernel.org, 刘炜, Jiri Slaby,
	linux-arm Mailing List, 张东风

On Tue, Jun 6, 2017 at 3:54 AM, Andreas Färber <afaerber@suse.de> wrote:
> Implement serial console driver to complement earlycon.
>
> Based on LeMaker linux-actions tree.

> +#define OWL_UART_CTL_DWLS_MASK         (0x3 << 0)

GENMASK() ?

> +#define OWL_UART_CTL_PRS_MASK          (0x7 << 4)

Ditto.

>  #define OWL_UART_STAT_TRFL_MASK                (0x1f << 11)

Ditto.

> +static struct owl_uart_port *owl_uart_ports[OWL_UART_PORT_NUM];

And this is needed for...?

> +static void owl_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
> +{
> +}

Do we need an empty stub?

> +static void owl_uart_send_chars(struct uart_port *port)
> +{

> +               xmit->tail = (xmit->tail + 1) & (SERIAL_XMIT_SIZE - 1);

% SERIAL_XMIT_SIZE shorter (I hope it's a power of 2), but it's up to you.

> +}

> +static irqreturn_t owl_uart_irq(int irq, void *dev_id)
> +{
> +       struct uart_port *port = (struct uart_port *)dev_id;

Useless casting.

> +       spin_lock(&port->lock);

spin_lock_irqsave() ?

Consider the kernel command option that switches all IRQ handlers to
be threaded.

> +}

> +static void owl_uart_change_baudrate(struct owl_uart_port *owl_port,
> +                                    unsigned long baud)
> +{
> +       clk_set_rate(owl_port->clk, baud * 8);
> +}

> +static void owl_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;
> +       }

Above is entirely redundant.

> +}
> +
> +static int owl_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_nocache(port->dev, port->mapbase,
> +                               resource_size(res));
> +               if (!port->membase)
> +                       return -EBUSY;
> +       }
> +
> +       return 0;
> +}

> +static void owl_uart_config_port(struct uart_port *port, int flags)
> +{

> +       if (flags & UART_CONFIG_TYPE) {

if (!(...))
 return;

?

> +               port->type = PORT_OWL;
> +               owl_uart_request_port(port);
> +       }
> +}


> +static int owl_uart_probe(struct platform_device *pdev)
> +{
> +       struct resource *res_mem, *res_irq;
> +       struct owl_uart_port *owl_port;
> +       int ret;
> +
> +       if (pdev->dev.of_node)
> +               pdev->id = of_alias_get_id(pdev->dev.of_node, "serial");
> +
> +       if (pdev->id < 0 || pdev->id >= OWL_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;
> +       }

You can use

struct resource *mem;

mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
x = devm_ioremap_resource();
if (IS_ERR(x))
 return PTR_ERR(x);

and remote IOREMAP flag below.

> +       res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> +       if (!res_irq) {
> +               dev_err(&pdev->dev, "could not get irq\n");
> +               return -ENODEV;
> +       }

platform_get_irq()

> +       if (owl_uart_ports[pdev->id]) {
> +               dev_err(&pdev->dev, "port %d already allocated\n", pdev->id);
> +               return -EBUSY;
> +       }

I guess it's redundant. It should be conflicting by resource (for example, IRQ).

> +       owl_port->clk = clk_get(&pdev->dev, NULL);

devm_ ?

> +       owl_port->port.iotype = UPIO_MEM;
> +       owl_port->port.mapbase = res_mem->start;
> +       owl_port->port.irq = res_irq->start;


> +       owl_port->port.uartclk = clk_get_rate(owl_port->clk);

You need to check if it's 0 and use device property instead or bail out.

> +       owl_port->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_LOW_LATENCY;
> +       owl_port->port.x_char = 0;
> +       owl_port->port.fifosize = 16;
> +       owl_port->port.ops = &owl_uart_ops;
> +
> +       owl_uart_ports[pdev->id] = owl_port;

> +       platform_set_drvdata(pdev, owl_port);

It should be just before return 0, right?..

> +
> +       ret = uart_add_one_port(&owl_uart_driver, &owl_port->port);
> +       if (ret)
> +               owl_uart_ports[pdev->id] = NULL;

...and thus, taking into consideration redundancy of that global var:

      ret = uart_add_one_port(&owl_uart_driver, &owl_port->port);
      if (ret)
          retrun ret;

      platform_set_drvdata(pdev, owl_port);
      return 0;

> +       return ret;
> +}

> +
> +static int owl_uart_remove(struct platform_device *pdev)
> +{

> +       struct owl_uart_port *owl_port;
> +
> +       owl_port = platform_get_drvdata(pdev);

Do above in one line.

> +       uart_remove_one_port(&owl_uart_driver, &owl_port->port);

> +       owl_uart_ports[pdev->id] = NULL;

Redundant.

> +
> +       return 0;
> +}

> +/* Actions Semi Owl UART */
> +#define PORT_OWL       117

We can use holes for now IIUC.

See 36 or alike

-- 
With Best Regards,
Andy Shevchenko

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v4 09/28] tty: serial: Add Actions Semi Owl UART earlycon
  2017-06-06  0:54 ` [PATCH v4 09/28] tty: serial: Add Actions Semi Owl UART earlycon Andreas Färber
@ 2017-06-18 21:45   ` Andreas Färber
  2017-06-19  1:16     ` Greg Kroah-Hartman
  0 siblings, 1 reply; 15+ messages in thread
From: Andreas Färber @ 2017-06-18 21:45 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: linux-arm-kernel, support, 张天益, 96boards,
	linux-kernel, Thomas Liau, mp-cs, linux-serial, 刘炜,
	Jiri Slaby, 张东风, Arnd Bergmann,
	Olof Johansson, Alan Cox, Andy Shevchenko

Greg,

Am 06.06.2017 um 02:54 schrieb Andreas Färber:
> This implements an earlycon for Actions Semi S500/S900 SoCs.
> 
> Based on LeMaker linux-actions tree.
> 
> Signed-off-by: Andreas Färber <afaerber@suse.de>
> ---
>  v3 -> v4: Unchanged
>  
>  v2 -> v3:
>  * Adopted BIT() macro
>  
>  v1 -> v2:
>  * Extended Kconfig help to mention earlycon (Arnd)
>  * Spelled out Actions Semiconductor in Kconfig help
>  * Adopted "actions" vendor prefix
>  
>  drivers/tty/serial/Kconfig    |  19 ++++++
>  drivers/tty/serial/Makefile   |   1 +
>  drivers/tty/serial/owl-uart.c | 135 ++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 155 insertions(+)
>  create mode 100644 drivers/tty/serial/owl-uart.c

The DT vendor prefix is applied to my linux-actions.git tree now, and
the serial binding has been ack'ed by Rob.

Is there anything keeping you from adding this patch, the preceding DT
binding (08/28) and the following documentation patch (10/28) to your
tree for 4.13?

The full serial driver (16/28) needs another spin and may miss 4.13, but
earlycon would prove the rest is working.

Thanks,
Andreas

-- 
SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)

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

* Re: [PATCH v4 09/28] tty: serial: Add Actions Semi Owl UART earlycon
  2017-06-18 21:45   ` Andreas Färber
@ 2017-06-19  1:16     ` Greg Kroah-Hartman
  2017-06-19  1:24       ` Andreas Färber
  0 siblings, 1 reply; 15+ messages in thread
From: Greg Kroah-Hartman @ 2017-06-19  1:16 UTC (permalink / raw)
  To: Andreas Färber
  Cc: linux-arm-kernel, support, 张天益, 96boards,
	linux-kernel, Thomas Liau, mp-cs, linux-serial, 刘炜,
	Jiri Slaby, 张东风, Arnd Bergmann,
	Olof Johansson, Alan Cox, Andy Shevchenko

On Sun, Jun 18, 2017 at 11:45:28PM +0200, Andreas Färber wrote:
> Greg,
> 
> Am 06.06.2017 um 02:54 schrieb Andreas Färber:
> > This implements an earlycon for Actions Semi S500/S900 SoCs.
> > 
> > Based on LeMaker linux-actions tree.
> > 
> > Signed-off-by: Andreas Färber <afaerber@suse.de>
> > ---
> >  v3 -> v4: Unchanged
> >  
> >  v2 -> v3:
> >  * Adopted BIT() macro
> >  
> >  v1 -> v2:
> >  * Extended Kconfig help to mention earlycon (Arnd)
> >  * Spelled out Actions Semiconductor in Kconfig help
> >  * Adopted "actions" vendor prefix
> >  
> >  drivers/tty/serial/Kconfig    |  19 ++++++
> >  drivers/tty/serial/Makefile   |   1 +
> >  drivers/tty/serial/owl-uart.c | 135 ++++++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 155 insertions(+)
> >  create mode 100644 drivers/tty/serial/owl-uart.c
> 
> The DT vendor prefix is applied to my linux-actions.git tree now, and
> the serial binding has been ack'ed by Rob.
> 
> Is there anything keeping you from adding this patch, the preceding DT
> binding (08/28) and the following documentation patch (10/28) to your
> tree for 4.13?

Yeah, I don't have it in my queue anymore :)

Can you resend it just as a single patch?

thanks,

greg k-h

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

* Re: [PATCH v4 09/28] tty: serial: Add Actions Semi Owl UART earlycon
  2017-06-19  1:16     ` Greg Kroah-Hartman
@ 2017-06-19  1:24       ` Andreas Färber
       [not found]         ` <7fff8813-cea4-0530-bf7b-3d0ad50d6e93-l3A5Bk7waGM@public.gmane.org>
  2017-06-19  2:12         ` [PATCH v4 09/28] " Greg Kroah-Hartman
  0 siblings, 2 replies; 15+ messages in thread
From: Andreas Färber @ 2017-06-19  1:24 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: linux-arm-kernel, support, 张天益, 96boards,
	linux-kernel, Thomas Liau, mp-cs, linux-serial, 刘炜,
	Jiri Slaby, 张东风, Arnd Bergmann,
	Olof Johansson, Alan Cox, Andy Shevchenko

Am 19.06.2017 um 03:16 schrieb Greg Kroah-Hartman:
> On Sun, Jun 18, 2017 at 11:45:28PM +0200, Andreas Färber wrote:
>> Greg,
>>
>> Am 06.06.2017 um 02:54 schrieb Andreas Färber:
>>> This implements an earlycon for Actions Semi S500/S900 SoCs.
>>>
>>> Based on LeMaker linux-actions tree.
>>>
>>> Signed-off-by: Andreas Färber <afaerber@suse.de>
>>
>> The DT vendor prefix is applied to my linux-actions.git tree now, and
>> the serial binding has been ack'ed by Rob.
>>
>> Is there anything keeping you from adding this patch, the preceding DT
>> binding (08/28) and the following documentation patch (10/28) to your
>> tree for 4.13?
> 
> Yeah, I don't have it in my queue anymore :)
> 
> Can you resend it just as a single patch?

Do you mean squash the documentation into this tty patch? As you wish.
But the DT binding is supposed to be a separate patch - I can queue it
in my tree if you prefer.

Cheers,
Andreas

-- 
SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)

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

* [PATCH v5 07/26] dt-bindings: serial: Document Actions Semi Owl UARTs
       [not found]         ` <7fff8813-cea4-0530-bf7b-3d0ad50d6e93-l3A5Bk7waGM@public.gmane.org>
@ 2017-06-19  1:46           ` Andreas Färber
  2017-06-19  1:46             ` [PATCH v5 08/26] tty: serial: Add Actions Semi Owl UART earlycon Andreas Färber
  0 siblings, 1 reply; 15+ messages in thread
From: Andreas Färber @ 2017-06-19  1:46 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	mp-cs-/sSyCTpAT0ql5r2w9Jh5Rg, Thomas Liau,
	张东风, 刘炜,
	张天益, 96boards-Ty1hIZOCd2XuufBYgWm87A,
	support-8Vy/tIz7429AfugRpC6u6w,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Andreas Färber,
	Rob Herring, Mark Rutland, linux-serial-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

This UART is found on S500 and S900 SoCs.

Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Signed-off-by: Andreas Färber <afaerber-l3A5Bk7waGM@public.gmane.org>
---
 v2 -> v3 -> v4 -> v5: Unchanged
 
 v1 -> v2:
 * Adopted "actions" vendor prefix
 
 .../devicetree/bindings/serial/actions,owl-uart.txt      | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/serial/actions,owl-uart.txt

diff --git a/Documentation/devicetree/bindings/serial/actions,owl-uart.txt b/Documentation/devicetree/bindings/serial/actions,owl-uart.txt
new file mode 100644
index 000000000000..aa873eada02d
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/actions,owl-uart.txt
@@ -0,0 +1,16 @@
+Actions Semi Owl UART
+
+Required properties:
+- compatible :  "actions,s500-uart", "actions,owl-uart" for S500
+                "actions,s900-uart", "actions,owl-uart" for S900
+- reg        :  Offset and length of the register set for the device.
+- interrupts :  Should contain UART interrupt.
+
+
+Example:
+
+		uart3: serial@b0126000 {
+			compatible = "actions,s500-uart", "actions,owl-uart";
+			reg = <0xb0126000 0x1000>;
+			interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+		};
-- 
2.12.3

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

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

* [PATCH v5 08/26] tty: serial: Add Actions Semi Owl UART earlycon
  2017-06-19  1:46           ` [PATCH v5 07/26] dt-bindings: serial: Document Actions Semi Owl UARTs Andreas Färber
@ 2017-06-19  1:46             ` Andreas Färber
  0 siblings, 0 replies; 15+ messages in thread
From: Andreas Färber @ 2017-06-19  1:46 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: linux-arm-kernel, mp-cs, Thomas Liau, 张东风,
	刘炜, 张天益, 96boards, support,
	linux-kernel, Andreas Färber, Jonathan Corbet, Jiri Slaby,
	linux-doc, linux-serial

This implements an earlycon for Actions Semi S500/S900 SoCs.

Based on LeMaker linux-actions tree.

Signed-off-by: Andreas Färber <afaerber@suse.de>
---
 v4 -> v5:
 * Squashed documentation (Greg)
 
 v3 -> v4: Unchanged
 
 v2 -> v3:
 * Adopted BIT() macro
 
 v1 -> v2:
 * Extended Kconfig help to mention earlycon (Arnd)
 * Spelled out Actions Semiconductor in Kconfig help
 * Adopted "actions" vendor prefix
 
 Documentation/admin-guide/kernel-parameters.txt |   6 ++
 drivers/tty/serial/Kconfig                      |  19 ++++
 drivers/tty/serial/Makefile                     |   1 +
 drivers/tty/serial/owl-uart.c                   | 135 ++++++++++++++++++++++++
 4 files changed, 161 insertions(+)
 create mode 100644 drivers/tty/serial/owl-uart.c

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index fb311bdccb7b..cc8a6bfcb299 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -961,6 +961,12 @@
 			must already be setup and configured. Options are not
 			yet supported.
 
+		owl,<addr>
+			Start an early, polled-mode console on a serial port
+			of an Actions Semi SoC, such as S500 or S900, at the
+			specified address. The serial port must already be
+			setup and configured. Options are not yet supported.
+
 		smh	Use ARM semihosting calls for early console.
 
 		s3c2410,<addr>
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 07812a7ea2a4..1f096e2bb398 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1688,6 +1688,25 @@ config SERIAL_MVEBU_CONSOLE
 	  and warnings and which allows logins in single user mode)
 	  Otherwise, say 'N'.
 
+config SERIAL_OWL
+	bool "Actions Semi Owl serial port support"
+	depends on ARCH_ACTIONS || COMPILE_TEST
+	select SERIAL_CORE
+	help
+	  This driver is for Actions Semiconductor S500/S900 SoC's UART.
+	  Say 'Y' here if you wish to use the on-board serial port.
+	  Otherwise, say 'N'.
+
+config SERIAL_OWL_CONSOLE
+	bool "Console on Actions Semi Owl serial port"
+	depends on SERIAL_OWL=y
+	select SERIAL_CORE_CONSOLE
+	select SERIAL_EARLYCON
+	default y
+	help
+	  Say 'Y' here if you wish to use Actions Semiconductor S500/S900 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 53c03e005132..fe88a75d9a59 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -92,6 +92,7 @@ obj-$(CONFIG_SERIAL_STM32)	+= stm32-usart.o
 obj-$(CONFIG_SERIAL_MVEBU_UART)	+= mvebu-uart.o
 obj-$(CONFIG_SERIAL_PIC32)	+= pic32_uart.o
 obj-$(CONFIG_SERIAL_MPS2_UART)	+= mps2-uart.o
+obj-$(CONFIG_SERIAL_OWL)	+= owl-uart.o
 
 # GPIOLIB helpers for modem control lines
 obj-$(CONFIG_SERIAL_MCTRL_GPIO)	+= serial_mctrl_gpio.o
diff --git a/drivers/tty/serial/owl-uart.c b/drivers/tty/serial/owl-uart.c
new file mode 100644
index 000000000000..1b8008797a1b
--- /dev/null
+++ b/drivers/tty/serial/owl-uart.c
@@ -0,0 +1,135 @@
+/*
+ * Actions Semi Owl family serial console
+ *
+ * Copyright 2013 Actions Semi Inc.
+ * Author: Actions Semi, Inc.
+ *
+ * Copyright (c) 2016-2017 Andreas Färber
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/console.h>
+#include <linux/delay.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 OWL_UART_CTL	0x000
+#define OWL_UART_TXDAT	0x008
+#define OWL_UART_STAT	0x00c
+
+#define OWL_UART_CTL_TRFS_TX		BIT(14)
+#define OWL_UART_CTL_EN			BIT(15)
+#define OWL_UART_CTL_RXIE		BIT(18)
+#define OWL_UART_CTL_TXIE		BIT(19)
+
+#define OWL_UART_STAT_RIP		BIT(0)
+#define OWL_UART_STAT_TIP		BIT(1)
+#define OWL_UART_STAT_TFFU		BIT(6)
+#define OWL_UART_STAT_TRFL_MASK		(0x1f << 11)
+#define OWL_UART_STAT_UTBB		BIT(17)
+
+static inline void owl_uart_write(struct uart_port *port, u32 val, unsigned int off)
+{
+	writel(val, port->membase + off);
+}
+
+static inline u32 owl_uart_read(struct uart_port *port, unsigned int off)
+{
+	return readl(port->membase + off);
+}
+
+#ifdef CONFIG_SERIAL_OWL_CONSOLE
+
+static void owl_console_putchar(struct uart_port *port, int ch)
+{
+	if (!port->membase)
+		return;
+
+	while (owl_uart_read(port, OWL_UART_STAT) & OWL_UART_STAT_TFFU)
+		cpu_relax();
+
+	owl_uart_write(port, ch, OWL_UART_TXDAT);
+}
+
+static void owl_uart_port_write(struct uart_port *port, const char *s,
+				u_int count)
+{
+	u32 old_ctl, val;
+	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;
+	}
+
+	old_ctl = owl_uart_read(port, OWL_UART_CTL);
+	val = old_ctl | OWL_UART_CTL_TRFS_TX;
+	/* disable IRQ */
+	val &= ~(OWL_UART_CTL_RXIE | OWL_UART_CTL_TXIE);
+	owl_uart_write(port, val, OWL_UART_CTL);
+
+	uart_console_write(port, s, count, owl_console_putchar);
+
+	/* wait until all contents have been sent out */
+	while (owl_uart_read(port, OWL_UART_STAT) & OWL_UART_STAT_TRFL_MASK)
+		cpu_relax();
+
+	/* clear IRQ pending */
+	val = owl_uart_read(port, OWL_UART_STAT);
+	val |= OWL_UART_STAT_TIP | OWL_UART_STAT_RIP;
+	owl_uart_write(port, val, OWL_UART_STAT);
+
+	owl_uart_write(port, old_ctl, OWL_UART_CTL);
+
+	if (locked)
+		spin_unlock(&port->lock);
+
+	local_irq_restore(flags);
+}
+
+static void owl_uart_early_console_write(struct console *co,
+					 const char *s,
+					 u_int count)
+{
+	struct earlycon_device *dev = co->data;
+
+	owl_uart_port_write(&dev->port, s, count);
+}
+
+static int __init
+owl_uart_early_console_setup(struct earlycon_device *device, const char *opt)
+{
+	if (!device->port.membase)
+		return -ENODEV;
+
+	device->con->write = owl_uart_early_console_write;
+
+	return 0;
+}
+OF_EARLYCON_DECLARE(owl, "actions,owl-uart",
+		    owl_uart_early_console_setup);
+
+#endif /* CONFIG_SERIAL_OWL_CONSOLE */
-- 
2.12.3


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

* Re: [PATCH v4 09/28] tty: serial: Add Actions Semi Owl UART earlycon
  2017-06-19  1:24       ` Andreas Färber
       [not found]         ` <7fff8813-cea4-0530-bf7b-3d0ad50d6e93-l3A5Bk7waGM@public.gmane.org>
@ 2017-06-19  2:12         ` Greg Kroah-Hartman
  2017-06-19  2:26           ` Andreas Färber
  1 sibling, 1 reply; 15+ messages in thread
From: Greg Kroah-Hartman @ 2017-06-19  2:12 UTC (permalink / raw)
  To: Andreas Färber
  Cc: linux-arm-kernel, support, 张天益, 96boards,
	linux-kernel, Thomas Liau, mp-cs, linux-serial, 刘炜,
	Jiri Slaby, 张东风, Arnd Bergmann,
	Olof Johansson, Alan Cox, Andy Shevchenko

On Mon, Jun 19, 2017 at 03:24:44AM +0200, Andreas Färber wrote:
> Am 19.06.2017 um 03:16 schrieb Greg Kroah-Hartman:
> > On Sun, Jun 18, 2017 at 11:45:28PM +0200, Andreas Färber wrote:
> >> Greg,
> >>
> >> Am 06.06.2017 um 02:54 schrieb Andreas Färber:
> >>> This implements an earlycon for Actions Semi S500/S900 SoCs.
> >>>
> >>> Based on LeMaker linux-actions tree.
> >>>
> >>> Signed-off-by: Andreas Färber <afaerber@suse.de>
> >>
> >> The DT vendor prefix is applied to my linux-actions.git tree now, and
> >> the serial binding has been ack'ed by Rob.
> >>
> >> Is there anything keeping you from adding this patch, the preceding DT
> >> binding (08/28) and the following documentation patch (10/28) to your
> >> tree for 4.13?
> > 
> > Yeah, I don't have it in my queue anymore :)
> > 
> > Can you resend it just as a single patch?
> 
> Do you mean squash the documentation into this tty patch? As you wish.
> But the DT binding is supposed to be a separate patch - I can queue it
> in my tree if you prefer.

No, just send me what ever you want me to apply to my tree.  If you want
me to pick some random patch out of the middle of a series, um, that's a
bit hard for me to know what to do, right?

Make it very very obvious please :)

thanks,

greg k-h

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

* Re: [PATCH v4 09/28] tty: serial: Add Actions Semi Owl UART earlycon
  2017-06-19  2:12         ` [PATCH v4 09/28] " Greg Kroah-Hartman
@ 2017-06-19  2:26           ` Andreas Färber
  0 siblings, 0 replies; 15+ messages in thread
From: Andreas Färber @ 2017-06-19  2:26 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: linux-arm-kernel, support, 张天益, 96boards,
	linux-kernel, Thomas Liau, mp-cs, linux-serial, 刘炜,
	Jiri Slaby, 张东风, Arnd Bergmann,
	Olof Johansson, Alan Cox, Andy Shevchenko

Am 19.06.2017 um 04:12 schrieb Greg Kroah-Hartman:
> On Mon, Jun 19, 2017 at 03:24:44AM +0200, Andreas Färber wrote:
>> Am 19.06.2017 um 03:16 schrieb Greg Kroah-Hartman:
>>> On Sun, Jun 18, 2017 at 11:45:28PM +0200, Andreas Färber wrote:
>>>> Am 06.06.2017 um 02:54 schrieb Andreas Färber:
>>>>> This implements an earlycon for Actions Semi S500/S900 SoCs.
>>>>>
>>>>> Based on LeMaker linux-actions tree.
>>>>>
>>>>> Signed-off-by: Andreas Färber <afaerber@suse.de>
>>>>
>>>> The DT vendor prefix is applied to my linux-actions.git tree now, and
>>>> the serial binding has been ack'ed by Rob.
>>>>
>>>> Is there anything keeping you from adding this patch, the preceding DT
>>>> binding (08/28) and the following documentation patch (10/28) to your
>>>> tree for 4.13?
>>>
>>> Yeah, I don't have it in my queue anymore :)
>>>
>>> Can you resend it just as a single patch?
>>
>> Do you mean squash the documentation into this tty patch? As you wish.
>> But the DT binding is supposed to be a separate patch - I can queue it
>> in my tree if you prefer.
> 
> No, just send me what ever you want me to apply to my tree.  If you want
> me to pick some random patch out of the middle of a series, um, that's a
> bit hard for me to know what to do, right?

Well, I thought that would be obvious from subject, diff stat and CC...
Only dependencies were ARCH_ACTIONS and actions vendor prefix, which
should be in linux-next by tomorrow.

> 
> Make it very very obvious please :)

I already resent the now two patches as v5 with you as only To.

Thanks,
Andreas

-- 
SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)

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

* Re: [PATCH v4 16/28] tty: serial: owl: Implement console driver
  2017-06-06 13:34   ` Alan Cox
@ 2017-07-02 20:27     ` Andreas Färber
  0 siblings, 0 replies; 15+ messages in thread
From: Andreas Färber @ 2017-07-02 20:27 UTC (permalink / raw)
  To: Alan Cox
  Cc: support, 张天益, Greg Kroah-Hartman, 96boards,
	linux-kernel, Thomas Liau, mp-cs, linux-serial, 刘炜,
	Jiri Slaby, linux-arm-kernel, 张东风,
	梅利, support, lee

Am 06.06.2017 um 15:34 schrieb Alan Cox:
>> +static void owl_uart_set_termios(struct uart_port *port,
>> +				 struct ktermios *termios,
>> +				 struct ktermios *old)
>> +{
>> +	struct owl_uart_port *owl_port = to_owl_uart_port(port);
>> +	unsigned int baud;
>> +	u32 ctl;
>> +	unsigned long flags;
>> +
>> +	spin_lock_irqsave(&port->lock, flags);
>> +
>> +	/* We don't support modem control lines. */
>> +	termios->c_cflag &= ~(HUPCL | CMSPAR);
>> +	termios->c_cflag |= CLOCAL;
> 
> CLOCAL and HUPCL are software not hardware properties so are probably
> best not forced (it'll confuse some apps if you do)
>> +
>> +	/* We don't support BREAK character recognition. */
>> +	termios->c_iflag &= ~(IGNBRK | BRKINT);
> 
> Ditto these

Fixed. These were obviously forward-ported from the vendor tree.

https://github.com/LeMaker/linux-actions/blob/linux-3.10.y/arch/arm/mach-owl/serial-owl.c

> You do clear CMSPAR which is right if not supported but then later on we
> have:
> 
>> +	if (termios->c_cflag & PARENB) {
>> +		if (termios->c_cflag & CMSPAR) {
>> +			if (termios->c_cflag & PARODD)
>> +				ctl |= OWL_UART_CTL_PRS_MARK;
>> +			else
>> +				ctl |= OWL_UART_CTL_PRS_SPACE;
>> +		} else if (termios->c_cflag & PARODD)
>> +			ctl |= OWL_UART_CTL_PRS_ODD;
>> +		else
>> +			ctl |= OWL_UART_CTL_PRS_EVEN;
>> +	} else
>> +		ctl |= OWL_UART_CTL_PRS_NONE;
> 
> 
> Which seems to indicate you do support CMSPAR so shouldn't be clearing it.

Again that's what the original code was like.

Since these register values do exist, I would rather not rip the code
out, unless it's wrong. In my testing, not clearing CMSPAR works so far.

>> +	baud = uart_get_baud_rate(port, termios, old, 9600, 3200000);
>> +	owl_uart_change_baudrate(owl_port, baud);
> 
> You should re-encode the resulting baud rate into the termios
> 
>         /* Don't rewrite B0 */
>         if (tty_termios_baud_rate(termios))
>                 tty_termios_encode_baud_rate(termios, baud, baud);

Added, thanks.

Regards,
Andreas

-- 
SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)

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

* Re: [PATCH v4 16/28] tty: serial: owl: Implement console driver
  2017-06-07 14:37   ` Andy Shevchenko
@ 2017-07-02 22:36     ` Andreas Färber
  0 siblings, 0 replies; 15+ messages in thread
From: Andreas Färber @ 2017-07-02 22:36 UTC (permalink / raw)
  To: Andy Shevchenko
  Cc: support, 张天益, Greg Kroah-Hartman, 96boards,
	linux-kernel@vger.kernel.org, Thomas Liau, mp-cs,
	linux-serial@vger.kernel.org, 刘炜, Jiri Slaby,
	linux-arm Mailing List, 张东风,
	梅利, support, lee

Am 07.06.2017 um 16:37 schrieb Andy Shevchenko:
> On Tue, Jun 6, 2017 at 3:54 AM, Andreas Färber <afaerber@suse.de> wrote:
>> Implement serial console driver to complement earlycon.
>>
>> Based on LeMaker linux-actions tree.
> 
>> +#define OWL_UART_CTL_DWLS_MASK         (0x3 << 0)
> 
> GENMASK() ?
> 
>> +#define OWL_UART_CTL_PRS_MASK          (0x7 << 4)
> 
> Ditto.
> 
>>  #define OWL_UART_STAT_TRFL_MASK                (0x1f << 11)
> 
> Ditto.

Changed.

>> +static struct owl_uart_port *owl_uart_ports[OWL_UART_PORT_NUM];
> 
> And this is needed for...?

That's what both the downstream driver and several in-tree drivers are
doing. See `git grep '_ports\[' -- drivers/tty/serial/`.

If you feel this is wrong, --verbose explanation please.

>> +static void owl_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
>> +{
>> +}
> 
> Do we need an empty stub?

The only flag I have found in the CTL register is AFE for automatic
RTS/CTS flow-control - RTS and CTS can only be read in STAT, not set.

And yes, if I drop this empty callback function, I get no serial output.

>> +static void owl_uart_send_chars(struct uart_port *port)
>> +{
> 
>> +               xmit->tail = (xmit->tail + 1) & (SERIAL_XMIT_SIZE - 1);
> 
> % SERIAL_XMIT_SIZE shorter (I hope it's a power of 2), but it's up to you.

crisv10 and meson_uart have it this way, modulo normalized whitespace.
No serial driver uses % for it.

>> +}
> 
>> +static irqreturn_t owl_uart_irq(int irq, void *dev_id)
>> +{
>> +       struct uart_port *port = (struct uart_port *)dev_id;
> 
> Useless casting.

Fixed.

>> +       spin_lock(&port->lock);
> 
> spin_lock_irqsave() ?

Fixed, with matching _irqrestore().

> Consider the kernel command option that switches all IRQ handlers to
> be threaded.
> 
>> +}
> 
>> +static void owl_uart_change_baudrate(struct owl_uart_port *owl_port,
>> +                                    unsigned long baud)
>> +{
>> +       clk_set_rate(owl_port->clk, baud * 8);
>> +}
> 
>> +static void owl_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;
>> +       }
> 
> Above is entirely redundant.

Can you explain what this flag is used for and why some other drivers
implement it? That word alone is not helping.

>> +}
>> +
>> +static int owl_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_nocache(port->dev, port->mapbase,
>> +                               resource_size(res));
>> +               if (!port->membase)
>> +                       return -EBUSY;
>> +       }
>> +
>> +       return 0;
>> +}
> 
>> +static void owl_uart_config_port(struct uart_port *port, int flags)
>> +{
> 
>> +       if (flags & UART_CONFIG_TYPE) {
> 
> if (!(...))
>  return;
> 
> ?

Not a single serial driver does it that way.
I guess it prepares for handling other flags.

>> +               port->type = PORT_OWL;
>> +               owl_uart_request_port(port);
>> +       }
>> +}
> 
> 
>> +static int owl_uart_probe(struct platform_device *pdev)
>> +{
>> +       struct resource *res_mem, *res_irq;
>> +       struct owl_uart_port *owl_port;
>> +       int ret;
>> +
>> +       if (pdev->dev.of_node)
>> +               pdev->id = of_alias_get_id(pdev->dev.of_node, "serial");
>> +
>> +       if (pdev->id < 0 || pdev->id >= OWL_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;
>> +       }
> 
> You can use
> 
> struct resource *mem;
> 
> mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> x = devm_ioremap_resource();
> if (IS_ERR(x))
>  return PTR_ERR(x);
> 
> and remote IOREMAP flag below.

>> +       res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
>> +       if (!res_irq) {
>> +               dev_err(&pdev->dev, "could not get irq\n");
>> +               return -ENODEV;
>> +       }
> 
> platform_get_irq()

Adopted.

>> +       if (owl_uart_ports[pdev->id]) {
>> +               dev_err(&pdev->dev, "port %d already allocated\n", pdev->id);
>> +               return -EBUSY;
>> +       }
> 
> I guess it's redundant. It should be conflicting by resource (for example, IRQ).

No, currently not. Memory resources are allocated on request_port, IRQ
is requested on startup.

>> +       owl_port->clk = clk_get(&pdev->dev, NULL);
> 
> devm_ ?

Changed.

>> +       owl_port->port.iotype = UPIO_MEM;
>> +       owl_port->port.mapbase = res_mem->start;
>> +       owl_port->port.irq = res_irq->start;
> 
> 
>> +       owl_port->port.uartclk = clk_get_rate(owl_port->clk);
> 
> You need to check if it's 0 and use device property instead or bail out.

Fixed. Since this is a new driver, I'd rather not fall back to
clock-frequency property here. The binding has clocks property as required.

>> +       owl_port->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_LOW_LATENCY;
>> +       owl_port->port.x_char = 0;
>> +       owl_port->port.fifosize = 16;
>> +       owl_port->port.ops = &owl_uart_ops;
>> +
>> +       owl_uart_ports[pdev->id] = owl_port;
> 
>> +       platform_set_drvdata(pdev, owl_port);
> 
> It should be just before return 0, right?..

Does it matter?

>> +
>> +       ret = uart_add_one_port(&owl_uart_driver, &owl_port->port);
>> +       if (ret)
>> +               owl_uart_ports[pdev->id] = NULL;
> 
> ...and thus, taking into consideration redundancy of that global var:
> 
>       ret = uart_add_one_port(&owl_uart_driver, &owl_port->port);
>       if (ret)
>           retrun ret;
> 
>       platform_set_drvdata(pdev, owl_port);
>       return 0;
> 
>> +       return ret;
>> +}
> 
>> +
>> +static int owl_uart_remove(struct platform_device *pdev)
>> +{
> 
>> +       struct owl_uart_port *owl_port;
>> +
>> +       owl_port = platform_get_drvdata(pdev);
> 
> Do above in one line.

Done.

>> +       uart_remove_one_port(&owl_uart_driver, &owl_port->port);
> 
>> +       owl_uart_ports[pdev->id] = NULL;
> 
> Redundant.
> 
>> +
>> +       return 0;
>> +}
> 
>> +/* Actions Semi Owl UART */
>> +#define PORT_OWL       117
> 
> We can use holes for now IIUC.
> 
> See 36 or alike

Okay. 36 works, too.

Please point to a good example of a serial driver that is not
"redundant" in your view. That will help also with other pending serial
drivers of mine. Thanks.

Regards,
Andreas

-- 
SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)

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

end of thread, other threads:[~2017-07-02 22:36 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-06-06  0:53 [PATCH v4 00/28] ARM: Initial Actions Semi S500 and S900 enablement Andreas Färber
2017-06-06  0:54 ` [PATCH v4 08/28] dt-bindings: serial: Document Actions Semi Owl UARTs Andreas Färber
2017-06-06  0:54 ` [PATCH v4 09/28] tty: serial: Add Actions Semi Owl UART earlycon Andreas Färber
2017-06-18 21:45   ` Andreas Färber
2017-06-19  1:16     ` Greg Kroah-Hartman
2017-06-19  1:24       ` Andreas Färber
     [not found]         ` <7fff8813-cea4-0530-bf7b-3d0ad50d6e93-l3A5Bk7waGM@public.gmane.org>
2017-06-19  1:46           ` [PATCH v5 07/26] dt-bindings: serial: Document Actions Semi Owl UARTs Andreas Färber
2017-06-19  1:46             ` [PATCH v5 08/26] tty: serial: Add Actions Semi Owl UART earlycon Andreas Färber
2017-06-19  2:12         ` [PATCH v4 09/28] " Greg Kroah-Hartman
2017-06-19  2:26           ` Andreas Färber
2017-06-06  0:54 ` [PATCH v4 16/28] tty: serial: owl: Implement console driver Andreas Färber
2017-06-06 13:34   ` Alan Cox
2017-07-02 20:27     ` Andreas Färber
2017-06-07 14:37   ` Andy Shevchenko
2017-07-02 22:36     ` Andreas Färber

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox