Linux Serial subsystem development
 help / color / mirror / Atom feed
* [PATCH v2 07/15] arm: dts: Add devicetree for OrangePi i96 board
From: Manivannan Sadhasivam @ 2018-11-21  3:36 UTC (permalink / raw)
  To: olof, arnd, robh+dt, tglx, jason, marc.zyngier, daniel.lezcano,
	gregkh, jslaby
  Cc: afaerber, linux-arm-kernel, linux-kernel, devicetree,
	linux-serial, amit.kucheria, linus.walleij, zhao_steven,
	overseas.sales, Manivannan Sadhasivam
In-Reply-To: <20181121033652.12247-1-manivannan.sadhasivam@linaro.org>

Add initial devicetree for Orange Pi i96 board from Xunlong. It
is one of the 96Boards IoT Edition board.

Signed-off-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
---
 arch/arm/boot/dts/Makefile                   |  3 +-
 arch/arm/boot/dts/rda8810pl-orangepi-i96.dts | 40 ++++++++++++++++++++
 2 files changed, 42 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/boot/dts/rda8810pl-orangepi-i96.dts

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index a0fdad8f10dd..cfb08ea33872 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -807,7 +807,8 @@ dtb-$(CONFIG_ARCH_QCOM) += \
 	qcom-msm8974-sony-xperia-honami.dtb \
 	qcom-mdm9615-wp8548-mangoh-green.dtb
 dtb-$(CONFIG_ARCH_RDA) += \
-	rda8810pl-orangepi-2g-iot.dtb
+	rda8810pl-orangepi-2g-iot.dtb \
+	rda8810pl-orangepi-i96.dtb
 dtb-$(CONFIG_ARCH_REALVIEW) += \
 	arm-realview-pb1176.dtb \
 	arm-realview-pb11mp.dtb \
diff --git a/arch/arm/boot/dts/rda8810pl-orangepi-i96.dts b/arch/arm/boot/dts/rda8810pl-orangepi-i96.dts
new file mode 100644
index 000000000000..11b586e3966b
--- /dev/null
+++ b/arch/arm/boot/dts/rda8810pl-orangepi-i96.dts
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2017 Andreas Färber
+ * Copyright (c) 2018 Manivannan Sadhasivam
+ */
+
+/dts-v1/;
+
+#include "rda8810pl.dtsi"
+
+/ {
+	compatible = "xunlong,orangepi-i96", "rda,8810pl";
+	model = "Orange Pi i96";
+
+	aliases {
+		serial0 = &uart0;
+		serial1 = &uart1;
+		serial2 = &uart2;
+	};
+
+	chosen {
+		stdout-path = "serial2:921600n8";
+	};
+
+	memory@80000000 {
+		device_type = "memory";
+		reg = <0x80000000 0x10000000>;
+	};
+
+	uart2_clk: uart2-clk {
+		compatible = "fixed-clock";
+		clock-frequency = <921600>;
+		#clock-cells = <0>;
+	};
+};
+
+&uart2 {
+	status = "okay";
+	clocks = <&uart2_clk>;
+};
-- 
2.17.1

^ permalink raw reply related

* [PATCH v2 08/15] irqchip: Add RDA8810PL interrupt driver
From: Manivannan Sadhasivam @ 2018-11-21  3:36 UTC (permalink / raw)
  To: olof, arnd, robh+dt, tglx, jason, marc.zyngier, daniel.lezcano,
	gregkh, jslaby
  Cc: afaerber, linux-arm-kernel, linux-kernel, devicetree,
	linux-serial, amit.kucheria, linus.walleij, zhao_steven,
	overseas.sales, Manivannan Sadhasivam
In-Reply-To: <20181121033652.12247-1-manivannan.sadhasivam@linaro.org>

Add interrupt driver for RDA Micro RDA8810PL SoC.

Signed-off-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
---
 arch/arm/mach-rda/Kconfig      |   1 +
 drivers/irqchip/Kconfig        |   4 ++
 drivers/irqchip/Makefile       |   1 +
 drivers/irqchip/irq-rda-intc.c | 113 +++++++++++++++++++++++++++++++++
 4 files changed, 119 insertions(+)
 create mode 100644 drivers/irqchip/irq-rda-intc.c

diff --git a/arch/arm/mach-rda/Kconfig b/arch/arm/mach-rda/Kconfig
index dafab78d7aab..29012bc68ca4 100644
--- a/arch/arm/mach-rda/Kconfig
+++ b/arch/arm/mach-rda/Kconfig
@@ -3,5 +3,6 @@ menuconfig ARCH_RDA
 	depends on ARCH_MULTI_V7
 	select COMMON_CLK
 	select GENERIC_IRQ_CHIP
+	select RDA_INTC
 	help
 	  This enables support for the RDA Micro 8810PL SoC family.
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index 51a5ef0e96ed..9d54645870ad 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -195,6 +195,10 @@ config JCORE_AIC
 	help
 	  Support for the J-Core integrated AIC.
 
+config RDA_INTC
+	bool
+	select IRQ_DOMAIN
+
 config RENESAS_INTC_IRQPIN
 	bool
 	select IRQ_DOMAIN
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 794c13d3ac3d..417108027e40 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -43,6 +43,7 @@ obj-$(CONFIG_IMGPDC_IRQ)		+= irq-imgpdc.o
 obj-$(CONFIG_IRQ_MIPS_CPU)		+= irq-mips-cpu.o
 obj-$(CONFIG_SIRF_IRQ)			+= irq-sirfsoc.o
 obj-$(CONFIG_JCORE_AIC)			+= irq-jcore-aic.o
+obj-$(CONFIG_RDA_INTC)			+= irq-rda-intc.o
 obj-$(CONFIG_RENESAS_INTC_IRQPIN)	+= irq-renesas-intc-irqpin.o
 obj-$(CONFIG_RENESAS_IRQC)		+= irq-renesas-irqc.o
 obj-$(CONFIG_VERSATILE_FPGA_IRQ)	+= irq-versatile-fpga.o
diff --git a/drivers/irqchip/irq-rda-intc.c b/drivers/irqchip/irq-rda-intc.c
new file mode 100644
index 000000000000..1b372bdb23bc
--- /dev/null
+++ b/drivers/irqchip/irq-rda-intc.c
@@ -0,0 +1,113 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * RDA8810PL SoC irqchip driver
+ *
+ * Copyright RDA Microelectronics Company Limited
+ * Copyright (c) 2017 Andreas Färber
+ * Copyright (c) 2018 Manivannan Sadhasivam
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqdomain.h>
+#include <linux/of_address.h>
+
+#include <asm/irq.h>
+#include <asm/exception.h>
+
+#define RDA_INTC_FINALSTATUS	0x00
+#define RDA_INTC_STATUS		0x04
+#define RDA_INTC_MASK_SET	0x08
+#define RDA_INTC_MASK_CLR	0x0c
+#define RDA_INTC_WAKEUP_MASK	0x18
+#define RDA_INTC_CPU_SLEEP	0x1c
+
+#define RDA_IRQ_MASK_ALL	0xFFFFFFFF
+
+#define RDA_NR_IRQS 32
+
+static void __iomem *base;
+
+static void rda_intc_mask_irq(struct irq_data *d)
+{
+	writel_relaxed(BIT(d->hwirq), base + RDA_INTC_MASK_CLR);
+}
+
+static void rda_intc_unmask_irq(struct irq_data *d)
+{
+	writel_relaxed(BIT(d->hwirq), base + RDA_INTC_MASK_SET);
+}
+
+static int rda_intc_set_type(struct irq_data *data, unsigned int flow_type)
+{
+	/* Hardware supports only level triggered interrupts */
+	if (flow_type & (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW))
+		irq_set_handler(data->irq, handle_level_irq);
+	else
+		return -EINVAL;
+
+	return 0;
+}
+
+static struct irq_domain *rda_irq_domain;
+
+static void __exception_irq_entry rda_handle_irq(struct pt_regs *regs)
+{
+	u32 stat = readl_relaxed(base + RDA_INTC_FINALSTATUS);
+	u32 hwirq;
+
+	while (stat) {
+		hwirq = __fls(stat);
+		handle_domain_irq(rda_irq_domain, hwirq, regs);
+		stat &= ~(1 << hwirq);
+	}
+}
+
+static struct irq_chip rda_irq_chip = {
+	.name		= "rda-intc",
+	.irq_mask	= rda_intc_mask_irq,
+	.irq_unmask	= rda_intc_unmask_irq,
+	.irq_set_type	= rda_intc_set_type,
+};
+
+static int rda_irq_map(struct irq_domain *d,
+		       unsigned int virq, irq_hw_number_t hw)
+{
+	irq_set_status_flags(virq, IRQ_LEVEL);
+	irq_set_chip_and_handler(virq, &rda_irq_chip, handle_level_irq);
+	irq_set_chip_data(virq, d->host_data);
+	irq_set_probe(virq);
+
+	return 0;
+}
+
+static const struct irq_domain_ops rda_irq_domain_ops = {
+	.map = rda_irq_map,
+	.xlate = irq_domain_xlate_onecell,
+};
+
+static int __init rda8810_intc_init(struct device_node *node,
+				    struct device_node *parent)
+{
+	base = of_io_request_and_map(node, 0, "rda-intc");
+	if (!base)
+		return -ENXIO;
+
+	/* Mask, and invalidate all interrupt sources */
+	writel_relaxed(RDA_IRQ_MASK_ALL, base + RDA_INTC_MASK_CLR);
+
+	rda_irq_domain = irq_domain_create_linear(&node->fwnode, RDA_NR_IRQS,
+						  &rda_irq_domain_ops, base);
+	if (WARN_ON(!rda_irq_domain)) {
+		iounmap(base);
+		return -ENODEV;
+	}
+
+	set_handle_irq(rda_handle_irq);
+
+	return 0;
+}
+
+IRQCHIP_DECLARE(rda_intc, "rda,8810pl-intc", rda8810_intc_init);
-- 
2.17.1

^ permalink raw reply related

* [PATCH v2 09/15] dt-bindings: timer: Document RDA8810PL SoC timer
From: Manivannan Sadhasivam @ 2018-11-21  3:36 UTC (permalink / raw)
  To: olof, arnd, robh+dt, tglx, jason, marc.zyngier, daniel.lezcano,
	gregkh, jslaby
  Cc: afaerber, linux-arm-kernel, linux-kernel, devicetree,
	linux-serial, amit.kucheria, linus.walleij, zhao_steven,
	overseas.sales, Manivannan Sadhasivam
In-Reply-To: <20181121033652.12247-1-manivannan.sadhasivam@linaro.org>

Document RDA Micro RDA8810PL SoC timer.

Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
---
 .../bindings/timer/rda,8810pl-timer.txt       | 21 +++++++++++++++++++
 1 file changed, 21 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/timer/rda,8810pl-timer.txt

diff --git a/Documentation/devicetree/bindings/timer/rda,8810pl-timer.txt b/Documentation/devicetree/bindings/timer/rda,8810pl-timer.txt
new file mode 100644
index 000000000000..06cc2b00be12
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/rda,8810pl-timer.txt
@@ -0,0 +1,21 @@
+RDA Micro RDA8810PL Timer
+
+Required properties:
+- compatible      :  "rda,8810pl-timer"
+- reg             :  Offset and length of the register set for the device.
+- interrupts      :  Should contain the interrupts.
+- interrupt-names :  Valid names are: "hwtimer", "ostimer".
+                     See ../resource-names.txt
+
+Example:
+
+		apb@20900000 {
+			compatible = "simple-bus";
+			...
+			timer@10000 {
+				compatible = "rda,8810pl-timer";
+				reg = <0x10000 0x1000>;
+				interrupts = <16 IRQ_TYPE_LEVEL_HIGH>,
+					     <17 IRQ_TYPE_LEVEL_HIGH>;
+				interrupt-names = "hwtimer", "ostimer";
+			};
-- 
2.17.1

^ permalink raw reply related

* [PATCH v2 10/15] arm: dts: rda8810pl: Add timer support
From: Manivannan Sadhasivam @ 2018-11-21  3:36 UTC (permalink / raw)
  To: olof, arnd, robh+dt, tglx, jason, marc.zyngier, daniel.lezcano,
	gregkh, jslaby
  Cc: afaerber, linux-arm-kernel, linux-kernel, devicetree,
	linux-serial, amit.kucheria, linus.walleij, zhao_steven,
	overseas.sales, Manivannan Sadhasivam
In-Reply-To: <20181121033652.12247-1-manivannan.sadhasivam@linaro.org>

Add timer support for RDA Micro RDA8810PL SoC.

Signed-off-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
---
 arch/arm/boot/dts/rda8810pl.dtsi | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arch/arm/boot/dts/rda8810pl.dtsi b/arch/arm/boot/dts/rda8810pl.dtsi
index ab85ee06d84f..17ae93410769 100644
--- a/arch/arm/boot/dts/rda8810pl.dtsi
+++ b/arch/arm/boot/dts/rda8810pl.dtsi
@@ -6,6 +6,8 @@
  * Copyright (c) 2018 Manivannan Sadhasivam
  */
 
+#include <dt-bindings/interrupt-controller/irq.h>
+
 / {
 	compatible = "rda,8810pl";
 	interrupt-parent = <&intc>;
@@ -50,6 +52,14 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 		ranges = <0x0 0x20900000 0x100000>;
+	
+		timer@10000 {
+			compatible = "rda,8810pl-timer";
+			reg = <0x10000 0x1000>;
+			interrupts = <16 IRQ_TYPE_LEVEL_HIGH>,
+				     <17 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "hwtimer", "ostimer";
+		};
 	};
 
 	apb@20a00000 {
-- 
2.17.1

^ permalink raw reply related

* [PATCH v2 11/15] clocksource: Add clock driver for RDA8810PL SoC
From: Manivannan Sadhasivam @ 2018-11-21  3:36 UTC (permalink / raw)
  To: olof, arnd, robh+dt, tglx, jason, marc.zyngier, daniel.lezcano,
	gregkh, jslaby
  Cc: afaerber, linux-arm-kernel, linux-kernel, devicetree,
	linux-serial, amit.kucheria, linus.walleij, zhao_steven,
	overseas.sales, Manivannan Sadhasivam
In-Reply-To: <20181121033652.12247-1-manivannan.sadhasivam@linaro.org>

Add clock driver for RDA Micro RDA8810PL SoC supporting OSTIMER
and HWTIMER.

RDA8810PL has two independent timers: OSTIMER (56 bit) and HWTIMER (64 bit).
Each timer provides optional interrupt support. In this driver, OSTIMER is
used for clockevents and HWTIMER is used for clocksource.

Signed-off-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
---
 arch/arm/mach-rda/Kconfig       |   1 +
 drivers/clocksource/Kconfig     |   8 ++
 drivers/clocksource/Makefile    |   1 +
 drivers/clocksource/timer-rda.c | 195 ++++++++++++++++++++++++++++++++
 4 files changed, 205 insertions(+)
 create mode 100644 drivers/clocksource/timer-rda.c

diff --git a/arch/arm/mach-rda/Kconfig b/arch/arm/mach-rda/Kconfig
index 29012bc68ca4..1ea753f57b2d 100644
--- a/arch/arm/mach-rda/Kconfig
+++ b/arch/arm/mach-rda/Kconfig
@@ -4,5 +4,6 @@ menuconfig ARCH_RDA
 	select COMMON_CLK
 	select GENERIC_IRQ_CHIP
 	select RDA_INTC
+	select RDA_TIMER
 	help
 	  This enables support for the RDA Micro 8810PL SoC family.
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 55c77e44bb2d..598b592e03d7 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -105,6 +105,14 @@ config OWL_TIMER
 	help
 	  Enables the support for the Actions Semi Owl timer driver.
 
+config RDA_TIMER
+	bool "RDA timer driver" if COMPILE_TEST
+	depends on GENERIC_CLOCKEVENTS
+	select CLKSRC_MMIO
+	select TIMER_OF
+	help
+	  Enables the support for the RDA Micro timer driver.
+
 config SUN4I_TIMER
 	bool "Sun4i timer driver" if COMPILE_TEST
 	depends on HAS_IOMEM
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index dd9138104568..150020a90707 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -57,6 +57,7 @@ obj-$(CONFIG_OXNAS_RPS_TIMER)	+= timer-oxnas-rps.o
 obj-$(CONFIG_OWL_TIMER)		+= timer-owl.o
 obj-$(CONFIG_SPRD_TIMER)	+= timer-sprd.o
 obj-$(CONFIG_NPCM7XX_TIMER)	+= timer-npcm7xx.o
+obj-$(CONFIG_RDA_TIMER)		+= timer-rda.o
 
 obj-$(CONFIG_ARC_TIMERS)		+= arc_timer.o
 obj-$(CONFIG_ARM_ARCH_TIMER)		+= arm_arch_timer.o
diff --git a/drivers/clocksource/timer-rda.c b/drivers/clocksource/timer-rda.c
new file mode 100644
index 000000000000..fd1199c189bf
--- /dev/null
+++ b/drivers/clocksource/timer-rda.c
@@ -0,0 +1,195 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * RDA8810PL SoC timer driver
+ *
+ * Copyright RDA Microelectronics Company Limited
+ * Copyright (c) 2017 Andreas Färber
+ * Copyright (c) 2018 Manivannan Sadhasivam
+ *
+ * RDA8810PL has two independent timers: OSTIMER (56 bit) and HWTIMER (64 bit).
+ * Each timer provides optional interrupt support. In this driver, OSTIMER is
+ * used for clockevents and HWTIMER is used for clocksource.
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+
+#include "timer-of.h"
+
+#define RDA_OSTIMER_LOADVAL_L	0x000
+#define RDA_OSTIMER_CTRL	0x004
+#define RDA_HWTIMER_LOCKVAL_L	0x024
+#define RDA_HWTIMER_LOCKVAL_H	0x028
+#define RDA_TIMER_IRQ_MASK_SET	0x02c
+#define RDA_TIMER_IRQ_MASK_CLR	0x030
+#define RDA_TIMER_IRQ_CLR	0x034
+
+#define RDA_OSTIMER_CTRL_ENABLE		BIT(24)
+#define RDA_OSTIMER_CTRL_REPEAT		BIT(28)
+#define RDA_OSTIMER_CTRL_LOAD		BIT(30)
+
+#define RDA_TIMER_IRQ_MASK_OSTIMER	BIT(0)
+
+#define RDA_TIMER_IRQ_CLR_OSTIMER	BIT(0)
+
+static int rda_ostimer_start(void __iomem *base, bool periodic, u64 cycles)
+{
+	u32 ctrl, load_l;
+
+	load_l = (u32)cycles;
+	ctrl = ((cycles >> 32) & 0xffffff);
+	ctrl |= RDA_OSTIMER_CTRL_LOAD | RDA_OSTIMER_CTRL_ENABLE;
+	if (periodic)
+		ctrl |= RDA_OSTIMER_CTRL_REPEAT;
+
+	/* Enable ostimer interrupt first */
+	writel_relaxed(RDA_TIMER_IRQ_MASK_OSTIMER,
+		       base + RDA_TIMER_IRQ_MASK_SET);
+
+	/* Write low 32 bits first, high 24 bits are with ctrl */
+	writel_relaxed(load_l, base + RDA_OSTIMER_LOADVAL_L);
+	writel_relaxed(ctrl, base + RDA_OSTIMER_CTRL);
+
+	return 0;
+}
+
+static int rda_ostimer_stop(void __iomem *base)
+{
+	/* Disable ostimer interrupt first */
+	writel_relaxed(RDA_TIMER_IRQ_MASK_OSTIMER,
+		       base + RDA_TIMER_IRQ_MASK_CLR);
+
+	writel_relaxed(0, base + RDA_OSTIMER_CTRL);
+
+	return 0;
+}
+
+static int rda_ostimer_set_state_shutdown(struct clock_event_device *evt)
+{
+	struct timer_of *to = to_timer_of(evt);
+
+	rda_ostimer_stop(timer_of_base(to));
+
+	return 0;
+}
+
+static int rda_ostimer_set_state_oneshot(struct clock_event_device *evt)
+{
+	struct timer_of *to = to_timer_of(evt);
+
+	rda_ostimer_stop(timer_of_base(to));
+
+	return 0;
+}
+
+static int rda_ostimer_set_state_periodic(struct clock_event_device *evt)
+{
+	struct timer_of *to = to_timer_of(evt);
+	unsigned long cycles_per_jiffy;
+
+	rda_ostimer_stop(timer_of_base(to));
+
+	cycles_per_jiffy = ((unsigned long long)NSEC_PER_SEC / HZ *
+			     evt->mult) >> evt->shift;
+	rda_ostimer_start(timer_of_base(to), true, cycles_per_jiffy);
+
+	return 0;
+}
+
+static int rda_ostimer_tick_resume(struct clock_event_device *evt)
+{
+	return 0;
+}
+
+static int rda_ostimer_set_next_event(unsigned long evt,
+				      struct clock_event_device *ev)
+{
+	struct timer_of *to = to_timer_of(ev);
+
+	rda_ostimer_start(timer_of_base(to), false, evt);
+
+	return 0;
+}
+
+static irqreturn_t rda_ostimer_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *evt = dev_id;
+	struct timer_of *to = to_timer_of(evt);
+
+	/* clear timer int */
+	writel_relaxed(RDA_TIMER_IRQ_CLR_OSTIMER,
+		       timer_of_base(to) + RDA_TIMER_IRQ_CLR);
+
+	if (evt->event_handler)
+		evt->event_handler(evt);
+
+	return IRQ_HANDLED;
+}
+
+static struct timer_of rda_ostimer_of = {
+	.flags = TIMER_OF_IRQ | TIMER_OF_BASE,
+
+	.clkevt = {
+		.name = "rda-ostimer",
+		.rating = 250,
+		.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |
+			    CLOCK_EVT_FEAT_DYNIRQ,
+		.set_state_shutdown = rda_ostimer_set_state_shutdown,
+		.set_state_oneshot = rda_ostimer_set_state_oneshot,
+		.set_state_periodic = rda_ostimer_set_state_periodic,
+		.tick_resume = rda_ostimer_tick_resume,
+		.set_next_event	= rda_ostimer_set_next_event,
+	},
+
+	.of_base = {
+		.name = "rda-timer",
+		.index = 0,
+	},
+
+	.of_irq = {
+		.name = "ostimer",
+		.handler = rda_ostimer_interrupt,
+		.flags = IRQF_TIMER,
+	},
+};
+
+static u64 rda_hwtimer_read(struct clocksource *cs)
+{
+	void __iomem *base = timer_of_base(&rda_ostimer_of);
+	u32 lo, hi;
+
+	/* Always read low 32 bits first */
+	do {
+		lo = readl_relaxed(base + RDA_HWTIMER_LOCKVAL_L);
+		hi = readl_relaxed(base + RDA_HWTIMER_LOCKVAL_H);
+	} while (hi != readl_relaxed(base + RDA_HWTIMER_LOCKVAL_H));
+
+	return ((u64)hi << 32) | lo;
+}
+
+static struct clocksource rda_hwtimer_clocksource = {
+	.name           = "rda-timer",
+	.rating         = 400,
+	.read           = rda_hwtimer_read,
+	.mask           = CLOCKSOURCE_MASK(64),
+	.flags          = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static int __init rda_timer_init(struct device_node *np)
+{
+	unsigned long rate = 2000000;
+	int ret;
+
+	ret = timer_of_init(np, &rda_ostimer_of);
+	if (ret)
+		return ret;
+
+	clocksource_register_hz(&rda_hwtimer_clocksource, rate);
+
+	clockevents_config_and_register(&rda_ostimer_of.clkevt, rate,
+					0x2, UINT_MAX);
+
+	return 0;
+}
+
+TIMER_OF_DECLARE(rda8810pl, "rda,8810pl-timer", rda_timer_init);
-- 
2.17.1

^ permalink raw reply related

* [PATCH v2 12/15] dt-bindings: serial: Document RDA Micro UART
From: Manivannan Sadhasivam @ 2018-11-21  3:36 UTC (permalink / raw)
  To: olof, arnd, robh+dt, tglx, jason, marc.zyngier, daniel.lezcano,
	gregkh, jslaby
  Cc: afaerber, linux-arm-kernel, linux-kernel, devicetree,
	linux-serial, amit.kucheria, linus.walleij, zhao_steven,
	overseas.sales, Manivannan Sadhasivam
In-Reply-To: <20181121033652.12247-1-manivannan.sadhasivam@linaro.org>

From: Andreas Färber <afaerber@suse.de>

Add an initial binding for the UART in RDA Micro RDA8810PL SoC.

Signed-off-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
---
 .../bindings/serial/rda,8810pl-uart.txt           | 15 +++++++++++++++
 1 file changed, 15 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/serial/rda,8810pl-uart.txt

diff --git a/Documentation/devicetree/bindings/serial/rda,8810pl-uart.txt b/Documentation/devicetree/bindings/serial/rda,8810pl-uart.txt
new file mode 100644
index 000000000000..ee03116d7415
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/rda,8810pl-uart.txt
@@ -0,0 +1,15 @@
+RDA Micro UART
+
+Required properties:
+- compatible :  "rda,8810pl-uart" for RDA8810PL SoCs.
+- reg        :  Offset and length of the register set for the device.
+- interrupts :  Should contain UART interrupt.
+
+
+Example:
+
+		uart2: serial@20a90000 {
+			compatible = "rda,8810pl-uart";
+			reg = <0x20a90000 0x1000>;
+			interrupts = <11 IRQ_TYPE_LEVEL_HIGH>;
+		};
-- 
2.17.1

^ permalink raw reply related

* [PATCH v2 13/15] arm: dts: rda8810pl: Add interrupt support for UART
From: Manivannan Sadhasivam @ 2018-11-21  3:36 UTC (permalink / raw)
  To: olof, arnd, robh+dt, tglx, jason, marc.zyngier, daniel.lezcano,
	gregkh, jslaby
  Cc: afaerber, linux-arm-kernel, linux-kernel, devicetree,
	linux-serial, amit.kucheria, linus.walleij, zhao_steven,
	overseas.sales, Manivannan Sadhasivam
In-Reply-To: <20181121033652.12247-1-manivannan.sadhasivam@linaro.org>

Add interrupt support for UART in RDA Micro RDA8810PL SoC.

Signed-off-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
---
 arch/arm/boot/dts/rda8810pl.dtsi | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm/boot/dts/rda8810pl.dtsi b/arch/arm/boot/dts/rda8810pl.dtsi
index 17ae93410769..d5df53ba9109 100644
--- a/arch/arm/boot/dts/rda8810pl.dtsi
+++ b/arch/arm/boot/dts/rda8810pl.dtsi
@@ -71,18 +71,21 @@
 		uart0: serial@0 {
 			compatible = "rda,8810pl-uart";
 			reg = <0x0 0x1000>;
+			interrupts = <9 IRQ_TYPE_LEVEL_HIGH>;
 			status = "disabled";
 		};
 
 		uart1: serial@10000 {
 			compatible = "rda,8810pl-uart";
 			reg = <0x10000 0x1000>;
+			interrupts = <10 IRQ_TYPE_LEVEL_HIGH>;
 			status = "disabled";
 		};
 
 		uart2: serial@90000 {
 			compatible = "rda,8810pl-uart";
 			reg = <0x90000 0x1000>;
+			interrupts = <11 IRQ_TYPE_LEVEL_HIGH>;
 			status = "disabled";
 		};
 	};
-- 
2.17.1

^ permalink raw reply related

* [PATCH v2 14/15] tty: serial: Add RDA8810PL UART driver
From: Manivannan Sadhasivam @ 2018-11-21  3:36 UTC (permalink / raw)
  To: olof, arnd, robh+dt, tglx, jason, marc.zyngier, daniel.lezcano,
	gregkh, jslaby
  Cc: afaerber, linux-arm-kernel, linux-kernel, devicetree,
	linux-serial, amit.kucheria, linus.walleij, zhao_steven,
	overseas.sales, Manivannan Sadhasivam
In-Reply-To: <20181121033652.12247-1-manivannan.sadhasivam@linaro.org>

Add UART driver for RDA Micro RDA8810PL SoC.

Signed-off-by: Andreas Färber <afaerber@suse.de>
Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
---
 .../admin-guide/kernel-parameters.txt         |   6 +
 drivers/tty/serial/Kconfig                    |  19 +
 drivers/tty/serial/Makefile                   |   1 +
 drivers/tty/serial/rda-uart.c                 | 831 ++++++++++++++++++
 include/uapi/linux/serial_core.h              |   3 +
 5 files changed, 860 insertions(+)
 create mode 100644 drivers/tty/serial/rda-uart.c

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 81d1d5a74728..07078880f7fd 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -1020,6 +1020,12 @@
 			specified address. The serial port must already be
 			setup and configured. Options are not yet supported.
 
+		rda,<addr>
+			Start an early, polled-mode console on a serial port
+			of an RDA Micro SoC, such as RDA8810PL, 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 32886c304641..67b9bf3b500e 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1529,6 +1529,25 @@ config SERIAL_OWL_CONSOLE
 	  Say 'Y' here if you wish to use Actions Semiconductor S500/S900 UART
 	  as the system console.
 
+config SERIAL_RDA
+	bool "RDA Micro serial port support"
+	depends on ARCH_RDA || COMPILE_TEST
+	select SERIAL_CORE
+	help
+	  This driver is for RDA8810PL SoC's UART.
+	  Say 'Y' here if you wish to use the on-board serial port.
+	  Otherwise, say 'N'.
+
+config SERIAL_RDA_CONSOLE
+	bool "Console on RDA Micro serial port"
+	depends on SERIAL_RDA=y
+	select SERIAL_CORE_CONSOLE
+	select SERIAL_EARLYCON
+	default y
+	help
+	  Say 'Y' here if you wish to use the RDA8810PL 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 daac675612df..8c303736b7e8 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -89,6 +89,7 @@ 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
+obj-$(CONFIG_SERIAL_RDA)	+= rda-uart.o
 
 # GPIOLIB helpers for modem control lines
 obj-$(CONFIG_SERIAL_MCTRL_GPIO)	+= serial_mctrl_gpio.o
diff --git a/drivers/tty/serial/rda-uart.c b/drivers/tty/serial/rda-uart.c
new file mode 100644
index 000000000000..7bf747edf129
--- /dev/null
+++ b/drivers/tty/serial/rda-uart.c
@@ -0,0 +1,831 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * RDA8810PL serial device driver
+ *
+ * Copyright RDA Microelectronics Company Limited
+ * Copyright (c) 2017 Andreas Färber
+ * Copyright (c) 2018 Manivannan Sadhasivam
+ */
+
+#include <linux/clk.h>
+#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>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+
+#define RDA_UART_PORT_NUM 3
+#define RDA_UART_DEV_NAME "ttyRDA"
+
+#define RDA_UART_CTRL		0x00
+#define RDA_UART_STATUS		0x04
+#define RDA_UART_RXTX_BUFFER	0x08
+#define RDA_UART_IRQ_MASK	0x0c
+#define RDA_UART_IRQ_CAUSE	0x10
+#define RDA_UART_IRQ_TRIGGERS	0x14
+#define RDA_UART_CMD_SET	0x18
+#define RDA_UART_CMD_CLR	0x1c
+
+/* UART_CTRL Bits */
+#define RDA_UART_ENABLE			BIT(0)
+#define RDA_UART_DBITS_8		BIT(1)
+#define RDA_UART_TX_SBITS_2		BIT(2)
+#define RDA_UART_PARITY_EN		BIT(3)
+#define RDA_UART_PARITY(x)		(((x) & 0x3) << 4)
+#define RDA_UART_PARITY_ODD		RDA_UART_PARITY(0)
+#define RDA_UART_PARITY_EVEN		RDA_UART_PARITY(1)
+#define RDA_UART_PARITY_SPACE		RDA_UART_PARITY(2)
+#define RDA_UART_PARITY_MARK		RDA_UART_PARITY(3)
+#define RDA_UART_DIV_MODE		BIT(20)
+#define RDA_UART_IRDA_EN		BIT(21)
+#define RDA_UART_DMA_EN			BIT(22)
+#define RDA_UART_FLOW_CNT_EN		BIT(23)
+#define RDA_UART_LOOP_BACK_EN		BIT(24)
+#define RDA_UART_RX_LOCK_ERR		BIT(25)
+#define RDA_UART_RX_BREAK_LEN(x)	(((x) & 0xf) << 28)
+
+/* UART_STATUS Bits */
+#define RDA_UART_RX_FIFO(x)		(((x) & 0x7f) << 0)
+#define RDA_UART_RX_FIFO_MASK		(0x7f << 0)
+#define RDA_UART_TX_FIFO(x)		(((x) & 0x1f) << 8)
+#define RDA_UART_TX_FIFO_MASK		(0x1f << 8)
+#define RDA_UART_TX_ACTIVE		BIT(14)
+#define RDA_UART_RX_ACTIVE		BIT(15)
+#define RDA_UART_RX_OVERFLOW_ERR	BIT(16)
+#define RDA_UART_TX_OVERFLOW_ERR	BIT(17)
+#define RDA_UART_RX_PARITY_ERR		BIT(18)
+#define RDA_UART_RX_FRAMING_ERR		BIT(19)
+#define RDA_UART_RX_BREAK_INT		BIT(20)
+#define RDA_UART_DCTS			BIT(24)
+#define RDA_UART_CTS			BIT(25)
+#define RDA_UART_DTR			BIT(28)
+#define RDA_UART_CLK_ENABLED		BIT(31)
+
+/* UART_RXTX_BUFFER Bits */
+#define RDA_UART_RX_DATA(x)		(((x) & 0xff) << 0)
+#define RDA_UART_TX_DATA(x)		(((x) & 0xff) << 0)
+
+/* UART_IRQ_MASK Bits */
+#define RDA_UART_TX_MODEM_STATUS	BIT(0)
+#define RDA_UART_RX_DATA_AVAILABLE	BIT(1)
+#define RDA_UART_TX_DATA_NEEDED		BIT(2)
+#define RDA_UART_RX_TIMEOUT		BIT(3)
+#define RDA_UART_RX_LINE_ERR		BIT(4)
+#define RDA_UART_TX_DMA_DONE		BIT(5)
+#define RDA_UART_RX_DMA_DONE		BIT(6)
+#define RDA_UART_RX_DMA_TIMEOUT		BIT(7)
+#define RDA_UART_DTR_RISE		BIT(8)
+#define RDA_UART_DTR_FALL		BIT(9)
+
+/* UART_IRQ_CAUSE Bits */
+#define RDA_UART_TX_MODEM_STATUS_U	BIT(16)
+#define RDA_UART_RX_DATA_AVAILABLE_U	BIT(17)
+#define RDA_UART_TX_DATA_NEEDED_U	BIT(18)
+#define RDA_UART_RX_TIMEOUT_U		BIT(19)
+#define RDA_UART_RX_LINE_ERR_U		BIT(20)
+#define RDA_UART_TX_DMA_DONE_U		BIT(21)
+#define RDA_UART_RX_DMA_DONE_U		BIT(22)
+#define RDA_UART_RX_DMA_TIMEOUT_U	BIT(23)
+#define RDA_UART_DTR_RISE_U		BIT(24)
+#define RDA_UART_DTR_FALL_U		BIT(25)
+
+/* UART_TRIGGERS Bits */
+#define RDA_UART_RX_TRIGGER(x)		(((x) & 0x1f) << 0)
+#define RDA_UART_TX_TRIGGER(x)		(((x) & 0xf) << 8)
+#define RDA_UART_AFC_LEVEL(x)		(((x) & 0x1f) << 16)
+
+/* UART_CMD_SET Bits */
+#define RDA_UART_RI			BIT(0)
+#define RDA_UART_DCD			BIT(1)
+#define RDA_UART_DSR			BIT(2)
+#define RDA_UART_TX_BREAK_CONTROL	BIT(3)
+#define RDA_UART_TX_FINISH_N_WAIT	BIT(4)
+#define RDA_UART_RTS			BIT(5)
+#define RDA_UART_RX_FIFO_RESET		BIT(6)
+#define RDA_UART_TX_FIFO_RESET		BIT(7)
+
+#define RDA_UART_TX_FIFO_SIZE	16
+
+static struct uart_driver rda_uart_driver;
+
+struct rda_uart_port {
+	struct uart_port port;
+	struct clk *clk;
+};
+
+#define to_rda_uart_port(port) container_of(port, struct rda_uart_port, port)
+
+static struct rda_uart_port *rda_uart_ports[RDA_UART_PORT_NUM];
+
+static inline void rda_uart_write(struct uart_port *port, u32 val,
+				  unsigned int off)
+{
+	writel(val, port->membase + off);
+}
+
+static inline u32 rda_uart_read(struct uart_port *port, unsigned int off)
+{
+	return readl(port->membase + off);
+}
+
+static unsigned int rda_uart_tx_empty(struct uart_port *port)
+{
+	unsigned long flags;
+	unsigned int ret;
+	u32 val;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	val = rda_uart_read(port, RDA_UART_STATUS);
+	ret = (val & RDA_UART_TX_FIFO_MASK) ? TIOCSER_TEMT : 0;
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	return ret;
+}
+
+static unsigned int rda_uart_get_mctrl(struct uart_port *port)
+{
+	unsigned int mctrl = 0;
+	u32 cmd_set, status;
+
+	cmd_set = rda_uart_read(port, RDA_UART_CMD_SET);
+	status = rda_uart_read(port, RDA_UART_STATUS);
+	if (cmd_set & RDA_UART_RTS)
+		mctrl |= TIOCM_RTS;
+	if (!(status & RDA_UART_CTS))
+		mctrl |= TIOCM_CTS;
+
+	return mctrl;
+}
+
+static void rda_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+	u32 val;
+
+	if (mctrl & TIOCM_RTS) {
+		val = rda_uart_read(port, RDA_UART_CMD_SET);
+		rda_uart_write(port, (val | RDA_UART_RTS), RDA_UART_CMD_SET);
+	} else {
+		/* Clear RTS to stop to receive. */
+		val = rda_uart_read(port, RDA_UART_CMD_CLR);
+		rda_uart_write(port, (val | RDA_UART_RTS), RDA_UART_CMD_CLR);
+	}
+
+	val = rda_uart_read(port, RDA_UART_CTRL);
+
+	if (mctrl & TIOCM_LOOP)
+		val |= RDA_UART_LOOP_BACK_EN;
+	else
+		val &= ~RDA_UART_LOOP_BACK_EN;
+
+	rda_uart_write(port, val, RDA_UART_CTRL);
+}
+
+static void rda_uart_stop_tx(struct uart_port *port)
+{
+	u32 val;
+
+	val = rda_uart_read(port, RDA_UART_IRQ_MASK);
+	val &= ~RDA_UART_TX_DATA_NEEDED;
+	rda_uart_write(port, val, RDA_UART_IRQ_MASK);
+
+	val = rda_uart_read(port, RDA_UART_CMD_SET);
+	val |= RDA_UART_TX_FIFO_RESET;
+	rda_uart_write(port, val, RDA_UART_CMD_SET);
+}
+
+static void rda_uart_stop_rx(struct uart_port *port)
+{
+	u32 val;
+
+	val = rda_uart_read(port, RDA_UART_IRQ_MASK);
+	val &= ~(RDA_UART_RX_DATA_AVAILABLE | RDA_UART_RX_TIMEOUT);
+	rda_uart_write(port, val, RDA_UART_IRQ_MASK);
+
+	/* Read Rx buffer before reset to avoid Rx timeout interrupt */
+	val = rda_uart_read(port, RDA_UART_RXTX_BUFFER);
+
+	val = rda_uart_read(port, RDA_UART_CMD_SET);
+	val |= RDA_UART_RX_FIFO_RESET;
+	rda_uart_write(port, val, RDA_UART_CMD_SET);
+}
+
+static void rda_uart_start_tx(struct uart_port *port)
+{
+	u32 val;
+
+	if (uart_tx_stopped(port)) {
+		rda_uart_stop_tx(port);
+		return;
+	}
+
+	val = rda_uart_read(port, RDA_UART_IRQ_MASK);
+	val |= RDA_UART_TX_DATA_NEEDED;
+	rda_uart_write(port, val, RDA_UART_IRQ_MASK);
+}
+
+static void rda_uart_change_baudrate(struct rda_uart_port *rda_port,
+				     unsigned long baud)
+{
+	clk_set_rate(rda_port->clk, baud * 8);
+}
+
+static void rda_uart_set_termios(struct uart_port *port,
+				 struct ktermios *termios,
+				 struct ktermios *old)
+{
+	struct rda_uart_port *rda_port = to_rda_uart_port(port);
+	unsigned long flags;
+	unsigned int ctrl, cmd_set, cmd_clr, triggers;
+	unsigned int baud;
+	u32 irq_mask;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	baud = uart_get_baud_rate(port, termios, old, 9600, port->uartclk / 4);
+	rda_uart_change_baudrate(rda_port, baud);
+
+	ctrl = rda_uart_read(port, RDA_UART_CTRL);
+	cmd_set = rda_uart_read(port, RDA_UART_CMD_SET);
+	cmd_clr = rda_uart_read(port, RDA_UART_CMD_CLR);
+
+	switch (termios->c_cflag & CSIZE) {
+	case CS5:
+	case CS6:
+		dev_warn(port->dev, "bit size not supported, using 7 bits\n");
+		/* Fall through */
+	case CS7:
+		ctrl &= ~RDA_UART_DBITS_8;
+		break;
+	default:
+		ctrl |= RDA_UART_DBITS_8;
+		break;
+	}
+
+	/* stop bits */
+	if (termios->c_cflag & CSTOPB)
+		ctrl |= RDA_UART_TX_SBITS_2;
+	else
+		ctrl &= ~RDA_UART_TX_SBITS_2;
+
+	/* parity check */
+	if (termios->c_cflag & PARENB) {
+		ctrl |= RDA_UART_PARITY_EN;
+
+		/* Mark or Space parity */
+		if (termios->c_cflag & CMSPAR) {
+			if (termios->c_cflag & PARODD)
+				ctrl |= RDA_UART_PARITY_MARK;
+			else
+				ctrl |= RDA_UART_PARITY_SPACE;
+		} else if (termios->c_cflag & PARODD) {
+			ctrl |= RDA_UART_PARITY_ODD;
+		} else {
+			ctrl |= RDA_UART_PARITY_EVEN;
+		}
+	} else {
+		ctrl &= ~RDA_UART_PARITY_EN;
+	}
+
+	/* Hardware handshake (RTS/CTS) */
+	if (termios->c_cflag & CRTSCTS) {
+		ctrl   |= RDA_UART_FLOW_CNT_EN;
+		cmd_set |= RDA_UART_RTS;
+	} else {
+		ctrl   &= ~RDA_UART_FLOW_CNT_EN;
+		cmd_clr |= RDA_UART_RTS;
+	}
+
+	ctrl |= RDA_UART_ENABLE;
+	ctrl &= ~RDA_UART_DMA_EN;
+
+	triggers  = (RDA_UART_AFC_LEVEL(20) | RDA_UART_RX_TRIGGER(16));
+	irq_mask = rda_uart_read(port, RDA_UART_IRQ_MASK);
+	rda_uart_write(port, 0, RDA_UART_IRQ_MASK);
+
+	rda_uart_write(port, triggers, RDA_UART_IRQ_TRIGGERS);
+	rda_uart_write(port, ctrl, RDA_UART_CTRL);
+	rda_uart_write(port, cmd_set, RDA_UART_CMD_SET);
+	rda_uart_write(port, cmd_clr, RDA_UART_CMD_CLR);
+
+	rda_uart_write(port, irq_mask, RDA_UART_IRQ_MASK);
+
+	/* Don't rewrite B0 */
+	if (tty_termios_baud_rate(termios))
+		tty_termios_encode_baud_rate(termios, baud, baud);
+
+	/* update the per-port timeout */
+	uart_update_timeout(port, termios->c_cflag, baud);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void rda_uart_send_chars(struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->state->xmit;
+	unsigned int ch;
+	u32 val;
+
+	if (uart_tx_stopped(port))
+		return;
+
+	if (port->x_char) {
+		while (!(rda_uart_read(port, RDA_UART_STATUS) &
+			 RDA_UART_TX_FIFO_MASK))
+			cpu_relax();
+
+		rda_uart_write(port, port->x_char, RDA_UART_RXTX_BUFFER);
+		port->icount.tx++;
+		port->x_char = 0;
+	}
+
+	while (rda_uart_read(port, RDA_UART_STATUS) & RDA_UART_TX_FIFO_MASK) {
+		if (uart_circ_empty(xmit))
+			break;
+
+		ch = xmit->buf[xmit->tail];
+		rda_uart_write(port, ch, RDA_UART_RXTX_BUFFER);
+		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)) {
+		/* Re-enable Tx FIFO interrupt */
+		val = rda_uart_read(port, RDA_UART_IRQ_MASK);
+		val |= RDA_UART_TX_DATA_NEEDED;
+		rda_uart_write(port, val, RDA_UART_IRQ_MASK);
+	}
+}
+
+static void rda_uart_receive_chars(struct uart_port *port)
+{
+	u32 status, val;
+
+	status = rda_uart_read(port, RDA_UART_STATUS);
+	while ((status & RDA_UART_RX_FIFO_MASK)) {
+		char flag = TTY_NORMAL;
+
+		if (status & RDA_UART_RX_PARITY_ERR) {
+			port->icount.parity++;
+			flag = TTY_PARITY;
+		}
+
+		if (status & RDA_UART_RX_FRAMING_ERR) {
+			port->icount.frame++;
+			flag = TTY_FRAME;
+		}
+
+		if (status & RDA_UART_RX_OVERFLOW_ERR) {
+			port->icount.overrun++;
+			flag = TTY_OVERRUN;
+		}
+
+		val = rda_uart_read(port, RDA_UART_RXTX_BUFFER);
+		val &= 0xff;
+
+		port->icount.rx++;
+		tty_insert_flip_char(&port->state->port, val, flag);
+
+		status = rda_uart_read(port, RDA_UART_STATUS);
+	}
+
+	spin_unlock(&port->lock);
+	tty_flip_buffer_push(&port->state->port);
+	spin_lock(&port->lock);
+}
+
+static irqreturn_t rda_interrupt(int irq, void *dev_id)
+{
+	struct uart_port *port = dev_id;
+	unsigned long flags;
+	u32 val, irq_mask;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	/* Clear IRQ cause */
+	val = rda_uart_read(port, RDA_UART_IRQ_CAUSE);
+	rda_uart_write(port, val, RDA_UART_IRQ_CAUSE);
+
+	if (val & (RDA_UART_RX_DATA_AVAILABLE | RDA_UART_RX_TIMEOUT))
+		rda_uart_receive_chars(port);
+
+	if (val & (RDA_UART_TX_DATA_NEEDED)) {
+		irq_mask = rda_uart_read(port, RDA_UART_IRQ_MASK);
+		irq_mask &= ~RDA_UART_TX_DATA_NEEDED;
+		rda_uart_write(port, irq_mask, RDA_UART_IRQ_MASK);
+
+		rda_uart_send_chars(port);
+	}
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+static int rda_uart_startup(struct uart_port *port)
+{
+	unsigned long flags;
+	int ret;
+	u32 val;
+
+	spin_lock_irqsave(&port->lock, flags);
+	rda_uart_write(port, 0, RDA_UART_IRQ_MASK);
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	ret = request_irq(port->irq, rda_interrupt, IRQF_NO_SUSPEND,
+			  "rda-uart", port);
+	if (ret)
+		return ret;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	val = rda_uart_read(port, RDA_UART_CTRL);
+	val |= RDA_UART_ENABLE;
+	rda_uart_write(port, val, RDA_UART_CTRL);
+
+	/* enable rx interrupt */
+	val = rda_uart_read(port, RDA_UART_IRQ_MASK);
+	val |= (RDA_UART_RX_DATA_AVAILABLE | RDA_UART_RX_TIMEOUT);
+	rda_uart_write(port, val, RDA_UART_IRQ_MASK);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	return 0;
+}
+
+static void rda_uart_shutdown(struct uart_port *port)
+{
+	unsigned long flags;
+	u32 val;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	rda_uart_stop_tx(port);
+	rda_uart_stop_rx(port);
+
+	val = rda_uart_read(port, RDA_UART_CTRL);
+	val &= ~RDA_UART_ENABLE;
+	rda_uart_write(port, val, RDA_UART_CTRL);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *rda_uart_type(struct uart_port *port)
+{
+	return (port->type == PORT_RDA) ? "rda-uart" : NULL;
+}
+
+static int rda_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 rda_uart_config_port(struct uart_port *port, int flags)
+{
+	unsigned long irq_flags;
+
+	if (flags & UART_CONFIG_TYPE) {
+		port->type = PORT_RDA;
+		rda_uart_request_port(port);
+	}
+
+	spin_lock_irqsave(&port->lock, irq_flags);
+
+	/* Clear mask, so no surprise interrupts. */
+	rda_uart_write(port, 0, RDA_UART_IRQ_MASK);
+
+	/* Clear status register */
+	rda_uart_write(port, 0, RDA_UART_STATUS);
+
+	spin_unlock_irqrestore(&port->lock, irq_flags);
+}
+
+static void rda_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 rda_uart_verify_port(struct uart_port *port,
+				struct serial_struct *ser)
+{
+	if (port->type != PORT_RDA)
+		return -EINVAL;
+
+	if (port->irq != ser->irq)
+		return -EINVAL;
+
+	return 0;
+}
+
+static const struct uart_ops rda_uart_ops = {
+	.tx_empty       = rda_uart_tx_empty,
+	.get_mctrl      = rda_uart_get_mctrl,
+	.set_mctrl      = rda_uart_set_mctrl,
+	.start_tx       = rda_uart_start_tx,
+	.stop_tx        = rda_uart_stop_tx,
+	.stop_rx        = rda_uart_stop_rx,
+	.startup        = rda_uart_startup,
+	.shutdown       = rda_uart_shutdown,
+	.set_termios    = rda_uart_set_termios,
+	.type           = rda_uart_type,
+	.request_port	= rda_uart_request_port,
+	.release_port	= rda_uart_release_port,
+	.config_port	= rda_uart_config_port,
+	.verify_port	= rda_uart_verify_port,
+};
+
+#ifdef CONFIG_SERIAL_RDA_CONSOLE
+
+static void rda_console_putchar(struct uart_port *port, int ch)
+{
+	if (!port->membase)
+		return;
+
+	while (!(rda_uart_read(port, RDA_UART_STATUS) & RDA_UART_TX_FIFO_MASK))
+		cpu_relax();
+
+	rda_uart_write(port, ch, RDA_UART_RXTX_BUFFER);
+}
+
+static void rda_uart_port_write(struct uart_port *port, const char *s,
+				u_int count)
+{
+	u32 old_irq_mask;
+	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_irq_mask = rda_uart_read(port, RDA_UART_IRQ_MASK);
+	rda_uart_write(port, 0, RDA_UART_IRQ_MASK);
+
+	uart_console_write(port, s, count, rda_console_putchar);
+
+	/* wait until all contents have been sent out */
+	while (!(rda_uart_read(port, RDA_UART_STATUS) & RDA_UART_TX_FIFO_MASK))
+		cpu_relax();
+
+	rda_uart_write(port, old_irq_mask, RDA_UART_IRQ_MASK);
+
+	if (locked)
+		spin_unlock(&port->lock);
+
+	local_irq_restore(flags);
+}
+
+static void rda_uart_console_write(struct console *co, const char *s,
+				   u_int count)
+{
+	struct rda_uart_port *rda_port;
+
+	rda_port = rda_uart_ports[co->index];
+	if (!rda_port)
+		return;
+
+	rda_uart_port_write(&rda_port->port, s, count);
+}
+
+static int rda_uart_console_setup(struct console *co, char *options)
+{
+	struct rda_uart_port *rda_port;
+	int baud = 921600;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
+
+	if (co->index < 0 || co->index > RDA_UART_PORT_NUM)
+		return -EINVAL;
+
+	rda_port = rda_uart_ports[co->index];
+	if (!rda_port || !rda_port->port.membase)
+		return -ENODEV;
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+	return uart_set_options(&rda_port->port, co, baud, parity, bits, flow);
+}
+
+static struct console rda_uart_console = {
+	.name = RDA_UART_DEV_NAME,
+	.write = rda_uart_console_write,
+	.device = uart_console_device,
+	.setup = rda_uart_console_setup,
+	.flags = CON_PRINTBUFFER,
+	.index = -1,
+	.data = &rda_uart_driver,
+};
+
+static int __init rda_uart_console_init(void)
+{
+	register_console(&rda_uart_console);
+
+	return 0;
+}
+console_initcall(rda_uart_console_init);
+
+static void rda_uart_early_console_write(struct console *co,
+					 const char *s,
+					 u_int count)
+{
+	struct earlycon_device *dev = co->data;
+
+	rda_uart_port_write(&dev->port, s, count);
+}
+
+static int __init
+rda_uart_early_console_setup(struct earlycon_device *device, const char *opt)
+{
+	if (!device->port.membase)
+		return -ENODEV;
+
+	device->con->write = rda_uart_early_console_write;
+
+	return 0;
+}
+
+OF_EARLYCON_DECLARE(rda, "rda,8810pl-uart",
+		    rda_uart_early_console_setup);
+
+#define RDA_UART_CONSOLE (&rda_uart_console)
+#else
+#define RDA_UART_CONSOLE NULL
+#endif /* CONFIG_SERIAL_RDA_CONSOLE */
+
+static struct uart_driver rda_uart_driver = {
+	.owner = THIS_MODULE,
+	.driver_name = "rda-uart",
+	.dev_name = RDA_UART_DEV_NAME,
+	.nr = RDA_UART_PORT_NUM,
+	.cons = RDA_UART_CONSOLE,
+};
+
+static const struct of_device_id rda_uart_dt_matches[] = {
+	{ .compatible = "rda,8810pl-uart" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, rda_uart_dt_matches);
+
+static int rda_uart_probe(struct platform_device *pdev)
+{
+	struct resource *res_mem;
+	struct rda_uart_port *rda_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 > RDA_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) {
+		dev_err(&pdev->dev, "could not get irq\n");
+		return irq;
+	}
+
+	if (rda_uart_ports[pdev->id]) {
+		dev_err(&pdev->dev, "port %d already allocated\n", pdev->id);
+		return -EBUSY;
+	}
+
+	rda_port = devm_kzalloc(&pdev->dev, sizeof(*rda_port), GFP_KERNEL);
+	if (!rda_port)
+		return -ENOMEM;
+
+	rda_port->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(rda_port->clk)) {
+		dev_err(&pdev->dev, "could not get clk\n");
+		return PTR_ERR(rda_port->clk);
+	}
+
+	rda_port->port.dev = &pdev->dev;
+	rda_port->port.regshift = 0;
+	rda_port->port.line = pdev->id;
+	rda_port->port.type = PORT_RDA;
+	rda_port->port.iotype = UPIO_MEM;
+	rda_port->port.mapbase = res_mem->start;
+	rda_port->port.irq = irq;
+	rda_port->port.uartclk = clk_get_rate(rda_port->clk);
+	if (rda_port->port.uartclk == 0) {
+		dev_err(&pdev->dev, "clock rate is zero\n");
+		return -EINVAL;
+	}
+	rda_port->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP |
+			       UPF_LOW_LATENCY;
+	rda_port->port.x_char = 0;
+	rda_port->port.fifosize = RDA_UART_TX_FIFO_SIZE;
+	rda_port->port.ops = &rda_uart_ops;
+
+	rda_uart_ports[pdev->id] = rda_port;
+	platform_set_drvdata(pdev, rda_port);
+
+	ret = uart_add_one_port(&rda_uart_driver, &rda_port->port);
+	if (ret)
+		rda_uart_ports[pdev->id] = NULL;
+
+	return ret;
+}
+
+static int rda_uart_remove(struct platform_device *pdev)
+{
+	struct rda_uart_port *rda_port = platform_get_drvdata(pdev);
+
+	uart_remove_one_port(&rda_uart_driver, &rda_port->port);
+	rda_uart_ports[pdev->id] = NULL;
+
+	return 0;
+}
+
+static struct platform_driver rda_uart_platform_driver = {
+	.probe = rda_uart_probe,
+	.remove = rda_uart_remove,
+	.driver = {
+		.name = "rda-uart",
+		.of_match_table = rda_uart_dt_matches,
+	},
+};
+
+static int __init rda_uart_init(void)
+{
+	int ret;
+
+	ret = uart_register_driver(&rda_uart_driver);
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&rda_uart_platform_driver);
+	if (ret)
+		uart_unregister_driver(&rda_uart_driver);
+
+	return ret;
+}
+
+static void __init rda_uart_exit(void)
+{
+	platform_driver_unregister(&rda_uart_platform_driver);
+	uart_unregister_driver(&rda_uart_driver);
+}
+
+module_init(rda_uart_init);
+module_exit(rda_uart_exit);
+
+MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>");
+MODULE_DESCRIPTION("RDA8810PL serial device driver");
+MODULE_LICENSE("GPL");
diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
index dce5f9dae121..df4a7534e239 100644
--- a/include/uapi/linux/serial_core.h
+++ b/include/uapi/linux/serial_core.h
@@ -281,4 +281,7 @@
 /* MediaTek BTIF */
 #define PORT_MTK_BTIF	117
 
+/* RDA UART */
+#define PORT_RDA	118
+
 #endif /* _UAPILINUX_SERIAL_CORE_H */
-- 
2.17.1

^ permalink raw reply related

* [PATCH v2 15/15] MAINTAINERS: Add entry for RDA Micro SoC architecture
From: Manivannan Sadhasivam @ 2018-11-21  3:36 UTC (permalink / raw)
  To: olof, arnd, robh+dt, tglx, jason, marc.zyngier, daniel.lezcano,
	gregkh, jslaby
  Cc: afaerber, linux-arm-kernel, linux-kernel, devicetree,
	linux-serial, amit.kucheria, linus.walleij, zhao_steven,
	overseas.sales, Manivannan Sadhasivam
In-Reply-To: <20181121033652.12247-1-manivannan.sadhasivam@linaro.org>

Add MAINTAINERS entry for RDA Micro SoC architecture with myself
and Andreas Färber as the maintainers.

Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
---
 MAINTAINERS | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 6c3fbbb361f8..7a5ae685a638 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1945,6 +1945,20 @@ M:	Lennert Buytenhek <kernel@wantstofly.org>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:	Maintained
 
+ARM/RDA MICRO ARCHITECTURE
+M:	Andreas Färber <afaerber@suse.de>
+M:	Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S:	Maintained
+F:	arch/arm/boot/dts/rda8810pl-*
+F:	drivers/clocksource/timer-rda.c
+F:	drivers/irqchip/irq-rda-intc.c
+F:	drivers/tty/serial/rda-uart.c
+F:	Documentation/devicetree/bindings/arm/rda.txt
+F:	Documentation/devicetree/bindings/interrupt-controller/rda,8810pl-intc.txt
+F:	Documentation/devicetree/bindings/serial/rda,8810pl-uart.txt
+F:	Documentation/devicetree/bindings/timer/rda,8810pl-timer.txt
+
 ARM/REALTEK ARCHITECTURE
 M:	Andreas Färber <afaerber@suse.de>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
-- 
2.17.1

^ permalink raw reply related

* RE: [PATCH 03/14] ARM: milbeaut: Add Milbeaut M10V early printk
From: sugaya.taichi @ 2018-11-21  4:07 UTC (permalink / raw)
  To: robh+dt
  Cc: linux-clk, devicetree, linux-arm-kernel, linux-kernel,
	linux-serial, mturquette, sboyd, mark.rutland, gregkh,
	daniel.lezcano, tglx, linux, jslaby, masami.hiramatsu,
	jaswinder.singh
In-Reply-To: <CAL_JsqKMK7nMUxZLu9eV8tpnCXsAr2F4j=xTO8UL0g8V30kYZg@mail.gmail.com>

Hi Rob

Thank you for your comment.

> -----Original Message-----
> From: Rob Herring [mailto:robh+dt@kernel.org]
> Sent: Tuesday, November 20, 2018 12:21 AM
> To: Sugaya, Taichi/菅谷 太一
> Cc: linux-clk; devicetree@vger.kernel.org; moderated list:ARM/FREESCALE
> IMX / MXC ARM ARCHITECTURE; linux-kernel@vger.kernel.org; open list:SERIAL
> DRIVERS; Michael Turquette; Stephen Boyd; Mark Rutland; Greg Kroah-Hartman;
> Daniel Lezcano; Thomas Gleixner; Russell King; Jiri Slaby; Masami Hiramatsu;
> Jassi Brar
> Subject: Re: [PATCH 03/14] ARM: milbeaut: Add Milbeaut M10V early printk
> 
> On Sun, Nov 18, 2018 at 7:00 PM Sugaya Taichi
> <sugaya.taichi@socionext.com> wrote:
> >
> > Add Milbeaut M10V earlyprintk.
> 
> Do you really need earlyprintk? earlycon is preferred instead. It's
> not quite as early, but doesn't require rebuilding the kernel and
> supports more than 1 fixed device. If you crash before earlycon is
> enabled, that pretty much means either a bad dtb memory node or just
> flaky memory.
OK. I use earlycon since would like to use flexible functions.

Thanks
Sugaya Taichi

> 
> Rob

^ permalink raw reply

* Re: [PATCH v2 08/15] irqchip: Add RDA8810PL interrupt driver
From: Marc Zyngier @ 2018-11-21  8:41 UTC (permalink / raw)
  To: Manivannan Sadhasivam, olof, arnd, robh+dt, tglx, jason,
	daniel.lezcano, gregkh, jslaby
  Cc: afaerber, linux-arm-kernel, linux-kernel, devicetree,
	linux-serial, amit.kucheria, linus.walleij, zhao_steven,
	overseas.sales
In-Reply-To: <20181121033652.12247-9-manivannan.sadhasivam@linaro.org>

On 21/11/2018 03:36, Manivannan Sadhasivam wrote:
> Add interrupt driver for RDA Micro RDA8810PL SoC.
> 
> Signed-off-by: Andreas Färber <afaerber@suse.de>
> Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> ---
>  arch/arm/mach-rda/Kconfig      |   1 +
>  drivers/irqchip/Kconfig        |   4 ++
>  drivers/irqchip/Makefile       |   1 +
>  drivers/irqchip/irq-rda-intc.c | 113 +++++++++++++++++++++++++++++++++
>  4 files changed, 119 insertions(+)
>  create mode 100644 drivers/irqchip/irq-rda-intc.c
> 
> diff --git a/arch/arm/mach-rda/Kconfig b/arch/arm/mach-rda/Kconfig
> index dafab78d7aab..29012bc68ca4 100644
> --- a/arch/arm/mach-rda/Kconfig
> +++ b/arch/arm/mach-rda/Kconfig
> @@ -3,5 +3,6 @@ menuconfig ARCH_RDA
>  	depends on ARCH_MULTI_V7
>  	select COMMON_CLK
>  	select GENERIC_IRQ_CHIP
> +	select RDA_INTC
>  	help
>  	  This enables support for the RDA Micro 8810PL SoC family.
> diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
> index 51a5ef0e96ed..9d54645870ad 100644
> --- a/drivers/irqchip/Kconfig
> +++ b/drivers/irqchip/Kconfig
> @@ -195,6 +195,10 @@ config JCORE_AIC
>  	help
>  	  Support for the J-Core integrated AIC.
>  
> +config RDA_INTC
> +	bool
> +	select IRQ_DOMAIN
> +
>  config RENESAS_INTC_IRQPIN
>  	bool
>  	select IRQ_DOMAIN
> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
> index 794c13d3ac3d..417108027e40 100644
> --- a/drivers/irqchip/Makefile
> +++ b/drivers/irqchip/Makefile
> @@ -43,6 +43,7 @@ obj-$(CONFIG_IMGPDC_IRQ)		+= irq-imgpdc.o
>  obj-$(CONFIG_IRQ_MIPS_CPU)		+= irq-mips-cpu.o
>  obj-$(CONFIG_SIRF_IRQ)			+= irq-sirfsoc.o
>  obj-$(CONFIG_JCORE_AIC)			+= irq-jcore-aic.o
> +obj-$(CONFIG_RDA_INTC)			+= irq-rda-intc.o
>  obj-$(CONFIG_RENESAS_INTC_IRQPIN)	+= irq-renesas-intc-irqpin.o
>  obj-$(CONFIG_RENESAS_IRQC)		+= irq-renesas-irqc.o
>  obj-$(CONFIG_VERSATILE_FPGA_IRQ)	+= irq-versatile-fpga.o
> diff --git a/drivers/irqchip/irq-rda-intc.c b/drivers/irqchip/irq-rda-intc.c
> new file mode 100644
> index 000000000000..1b372bdb23bc
> --- /dev/null
> +++ b/drivers/irqchip/irq-rda-intc.c
> @@ -0,0 +1,113 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * RDA8810PL SoC irqchip driver
> + *
> + * Copyright RDA Microelectronics Company Limited
> + * Copyright (c) 2017 Andreas Färber
> + * Copyright (c) 2018 Manivannan Sadhasivam
> + */
> +
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/irqchip.h>
> +#include <linux/irqdomain.h>
> +#include <linux/of_address.h>
> +
> +#include <asm/irq.h>

You shouldn't need to include this.

> +#include <asm/exception.h>
> +
> +#define RDA_INTC_FINALSTATUS	0x00
> +#define RDA_INTC_STATUS		0x04
> +#define RDA_INTC_MASK_SET	0x08
> +#define RDA_INTC_MASK_CLR	0x0c
> +#define RDA_INTC_WAKEUP_MASK	0x18
> +#define RDA_INTC_CPU_SLEEP	0x1c

Half of these constants are unused. Do we really need them?

> +
> +#define RDA_IRQ_MASK_ALL	0xFFFFFFFF
> +
> +#define RDA_NR_IRQS 32

Surely the mask can be derived from the number of interrupts?

> +
> +static void __iomem *base;

Everything in this driver is prefixed with rda_. It would seem valuable
to  do the same here, as "base" is a bit too generic.

> +
> +static void rda_intc_mask_irq(struct irq_data *d)
> +{
> +	writel_relaxed(BIT(d->hwirq), base + RDA_INTC_MASK_CLR);
> +}
> +
> +static void rda_intc_unmask_irq(struct irq_data *d)
> +{
> +	writel_relaxed(BIT(d->hwirq), base + RDA_INTC_MASK_SET);

Are the names MASK_CLR and MASK_SET from the datasheet? They seem to be
backward (you set the mask to unmask...), and seem to behave like an
enable instead. That's not a big issue, just curious.

> +}
> +
> +static int rda_intc_set_type(struct irq_data *data, unsigned int flow_type)
> +{
> +	/* Hardware supports only level triggered interrupts */
> +	if (flow_type & (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW))
> +		irq_set_handler(data->irq, handle_level_irq);

Why do you need to do this? You've already configured it at map time,
and it is not changing under your feet. This should be written as:

if ((flow_type & (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW)) == flow_type)
	return 0;

return -EINVAL;

> +	else
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +static struct irq_domain *rda_irq_domain;

Please move this to the top of the file, next to "base".

> +
> +static void __exception_irq_entry rda_handle_irq(struct pt_regs *regs)
> +{
> +	u32 stat = readl_relaxed(base + RDA_INTC_FINALSTATUS);
> +	u32 hwirq;
> +
> +	while (stat) {
> +		hwirq = __fls(stat);
> +		handle_domain_irq(rda_irq_domain, hwirq, regs);
> +		stat &= ~(1 << hwirq);
> +	}
> +}
> +
> +static struct irq_chip rda_irq_chip = {
> +	.name		= "rda-intc",
> +	.irq_mask	= rda_intc_mask_irq,
> +	.irq_unmask	= rda_intc_unmask_irq,
> +	.irq_set_type	= rda_intc_set_type,
> +};
> +
> +static int rda_irq_map(struct irq_domain *d,
> +		       unsigned int virq, irq_hw_number_t hw)
> +{
> +	irq_set_status_flags(virq, IRQ_LEVEL);
> +	irq_set_chip_and_handler(virq, &rda_irq_chip, handle_level_irq);
> +	irq_set_chip_data(virq, d->host_data);
> +	irq_set_probe(virq);
> +
> +	return 0;
> +}
> +
> +static const struct irq_domain_ops rda_irq_domain_ops = {
> +	.map = rda_irq_map,
> +	.xlate = irq_domain_xlate_onecell,
> +};
> +
> +static int __init rda8810_intc_init(struct device_node *node,
> +				    struct device_node *parent)
> +{
> +	base = of_io_request_and_map(node, 0, "rda-intc");
> +	if (!base)
> +		return -ENXIO;
> +
> +	/* Mask, and invalidate all interrupt sources */

What does "invalidate" mean here?

> +	writel_relaxed(RDA_IRQ_MASK_ALL, base + RDA_INTC_MASK_CLR);
> +
> +	rda_irq_domain = irq_domain_create_linear(&node->fwnode, RDA_NR_IRQS,
> +						  &rda_irq_domain_ops, base);
> +	if (WARN_ON(!rda_irq_domain)) {
> +		iounmap(base);
> +		return -ENODEV;

Why ENODEV? ENOMEM seems more appropriate. The WARN_ON is a bit
superfluous, as the failing probe should be noisy enough.

> +	}
> +
> +	set_handle_irq(rda_handle_irq);
> +
> +	return 0;
> +}
> +
> +IRQCHIP_DECLARE(rda_intc, "rda,8810pl-intc", rda8810_intc_init);
> 

You've already posted two versions in 3 days, please allow for a week
between versions.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply

* Re: [PATCH v2 06/15] arm: dts: Add devicetree for OrangePi 2G IoT board
From: Arnd Bergmann @ 2018-11-21  8:55 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: Olof Johansson, Rob Herring, Thomas Gleixner, Jason Cooper,
	Marc Zyngier, Daniel Lezcano, gregkh, Jiri Slaby,
	Andreas Färber, Linux ARM, Linux Kernel Mailing List, DTML,
	linux-serial, Amit Kucheria, Linus Walleij, zhao_steven,
	overseas.sales
In-Reply-To: <20181121033652.12247-7-manivannan.sadhasivam@linaro.org>

On Wed, Nov 21, 2018 at 4:38 AM Manivannan Sadhasivam
<manivannan.sadhasivam@linaro.org> wrote:
> +       aliases {
> +               serial0 = &uart0;
> +               serial1 = &uart1;
> +               serial2 = &uart2;
> +       };
>
+
> +&uart2 {
> +       status = "okay";
> +       clocks = <&uart2_clk>;
> +};

This is clearly mismatched here: you mark only one uart as 'enabled, but
list three of them as aliases. Having 'serial0' point to a disabled uart
may easily break applications that expect the first one to be the
console.

Best make that

       serial0 = &uart2;

and drop the other ones if only one of them is exposed on the
board. If all three are usable, you should enable them all here,
and make sure that the numbering of the aliases matches the
labels on the board or its documentation.

        Arnd

^ permalink raw reply

* RE: [PATCH 01/14] ARM: milbeaut: Add basic support for Milbeaut m10v SoC
From: sugaya.taichi @ 2018-11-21  9:33 UTC (permalink / raw)
  To: robh+dt
  Cc: linux-clk, devicetree, linux-arm-kernel, linux-kernel,
	linux-serial, mturquette, sboyd, mark.rutland, gregkh,
	daniel.lezcano, tglx, linux, jslaby, masami.hiramatsu,
	jaswinder.singh
In-Reply-To: <CAL_JsqJotYwwC490XmCtn_=-mrosxG3UUCy0P_SVO3d94yW6VA@mail.gmail.com>

Hi Rob

Thank you for your comments.

> -----Original Message-----
> From: Rob Herring [mailto:robh+dt@kernel.org]
> Sent: Tuesday, November 20, 2018 1:24 AM
> To: Sugaya, Taichi
> Cc: linux-clk; devicetree@vger.kernel.org; moderated list:ARM/FREESCALE
> IMX / MXC ARM ARCHITECTURE; linux-kernel@vger.kernel.org; open list:SERIAL
> DRIVERS; Michael Turquette; Stephen Boyd; Mark Rutland; Greg Kroah-Hartman;
> Daniel Lezcano; Thomas Gleixner; Russell King; Jiri Slaby; Masami Hiramatsu;
> Jassi Brar
> Subject: Re: [PATCH 01/14] ARM: milbeaut: Add basic support for Milbeaut
> m10v SoC
> 
> On Sun, Nov 18, 2018 at 7:00 PM Sugaya Taichi
> <sugaya.taichi@socionext.com> wrote:
> >
> > This adds the basic M10V SoC support under arch/arm.
> > Since all cores are activated in the custom bootloader before booting
> > linux, it is necessary to wait for sub-cores using the trampoline area.
> >
> > Signed-off-by: Sugaya Taichi <sugaya.taichi@socionext.com>
> > ---
> >  arch/arm/Kconfig                  |   2 +
> >  arch/arm/Makefile                 |   1 +
> >  arch/arm/mach-milbeaut/Kconfig    |  28 +++++++
> >  arch/arm/mach-milbeaut/Makefile   |   3 +
> >  arch/arm/mach-milbeaut/m10v_evb.c |  31 ++++++++
> >  arch/arm/mach-milbeaut/platsmp.c  | 157
> ++++++++++++++++++++++++++++++++++++++
> >  6 files changed, 222 insertions(+)
> >  create mode 100644 arch/arm/mach-milbeaut/Kconfig
> >  create mode 100644 arch/arm/mach-milbeaut/Makefile
> >  create mode 100644 arch/arm/mach-milbeaut/m10v_evb.c
> >  create mode 100644 arch/arm/mach-milbeaut/platsmp.c
> >
> > diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> > index 91be74d..0b8a1af 100644
> > --- a/arch/arm/Kconfig
> > +++ b/arch/arm/Kconfig
> > @@ -767,6 +767,8 @@ source "arch/arm/mach-mediatek/Kconfig"
> >
> >  source "arch/arm/mach-meson/Kconfig"
> >
> > +source "arch/arm/mach-milbeaut/Kconfig"
> > +
> >  source "arch/arm/mach-mmp/Kconfig"
> >
> >  source "arch/arm/mach-moxart/Kconfig"
> > diff --git a/arch/arm/Makefile b/arch/arm/Makefile
> > index 05a91d8..627853c 100644
> > --- a/arch/arm/Makefile
> > +++ b/arch/arm/Makefile
> > @@ -190,6 +190,7 @@ machine-$(CONFIG_ARCH_MV78XX0)              +=
> mv78xx0
> >  machine-$(CONFIG_ARCH_MVEBU)           += mvebu
> >  machine-$(CONFIG_ARCH_MXC)             += imx
> >  machine-$(CONFIG_ARCH_MEDIATEK)                += mediatek
> > +machine-$(CONFIG_ARCH_MILBEAUT)                += milbeaut
> >  machine-$(CONFIG_ARCH_MXS)             += mxs
> >  machine-$(CONFIG_ARCH_NETX)            += netx
> >  machine-$(CONFIG_ARCH_NOMADIK)         += nomadik
> > diff --git a/arch/arm/mach-milbeaut/Kconfig
> b/arch/arm/mach-milbeaut/Kconfig
> > new file mode 100644
> > index 0000000..63b6f69
> > --- /dev/null
> > +++ b/arch/arm/mach-milbeaut/Kconfig
> > @@ -0,0 +1,28 @@
> > +# SPDX-License-Identifier: GPL-2.0
> > +menuconfig ARCH_MILBEAUT
> > +       bool "Socionext Milbeaut SoCs"
> > +       depends on ARCH_MULTI_V7
> > +       select ARM_GIC
> 
> > +       select CLKDEV_LOOKUP
> > +       select GENERIC_CLOCKEVENTS
> > +       select CLKSRC_MMIO
> 
> The clock and timer drivers' kconfig entries should select these.
OK. move these to the correct kconfig.

> 
> > +       select ZONE_DMA
> 
> Why is this needed?
Ah, it may not be needed yet. confirm it.

> 
> > +       help
> > +               This enables support for Socionext Milbeaut SoCs
> > +
> > +if ARCH_MILBEAUT
> > +
> > +config ARCH_MILBEAUT_M10V
> > +       bool "Milbeaut SC2000/M10V platform"
> > +       select ARM_ARCH_TIMER
> > +       select M10V_TIMER
> > +       select PINCTRL
> > +       select PINCTRL_M10V
> > +       help
> > +         Support for Socionext's MILBEAUT M10V based systems
> > +
> > +config MACH_M10V_EVB
> > +       bool "Support for Milbeaut Evaluation boards"
> 
> You shouldn't need a kconfig entry for each board.
I see. 

> 
> > +       default y
> > +
> > +endif
> > diff --git a/arch/arm/mach-milbeaut/Makefile
> b/arch/arm/mach-milbeaut/Makefile
> > new file mode 100644
> > index 0000000..64f6f52
> > --- /dev/null
> > +++ b/arch/arm/mach-milbeaut/Makefile
> > @@ -0,0 +1,3 @@
> > +obj-$(CONFIG_SMP) += platsmp.o
> > +obj-$(CONFIG_MACH_M10V_EVB) += m10v_evb.o
> > +
> > diff --git a/arch/arm/mach-milbeaut/m10v_evb.c
> b/arch/arm/mach-milbeaut/m10v_evb.c
> > new file mode 100644
> > index 0000000..a1fa7c3
> > --- /dev/null
> > +++ b/arch/arm/mach-milbeaut/m10v_evb.c
> 
> This all looks SoC specific, not board specific.
Um that is right..

> 
> > @@ -0,0 +1,31 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (C) 2018 Socionext Inc.
> > + * Copyright:   (C) 2015 Linaro Ltd.
> > + */
> > +
> > +#include <linux/of.h>
> > +#include <linux/platform_device.h>
> 
> Not needed.
OK.

> 
> > +
> > +#include <asm/mach/arch.h>
> > +#include <asm/mach/map.h>
> > +
> > +static struct map_desc m10v_io_desc[] __initdata = {
> > +};
> > +
> > +void __init m10v_map_io(void)
> > +{
> > +       debug_ll_io_init();
> 
> If you use earlycon instead, then this isn't needed.
> 
> > +       iotable_init(m10v_io_desc, ARRAY_SIZE(m10v_io_desc));
> 
> This isn't needed.
OK.

> 
> > +}
> > +
> > +static const char * const m10v_compat[] = {
> > +       "socionext,milbeaut-m10v-evb",
> > +       NULL,
> > +};
> > +
> > +DT_MACHINE_START(M10V_REB, "Socionext Milbeaut")
> > +       .dt_compat      = m10v_compat,
> > +       .l2c_aux_mask   = 0xffffffff,
> > +       .map_io         = m10v_map_io,
> 
> It looks like you can remove this entire file and use the default machine
> desc.
OK, try to use the default machine descriptor instead.

> 
> > +MACHINE_END
> > diff --git a/arch/arm/mach-milbeaut/platsmp.c
> b/arch/arm/mach-milbeaut/platsmp.c
> > new file mode 100644
> > index 0000000..b706851
> > --- /dev/null
> > +++ b/arch/arm/mach-milbeaut/platsmp.c
> > @@ -0,0 +1,157 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Copyright (C) 2018 Socionext Inc.
> > + * Copyright:  (C) 2015 Linaro Ltd.
> > + */
> > +
> > +#include <linux/cpu_pm.h>
> > +#include <linux/irqchip/arm-gic.h>
> > +#include <linux/of_device.h>
> 
> Not needed.
Okay.

> 
> > +#include <linux/of_address.h>
> > +#include <linux/platform_device.h>
> 
> Not needed.
Okay.

> 
> > +#include <linux/suspend.h>
> > +
> > +#include <asm/cacheflush.h>
> > +#include <asm/cp15.h>
> > +#include <asm/idmap.h>
> > +#include <asm/smp_plat.h>
> > +#include <asm/suspend.h>
> > +
> > +#define M10V_MAX_CPU   4
> > +
> > +#define KERNEL_UNBOOT_FLAG     0x12345678
> > +#define CPU_FINISH_SUSPEND_FLAG 0x56784321
> > +
> > +static void __iomem *trampoline;
> > +
> > +static int m10v_boot_secondary(unsigned int l_cpu, struct task_struct
> *idle)
> > +{
> > +       unsigned int mpidr, cpu, cluster;
> > +
> > +       mpidr = cpu_logical_map(l_cpu);
> > +       cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
> > +       cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
> > +
> > +       if (cpu >= M10V_MAX_CPU)
> > +               return -EINVAL;
> > +
> > +       pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
> > +
> > +       writel(virt_to_phys(secondary_startup), trampoline + cpu * 4);
> > +       arch_send_wakeup_ipi_mask(cpumask_of(l_cpu));
> > +
> > +       return 0;
> > +}
> > +
> > +static void m10v_cpu_die(unsigned int l_cpu)
> > +{
> > +       gic_cpu_if_down(0);
> > +
> > +       v7_exit_coherency_flush(louis);
> > +
> > +       /* Now we are prepared for power-down, do it: */
> > +       wfi();
> > +}
> > +
> > +static int m10v_cpu_kill(unsigned int l_cpu)
> > +{
> > +       unsigned int mpidr, cpu;
> > +
> > +       mpidr = cpu_logical_map(l_cpu);
> > +       cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
> > +
> > +       writel(KERNEL_UNBOOT_FLAG, trampoline + cpu * 4);
> > +
> > +       return 1;
> > +}
> > +
> > +static struct smp_operations m10v_smp_ops __initdata = {
> > +       .smp_boot_secondary     = m10v_boot_secondary,
> > +       .cpu_die                = m10v_cpu_die,
> > +       .cpu_kill               = m10v_cpu_kill,
> > +};
> > +
> > +static int __init m10v_smp_init(void)
> > +{
> > +       unsigned int mpidr, cpu, cluster;
> > +       struct device_node *np;
> > +
> > +       np = of_find_compatible_node(NULL, NULL,
> "socionext,milbeaut-m10v-evb");
> > +       if (!np || !of_device_is_available(np))
> 
> Just use of_machine_is_compatible() here.
I got it, use the function instead.

Thanks
Sugaya Taichi

> 
> > +               return -ENODEV;
> > +       of_node_put(np);
> > +
> > +       np = of_find_compatible_node(NULL, NULL,
> "socionext,smp-trampoline");
> > +       if (!np)
> > +               return -ENODEV;
> > +
> > +       trampoline = of_iomap(np, 0);
> > +       if (!trampoline)
> > +               return -ENODEV;
> > +       of_node_put(np);
> > +
> > +       mpidr = read_cpuid_mpidr();
> > +       cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
> > +       cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
> > +
> > +       pr_info("MCPM boot on cpu_%u cluster_%u\n", cpu, cluster);
> > +
> > +       for (cpu = 0; cpu < M10V_MAX_CPU; cpu++)
> > +               writel(KERNEL_UNBOOT_FLAG, trampoline + cpu * 4);
> > +
> > +       smp_set_ops(&m10v_smp_ops);
> > +
> > +       return 0;
> > +}
> > +early_initcall(m10v_smp_init);
> > +
> > +static int m10v_pm_valid(suspend_state_t state)
> > +{
> > +       return (state == PM_SUSPEND_STANDBY) || (state ==
> PM_SUSPEND_MEM);
> > +}
> > +
> > +typedef void (*phys_reset_t)(unsigned long);
> > +static phys_reset_t phys_reset;
> > +
> > +static int m10v_die(unsigned long arg)
> > +{
> > +       setup_mm_for_reboot();
> > +       asm("wfi");
> > +       /* Boot just like a secondary */
> > +       phys_reset = (phys_reset_t)(unsigned
> long)virt_to_phys(cpu_reset);
> > +       phys_reset(virt_to_phys(cpu_resume));
> > +
> > +       return 0;
> > +}
> > +
> > +static int m10v_pm_enter(suspend_state_t state)
> > +{
> > +       switch (state) {
> > +       case PM_SUSPEND_STANDBY:
> > +               pr_err("STANDBY\n");
> > +               asm("wfi");
> > +               break;
> > +       case PM_SUSPEND_MEM:
> > +               pr_err("SUSPEND\n");
> > +               cpu_pm_enter();
> > +               cpu_suspend(0, m10v_die);
> > +               cpu_pm_exit();
> > +               break;
> > +       }
> > +       return 0;
> > +}
> > +
> > +static const struct platform_suspend_ops m10v_pm_ops = {
> > +       .valid          = m10v_pm_valid,
> > +       .enter          = m10v_pm_enter,
> > +};
> > +
> > +struct clk *m10v_clclk_register(struct device *cpu_dev);
> > +
> > +static int __init m10v_pm_init(void)
> > +{
> > +       suspend_set_ops(&m10v_pm_ops);
> > +
> > +       return 0;
> > +}
> > +late_initcall(m10v_pm_init);
> > --
> > 1.9.1
> >

^ permalink raw reply

* Re: [PATCH 05/14] clocksource/drivers/timer-milbeaut: Add Milbeaut M10V timer
From: Daniel Lezcano @ 2018-11-21 10:08 UTC (permalink / raw)
  To: Sugaya Taichi, linux-clk, devicetree, linux-arm-kernel,
	linux-kernel, linux-serial
  Cc: Michael Turquette, Stephen Boyd, Rob Herring, Mark Rutland,
	Greg Kroah-Hartman, Thomas Gleixner, Russell King, Jiri Slaby,
	Masami Hiramatsu, Jassi Brar
In-Reply-To: <1542589274-13878-6-git-send-email-sugaya.taichi@socionext.com>


Hi Sugaya,


On 19/11/2018 02:01, Sugaya Taichi wrote:
> Add Milbeaut M10V timer using 32bit timer in peripheral.

Give a better description of the timer as it is new timer introduced.

> Signed-off-by: Sugaya Taichi <sugaya.taichi@socionext.com>
> ---
>  drivers/clocksource/Kconfig      |   8 +++
>  drivers/clocksource/Makefile     |   1 +
>  drivers/clocksource/timer-m10v.c | 146 +++++++++++++++++++++++++++++++++++++++
>  3 files changed, 155 insertions(+)
>  create mode 100644 drivers/clocksource/timer-m10v.c
> 
> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
> index 55c77e4..a278d72 100644
> --- a/drivers/clocksource/Kconfig
> +++ b/drivers/clocksource/Kconfig
> @@ -638,4 +638,12 @@ config GX6605S_TIMER
>  	help
>  	  This option enables support for gx6605s SOC's timer.
>  
> +config M10V_TIMER
> +	bool "Milbeaut M10V timer driver" if COMPILE_TEST
> +	depends on OF
> +	depends on ARM
> +	select TIMER_OF
> +	help
> +	  Enables the support for Milbeaut M10V timer driver.
> +
>  endmenu
> diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
> index dd91381..8e908b4 100644
> --- a/drivers/clocksource/Makefile
> +++ b/drivers/clocksource/Makefile
> @@ -55,6 +55,7 @@ obj-$(CONFIG_CLKSRC_TI_32K)	+= timer-ti-32k.o
>  obj-$(CONFIG_CLKSRC_NPS)	+= timer-nps.o
>  obj-$(CONFIG_OXNAS_RPS_TIMER)	+= timer-oxnas-rps.o
>  obj-$(CONFIG_OWL_TIMER)		+= timer-owl.o
> +obj-$(CONFIG_M10V_TIMER)	+= timer-m10v.o
>  obj-$(CONFIG_SPRD_TIMER)	+= timer-sprd.o
>  obj-$(CONFIG_NPCM7XX_TIMER)	+= timer-npcm7xx.o
>  
> diff --git a/drivers/clocksource/timer-m10v.c b/drivers/clocksource/timer-m10v.c
> new file mode 100644
> index 0000000..ff97c23
> --- /dev/null
> +++ b/drivers/clocksource/timer-m10v.c
> @@ -0,0 +1,146 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright (C) 2018 Socionext Inc.
> + */
> +
> +#include <linux/clk.h>

------->

> +#include <linux/clockchips.h>

It is included from timer-of.h

<-------

> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/irqreturn.h>

------->

> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +#include <linux/slab.h>

Those are not needed IMO.

<---------


> +#include "timer-of.h"
> +
> +#define FSL_TMR_TMCSR_OFS	0x0
> +#define FSL_TMR_TMR_OFS		0x4
> +#define FSL_TMR_TMRLR1_OFS	0x8
> +#define FSL_TMR_TMRLR2_OFS	0xc
> +#define FSL_RMT_REGSZPCH	0x10
> +
> +#define FSL_TMR_TMCSR_OUTL	BIT(5)
> +#define FSL_TMR_TMCSR_RELD	BIT(4)
> +#define FSL_TMR_TMCSR_INTE	BIT(3)
> +#define FSL_TMR_TMCSR_UF	BIT(2)
> +#define FSL_TMR_TMCSR_CNTE	BIT(1)
> +#define FSL_TMR_TMCSR_TRG	BIT(0)
> +
> +#define FSL_TMR_TMCSR_CSL_DIV2	0
> +#define FSL_TMR_TMCSR_CSL	BIT(10)
> +
> +#define M10V_TIMER_RATING	500
> +
> +static irqreturn_t m10v_timer_interrupt(int irq, void *dev_id)
> +{
> +	struct clock_event_device *clk = dev_id;
> +	struct timer_of *to = to_timer_of(clk);
> +	u32 val;
> +
> +	val = readl_relaxed(timer_of_base(to) + FSL_TMR_TMCSR_OFS);
> +	val &= ~FSL_TMR_TMCSR_UF;
> +	writel_relaxed(val, timer_of_base(to) + FSL_TMR_TMCSR_OFS);
> +
> +	clk->event_handler(clk);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int m10v_set_state_periodic(struct clock_event_device *clk)
> +{
> +	struct timer_of *to = to_timer_of(clk);
> +	u32 val = (FSL_TMR_TMCSR_CSL_DIV2 * FSL_TMR_TMCSR_CSL);

	FSL_TMR_TMCSR_CSL_DIV2 is zero, so val is always zero.
	
> +	writel_relaxed(val, timer_of_base(to) + FSL_TMR_TMCSR_OFS);
> +
> +	writel_relaxed(to->of_clk.period, timer_of_base(to) +
> +				FSL_TMR_TMRLR1_OFS);
> +	val |= FSL_TMR_TMCSR_RELD | FSL_TMR_TMCSR_CNTE |
> +		FSL_TMR_TMCSR_TRG | FSL_TMR_TMCSR_INTE;
> +	writel_relaxed(val, timer_of_base(to) + FSL_TMR_TMCSR_OFS);
> +	return 0;
> +}
> +
> +static int m10v_set_state_oneshot(struct clock_event_device *clk)
> +{
> +	struct timer_of *to = to_timer_of(clk);
> +	u32 val = (FSL_TMR_TMCSR_CSL_DIV2 * FSL_TMR_TMCSR_CSL);
> +
> +	writel_relaxed(val, timer_of_base(to) + FSL_TMR_TMCSR_OFS);
> +	return 0;
> +}
> +
> +static int m10v_clkevt_next_event(unsigned long event,
> +				   struct clock_event_device *clk)
> +{
> +	struct timer_of *to = to_timer_of(clk);
> +
> +	writel_relaxed(event, timer_of_base(to) + FSL_TMR_TMRLR1_OFS);
> +	writel_relaxed((FSL_TMR_TMCSR_CSL_DIV2 * FSL_TMR_TMCSR_CSL) |

Same comment here.

> +			FSL_TMR_TMCSR_CNTE | FSL_TMR_TMCSR_INTE |
> +			FSL_TMR_TMCSR_TRG, timer_of_base(to) +
> +			FSL_TMR_TMCSR_OFS);
> +	return 0;
> +}
> +
> +static int m10v_config_clock_source(struct timer_of *to)
> +{
> +	writel_relaxed(0, timer_of_base(to) + FSL_TMR_TMCSR_OFS);
> +	writel_relaxed(~0, timer_of_base(to) + FSL_TMR_TMR_OFS);
> +	writel_relaxed(~0, timer_of_base(to) + FSL_TMR_TMRLR1_OFS);
> +	writel_relaxed(~0, timer_of_base(to) + FSL_TMR_TMRLR2_OFS);
> +	writel_relaxed(BIT(4) | BIT(1) | BIT(0), timer_of_base(to) +
> +		FSL_TMR_TMCSR_OFS);
> +	return 0;
> +}
> +
> +static int m10v_config_clock_event(struct timer_of *to)
> +{
> +	writel_relaxed(0, timer_of_base(to) + FSL_TMR_TMCSR_OFS);
> +	return 0;
> +}
> +
> +static struct timer_of to = {
> +	.flags = TIMER_OF_IRQ | TIMER_OF_BASE | TIMER_OF_CLOCK,
> +
> +	.clkevt = {
> +		.name = "m10v-clkevt",
> +		.rating = M10V_TIMER_RATING,
> +		.cpumask = cpu_possible_mask,
> +	},
> +
> +	.of_irq = {
> +		.flags = IRQF_TIMER | IRQF_IRQPOLL,
> +	},
> +};
> +
> +static int __init m10v_timer_init(struct device_node *node)
> +{
> +	int ret;
> +
> +	to.clkevt.features = CLOCK_EVT_FEAT_DYNIRQ | CLOCK_EVT_FEAT_ONESHOT;
> +	to.clkevt.set_state_oneshot = m10v_set_state_oneshot;
> +	to.clkevt.set_state_periodic = m10v_set_state_periodic;
> +	to.clkevt.set_next_event = m10v_clkevt_next_event;
> +	to.of_irq.handler = m10v_timer_interrupt;

Move the initialization in the timer_of structure above.

> +	ret = timer_of_init(node, &to);
> +	if (ret)
> +		goto err;

You should return directly, rollback is done in the timer_of_init().

> +
> +	m10v_config_clock_source(&to);
> +	clocksource_mmio_init(timer_of_base(&to) + FSL_TMR_TMR_OFS,
> +		node->name, timer_of_rate(&to), M10V_TIMER_RATING, 32,
> +		clocksource_mmio_readl_down);

May be you can add the sched_clock also ?

> +	m10v_config_clock_event(&to);
> +	clockevents_config_and_register(&to.clkevt, timer_of_rate(&to),
> +				15, 0xffffffff);
> +
> +	return 0;
> +err:
> +	timer_of_cleanup(&to);
> +	return ret;
> +}
> +TIMER_OF_DECLARE(m10v_peritimer, "socionext,milbeaut-m10v-timer",
> +		m10v_timer_init);
> 


-- 
 <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog

^ permalink raw reply

* Re: [PATCH v2 01/10] mailbox: Support blocking transfers in atomic context
From: Thierry Reding @ 2018-11-21 14:27 UTC (permalink / raw)
  To: Jassi Brar
  Cc: Devicetree List, Greg KH, mliljeberg, Mikko Perttunen, talho,
	linux-serial, jslaby, linux-tegra, ppessi, Jon Hunter,
	linux-arm-kernel
In-Reply-To: <20181120152907.GA28796@ulmo>


[-- Attachment #1.1: Type: text/plain, Size: 4139 bytes --]

On Tue, Nov 20, 2018 at 04:29:07PM +0100, Thierry Reding wrote:
> On Sat, Nov 17, 2018 at 11:27:17AM -0600, Jassi Brar wrote:
> > On Mon, Nov 12, 2018 at 9:18 AM Thierry Reding <thierry.reding@gmail.com> wrote:
> > >
> > > From: Thierry Reding <treding@nvidia.com>
> > >
> > > The mailbox framework supports blocking transfers via completions for
> > > clients that can sleep. In order to support blocking transfers in cases
> > > where the transmission is not permitted to sleep, add a new ->flush()
> > > callback that controller drivers can implement to busy loop until the
> > > transmission has been completed. This will automatically be called when
> > > available and interrupts are disabled for clients that request blocking
> > > transfers.
> > >
> > > Signed-off-by: Thierry Reding <treding@nvidia.com>
> > > ---
> > >  drivers/mailbox/mailbox.c          | 8 ++++++++
> > >  include/linux/mailbox_controller.h | 4 ++++
> > >  2 files changed, 12 insertions(+)
> > >
> > > diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
> > > index 674b35f402f5..0eaf21259874 100644
> > > --- a/drivers/mailbox/mailbox.c
> > > +++ b/drivers/mailbox/mailbox.c
> > > @@ -267,6 +267,14 @@ int mbox_send_message(struct mbox_chan *chan, void *mssg)
> > >                 unsigned long wait;
> > >                 int ret;
> > >
> > > +               if (irqs_disabled() && chan->mbox->ops->flush) {
> > > +                       ret = chan->mbox->ops->flush(chan, chan->cl->tx_tout);
> > > +                       if (ret < 0)
> > > +                               tx_tick(chan, ret);
> > > +
> > > +                       return ret;
> > > +               }
> > > +
> > This is hacky. I think we can do without busy waiting in atomic
> > context. You could queue locally while in atomic context and then
> > transfer in blocking mode. I don't think we should worry about the
> > 'throughput' as there already is no h/w rate control even with
> > busy-waiting.
> 
> I actually tried to do that before I added this flushing mechanism. The
> problem is, like you said, one of rate control. As mentioned in the
> cover letter, the shared mailboxes implemented in tegra-hsp are used as
> RX and TX channels for the TCU, which is like a virtual UART. The TTY
> driver included as part of this series will use one of the mailboxes to
> transmit data that is written to the console. The problem is that if
> these transmissions are not rate-limited on the TTY driver side, the
> console will just keep writing data and eventually overflow the buffer
> that we have in the mailbox subsystem.
> 
> The problem is that data comes in at a much higher rate than what we can
> output. This is especially true at boot when the TCU console takes over
> and the whole log buffer is dumped on it.
> 
> So the only way to rate-limit is to either make mbox_send_message()
> block, but that can only be done in non-atomic context. The console,
> however, will always run in atomic context, so the only way to do rate-
> limiting is by busy looping.

What I also tried before was to implement busy looping within the
->send_data() callback of the driver so that we didn't have to put this
into the core. Unfortunately, however, the ->send_data() callback is
called under chan->lock, which means that from mbox_send_message() we
don't have a way to mark the transfer as done. In order to do that we'd
have to call mbox_chan_txdone(), but that ends up calling tx_tick() and
that in turn also attempts to take the chan->lock, which would cause a
deadlock.

The explicit flushing is the best alternative that I could come up with.
I think it's not all that hacky, because it's very explicit about what's
going on and it has the nice side-effect that it will allow the mailbox
to work in interrupt driven mode if possible and only resorting to the
busy loop in atomic context.

At this point I think I have explored all other options and I frankly
can't find a more proper way to achieve what we need here. Perhaps you
can think of additional ways to accomplish this?

Thierry

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

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

^ permalink raw reply

* [PATCH] drivers/tty: add missing of_node_put()
From: Yangtao Li @ 2018-11-21 15:22 UTC (permalink / raw)
  To: davem, gregkh, jslaby; +Cc: sparclinux, linux-serial, linux-kernel, Yangtao Li

of_find_node_by_path() acquires a reference to the node
returned by it and that reference needs to be dropped by its caller.
This place is not doing this, so fix it.

Signed-off-by: Yangtao Li <tiny.windzz@gmail.com>
---
 drivers/tty/serial/suncore.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/tty/serial/suncore.c b/drivers/tty/serial/suncore.c
index 70a4ea4eaa6e..990376576970 100644
--- a/drivers/tty/serial/suncore.c
+++ b/drivers/tty/serial/suncore.c
@@ -112,6 +112,7 @@ void sunserial_console_termios(struct console *con, struct device_node *uart_dp)
 		mode = of_get_property(dp, mode_prop, NULL);
 		if (!mode)
 			mode = "9600,8,n,1,-";
+		of_node_put(dp);
 	}
 
 	cflag = CREAD | HUPCL | CLOCAL;
-- 
2.17.0

^ permalink raw reply related

* [PATCH] serial/sunsu: add missing of_node_put()
From: Yangtao Li @ 2018-11-21 16:06 UTC (permalink / raw)
  To: davem, gregkh, jslaby; +Cc: sparclinux, linux-serial, linux-kernel, Yangtao Li

of_find_node_by_path() acquires a reference to the node
returned by it and that reference needs to be dropped by its caller.
This place is not doing this, so fix it.

Signed-off-by: Yangtao Li <tiny.windzz@gmail.com>
---
 drivers/tty/serial/sunsu.c | 20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c
index 6cf3e9b0728f..4a27c0114d50 100644
--- a/drivers/tty/serial/sunsu.c
+++ b/drivers/tty/serial/sunsu.c
@@ -1394,22 +1394,32 @@ static inline struct console *SUNSU_CONSOLE(void)
 static enum su_type su_get_type(struct device_node *dp)
 {
 	struct device_node *ap = of_find_node_by_path("/aliases");
+	enum su_type rc = SU_PORT_PORT;
 
 	if (ap) {
+		struct device_node *tmp;
 		const char *keyb = of_get_property(ap, "keyboard", NULL);
 		const char *ms = of_get_property(ap, "mouse", NULL);
 
 		if (keyb) {
-			if (dp == of_find_node_by_path(keyb))
-				return SU_PORT_KBD;
+			tmp = of_find_node_by_path(keyb);
+			if (tmp && dp == tmp){
+				rc = SU_PORT_KBD;
+				goto out;
+			}
 		}
 		if (ms) {
-			if (dp == of_find_node_by_path(ms))
-				return SU_PORT_MS;
+			tmp = of_find_node_by_path(ms);
+			if (tmp && dp == tmp){
+				rc = SU_PORT_MS;
+				goto out;
+			}
 		}
 	}
 
-	return SU_PORT_PORT;
+out:
+	of_node_put(ap);
+	return rc;
 }
 
 static int su_probe(struct platform_device *op)
-- 
2.17.0

^ permalink raw reply related

* Re: [PATCH v2 08/15] irqchip: Add RDA8810PL interrupt driver
From: Manivannan Sadhasivam @ 2018-11-21 17:41 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: olof, arnd, robh+dt, tglx, jason, daniel.lezcano, gregkh, jslaby,
	afaerber, linux-arm-kernel, linux-kernel, devicetree,
	linux-serial, amit.kucheria, linus.walleij, zhao_steven,
	overseas.sales
In-Reply-To: <83f70f64-79f1-c6e5-0328-09cc567f2686@arm.com>

Hi Marc,

On Wed, Nov 21, 2018 at 08:41:25AM +0000, Marc Zyngier wrote:
> On 21/11/2018 03:36, Manivannan Sadhasivam wrote:
> > Add interrupt driver for RDA Micro RDA8810PL SoC.
> > 
> > Signed-off-by: Andreas Färber <afaerber@suse.de>
> > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > ---
> >  arch/arm/mach-rda/Kconfig      |   1 +
> >  drivers/irqchip/Kconfig        |   4 ++
> >  drivers/irqchip/Makefile       |   1 +
> >  drivers/irqchip/irq-rda-intc.c | 113 +++++++++++++++++++++++++++++++++
> >  4 files changed, 119 insertions(+)
> >  create mode 100644 drivers/irqchip/irq-rda-intc.c
> > 
> > diff --git a/arch/arm/mach-rda/Kconfig b/arch/arm/mach-rda/Kconfig
> > index dafab78d7aab..29012bc68ca4 100644
> > --- a/arch/arm/mach-rda/Kconfig
> > +++ b/arch/arm/mach-rda/Kconfig
> > @@ -3,5 +3,6 @@ menuconfig ARCH_RDA
> >  	depends on ARCH_MULTI_V7
> >  	select COMMON_CLK
> >  	select GENERIC_IRQ_CHIP
> > +	select RDA_INTC
> >  	help
> >  	  This enables support for the RDA Micro 8810PL SoC family.
> > diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
> > index 51a5ef0e96ed..9d54645870ad 100644
> > --- a/drivers/irqchip/Kconfig
> > +++ b/drivers/irqchip/Kconfig
> > @@ -195,6 +195,10 @@ config JCORE_AIC
> >  	help
> >  	  Support for the J-Core integrated AIC.
> >  
> > +config RDA_INTC
> > +	bool
> > +	select IRQ_DOMAIN
> > +
> >  config RENESAS_INTC_IRQPIN
> >  	bool
> >  	select IRQ_DOMAIN
> > diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
> > index 794c13d3ac3d..417108027e40 100644
> > --- a/drivers/irqchip/Makefile
> > +++ b/drivers/irqchip/Makefile
> > @@ -43,6 +43,7 @@ obj-$(CONFIG_IMGPDC_IRQ)		+= irq-imgpdc.o
> >  obj-$(CONFIG_IRQ_MIPS_CPU)		+= irq-mips-cpu.o
> >  obj-$(CONFIG_SIRF_IRQ)			+= irq-sirfsoc.o
> >  obj-$(CONFIG_JCORE_AIC)			+= irq-jcore-aic.o
> > +obj-$(CONFIG_RDA_INTC)			+= irq-rda-intc.o
> >  obj-$(CONFIG_RENESAS_INTC_IRQPIN)	+= irq-renesas-intc-irqpin.o
> >  obj-$(CONFIG_RENESAS_IRQC)		+= irq-renesas-irqc.o
> >  obj-$(CONFIG_VERSATILE_FPGA_IRQ)	+= irq-versatile-fpga.o
> > diff --git a/drivers/irqchip/irq-rda-intc.c b/drivers/irqchip/irq-rda-intc.c
> > new file mode 100644
> > index 000000000000..1b372bdb23bc
> > --- /dev/null
> > +++ b/drivers/irqchip/irq-rda-intc.c
> > @@ -0,0 +1,113 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * RDA8810PL SoC irqchip driver
> > + *
> > + * Copyright RDA Microelectronics Company Limited
> > + * Copyright (c) 2017 Andreas Färber
> > + * Copyright (c) 2018 Manivannan Sadhasivam
> > + */
> > +
> > +#include <linux/init.h>
> > +#include <linux/interrupt.h>
> > +#include <linux/irq.h>
> > +#include <linux/irqchip.h>
> > +#include <linux/irqdomain.h>
> > +#include <linux/of_address.h>
> > +
> > +#include <asm/irq.h>
> 
> You shouldn't need to include this.
> 

Ack.

> > +#include <asm/exception.h>
> > +
> > +#define RDA_INTC_FINALSTATUS	0x00
> > +#define RDA_INTC_STATUS		0x04
> > +#define RDA_INTC_MASK_SET	0x08
> > +#define RDA_INTC_MASK_CLR	0x0c
> > +#define RDA_INTC_WAKEUP_MASK	0x18
> > +#define RDA_INTC_CPU_SLEEP	0x1c
> 
> Half of these constants are unused. Do we really need them?
> 

Usually I tend to define all registers to provide overall reg map. But
I have no issues to remove the not used ones.

> > +
> > +#define RDA_IRQ_MASK_ALL	0xFFFFFFFF
> > +
> > +#define RDA_NR_IRQS 32
> 
> Surely the mask can be derived from the number of interrupts?
> 

Why not? Since each bit corresponds to a single interrupt, 0xFFFFFFFF
can cover all 32 bits which is equal to the total number of interrupts
supported by the controller. Am I missing anything here?

> > +
> > +static void __iomem *base;
> 
> Everything in this driver is prefixed with rda_. It would seem valuable
> to  do the same here, as "base" is a bit too generic.
> 

Ack.

> > +
> > +static void rda_intc_mask_irq(struct irq_data *d)
> > +{
> > +	writel_relaxed(BIT(d->hwirq), base + RDA_INTC_MASK_CLR);
> > +}
> > +
> > +static void rda_intc_unmask_irq(struct irq_data *d)
> > +{
> > +	writel_relaxed(BIT(d->hwirq), base + RDA_INTC_MASK_SET);
> 
> Are the names MASK_CLR and MASK_SET from the datasheet? They seem to be
> backward (you set the mask to unmask...), and seem to behave like an
> enable instead. That's not a big issue, just curious.
> 

Yes, this naming convention comes from the datasheet and it is a bit
wierd as you said ;-)

> > +}
> > +
> > +static int rda_intc_set_type(struct irq_data *data, unsigned int flow_type)
> > +{
> > +	/* Hardware supports only level triggered interrupts */
> > +	if (flow_type & (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW))
> > +		irq_set_handler(data->irq, handle_level_irq);
> 
> Why do you need to do this? You've already configured it at map time,
> and it is not changing under your feet. This should be written as:
> 
> if ((flow_type & (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW)) == flow_type)
> 	return 0;
> 
> return -EINVAL;
> 

Okay.

> > +	else
> > +		return -EINVAL;
> > +
> > +	return 0;
> > +}
> > +
> > +static struct irq_domain *rda_irq_domain;
> 
> Please move this to the top of the file, next to "base".
> 

Ack.

> > +
> > +static void __exception_irq_entry rda_handle_irq(struct pt_regs *regs)
> > +{
> > +	u32 stat = readl_relaxed(base + RDA_INTC_FINALSTATUS);
> > +	u32 hwirq;
> > +
> > +	while (stat) {
> > +		hwirq = __fls(stat);
> > +		handle_domain_irq(rda_irq_domain, hwirq, regs);
> > +		stat &= ~(1 << hwirq);
> > +	}
> > +}
> > +
> > +static struct irq_chip rda_irq_chip = {
> > +	.name		= "rda-intc",
> > +	.irq_mask	= rda_intc_mask_irq,
> > +	.irq_unmask	= rda_intc_unmask_irq,
> > +	.irq_set_type	= rda_intc_set_type,
> > +};
> > +
> > +static int rda_irq_map(struct irq_domain *d,
> > +		       unsigned int virq, irq_hw_number_t hw)
> > +{
> > +	irq_set_status_flags(virq, IRQ_LEVEL);
> > +	irq_set_chip_and_handler(virq, &rda_irq_chip, handle_level_irq);
> > +	irq_set_chip_data(virq, d->host_data);
> > +	irq_set_probe(virq);
> > +
> > +	return 0;
> > +}
> > +
> > +static const struct irq_domain_ops rda_irq_domain_ops = {
> > +	.map = rda_irq_map,
> > +	.xlate = irq_domain_xlate_onecell,
> > +};
> > +
> > +static int __init rda8810_intc_init(struct device_node *node,
> > +				    struct device_node *parent)
> > +{
> > +	base = of_io_request_and_map(node, 0, "rda-intc");
> > +	if (!base)
> > +		return -ENXIO;
> > +
> > +	/* Mask, and invalidate all interrupt sources */
> 
> What does "invalidate" mean here?
> 

Mean to say "disable" but yeah not appropriate. Will remove it.

> > +	writel_relaxed(RDA_IRQ_MASK_ALL, base + RDA_INTC_MASK_CLR);
> > +
> > +	rda_irq_domain = irq_domain_create_linear(&node->fwnode, RDA_NR_IRQS,
> > +						  &rda_irq_domain_ops, base);
> > +	if (WARN_ON(!rda_irq_domain)) {
> > +		iounmap(base);
> > +		return -ENODEV;
> 
> Why ENODEV? ENOMEM seems more appropriate. The WARN_ON is a bit
> superfluous, as the failing probe should be noisy enough.
> 

Ack. ENOMEM comes from your suggestion in previous review.

> > +	}
> > +
> > +	set_handle_irq(rda_handle_irq);
> > +
> > +	return 0;
> > +}
> > +
> > +IRQCHIP_DECLARE(rda_intc, "rda,8810pl-intc", rda8810_intc_init);
> > 
> 
> You've already posted two versions in 3 days, please allow for a week
> between versions.
> 

Sorry for that. I thought the other way, allowing too much delay would
hinder the review process. Will post the next revision after few more days.

Thanks,
Mani

> Thanks,
> 
> 	M.
> -- 
> Jazz is not dead. It just smells funny...

^ permalink raw reply

* Re: [PATCH v2 01/10] mailbox: Support blocking transfers in atomic context
From: Jassi Brar @ 2018-11-22  2:18 UTC (permalink / raw)
  To: Thierry Reding
  Cc: Devicetree List, Greg KH, mliljeberg, Mikko Perttunen, talho,
	linux-serial, jslaby, linux-tegra, ppessi, Jon Hunter,
	linux-arm-kernel
In-Reply-To: <20181121142740.GA29704@ulmo>

On Wed, Nov 21, 2018 at 8:27 AM Thierry Reding <thierry.reding@gmail.com> wrote:
>
> On Tue, Nov 20, 2018 at 04:29:07PM +0100, Thierry Reding wrote:
> > On Sat, Nov 17, 2018 at 11:27:17AM -0600, Jassi Brar wrote:
> > > On Mon, Nov 12, 2018 at 9:18 AM Thierry Reding <thierry.reding@gmail.com> wrote:
> > > >
> > > > From: Thierry Reding <treding@nvidia.com>
> > > >
> > > > The mailbox framework supports blocking transfers via completions for
> > > > clients that can sleep. In order to support blocking transfers in cases
> > > > where the transmission is not permitted to sleep, add a new ->flush()
> > > > callback that controller drivers can implement to busy loop until the
> > > > transmission has been completed. This will automatically be called when
> > > > available and interrupts are disabled for clients that request blocking
> > > > transfers.
> > > >
> > > > Signed-off-by: Thierry Reding <treding@nvidia.com>
> > > > ---
> > > >  drivers/mailbox/mailbox.c          | 8 ++++++++
> > > >  include/linux/mailbox_controller.h | 4 ++++
> > > >  2 files changed, 12 insertions(+)
> > > >
> > > > diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
> > > > index 674b35f402f5..0eaf21259874 100644
> > > > --- a/drivers/mailbox/mailbox.c
> > > > +++ b/drivers/mailbox/mailbox.c
> > > > @@ -267,6 +267,14 @@ int mbox_send_message(struct mbox_chan *chan, void *mssg)
> > > >                 unsigned long wait;
> > > >                 int ret;
> > > >
> > > > +               if (irqs_disabled() && chan->mbox->ops->flush) {
> > > > +                       ret = chan->mbox->ops->flush(chan, chan->cl->tx_tout);
> > > > +                       if (ret < 0)
> > > > +                               tx_tick(chan, ret);
> > > > +
> > > > +                       return ret;
> > > > +               }
> > > > +
> > > This is hacky. I think we can do without busy waiting in atomic
> > > context. You could queue locally while in atomic context and then
> > > transfer in blocking mode. I don't think we should worry about the
> > > 'throughput' as there already is no h/w rate control even with
> > > busy-waiting.
> >
> > I actually tried to do that before I added this flushing mechanism. The
> > problem is, like you said, one of rate control. As mentioned in the
> > cover letter, the shared mailboxes implemented in tegra-hsp are used as
> > RX and TX channels for the TCU, which is like a virtual UART. The TTY
> > driver included as part of this series will use one of the mailboxes to
> > transmit data that is written to the console. The problem is that if
> > these transmissions are not rate-limited on the TTY driver side, the
> > console will just keep writing data and eventually overflow the buffer
> > that we have in the mailbox subsystem.
> >
> > The problem is that data comes in at a much higher rate than what we can
> > output. This is especially true at boot when the TCU console takes over
> > and the whole log buffer is dumped on it.
> >
> > So the only way to rate-limit is to either make mbox_send_message()
> > block, but that can only be done in non-atomic context. The console,
> > however, will always run in atomic context, so the only way to do rate-
> > limiting is by busy looping.
>
> What I also tried before was to implement busy looping within the
> ->send_data() callback of the driver so that we didn't have to put this
> into the core. Unfortunately, however, the ->send_data() callback is
> called under chan->lock, which means that from mbox_send_message() we
> don't have a way to mark the transfer as done. In order to do that we'd
> have to call mbox_chan_txdone(), but that ends up calling tx_tick() and
> that in turn also attempts to take the chan->lock, which would cause a
> deadlock.
>
> The explicit flushing is the best alternative that I could come up with.
> I think it's not all that hacky, because it's very explicit about what's
> going on and it has the nice side-effect that it will allow the mailbox
> to work in interrupt driven mode if possible and only resorting to the
> busy loop in atomic context.
>
> At this point I think I have explored all other options and I frankly
> can't find a more proper way to achieve what we need here. Perhaps you
> can think of additional ways to accomplish this?
>
Well, I would have a local ring buffer (array) of enough size to hold
the characters and then have a task consuming data from that ring
buffer by transmitting over mailbox.

-jassi

^ permalink raw reply

* Re: [PATCH 05/14] clocksource/drivers/timer-milbeaut: Add Milbeaut M10V timer
From: Sugaya, Taichi @ 2018-11-22  2:23 UTC (permalink / raw)
  To: Daniel Lezcano, linux-clk, devicetree, linux-arm-kernel,
	linux-kernel, linux-serial
  Cc: Michael Turquette, Stephen Boyd, Rob Herring, Mark Rutland,
	Greg Kroah-Hartman, Thomas Gleixner, Russell King, Jiri Slaby,
	Masami Hiramatsu, Jassi Brar
In-Reply-To: <c6b7ddb0-064a-8f09-bbb4-9754f3d63ecb@linaro.org>

Hi Daniel

Thank you for your comments.

On 2018/11/21 19:08, Daniel Lezcano wrote:
> Hi Sugaya,
>
>
> On 19/11/2018 02:01, Sugaya Taichi wrote:
>> Add Milbeaut M10V timer using 32bit timer in peripheral.
> Give a better description of the timer as it is new timer introduced.

I got it. Add more description.


>> Signed-off-by: Sugaya Taichi <sugaya.taichi@socionext.com>
>> ---
>>   drivers/clocksource/Kconfig      |   8 +++
>>   drivers/clocksource/Makefile     |   1 +
>>   drivers/clocksource/timer-m10v.c | 146 +++++++++++++++++++++++++++++++++++++++
>>   3 files changed, 155 insertions(+)
>>   create mode 100644 drivers/clocksource/timer-m10v.c
>>
>> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
>> index 55c77e4..a278d72 100644
>> --- a/drivers/clocksource/Kconfig
>> +++ b/drivers/clocksource/Kconfig
>> @@ -638,4 +638,12 @@ config GX6605S_TIMER
>>   	help
>>   	  This option enables support for gx6605s SOC's timer.
>>   
>> +config M10V_TIMER
>> +	bool "Milbeaut M10V timer driver" if COMPILE_TEST
>> +	depends on OF
>> +	depends on ARM
>> +	select TIMER_OF
>> +	help
>> +	  Enables the support for Milbeaut M10V timer driver.
>> +
>>   endmenu
>> diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
>> index dd91381..8e908b4 100644
>> --- a/drivers/clocksource/Makefile
>> +++ b/drivers/clocksource/Makefile
>> @@ -55,6 +55,7 @@ obj-$(CONFIG_CLKSRC_TI_32K)	+= timer-ti-32k.o
>>   obj-$(CONFIG_CLKSRC_NPS)	+= timer-nps.o
>>   obj-$(CONFIG_OXNAS_RPS_TIMER)	+= timer-oxnas-rps.o
>>   obj-$(CONFIG_OWL_TIMER)		+= timer-owl.o
>> +obj-$(CONFIG_M10V_TIMER)	+= timer-m10v.o
>>   obj-$(CONFIG_SPRD_TIMER)	+= timer-sprd.o
>>   obj-$(CONFIG_NPCM7XX_TIMER)	+= timer-npcm7xx.o
>>   
>> diff --git a/drivers/clocksource/timer-m10v.c b/drivers/clocksource/timer-m10v.c
>> new file mode 100644
>> index 0000000..ff97c23
>> --- /dev/null
>> +++ b/drivers/clocksource/timer-m10v.c
>> @@ -0,0 +1,146 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * Copyright (C) 2018 Socionext Inc.
>> + */
>> +
>> +#include <linux/clk.h>
> ------->
>
>> +#include <linux/clockchips.h>
> It is included from timer-of.h
>
> <-------

OK. Remove it.


>
>> +#include <linux/interrupt.h>
>> +#include <linux/irq.h>
>> +#include <linux/irqreturn.h>
> ------->
>
>> +#include <linux/of.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_irq.h>
>> +#include <linux/slab.h>
> Those are not needed IMO.
>
> <---------

OK, remove these.


>
>
>> +#include "timer-of.h"
>> +
>> +#define FSL_TMR_TMCSR_OFS	0x0
>> +#define FSL_TMR_TMR_OFS		0x4
>> +#define FSL_TMR_TMRLR1_OFS	0x8
>> +#define FSL_TMR_TMRLR2_OFS	0xc
>> +#define FSL_RMT_REGSZPCH	0x10
>> +
>> +#define FSL_TMR_TMCSR_OUTL	BIT(5)
>> +#define FSL_TMR_TMCSR_RELD	BIT(4)
>> +#define FSL_TMR_TMCSR_INTE	BIT(3)
>> +#define FSL_TMR_TMCSR_UF	BIT(2)
>> +#define FSL_TMR_TMCSR_CNTE	BIT(1)
>> +#define FSL_TMR_TMCSR_TRG	BIT(0)
>> +
>> +#define FSL_TMR_TMCSR_CSL_DIV2	0
>> +#define FSL_TMR_TMCSR_CSL	BIT(10)
>> +
>> +#define M10V_TIMER_RATING	500
>> +
>> +static irqreturn_t m10v_timer_interrupt(int irq, void *dev_id)
>> +{
>> +	struct clock_event_device *clk = dev_id;
>> +	struct timer_of *to = to_timer_of(clk);
>> +	u32 val;
>> +
>> +	val = readl_relaxed(timer_of_base(to) + FSL_TMR_TMCSR_OFS);
>> +	val &= ~FSL_TMR_TMCSR_UF;
>> +	writel_relaxed(val, timer_of_base(to) + FSL_TMR_TMCSR_OFS);
>> +
>> +	clk->event_handler(clk);
>> +
>> +	return IRQ_HANDLED;
>> +}
>> +
>> +static int m10v_set_state_periodic(struct clock_event_device *clk)
>> +{
>> +	struct timer_of *to = to_timer_of(clk);
>> +	u32 val = (FSL_TMR_TMCSR_CSL_DIV2 * FSL_TMR_TMCSR_CSL);
> 	FSL_TMR_TMCSR_CSL_DIV2 is zero, so val is always zero.
Ah, yes.
The FSL_TMR_TMCSR is the 10th bit field of the register, so it would be 
better
to bit-shift.
I will use it as simply 0.

> 	
>> +	writel_relaxed(val, timer_of_base(to) + FSL_TMR_TMCSR_OFS);
>> +
>> +	writel_relaxed(to->of_clk.period, timer_of_base(to) +
>> +				FSL_TMR_TMRLR1_OFS);
>> +	val |= FSL_TMR_TMCSR_RELD | FSL_TMR_TMCSR_CNTE |
>> +		FSL_TMR_TMCSR_TRG | FSL_TMR_TMCSR_INTE;
>> +	writel_relaxed(val, timer_of_base(to) + FSL_TMR_TMCSR_OFS);
>> +	return 0;
>> +}
>> +
>> +static int m10v_set_state_oneshot(struct clock_event_device *clk)
>> +{
>> +	struct timer_of *to = to_timer_of(clk);
>> +	u32 val = (FSL_TMR_TMCSR_CSL_DIV2 * FSL_TMR_TMCSR_CSL);
>> +
>> +	writel_relaxed(val, timer_of_base(to) + FSL_TMR_TMCSR_OFS);
>> +	return 0;
>> +}
>> +
>> +static int m10v_clkevt_next_event(unsigned long event,
>> +				   struct clock_event_device *clk)
>> +{
>> +	struct timer_of *to = to_timer_of(clk);
>> +
>> +	writel_relaxed(event, timer_of_base(to) + FSL_TMR_TMRLR1_OFS);
>> +	writel_relaxed((FSL_TMR_TMCSR_CSL_DIV2 * FSL_TMR_TMCSR_CSL) |
> Same comment here.

I got it.


>> +			FSL_TMR_TMCSR_CNTE | FSL_TMR_TMCSR_INTE |
>> +			FSL_TMR_TMCSR_TRG, timer_of_base(to) +
>> +			FSL_TMR_TMCSR_OFS);
>> +	return 0;
>> +}
>> +
>> +static int m10v_config_clock_source(struct timer_of *to)
>> +{
>> +	writel_relaxed(0, timer_of_base(to) + FSL_TMR_TMCSR_OFS);
>> +	writel_relaxed(~0, timer_of_base(to) + FSL_TMR_TMR_OFS);
>> +	writel_relaxed(~0, timer_of_base(to) + FSL_TMR_TMRLR1_OFS);
>> +	writel_relaxed(~0, timer_of_base(to) + FSL_TMR_TMRLR2_OFS);
>> +	writel_relaxed(BIT(4) | BIT(1) | BIT(0), timer_of_base(to) +
>> +		FSL_TMR_TMCSR_OFS);
>> +	return 0;
>> +}
>> +
>> +static int m10v_config_clock_event(struct timer_of *to)
>> +{
>> +	writel_relaxed(0, timer_of_base(to) + FSL_TMR_TMCSR_OFS);
>> +	return 0;
>> +}
>> +
>> +static struct timer_of to = {
>> +	.flags = TIMER_OF_IRQ | TIMER_OF_BASE | TIMER_OF_CLOCK,
>> +
>> +	.clkevt = {
>> +		.name = "m10v-clkevt",
>> +		.rating = M10V_TIMER_RATING,
>> +		.cpumask = cpu_possible_mask,
>> +	},
>> +
>> +	.of_irq = {
>> +		.flags = IRQF_TIMER | IRQF_IRQPOLL,
>> +	},
>> +};
>> +
>> +static int __init m10v_timer_init(struct device_node *node)
>> +{
>> +	int ret;
>> +
>> +	to.clkevt.features = CLOCK_EVT_FEAT_DYNIRQ | CLOCK_EVT_FEAT_ONESHOT;
>> +	to.clkevt.set_state_oneshot = m10v_set_state_oneshot;
>> +	to.clkevt.set_state_periodic = m10v_set_state_periodic;
>> +	to.clkevt.set_next_event = m10v_clkevt_next_event;
>> +	to.of_irq.handler = m10v_timer_interrupt;
> Move the initialization in the timer_of structure above.

Okay.


>
>> +	ret = timer_of_init(node, &to);
>> +	if (ret)
>> +		goto err;
> You should return directly, rollback is done in the timer_of_init().

OK.


>
>> +
>> +	m10v_config_clock_source(&to);
>> +	clocksource_mmio_init(timer_of_base(&to) + FSL_TMR_TMR_OFS,
>> +		node->name, timer_of_rate(&to), M10V_TIMER_RATING, 32,
>> +		clocksource_mmio_readl_down);
> May be you can add the sched_clock also ?

OK. Add it and confirm.


Thanks
Sugaya Taichi


>
>> +	m10v_config_clock_event(&to);
>> +	clockevents_config_and_register(&to.clkevt, timer_of_rate(&to),
>> +				15, 0xffffffff);
>> +
>> +	return 0;
>> +err:
>> +	timer_of_cleanup(&to);
>> +	return ret;
>> +}
>> +TIMER_OF_DECLARE(m10v_peritimer, "socionext,milbeaut-m10v-timer",
>> +		m10v_timer_init);
>>
>

^ permalink raw reply

* [RESEND PATCH] include: Add lantiq.h in include/linux/
From: Songjun Wu @ 2018-11-22  7:47 UTC (permalink / raw)
  To: gregkh; +Cc: linux-serial, Songjun Wu, linux-kernel

In some existing lantiq driver, the C codes include lantiq_soc.h
header file directly.

./arch/mips/include/asm/mach-lantiq/falcon/lantiq_soc.h
./arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h

Those drivers need to be extended to support more platform.
lantiq.h is added in include/linux/ to make it
globally available and provides some wrapper codes.

Signed-off-by: Songjun Wu <songjun.wu@linux.intel.com>
---

 include/linux/lantiq.h | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)
 create mode 100644 include/linux/lantiq.h

diff --git a/include/linux/lantiq.h b/include/linux/lantiq.h
new file mode 100644
index 000000000000..67921169d84d
--- /dev/null
+++ b/include/linux/lantiq.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __LINUX_LANTIQ_H
+#define __LINUX_LANTIQ_H
+
+#ifdef CONFIG_LANTIQ
+#include <lantiq_soc.h>
+#else
+
+#ifndef LTQ_EARLY_ASC
+#define LTQ_EARLY_ASC 0
+#endif
+
+#ifndef CPHYSADDR
+#define CPHYSADDR(a) 0
+#endif
+
+static inline struct clk *clk_get_fpi(void)
+{
+	return NULL;
+}
+#endif /* CONFIG_LANTIQ */
+#endif /* __LINUX_LANTIQ_H */
-- 
2.11.0

^ permalink raw reply related

* Re: [PATCH v2 01/10] mailbox: Support blocking transfers in atomic context
From: Thierry Reding @ 2018-11-22  8:47 UTC (permalink / raw)
  To: Jassi Brar
  Cc: Devicetree List, Greg KH, mliljeberg, Mikko Perttunen, talho,
	linux-serial, jslaby, linux-tegra, ppessi, Jon Hunter,
	linux-arm-kernel
In-Reply-To: <CABb+yY0nH3Su6a11TZLJf=CCpD+gTpqUkLnRhpy4MUwNJk5prw@mail.gmail.com>


[-- Attachment #1.1: Type: text/plain, Size: 5884 bytes --]

On Wed, Nov 21, 2018 at 08:18:22PM -0600, Jassi Brar wrote:
> On Wed, Nov 21, 2018 at 8:27 AM Thierry Reding <thierry.reding@gmail.com> wrote:
> >
> > On Tue, Nov 20, 2018 at 04:29:07PM +0100, Thierry Reding wrote:
> > > On Sat, Nov 17, 2018 at 11:27:17AM -0600, Jassi Brar wrote:
> > > > On Mon, Nov 12, 2018 at 9:18 AM Thierry Reding <thierry.reding@gmail.com> wrote:
> > > > >
> > > > > From: Thierry Reding <treding@nvidia.com>
> > > > >
> > > > > The mailbox framework supports blocking transfers via completions for
> > > > > clients that can sleep. In order to support blocking transfers in cases
> > > > > where the transmission is not permitted to sleep, add a new ->flush()
> > > > > callback that controller drivers can implement to busy loop until the
> > > > > transmission has been completed. This will automatically be called when
> > > > > available and interrupts are disabled for clients that request blocking
> > > > > transfers.
> > > > >
> > > > > Signed-off-by: Thierry Reding <treding@nvidia.com>
> > > > > ---
> > > > >  drivers/mailbox/mailbox.c          | 8 ++++++++
> > > > >  include/linux/mailbox_controller.h | 4 ++++
> > > > >  2 files changed, 12 insertions(+)
> > > > >
> > > > > diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
> > > > > index 674b35f402f5..0eaf21259874 100644
> > > > > --- a/drivers/mailbox/mailbox.c
> > > > > +++ b/drivers/mailbox/mailbox.c
> > > > > @@ -267,6 +267,14 @@ int mbox_send_message(struct mbox_chan *chan, void *mssg)
> > > > >                 unsigned long wait;
> > > > >                 int ret;
> > > > >
> > > > > +               if (irqs_disabled() && chan->mbox->ops->flush) {
> > > > > +                       ret = chan->mbox->ops->flush(chan, chan->cl->tx_tout);
> > > > > +                       if (ret < 0)
> > > > > +                               tx_tick(chan, ret);
> > > > > +
> > > > > +                       return ret;
> > > > > +               }
> > > > > +
> > > > This is hacky. I think we can do without busy waiting in atomic
> > > > context. You could queue locally while in atomic context and then
> > > > transfer in blocking mode. I don't think we should worry about the
> > > > 'throughput' as there already is no h/w rate control even with
> > > > busy-waiting.
> > >
> > > I actually tried to do that before I added this flushing mechanism. The
> > > problem is, like you said, one of rate control. As mentioned in the
> > > cover letter, the shared mailboxes implemented in tegra-hsp are used as
> > > RX and TX channels for the TCU, which is like a virtual UART. The TTY
> > > driver included as part of this series will use one of the mailboxes to
> > > transmit data that is written to the console. The problem is that if
> > > these transmissions are not rate-limited on the TTY driver side, the
> > > console will just keep writing data and eventually overflow the buffer
> > > that we have in the mailbox subsystem.
> > >
> > > The problem is that data comes in at a much higher rate than what we can
> > > output. This is especially true at boot when the TCU console takes over
> > > and the whole log buffer is dumped on it.
> > >
> > > So the only way to rate-limit is to either make mbox_send_message()
> > > block, but that can only be done in non-atomic context. The console,
> > > however, will always run in atomic context, so the only way to do rate-
> > > limiting is by busy looping.
> >
> > What I also tried before was to implement busy looping within the
> > ->send_data() callback of the driver so that we didn't have to put this
> > into the core. Unfortunately, however, the ->send_data() callback is
> > called under chan->lock, which means that from mbox_send_message() we
> > don't have a way to mark the transfer as done. In order to do that we'd
> > have to call mbox_chan_txdone(), but that ends up calling tx_tick() and
> > that in turn also attempts to take the chan->lock, which would cause a
> > deadlock.
> >
> > The explicit flushing is the best alternative that I could come up with.
> > I think it's not all that hacky, because it's very explicit about what's
> > going on and it has the nice side-effect that it will allow the mailbox
> > to work in interrupt driven mode if possible and only resorting to the
> > busy loop in atomic context.
> >
> > At this point I think I have explored all other options and I frankly
> > can't find a more proper way to achieve what we need here. Perhaps you
> > can think of additional ways to accomplish this?
> >
> Well, I would have a local ring buffer (array) of enough size to hold
> the characters and then have a task consuming data from that ring
> buffer by transmitting over mailbox.

There's already such a ringbuffer in the printk code. To implement what
you suggest would effectively be creating a copy of that buffer because
we'd be allocating the buffer and the console code would just dump each
and every character in the logbuf into that ring buffer without rate-
limitation.

To make matters worse, the ringbuffer would be empty most of the time
after the initial dump of the logbuf, so we'd be wasting all that buffer
space.

It just seems to me like we should be keeping the TCU driver as close as
possible to other UART drivers which also busy loop in order to rate-
limit what the console can write. Given the current mailbox framework it
is not possible to do that (in interrupt context), so an extension seems
like the most sensible option.

Perhaps you'd be less concerned about such a change if it was perhaps
more explicit? Just throwing ideas around, I think something that could
also work is if we explicitly add a mbox_flush() function that would
basically be calling ->flush(). That way users of the mailbox can make
their requirement very explicit. I haven't actually tested that, but I
think it would work. Does that sound more acceptable to you?

Thierry

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

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

^ permalink raw reply

* [PATCH] tty: do not set TTY_IO_ERROR flag if console port
From: Chanho Park @ 2018-11-22  9:23 UTC (permalink / raw)
  To: gregkh, jslaby, linux-kernel, linux-serial
  Cc: Chanho Park, Geert Uytterhoeven, Rob Herring

Since Commit 761ed4a94582 ('tty: serial_core: convert uart_close to use
tty_port_close') and Commit 4dda864d7307 ('tty: serial_core: Fix serial
console crash on port shutdown), a serial port which is used as
console can be stuck when logging out if there is a remained process.
After logged out, agetty will try to grab the serial port but it will
be failed because the previous process did not release the port
correctly. To fix this, TTY_IO_ERROR bit should not be enabled of
tty_port_close if the port is console port.

Reproduce step:
- Run background processes from serial console
$ while true; do sleep 10; done &

- Log out
$ logout
-> Stuck

- Read journal log by journalctl | tail
Jan 28 16:07:01 ubuntu systemd[1]: Stopped Serial Getty on ttyAMA0.
Jan 28 16:07:01 ubuntu systemd[1]: Started Serial Getty on ttyAMA0.
Jan 28 16:07:02 ubuntu agetty[1643]: /dev/ttyAMA0: not a tty

Fixes: 761ed4a94582ab29 ("tty: serial_core: convert uart_close to use tty_port_close")

Cc: Geert Uytterhoeven <geert+renesas@glider.be>
Cc: Rob Herring <robh@kernel.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Jiri Slaby <jslaby@suse.com>
Signed-off-by: Chanho Park <parkch98@gmail.com>
---
 drivers/tty/tty_port.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c
index cb60750..044c3cb 100644
--- a/drivers/tty/tty_port.c
+++ b/drivers/tty/tty_port.c
@@ -633,7 +633,8 @@ void tty_port_close(struct tty_port *port, struct tty_struct *tty,
 	if (tty_port_close_start(port, tty, filp) == 0)
 		return;
 	tty_port_shutdown(port, tty);
-	set_bit(TTY_IO_ERROR, &tty->flags);
+	if (!port->console)
+		set_bit(TTY_IO_ERROR, &tty->flags);
 	tty_port_close_end(port, tty);
 	tty_port_tty_set(port, NULL);
 }
-- 
1.9.1

^ permalink raw reply related

* Re: [PATCH v2 14/15] tty: serial: Add RDA8810PL UART driver
From: Greg KH @ 2018-11-22 10:09 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: olof, arnd, robh+dt, tglx, jason, marc.zyngier, daniel.lezcano,
	jslaby, afaerber, linux-arm-kernel, linux-kernel, devicetree,
	linux-serial, amit.kucheria, linus.walleij, zhao_steven,
	overseas.sales
In-Reply-To: <20181121033652.12247-15-manivannan.sadhasivam@linaro.org>

On Wed, Nov 21, 2018 at 09:06:51AM +0530, Manivannan Sadhasivam wrote:
> Add UART driver for RDA Micro RDA8810PL SoC.
> 
> Signed-off-by: Andreas Färber <afaerber@suse.de>
> Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>

Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

^ permalink raw reply

* Re: [PATCHv3] panic: avoid deadlocks in re-entrant console drivers
From: Petr Mladek @ 2018-11-22 13:12 UTC (permalink / raw)
  To: Sergey Senozhatsky
  Cc: linux-kernel, Steven Rostedt, Daniel Wang, Peter Zijlstra,
	Andrew Morton, Linus Torvalds, Greg Kroah-Hartman, Alan Cox,
	Jiri Slaby, Peter Feiner, linux-serial, Sergey Senozhatsky
In-Reply-To: <20181101080808.n73lrlnjd65nk4qf@pathway.suse.cz>

On Thu 2018-11-01 09:08:08, Petr Mladek wrote:
> On Thu 2018-11-01 10:48:21, Sergey Senozhatsky wrote:
> > On (10/31/18 13:27), Petr Mladek wrote:
> > > > 
> > > > Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
> > > 
> > > The patch makes sense to me. The locks should stay busted also for
> > > console_flush_on_panic().
> > > 
> > > With the added #include <linux/vt_kern.h>:
> > > 
> > > Reviewed-by: Petr Mladek <pmladek@suse.com>
> > 
> > Thanks!
> > 
> > Since there are no objections - how shall we route it? Via printk tree?
> 
> Good question. OK, I am going to put it into printk.git unless I hear
> complains withing next couple of days.

I have pushed this into printk.git, branch for-4.21.

Best Regards,
Petr

^ permalink raw reply


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