linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/10] ARM: NUC900: Add NUC970 SoC support
@ 2016-07-10  7:27 Wan Zongshun
  2016-07-10  7:27 ` [PATCH v2 01/10] ARM: NUC900: Add nuc970 machine support Wan Zongshun
                   ` (6 more replies)
  0 siblings, 7 replies; 45+ messages in thread
From: Wan Zongshun @ 2016-07-10  7:27 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

This patch series added Nuvoton new SoC NUC970 development board
support, this nuc970 belongs to nuc900 series, but many features are
not compatible with old nuc900 SoCs like nuc910, nuc920.

Those patches are basing on old w90x900 codes, and are using standard
linux subsystem interface, such as dts, driver/clk, driver/clocksource
, driver/irqchip drivers.

The old w90x900 plat such as nuc910,nuc960 codes will also be changed
to new style according to nuc970 codes after those patches was accepted.

PATCH V2:
The V2 patches change some code style, re-archtect some drivers and add reset
and soc drivers, split some dts patches according to maillist's comments.

Wan Zongshun (10):
  ARM: NUC900: Add nuc970 machine support
  irqchip: add irqchip driver for nuc900
  Clocksource: add nuc970 clocksource driver
  clk: add Clock driver for nuc970
  power/reset: Add reset driver support for nuc900
  soc: Add SoC specific driver support for nuc900
  ARM: dts: Add clock header file into dt-bindings
  ARM: dts: nuc900: Add nuc970 dts files
  Documentation: devicetree: Add dts description for nuc900
  nuc900: add nuc970 platform defconfig file

 .../devicetree/bindings/arm/nuvoton/nuc970.txt     |  12 +
 .../bindings/clock/nuvoton,nuc970-clk.txt          |  13 +
 .../interrupt-controller/nuvoton,nuc900-aic.txt    |  15 +
 .../bindings/reset/nuvoton,nuc900-reset.txt        |  12 +
 .../devicetree/bindings/serial/nuc970-uart.txt     |  22 +
 .../bindings/soc/nuvoton/nuvoton,nuc900-soc.txt    |  12 +
 .../bindings/timer/nuvoton,nuc970-tmr.txt          |  20 +
 arch/arm/boot/dts/Makefile                         |   1 +
 arch/arm/boot/dts/nuc970-evb.dts                   |  34 +
 arch/arm/boot/dts/nuc970.dtsi                      |  88 ++
 arch/arm/configs/nuc970_defconfig                  |  76 ++
 arch/arm/mach-w90x900/Kconfig                      |  20 +
 arch/arm/mach-w90x900/Makefile                     |   3 +
 arch/arm/mach-w90x900/include/mach/irqs.h          |   5 +
 arch/arm/mach-w90x900/nuc900.c                     |  41 +
 drivers/clk/Makefile                               |   1 +
 drivers/clk/nuc900/Makefile                        |   6 +
 drivers/clk/nuc900/clk-apll.c                      | 168 ++++
 drivers/clk/nuc900/clk-ccf.h                       |  53 ++
 drivers/clk/nuc900/clk-nuc970.c                    | 925 +++++++++++++++++++++
 drivers/clk/nuc900/clk-upll.c                      |  83 ++
 drivers/clocksource/Kconfig                        |   8 +
 drivers/clocksource/Makefile                       |   1 +
 drivers/clocksource/timer-nuc900.c                 | 305 +++++++
 drivers/irqchip/Makefile                           |   1 +
 drivers/irqchip/irq-nuc900.c                       | 150 ++++
 drivers/power/reset/Kconfig                        |   7 +
 drivers/power/reset/Makefile                       |   1 +
 drivers/power/reset/nuc900-reset.c                 |  93 +++
 drivers/soc/Kconfig                                |   1 +
 drivers/soc/Makefile                               |   1 +
 drivers/soc/nuvoton/Kconfig                        |  10 +
 drivers/soc/nuvoton/Makefile                       |   1 +
 drivers/soc/nuvoton/soc-nuc900.c                   | 100 +++
 include/dt-bindings/clock/nuc970-clock.h           | 233 ++++++
 35 files changed, 2522 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/arm/nuvoton/nuc970.txt
 create mode 100644 Documentation/devicetree/bindings/clock/nuvoton,nuc970-clk.txt
 create mode 100644 Documentation/devicetree/bindings/interrupt-controller/nuvoton,nuc900-aic.txt
 create mode 100644 Documentation/devicetree/bindings/reset/nuvoton,nuc900-reset.txt
 create mode 100644 Documentation/devicetree/bindings/serial/nuc970-uart.txt
 create mode 100644 Documentation/devicetree/bindings/soc/nuvoton/nuvoton,nuc900-soc.txt
 create mode 100644 Documentation/devicetree/bindings/timer/nuvoton,nuc970-tmr.txt
 create mode 100644 arch/arm/boot/dts/nuc970-evb.dts
 create mode 100644 arch/arm/boot/dts/nuc970.dtsi
 create mode 100644 arch/arm/configs/nuc970_defconfig
 create mode 100644 arch/arm/mach-w90x900/nuc900.c
 create mode 100644 drivers/clk/nuc900/Makefile
 create mode 100644 drivers/clk/nuc900/clk-apll.c
 create mode 100644 drivers/clk/nuc900/clk-ccf.h
 create mode 100644 drivers/clk/nuc900/clk-nuc970.c
 create mode 100644 drivers/clk/nuc900/clk-upll.c
 create mode 100644 drivers/clocksource/timer-nuc900.c
 create mode 100644 drivers/irqchip/irq-nuc900.c
 create mode 100644 drivers/power/reset/nuc900-reset.c
 create mode 100644 drivers/soc/nuvoton/Kconfig
 create mode 100644 drivers/soc/nuvoton/Makefile
 create mode 100644 drivers/soc/nuvoton/soc-nuc900.c
 create mode 100644 include/dt-bindings/clock/nuc970-clock.h

-- 
2.7.4

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

* [PATCH v2 01/10] ARM: NUC900: Add nuc970 machine support
  2016-07-10  7:27 [PATCH v2 00/10] ARM: NUC900: Add NUC970 SoC support Wan Zongshun
@ 2016-07-10  7:27 ` Wan Zongshun
  2016-07-10 22:11   ` Arnd Bergmann
  2016-07-11 16:04   ` Arnd Bergmann
  2016-07-10  7:27 ` [PATCH v2 02/10] irqchip: add irqchip driver for nuc900 Wan Zongshun
                   ` (5 subsequent siblings)
  6 siblings, 2 replies; 45+ messages in thread
From: Wan Zongshun @ 2016-07-10  7:27 UTC (permalink / raw)
  To: linux-arm-kernel

NUC970 is a new SoC of Nuvoton nuc900 series, this patch is
to add machine file support for it.

Signed-off-by: Wan Zongshun <mcuos.com@gmail.com>
---
 arch/arm/mach-w90x900/Kconfig  | 20 ++++++++++++++++++++
 arch/arm/mach-w90x900/Makefile |  3 +++
 arch/arm/mach-w90x900/nuc900.c | 41 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 64 insertions(+)
 create mode 100644 arch/arm/mach-w90x900/nuc900.c

diff --git a/arch/arm/mach-w90x900/Kconfig b/arch/arm/mach-w90x900/Kconfig
index 69bab32..80ab00c 100644
--- a/arch/arm/mach-w90x900/Kconfig
+++ b/arch/arm/mach-w90x900/Kconfig
@@ -15,6 +15,26 @@ config CPU_NUC960
 	help
 	  Support for NUCP960 of Nuvoton NUC900 CPUs.
 
+config SOC_NUC970
+	bool "Nuvoton NUC970 SoC support"
+	select COMMON_CLK
+	select GENERIC_IRQ_CHIP
+	select HAVE_CLK_PREPARE
+	select IRQ_DOMAIN
+	select MULTI_IRQ_HANDLER
+	select MFD_SYSCON
+	select NUC900_TIMER
+	select SOC_NUC900
+	select USE_OF
+	help
+	  Support for NUC970 of Nuvoton NUC900 SoCs.
+	  The NUC970 series runs up to 300 MHz, with 16 KB I-cache,
+	  16 KB D-cache and MMU, 56KB embedded SRAM and 16 KB Internal
+	  Boot ROM for booting from USB, NAND and SPI FLASH.
+	  Detailed information please check the following link:
+	  https://github.com/zswan/nuc900-document/blob/master/
+	  NUC970_TechnicalReferenceManual_EN_Rev1.30.pdf
+
 menu "W90P910 Machines"
 
 config MACH_W90P910EVB
diff --git a/arch/arm/mach-w90x900/Makefile b/arch/arm/mach-w90x900/Makefile
index 828c032..d13ba5a 100644
--- a/arch/arm/mach-w90x900/Makefile
+++ b/arch/arm/mach-w90x900/Makefile
@@ -4,8 +4,10 @@
 
 # Object file lists.
 
+ifeq ($(CONFIG_SOC_NUC970),)
 obj-y				:= irq.o time.o mfp.o gpio.o clock.o
 obj-y				+= clksel.o dev.o cpu.o
+endif
 # W90X900 CPU support files
 
 obj-$(CONFIG_CPU_W90P910)	+= nuc910.o
@@ -17,3 +19,4 @@ obj-$(CONFIG_CPU_NUC960)	+= nuc960.o
 obj-$(CONFIG_MACH_W90P910EVB)	+= mach-nuc910evb.o
 obj-$(CONFIG_MACH_W90P950EVB)	+= mach-nuc950evb.o
 obj-$(CONFIG_MACH_W90N960EVB)	+= mach-nuc960evb.o
+obj-$(CONFIG_SOC_NUC970)	+= nuc900.o
diff --git a/arch/arm/mach-w90x900/nuc900.c b/arch/arm/mach-w90x900/nuc900.c
new file mode 100644
index 0000000..309c332
--- /dev/null
+++ b/arch/arm/mach-w90x900/nuc900.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2016 Wan Zongshun <mcuos.com@gmail.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/reboot.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/sys_soc.h>
+#include <linux/semaphore.h>
+
+#include <asm/system_misc.h>
+#include <asm/mach/arch.h>
+
+static void __init nuc900_machine_init(void)
+{
+	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+}
+
+static const char *nuc900_dt_compat[] __initconst = {
+	"nuvoton,nuc970",
+	NULL,
+};
+
+DT_MACHINE_START(nuc900_dt, "Nuvoton NUC900 (Device Tree Support)")
+	.init_machine	= nuc900_machine_init,
+	.dt_compat	= nuc900_dt_compat,
+MACHINE_END
-- 
2.7.4

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

* [PATCH v2 02/10] irqchip: add irqchip driver for nuc900
  2016-07-10  7:27 [PATCH v2 00/10] ARM: NUC900: Add NUC970 SoC support Wan Zongshun
  2016-07-10  7:27 ` [PATCH v2 01/10] ARM: NUC900: Add nuc970 machine support Wan Zongshun
@ 2016-07-10  7:27 ` Wan Zongshun
  2016-07-10 21:51   ` Paul Gortmaker
                     ` (2 more replies)
  2016-07-10  7:27 ` [PATCH v2 03/10] Clocksource: add nuc970 clocksource driver Wan Zongshun
                   ` (4 subsequent siblings)
  6 siblings, 3 replies; 45+ messages in thread
From: Wan Zongshun @ 2016-07-10  7:27 UTC (permalink / raw)
  To: linux-arm-kernel

This patch is to add irqchip driver support for nuc900 plat,
current this driver only supports nuc970 SoC.

Signed-off-by: Wan Zongshun <mcuos.com@gmail.com>
---
 arch/arm/mach-w90x900/include/mach/irqs.h |   5 +
 drivers/irqchip/Makefile                  |   1 +
 drivers/irqchip/irq-nuc900.c              | 150 ++++++++++++++++++++++++++++++
 3 files changed, 156 insertions(+)
 create mode 100644 drivers/irqchip/irq-nuc900.c

diff --git a/arch/arm/mach-w90x900/include/mach/irqs.h b/arch/arm/mach-w90x900/include/mach/irqs.h
index 9d5cba3..3b035c6 100644
--- a/arch/arm/mach-w90x900/include/mach/irqs.h
+++ b/arch/arm/mach-w90x900/include/mach/irqs.h
@@ -59,7 +59,12 @@
 #define IRQ_KPI		W90X900_IRQ(29)
 #define IRQ_P2SGROUP	W90X900_IRQ(30)
 #define IRQ_ADC		W90X900_IRQ(31)
+
+#if !defined(CONFIG_SOC_NUC900)
 #define NR_IRQS		(IRQ_ADC+1)
+#else
+#define NR_IRQS		62
+#endif
 
 /*for irq group*/
 
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 38853a1..9ccd5af8a 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -69,3 +69,4 @@ obj-$(CONFIG_PIC32_EVIC)		+= irq-pic32-evic.o
 obj-$(CONFIG_MVEBU_ODMI)		+= irq-mvebu-odmi.o
 obj-$(CONFIG_LS_SCFG_MSI)		+= irq-ls-scfg-msi.o
 obj-$(CONFIG_EZNPS_GIC)			+= irq-eznps.o
+obj-$(CONFIG_SOC_NUC970)		+= irq-nuc900.o
diff --git a/drivers/irqchip/irq-nuc900.c b/drivers/irqchip/irq-nuc900.c
new file mode 100644
index 0000000..c4b2e39
--- /dev/null
+++ b/drivers/irqchip/irq-nuc900.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2016 Wan Zongshun <mcuos.com@gmail.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/irqchip.h>
+#include <linux/irqdomain.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#include <asm/exception.h>
+#include <asm/hardirq.h>
+
+#define	REG_AIC_SCR1	0x00
+#define	REG_AIC_SCR2	0x04
+#define	REG_AIC_SCR3	0x08
+#define	REG_AIC_SCR4	0x0C
+#define	REG_AIC_SCR5	0x10
+#define	REG_AIC_SCR6	0x14
+#define	REG_AIC_SCR7	0x18
+#define	REG_AIC_SCR8	0x1C
+#define	REG_AIC_SCR9	0x20
+#define	REG_AIC_SCR10	0x24
+#define	REG_AIC_SCR11	0x28
+#define	REG_AIC_SCR12	0x2C
+#define	REG_AIC_SCR13	0x30
+#define	REG_AIC_SCR14	0x34
+#define	REG_AIC_SCR15	0x38
+#define	REG_AIC_IRSR	0x100
+#define	REG_AIC_IRSRH	0x104
+#define	REG_AIC_IASR	0x108
+#define	REG_AIC_IASRH	0x10C
+#define	REG_AIC_ISR	0x110
+#define	REG_AIC_ISRH	0x114
+#define	REG_AIC_IPER	0x118
+#define	REG_AIC_ISNR	0x120
+#define	REG_AIC_OISR	0x124
+#define	REG_AIC_IMR	0x128
+#define	REG_AIC_IMRH	0x12C
+#define	REG_AIC_MECR	0x130
+#define	REG_AIC_MECRH	0x134
+#define	REG_AIC_MDCR	0x138
+#define	REG_AIC_MDCRH	0x13C
+#define	REG_AIC_SSCR	0x140
+#define	REG_AIC_SSCRH	0x144
+#define	REG_AIC_SCCR	0x148
+#define	REG_AIC_SCCRH	0x14C
+#define	REG_AIC_EOSCR	0x150
+
+static void __iomem *aic_base;
+static struct irq_domain *aic_domain;
+
+static void nuc900_irq_mask(struct irq_data *d)
+{
+	if (d->irq < 32)
+		writel(1 << (d->irq), aic_base + REG_AIC_MDCR);
+	else
+		writel(1 << (d->irq - 32), aic_base + REG_AIC_MDCRH);
+}
+
+static void nuc900_irq_ack(struct irq_data *d)
+{
+	writel(0x01, aic_base + REG_AIC_EOSCR);
+}
+
+static void nuc900_irq_unmask(struct irq_data *d)
+{
+	if (d->irq < 32)
+		writel(1 << (d->irq), aic_base + REG_AIC_MECR);
+	else
+		writel(1 << (d->irq - 32), aic_base + REG_AIC_MECRH);
+}
+
+static struct irq_chip nuc900_irq_chip = {
+	.irq_ack	= nuc900_irq_ack,
+	.irq_mask	= nuc900_irq_mask,
+	.irq_unmask	= nuc900_irq_unmask,
+};
+
+void __exception_irq_entry aic_handle_irq(struct pt_regs *regs)
+{
+	u32 hwirq;
+
+	hwirq = readl(aic_base + REG_AIC_IPER);
+	hwirq = readl(aic_base + REG_AIC_ISNR);
+	if (!hwirq)
+		writel(0x01, aic_base + REG_AIC_EOSCR);
+
+	handle_IRQ((irq_find_mapping(aic_domain, hwirq)), regs);
+}
+
+static int aic_irq_domain_map(struct irq_domain *d, unsigned int virq,
+			      irq_hw_number_t hw)
+{
+	irq_set_chip_and_handler(virq, &nuc900_irq_chip, handle_level_irq);
+	irq_clear_status_flags(virq, IRQ_NOREQUEST);
+
+	return 0;
+}
+
+static struct irq_domain_ops aic_irq_domain_ops = {
+	.map = aic_irq_domain_map,
+	.xlate = irq_domain_xlate_onecell,
+};
+
+static int __init aic_of_init(struct device_node *node,
+			      struct device_node *parent)
+{
+	int ret;
+
+	aic_base = of_iomap(node, 0);
+	if (!aic_base) {
+		ret = -ENOMEM;
+		pr_err("%s: unable to map registers\n", node->full_name);
+		goto err_iomap;
+	}
+
+	writel(0xFFFFFFFC, aic_base + REG_AIC_MDCR);
+	writel(0xFFFFFFFF, aic_base + REG_AIC_MDCRH);
+
+	aic_domain = irq_domain_add_linear(node, NR_IRQS,
+					   &aic_irq_domain_ops, NULL);
+
+	if (!aic_domain) {
+		ret = -ENOMEM;
+		pr_err("%s: unable to create IRQ domain\n", node->full_name);
+		goto err_aic_domain;
+	}
+
+	set_handle_irq(aic_handle_irq);
+	return 0;
+
+err_aic_domain:
+	iounmap(aic_base);
+err_iomap:
+	return ret;
+}
+
+IRQCHIP_DECLARE(nuc900, "nuvoton,nuc900-aic", aic_of_init);
-- 
2.7.4

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

* [PATCH v2 03/10] Clocksource: add nuc970 clocksource driver
  2016-07-10  7:27 [PATCH v2 00/10] ARM: NUC900: Add NUC970 SoC support Wan Zongshun
  2016-07-10  7:27 ` [PATCH v2 01/10] ARM: NUC900: Add nuc970 machine support Wan Zongshun
  2016-07-10  7:27 ` [PATCH v2 02/10] irqchip: add irqchip driver for nuc900 Wan Zongshun
@ 2016-07-10  7:27 ` Wan Zongshun
  2016-07-11 15:36   ` Arnd Bergmann
  2016-07-10  7:27 ` [PATCH v2 04/10] clk: add Clock driver for nuc970 Wan Zongshun
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 45+ messages in thread
From: Wan Zongshun @ 2016-07-10  7:27 UTC (permalink / raw)
  To: linux-arm-kernel

This patch is to add nuc970 clocksource driver support.

NUC970 general timer controller includes five channels, TIMER0, TIMER1,
TIMER2, TIMER3, and TIMER4, which allow user to easily implement a
counting scheme or timing control for applications.The timer possesses
features such as adjustable resolution, and programmable counting period.
The timer can generate an interrupt signal upon timeout, or provide the
current value of count during operation.

Currently, we are using TIMER0 and TIMER1 for clocksource and clockevent
device driver support.

Signed-off-by: Wan Zongshun <mcuos.com@gmail.com>
---
 drivers/clocksource/Kconfig        |   8 +
 drivers/clocksource/Makefile       |   1 +
 drivers/clocksource/timer-nuc900.c | 305 +++++++++++++++++++++++++++++++++++++
 3 files changed, 314 insertions(+)
 create mode 100644 drivers/clocksource/timer-nuc900.c

diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 47352d2..441c5ee 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -427,4 +427,12 @@ config CLKSRC_ST_LPC
 	  Enable this option to use the Low Power controller timer
 	  as clocksource.
 
+config NUC900_TIMER
+        bool "Clocksource timer for nuc900 platform" if COMPILE_TEST
+        depends on ARM
+        select CLKSRC_OF if OF
+        select CLKSRC_MMIO
+        help
+          Enables the clocksource for the NUC900 platform.
+
 endmenu
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 473974f..c74e252 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -67,3 +67,4 @@ obj-$(CONFIG_H8300_TMR16)		+= h8300_timer16.o
 obj-$(CONFIG_H8300_TPU)			+= h8300_tpu.o
 obj-$(CONFIG_CLKSRC_ST_LPC)		+= clksrc_st_lpc.o
 obj-$(CONFIG_X86_NUMACHIP)		+= numachip.o
+obj-$(CONFIG_NUC900_TIMER)		+= timer-nuc900.o
diff --git a/drivers/clocksource/timer-nuc900.c b/drivers/clocksource/timer-nuc900.c
new file mode 100644
index 0000000..28ccbcf
--- /dev/null
+++ b/drivers/clocksource/timer-nuc900.c
@@ -0,0 +1,305 @@
+/*
+ * Copyright 2016 Wan Zongshun <mcuos.com@gmail.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/clockchips.h>
+#include <linux/types.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+
+#include <linux/io.h>
+#include <asm/mach/time.h>
+
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#define TMR_TCSR0	0x00
+#define TMR_TICR0	0x04
+#define TMR_TDR0	0x08
+#define TMR_TCSR1	0x10
+#define TMR_TICR1	0x14
+#define TMR_TDR1	0x18
+#define TMR_TISR	0x60
+
+#define RESETINT	0x1f
+#define PERIODIC	(0x01 << 27)
+#define ONESHOT		(0x00 << 27)
+#define COUNTEN		(0x01 << 30)
+#define INTEN		(0x01 << 29)
+
+#define TICKS_PER_SEC	100
+/* Divider = prescale + 1 */
+#define PRESCALE	0x63
+
+#define	TDR_SHIFT	24
+#define	TDR_MASK	((1 << TDR_SHIFT) - 1)
+#define OPMODE_MASK	~(0x03 << 27)
+
+struct nuc970_clockevents {
+	struct clock_event_device clkevt;
+	unsigned int timer0_load;
+	void __iomem *base;
+};
+
+struct nuc970_clockevents *clkevt_to_nuc970(struct clock_event_device *clk)
+{
+	return container_of(clk, struct nuc970_clockevents, clkevt);
+}
+
+static int nuc970_clockevent_set(bool periodic, struct clock_event_device *clk)
+{
+	struct nuc970_clockevents *evt = clkevt_to_nuc970(clk);
+	unsigned int val;
+
+	val = readl(evt->base + TMR_TCSR0);
+	val &= OPMODE_MASK;
+
+	writel(evt->timer0_load, evt->base + TMR_TICR0);
+
+	val |= periodic ? PERIODIC:ONESHOT;
+	val |= (COUNTEN | INTEN | PRESCALE);
+
+	writel(val, evt->base + TMR_TCSR0);
+
+	return 0;
+}
+
+
+static int nuc970_clockevent_set_oneshot(struct clock_event_device *clk)
+{
+	nuc970_clockevent_set(0, clk);
+	return 0;
+}
+
+static int nuc970_clockevent_set_periodic(struct clock_event_device *clk)
+{
+	nuc970_clockevent_set(1, clk);
+	return 0;
+}
+
+static int nuc970_clockevent_setnextevent(unsigned long evtval,
+					  struct clock_event_device *clk)
+{
+	struct nuc970_clockevents *evt = clkevt_to_nuc970(clk);
+	unsigned int tcsr, tdelta;
+
+	tcsr = readl(evt->base + TMR_TCSR0);
+	tdelta = readl(evt->base + TMR_TICR0) - readl(evt->base + TMR_TDR0);
+
+	writel(evtval, evt->base + TMR_TICR0);
+
+	if (!(tcsr & COUNTEN) && ((tdelta > 2) || (tdelta == 0)))
+		writel(readl(evt->base + TMR_TCSR0) | COUNTEN,
+			     evt->base + TMR_TCSR0);
+
+	return 0;
+}
+
+static int nuc970_clockevent_shutdown(struct clock_event_device *clk)
+{
+	struct nuc970_clockevents *evt = clkevt_to_nuc970(clk);
+	unsigned int val = readl(evt->base + TMR_TCSR0) & ~(0x03 << 27);
+
+	writel(val, evt->base + TMR_TCSR0);
+
+	return 0;
+}
+
+/*IRQ handler for the timer*/
+static irqreturn_t nuc970_timer0_interrupt(int irq, void *dev_id)
+{
+	struct nuc970_clockevents *evt = dev_id;
+	struct clock_event_device *clk = &(evt->clkevt);
+
+	writel(0x01, evt->base + TMR_TISR);
+
+	clk->event_handler(clk);
+
+	return IRQ_HANDLED;
+}
+
+static int clock_event_device_init(struct clock_event_device *clk,
+				   unsigned int rate)
+{
+	clk->name = "nuc970-timer0";
+	clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
+	clk->set_state_shutdown = nuc970_clockevent_shutdown;
+	clk->set_state_periodic = nuc970_clockevent_set_periodic;
+	clk->set_state_oneshot = nuc970_clockevent_set_oneshot;
+	clk->set_state_oneshot_stopped = nuc970_clockevent_shutdown;
+	clk->set_next_event = nuc970_clockevent_setnextevent;
+	clk->cpumask = cpumask_of(0);
+	clk->rating = 300;
+
+	clockevents_config_and_register(clk, rate, 0xf, 0xffffffff);
+	return 0;
+}
+
+static int __init nuc970_clkevt_init(struct nuc970_clockevents *evt,
+				     int irq, struct clk *clk_timer0)
+{
+	unsigned int rate = 0;
+	int ret;
+
+	/*Clockevents init*/
+	ret = clk_prepare_enable(clk_timer0);
+	if (ret) {
+		pr_err("Failed to enable clk_timer0 clock :%d.\n", ret);
+		goto err_clk_prepare_enable;
+	}
+
+	writel(0x00, evt->base + TMR_TCSR0);
+
+	rate = clk_get_rate(clk_timer0);
+	if (!rate) {
+		pr_err("Failed to get clk_timer0 rate :%d.\n", rate);
+		ret = -EINVAL;
+		goto err_clk_get_rate;
+	}
+
+	rate /= (PRESCALE + 1);
+
+	evt->timer0_load = (rate / TICKS_PER_SEC);
+
+	writel(RESETINT, evt->base + TMR_TISR);
+
+	clock_event_device_init(&(evt->clkevt), rate);
+
+	ret = request_irq(irq, nuc970_timer0_interrupt,
+			  IRQF_TIMER | IRQF_IRQPOLL, "nuc970-timer0", evt);
+	if (ret) {
+		pr_err("Failed to request irq :%d, return: %d.\n", irq, ret);
+		goto err_clk_get_rate;
+	}
+
+	return 0;
+
+err_clk_get_rate:
+	clk_disable_unprepare(clk_timer0);
+err_clk_prepare_enable:
+	return ret;
+}
+
+static int __init nuc970_clksrc_init(struct nuc970_clockevents *evt,
+				     struct clk *clk_timer1)
+{
+	unsigned int val, rate = 0;
+	int ret;
+
+	/*Clocksource init*/
+	ret = clk_prepare_enable(clk_timer1);
+	if (ret) {
+		pr_err("Failed to enable clk_timer1 clock :%d.\n", ret);
+		goto err_clk_prepare_enable;
+	}
+
+	writel(0x00, evt->base + TMR_TCSR1);
+
+	rate = clk_get_rate(clk_timer1);
+	if (!rate) {
+		pr_err("Failed to get clk_timer1 rate :%d.\n", rate);
+		ret = -EINVAL;
+		goto err_clk_get_rate;
+	}
+
+	rate /= (PRESCALE + 1);
+
+	writel(0xffffffff, evt->base + TMR_TICR1);
+
+	val = readl(evt->base + TMR_TCSR1);
+	val |= (COUNTEN | PERIODIC  | PRESCALE);
+	writel(val, evt->base + TMR_TCSR1);
+
+	ret = clocksource_mmio_init(evt->base + TMR_TDR1, "nuc970-timer1",
+			      rate, 200, TDR_SHIFT,
+			      clocksource_mmio_readl_down);
+	if (ret) {
+		pr_err("nuc970-timer1: can't register clocksource\n");
+		goto err_clk_get_rate;
+	}
+
+	return 0;
+
+err_clk_get_rate:
+	clk_disable_unprepare(clk_timer1);
+err_clk_prepare_enable:
+	return ret;
+
+}
+
+static void __init nuc970_timer_of_init(struct device_node *node)
+{
+	struct nuc970_clockevents *nuc970_evt;
+	struct clk *clk_timer0, *clk_timer1;
+	int irq, ret;
+
+	nuc970_evt = kzalloc(sizeof(struct nuc970_clockevents), GFP_KERNEL);
+	if (!nuc970_evt) {
+		ret = -ENOMEM;
+		pr_err("%s: Failed to kzalloc memory\n", node->full_name);
+		goto err_alloc_mem;
+	}
+
+	nuc970_evt->base = of_iomap(node, 0);
+	if (!nuc970_evt->base) {
+		ret = -ENOMEM;
+		pr_err("%s: Unable to map timer base\n", node->full_name);
+		goto err_iomap;
+	}
+
+	clk_timer0 = of_clk_get_by_name(node, "timer0");
+	if (IS_ERR(clk_timer0)) {
+		ret = PTR_ERR(clk_timer0);
+		pr_err("%s: Unable to get clk_timer0\n", node->full_name);
+		goto err_get_clk;
+	}
+
+	clk_timer1 = of_clk_get_by_name(node, "timer1");
+	if (IS_ERR(clk_timer1)) {
+		ret = PTR_ERR(clk_timer1);
+		pr_err("%s: Unable to get clk_timer1\n", node->full_name);
+		goto err_get_clk;
+	}
+
+	irq = irq_of_parse_and_map(node, 0);
+	if (irq <= 0) {
+		ret = irq;
+		pr_err("%s: Unable to get irq\n", node->full_name);
+		goto err_get_clk;
+	}
+
+	ret = nuc970_clksrc_init(nuc970_evt, clk_timer1);
+	if (ret) {
+		pr_err("Failed to init clock source :%d.\n", ret);
+		goto err_get_clk;
+	}
+
+	nuc970_clkevt_init(nuc970_evt, irq, clk_timer0);
+	if (ret) {
+		pr_err("Failed to init clock event device :%d.\n", ret);
+		goto err_get_clk;
+	}
+
+	return;
+
+err_get_clk:
+	iounmap(nuc970_evt->base);
+err_iomap:
+	kfree(nuc970_evt);
+err_alloc_mem:
+	return;
+}
+
+CLOCKSOURCE_OF_DECLARE(nuc970, "nuvoton,nuc970-tmr", nuc970_timer_of_init);
-- 
2.7.4

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

* [PATCH v2 04/10] clk: add Clock driver for nuc970
  2016-07-10  7:27 [PATCH v2 00/10] ARM: NUC900: Add NUC970 SoC support Wan Zongshun
                   ` (2 preceding siblings ...)
  2016-07-10  7:27 ` [PATCH v2 03/10] Clocksource: add nuc970 clocksource driver Wan Zongshun
@ 2016-07-10  7:27 ` Wan Zongshun
  2016-07-11 22:14   ` Michael Turquette
  2016-07-10  7:27 ` [PATCH v2 05/10] power/reset: Add reset driver support for nuc900 Wan Zongshun
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 45+ messages in thread
From: Wan Zongshun @ 2016-07-10  7:27 UTC (permalink / raw)
  To: linux-arm-kernel

This patch is to add clock framework driver for nuc970.
The clock controller generates all clocks for Video, Audio,
CPU, system bus and all functionalities, nuc970 includes
two PLL modules.

Signed-off-by: Wan Zongshun <mcuos.com@gmail.com>
---
 drivers/clk/Makefile            |   1 +
 drivers/clk/nuc900/Makefile     |   6 +
 drivers/clk/nuc900/clk-apll.c   | 168 ++++++++
 drivers/clk/nuc900/clk-ccf.h    |  53 +++
 drivers/clk/nuc900/clk-nuc970.c | 925 ++++++++++++++++++++++++++++++++++++++++
 drivers/clk/nuc900/clk-upll.c   |  83 ++++
 6 files changed, 1236 insertions(+)
 create mode 100644 drivers/clk/nuc900/Makefile
 create mode 100644 drivers/clk/nuc900/clk-apll.c
 create mode 100644 drivers/clk/nuc900/clk-ccf.h
 create mode 100644 drivers/clk/nuc900/clk-nuc970.c
 create mode 100644 drivers/clk/nuc900/clk-upll.c

diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index dcc5e69..042377d 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -88,3 +88,4 @@ obj-$(CONFIG_ARCH_ZX)			+= zte/
 obj-$(CONFIG_ARCH_ZYNQ)			+= zynq/
 obj-$(CONFIG_H8300)		+= h8300/
 obj-$(CONFIG_ARC_PLAT_AXS10X)		+= axs10x/
+obj-$(CONFIG_ARCH_W90X900)		+= nuc900/
diff --git a/drivers/clk/nuc900/Makefile b/drivers/clk/nuc900/Makefile
new file mode 100644
index 0000000..a6785ab
--- /dev/null
+++ b/drivers/clk/nuc900/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for nuvoton specific clk
+#
+
+obj-$(CONFIG_SOC_NUC970) += clk-apll.o clk-upll.o clk-nuc970.o
+
diff --git a/drivers/clk/nuc900/clk-apll.c b/drivers/clk/nuc900/clk-apll.c
new file mode 100644
index 0000000..a05aec7
--- /dev/null
+++ b/drivers/clk/nuc900/clk-apll.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2016 Wan Zongshun <mcuos.com@gmail.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+
+#include "clk-ccf.h"
+
+struct clk_apll {
+	struct clk_hw	hw;
+	void __iomem	*base;
+};
+
+#define to_clk_apll(clk) (container_of(clk, struct clk_apll, clk))
+
+static int clk_apll_set_rate(struct clk_hw *hw, unsigned long rate,
+			     unsigned long parent_rate)
+{
+	struct clk_apll *pll = to_clk_apll(hw);
+	unsigned long reg;
+
+	reg = readl(pll->base) & ~0x0FFFFFFF;
+
+	switch (rate) {
+	/*usbh*/
+	case 96000000:
+		reg |= 0x8027;
+		break;
+	/*i2s*/
+	case 98400000:
+		reg |= 0x8028;
+		break;
+	/*i2s*/
+	case 169500000:
+		reg |= 0x21f0;
+		break;
+	/*system default, 264MHz*/
+	case 264000000:
+		reg |= 0x15;
+		break;
+	case 300000000:
+		reg |= 0x18;
+		break;
+	default:
+		reg |= 0x15;
+		break;
+	}
+
+	writel(reg, pll->base);
+
+	return 0;
+}
+
+static unsigned long clk_apll_recalc_rate(struct clk_hw *hw,
+					  unsigned long parent_rate)
+{
+	struct clk_apll *pll = to_clk_apll(hw);
+	unsigned long reg = readl(pll->base) & 0x0FFFFFFF;
+	unsigned long rate;
+
+	if (parent_rate != 12000000)
+		return 0;
+
+	switch (reg) {
+	/*system default, 264MHz*/
+	case 0x15:
+		rate = 264000000;
+		break;
+	case 0x18:
+		rate = 300000000;
+		break;
+	/*usbh*/
+	case 0x8027:
+		rate = 96000000;
+		break;
+	/*i2s*/
+	case 0x8028:
+		rate = 98400000;
+		break;
+	/*i2s*/
+	case 0x21f0:
+		rate = 169500000;
+		break;
+	default:
+		rate = 264000000;
+		break;
+	}
+
+	return rate;
+}
+
+static long clk_apll_round_rate(struct clk_hw *hw, unsigned long rate,
+				unsigned long *prate)
+{
+	return rate;
+}
+
+static int clk_apll_enable(struct clk_hw *hw)
+{
+	struct clk_apll *pll = to_clk_apll(hw);
+	unsigned long val;
+
+	val = readl(pll->base);
+	val &= ~0x10000000;
+	val |= 0x40000000;
+	writel(val, pll->base);
+
+	return 0;
+}
+
+static void clk_apll_disable(struct clk_hw *hw)
+{
+	struct clk_apll *pll = to_clk_apll(hw);
+	unsigned long val;
+
+	val = readl(pll->base);
+	val |= 0x10000000;
+	val &= ~0x40000000;
+	writel(val, pll->base);
+}
+
+static struct clk_ops clk_apll_ops = {
+	.recalc_rate = clk_apll_recalc_rate,
+	.enable = clk_apll_enable,
+	.disable = clk_apll_disable,
+	.set_rate = clk_apll_set_rate,
+	.round_rate = clk_apll_round_rate,
+};
+
+struct clk *nuc970_clk_apll(const char *name, const char *parent,
+			    void __iomem *base)
+{
+	struct clk_apll *pll;
+	struct clk *clk;
+	struct clk_init_data init;
+
+	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll)
+		return ERR_PTR(-ENOMEM);
+
+	pll->base = base;
+
+	init.name = name;
+	init.ops = &clk_apll_ops;
+	init.flags = 0;
+	init.parent_names = &parent;
+	init.num_parents = 1;
+
+	pll->hw.init = &init;
+
+	clk = clk_register(NULL, &pll->hw);
+	if (IS_ERR(clk))
+		kfree(pll);
+
+	return clk;
+}
diff --git a/drivers/clk/nuc900/clk-ccf.h b/drivers/clk/nuc900/clk-ccf.h
new file mode 100644
index 0000000..2808933
--- /dev/null
+++ b/drivers/clk/nuc900/clk-ccf.h
@@ -0,0 +1,53 @@
+#ifndef __MACH_NUC970_CLK_H
+#define __MACH_NUC970_CLK_H
+
+#include <linux/spinlock.h>
+#include <linux/clk-provider.h>
+
+static spinlock_t nuc970_lock;
+
+extern struct clk *nuc970_clk_apll(const char *name, const char *parent,
+				   void __iomem *base);
+extern struct clk *nuc970_clk_upll(const char *name, const char *parent,
+				   void __iomem *base);
+
+static inline struct clk *nuc970_clk_fixed(const char *name, int rate)
+{
+	return clk_register_fixed_rate(NULL, name, NULL, 0, rate);
+}
+
+static inline struct clk *nuc970_clk_mux(const char *name, void __iomem *reg,
+					 u8 shift, u8 width,
+					 const char * const *parents,
+					 int num_parents)
+{
+	return clk_register_mux(NULL, name, parents, num_parents, 0, reg, shift,
+				width, 0, &nuc970_lock);
+}
+
+static inline struct clk *nuc970_clk_divider(const char *name,
+					     const char *parent,
+					     void __iomem *reg, u8 shift,
+					     u8 width)
+{
+	return clk_register_divider(NULL, name, parent, 0,
+				    reg, shift, width, 0, &nuc970_lock);
+}
+
+static inline struct clk *nuc970_clk_fixed_factor(const char *name,
+						  const char *parent,
+						  unsigned int mult,
+						  unsigned int div)
+{
+	return clk_register_fixed_factor(NULL, name, parent,
+					 CLK_SET_RATE_PARENT, mult, div);
+}
+
+static inline struct clk *nuc970_clk_gate(const char *name, const char *parent,
+					  void __iomem *reg, u8 shift)
+{
+	return clk_register_gate(NULL, name, parent, CLK_SET_RATE_PARENT, reg,
+				 shift, 0, &nuc970_lock);
+}
+
+#endif
diff --git a/drivers/clk/nuc900/clk-nuc970.c b/drivers/clk/nuc900/clk-nuc970.c
new file mode 100644
index 0000000..55f02c8
--- /dev/null
+++ b/drivers/clk/nuc900/clk-nuc970.c
@@ -0,0 +1,925 @@
+/*
+ * Copyright 2016 Wan Zongshun <mcuos.com@gmail.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/clk-provider.h>
+#include <linux/spinlock.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include <dt-bindings/clock/nuc970-clock.h>
+#include "clk-ccf.h"
+
+/* Clock Control Registers  */
+static void __iomem *clkctrl;
+#define CLK_BA clkctrl
+
+#define REG_CLK_PMCON	(CLK_BA + 0x000)
+#define REG_CLK_HCLKEN	(CLK_BA + 0x010)
+#define REG_CLK_PCLKEN0	(CLK_BA + 0x018)
+#define REG_CLK_PCLKEN1	(CLK_BA + 0x01C)
+#define REG_CLK_DIV0	(CLK_BA + 0x020)
+#define REG_CLK_DIV1	(CLK_BA + 0x024)
+#define REG_CLK_DIV2	(CLK_BA + 0x028)
+#define REG_CLK_DIV3	(CLK_BA + 0x02C)
+#define REG_CLK_DIV4	(CLK_BA + 0x030)
+#define REG_CLK_DIV5	(CLK_BA + 0x034)
+#define REG_CLK_DIV6	(CLK_BA + 0x038)
+#define REG_CLK_DIV7	(CLK_BA + 0x03C)
+#define REG_CLK_DIV8	(CLK_BA + 0x040)
+#define REG_CLK_DIV9	(CLK_BA + 0x044)
+#define REG_CLK_APLLCON	(CLK_BA + 0x060)
+#define REG_CLK_UPLLCON	(CLK_BA + 0x064)
+
+static const char *const sys_sel_clks[] = { "xin",
+					    "dummy",
+					    "apll",
+					    "upll" };
+
+static const char *const lcd_sel_clks[] = { "xin",
+					    "dummy",
+					    "lcd_aplldiv",
+					    "lcd_uplldiv" };
+
+static const char *const audio_sel_clks[] = { "xin",
+					      "dummy",
+					      "audio_aplldiv",
+					      "audio_uplldiv" };
+
+static const char *const usb_sel_clks[] = { "xin",
+					    "dummy",
+					    "usb_aplldiv",
+					    "usb_uplldiv" };
+
+static const char *const adc_sel_clks[] = { "xin",
+					    "dummy",
+					    "adc_aplldiv",
+					    "adc_uplldiv" };
+
+static const char *const cap_sel_clks[] = { "xin",
+					    "dummy",
+					    "cap_aplldiv",
+					    "cap_uplldiv" };
+
+static const char *const sdh_sel_clks[] = { "xin",
+					    "dummy",
+					    "sdh_aplldiv",
+					    "sdh_uplldiv" };
+
+static const char *const emmc_sel_clks[] = { "xin",
+					     "dummy",
+					     "emmc_aplldiv",
+					     "emmc_uplldiv" };
+
+static const char *const uart0_sel_clks[] = { "xin",
+					      "dummy",
+					      "uart0_aplldiv",
+					      "uart0_uplldiv" };
+
+static const char *const uart1_sel_clks[] = { "xin",
+					      "dummy",
+					      "uart1_aplldiv",
+					      "uart1_uplldiv" };
+
+static const char *const uart2_sel_clks[] = { "xin",
+					      "dummy",
+					      "uart2_aplldiv",
+					      "uart2_uplldiv" };
+
+static const char *const uart3_sel_clks[] = { "xin",
+					      "dummy",
+					      "uart3_aplldiv",
+					      "uart3_uplldiv" };
+
+static const char *const uart4_sel_clks[] = { "xin",
+					      "dummy",
+					      "uart4_aplldiv",
+					      "uart4_uplldiv" };
+
+static const char *const uart5_sel_clks[] = { "xin",
+					      "dummy",
+					      "uart5_aplldiv",
+					      "uart5_uplldiv" };
+
+static const char *const uart6_sel_clks[] = { "xin",
+					      "dummy",
+					      "uart6_aplldiv",
+					      "uart6_uplldiv" };
+
+static const char *const uart7_sel_clks[] = { "xin",
+					      "dummy",
+					      "uart7_aplldiv",
+					      "uart7_uplldiv" };
+
+static const char *const uart8_sel_clks[] = { "xin",
+					      "dummy",
+					      "uart8_aplldiv",
+					      "uart8_uplldiv" };
+
+static const char *const uart9_sel_clks[] = { "xin",
+					      "dummy",
+					      "uart9_aplldiv",
+					      "uart9_uplldiv" };
+
+static const char *const uart10_sel_clks[] = { "xin",
+					       "dummy",
+					       "uart10_aplldiv",
+					       "uart10_uplldiv" };
+
+static const char *const system_sel_clks[] = { "xin",
+					       "dummy",
+					       "system_aplldiv",
+					       "system_uplldiv" };
+
+static const char *const gpio_sel_clks[] = { "xin", "xin32k"};
+static const char *const kpi_sel_clks[] = { "xin", "xin32k"};
+static const char *const etimer_sel_clks[] = { "xin",
+					       "pclk_div",
+					      "pclk4096_div",
+					      "xin32k" };
+
+static const char *const wwdt_sel_clks[] = { "xin",
+					     "xin128_div",
+					     "pclk4096_div",
+					     "xin32k" };
+
+static struct clk *clk[NUC970_CLK_MAX];
+static struct clk_onecell_data clk_data;
+
+static void __init nuc970_clocks_init(struct device_node *np)
+{
+	int i, ret;
+
+	clkctrl = of_iomap(np, 0);
+	if (!clkctrl)
+		pr_err("%s: unable to map registers\n", np->full_name);
+
+
+	/* source */
+	clk[XIN]	= nuc970_clk_fixed("xin", 12000000);
+	clk[XIN32K]	= nuc970_clk_fixed("xin32k", 32768);
+	clk[APLL]	= nuc970_clk_apll("apll", "xin", REG_CLK_APLLCON);
+	clk[UPLL]	= nuc970_clk_upll("upll", "xin", REG_CLK_UPLLCON);
+	clk[XIN128_DIV]	= nuc970_clk_fixed_factor("xin128_div", "xin", 1, 128);
+	clk[SYS_MUX]	= nuc970_clk_mux("sys_mux", REG_CLK_DIV0, 3, 2,
+					 sys_sel_clks,
+					 ARRAY_SIZE(sys_sel_clks));
+	clk[SYS_DIV]	= nuc970_clk_divider("sys_div", "sys_mux",
+					     REG_CLK_DIV0, 0, 2);
+	clk[DDR_GATE]	= nuc970_clk_gate("ddr_gate", "sys_div",
+					  REG_CLK_HCLKEN, 10);
+	/* CPU */
+	clk[CPU_DIV]  = nuc970_clk_divider("cpu_div", "sys_div",
+					   REG_CLK_DIV0, 16, 1);
+	clk[CPU_GATE] = nuc970_clk_gate("cpu_gate", "cpu_div",
+					REG_CLK_HCLKEN, 0);
+	/*HCLK1 & PCLK*/
+	clk[HCLK1_DIV]	= nuc970_clk_fixed_factor("hclk1_div", "cpu_div", 1, 2);
+	clk[GDMA_GATE]	= nuc970_clk_gate("gdma_hclk_gate", "hclk1_div",
+					  REG_CLK_HCLKEN, 12);
+	clk[EBI_GATE]	= nuc970_clk_gate("ebi_hclk_gate", "hclk1_div",
+					  REG_CLK_HCLKEN, 9);
+	clk[TIC_GATE]	= nuc970_clk_gate("tic_hclk_gate", "hclk1_div",
+					  REG_CLK_HCLKEN, 7);
+	/* HCLK & HCLK234 */
+	clk[HCLKN_DIV]		= nuc970_clk_fixed_factor("hclkn_div",
+							  "sys_div", 1, 2);
+	clk[DRAM_GATE]		= nuc970_clk_gate("dram_gate", "hclkn_div",
+						  REG_CLK_HCLKEN, 10);
+	clk[HCLK_GATE]		= nuc970_clk_gate("hclk_gate", "hclkn_div",
+						  REG_CLK_HCLKEN, 1);
+	clk[SRAM_GATE]		= nuc970_clk_gate("sram_gate", "hclk_gate",
+						  REG_CLK_HCLKEN, 8);
+	clk[HCLK234_DIV]	= nuc970_clk_divider("hclk234_div", "hclkn_div",
+						     REG_CLK_DIV0, 20, 4);
+	/* HCLK3 */
+	clk[USBH_GATE]		= nuc970_clk_gate("usbh_hclk_gate",
+						  "hclk234_div",
+						  REG_CLK_HCLKEN, 18);
+	clk[USBD_GATE]		= nuc970_clk_gate("usbd_hclk_gate",
+						  "hclk234_div",
+						  REG_CLK_HCLKEN, 19);
+	clk[FMI_GATE]		= nuc970_clk_gate("fmi_hclk_gate",
+						  "hclk234_div",
+						  REG_CLK_HCLKEN, 20);
+	clk[NAND_GATE]		= nuc970_clk_gate("nand_hclk_gate",
+						  "hclk234_div",
+						  REG_CLK_HCLKEN, 21);
+	clk[EMMC_GATE]		= nuc970_clk_gate("emmc_hclk_gate",
+						  "hclk234_div",
+						  REG_CLK_HCLKEN, 22);
+	clk[CRYPTO_GATE]	= nuc970_clk_gate("crypto_hclk_gate",
+						  "hclk234_div",
+						  REG_CLK_HCLKEN, 23);
+	clk[EMAC1_GATE]		= nuc970_clk_gate("emac1_hclk_gate",
+						  "hclk234_div",
+						  REG_CLK_HCLKEN, 17);
+	clk[EMAC1_ECLK_DIV]	= nuc970_clk_divider("emac1_eclk_div",
+						     "hclk234_div",
+						     REG_CLK_DIV8, 0, 8);
+	clk[EMAC1_ECLK_GATE]	= nuc970_clk_gate("emac1_eclk_gate",
+						  "emac1_eclk_div",
+						  REG_CLK_HCLKEN, 17);
+	clk[JPEG_GATE]		= nuc970_clk_gate("jpeg_hclk_gate",
+						  "hclk234_div",
+						  REG_CLK_HCLKEN, 29);
+	clk[JPEG_ECLK_DIV]	= nuc970_clk_divider("jpeg_eclk_div",
+						     "hclk234_div",
+						     REG_CLK_DIV3, 28, 3);
+	clk[JPEG_ECLK_GATE]	= nuc970_clk_gate("jpeg_eclk_gate",
+						  "jpeg_eclk_div",
+						  REG_CLK_HCLKEN, 29);
+	clk[GE2D_GATE]		= nuc970_clk_gate("ge2d_hclk_gate",
+						  "hclk234_div",
+						  REG_CLK_HCLKEN, 28);
+	clk[GE2D_ECLK_DIV]	= nuc970_clk_divider("ge2d_eclk_div",
+						     "hclk234_div",
+						     REG_CLK_DIV2, 28, 2);
+	clk[GE2D_ECLK_GATE]	= nuc970_clk_gate("ge2d_eclk_gate",
+						  "ge2d_eclk_div",
+						  REG_CLK_HCLKEN, 28);
+	/* HCLK4 */
+	clk[SDH_GATE]		= nuc970_clk_gate("sdh_hclk_gate",
+						  "hclk234_div",
+						  REG_CLK_HCLKEN, 30);
+	clk[AUDIO_GATE]		= nuc970_clk_gate("audio_hclk_gate",
+						  "hclk234_div",
+						  REG_CLK_HCLKEN, 24);
+	clk[LCD_GATE]		= nuc970_clk_gate("lcd_hclk_gate",
+						  "hclk234_div",
+						  REG_CLK_HCLKEN, 25);
+	clk[CAP_GATE]		= nuc970_clk_gate("cap_hclk_gate",
+						  "hclk234_div",
+						  REG_CLK_HCLKEN, 26);
+	clk[SENSOR_GATE]	= nuc970_clk_gate("sensor_hclk_gate",
+						  "hclk234_div",
+						  REG_CLK_HCLKEN, 27);
+	clk[EMAC0_GATE]		= nuc970_clk_gate("emac0_hclk_gate",
+						  "hclk234_div",
+						  REG_CLK_HCLKEN, 16);
+	clk[EMAC0_ECLK_DIV]	= nuc970_clk_divider("emac0_eclk_div",
+						     "hclk234_div",
+						     REG_CLK_DIV8, 0, 8);
+	clk[EMAC0_ECLK_GATE]	= nuc970_clk_gate("emac0_eclk_gate",
+						  "emac0_eclk_div",
+						  REG_CLK_HCLKEN, 16);
+	/* ECLK */
+	/* USB */
+	clk[USB_APLLDIV]	= nuc970_clk_divider("usb_aplldiv", "apll",
+						     REG_CLK_DIV2, 0, 3);
+	clk[USB_UPLLDIV]	= nuc970_clk_divider("usb_uplldiv", "upll",
+						     REG_CLK_DIV2, 0, 3);
+	clk[USB_ECLK_MUX]	= nuc970_clk_mux("usb_eclk_mux", REG_CLK_DIV2,
+						 3, 2, usb_sel_clks,
+						 ARRAY_SIZE(usb_sel_clks));
+	clk[USB_ECLK_DIV]	= nuc970_clk_divider("usb_eclk_div",
+						     "usb_eclk_mux",
+						     REG_CLK_DIV2, 8, 4);
+	clk[USB_ECLK_GATE]	= nuc970_clk_gate("usb_eclk_gate",
+						  "usb_eclk_div",
+						  REG_CLK_HCLKEN, 18);
+	/* SDH */
+	clk[SDH_APLLDIV]	= nuc970_clk_divider("sdh_aplldiv", "apll",
+						     REG_CLK_DIV9, 0, 3);
+	clk[SDH_UPLLDIV]	= nuc970_clk_divider("sdh_uplldiv", "upll",
+						     REG_CLK_DIV9, 0, 3);
+	clk[SDH_ECLK_MUX]	= nuc970_clk_mux("sdh_eclk_mux", REG_CLK_DIV9,
+						 3, 2, sdh_sel_clks,
+						 ARRAY_SIZE(sdh_sel_clks));
+	clk[SDH_ECLK_DIV]	= nuc970_clk_divider("sdh_eclk_div",
+						     "sdh_eclk_mux",
+						     REG_CLK_DIV9, 8, 8);
+	clk[SDH_ECLK_GATE]	= nuc970_clk_gate("sdh_eclk_gate",
+						  "sdh_eclk_div",
+						  REG_CLK_HCLKEN, 30);
+	/* EMMC */
+	clk[EMMC_APLLDIV]	= nuc970_clk_divider("emmc_aplldiv", "apll",
+						     REG_CLK_DIV3, 0, 3);
+	clk[EMMC_UPLLDIV]	= nuc970_clk_divider("emmc_uplldiv", "upll",
+						     REG_CLK_DIV3, 0, 3);
+	clk[EMMC_ECLK_MUX]	= nuc970_clk_mux("emmc_eclk_mux", REG_CLK_DIV3,
+						 3, 2, emmc_sel_clks,
+						 ARRAY_SIZE(emmc_sel_clks));
+	clk[EMMC_ECLK_DIV]	= nuc970_clk_divider("emmc_eclk_div",
+						     "emmc_eclk_mux",
+						     REG_CLK_DIV3, 8, 8);
+	clk[EMMC_ECLK_GATE]	= nuc970_clk_gate("emmc_eclk_gate",
+						  "emmc_eclk_div",
+						  REG_CLK_HCLKEN, 22);
+	/* ADC */
+	clk[ADC_APLLDIV]	= nuc970_clk_divider("adc_aplldiv", "apll",
+						     REG_CLK_DIV7, 16, 3);
+	clk[ADC_UPLLDIV]	= nuc970_clk_divider("adc_uplldiv", "upll",
+						     REG_CLK_DIV7, 16, 3);
+	clk[ADC_ECLK_MUX]	= nuc970_clk_mux("adc_eclk_mux", REG_CLK_DIV7,
+						 19, 2, adc_sel_clks,
+						 ARRAY_SIZE(adc_sel_clks));
+	clk[ADC_ECLK_DIV]	= nuc970_clk_divider("adc_eclk_div",
+						     "adc_eclk_mux",
+						     REG_CLK_DIV7, 24, 8);
+	clk[ADC_ECLK_GATE]	= nuc970_clk_gate("adc_eclk_gate",
+						  "adc_eclk_div",
+						  REG_CLK_PCLKEN1, 24);
+	/* LCD */
+	clk[LCD_APLLDIV]	= nuc970_clk_divider("lcd_aplldiv", "apll",
+						     REG_CLK_DIV1, 0, 3);
+	clk[LCD_UPLLDIV]	= nuc970_clk_divider("lcd_uplldiv", "upll",
+					     REG_CLK_DIV1, 0, 3);
+	clk[LCD_ECLK_MUX]	= nuc970_clk_mux("lcd_eclk_mux", REG_CLK_DIV1,
+						 3, 2, lcd_sel_clks,
+						 ARRAY_SIZE(lcd_sel_clks));
+	clk[LCD_ECLK_DIV]	= nuc970_clk_divider("lcd_eclk_div",
+						     "lcd_eclk_mux",
+						     REG_CLK_DIV1, 8, 8);
+	clk[LCD_ECLK_GATE]	= nuc970_clk_gate("lcd_eclk_gate",
+						  "lcd_eclk_div",
+						  REG_CLK_HCLKEN, 25);
+	/* AUDIO */
+	clk[AUDIO_APLLDIV]	= nuc970_clk_divider("audio_aplldiv", "apll",
+						     REG_CLK_DIV1, 16, 3);
+	clk[AUDIO_UPLLDIV]	= nuc970_clk_divider("audio_uplldiv", "upll",
+						     REG_CLK_DIV1, 16, 3);
+	clk[AUDIO_ECLK_MUX]	= nuc970_clk_mux("audio_eclk_mux", REG_CLK_DIV1,
+						 19, 2, audio_sel_clks,
+						 ARRAY_SIZE(audio_sel_clks));
+	clk[AUDIO_ECLK_DIV]	= nuc970_clk_divider("audio_eclk_div",
+						     "audio_eclk_mux",
+						     REG_CLK_DIV1, 24, 8);
+	clk[AUDIO_ECLK_GATE]	= nuc970_clk_gate("audio_eclk_gate",
+						  "audio_eclk_div",
+						  REG_CLK_HCLKEN, 24);
+	/* CAP */
+	clk[CAP_APLLDIV]	= nuc970_clk_divider("cap_aplldiv", "apll",
+						     REG_CLK_DIV3, 16, 3);
+	clk[CAP_UPLLDIV]	= nuc970_clk_divider("cap_uplldiv", "upll",
+						     REG_CLK_DIV3, 16, 3);
+	clk[CAP_ECLK_MUX]	= nuc970_clk_mux("cap_eclk_mux", REG_CLK_DIV3,
+						 19, 2, cap_sel_clks,
+						 ARRAY_SIZE(cap_sel_clks));
+	clk[CAP_ECLK_DIV]	= nuc970_clk_divider("cap_eclk_div",
+						     "cap_eclk_mux",
+						     REG_CLK_DIV3, 24, 4);
+	clk[CAP_ECLK_GATE]	= nuc970_clk_gate("cap_eclk_gate",
+						  "cap_eclk_div",
+						  REG_CLK_HCLKEN, 26);
+	/* UART0 */
+	clk[UART0_APLLDIV]	= nuc970_clk_divider("uart0_aplldiv",
+						     "apll", REG_CLK_DIV4,
+						     0, 3);
+	clk[UART0_UPLLDIV]	= nuc970_clk_divider("uart0_uplldiv", "upll",
+						     REG_CLK_DIV4, 0, 3);
+	clk[UART0_ECLK_MUX]	= nuc970_clk_mux("uart0_eclk_mux", REG_CLK_DIV4,
+						 3, 2, uart0_sel_clks,
+						 ARRAY_SIZE(uart0_sel_clks));
+	clk[UART0_ECLK_DIV]	= nuc970_clk_divider("uart0_eclk_div",
+						     "uart0_eclk_mux",
+						     REG_CLK_DIV4, 5, 3);
+	clk[UART0_ECLK_GATE]	= nuc970_clk_gate("uart0_eclk_gate",
+						  "uart0_eclk_div",
+						  REG_CLK_PCLKEN0, 16);
+	/* UART1 */
+	clk[UART1_APLLDIV]	= nuc970_clk_divider("uart1_aplldiv", "apll",
+						     REG_CLK_DIV4, 8, 3);
+	clk[UART1_UPLLDIV]	= nuc970_clk_divider("uart1_uplldiv", "upll",
+						     REG_CLK_DIV4, 8, 3);
+	clk[UART1_ECLK_MUX]	= nuc970_clk_mux("uart1_eclk_mux", REG_CLK_DIV4,
+						 11, 2, uart1_sel_clks,
+						 ARRAY_SIZE(uart1_sel_clks));
+	clk[UART1_ECLK_DIV]	= nuc970_clk_divider("uart1_eclk_div",
+						     "uart1_eclk_mux",
+						     REG_CLK_DIV4, 13, 3);
+	clk[UART1_ECLK_GATE]	= nuc970_clk_gate("uart1_eclk_gate",
+						  "uart1_eclk_div",
+						  REG_CLK_PCLKEN0, 17);
+	/* UART2 */
+	clk[UART2_APLLDIV]	= nuc970_clk_divider("uart2_aplldiv", "apll",
+						     REG_CLK_DIV4, 16, 3);
+	clk[UART2_UPLLDIV]	= nuc970_clk_divider("uart2_uplldiv", "upll",
+						     REG_CLK_DIV4, 16, 3);
+	clk[UART2_ECLK_MUX]	= nuc970_clk_mux("uart2_eclk_mux", REG_CLK_DIV4,
+						 19, 2, uart2_sel_clks,
+						 ARRAY_SIZE(uart2_sel_clks));
+	clk[UART2_ECLK_DIV]	= nuc970_clk_divider("uart2_eclk_div",
+						     "uart2_eclk_mux",
+						     REG_CLK_DIV4, 21, 3);
+	clk[UART2_ECLK_GATE]	= nuc970_clk_gate("uart2_eclk_gate",
+						  "uart2_eclk_div",
+						  REG_CLK_PCLKEN0, 18);
+	/* UART3 */
+	clk[UART3_APLLDIV]	= nuc970_clk_divider("uart3_aplldiv", "apll",
+						     REG_CLK_DIV4, 24, 3);
+	clk[UART3_UPLLDIV]	= nuc970_clk_divider("uart3_uplldiv", "upll",
+						     REG_CLK_DIV4, 24, 3);
+	clk[UART3_ECLK_MUX]	= nuc970_clk_mux("uart3_eclk_mux", REG_CLK_DIV4,
+						 27, 2, uart3_sel_clks,
+						 ARRAY_SIZE(uart3_sel_clks));
+	clk[UART3_ECLK_DIV]	= nuc970_clk_divider("uart3_eclk_div",
+						     "uart3_eclk_mux",
+						     REG_CLK_DIV4, 29, 3);
+	clk[UART3_ECLK_GATE]	= nuc970_clk_gate("uart3_eclk_gate",
+						  "uart3_eclk_div",
+						  REG_CLK_PCLKEN0, 19);
+	/* UART4 */
+	clk[UART4_APLLDIV]	= nuc970_clk_divider("uart4_aplldiv", "apll",
+						     REG_CLK_DIV5, 0, 3);
+	clk[UART4_UPLLDIV]	= nuc970_clk_divider("uart4_uplldiv", "upll",
+						     REG_CLK_DIV5, 0, 3);
+	clk[UART4_ECLK_MUX]	= nuc970_clk_mux("uart4_eclk_mux", REG_CLK_DIV5,
+						 3, 2, uart4_sel_clks,
+						 ARRAY_SIZE(uart4_sel_clks));
+	clk[UART4_ECLK_DIV]	= nuc970_clk_divider("uart4_eclk_div",
+						     "uart4_eclk_mux",
+						     REG_CLK_DIV5, 5, 3);
+	clk[UART4_ECLK_GATE]	= nuc970_clk_gate("uart4_eclk_gate",
+						  "uart4_eclk_div",
+						  REG_CLK_PCLKEN0, 20);
+	/* UART5 */
+	clk[UART5_APLLDIV]	= nuc970_clk_divider("uart5_aplldiv", "apll",
+						     REG_CLK_DIV5, 8, 3);
+	clk[UART5_UPLLDIV]	= nuc970_clk_divider("uart5_uplldiv", "upll",
+						     REG_CLK_DIV5, 8, 3);
+	clk[UART5_ECLK_MUX]	= nuc970_clk_mux("uart5_eclk_mux", REG_CLK_DIV5,
+						 11, 2, uart5_sel_clks,
+						 ARRAY_SIZE(uart5_sel_clks));
+	clk[UART5_ECLK_DIV]	= nuc970_clk_divider("uart5_eclk_div",
+						     "uart5_eclk_mux",
+						     REG_CLK_DIV5, 13, 3);
+	clk[UART5_ECLK_GATE]	= nuc970_clk_gate("uart5_eclk_gate",
+						  "uart5_eclk_div",
+						  REG_CLK_PCLKEN0, 21);
+	/* UART6 */
+	clk[UART6_APLLDIV]	= nuc970_clk_divider("uart6_aplldiv", "apll",
+						     REG_CLK_DIV5, 16, 3);
+	clk[UART6_UPLLDIV]	= nuc970_clk_divider("uart6_uplldiv", "upll",
+						     REG_CLK_DIV5, 16, 3);
+	clk[UART6_ECLK_MUX]	= nuc970_clk_mux("uart6_eclk_mux", REG_CLK_DIV5,
+						 19, 2, uart6_sel_clks,
+						 ARRAY_SIZE(uart6_sel_clks));
+	clk[UART6_ECLK_DIV]	= nuc970_clk_divider("uart6_eclk_div",
+						     "uart6_eclk_mux",
+						     REG_CLK_DIV5, 21, 3);
+	clk[UART6_ECLK_GATE]	= nuc970_clk_gate("uart6_eclk_gate",
+						  "uart6_eclk_div",
+						  REG_CLK_PCLKEN0, 22);
+	/* UART7 */
+	clk[UART7_APLLDIV]	= nuc970_clk_divider("uart7_aplldiv", "apll",
+						     REG_CLK_DIV5, 24, 3);
+	clk[UART7_UPLLDIV]	= nuc970_clk_divider("uart7_uplldiv", "upll",
+						     REG_CLK_DIV5, 24, 3);
+	clk[UART7_ECLK_MUX]	= nuc970_clk_mux("uart7_eclk_mux", REG_CLK_DIV5,
+						 27, 2, uart7_sel_clks,
+						 ARRAY_SIZE(uart7_sel_clks));
+	clk[UART7_ECLK_DIV]	= nuc970_clk_divider("uart7_eclk_div",
+						     "uart7_eclk_mux",
+						     REG_CLK_DIV5, 29, 3);
+	clk[UART7_ECLK_GATE]	= nuc970_clk_gate("uart7_eclk_gate",
+						  "uart7_eclk_div",
+						  REG_CLK_PCLKEN0, 23);
+	/* UART8 */
+	clk[UART8_APLLDIV]	= nuc970_clk_divider("uart8_aplldiv", "apll",
+						     REG_CLK_DIV6, 0, 3);
+	clk[UART8_UPLLDIV]	= nuc970_clk_divider("uart8_uplldiv", "upll",
+						     REG_CLK_DIV6, 0, 3);
+	clk[UART8_ECLK_MUX]	= nuc970_clk_mux("uart8_eclk_mux", REG_CLK_DIV6,
+						 3, 2, uart8_sel_clks,
+						 ARRAY_SIZE(uart8_sel_clks));
+	clk[UART8_ECLK_DIV]	= nuc970_clk_divider("uart8_eclk_div",
+						     "uart8_eclk_mux",
+						     REG_CLK_DIV6, 5, 3);
+	clk[UART8_ECLK_GATE]	= nuc970_clk_gate("uart8_eclk_gate",
+						  "uart8_eclk_div",
+						  REG_CLK_PCLKEN0, 24);
+	/* UART9 */
+	clk[UART9_APLLDIV]	= nuc970_clk_divider("uart9_aplldiv", "apll",
+						     REG_CLK_DIV6, 8, 3);
+	clk[UART9_UPLLDIV]	= nuc970_clk_divider("uart9_uplldiv", "upll",
+						     REG_CLK_DIV6, 8, 3);
+	clk[UART9_ECLK_MUX]	= nuc970_clk_mux("uart9_eclk_mux", REG_CLK_DIV6,
+						 11, 2, uart9_sel_clks,
+						 ARRAY_SIZE(uart9_sel_clks));
+	clk[UART9_ECLK_DIV]	= nuc970_clk_divider("uart9_eclk_div",
+						     "uart9_eclk_mux",
+						     REG_CLK_DIV6, 13, 3);
+	clk[UART9_ECLK_GATE]	= nuc970_clk_gate("uart9_eclk_gate",
+						  "uart9_eclk_div",
+						  REG_CLK_PCLKEN0, 25);
+	/* UART10 */
+	clk[UART10_APLLDIV]	 = nuc970_clk_divider("uart10_aplldiv", "apll",
+						      REG_CLK_DIV6, 16, 3);
+	clk[UART10_UPLLDIV]	 = nuc970_clk_divider("uart10_uplldiv", "upll",
+						      REG_CLK_DIV6, 16, 3);
+	clk[UART10_ECLK_MUX]	= nuc970_clk_mux("uart10_eclk_mux",
+						 REG_CLK_DIV6, 19, 2,
+						 uart10_sel_clks,
+						 ARRAY_SIZE(uart10_sel_clks));
+	clk[UART10_ECLK_DIV]	= nuc970_clk_divider("uart10_eclk_div",
+						     "uart10_eclk_mux",
+						     REG_CLK_DIV6, 21, 3);
+	clk[UART10_ECLK_GATE]	= nuc970_clk_gate("uart10_eclk_gate",
+						  "uart10_eclk_div",
+						  REG_CLK_PCLKEN0, 26);
+	/* SYSTEM */
+	clk[SYSTEM_APLLDIV]	= nuc970_clk_divider("system_aplldiv", "apll",
+						     REG_CLK_DIV0, 0, 3);
+	clk[SYSTEM_UPLLDIV]	= nuc970_clk_divider("system_uplldiv", "upll",
+						     REG_CLK_DIV0, 0, 3);
+	clk[SYSTEM_ECLK_MUX]	= nuc970_clk_mux("system_eclk_mux",
+						 REG_CLK_DIV0, 3, 2,
+						 system_sel_clks,
+						 ARRAY_SIZE(system_sel_clks));
+	clk[SYSTEM_ECLK_DIV]	= nuc970_clk_divider("system_eclk_div",
+						     "system_eclk_mux",
+						     REG_CLK_DIV0, 8, 4);
+	/* GPIO */
+	clk[GPIO_ECLK_MUX]	= nuc970_clk_mux("gpio_eclk_mux", REG_CLK_DIV7,
+						 7, 1, gpio_sel_clks,
+						 ARRAY_SIZE(gpio_sel_clks));
+	clk[GPIO_ECLK_DIV]	= nuc970_clk_divider("gpio_eclk_div",
+						     "gpio_eclk_mux",
+						     REG_CLK_DIV7, 0, 7);
+	clk[GPIO_ECLK_GATE]	= nuc970_clk_gate("gpio_eclk_gate",
+						  "gpio_eclk_div",
+						  REG_CLK_PCLKEN0, 3);
+	/* KPI */
+	clk[KPI_ECLK_MUX]	= nuc970_clk_mux("kpi_eclk_mux", REG_CLK_DIV7,
+						 15, 1, kpi_sel_clks,
+						 ARRAY_SIZE(kpi_sel_clks));
+	clk[KPI_ECLK_DIV]	= nuc970_clk_divider("kpi_eclk_div",
+						     "kpi_eclk_mux",
+						     REG_CLK_DIV7, 8, 7);
+	clk[KPI_ECLK_GATE]	= nuc970_clk_gate("kpi_eclk_gate",
+						  "kpi_eclk_div",
+						  REG_CLK_PCLKEN1, 25);
+	/* ETIMER0 */
+	clk[ETIMER0_ECLK_MUX]	= nuc970_clk_mux("etimer0_eclk_mux",
+						 REG_CLK_DIV8, 16, 2,
+						 etimer_sel_clks,
+						 ARRAY_SIZE(etimer_sel_clks));
+	clk[ETIMER0_ECLK_GATE]	= nuc970_clk_gate("etimer0_eclk_gate",
+						  "etimer0_eclk_mux",
+						  REG_CLK_PCLKEN0, 4);
+	/* ETIMER1 */
+	clk[ETIMER1_ECLK_MUX]	= nuc970_clk_mux("etimer1_eclk_mux",
+						 REG_CLK_DIV8, 18, 2,
+						 etimer_sel_clks,
+						 ARRAY_SIZE(etimer_sel_clks));
+	clk[ETIMER1_ECLK_GATE]	= nuc970_clk_gate("etimer1_eclk_gate",
+						  "etimer1_eclk_mux",
+						  REG_CLK_PCLKEN0, 5);
+	/* ETIMER2 */
+	clk[ETIMER2_ECLK_MUX]	= nuc970_clk_mux("etimer2_eclk_mux",
+						 REG_CLK_DIV8, 20, 2,
+						 etimer_sel_clks,
+						 ARRAY_SIZE(etimer_sel_clks));
+	clk[ETIMER2_ECLK_GATE]	= nuc970_clk_gate("etimer2_eclk_gate",
+						  "etimer2_eclk_mux",
+						  REG_CLK_PCLKEN0, 6);
+	/* ETIMER3 */
+	clk[ETIMER3_ECLK_MUX]	= nuc970_clk_mux("etimer3_eclk_mux",
+						 REG_CLK_DIV8, 22, 2,
+						 etimer_sel_clks,
+						 ARRAY_SIZE(etimer_sel_clks));
+	clk[ETIMER3_ECLK_GATE]	= nuc970_clk_gate("etimer3_eclk_gate",
+						  "etimer3_eclk_mux",
+						  REG_CLK_PCLKEN0, 7);
+	/* WWDT */
+	clk[WWDT_ECLK_MUX]	= nuc970_clk_mux("wwdt_eclk_mux", REG_CLK_DIV8,
+						 10, 2, wwdt_sel_clks,
+						 ARRAY_SIZE(wwdt_sel_clks));
+	clk[WWDT_ECLK_GATE]	= nuc970_clk_gate("wwdt_eclk_gate",
+						  "wwdt_eclk_mux",
+						  REG_CLK_PCLKEN0, 1);
+	/* WDT */
+	clk[WDT_ECLK_MUX]	= nuc970_clk_mux("wdt_eclk_mux", REG_CLK_DIV8,
+						 8, 2, wwdt_sel_clks,
+						 ARRAY_SIZE(wwdt_sel_clks));
+	clk[WDT_ECLK_GATE]	= nuc970_clk_gate("wdt_eclk_gate",
+						  "wdt_eclk_mux",
+						  REG_CLK_PCLKEN0, 0);
+	/* SMARTCARD */
+	clk[SMC0_ECLK_DIV]	= nuc970_clk_divider("smc0_eclk_div", "xin",
+						     REG_CLK_DIV6, 24, 4);
+	clk[SMC0_ECLK_GATE]	= nuc970_clk_gate("smc0_eclk_gate",
+						  "smc0_eclk_div",
+						  REG_CLK_PCLKEN1, 12);
+	clk[SMC1_ECLK_DIV]	= nuc970_clk_divider("smc1_eclk_div", "xin",
+						     REG_CLK_DIV6, 28, 4);
+	clk[SMC1_ECLK_GATE]	= nuc970_clk_gate("smc1_eclk_gate",
+						  "smc1_eclk_div",
+						  REG_CLK_PCLKEN1, 13);
+	/* PCLK */
+	clk[PCLK_DIV]		= nuc970_clk_divider("pclk_div", "hclk1_div",
+						     REG_CLK_DIV0, 24, 4);
+	clk[PCLK4096_DIV]	= nuc970_clk_fixed_factor("pclk4096_div",
+							  "pclk_div", 1, 4096);
+	clk[I2C0_GATE]		= nuc970_clk_gate("i2c0_gate", "pclk_div",
+						  REG_CLK_PCLKEN1, 0);
+	clk[I2C1_GATE]		= nuc970_clk_gate("i2c1_gate", "pclk_div",
+						  REG_CLK_PCLKEN1, 1);
+	clk[SPI0_GATE]		= nuc970_clk_gate("spi0_gate", "pclk_div",
+						  REG_CLK_PCLKEN1, 4);
+	clk[SPI1_GATE]		= nuc970_clk_gate("spi1_gate", "pclk_div",
+						  REG_CLK_PCLKEN1, 5);
+	clk[UART0_GATE]		= nuc970_clk_gate("uart0_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 16);
+	clk[UART1_GATE]		= nuc970_clk_gate("uart1_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 17);
+	clk[UART2_GATE]		= nuc970_clk_gate("uart2_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 18);
+	clk[UART3_GATE]		= nuc970_clk_gate("uart3_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 19);
+	clk[UART4_GATE]		= nuc970_clk_gate("uart4_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 20);
+	clk[UART5_GATE]		= nuc970_clk_gate("uart5_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 21);
+	clk[UART6_GATE]		= nuc970_clk_gate("uart6_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 22);
+	clk[UART7_GATE]		= nuc970_clk_gate("uart7_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 23);
+	clk[UART8_GATE]		= nuc970_clk_gate("uart8_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 24);
+	clk[UART9_GATE]		= nuc970_clk_gate("uart9_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 25);
+	clk[UART10_GATE]	= nuc970_clk_gate("uart10_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 26);
+	clk[WDT_GATE]		= nuc970_clk_gate("wdt_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 0);
+	clk[WWDT_GATE]		= nuc970_clk_gate("wwdt_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 1);
+	clk[RTC_GATE]		= nuc970_clk_gate("rtc_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 2);
+	clk[GPIO_GATE]		= nuc970_clk_gate("gpio_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 3);
+	clk[ADC_GATE]		= nuc970_clk_gate("adc_gate", "pclk_div",
+						  REG_CLK_PCLKEN1, 24);
+	clk[KPI_GATE]		= nuc970_clk_gate("kpi_gate", "pclk_div",
+						  REG_CLK_PCLKEN1, 25);
+	clk[MTPC_GATE]		= nuc970_clk_gate("mtpc_gate", "pclk_div",
+						  REG_CLK_PCLKEN1, 26);
+	clk[PWM_GATE]		= nuc970_clk_gate("pwm_gate", "pclk_div",
+						  REG_CLK_PCLKEN1, 27);
+	clk[ETIMER0_GATE]	= nuc970_clk_gate("etimer0_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 4);
+	clk[ETIMER1_GATE]	= nuc970_clk_gate("etimer1_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 5);
+	clk[ETIMER2_GATE]	= nuc970_clk_gate("etimer2_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 6);
+	clk[ETIMER3_GATE]	= nuc970_clk_gate("etimer3_gate", "pclk_div",
+						  REG_CLK_PCLKEN0, 7);
+	clk[CAN0_GATE]		= nuc970_clk_gate("can0_gate", "pclk_div",
+						  REG_CLK_PCLKEN1, 8);
+	clk[CAN1_GATE]		= nuc970_clk_gate("can1_gate", "pclk_div",
+						  REG_CLK_PCLKEN1, 9);
+	clk[TIMER0_GATE]	= nuc970_clk_gate("timer0_gate", "xin",
+						  REG_CLK_PCLKEN0, 8);
+	clk[TIMER1_GATE]	= nuc970_clk_gate("timer1_gate", "xin",
+						  REG_CLK_PCLKEN0, 9);
+	clk[TIMER2_GATE]	= nuc970_clk_gate("timer2_gate", "xin",
+						  REG_CLK_PCLKEN0, 10);
+	clk[TIMER3_GATE]	= nuc970_clk_gate("timer3_gate", "xin",
+						  REG_CLK_PCLKEN0, 11);
+	clk[TIMER4_GATE]	= nuc970_clk_gate("timer4_gate", "xin",
+						  REG_CLK_PCLKEN0, 12);
+	clk[SMC0_GATE]		= nuc970_clk_gate("smc0_gate", "pclk_div",
+						  REG_CLK_PCLKEN1, 12);
+	clk[SMC1_GATE]		= nuc970_clk_gate("smc1_gate", "pclk_div",
+						  REG_CLK_PCLKEN1, 13);
+
+	for (i = 0; i < ARRAY_SIZE(clk); i++)
+		if (IS_ERR(clk[i]))
+			pr_err("nuc970 clk %d: register failed with %ld\n",
+				i, PTR_ERR(clk[i]));
+
+	clk_data.clks = clk;
+	clk_data.clk_num = ARRAY_SIZE(clk);
+
+	ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+	if (ret)
+		pr_err("Failed to register OF clock provider\n");
+
+	/* Register clock device */
+	clk_register_clkdev(clk[TIMER0_GATE], "timer0", NULL);
+	clk_register_clkdev(clk[TIMER1_GATE], "timer1", NULL);
+	clk_register_clkdev(clk[PCLK4096_DIV], "pclk4096_div", NULL);
+	clk_register_clkdev(clk[XIN], "xin", NULL);
+	clk_register_clkdev(clk[XIN32K], "xin32k", NULL);
+	clk_register_clkdev(clk[APLL], "apll", NULL);
+	clk_register_clkdev(clk[UPLL], "upll", NULL);
+	clk_register_clkdev(clk[SYS_MUX], "sysmux", NULL);
+	clk_register_clkdev(clk[SYS_DIV], "sysdiv", NULL);
+	clk_register_clkdev(clk[XIN128_DIV], "xin128div", NULL);
+	/* CPU */
+	clk_register_clkdev(clk[CPU_DIV], "cpudiv", NULL);
+	clk_register_clkdev(clk[CPU_GATE], "cpu", NULL);
+	/* HCLK1 */
+	clk_register_clkdev(clk[HCLK_GATE], "hclk", NULL);
+	clk_register_clkdev(clk[SRAM_GATE], "sram", NULL);
+	clk_register_clkdev(clk[HCLK1_DIV], "hclk1div", NULL);
+	clk_register_clkdev(clk[DDR_GATE], "ddr_hclk", NULL);
+	clk_register_clkdev(clk[GDMA_GATE], "gdma_hclk", NULL);
+	clk_register_clkdev(clk[EBI_GATE], "ebi_hclk", NULL);
+	clk_register_clkdev(clk[TIC_GATE], "tic_hclk", NULL);
+	/* HCLK234 */
+	clk_register_clkdev(clk[HCLKN_DIV], "hclkndiv", NULL);
+	clk_register_clkdev(clk[DRAM_GATE], "dram", NULL);
+	clk_register_clkdev(clk[HCLK234_DIV], "hclk234div", NULL);
+	/* HCLK3 */
+	clk_register_clkdev(clk[USBH_GATE], "usbh_hclk", NULL);
+	clk_register_clkdev(clk[EMAC1_GATE], "emac1_hclk", NULL);
+	clk_register_clkdev(clk[EMAC1_ECLK_DIV], "emac1_eclk_div", NULL);
+	clk_register_clkdev(clk[EMAC1_ECLK_GATE], "emac1_eclk", NULL);
+	clk_register_clkdev(clk[USBD_GATE], "usbd_hclk", NULL);
+	clk_register_clkdev(clk[FMI_GATE], "fmi_hclk", NULL);
+	clk_register_clkdev(clk[NAND_GATE], "nand_hclk", NULL);
+	clk_register_clkdev(clk[EMMC_GATE], "emmc_hclk", NULL);
+	clk_register_clkdev(clk[CRYPTO_GATE], "crypto_hclk", NULL);
+	clk_register_clkdev(clk[JPEG_GATE], "jpeg_hclk", NULL);
+	clk_register_clkdev(clk[JPEG_ECLK_DIV], "jpeg_eclk_div", NULL);
+	clk_register_clkdev(clk[JPEG_ECLK_GATE], "jpeg_eclk", NULL);
+	clk_register_clkdev(clk[GE2D_GATE], "ge2d_hclk", NULL);
+	clk_register_clkdev(clk[GE2D_ECLK_DIV], "ge2d_eclk_div", NULL);
+	clk_register_clkdev(clk[GE2D_ECLK_GATE], "ge2d_eclk", NULL);
+	/* HCLK4 */
+	clk_register_clkdev(clk[EMAC0_GATE], "emac0_hclk", NULL);
+	clk_register_clkdev(clk[EMAC0_ECLK_DIV], "emac0_eclk_div", NULL);
+	clk_register_clkdev(clk[EMAC0_ECLK_GATE], "emac0_eclk", NULL);
+	clk_register_clkdev(clk[SDH_GATE], "sdh_hclk", NULL);
+	clk_register_clkdev(clk[AUDIO_GATE], "audio_hclk", NULL);
+	clk_register_clkdev(clk[LCD_GATE], "lcd_hclk", NULL);
+	clk_register_clkdev(clk[SENSOR_GATE], "sensor_hclk", NULL);
+	clk_register_clkdev(clk[CAP_GATE], "cap_hclk", NULL);
+	/* ECLK */
+	clk_register_clkdev(clk[LCD_APLLDIV], "lcd_aplldiv", NULL);
+	clk_register_clkdev(clk[LCD_UPLLDIV], "lcd_uplldiv", NULL);
+	clk_register_clkdev(clk[LCD_ECLK_MUX], "lcd_eclk_mux", NULL);
+	clk_register_clkdev(clk[LCD_ECLK_DIV], "lcd_eclk_div", NULL);
+	clk_register_clkdev(clk[LCD_ECLK_GATE], "lcd_eclk", NULL);
+	clk_register_clkdev(clk[AUDIO_APLLDIV], "audio_aplldiv", NULL);
+	clk_register_clkdev(clk[AUDIO_UPLLDIV], "audio_uplldiv", NULL);
+	clk_register_clkdev(clk[AUDIO_ECLK_MUX], "audio_eclk_mux", NULL);
+	clk_register_clkdev(clk[AUDIO_ECLK_DIV], "audio_eclk_div", NULL);
+	clk_register_clkdev(clk[AUDIO_ECLK_GATE], "audio_eclk", NULL);
+	clk_register_clkdev(clk[USB_APLLDIV], "usb_aplldiv", NULL);
+	clk_register_clkdev(clk[USB_UPLLDIV], "usb_uplldiv", NULL);
+	clk_register_clkdev(clk[USB_ECLK_MUX], "usb_eclk_mux", NULL);
+	clk_register_clkdev(clk[USB_ECLK_DIV], "usb_eclk_div", NULL);
+	clk_register_clkdev(clk[USB_ECLK_GATE], "usb_eclk", NULL);
+	clk_register_clkdev(clk[SDH_APLLDIV], "sdh_aplldiv", NULL);
+	clk_register_clkdev(clk[SDH_UPLLDIV], "sdh_uplldiv", NULL);
+	clk_register_clkdev(clk[SDH_ECLK_MUX], "sdh_eclk_mux", NULL);
+	clk_register_clkdev(clk[SDH_ECLK_DIV], "sdh_eclk_div", NULL);
+	clk_register_clkdev(clk[SDH_ECLK_GATE], "sdh_eclk", NULL);
+	clk_register_clkdev(clk[EMMC_APLLDIV], "emmc_aplldiv", NULL);
+	clk_register_clkdev(clk[EMMC_UPLLDIV], "emmc_uplldiv", NULL);
+	clk_register_clkdev(clk[EMMC_ECLK_MUX], "emmc_eclk_mux", NULL);
+	clk_register_clkdev(clk[EMMC_ECLK_DIV], "emmc_eclk_div", NULL);
+	clk_register_clkdev(clk[EMMC_ECLK_GATE], "emmc_eclk", NULL);
+	clk_register_clkdev(clk[ADC_APLLDIV], "adc_aplldiv", NULL);
+	clk_register_clkdev(clk[ADC_UPLLDIV], "adc_uplldiv", NULL);
+	clk_register_clkdev(clk[ADC_ECLK_MUX], "adc_eclk_mux", NULL);
+	clk_register_clkdev(clk[ADC_ECLK_DIV], "adc_eclk_div", NULL);
+	clk_register_clkdev(clk[ADC_ECLK_GATE], "adc_eclk", NULL);
+	clk_register_clkdev(clk[CAP_APLLDIV], "cap_aplldiv", NULL);
+	clk_register_clkdev(clk[CAP_UPLLDIV], "cap_uplldiv", NULL);
+	clk_register_clkdev(clk[CAP_ECLK_MUX], "cap_eclk_mux", NULL);
+	clk_register_clkdev(clk[CAP_ECLK_DIV], "cap_eclk_div", NULL);
+	clk_register_clkdev(clk[CAP_ECLK_GATE], "cap_eclk", NULL);
+	clk_register_clkdev(clk[UART0_APLLDIV], "uart0_aplldiv", NULL);
+	clk_register_clkdev(clk[UART0_UPLLDIV], "uart0_uplldiv", NULL);
+	clk_register_clkdev(clk[UART0_ECLK_MUX], "uart0_eclk_mux", NULL);
+	clk_register_clkdev(clk[UART0_ECLK_DIV], "uart0_eclk_div", NULL);
+	clk_register_clkdev(clk[UART0_ECLK_GATE], "uart0_eclk", NULL);
+	clk_register_clkdev(clk[UART1_APLLDIV], "uart1_aplldiv", NULL);
+	clk_register_clkdev(clk[UART1_UPLLDIV], "uart1_uplldiv", NULL);
+	clk_register_clkdev(clk[UART1_ECLK_MUX], "uart1_eclk_mux", NULL);
+	clk_register_clkdev(clk[UART1_ECLK_DIV], "uart1_eclk_div", NULL);
+	clk_register_clkdev(clk[UART1_ECLK_GATE], "uart1_eclk", NULL);
+	clk_register_clkdev(clk[UART2_APLLDIV], "uart2_aplldiv", NULL);
+	clk_register_clkdev(clk[UART2_UPLLDIV], "uart2_uplldiv", NULL);
+	clk_register_clkdev(clk[UART2_ECLK_MUX], "uart2_eclk_mux", NULL);
+	clk_register_clkdev(clk[UART2_ECLK_DIV], "uart2_eclk_div", NULL);
+	clk_register_clkdev(clk[UART2_ECLK_GATE], "uart2_eclk", NULL);
+	clk_register_clkdev(clk[UART3_APLLDIV], "uart3_aplldiv", NULL);
+	clk_register_clkdev(clk[UART3_UPLLDIV], "uart3_uplldiv", NULL);
+	clk_register_clkdev(clk[UART3_ECLK_MUX], "uart3_eclk_mux", NULL);
+	clk_register_clkdev(clk[UART3_ECLK_DIV], "uart3_eclk_div", NULL);
+	clk_register_clkdev(clk[UART3_ECLK_GATE], "uart3_eclk", NULL);
+	clk_register_clkdev(clk[UART4_APLLDIV], "uart4_aplldiv", NULL);
+	clk_register_clkdev(clk[UART4_UPLLDIV], "uart4_uplldiv", NULL);
+	clk_register_clkdev(clk[UART4_ECLK_MUX], "uart4_eclk_mux", NULL);
+	clk_register_clkdev(clk[UART4_ECLK_DIV], "uart4_eclk_div", NULL);
+	clk_register_clkdev(clk[UART4_ECLK_GATE], "uart4_eclk", NULL);
+	clk_register_clkdev(clk[UART5_APLLDIV], "uart5_aplldiv", NULL);
+	clk_register_clkdev(clk[UART5_UPLLDIV], "uart5_uplldiv", NULL);
+	clk_register_clkdev(clk[UART5_ECLK_MUX], "uart5_eclk_mux", NULL);
+	clk_register_clkdev(clk[UART5_ECLK_DIV], "uart5_eclk_div", NULL);
+	clk_register_clkdev(clk[UART5_ECLK_GATE], "uart5_eclk", NULL);
+	clk_register_clkdev(clk[UART6_APLLDIV], "uart6_aplldiv", NULL);
+	clk_register_clkdev(clk[UART6_UPLLDIV], "uart6_uplldiv", NULL);
+	clk_register_clkdev(clk[UART6_ECLK_MUX], "uart6_eclk_mux", NULL);
+	clk_register_clkdev(clk[UART6_ECLK_DIV], "uart6_eclk_div", NULL);
+	clk_register_clkdev(clk[UART6_ECLK_GATE], "uart6_eclk", NULL);
+	clk_register_clkdev(clk[UART7_APLLDIV], "uart7_aplldiv", NULL);
+	clk_register_clkdev(clk[UART7_UPLLDIV], "uart7_uplldiv", NULL);
+	clk_register_clkdev(clk[UART7_ECLK_MUX], "uart7_eclk_mux", NULL);
+	clk_register_clkdev(clk[UART7_ECLK_DIV], "uart7_eclk_div", NULL);
+	clk_register_clkdev(clk[UART7_ECLK_GATE], "uart7_eclk", NULL);
+	clk_register_clkdev(clk[UART8_APLLDIV], "uart8_aplldiv", NULL);
+	clk_register_clkdev(clk[UART8_UPLLDIV], "uart8_uplldiv", NULL);
+	clk_register_clkdev(clk[UART8_ECLK_MUX], "uart8_eclk_mux", NULL);
+	clk_register_clkdev(clk[UART8_ECLK_DIV], "uart8_eclk_div", NULL);
+	clk_register_clkdev(clk[UART8_ECLK_GATE], "uart8_eclk", NULL);
+	clk_register_clkdev(clk[UART9_APLLDIV], "uart9_aplldiv", NULL);
+	clk_register_clkdev(clk[UART9_UPLLDIV], "uart9_uplldiv", NULL);
+	clk_register_clkdev(clk[UART9_ECLK_MUX], "uart9_eclk_mux", NULL);
+	clk_register_clkdev(clk[UART9_ECLK_DIV], "uart9_eclk_div", NULL);
+	clk_register_clkdev(clk[UART9_ECLK_GATE], "uart9_eclk", NULL);
+	clk_register_clkdev(clk[UART10_APLLDIV], "uart10_aplldiv", NULL);
+	clk_register_clkdev(clk[UART10_UPLLDIV], "uart10_uplldiv", NULL);
+	clk_register_clkdev(clk[UART10_ECLK_MUX], "uart10_eclk_mux", NULL);
+	clk_register_clkdev(clk[UART10_ECLK_DIV], "uart10_eclk_div", NULL);
+	clk_register_clkdev(clk[UART10_ECLK_GATE], "uart10_eclk", NULL);
+	clk_register_clkdev(clk[SYSTEM_APLLDIV], "system_aplldiv", NULL);
+	clk_register_clkdev(clk[SYSTEM_UPLLDIV], "system_uplldiv", NULL);
+	clk_register_clkdev(clk[SYSTEM_ECLK_MUX], "system_eclk_mux", NULL);
+	clk_register_clkdev(clk[SYSTEM_ECLK_DIV], "system_eclk_div", NULL);
+	clk_register_clkdev(clk[SYSTEM_ECLK_GATE], "system_eclk", NULL);
+	clk_register_clkdev(clk[GPIO_ECLK_MUX], "gpio_eclk_mux", NULL);
+	clk_register_clkdev(clk[GPIO_ECLK_DIV], "gpio_eclk_div", NULL);
+	clk_register_clkdev(clk[GPIO_ECLK_GATE], "gpio_eclk", NULL);
+	clk_register_clkdev(clk[KPI_ECLK_MUX], "kpi_eclk_mux", NULL);
+	clk_register_clkdev(clk[KPI_ECLK_DIV], "kpi_eclk_div", NULL);
+	clk_register_clkdev(clk[KPI_ECLK_GATE], "kpi_eclk", NULL);
+	clk_register_clkdev(clk[ETIMER0_ECLK_MUX], "etmr0_eclk_mux", NULL);
+	clk_register_clkdev(clk[ETIMER0_ECLK_GATE], "etmr0_eclk", NULL);
+	clk_register_clkdev(clk[ETIMER1_ECLK_MUX], "etmr1_eclk_mux", NULL);
+	clk_register_clkdev(clk[ETIMER1_ECLK_GATE], "etmr1_eclk", NULL);
+	clk_register_clkdev(clk[ETIMER2_ECLK_MUX], "etmr2_eclk_mux", NULL);
+	clk_register_clkdev(clk[ETIMER2_ECLK_GATE], "etmr2_eclk", NULL);
+	clk_register_clkdev(clk[ETIMER3_ECLK_MUX], "etmr3_eclk_mux", NULL);
+	clk_register_clkdev(clk[ETIMER3_ECLK_GATE], "etmr3_eclk", NULL);
+	clk_register_clkdev(clk[WWDT_ECLK_MUX], "wwdt_eclk_mux", NULL);
+	clk_register_clkdev(clk[WWDT_ECLK_GATE], "wwdt_eclk", NULL);
+	clk_register_clkdev(clk[WDT_ECLK_MUX], "wdt_eclk_mux", NULL);
+	clk_register_clkdev(clk[WDT_ECLK_GATE], "wdt_eclk", NULL);
+	clk_register_clkdev(clk[SMC0_ECLK_DIV], "smc0_eclk_div", NULL);
+	clk_register_clkdev(clk[SMC0_ECLK_GATE], "smc0_eclk", NULL);
+	clk_register_clkdev(clk[SMC1_ECLK_DIV], "smc1_eclk_div", NULL);
+	clk_register_clkdev(clk[SMC1_ECLK_GATE], "smc1_eclk", NULL);
+	/* PCLK */
+	clk_register_clkdev(clk[PCLK_DIV], "pclkdiv", NULL);
+	clk_register_clkdev(clk[RTC_GATE], "rtc", NULL);
+	clk_register_clkdev(clk[I2C0_GATE], "i2c0", NULL);
+	clk_register_clkdev(clk[I2C1_GATE], "i2c1", NULL);
+	clk_register_clkdev(clk[SPI0_GATE], "spi0", NULL);
+	clk_register_clkdev(clk[SPI1_GATE], "spi1", NULL);
+	clk_register_clkdev(clk[UART0_GATE], "uart0", NULL);
+	clk_register_clkdev(clk[UART1_GATE], "uart1", NULL);
+	clk_register_clkdev(clk[UART2_GATE], "uart2", NULL);
+	clk_register_clkdev(clk[UART3_GATE], "uart3", NULL);
+	clk_register_clkdev(clk[UART4_GATE], "uart4", NULL);
+	clk_register_clkdev(clk[UART5_GATE], "uart5", NULL);
+	clk_register_clkdev(clk[UART6_GATE], "uart6", NULL);
+	clk_register_clkdev(clk[UART7_GATE], "uart7", NULL);
+	clk_register_clkdev(clk[UART8_GATE], "uart8", NULL);
+	clk_register_clkdev(clk[UART9_GATE], "uart9", NULL);
+	clk_register_clkdev(clk[UART10_GATE], "uart10", NULL);
+	clk_register_clkdev(clk[WDT_GATE], "wdt", NULL);
+	clk_register_clkdev(clk[WWDT_GATE], "wwdt", NULL);
+	clk_register_clkdev(clk[GPIO_GATE], "gpio", NULL);
+	clk_register_clkdev(clk[SMC0_GATE], "smc0", NULL);
+	clk_register_clkdev(clk[SMC1_GATE], "smc1", NULL);
+	clk_register_clkdev(clk[ADC_GATE], "adc", NULL);
+	clk_register_clkdev(clk[KPI_GATE], "kpi", NULL);
+	clk_register_clkdev(clk[MTPC_GATE], "mtpc", NULL);
+	clk_register_clkdev(clk[PWM_GATE], "pwm", NULL);
+	clk_register_clkdev(clk[ETIMER0_GATE], "etimer0", NULL);
+	clk_register_clkdev(clk[ETIMER1_GATE], "etimer1", NULL);
+	clk_register_clkdev(clk[ETIMER2_GATE], "etimer2", NULL);
+	clk_register_clkdev(clk[ETIMER3_GATE], "etimer3", NULL);
+	clk_register_clkdev(clk[TIMER2_GATE], "timer2", NULL);
+	clk_register_clkdev(clk[TIMER3_GATE], "timer3", NULL);
+	clk_register_clkdev(clk[TIMER4_GATE], "timer4", NULL);
+	clk_register_clkdev(clk[CAN0_GATE], "can0", NULL);
+	clk_register_clkdev(clk[CAN1_GATE], "can1", NULL);
+
+	/* enable some important clocks */
+	clk_prepare_enable(clk_get(NULL, "cpu"));
+	clk_prepare_enable(clk_get(NULL, "hclk"));
+	clk_prepare_enable(clk_get(NULL, "sram"));
+	clk_prepare_enable(clk_get(NULL, "dram"));
+	clk_prepare_enable(clk_get(NULL, "ddr_hclk"));
+}
+
+CLK_OF_DECLARE(nuc970_clk, "nuvoton,nuc970-clk", nuc970_clocks_init);
diff --git a/drivers/clk/nuc900/clk-upll.c b/drivers/clk/nuc900/clk-upll.c
new file mode 100644
index 0000000..563fdcd
--- /dev/null
+++ b/drivers/clk/nuc900/clk-upll.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2016 Wan Zongshun <mcuos.com@gmail.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+
+#include "clk-ccf.h"
+
+struct clk_upll {
+	struct clk_hw	hw;
+	void __iomem	*base;
+};
+
+#define to_clk_upll(clk) (container_of(clk, struct clk_upll, clk))
+
+static unsigned long clk_upll_recalc_rate(struct clk_hw *hw,
+					  unsigned long parent_rate)
+{
+	struct clk_upll *pll = to_clk_upll(hw);
+	unsigned long rate;
+	unsigned long reg = readl(pll->base) & 0x0FFFFFFF;
+
+	if (parent_rate != 12000000)
+		return 0;
+
+	switch (reg) {
+	case 0x15:
+		rate = 264000000;
+		break;
+	case 0x18:
+		rate = 300000000;
+		break;
+	default:
+		rate = 264000000;
+		break;
+	}
+
+	return rate;
+}
+
+static struct clk_ops clk_upll_ops = {
+	.recalc_rate = clk_upll_recalc_rate,
+};
+
+struct clk *nuc970_clk_upll(const char *name, const char *parent,
+			    void __iomem *base)
+{
+	struct clk_upll *pll;
+	struct clk *clk;
+	struct clk_init_data init;
+
+	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll)
+		return ERR_PTR(-ENOMEM);
+
+	pll->base = base;
+
+	init.name = name;
+	init.ops = &clk_upll_ops;
+	init.flags = 0;
+	init.parent_names = &parent;
+	init.num_parents = 1;
+
+	pll->hw.init = &init;
+
+	clk = clk_register(NULL, &pll->hw);
+	if (IS_ERR(clk))
+		kfree(pll);
+
+	return clk;
+}
-- 
2.7.4

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

* [PATCH v2 05/10] power/reset: Add reset driver support for nuc900
  2016-07-10  7:27 [PATCH v2 00/10] ARM: NUC900: Add NUC970 SoC support Wan Zongshun
                   ` (3 preceding siblings ...)
  2016-07-10  7:27 ` [PATCH v2 04/10] clk: add Clock driver for nuc970 Wan Zongshun
@ 2016-07-10  7:27 ` Wan Zongshun
  2016-07-10 21:56   ` Paul Gortmaker
  2016-07-10  7:27 ` [PATCH v2 06/10] soc: Add SoC specific " Wan Zongshun
  2016-07-10  7:27 ` [PATCH v2 07/10] ARM: dts: Add clock header file into dt-bindings Wan Zongshun
  6 siblings, 1 reply; 45+ messages in thread
From: Wan Zongshun @ 2016-07-10  7:27 UTC (permalink / raw)
  To: linux-arm-kernel

This driver is to add reset support for nuc900 series,
currently, it only supports nuc970 SoC reset.

Signed-off-by: Wan Zongshun <mcuos.com@gmail.com>
---
 drivers/power/reset/Kconfig        |  7 +++
 drivers/power/reset/Makefile       |  1 +
 drivers/power/reset/nuc900-reset.c | 93 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 101 insertions(+)
 create mode 100644 drivers/power/reset/nuc900-reset.c

diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index 9bb2622..8c84892 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -94,6 +94,13 @@ config POWER_RESET_MSM
 	help
 	  Power off and restart support for Qualcomm boards.
 
+config POWER_RESET_NUC900
+	bool "Nuc900 restart driver"
+	depends on ARCH_W90X900
+	help
+	  Power off and restart support for Nuvoton NUC900 family of
+	  reference boards.
+
 config POWER_RESET_LTC2952
 	bool "LTC2952 PowerPath power-off driver"
 	depends on OF_GPIO
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index ab7aa86..d4df889 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o
 obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o
 obj-$(CONFIG_POWER_RESET_IMX) += imx-snvs-poweroff.o
 obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o
+obj-$(CONFIG_POWER_RESET_NUC900) += nuc900-reset.o
 obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o
 obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
 obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o
diff --git a/drivers/power/reset/nuc900-reset.c b/drivers/power/reset/nuc900-reset.c
new file mode 100644
index 0000000..49986b7
--- /dev/null
+++ b/drivers/power/reset/nuc900-reset.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2016 Wan Zongshun <mcuos.com@gmail.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <linux/regmap.h>
+
+#define REG_WRPRTR	0x1fc
+#define REG_AHBIPRST	0x060
+
+static struct regmap *syscon;
+
+static int nuc900_restart_handler(struct notifier_block *this,
+				  unsigned long mode, void *cmd)
+{
+	/*0:register protect enable*/
+	int write_protect = 0;
+
+	/*register protection disable*/
+	do {
+		regmap_read(syscon, REG_WRPRTR, &write_protect);
+
+		if (write_protect != 1) {
+			regmap_write(syscon, REG_WRPRTR, 0x59);
+			regmap_write(syscon, REG_WRPRTR, 0x16);
+			regmap_write(syscon, REG_WRPRTR, 0x88);
+		}
+
+	} while (write_protect != 1);
+
+	/*trigger reset*/
+	regmap_write(syscon, REG_AHBIPRST, 0x01);
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block nuc900_restart_nb = {
+	.notifier_call = nuc900_restart_handler,
+	.priority = 128,
+};
+
+static int nuc900_reset_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	int err;
+
+	syscon = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon");
+	if (IS_ERR(syscon)) {
+		pr_err("%s: syscon lookup failed\n", dev->of_node->name);
+		return PTR_ERR(syscon);
+	}
+
+	err = register_restart_handler(&nuc900_restart_nb);
+	if (err)
+		dev_err(dev, "cannot register restart handler (err=%d)\n", err);
+
+	return err;
+}
+
+static const struct of_device_id of_nuc900_reset_match[] = {
+	{ .compatible = "nuvoton,nuc900-reset", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, of_nuc900_reset_match);
+
+static struct platform_driver nuc900_reset_driver = {
+	.probe = nuc900_reset_probe,
+	.driver = {
+		.name = "nuc900-reset",
+		.of_match_table = of_match_ptr(of_nuc900_reset_match),
+	},
+};
+
+static int __init nuc900_reset_init(void)
+{
+	return platform_driver_register(&nuc900_reset_driver);
+}
+device_initcall(nuc900_reset_init);
-- 
2.7.4

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

* [PATCH v2 06/10] soc: Add SoC specific driver support for nuc900
  2016-07-10  7:27 [PATCH v2 00/10] ARM: NUC900: Add NUC970 SoC support Wan Zongshun
                   ` (4 preceding siblings ...)
  2016-07-10  7:27 ` [PATCH v2 05/10] power/reset: Add reset driver support for nuc900 Wan Zongshun
@ 2016-07-10  7:27 ` Wan Zongshun
  2016-07-11  8:03   ` Arnd Bergmann
  2016-07-10  7:27 ` [PATCH v2 07/10] ARM: dts: Add clock header file into dt-bindings Wan Zongshun
  6 siblings, 1 reply; 45+ messages in thread
From: Wan Zongshun @ 2016-07-10  7:27 UTC (permalink / raw)
  To: linux-arm-kernel

This patch is to add SoC specific driver for nuc970 SoC,
it is for getting nuc970 version id and chip id.

Signed-off-by: Wan Zongshun <mcuos.com@gmail.com>
---
 drivers/soc/Kconfig              |   1 +
 drivers/soc/Makefile             |   1 +
 drivers/soc/nuvoton/Kconfig      |  10 ++++
 drivers/soc/nuvoton/Makefile     |   1 +
 drivers/soc/nuvoton/soc-nuc900.c | 100 +++++++++++++++++++++++++++++++++++++++
 5 files changed, 113 insertions(+)
 create mode 100644 drivers/soc/nuvoton/Kconfig
 create mode 100644 drivers/soc/nuvoton/Makefile
 create mode 100644 drivers/soc/nuvoton/soc-nuc900.c

diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig
index cb58ef0..2119733 100644
--- a/drivers/soc/Kconfig
+++ b/drivers/soc/Kconfig
@@ -4,6 +4,7 @@ source "drivers/soc/bcm/Kconfig"
 source "drivers/soc/brcmstb/Kconfig"
 source "drivers/soc/fsl/qe/Kconfig"
 source "drivers/soc/mediatek/Kconfig"
+source "drivers/soc/nuvoton/Kconfig"
 source "drivers/soc/qcom/Kconfig"
 source "drivers/soc/rockchip/Kconfig"
 source "drivers/soc/samsung/Kconfig"
diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index 380230f..bb1bfba 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_ARCH_DOVE)		+= dove/
 obj-$(CONFIG_MACH_DOVE)		+= dove/
 obj-y				+= fsl/
 obj-$(CONFIG_ARCH_MEDIATEK)	+= mediatek/
+obj-$(CONFIG_SOC_NUC900)	+= nuvoton/
 obj-$(CONFIG_ARCH_QCOM)		+= qcom/
 obj-$(CONFIG_ARCH_RENESAS)	+= renesas/
 obj-$(CONFIG_ARCH_ROCKCHIP)	+= rockchip/
diff --git a/drivers/soc/nuvoton/Kconfig b/drivers/soc/nuvoton/Kconfig
new file mode 100644
index 0000000..53c106c
--- /dev/null
+++ b/drivers/soc/nuvoton/Kconfig
@@ -0,0 +1,10 @@
+#
+# ARM Versatile SoC drivers
+#
+config SOC_NUC900
+	bool "SoC bus device for the nuvoton NUC900 platforms"
+	depends on ARCH_W90X900
+	select SOC_BUS
+	help
+	  Include support for the SoC bus on the NUC900 platforms
+	  providing some sysfs information about the ASIC variant.
diff --git a/drivers/soc/nuvoton/Makefile b/drivers/soc/nuvoton/Makefile
new file mode 100644
index 0000000..88f9b7e
--- /dev/null
+++ b/drivers/soc/nuvoton/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_SOC_NUC900)	+= soc-nuc900.o
diff --git a/drivers/soc/nuvoton/soc-nuc900.c b/drivers/soc/nuvoton/soc-nuc900.c
new file mode 100644
index 0000000..034ef94
--- /dev/null
+++ b/drivers/soc/nuvoton/soc-nuc900.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2016 Wan Zongshun <mcuos.com@gmail.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/sys_soc.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/of.h>
+
+/* System ID in syscon */
+#define GCR_CHIPID		0x00
+#define GCR_CHIPID_MASK		0x00ffffff
+
+static const struct of_device_id nuc900_soc_of_match[] = {
+	{ .compatible = "nuvoton,nuc900-soc",	},
+	{ }
+};
+
+static u32 nuc900_chipid;
+
+static ssize_t nuc900_get_chipid(struct device *dev,
+				 struct device_attribute *attr,
+				 char *buf)
+{
+	return sprintf(buf, "0x%x\n", nuc900_chipid & GCR_CHIPID_MASK);
+}
+
+static struct device_attribute nuc900_chipid_attr =
+	__ATTR(manufacturer,  S_IRUGO, nuc900_get_chipid,  NULL);
+
+static ssize_t nuc900_get_versionid(struct device *dev,
+			      struct device_attribute *attr,
+			      char *buf)
+{
+	return sprintf(buf, "0x%x\n", (nuc900_chipid >> 24) & 0xff);
+}
+
+static struct device_attribute nuc900_version_attr =
+	__ATTR(board,  S_IRUGO, nuc900_get_versionid,  NULL);
+
+static int nuc900_soc_probe(struct platform_device *pdev)
+{
+	static struct regmap *syscon_regmap;
+	struct soc_device *soc_dev;
+	struct soc_device_attribute *soc_dev_attr;
+	struct device_node *np = pdev->dev.of_node;
+	int ret;
+
+	syscon_regmap = syscon_regmap_lookup_by_phandle(np, "syscon");
+	if (IS_ERR(syscon_regmap))
+		return PTR_ERR(syscon_regmap);
+
+	soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
+	if (!soc_dev_attr)
+		return -ENOMEM;
+
+	ret = of_property_read_string(np, "compatible", &soc_dev_attr->soc_id);
+	if (ret)
+		return -EINVAL;
+
+	soc_dev_attr->machine = "NUC900EVB";
+	soc_dev_attr->family = "NUC900";
+	soc_dev = soc_device_register(soc_dev_attr);
+	if (IS_ERR(soc_dev)) {
+		kfree(soc_dev_attr);
+		return -ENODEV;
+	}
+
+	ret = regmap_read(syscon_regmap, GCR_CHIPID, &nuc900_chipid);
+	if (ret)
+		return -ENODEV;
+
+	device_create_file(soc_device_to_device(soc_dev), &nuc900_chipid_attr);
+	device_create_file(soc_device_to_device(soc_dev), &nuc900_version_attr);
+
+	dev_info(&pdev->dev, "Nuvoton Chip ID: 0x%x, Version ID:0x%x\n",
+		 nuc900_chipid & GCR_CHIPID_MASK,
+		 (nuc900_chipid >> 24) & 0xff);
+
+	return 0;
+}
+
+static struct platform_driver nuc900_soc_driver = {
+	.probe = nuc900_soc_probe,
+	.driver = {
+		.name = "nuc900-soc",
+		.of_match_table = nuc900_soc_of_match,
+	},
+};
+builtin_platform_driver(nuc900_soc_driver);
-- 
2.7.4

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

* [PATCH v2 07/10] ARM: dts: Add clock header file into dt-bindings
  2016-07-10  7:27 [PATCH v2 00/10] ARM: NUC900: Add NUC970 SoC support Wan Zongshun
                   ` (5 preceding siblings ...)
  2016-07-10  7:27 ` [PATCH v2 06/10] soc: Add SoC specific " Wan Zongshun
@ 2016-07-10  7:27 ` Wan Zongshun
  6 siblings, 0 replies; 45+ messages in thread
From: Wan Zongshun @ 2016-07-10  7:27 UTC (permalink / raw)
  To: linux-arm-kernel

This patch is to add nuc970 clock Macros header file
into include/dt-bindings/clock.

Signed-off-by: Wan Zongshun <mcuos.com@gmail.com>
---
 include/dt-bindings/clock/nuc970-clock.h | 233 +++++++++++++++++++++++++++++++
 1 file changed, 233 insertions(+)
 create mode 100644 include/dt-bindings/clock/nuc970-clock.h

diff --git a/include/dt-bindings/clock/nuc970-clock.h b/include/dt-bindings/clock/nuc970-clock.h
new file mode 100644
index 0000000..cbfcc77
--- /dev/null
+++ b/include/dt-bindings/clock/nuc970-clock.h
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2016 Wan Zongshun <mcuos.com@gmail.com>
+ *
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_NUC970_H
+#define __DT_BINDINGS_CLOCK_NUC970_H
+
+/*SOURCE*/
+
+#define	XIN			0
+#define	APLL			1
+#define	UPLL			2
+#define	XIN32K			3
+#define	XIN128_DIV		4
+
+/*ECLK*/
+
+#define	USB_APLLDIV		5
+#define	USB_UPLLDIV		6
+#define	USB_ECLK_MUX		7
+#define	USB_ECLK_DIV		8
+#define	USB_ECLK_GATE		9
+#define	SD_APLLDIV		10
+#define	SD_UPLLDIV		11
+#define	SD_ECLK_MUX		12
+#define	SD_ECLK_DIV		13
+#define	SD_ECLK_GATE		14
+#define	LCD_APLLDIV		15
+#define	LCD_UPLLDIV		16
+#define	LCD_ECLK_MUX		17
+#define	LCD_ECLK_DIV		18
+#define	LCD_ECLK_GATE		19
+#define	ADC_APLLDIV		20
+#define	ADC_UPLLDIV		21
+#define	ADC_ECLK_MUX		22
+#define	ADC_ECLK_DIV		23
+#define	ADC_ECLK_GATE		24
+#define	AUDIO_APLLDIV		25
+#define	AUDIO_UPLLDIV		26
+#define	AUDIO_ECLK_MUX		27
+#define	AUDIO_ECLK_DIV		28
+#define	AUDIO_ECLK_GATE		29
+#define	CAP_APLLDIV		30
+#define	CAP_UPLLDIV		31
+#define	CAP_ECLK_MUX		32
+#define	CAP_ECLK_DIV		33
+#define	CAP_ECLK_GATE		34
+#define	SDH_APLLDIV		35
+#define	SDH_UPLLDIV		36
+#define	SDH_ECLK_MUX		37
+#define	SDH_ECLK_DIV		38
+#define	SDH_ECLK_GATE		39
+#define	EMMC_APLLDIV		40
+#define	EMMC_UPLLDIV		41
+#define	EMMC_ECLK_MUX		42
+#define	EMMC_ECLK_DIV		43
+#define	EMMC_ECLK_GATE		44
+#define	UART0_APLLDIV		45
+#define	UART0_UPLLDIV		46
+#define	UART0_ECLK_MUX		47
+#define	UART0_ECLK_DIV		48
+#define	UART0_ECLK_GATE		49
+#define	UART1_APLLDIV		50
+#define	UART1_UPLLDIV		51
+#define	UART1_ECLK_MUX		52
+#define	UART1_ECLK_DIV		53
+#define	UART1_ECLK_GATE		54
+#define	UART2_APLLDIV		55
+#define	UART2_UPLLDIV		56
+#define	UART2_ECLK_MUX		57
+#define	UART2_ECLK_DIV		58
+#define	UART2_ECLK_GATE		59
+#define	UART3_APLLDIV		60
+#define	UART3_UPLLDIV		61
+#define	UART3_ECLK_MUX		62
+#define	UART3_ECLK_DIV		63
+#define	UART3_ECLK_GATE		64
+#define	UART4_APLLDIV		65
+#define	UART4_UPLLDIV		66
+#define	UART4_ECLK_MUX		67
+#define	UART4_ECLK_DIV		68
+#define	UART4_ECLK_GATE		69
+#define	UART5_APLLDIV		70
+#define	UART5_UPLLDIV		71
+#define	UART5_ECLK_MUX		72
+#define	UART5_ECLK_DIV		73
+#define	UART5_ECLK_GATE		74
+#define	UART6_APLLDIV		75
+#define	UART6_UPLLDIV		76
+#define	UART6_ECLK_MUX		77
+#define	UART6_ECLK_DIV		78
+#define	UART6_ECLK_GATE		79
+#define	UART7_APLLDIV		80
+#define	UART7_UPLLDIV		81
+#define	UART7_ECLK_MUX		82
+#define	UART7_ECLK_DIV		83
+#define	UART7_ECLK_GATE		84
+#define	UART8_APLLDIV		85
+#define	UART8_UPLLDIV		86
+#define	UART8_ECLK_MUX		87
+#define	UART8_ECLK_DIV		88
+#define	UART8_ECLK_GATE		89
+#define	UART9_APLLDIV		90
+#define	UART9_UPLLDIV		91
+#define	UART9_ECLK_MUX		92
+#define	UART9_ECLK_DIV		93
+#define	UART9_ECLK_GATE		94
+#define	UART10_APLLDIV		95
+#define	UART10_UPLLDIV		96
+#define	UART10_ECLK_MUX		97
+#define	UART10_ECLK_DIV		98
+#define	UART10_ECLK_GATE	99
+#define	SYSTEM_APLLDIV		100
+#define	SYSTEM_UPLLDIV		101
+#define	SYSTEM_ECLK_MUX		102
+#define	SYSTEM_ECLK_DIV		103
+#define	SYSTEM_ECLK_GATE	104
+#define	GPIO_ECLK_MUX		105
+#define	GPIO_ECLK_DIV		106
+#define	GPIO_ECLK_GATE		107
+#define	KPI_ECLK_MUX		108
+#define	KPI_ECLK_DIV		109
+#define	KPI_ECLK_GATE		110
+#define	ETIMER0_ECLK_MUX	111
+#define	ETIMER0_ECLK_GATE	12
+#define	ETIMER1_ECLK_MUX	113
+#define	ETIMER1_ECLK_GATE	114
+#define	ETIMER2_ECLK_MUX	115
+#define	ETIMER2_ECLK_GATE	116
+#define	ETIMER3_ECLK_MUX	117
+#define	ETIMER3_ECLK_GATE	118
+#define	WWDT_ECLK_MUX		119
+#define	WWDT_ECLK_GATE		120
+#define	WDT_ECLK_MUX		121
+#define	WDT_ECLK_GATE		122
+#define	SMC0_ECLK_DIV		123
+#define	SMC0_ECLK_GATE		124
+#define	SMC0_GATE		125
+#define	SMC1_ECLK_DIV		126
+#define	SMC1_ECLK_GATE		127
+#define	SMC1_GATE		128
+
+/*SYS*/
+
+#define	SYS_MUX			129
+#define	SYS_DIV			130
+#define	CPU_DIV			131
+#define	CPU_GATE		132
+#define	DDR_GATE		133
+
+/*HCLK*/
+
+#define	HCLK_GATE		134
+#define	HCLK1_DIV		135
+#define	GDMA_GATE		136
+#define	EBI_GATE		137
+#define	TIC_GATE		138
+#define	SRAM_GATE		139
+#define	HCLKN_DIV		140
+#define	DRAM_GATE		141
+#define	HCLK234_DIV		142
+#define	USBH_GATE		143
+#define	EMAC1_GATE		144
+#define	EMAC1_ECLK_DIV		145
+#define	EMAC1_ECLK_GATE		146
+#define	USBD_GATE		147
+#define	FMI_GATE		148
+#define	NAND_GATE		149
+#define	EMMC_GATE		150
+#define	CRYPTO_GATE		151
+#define	JPEG_GATE		152
+#define	JPEG_ECLK_DIV		153
+#define	JPEG_ECLK_GATE		154
+#define	GE2D_GATE		155
+#define	GE2D_ECLK_DIV		156
+#define	GE2D_ECLK_GATE		157
+#define	EMAC0_GATE		158
+#define	EMAC0_ECLK_DIV		159
+#define	EMAC0_ECLK_GATE		160
+#define	SDH_GATE		161
+#define	AUDIO_GATE		162
+#define	LCD_GATE		163
+#define	CAP_GATE		164
+#define	SENSOR_GATE		165
+
+/*PCLK*/
+
+#define	PCLK_DIV		166
+#define	PCLK4096_DIV		167
+#define	I2C0_GATE		168
+#define	I2C1_GATE		169
+#define	SPI0_GATE		170
+#define	SPI1_GATE		171
+#define	UART0_GATE		172
+#define	UART1_GATE		173
+#define	UART2_GATE		174
+#define	UART3_GATE		175
+#define	UART4_GATE		176
+#define	UART5_GATE		177
+#define	UART6_GATE		178
+#define	UART7_GATE		179
+#define	UART8_GATE		180
+#define	UART9_GATE		181
+#define	UART10_GATE		182
+#define	TIMER0_GATE		183
+#define	TIMER1_GATE		184
+#define	TIMER2_GATE		185
+#define	TIMER3_GATE		186
+#define	TIMER4_GATE		187
+#define	WDT_GATE		188
+#define	RTC_GATE		189
+#define	WWDT_GATE		190
+#define	GPIO_GATE		191
+#define	ADC_GATE		192
+#define	KPI_GATE		193
+#define	MTPC_GATE		194
+#define	PWM_GATE		195
+#define	ETIMER0_GATE		196
+#define	ETIMER1_GATE		197
+#define	ETIMER2_GATE		198
+#define	ETIMER3_GATE		199
+#define	CAN0_GATE		200
+#define	CAN1_GATE		201
+#define	NUC970_CLK_MAX		202
+
+#endif
-- 
2.7.4

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

* [PATCH v2 02/10] irqchip: add irqchip driver for nuc900
  2016-07-10  7:27 ` [PATCH v2 02/10] irqchip: add irqchip driver for nuc900 Wan Zongshun
@ 2016-07-10 21:51   ` Paul Gortmaker
  2016-07-11  2:19     ` Wan Zongshun
  2016-07-11 15:46   ` Arnd Bergmann
  2016-07-13 20:09   ` Jason Cooper
  2 siblings, 1 reply; 45+ messages in thread
From: Paul Gortmaker @ 2016-07-10 21:51 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, Jul 10, 2016 at 3:27 AM, Wan Zongshun <vw@iommu.org> wrote:
> This patch is to add irqchip driver support for nuc900 plat,
> current this driver only supports nuc970 SoC.
>
> Signed-off-by: Wan Zongshun <mcuos.com@gmail.com>
> ---
>  arch/arm/mach-w90x900/include/mach/irqs.h |   5 +
>  drivers/irqchip/Makefile                  |   1 +
>  drivers/irqchip/irq-nuc900.c              | 150 ++++++++++++++++++++++++++++++
>  3 files changed, 156 insertions(+)
>  create mode 100644 drivers/irqchip/irq-nuc900.c
>
> diff --git a/arch/arm/mach-w90x900/include/mach/irqs.h b/arch/arm/mach-w90x900/include/mach/irqs.h
> index 9d5cba3..3b035c6 100644
> --- a/arch/arm/mach-w90x900/include/mach/irqs.h
> +++ b/arch/arm/mach-w90x900/include/mach/irqs.h
> @@ -59,7 +59,12 @@
>  #define IRQ_KPI                W90X900_IRQ(29)
>  #define IRQ_P2SGROUP   W90X900_IRQ(30)
>  #define IRQ_ADC                W90X900_IRQ(31)
> +
> +#if !defined(CONFIG_SOC_NUC900)
>  #define NR_IRQS                (IRQ_ADC+1)
> +#else
> +#define NR_IRQS                62
> +#endif
>
>  /*for irq group*/
>
> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
> index 38853a1..9ccd5af8a 100644
> --- a/drivers/irqchip/Makefile
> +++ b/drivers/irqchip/Makefile
> @@ -69,3 +69,4 @@ obj-$(CONFIG_PIC32_EVIC)              += irq-pic32-evic.o
>  obj-$(CONFIG_MVEBU_ODMI)               += irq-mvebu-odmi.o
>  obj-$(CONFIG_LS_SCFG_MSI)              += irq-ls-scfg-msi.o
>  obj-$(CONFIG_EZNPS_GIC)                        += irq-eznps.o
> +obj-$(CONFIG_SOC_NUC970)               += irq-nuc900.o
> diff --git a/drivers/irqchip/irq-nuc900.c b/drivers/irqchip/irq-nuc900.c
> new file mode 100644
> index 0000000..c4b2e39
> --- /dev/null
> +++ b/drivers/irqchip/irq-nuc900.c
> @@ -0,0 +1,150 @@
> +/*
> + * Copyright 2016 Wan Zongshun <mcuos.com@gmail.com>
> + *
> + * The code contained herein is licensed under the GNU General Public
> + * License. You may obtain a copy of the GNU General Public License
> + * Version 2 or later at the following locations:
> + *
> + * http://www.opensource.org/licenses/gpl-license.html
> + * http://www.gnu.org/copyleft/gpl.html
> + */
> +
> +#include <linux/module.h>

Why do you include module.h when I don't see anything modular in
this driver?

Paul.
--

> +#include <linux/init.h>
> +#include <linux/irq.h>
> +#include <linux/irqchip.h>
> +#include <linux/irqdomain.h>
> +#include <linux/io.h>
> +#include <linux/ioport.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +
> +#include <asm/exception.h>
> +#include <asm/hardirq.h>
> +

[...]

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

* [PATCH v2 05/10] power/reset: Add reset driver support for nuc900
  2016-07-10  7:27 ` [PATCH v2 05/10] power/reset: Add reset driver support for nuc900 Wan Zongshun
@ 2016-07-10 21:56   ` Paul Gortmaker
  2016-07-11  2:30     ` Wan Zongshun
  0 siblings, 1 reply; 45+ messages in thread
From: Paul Gortmaker @ 2016-07-10 21:56 UTC (permalink / raw)
  To: linux-arm-kernel

On Sun, Jul 10, 2016 at 3:27 AM, Wan Zongshun <vw@iommu.org> wrote
> This driver is to add reset support for nuc900 series,
> currently, it only supports nuc970 SoC reset.
>
> Signed-off-by: Wan Zongshun <mcuos.com@gmail.com>
> ---
>  drivers/power/reset/Kconfig        |  7 +++
>  drivers/power/reset/Makefile       |  1 +
>  drivers/power/reset/nuc900-reset.c | 93 ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 101 insertions(+)
>  create mode 100644 drivers/power/reset/nuc900-reset.c
>
> diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
> index 9bb2622..8c84892 100644
> --- a/drivers/power/reset/Kconfig
> +++ b/drivers/power/reset/Kconfig
> @@ -94,6 +94,13 @@ config POWER_RESET_MSM
>         help
>           Power off and restart support for Qualcomm boards.
>
> +config POWER_RESET_NUC900
> +       bool "Nuc900 restart driver"

If this driver is bool and not tristate, then please remove all references
to MODULE_<xyz> and then the module.h include as well.

Thanks,
Paul.
--

> +       depends on ARCH_W90X900
> +       help
> +         Power off and restart support for Nuvoton NUC900 family of
> +         reference boards.
> +
>  config POWER_RESET_LTC2952
>         bool "LTC2952 PowerPath power-off driver"
>         depends on OF_GPIO
> diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
> index ab7aa86..d4df889 100644
> --- a/drivers/power/reset/Makefile
> +++ b/drivers/power/reset/Makefile
> @@ -9,6 +9,7 @@ obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o
>  obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o
>  obj-$(CONFIG_POWER_RESET_IMX) += imx-snvs-poweroff.o
>  obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o
> +obj-$(CONFIG_POWER_RESET_NUC900) += nuc900-reset.o
>  obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o
>  obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
>  obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o
> diff --git a/drivers/power/reset/nuc900-reset.c b/drivers/power/reset/nuc900-reset.c
> new file mode 100644
> index 0000000..49986b7
> --- /dev/null
> +++ b/drivers/power/reset/nuc900-reset.c
> @@ -0,0 +1,93 @@
> +/*
> + * Copyright 2016 Wan Zongshun <mcuos.com@gmail.com>
> + *
> + * The code contained herein is licensed under the GNU General Public
> + * License. You may obtain a copy of the GNU General Public License
> + * Version 2 or later at the following locations:
> + *
> + * http://www.opensource.org/licenses/gpl-license.html
> + * http://www.gnu.org/copyleft/gpl.html
> + */
> +#include <linux/init.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/notifier.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/reboot.h>
> +#include <linux/regmap.h>
>

[...]

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

* [PATCH v2 01/10] ARM: NUC900: Add nuc970 machine support
  2016-07-10  7:27 ` [PATCH v2 01/10] ARM: NUC900: Add nuc970 machine support Wan Zongshun
@ 2016-07-10 22:11   ` Arnd Bergmann
  2016-07-11 16:04   ` Arnd Bergmann
  1 sibling, 0 replies; 45+ messages in thread
From: Arnd Bergmann @ 2016-07-10 22:11 UTC (permalink / raw)
  To: linux-arm-kernel

On Sunday, July 10, 2016 3:27:21 PM CEST Wan Zongshun wrote:
> +
> +#include <linux/platform_device.h>
> +#include <linux/clk.h>
> +#include <linux/clkdev.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/gpio.h>
> +#include <linux/init.h>
> +#include <linux/reboot.h>
> +#include <linux/of_address.h>
> +#include <linux/of_platform.h>
> +#include <linux/sys_soc.h>
> +#include <linux/semaphore.h>
> +
> +#include <asm/system_misc.h>
> +#include <asm/mach/arch.h>
> +
> +static void __init nuc900_machine_init(void)
> +{
> +       of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
> +}


This is the default for .init_machine, so you can leave the function
undefined.

> +static const char *nuc900_dt_compat[] __initconst = {
> +       "nuvoton,nuc970",
> +       NULL,
> +};
> +
> +DT_MACHINE_START(nuc900_dt, "Nuvoton NUC900 (Device Tree Support)")
> +       .init_machine   = nuc900_machine_init,
> +       .dt_compat      = nuc900_dt_compat,
> +MACHINE_END
> 

After that, you can probably remove most of the #include statements.
The file is still needed for now, until you move to ARCH_MULTIPLATFORM,
at which point the entire machine descriptor is redundant.

	Arnd

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

* [PATCH v2 02/10] irqchip: add irqchip driver for nuc900
  2016-07-10 21:51   ` Paul Gortmaker
@ 2016-07-11  2:19     ` Wan Zongshun
  0 siblings, 0 replies; 45+ messages in thread
From: Wan Zongshun @ 2016-07-11  2:19 UTC (permalink / raw)
  To: linux-arm-kernel



On 2016?07?11? 05:51, Paul Gortmaker wrote:
> On Sun, Jul 10, 2016 at 3:27 AM, Wan Zongshun <vw@iommu.org> wrote:
>> This patch is to add irqchip driver support for nuc900 plat,
>> current this driver only supports nuc970 SoC.
>>
>> Signed-off-by: Wan Zongshun <mcuos.com@gmail.com>
>> ---
>>   arch/arm/mach-w90x900/include/mach/irqs.h |   5 +
>>   drivers/irqchip/Makefile                  |   1 +
>>   drivers/irqchip/irq-nuc900.c              | 150 ++++++++++++++++++++++++++++++
>>   3 files changed, 156 insertions(+)
>>   create mode 100644 drivers/irqchip/irq-nuc900.c
>>
>> diff --git a/arch/arm/mach-w90x900/include/mach/irqs.h b/arch/arm/mach-w90x900/include/mach/irqs.h
>> index 9d5cba3..3b035c6 100644
>> --- a/arch/arm/mach-w90x900/include/mach/irqs.h
>> +++ b/arch/arm/mach-w90x900/include/mach/irqs.h
>> @@ -59,7 +59,12 @@
>>   #define IRQ_KPI                W90X900_IRQ(29)
>>   #define IRQ_P2SGROUP   W90X900_IRQ(30)
>>   #define IRQ_ADC                W90X900_IRQ(31)
>> +
>> +#if !defined(CONFIG_SOC_NUC900)
>>   #define NR_IRQS                (IRQ_ADC+1)
>> +#else
>> +#define NR_IRQS                62
>> +#endif
>>
>>   /*for irq group*/
>>
>> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
>> index 38853a1..9ccd5af8a 100644
>> --- a/drivers/irqchip/Makefile
>> +++ b/drivers/irqchip/Makefile
>> @@ -69,3 +69,4 @@ obj-$(CONFIG_PIC32_EVIC)              += irq-pic32-evic.o
>>   obj-$(CONFIG_MVEBU_ODMI)               += irq-mvebu-odmi.o
>>   obj-$(CONFIG_LS_SCFG_MSI)              += irq-ls-scfg-msi.o
>>   obj-$(CONFIG_EZNPS_GIC)                        += irq-eznps.o
>> +obj-$(CONFIG_SOC_NUC970)               += irq-nuc900.o
>> diff --git a/drivers/irqchip/irq-nuc900.c b/drivers/irqchip/irq-nuc900.c
>> new file mode 100644
>> index 0000000..c4b2e39
>> --- /dev/null
>> +++ b/drivers/irqchip/irq-nuc900.c
>> @@ -0,0 +1,150 @@
>> +/*
>> + * Copyright 2016 Wan Zongshun <mcuos.com@gmail.com>
>> + *
>> + * The code contained herein is licensed under the GNU General Public
>> + * License. You may obtain a copy of the GNU General Public License
>> + * Version 2 or later at the following locations:
>> + *
>> + * http://www.opensource.org/licenses/gpl-license.html
>> + * http://www.gnu.org/copyleft/gpl.html
>> + */
>> +
>> +#include <linux/module.h>
>
> Why do you include module.h when I don't see anything modular in
> this driver?

Okay, I can delete it.

>
> Paul.
> --
>
>> +#include <linux/init.h>
>> +#include <linux/irq.h>
>> +#include <linux/irqchip.h>
>> +#include <linux/irqdomain.h>
>> +#include <linux/io.h>
>> +#include <linux/ioport.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_irq.h>
>> +
>> +#include <asm/exception.h>
>> +#include <asm/hardirq.h>
>> +
>
> [...]
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
>

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

* [PATCH v2 05/10] power/reset: Add reset driver support for nuc900
  2016-07-10 21:56   ` Paul Gortmaker
@ 2016-07-11  2:30     ` Wan Zongshun
  2016-07-11  2:58       ` Paul Gortmaker
  0 siblings, 1 reply; 45+ messages in thread
From: Wan Zongshun @ 2016-07-11  2:30 UTC (permalink / raw)
  To: linux-arm-kernel



On 2016?07?11? 05:56, Paul Gortmaker wrote:
> On Sun, Jul 10, 2016 at 3:27 AM, Wan Zongshun <vw@iommu.org> wrote
>> This driver is to add reset support for nuc900 series,
>> currently, it only supports nuc970 SoC reset.
>>
>> Signed-off-by: Wan Zongshun <mcuos.com@gmail.com>
>> ---
>>   drivers/power/reset/Kconfig        |  7 +++
>>   drivers/power/reset/Makefile       |  1 +
>>   drivers/power/reset/nuc900-reset.c | 93 ++++++++++++++++++++++++++++++++++++++
>>   3 files changed, 101 insertions(+)
>>   create mode 100644 drivers/power/reset/nuc900-reset.c
>>
>> diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
>> index 9bb2622..8c84892 100644
>> --- a/drivers/power/reset/Kconfig
>> +++ b/drivers/power/reset/Kconfig
>> @@ -94,6 +94,13 @@ config POWER_RESET_MSM
>>          help
>>            Power off and restart support for Qualcomm boards.
>>
>> +config POWER_RESET_NUC900
>> +       bool "Nuc900 restart driver"
>
> If this driver is bool and not tristate, then please remove all references
> to MODULE_<xyz> and then the module.h include as well.

I will remove the following codes in my reset.c driver.

MODULE_DEVICE_TABLE(of, of_nuc900_reset_match);
#include <linux/module.h>


>
> Thanks,
> Paul.
> --
>
>> +       depends on ARCH_W90X900
>> +       help
>> +         Power off and restart support for Nuvoton NUC900 family of
>> +         reference boards.
>> +
>>   config POWER_RESET_LTC2952
>>          bool "LTC2952 PowerPath power-off driver"
>>          depends on OF_GPIO
>> diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
>> index ab7aa86..d4df889 100644
>> --- a/drivers/power/reset/Makefile
>> +++ b/drivers/power/reset/Makefile
>> @@ -9,6 +9,7 @@ obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o
>>   obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o
>>   obj-$(CONFIG_POWER_RESET_IMX) += imx-snvs-poweroff.o
>>   obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o
>> +obj-$(CONFIG_POWER_RESET_NUC900) += nuc900-reset.o
>>   obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o
>>   obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
>>   obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o
>> diff --git a/drivers/power/reset/nuc900-reset.c b/drivers/power/reset/nuc900-reset.c
>> new file mode 100644
>> index 0000000..49986b7
>> --- /dev/null
>> +++ b/drivers/power/reset/nuc900-reset.c
>> @@ -0,0 +1,93 @@
>> +/*
>> + * Copyright 2016 Wan Zongshun <mcuos.com@gmail.com>
>> + *
>> + * The code contained herein is licensed under the GNU General Public
>> + * License. You may obtain a copy of the GNU General Public License
>> + * Version 2 or later at the following locations:
>> + *
>> + * http://www.opensource.org/licenses/gpl-license.html
>> + * http://www.gnu.org/copyleft/gpl.html
>> + */
>> +#include <linux/init.h>
>> +#include <linux/err.h>
>> +#include <linux/io.h>
>> +#include <linux/kernel.h>
>> +#include <linux/mfd/syscon.h>
>> +#include <linux/module.h>
>> +#include <linux/notifier.h>
>> +#include <linux/of.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/reboot.h>
>> +#include <linux/regmap.h>
>>
>
> [...]
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
>

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

* [PATCH v2 05/10] power/reset: Add reset driver support for nuc900
  2016-07-11  2:30     ` Wan Zongshun
@ 2016-07-11  2:58       ` Paul Gortmaker
  0 siblings, 0 replies; 45+ messages in thread
From: Paul Gortmaker @ 2016-07-11  2:58 UTC (permalink / raw)
  To: linux-arm-kernel

[Re: [PATCH v2 05/10] power/reset: Add reset driver support for nuc900] On 11/07/2016 (Mon 10:30) Wan Zongshun wrote:

> 
> 
> On 2016?07?11? 05:56, Paul Gortmaker wrote:
> >On Sun, Jul 10, 2016 at 3:27 AM, Wan Zongshun <vw@iommu.org> wrote
> >>This driver is to add reset support for nuc900 series,
> >>currently, it only supports nuc970 SoC reset.
> >>
> >>Signed-off-by: Wan Zongshun <mcuos.com@gmail.com>
> >>---
> >>  drivers/power/reset/Kconfig        |  7 +++
> >>  drivers/power/reset/Makefile       |  1 +
> >>  drivers/power/reset/nuc900-reset.c | 93 ++++++++++++++++++++++++++++++++++++++
> >>  3 files changed, 101 insertions(+)
> >>  create mode 100644 drivers/power/reset/nuc900-reset.c
> >>
> >>diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
> >>index 9bb2622..8c84892 100644
> >>--- a/drivers/power/reset/Kconfig
> >>+++ b/drivers/power/reset/Kconfig
> >>@@ -94,6 +94,13 @@ config POWER_RESET_MSM
> >>         help
> >>           Power off and restart support for Qualcomm boards.
> >>
> >>+config POWER_RESET_NUC900
> >>+       bool "Nuc900 restart driver"
> >
> >If this driver is bool and not tristate, then please remove all references
> >to MODULE_<xyz> and then the module.h include as well.
> 
> I will remove the following codes in my reset.c driver.
> 
> MODULE_DEVICE_TABLE(of, of_nuc900_reset_match);
> #include <linux/module.h>

Thanks -- it is not a specific criticism of your driver, but just a
mistake that we have consistently copied from one driver to the next,
and I hope we can stop doing that with the right reviews.

P.
--

> 
> 
> >
> >Thanks,
> >Paul.
> >--
> >
> >>+       depends on ARCH_W90X900
> >>+       help
> >>+         Power off and restart support for Nuvoton NUC900 family of
> >>+         reference boards.
> >>+
> >>  config POWER_RESET_LTC2952
> >>         bool "LTC2952 PowerPath power-off driver"
> >>         depends on OF_GPIO
> >>diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
> >>index ab7aa86..d4df889 100644
> >>--- a/drivers/power/reset/Makefile
> >>+++ b/drivers/power/reset/Makefile
> >>@@ -9,6 +9,7 @@ obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o
> >>  obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o
> >>  obj-$(CONFIG_POWER_RESET_IMX) += imx-snvs-poweroff.o
> >>  obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o
> >>+obj-$(CONFIG_POWER_RESET_NUC900) += nuc900-reset.o
> >>  obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o
> >>  obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
> >>  obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o
> >>diff --git a/drivers/power/reset/nuc900-reset.c b/drivers/power/reset/nuc900-reset.c
> >>new file mode 100644
> >>index 0000000..49986b7
> >>--- /dev/null
> >>+++ b/drivers/power/reset/nuc900-reset.c
> >>@@ -0,0 +1,93 @@
> >>+/*
> >>+ * Copyright 2016 Wan Zongshun <mcuos.com@gmail.com>
> >>+ *
> >>+ * The code contained herein is licensed under the GNU General Public
> >>+ * License. You may obtain a copy of the GNU General Public License
> >>+ * Version 2 or later at the following locations:
> >>+ *
> >>+ * http://www.opensource.org/licenses/gpl-license.html
> >>+ * http://www.gnu.org/copyleft/gpl.html
> >>+ */
> >>+#include <linux/init.h>
> >>+#include <linux/err.h>
> >>+#include <linux/io.h>
> >>+#include <linux/kernel.h>
> >>+#include <linux/mfd/syscon.h>
> >>+#include <linux/module.h>
> >>+#include <linux/notifier.h>
> >>+#include <linux/of.h>
> >>+#include <linux/platform_device.h>
> >>+#include <linux/reboot.h>
> >>+#include <linux/regmap.h>
> >>
> >
> >[...]
> >
> >_______________________________________________
> >linux-arm-kernel mailing list
> >linux-arm-kernel at lists.infradead.org
> >http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> >
> >

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

* [PATCH v2 06/10] soc: Add SoC specific driver support for nuc900
  2016-07-10  7:27 ` [PATCH v2 06/10] soc: Add SoC specific " Wan Zongshun
@ 2016-07-11  8:03   ` Arnd Bergmann
  2016-07-11  9:07     ` Wan Zongshun
  2016-07-12  9:06     ` Wan Zongshun
  0 siblings, 2 replies; 45+ messages in thread
From: Arnd Bergmann @ 2016-07-11  8:03 UTC (permalink / raw)
  To: linux-arm-kernel

On Sunday, July 10, 2016 3:27:26 PM CEST Wan Zongshun wrote:
> +       ret = of_property_read_string(np, "compatible", &soc_dev_attr->soc_id);
> +       if (ret)
>               return -EINVAL;
> +
> +       soc_dev_attr->machine = "NUC900EVB";
> +       soc_dev_attr->family = "NUC900";
> +       soc_dev = soc_device_register(soc_dev_attr);
> +       if (IS_ERR(soc_dev)) {
> +               kfree(soc_dev_attr);
> +               return -ENODEV;
> +       }
> +
> +       ret = regmap_read(syscon_regmap, GCR_CHIPID, &nuc900_chipid);
> +       if (ret)
> +               return -ENODEV;
> +
> +       device_create_file(soc_device_to_device(soc_dev), &nuc900_chipid_attr);
> +       device_create_file(soc_device_to_device(soc_dev), &nuc900_version_attr);
> +
> +       dev_info(&pdev->dev, "Nuvoton Chip ID: 0x%x, Version ID:0x%x\n",
> +                nuc900_chipid & GCR_CHIPID_MASK,
> +                (nuc900_chipid >> 24) & 0xff);

I'm still a bit unsure about the set of attributes here.

- The "soc_id" is read from the device tree from the field that contains
  the board name, I think for consistency you should try to map the
  GCR_CHIPID to the name of the SoC and assign that here

- The "machine" is hardcoded to "NUC900EVB", which in turn looks like
  a particular board but not the one you are running on. Maybe read
  that from the DT instead?

- The "revision" is not filled at all, I would suggest using something
  derived from the GCR_CHIPID register here

- you have two nonstandard attributes "chipid" and "version", which
  I'd hope to avoid -- the set of standard attributes is supposed to
  give enough information about the machine, and platform independent
  user space will never read those.

	Arnd

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

* [PATCH v2 06/10] soc: Add SoC specific driver support for nuc900
  2016-07-11  8:03   ` Arnd Bergmann
@ 2016-07-11  9:07     ` Wan Zongshun
  2016-07-11 10:24       ` Arnd Bergmann
  2016-07-12  9:06     ` Wan Zongshun
  1 sibling, 1 reply; 45+ messages in thread
From: Wan Zongshun @ 2016-07-11  9:07 UTC (permalink / raw)
  To: linux-arm-kernel



On 2016?07?11? 16:03, Arnd Bergmann wrote:
> On Sunday, July 10, 2016 3:27:26 PM CEST Wan Zongshun wrote:
>> +       ret = of_property_read_string(np, "compatible", &soc_dev_attr->soc_id);
>> +       if (ret)
>>                return -EINVAL;
>> +
>> +       soc_dev_attr->machine = "NUC900EVB";
>> +       soc_dev_attr->family = "NUC900";
>> +       soc_dev = soc_device_register(soc_dev_attr);
>> +       if (IS_ERR(soc_dev)) {
>> +               kfree(soc_dev_attr);
>> +               return -ENODEV;
>> +       }
>> +
>> +       ret = regmap_read(syscon_regmap, GCR_CHIPID, &nuc900_chipid);
>> +       if (ret)
>> +               return -ENODEV;
>> +
>> +       device_create_file(soc_device_to_device(soc_dev), &nuc900_chipid_attr);
>> +       device_create_file(soc_device_to_device(soc_dev), &nuc900_version_attr);
>> +
>> +       dev_info(&pdev->dev, "Nuvoton Chip ID: 0x%x, Version ID:0x%x\n",
>> +                nuc900_chipid & GCR_CHIPID_MASK,
>> +                (nuc900_chipid >> 24) & 0xff);
>
> I'm still a bit unsure about the set of attributes here.
>
> - The "soc_id" is read from the device tree from the field that contains
>    the board name, I think for consistency you should try to map the
>    GCR_CHIPID to the name of the SoC and assign that here

I will try to get chipid and map it to soc name like: ?nuc970?, "nuc910".

And I will set this soc name to soc_id, ok?

>
> - The "machine" is hardcoded to "NUC900EVB", which in turn looks like
>    a particular board but not the one you are running on. Maybe read
>    that from the DT instead?

Should I read nuc970-evb.dts's "model" or "compatible" properties?

>
> - The "revision" is not filled at all, I would suggest using something
>    derived from the GCR_CHIPID register here
>
> - you have two nonstandard attributes "chipid" and "version", which
>    I'd hope to avoid -- the set of standard attributes is supposed to
>    give enough information about the machine, and platform independent
>    user space will never read those.
>
> 	Arnd
>
>

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

* [PATCH v2 06/10] soc: Add SoC specific driver support for nuc900
  2016-07-11  9:07     ` Wan Zongshun
@ 2016-07-11 10:24       ` Arnd Bergmann
  2016-07-11 10:28         ` Wan ZongShun
  0 siblings, 1 reply; 45+ messages in thread
From: Arnd Bergmann @ 2016-07-11 10:24 UTC (permalink / raw)
  To: linux-arm-kernel

On Monday, July 11, 2016 5:07:01 PM CEST Wan Zongshun wrote:
> 
> On 2016?07?11? 16:03, Arnd Bergmann wrote:
> > On Sunday, July 10, 2016 3:27:26 PM CEST Wan Zongshun wrote:
> >> +       ret = of_property_read_string(np, "compatible", &soc_dev_attr->soc_id);
> >> +       if (ret)
> >>                return -EINVAL;
> >> +
> >> +       soc_dev_attr->machine = "NUC900EVB";
> >> +       soc_dev_attr->family = "NUC900";
> >> +       soc_dev = soc_device_register(soc_dev_attr);
> >> +       if (IS_ERR(soc_dev)) {
> >> +               kfree(soc_dev_attr);
> >> +               return -ENODEV;
> >> +       }
> >> +
> >> +       ret = regmap_read(syscon_regmap, GCR_CHIPID, &nuc900_chipid);
> >> +       if (ret)
> >> +               return -ENODEV;
> >> +
> >> +       device_create_file(soc_device_to_device(soc_dev), &nuc900_chipid_attr);
> >> +       device_create_file(soc_device_to_device(soc_dev), &nuc900_version_attr);
> >> +
> >> +       dev_info(&pdev->dev, "Nuvoton Chip ID: 0x%x, Version ID:0x%x\n",
> >> +                nuc900_chipid & GCR_CHIPID_MASK,
> >> +                (nuc900_chipid >> 24) & 0xff);
> >
> > I'm still a bit unsure about the set of attributes here.
> >
> > - The "soc_id" is read from the device tree from the field that contains
> >    the board name, I think for consistency you should try to map the
> >    GCR_CHIPID to the name of the SoC and assign that here
> 
> I will try to get chipid and map it to soc name like: ?nuc970?, "nuc910".
> 
> And I will set this soc name to soc_id, ok?

Ok.

> > - The "machine" is hardcoded to "NUC900EVB", which in turn looks like
> >    a particular board but not the one you are running on. Maybe read
> >    that from the DT instead?
> 
> Should I read nuc970-evb.dts's "model" or "compatible" properties?

I think "model" is best here, but see what the others do.

	Arnd

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

* [PATCH v2 06/10] soc: Add SoC specific driver support for nuc900
  2016-07-11 10:24       ` Arnd Bergmann
@ 2016-07-11 10:28         ` Wan ZongShun
  2016-07-11 10:36           ` Arnd Bergmann
  0 siblings, 1 reply; 45+ messages in thread
From: Wan ZongShun @ 2016-07-11 10:28 UTC (permalink / raw)
  To: linux-arm-kernel

2016-07-11 18:24 GMT+08:00 Arnd Bergmann <arnd@arndb.de>:
> On Monday, July 11, 2016 5:07:01 PM CEST Wan Zongshun wrote:
>>
>> On 2016?07?11? 16:03, Arnd Bergmann wrote:
>> > On Sunday, July 10, 2016 3:27:26 PM CEST Wan Zongshun wrote:
>> >> +       ret = of_property_read_string(np, "compatible", &soc_dev_attr->soc_id);
>> >> +       if (ret)
>> >>                return -EINVAL;
>> >> +
>> >> +       soc_dev_attr->machine = "NUC900EVB";
>> >> +       soc_dev_attr->family = "NUC900";
>> >> +       soc_dev = soc_device_register(soc_dev_attr);
>> >> +       if (IS_ERR(soc_dev)) {
>> >> +               kfree(soc_dev_attr);
>> >> +               return -ENODEV;
>> >> +       }
>> >> +
>> >> +       ret = regmap_read(syscon_regmap, GCR_CHIPID, &nuc900_chipid);
>> >> +       if (ret)
>> >> +               return -ENODEV;
>> >> +
>> >> +       device_create_file(soc_device_to_device(soc_dev), &nuc900_chipid_attr);
>> >> +       device_create_file(soc_device_to_device(soc_dev), &nuc900_version_attr);
>> >> +
>> >> +       dev_info(&pdev->dev, "Nuvoton Chip ID: 0x%x, Version ID:0x%x\n",
>> >> +                nuc900_chipid & GCR_CHIPID_MASK,
>> >> +                (nuc900_chipid >> 24) & 0xff);
>> >
>> > I'm still a bit unsure about the set of attributes here.
>> >
>> > - The "soc_id" is read from the device tree from the field that contains
>> >    the board name, I think for consistency you should try to map the
>> >    GCR_CHIPID to the name of the SoC and assign that here
>>
>> I will try to get chipid and map it to soc name like: ?nuc970?, "nuc910".
>>
>> And I will set this soc name to soc_id, ok?
>
> Ok.

Maybe I also can set versionid as soc name partly, like
nuc970-version1,nuc970-version2? and then set the to soc_id, make
sense?


>
>> > - The "machine" is hardcoded to "NUC900EVB", which in turn looks like
>> >    a particular board but not the one you are running on. Maybe read
>> >    that from the DT instead?
>>
>> Should I read nuc970-evb.dts's "model" or "compatible" properties?
>
> I think "model" is best here, but see what the others do.
>
>         Arnd
>



-- 
---
Vincent Wan(Zongshun)
www.mcuos.com

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

* [PATCH v2 06/10] soc: Add SoC specific driver support for nuc900
  2016-07-11 10:28         ` Wan ZongShun
@ 2016-07-11 10:36           ` Arnd Bergmann
  0 siblings, 0 replies; 45+ messages in thread
From: Arnd Bergmann @ 2016-07-11 10:36 UTC (permalink / raw)
  To: linux-arm-kernel

On Monday, July 11, 2016 6:28:57 PM CEST Wan ZongShun wrote:
> 2016-07-11 18:24 GMT+08:00 Arnd Bergmann <arnd@arndb.de>:
> > On Monday, July 11, 2016 5:07:01 PM CEST Wan Zongshun wrote:
> >>
> >> On 2016?07?11? 16:03, Arnd Bergmann wrote:
> >> > On Sunday, July 10, 2016 3:27:26 PM CEST Wan Zongshun wrote:
> >> >> +       ret = of_property_read_string(np, "compatible", &soc_dev_attr->soc_id);
> >> >> +       if (ret)
> >> >>                return -EINVAL;
> >> >> +
> >> >> +       soc_dev_attr->machine = "NUC900EVB";
> >> >> +       soc_dev_attr->family = "NUC900";
> >> >> +       soc_dev = soc_device_register(soc_dev_attr);
> >> >> +       if (IS_ERR(soc_dev)) {
> >> >> +               kfree(soc_dev_attr);
> >> >> +               return -ENODEV;
> >> >> +       }
> >> >> +
> >> >> +       ret = regmap_read(syscon_regmap, GCR_CHIPID, &nuc900_chipid);
> >> >> +       if (ret)
> >> >> +               return -ENODEV;
> >> >> +
> >> >> +       device_create_file(soc_device_to_device(soc_dev), &nuc900_chipid_attr);
> >> >> +       device_create_file(soc_device_to_device(soc_dev), &nuc900_version_attr);
> >> >> +
> >> >> +       dev_info(&pdev->dev, "Nuvoton Chip ID: 0x%x, Version ID:0x%x\n",
> >> >> +                nuc900_chipid & GCR_CHIPID_MASK,
> >> >> +                (nuc900_chipid >> 24) & 0xff);
> >> >
> >> > I'm still a bit unsure about the set of attributes here.
> >> >
> >> > - The "soc_id" is read from the device tree from the field that contains
> >> >    the board name, I think for consistency you should try to map the
> >> >    GCR_CHIPID to the name of the SoC and assign that here
> >>
> >> I will try to get chipid and map it to soc name like: ?nuc970?, "nuc910".
> >>
> >> And I will set this soc name to soc_id, ok?
> >
> > Ok.
> 
> Maybe I also can set versionid as soc name partly, like
> nuc970-version1,nuc970-version2? and then set the to soc_id, make
> sense?
> 

I didn't exactly understand what the suggestion is, maybe send that
as code so I see what you mean.

	Arnd

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

* [PATCH v2 03/10] Clocksource: add nuc970 clocksource driver
  2016-07-10  7:27 ` [PATCH v2 03/10] Clocksource: add nuc970 clocksource driver Wan Zongshun
@ 2016-07-11 15:36   ` Arnd Bergmann
  2016-07-12  7:32     ` Wan Zongshun
  0 siblings, 1 reply; 45+ messages in thread
From: Arnd Bergmann @ 2016-07-11 15:36 UTC (permalink / raw)
  To: linux-arm-kernel

On Sunday, July 10, 2016 3:27:23 PM CEST Wan Zongshun wrote:
> 
> +config NUC900_TIMER
> +        bool "Clocksource timer for nuc900 platform" if COMPILE_TEST
> +        depends on ARM
> +        select CLKSRC_OF if OF
> +        select CLKSRC_MMIO
> +        help
> +          Enables the clocksource for the NUC900 platform.
> 

I have put this patch into my randconfig build system and found that
it lacks a dependency:



diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index e18ef32776a3..59b9251eef37 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -523,7 +523,7 @@ config CLKSRC_ST_LPC
 
 config NUC900_TIMER
         bool "Clocksource timer for nuc900 platform" if COMPILE_TEST
-        depends on ARM
+        depends on ARM && GENERIC_CLOCKEVENTS
         select CLKSRC_OF if OF
         select CLKSRC_MMIO
         help
	

Also the init function has changed its return type in linux-next:

> +static void __init nuc970_timer_of_init(struct device_node *node)

This now needs to return an error code or we get:

../include/linux/of.h:1004:20: error: comparison of distinct pointer types lacks a cast [-Werror]
        .data = (fn == (fn_type)NULL) ? fn : fn  }

Daniel Lezcano seems to have implemented a migration strategy, but I
can't see what you are supposed to do here, since the
CLOCKSOURCE_OF_DECLARE_RET macro is no longer part of linux-next.

	Arnd

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

* [PATCH v2 02/10] irqchip: add irqchip driver for nuc900
  2016-07-10  7:27 ` [PATCH v2 02/10] irqchip: add irqchip driver for nuc900 Wan Zongshun
  2016-07-10 21:51   ` Paul Gortmaker
@ 2016-07-11 15:46   ` Arnd Bergmann
  2016-07-12  7:04     ` Wan Zongshun
  2016-07-13 20:09   ` Jason Cooper
  2 siblings, 1 reply; 45+ messages in thread
From: Arnd Bergmann @ 2016-07-11 15:46 UTC (permalink / raw)
  To: linux-arm-kernel

On Sunday, July 10, 2016 3:27:22 PM CEST Wan Zongshun wrote:
> +
> +#if !defined(CONFIG_SOC_NUC900)
>  #define NR_IRQS                (IRQ_ADC+1)
> +#else
> +#define NR_IRQS                62
> +#endif
>  

The Kconfig symbols are a bit confusing here: CONFIG_SOC_NUC900
controls the compilation of the soc_device driver, but I guess
what you actually mean here is CONFIG_SOC_NUC970, which is the
support for the actual chip.

Maybe rename the former to something less confusing and change
this to CONFIG_SOC_NUC970?

Ideally, this should just go away once we use SPARSE_IRQ.

	Arnd

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

* [PATCH v2 01/10] ARM: NUC900: Add nuc970 machine support
  2016-07-10  7:27 ` [PATCH v2 01/10] ARM: NUC900: Add nuc970 machine support Wan Zongshun
  2016-07-10 22:11   ` Arnd Bergmann
@ 2016-07-11 16:04   ` Arnd Bergmann
  2016-07-12  4:30     ` Wan Zongshun
  1 sibling, 1 reply; 45+ messages in thread
From: Arnd Bergmann @ 2016-07-11 16:04 UTC (permalink / raw)
  To: linux-arm-kernel

On Sunday, July 10, 2016 3:27:21 PM CEST Wan Zongshun wrote:
> +ifeq ($(CONFIG_SOC_NUC970),)
>  obj-y                          := irq.o time.o mfp.o gpio.o clock.o
>  obj-y                          += clksel.o dev.o cpu.o
> +endif
>  # W90X900 CPU support files

When mfp.o is disabled like this, I get a link error in two drivers
using the exported interface:

ERROR: "mfp_set_groupg" [drivers/spi/spi-nuc900.ko] undefined!
ERROR: "mfp_set_groupi" [drivers/input/keyboard/w90p910_keypad.ko] undefined!

Any idea for a better migration strategy?

	Arnd

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

* [PATCH v2 04/10] clk: add Clock driver for nuc970
  2016-07-10  7:27 ` [PATCH v2 04/10] clk: add Clock driver for nuc970 Wan Zongshun
@ 2016-07-11 22:14   ` Michael Turquette
  0 siblings, 0 replies; 45+ messages in thread
From: Michael Turquette @ 2016-07-11 22:14 UTC (permalink / raw)
  To: linux-arm-kernel

Quoting Wan Zongshun (2016-07-10 00:27:24)
> diff --git a/drivers/clk/nuc900/clk-apll.c b/drivers/clk/nuc900/clk-apll.c
> new file mode 100644
> index 0000000..a05aec7
> --- /dev/null
> +++ b/drivers/clk/nuc900/clk-apll.c
> @@ -0,0 +1,168 @@
> +/*
> + * Copyright 2016 Wan Zongshun <mcuos.com@gmail.com>
> + *
> + * The code contained herein is licensed under the GNU General Public
> + * License. You may obtain a copy of the GNU General Public License
> + * Version 2 or later at the following locations:
> + *
> + * http://www.opensource.org/licenses/gpl-license.html
> + * http://www.gnu.org/copyleft/gpl.html
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/io.h>
> +#include <linux/slab.h>
> +#include <linux/kernel.h>
> +#include <linux/err.h>
> +
> +#include "clk-ccf.h"

Maybe call it clk-nuc.h?

> +static struct clk_ops clk_apll_ops = {
> +       .recalc_rate = clk_apll_recalc_rate,
> +       .enable = clk_apll_enable,
> +       .disable = clk_apll_disable,

Can you provide a .is_enabled?

> +static void __init nuc970_clocks_init(struct device_node *np)
> +{
> +       int i, ret;
> +
> +       clkctrl = of_iomap(np, 0);
> +       if (!clkctrl)
> +               pr_err("%s: unable to map registers\n", np->full_name);
> +
> +
> +       /* source */
> +       clk[XIN]        = nuc970_clk_fixed("xin", 12000000);
> +       clk[XIN32K]     = nuc970_clk_fixed("xin32k", 32768);
> +       clk[APLL]       = nuc970_clk_apll("apll", "xin", REG_CLK_APLLCON);
> +       clk[UPLL]       = nuc970_clk_upll("upll", "xin", REG_CLK_UPLLCON);
> +       clk[XIN128_DIV] = nuc970_clk_fixed_factor("xin128_div", "xin", 1, 128);
> +       clk[SYS_MUX]    = nuc970_clk_mux("sys_mux", REG_CLK_DIV0, 3, 2,
> +                                        sys_sel_clks,
> +                                        ARRAY_SIZE(sys_sel_clks));

Instead of executing all of these registration functions, how about
initializing your clock data statically, and then simply calling
clk_hw_register?

For an example see the recently merged drivers/clk/meson/gxbb.c

> +       for (i = 0; i < ARRAY_SIZE(clk); i++)
> +               if (IS_ERR(clk[i]))
> +                       pr_err("nuc970 clk %d: register failed with %ld\n",
> +                               i, PTR_ERR(clk[i]));

Better to fail quickly, bail out and unwind your clk registration
instead of trying to register everything and then walk the list looking
for failures.

> +
> +       clk_data.clks = clk;
> +       clk_data.clk_num = ARRAY_SIZE(clk);
> +
> +       ret = of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
> +       if (ret)
> +               pr_err("Failed to register OF clock provider\n");
> +
> +       /* Register clock device */
> +       clk_register_clkdev(clk[TIMER0_GATE], "timer0", NULL);
> +       clk_register_clkdev(clk[TIMER1_GATE], "timer1", NULL);

Again, look at how the gxbb.c driver does this. Why do you need to call
clk_register_clkdev? You're using of_clk_add_provider above, so that
should be enough to perform lookups.

> +       /* enable some important clocks */
> +       clk_prepare_enable(clk_get(NULL, "cpu"));
> +       clk_prepare_enable(clk_get(NULL, "hclk"));
> +       clk_prepare_enable(clk_get(NULL, "sram"));
> +       clk_prepare_enable(clk_get(NULL, "dram"));
> +       clk_prepare_enable(clk_get(NULL, "ddr_hclk"));

You can use the CLK_IS_CRITICAL flag for these clocks if you want. It
would be better to have drivers that claim them and enable them of
course.

> +}
> +
> +CLK_OF_DECLARE(nuc970_clk, "nuvoton,nuc970-clk", nuc970_clocks_init);

Why do you need to use CLK_OF_DECLARE? Please convert this to a
platform_driver and load it at module_init.

Regards,
Mike

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

* [PATCH v2 01/10] ARM: NUC900: Add nuc970 machine support
  2016-07-11 16:04   ` Arnd Bergmann
@ 2016-07-12  4:30     ` Wan Zongshun
  2016-07-12  7:14       ` Wan Zongshun
  0 siblings, 1 reply; 45+ messages in thread
From: Wan Zongshun @ 2016-07-12  4:30 UTC (permalink / raw)
  To: linux-arm-kernel



On 2016?07?12? 00:04, Arnd Bergmann wrote:
> On Sunday, July 10, 2016 3:27:21 PM CEST Wan Zongshun wrote:
>> +ifeq ($(CONFIG_SOC_NUC970),)
>>   obj-y                          := irq.o time.o mfp.o gpio.o clock.o
>>   obj-y                          += clksel.o dev.o cpu.o
>> +endif
>>   # W90X900 CPU support files
>
> When mfp.o is disabled like this, I get a link error in two drivers
> using the exported interface:
>
> ERROR: "mfp_set_groupg" [drivers/spi/spi-nuc900.ko] undefined!
> ERROR: "mfp_set_groupi" [drivers/input/keyboard/w90p910_keypad.ko] undefined!

Why remove mfp modules? this multifunction pin driver should be used for 
those two drivers, if no mfp_set_groupX, I don't think driver can work.

Now mfp has standard driver subsystem?

>
> Any idea for a better migration strategy?
>
> 	Arnd
>
>

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

* [PATCH v2 02/10] irqchip: add irqchip driver for nuc900
  2016-07-11 15:46   ` Arnd Bergmann
@ 2016-07-12  7:04     ` Wan Zongshun
  2016-07-12  8:26       ` Arnd Bergmann
  0 siblings, 1 reply; 45+ messages in thread
From: Wan Zongshun @ 2016-07-12  7:04 UTC (permalink / raw)
  To: linux-arm-kernel



On 2016?07?11? 23:46, Arnd Bergmann wrote:
> On Sunday, July 10, 2016 3:27:22 PM CEST Wan Zongshun wrote:
>> +
>> +#if !defined(CONFIG_SOC_NUC900)
>>   #define NR_IRQS                (IRQ_ADC+1)
>> +#else
>> +#define NR_IRQS                62
>> +#endif
>>
>
> The Kconfig symbols are a bit confusing here: CONFIG_SOC_NUC900
> controls the compilation of the soc_device driver, but I guess
> what you actually mean here is CONFIG_SOC_NUC970, which is the
> support for the actual chip.
>
> Maybe rename the former to something less confusing and change
> this to CONFIG_SOC_NUC970?

You are right, it should _NUC970. Many thanks!

>
> Ideally, this should just go away once we use SPARSE_IRQ.

This platform also can use SPARSE_IRQ? this just a simple irq map and no 
more irq number in this Soc.

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

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

* [PATCH v2 01/10] ARM: NUC900: Add nuc970 machine support
  2016-07-12  4:30     ` Wan Zongshun
@ 2016-07-12  7:14       ` Wan Zongshun
  2016-07-12  8:23         ` Arnd Bergmann
  0 siblings, 1 reply; 45+ messages in thread
From: Wan Zongshun @ 2016-07-12  7:14 UTC (permalink / raw)
  To: linux-arm-kernel



On 2016?07?12? 12:30, Wan Zongshun wrote:
>
>
> On 2016?07?12? 00:04, Arnd Bergmann wrote:
>> On Sunday, July 10, 2016 3:27:21 PM CEST Wan Zongshun wrote:
>>> +ifeq ($(CONFIG_SOC_NUC970),)
>>>   obj-y                          := irq.o time.o mfp.o gpio.o clock.o
>>>   obj-y                          += clksel.o dev.o cpu.o
>>> +endif
>>>   # W90X900 CPU support files
>>
>> When mfp.o is disabled like this, I get a link error in two drivers
>> using the exported interface:
>>
>> ERROR: "mfp_set_groupg" [drivers/spi/spi-nuc900.ko] undefined!
>> ERROR: "mfp_set_groupi" [drivers/input/keyboard/w90p910_keypad.ko]
>> undefined!
>
> Why remove mfp modules? this multifunction pin driver should be used for
> those two drivers, if no mfp_set_groupX, I don't think driver can work.
>
> Now mfp has standard driver subsystem?
>
>>
>> Any idea for a better migration strategy?

Arnd, If you still think the mfp should be removed, we can send a series 
patches to instead of using mfp interface quickly, and do mfp set in 
local driver. Do you think it is ok?

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

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

* [PATCH v2 03/10] Clocksource: add nuc970 clocksource driver
  2016-07-11 15:36   ` Arnd Bergmann
@ 2016-07-12  7:32     ` Wan Zongshun
  2016-07-12  8:28       ` Arnd Bergmann
  0 siblings, 1 reply; 45+ messages in thread
From: Wan Zongshun @ 2016-07-12  7:32 UTC (permalink / raw)
  To: linux-arm-kernel



On 2016?07?11? 23:36, Arnd Bergmann wrote:
> On Sunday, July 10, 2016 3:27:23 PM CEST Wan Zongshun wrote:
>>
>> +config NUC900_TIMER
>> +        bool "Clocksource timer for nuc900 platform" if COMPILE_TEST
>> +        depends on ARM
>> +        select CLKSRC_OF if OF
>> +        select CLKSRC_MMIO
>> +        help
>> +          Enables the clocksource for the NUC900 platform.
>>
>
> I have put this patch into my randconfig build system and found that
> it lacks a dependency:
>
>
>
> diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
> index e18ef32776a3..59b9251eef37 100644
> --- a/drivers/clocksource/Kconfig
> +++ b/drivers/clocksource/Kconfig
> @@ -523,7 +523,7 @@ config CLKSRC_ST_LPC
>
>   config NUC900_TIMER
>           bool "Clocksource timer for nuc900 platform" if COMPILE_TEST
> -        depends on ARM
> +        depends on ARM && GENERIC_CLOCKEVENTS
>           select CLKSRC_OF if OF
>           select CLKSRC_MMIO
>           help
> 	

So this patch, I still need submit or you have merged it?

>
> Also the init function has changed its return type in linux-next:
>
>> +static void __init nuc970_timer_of_init(struct device_node *node)
>
> This now needs to return an error code or we get:
>
> ../include/linux/of.h:1004:20: error: comparison of distinct pointer types lacks a cast [-Werror]
>          .data = (fn == (fn_type)NULL) ? fn : fn  }
>
> Daniel Lezcano seems to have implemented a migration strategy, but I
> can't see what you are supposed to do here, since the
> CLOCKSOURCE_OF_DECLARE_RET macro is no longer part of linux-next.

Wait for Daniel's comments? or what should I do now?

>
> 	Arnd
>
>

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

* [PATCH v2 01/10] ARM: NUC900: Add nuc970 machine support
  2016-07-12  7:14       ` Wan Zongshun
@ 2016-07-12  8:23         ` Arnd Bergmann
  0 siblings, 0 replies; 45+ messages in thread
From: Arnd Bergmann @ 2016-07-12  8:23 UTC (permalink / raw)
  To: linux-arm-kernel

On Tuesday, July 12, 2016 3:14:47 PM CEST Wan Zongshun wrote:
> On 2016?07?12? 12:30, Wan Zongshun wrote:
> >
> >
> > On 2016?07?12? 00:04, Arnd Bergmann wrote:
> >> On Sunday, July 10, 2016 3:27:21 PM CEST Wan Zongshun wrote:
> >>> +ifeq ($(CONFIG_SOC_NUC970),)
> >>>   obj-y                          := irq.o time.o mfp.o gpio.o clock.o
> >>>   obj-y                          += clksel.o dev.o cpu.o
> >>> +endif
> >>>   # W90X900 CPU support files
> >>
> >> When mfp.o is disabled like this, I get a link error in two drivers
> >> using the exported interface:
> >>
> >> ERROR: "mfp_set_groupg" [drivers/spi/spi-nuc900.ko] undefined!
> >> ERROR: "mfp_set_groupi" [drivers/input/keyboard/w90p910_keypad.ko]
> >> undefined!
> >
> > Why remove mfp modules? this multifunction pin driver should be used for
> > those two drivers, if no mfp_set_groupX, I don't think driver can work.
> >
> > Now mfp has standard driver subsystem?
> >
> >>
> >> Any idea for a better migration strategy?
> 
> Arnd, If you still think the mfp should be removed, we can send a series 
> patches to instead of using mfp interface quickly, and do mfp set in 
> local driver. Do you think it is ok?

I don't think setting it locally in the driver is a good idea.

In the long run, this should go through the pinctrl framework, but
there is no need to implement that right away. Until then, I think
using the existing mfp.o code is fine, it will just need to be
adapted slightly to understand the DT based device names.

	Arnd

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

* [PATCH v2 02/10] irqchip: add irqchip driver for nuc900
  2016-07-12  7:04     ` Wan Zongshun
@ 2016-07-12  8:26       ` Arnd Bergmann
  2016-07-14  8:52         ` Wan Zongshun
  0 siblings, 1 reply; 45+ messages in thread
From: Arnd Bergmann @ 2016-07-12  8:26 UTC (permalink / raw)
  To: linux-arm-kernel

On Tuesday, July 12, 2016 3:04:42 PM CEST Wan Zongshun wrote:
> >
> > Ideally, this should just go away once we use SPARSE_IRQ.
> 
> This platform also can use SPARSE_IRQ? this just a simple irq map and no 
> more irq number in this Soc.
> 

SPARSE_IRQ is implied by ARCH_MULTIPLATFORM, so we will have to
use it once that gets enabled.

Your new irqchip driver already handles IRQ domains, so it will
work out of the box with SPARSE_IRQ, but you have to change the
reference to "NR_IRQS" into something else.

I've prototyped a patch series to enable ARCH_MULTIPLATFORM,
I hope you can start working from what I have and get it to run.

	Arnd

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

* [PATCH v2 03/10] Clocksource: add nuc970 clocksource driver
  2016-07-12  7:32     ` Wan Zongshun
@ 2016-07-12  8:28       ` Arnd Bergmann
  2016-07-21 12:52         ` Daniel Lezcano
  0 siblings, 1 reply; 45+ messages in thread
From: Arnd Bergmann @ 2016-07-12  8:28 UTC (permalink / raw)
  To: linux-arm-kernel

On Tuesday, July 12, 2016 3:32:59 PM CEST Wan Zongshun wrote:
> 
> On 2016?07?11? 23:36, Arnd Bergmann wrote:
> > On Sunday, July 10, 2016 3:27:23 PM CEST Wan Zongshun wrote:
> >>
> >> +config NUC900_TIMER
> >> +        bool "Clocksource timer for nuc900 platform" if COMPILE_TEST
> >> +        depends on ARM
> >> +        select CLKSRC_OF if OF
> >> +        select CLKSRC_MMIO
> >> +        help
> >> +          Enables the clocksource for the NUC900 platform.
> >>
> >
> > I have put this patch into my randconfig build system and found that
> > it lacks a dependency:
> >
> >
> >
> > diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
> > index e18ef32776a3..59b9251eef37 100644
> > --- a/drivers/clocksource/Kconfig
> > +++ b/drivers/clocksource/Kconfig
> > @@ -523,7 +523,7 @@ config CLKSRC_ST_LPC
> >
> >   config NUC900_TIMER
> >           bool "Clocksource timer for nuc900 platform" if COMPILE_TEST
> > -        depends on ARM
> > +        depends on ARM && GENERIC_CLOCKEVENTS
> >           select CLKSRC_OF if OF
> >           select CLKSRC_MMIO
> >           help
> > 	
> 
> So this patch, I still need submit or you have merged it?

Ideally the driver should get submitted through the clocksource
maintainer tree. I have not applied it to any git tree that I
plan to send anywhere.

> >
> > Also the init function has changed its return type in linux-next:
> >
> >> +static void __init nuc970_timer_of_init(struct device_node *node)
> >
> > This now needs to return an error code or we get:
> >
> > ../include/linux/of.h:1004:20: error: comparison of distinct pointer types lacks a cast [-Werror]
> >          .data = (fn == (fn_type)NULL) ? fn : fn  }
> >
> > Daniel Lezcano seems to have implemented a migration strategy, but I
> > can't see what you are supposed to do here, since the
> > CLOCKSOURCE_OF_DECLARE_RET macro is no longer part of linux-next.
> 
> Wait for Daniel's comments? or what should I do now?

Yes, let's see what he says. I guess from the timing, this will probably
have to wait for linux-4.9 anyway, and then we have no problem because the
API change will make it into 4.8.

	Arnd

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

* [PATCH v2 06/10] soc: Add SoC specific driver support for nuc900
  2016-07-11  8:03   ` Arnd Bergmann
  2016-07-11  9:07     ` Wan Zongshun
@ 2016-07-12  9:06     ` Wan Zongshun
  2016-07-12  9:50       ` Arnd Bergmann
  1 sibling, 1 reply; 45+ messages in thread
From: Wan Zongshun @ 2016-07-12  9:06 UTC (permalink / raw)
  To: linux-arm-kernel



On 2016?07?11? 16:03, Arnd Bergmann wrote:
> On Sunday, July 10, 2016 3:27:26 PM CEST Wan Zongshun wrote:
>> +       ret = of_property_read_string(np, "compatible", &soc_dev_attr->soc_id);
>> +       if (ret)
>>                return -EINVAL;
>> +
>> +       soc_dev_attr->machine = "NUC900EVB";
>> +       soc_dev_attr->family = "NUC900";
>> +       soc_dev = soc_device_register(soc_dev_attr);
>> +       if (IS_ERR(soc_dev)) {
>> +               kfree(soc_dev_attr);
>> +               return -ENODEV;
>> +       }
>> +
>> +       ret = regmap_read(syscon_regmap, GCR_CHIPID, &nuc900_chipid);
>> +       if (ret)
>> +               return -ENODEV;
>> +
>> +       device_create_file(soc_device_to_device(soc_dev), &nuc900_chipid_attr);
>> +       device_create_file(soc_device_to_device(soc_dev), &nuc900_version_attr);
>> +
>> +       dev_info(&pdev->dev, "Nuvoton Chip ID: 0x%x, Version ID:0x%x\n",
>> +                nuc900_chipid & GCR_CHIPID_MASK,
>> +                (nuc900_chipid >> 24) & 0xff);
>
> I'm still a bit unsure about the set of attributes here.
>
> - The "soc_id" is read from the device tree from the field that contains
>    the board name, I think for consistency you should try to map the
>    GCR_CHIPID to the name of the SoC and assign that here
>
> - The "machine" is hardcoded to "NUC900EVB", which in turn looks like
>    a particular board but not the one you are running on. Maybe read
>    that from the DT instead?
>
> - The "revision" is not filled at all, I would suggest using something
>    derived from the GCR_CHIPID register here
>
> - you have two nonstandard attributes "chipid" and "version", which
>    I'd hope to avoid -- the set of standard attributes is supposed to
>    give enough information about the machine, and platform independent
>    user space will never read those.

So, Maybe I can remove those two codes, no need push those information 
to user space?

device_create_file(soc_device_to_device(soc_dev), &nuc900_chipid_attr);
device_create_file(soc_device_to_device(soc_dev), &nuc900_version_attr);

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

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

* [PATCH v2 06/10] soc: Add SoC specific driver support for nuc900
  2016-07-12  9:06     ` Wan Zongshun
@ 2016-07-12  9:50       ` Arnd Bergmann
  0 siblings, 0 replies; 45+ messages in thread
From: Arnd Bergmann @ 2016-07-12  9:50 UTC (permalink / raw)
  To: linux-arm-kernel

On Tuesday, July 12, 2016 5:06:10 PM CEST Wan Zongshun wrote:
> On 2016?07?11? 16:03, Arnd Bergmann wrote:
> > On Sunday, July 10, 2016 3:27:26 PM CEST Wan Zongshun wrote:
> > I'm still a bit unsure about the set of attributes here.
> >
> > - The "soc_id" is read from the device tree from the field that contains
> >    the board name, I think for consistency you should try to map the
> >    GCR_CHIPID to the name of the SoC and assign that here
> >
> > - The "machine" is hardcoded to "NUC900EVB", which in turn looks like
> >    a particular board but not the one you are running on. Maybe read
> >    that from the DT instead?
> >
> > - The "revision" is not filled at all, I would suggest using something
> >    derived from the GCR_CHIPID register here
> >
> > - you have two nonstandard attributes "chipid" and "version", which
> >    I'd hope to avoid -- the set of standard attributes is supposed to
> >    give enough information about the machine, and platform independent
> >    user space will never read those.
> 
> So, Maybe I can remove those two codes, no need push those information 
> to user space?
> 
> device_create_file(soc_device_to_device(soc_dev), &nuc900_chipid_attr);
> device_create_file(soc_device_to_device(soc_dev), &nuc900_version_attr);
> 

Yes, that would be good.

	Arnd

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

* [PATCH v2 02/10] irqchip: add irqchip driver for nuc900
  2016-07-10  7:27 ` [PATCH v2 02/10] irqchip: add irqchip driver for nuc900 Wan Zongshun
  2016-07-10 21:51   ` Paul Gortmaker
  2016-07-11 15:46   ` Arnd Bergmann
@ 2016-07-13 20:09   ` Jason Cooper
  2016-07-14  3:36     ` Wan Zongshun
  2 siblings, 1 reply; 45+ messages in thread
From: Jason Cooper @ 2016-07-13 20:09 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Wan Zongshun,

On Sun, Jul 10, 2016 at 03:27:22PM +0800, Wan Zongshun wrote:
> This patch is to add irqchip driver support for nuc900 plat,
> current this driver only supports nuc970 SoC.
> 
> Signed-off-by: Wan Zongshun <mcuos.com@gmail.com>
> ---
>  arch/arm/mach-w90x900/include/mach/irqs.h |   5 +
>  drivers/irqchip/Makefile                  |   1 +
>  drivers/irqchip/irq-nuc900.c              | 150 ++++++++++++++++++++++++++++++
>  3 files changed, 156 insertions(+)
>  create mode 100644 drivers/irqchip/irq-nuc900.c
> 
> diff --git a/arch/arm/mach-w90x900/include/mach/irqs.h b/arch/arm/mach-w90x900/include/mach/irqs.h
> index 9d5cba3..3b035c6 100644
> --- a/arch/arm/mach-w90x900/include/mach/irqs.h
> +++ b/arch/arm/mach-w90x900/include/mach/irqs.h
> @@ -59,7 +59,12 @@
>  #define IRQ_KPI		W90X900_IRQ(29)
>  #define IRQ_P2SGROUP	W90X900_IRQ(30)
>  #define IRQ_ADC		W90X900_IRQ(31)
> +
> +#if !defined(CONFIG_SOC_NUC900)
>  #define NR_IRQS		(IRQ_ADC+1)
> +#else
> +#define NR_IRQS		62
> +#endif

Arnd already covered this...

>  
>  /*for irq group*/
>  
> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
> index 38853a1..9ccd5af8a 100644
> --- a/drivers/irqchip/Makefile
> +++ b/drivers/irqchip/Makefile
> @@ -69,3 +69,4 @@ obj-$(CONFIG_PIC32_EVIC)		+= irq-pic32-evic.o
>  obj-$(CONFIG_MVEBU_ODMI)		+= irq-mvebu-odmi.o
>  obj-$(CONFIG_LS_SCFG_MSI)		+= irq-ls-scfg-msi.o
>  obj-$(CONFIG_EZNPS_GIC)			+= irq-eznps.o
> +obj-$(CONFIG_SOC_NUC970)		+= irq-nuc900.o
> diff --git a/drivers/irqchip/irq-nuc900.c b/drivers/irqchip/irq-nuc900.c
> new file mode 100644
> index 0000000..c4b2e39
> --- /dev/null
> +++ b/drivers/irqchip/irq-nuc900.c
> @@ -0,0 +1,150 @@
> +/*
> + * Copyright 2016 Wan Zongshun <mcuos.com@gmail.com>
> + *
> + * The code contained herein is licensed under the GNU General Public
> + * License. You may obtain a copy of the GNU General Public License
> + * Version 2 or later at the following locations:
> + *
> + * http://www.opensource.org/licenses/gpl-license.html
> + * http://www.gnu.org/copyleft/gpl.html
> + */
> +
> +#include <linux/module.h>
> +#include <linux/init.h>
> +#include <linux/irq.h>
> +#include <linux/irqchip.h>
> +#include <linux/irqdomain.h>
> +#include <linux/io.h>
> +#include <linux/ioport.h>
> +#include <linux/of_address.h>
> +#include <linux/of_irq.h>
> +
> +#include <asm/exception.h>
> +#include <asm/hardirq.h>
> +
> +#define	REG_AIC_SCR1	0x00
> +#define	REG_AIC_SCR2	0x04
> +#define	REG_AIC_SCR3	0x08
> +#define	REG_AIC_SCR4	0x0C
> +#define	REG_AIC_SCR5	0x10
> +#define	REG_AIC_SCR6	0x14
> +#define	REG_AIC_SCR7	0x18
> +#define	REG_AIC_SCR8	0x1C
> +#define	REG_AIC_SCR9	0x20
> +#define	REG_AIC_SCR10	0x24
> +#define	REG_AIC_SCR11	0x28
> +#define	REG_AIC_SCR12	0x2C
> +#define	REG_AIC_SCR13	0x30
> +#define	REG_AIC_SCR14	0x34
> +#define	REG_AIC_SCR15	0x38
> +#define	REG_AIC_IRSR	0x100
> +#define	REG_AIC_IRSRH	0x104
> +#define	REG_AIC_IASR	0x108
> +#define	REG_AIC_IASRH	0x10C
> +#define	REG_AIC_ISR	0x110
> +#define	REG_AIC_ISRH	0x114
> +#define	REG_AIC_IPER	0x118
> +#define	REG_AIC_ISNR	0x120
> +#define	REG_AIC_OISR	0x124
> +#define	REG_AIC_IMR	0x128
> +#define	REG_AIC_IMRH	0x12C
> +#define	REG_AIC_MECR	0x130
> +#define	REG_AIC_MECRH	0x134
> +#define	REG_AIC_MDCR	0x138
> +#define	REG_AIC_MDCRH	0x13C
> +#define	REG_AIC_SSCR	0x140
> +#define	REG_AIC_SSCRH	0x144
> +#define	REG_AIC_SCCR	0x148
> +#define	REG_AIC_SCCRH	0x14C
> +#define	REG_AIC_EOSCR	0x150

Please remove unused defines.

> +
> +static void __iomem *aic_base;
> +static struct irq_domain *aic_domain;
> +
> +static void nuc900_irq_mask(struct irq_data *d)
> +{
> +	if (d->irq < 32)
> +		writel(1 << (d->irq), aic_base + REG_AIC_MDCR);
> +	else
> +		writel(1 << (d->irq - 32), aic_base + REG_AIC_MDCRH);
> +}
> +
> +static void nuc900_irq_ack(struct irq_data *d)
> +{
> +	writel(0x01, aic_base + REG_AIC_EOSCR);
> +}
> +
> +static void nuc900_irq_unmask(struct irq_data *d)
> +{
> +	if (d->irq < 32)
> +		writel(1 << (d->irq), aic_base + REG_AIC_MECR);
> +	else
> +		writel(1 << (d->irq - 32), aic_base + REG_AIC_MECRH);
> +}
> +
> +static struct irq_chip nuc900_irq_chip = {
> +	.irq_ack	= nuc900_irq_ack,
> +	.irq_mask	= nuc900_irq_mask,
> +	.irq_unmask	= nuc900_irq_unmask,
> +};
> +
> +void __exception_irq_entry aic_handle_irq(struct pt_regs *regs)
> +{
> +	u32 hwirq;
> +
> +	hwirq = readl(aic_base + REG_AIC_IPER);
> +	hwirq = readl(aic_base + REG_AIC_ISNR);
> +	if (!hwirq)
> +		writel(0x01, aic_base + REG_AIC_EOSCR);

Could you explain what's going on here?

> +
> +	handle_IRQ((irq_find_mapping(aic_domain, hwirq)), regs);
> +}
> +
> +static int aic_irq_domain_map(struct irq_domain *d, unsigned int virq,
> +			      irq_hw_number_t hw)
> +{
> +	irq_set_chip_and_handler(virq, &nuc900_irq_chip, handle_level_irq);
> +	irq_clear_status_flags(virq, IRQ_NOREQUEST);
> +
> +	return 0;
> +}
> +
> +static struct irq_domain_ops aic_irq_domain_ops = {
> +	.map = aic_irq_domain_map,
> +	.xlate = irq_domain_xlate_onecell,
> +};
> +
> +static int __init aic_of_init(struct device_node *node,
> +			      struct device_node *parent)
> +{
> +	int ret;
> +
> +	aic_base = of_iomap(node, 0);
> +	if (!aic_base) {
> +		ret = -ENOMEM;
> +		pr_err("%s: unable to map registers\n", node->full_name);
> +		goto err_iomap;
> +	}
> +
> +	writel(0xFFFFFFFC, aic_base + REG_AIC_MDCR);
> +	writel(0xFFFFFFFF, aic_base + REG_AIC_MDCRH);
> +
> +	aic_domain = irq_domain_add_linear(node, NR_IRQS,
> +					   &aic_irq_domain_ops, NULL);
> +
> +	if (!aic_domain) {
> +		ret = -ENOMEM;
> +		pr_err("%s: unable to create IRQ domain\n", node->full_name);
> +		goto err_aic_domain;
> +	}
> +
> +	set_handle_irq(aic_handle_irq);
> +	return 0;
> +
> +err_aic_domain:
> +	iounmap(aic_base);
> +err_iomap:
> +	return ret;
> +}
> +
> +IRQCHIP_DECLARE(nuc900, "nuvoton,nuc900-aic", aic_of_init);

afaict, there is no 'nuc900', that's a family.  If so, this compatible
needs to be 'nuvoton,nuc970-aic'.

thx,

Jason.

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

* [PATCH v2 02/10] irqchip: add irqchip driver for nuc900
  2016-07-13 20:09   ` Jason Cooper
@ 2016-07-14  3:36     ` Wan Zongshun
  2016-07-14 13:54       ` Jason Cooper
  0 siblings, 1 reply; 45+ messages in thread
From: Wan Zongshun @ 2016-07-14  3:36 UTC (permalink / raw)
  To: linux-arm-kernel



On 2016?07?14? 04:09, Jason Cooper wrote:
> Hi Wan Zongshun,
>
> On Sun, Jul 10, 2016 at 03:27:22PM +0800, Wan Zongshun wrote:
>> This patch is to add irqchip driver support for nuc900 plat,
>> current this driver only supports nuc970 SoC.
>>
>> Signed-off-by: Wan Zongshun <mcuos.com@gmail.com>
>> ---
>>   arch/arm/mach-w90x900/include/mach/irqs.h |   5 +
>>   drivers/irqchip/Makefile                  |   1 +
>>   drivers/irqchip/irq-nuc900.c              | 150 ++++++++++++++++++++++++++++++
>>   3 files changed, 156 insertions(+)
>>   create mode 100644 drivers/irqchip/irq-nuc900.c
>>
>> diff --git a/arch/arm/mach-w90x900/include/mach/irqs.h b/arch/arm/mach-w90x900/include/mach/irqs.h
>> index 9d5cba3..3b035c6 100644
>> --- a/arch/arm/mach-w90x900/include/mach/irqs.h
>> +++ b/arch/arm/mach-w90x900/include/mach/irqs.h
>> @@ -59,7 +59,12 @@
>>   #define IRQ_KPI		W90X900_IRQ(29)
>>   #define IRQ_P2SGROUP	W90X900_IRQ(30)
>>   #define IRQ_ADC		W90X900_IRQ(31)
>> +
>> +#if !defined(CONFIG_SOC_NUC900)
>>   #define NR_IRQS		(IRQ_ADC+1)
>> +#else
>> +#define NR_IRQS		62
>> +#endif
>
> Arnd already covered this...
>
>>
>>   /*for irq group*/
>>
>> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
>> index 38853a1..9ccd5af8a 100644
>> --- a/drivers/irqchip/Makefile
>> +++ b/drivers/irqchip/Makefile
>> @@ -69,3 +69,4 @@ obj-$(CONFIG_PIC32_EVIC)		+= irq-pic32-evic.o
>>   obj-$(CONFIG_MVEBU_ODMI)		+= irq-mvebu-odmi.o
>>   obj-$(CONFIG_LS_SCFG_MSI)		+= irq-ls-scfg-msi.o
>>   obj-$(CONFIG_EZNPS_GIC)			+= irq-eznps.o
>> +obj-$(CONFIG_SOC_NUC970)		+= irq-nuc900.o
>> diff --git a/drivers/irqchip/irq-nuc900.c b/drivers/irqchip/irq-nuc900.c
>> new file mode 100644
>> index 0000000..c4b2e39
>> --- /dev/null
>> +++ b/drivers/irqchip/irq-nuc900.c
>> @@ -0,0 +1,150 @@
>> +/*
>> + * Copyright 2016 Wan Zongshun <mcuos.com@gmail.com>
>> + *
>> + * The code contained herein is licensed under the GNU General Public
>> + * License. You may obtain a copy of the GNU General Public License
>> + * Version 2 or later at the following locations:
>> + *
>> + * http://www.opensource.org/licenses/gpl-license.html
>> + * http://www.gnu.org/copyleft/gpl.html
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/init.h>
>> +#include <linux/irq.h>
>> +#include <linux/irqchip.h>
>> +#include <linux/irqdomain.h>
>> +#include <linux/io.h>
>> +#include <linux/ioport.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_irq.h>
>> +
>> +#include <asm/exception.h>
>> +#include <asm/hardirq.h>
>> +
>> +#define	REG_AIC_SCR1	0x00
>> +#define	REG_AIC_SCR2	0x04
>> +#define	REG_AIC_SCR3	0x08
>> +#define	REG_AIC_SCR4	0x0C
>> +#define	REG_AIC_SCR5	0x10
>> +#define	REG_AIC_SCR6	0x14
>> +#define	REG_AIC_SCR7	0x18
>> +#define	REG_AIC_SCR8	0x1C
>> +#define	REG_AIC_SCR9	0x20
>> +#define	REG_AIC_SCR10	0x24
>> +#define	REG_AIC_SCR11	0x28
>> +#define	REG_AIC_SCR12	0x2C
>> +#define	REG_AIC_SCR13	0x30
>> +#define	REG_AIC_SCR14	0x34
>> +#define	REG_AIC_SCR15	0x38
>> +#define	REG_AIC_IRSR	0x100
>> +#define	REG_AIC_IRSRH	0x104
>> +#define	REG_AIC_IASR	0x108
>> +#define	REG_AIC_IASRH	0x10C
>> +#define	REG_AIC_ISR	0x110
>> +#define	REG_AIC_ISRH	0x114
>> +#define	REG_AIC_IPER	0x118
>> +#define	REG_AIC_ISNR	0x120
>> +#define	REG_AIC_OISR	0x124
>> +#define	REG_AIC_IMR	0x128
>> +#define	REG_AIC_IMRH	0x12C
>> +#define	REG_AIC_MECR	0x130
>> +#define	REG_AIC_MECRH	0x134
>> +#define	REG_AIC_MDCR	0x138
>> +#define	REG_AIC_MDCRH	0x13C
>> +#define	REG_AIC_SSCR	0x140
>> +#define	REG_AIC_SSCRH	0x144
>> +#define	REG_AIC_SCCR	0x148
>> +#define	REG_AIC_SCCRH	0x14C
>> +#define	REG_AIC_EOSCR	0x150
>
> Please remove unused defines.

Okay.

>
>> +
>> +static void __iomem *aic_base;
>> +static struct irq_domain *aic_domain;
>> +
>> +static void nuc900_irq_mask(struct irq_data *d)
>> +{
>> +	if (d->irq < 32)
>> +		writel(1 << (d->irq), aic_base + REG_AIC_MDCR);
>> +	else
>> +		writel(1 << (d->irq - 32), aic_base + REG_AIC_MDCRH);
>> +}
>> +
>> +static void nuc900_irq_ack(struct irq_data *d)
>> +{
>> +	writel(0x01, aic_base + REG_AIC_EOSCR);
>> +}
>> +
>> +static void nuc900_irq_unmask(struct irq_data *d)
>> +{
>> +	if (d->irq < 32)
>> +		writel(1 << (d->irq), aic_base + REG_AIC_MECR);
>> +	else
>> +		writel(1 << (d->irq - 32), aic_base + REG_AIC_MECRH);
>> +}
>> +
>> +static struct irq_chip nuc900_irq_chip = {
>> +	.irq_ack	= nuc900_irq_ack,
>> +	.irq_mask	= nuc900_irq_mask,
>> +	.irq_unmask	= nuc900_irq_unmask,
>> +};
>> +
>> +void __exception_irq_entry aic_handle_irq(struct pt_regs *regs)
>> +{
>> +	u32 hwirq;
>> +
>> +	hwirq = readl(aic_base + REG_AIC_IPER);
>> +	hwirq = readl(aic_base + REG_AIC_ISNR);
>> +	if (!hwirq)
>> +		writel(0x01, aic_base + REG_AIC_EOSCR);
>
> Could you explain what's going on here?

AIC_IPER, When the AIC generates the interrupt, VECTOR represents the 
interrupt channel number that is active, enabled, and has the highest 
priority.

The value of VECTOR is copied to the register AIC_ISNR thereafter by the 
AIC. This register was restored a value 0 after it was read by the
interrupt handler.

So I must read two registers for one irq number, after read IPER, the 
ISNR(bit0:5) will be updated. ISNR value has no need do offset, it is 
better than read IPER(bit2:7).

?writel(0x01, aic_base + REG_AIC_EOSCR);??seems not necessary here, 
since irqchip has the ack interface. I will remove it.

This AIC_EOSCR register is used by the interrupt service routine to 
indicate that it is completely served. Thus, the
interrupt handler can write any value to this register to indicate the 
end of its interrupt service.

>
>> +
>> +	handle_IRQ((irq_find_mapping(aic_domain, hwirq)), regs);
>> +}
>> +
>> +static int aic_irq_domain_map(struct irq_domain *d, unsigned int virq,
>> +			      irq_hw_number_t hw)
>> +{
>> +	irq_set_chip_and_handler(virq, &nuc900_irq_chip, handle_level_irq);
>> +	irq_clear_status_flags(virq, IRQ_NOREQUEST);
>> +
>> +	return 0;
>> +}
>> +
>> +static struct irq_domain_ops aic_irq_domain_ops = {
>> +	.map = aic_irq_domain_map,
>> +	.xlate = irq_domain_xlate_onecell,
>> +};
>> +
>> +static int __init aic_of_init(struct device_node *node,
>> +			      struct device_node *parent)
>> +{
>> +	int ret;
>> +
>> +	aic_base = of_iomap(node, 0);
>> +	if (!aic_base) {
>> +		ret = -ENOMEM;
>> +		pr_err("%s: unable to map registers\n", node->full_name);
>> +		goto err_iomap;
>> +	}
>> +
>> +	writel(0xFFFFFFFC, aic_base + REG_AIC_MDCR);
>> +	writel(0xFFFFFFFF, aic_base + REG_AIC_MDCRH);
>> +
>> +	aic_domain = irq_domain_add_linear(node, NR_IRQS,
>> +					   &aic_irq_domain_ops, NULL);
>> +
>> +	if (!aic_domain) {
>> +		ret = -ENOMEM;
>> +		pr_err("%s: unable to create IRQ domain\n", node->full_name);
>> +		goto err_aic_domain;
>> +	}
>> +
>> +	set_handle_irq(aic_handle_irq);
>> +	return 0;
>> +
>> +err_aic_domain:
>> +	iounmap(aic_base);
>> +err_iomap:
>> +	return ret;
>> +}
>> +
>> +IRQCHIP_DECLARE(nuc900, "nuvoton,nuc900-aic", aic_of_init);
>
> afaict, there is no 'nuc900', that's a family.  If so, this compatible
> needs to be 'nuvoton,nuc970-aic'.
>

IRQCHIP_DECLARE(nuvoton, "nuvoton,nuc900-aic", aic_of_init);, change 
nuc900 to nuvoton, ok?

> thx,
>
> Jason.
>
>

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

* [PATCH v2 02/10] irqchip: add irqchip driver for nuc900
  2016-07-12  8:26       ` Arnd Bergmann
@ 2016-07-14  8:52         ` Wan Zongshun
  2016-07-14 11:09           ` Arnd Bergmann
  0 siblings, 1 reply; 45+ messages in thread
From: Wan Zongshun @ 2016-07-14  8:52 UTC (permalink / raw)
  To: linux-arm-kernel



On 2016?07?12? 16:26, Arnd Bergmann wrote:
> On Tuesday, July 12, 2016 3:04:42 PM CEST Wan Zongshun wrote:
>>>
>>> Ideally, this should just go away once we use SPARSE_IRQ.
>>
>> This platform also can use SPARSE_IRQ? this just a simple irq map and no
>> more irq number in this Soc.
>>
>
> SPARSE_IRQ is implied by ARCH_MULTIPLATFORM, so we will have to
> use it once that gets enabled.
>
> Your new irqchip driver already handles IRQ domains, so it will
> work out of the box with SPARSE_IRQ, but you have to change the
> reference to "NR_IRQS" into something else.
>
> I've prototyped a patch series to enable ARCH_MULTIPLATFORM,
> I hope you can start working from what I have and get it to run.

I go through the ARCH_MULTIPLATFORM and SPARSE_IRQ related codes, but I 
find I also have to define the NUC900_NR_IRQS firstly like below, so 
that I can init the .nr_irq.

+#if !defined(CONFIG_SOC_NUC970)
  #define NUC900_NR_IRQS		(IRQ_ADC+1)
+#else
+#define NUC900_NR_IRQS		62
+#endif

  DT_MACHINE_START(nuc900_dt, "Nuvoton NUC900 (Device Tree Support)")
         .dt_compat      = nuc900_dt_compat,
+       .nr_irqs        = NUC900_NR_IRQS,
  MACHINE_END

and then in my irqchip driver, I will use the NUC900_NR_IRQS:

+aic_domain = irq_domain_add_linear(node, NUC900_NR_IRQS,
+				    &aic_irq_domain_ops, NULL);


Is that a right usage?

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

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

* [PATCH v2 02/10] irqchip: add irqchip driver for nuc900
  2016-07-14  8:52         ` Wan Zongshun
@ 2016-07-14 11:09           ` Arnd Bergmann
  0 siblings, 0 replies; 45+ messages in thread
From: Arnd Bergmann @ 2016-07-14 11:09 UTC (permalink / raw)
  To: linux-arm-kernel

On Thursday, July 14, 2016 4:52:29 PM CEST Wan Zongshun wrote:
> 
> On 2016?07?12? 16:26, Arnd Bergmann wrote:
> > On Tuesday, July 12, 2016 3:04:42 PM CEST Wan Zongshun wrote:
> >>>
> >>> Ideally, this should just go away once we use SPARSE_IRQ.
> >>
> >> This platform also can use SPARSE_IRQ? this just a simple irq map and no
> >> more irq number in this Soc.
> >>
> >
> > SPARSE_IRQ is implied by ARCH_MULTIPLATFORM, so we will have to
> > use it once that gets enabled.
> >
> > Your new irqchip driver already handles IRQ domains, so it will
> > work out of the box with SPARSE_IRQ, but you have to change the
> > reference to "NR_IRQS" into something else.
> >
> > I've prototyped a patch series to enable ARCH_MULTIPLATFORM,
> > I hope you can start working from what I have and get it to run.
> 
> I go through the ARCH_MULTIPLATFORM and SPARSE_IRQ related codes, but I 
> find I also have to define the NUC900_NR_IRQS firstly like below, so 
> that I can init the .nr_irq.
> 
> +#if !defined(CONFIG_SOC_NUC970)
>   #define NUC900_NR_IRQS		(IRQ_ADC+1)
> +#else
> +#define NUC900_NR_IRQS		62
> +#endif
> 
>   DT_MACHINE_START(nuc900_dt, "Nuvoton NUC900 (Device Tree Support)")
>          .dt_compat      = nuc900_dt_compat,
> +       .nr_irqs        = NUC900_NR_IRQS,
>   MACHINE_END

You don't need to set this for the DT based machines, this number
is just for the set of IRQ that have a hardcoded mapping. With DT,
they get dynamically allocated as required.

For the board files, you can hardcode the original definition of 32
IRQs, but I think you don't need that if you register a legacy IRQ
domain in mach-w90x900/irq.c.

> and then in my irqchip driver, I will use the NUC900_NR_IRQS:
> 
> +aic_domain = irq_domain_add_linear(node, NUC900_NR_IRQS,
> +				    &aic_irq_domain_ops, NULL);
> 
> 
> Is that a right usage?

This does not look right when NUC900_NR_IRQS can have configuration
dependent values. I can see two ways of handling it:

a) register the maximum number of IRQs that the irqchip can handle.
   There is no real cost for having a large number here, as SPARSE_IRQ
   ensures we only need to allocate the descriptors that are actually
   used.

b) make the number of interrupts dependent on the compatible string
   for the irqchip, and handle NUC970 differently from the others
   in the driver.

In the meantime, I also have a series to enable multiplatform support
for all of mach-w90x900 based on your patches, but lacking a proper
clk driver. I'll send that to you so you can include it in your
series (after verifying that it works, or fixing it where necessary).

	Arnd

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

* [PATCH v2 02/10] irqchip: add irqchip driver for nuc900
  2016-07-14  3:36     ` Wan Zongshun
@ 2016-07-14 13:54       ` Jason Cooper
  2016-07-15  5:15         ` Wan Zongshun
  0 siblings, 1 reply; 45+ messages in thread
From: Jason Cooper @ 2016-07-14 13:54 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Wan Zongshun,

On Thu, Jul 14, 2016 at 11:36:53AM +0800, Wan Zongshun wrote:
> On 2016?07?14? 04:09, Jason Cooper wrote:
> >On Sun, Jul 10, 2016 at 03:27:22PM +0800, Wan Zongshun wrote:
> >>This patch is to add irqchip driver support for nuc900 plat,
> >>current this driver only supports nuc970 SoC.
> >>
> >>Signed-off-by: Wan Zongshun <mcuos.com@gmail.com>
> >>---
> >>  arch/arm/mach-w90x900/include/mach/irqs.h |   5 +
> >>  drivers/irqchip/Makefile                  |   1 +
> >>  drivers/irqchip/irq-nuc900.c              | 150 ++++++++++++++++++++++++++++++
> >>  3 files changed, 156 insertions(+)
> >>  create mode 100644 drivers/irqchip/irq-nuc900.c
> >>
> >>diff --git a/arch/arm/mach-w90x900/include/mach/irqs.h b/arch/arm/mach-w90x900/include/mach/irqs.h
> >>index 9d5cba3..3b035c6 100644
> >>--- a/arch/arm/mach-w90x900/include/mach/irqs.h
> >>+++ b/arch/arm/mach-w90x900/include/mach/irqs.h
> >>@@ -59,7 +59,12 @@
> >>  #define IRQ_KPI		W90X900_IRQ(29)
> >>  #define IRQ_P2SGROUP	W90X900_IRQ(30)
> >>  #define IRQ_ADC		W90X900_IRQ(31)
> >>+
> >>+#if !defined(CONFIG_SOC_NUC900)
> >>  #define NR_IRQS		(IRQ_ADC+1)
> >>+#else
> >>+#define NR_IRQS		62
> >>+#endif
> >
> >Arnd already covered this...
> >
> >>
> >>  /*for irq group*/
> >>
> >>diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
> >>index 38853a1..9ccd5af8a 100644
> >>--- a/drivers/irqchip/Makefile
> >>+++ b/drivers/irqchip/Makefile
> >>@@ -69,3 +69,4 @@ obj-$(CONFIG_PIC32_EVIC)		+= irq-pic32-evic.o
> >>  obj-$(CONFIG_MVEBU_ODMI)		+= irq-mvebu-odmi.o
> >>  obj-$(CONFIG_LS_SCFG_MSI)		+= irq-ls-scfg-msi.o
> >>  obj-$(CONFIG_EZNPS_GIC)			+= irq-eznps.o
> >>+obj-$(CONFIG_SOC_NUC970)		+= irq-nuc900.o
> >>diff --git a/drivers/irqchip/irq-nuc900.c b/drivers/irqchip/irq-nuc900.c
> >>new file mode 100644
> >>index 0000000..c4b2e39
> >>--- /dev/null
> >>+++ b/drivers/irqchip/irq-nuc900.c
> >>@@ -0,0 +1,150 @@
> >>+/*
> >>+ * Copyright 2016 Wan Zongshun <mcuos.com@gmail.com>
> >>+ *
> >>+ * The code contained herein is licensed under the GNU General Public
> >>+ * License. You may obtain a copy of the GNU General Public License
> >>+ * Version 2 or later at the following locations:
> >>+ *
> >>+ * http://www.opensource.org/licenses/gpl-license.html
> >>+ * http://www.gnu.org/copyleft/gpl.html
> >>+ */
> >>+
> >>+#include <linux/module.h>
> >>+#include <linux/init.h>
> >>+#include <linux/irq.h>
> >>+#include <linux/irqchip.h>
> >>+#include <linux/irqdomain.h>
> >>+#include <linux/io.h>
> >>+#include <linux/ioport.h>
> >>+#include <linux/of_address.h>
> >>+#include <linux/of_irq.h>
> >>+
> >>+#include <asm/exception.h>
> >>+#include <asm/hardirq.h>
> >>+
> >>+#define	REG_AIC_SCR1	0x00
> >>+#define	REG_AIC_SCR2	0x04
> >>+#define	REG_AIC_SCR3	0x08
> >>+#define	REG_AIC_SCR4	0x0C
> >>+#define	REG_AIC_SCR5	0x10
> >>+#define	REG_AIC_SCR6	0x14
> >>+#define	REG_AIC_SCR7	0x18
> >>+#define	REG_AIC_SCR8	0x1C
> >>+#define	REG_AIC_SCR9	0x20
> >>+#define	REG_AIC_SCR10	0x24
> >>+#define	REG_AIC_SCR11	0x28
> >>+#define	REG_AIC_SCR12	0x2C
> >>+#define	REG_AIC_SCR13	0x30
> >>+#define	REG_AIC_SCR14	0x34
> >>+#define	REG_AIC_SCR15	0x38
> >>+#define	REG_AIC_IRSR	0x100
> >>+#define	REG_AIC_IRSRH	0x104
> >>+#define	REG_AIC_IASR	0x108
> >>+#define	REG_AIC_IASRH	0x10C
> >>+#define	REG_AIC_ISR	0x110
> >>+#define	REG_AIC_ISRH	0x114
> >>+#define	REG_AIC_IPER	0x118
> >>+#define	REG_AIC_ISNR	0x120
> >>+#define	REG_AIC_OISR	0x124
> >>+#define	REG_AIC_IMR	0x128
> >>+#define	REG_AIC_IMRH	0x12C
> >>+#define	REG_AIC_MECR	0x130
> >>+#define	REG_AIC_MECRH	0x134
> >>+#define	REG_AIC_MDCR	0x138
> >>+#define	REG_AIC_MDCRH	0x13C
> >>+#define	REG_AIC_SSCR	0x140
> >>+#define	REG_AIC_SSCRH	0x144
> >>+#define	REG_AIC_SCCR	0x148
> >>+#define	REG_AIC_SCCRH	0x14C
> >>+#define	REG_AIC_EOSCR	0x150
> >
> >Please remove unused defines.
> 
> Okay.
> 
> >
> >>+
> >>+static void __iomem *aic_base;
> >>+static struct irq_domain *aic_domain;
> >>+
> >>+static void nuc900_irq_mask(struct irq_data *d)
> >>+{
> >>+	if (d->irq < 32)
> >>+		writel(1 << (d->irq), aic_base + REG_AIC_MDCR);
> >>+	else
> >>+		writel(1 << (d->irq - 32), aic_base + REG_AIC_MDCRH);
> >>+}
> >>+
> >>+static void nuc900_irq_ack(struct irq_data *d)
> >>+{
> >>+	writel(0x01, aic_base + REG_AIC_EOSCR);
> >>+}
> >>+
> >>+static void nuc900_irq_unmask(struct irq_data *d)
> >>+{
> >>+	if (d->irq < 32)
> >>+		writel(1 << (d->irq), aic_base + REG_AIC_MECR);
> >>+	else
> >>+		writel(1 << (d->irq - 32), aic_base + REG_AIC_MECRH);
> >>+}
> >>+
> >>+static struct irq_chip nuc900_irq_chip = {
> >>+	.irq_ack	= nuc900_irq_ack,
> >>+	.irq_mask	= nuc900_irq_mask,
> >>+	.irq_unmask	= nuc900_irq_unmask,
> >>+};
> >>+
> >>+void __exception_irq_entry aic_handle_irq(struct pt_regs *regs)
> >>+{
> >>+	u32 hwirq;
> >>+
> >>+	hwirq = readl(aic_base + REG_AIC_IPER);
> >>+	hwirq = readl(aic_base + REG_AIC_ISNR);
> >>+	if (!hwirq)
> >>+		writel(0x01, aic_base + REG_AIC_EOSCR);
> >
> >Could you explain what's going on here?
> 
> AIC_IPER, When the AIC generates the interrupt, VECTOR represents
> the interrupt channel number that is active, enabled, and has the
> highest priority.
> 
> The value of VECTOR is copied to the register AIC_ISNR thereafter by
> the AIC. This register was restored a value 0 after it was read by
> the
> interrupt handler.

So, iiuc, the first readl() of AIC_IPER kicks the AIC to copy the value
of VECTOR into AIC_ISNR?  Then we can read it?

If so, please add a comment above the code explaining that.

> So I must read two registers for one irq number, after read IPER,
> the ISNR(bit0:5) will be updated. ISNR value has no need do offset,
> it is better than read IPER(bit2:7).

But you aren't using the value from the first readl(...AIC_IPER)?  You
overwrite hwirq with the value from the second readl(...AIC_ISNR)
...

The first part of your explaination makes sense, but this part isn't
clear to me.


> ?writel(0x01, aic_base + REG_AIC_EOSCR);??seems not necessary here,
> since irqchip has the ack interface. I will remove it.

Ok, thanks.

> This AIC_EOSCR register is used by the interrupt service routine to
> indicate that it is completely served. Thus, the
> interrupt handler can write any value to this register to indicate
> the end of its interrupt service.

A short comment in the ack routine would be helpful.


> >>+IRQCHIP_DECLARE(nuc900, "nuvoton,nuc900-aic", aic_of_init);
> >
> >afaict, there is no 'nuc900', that's a family.  If so, this compatible
> >needs to be 'nuvoton,nuc970-aic'.
> >
> 
> IRQCHIP_DECLARE(nuvoton, "nuvoton,nuc900-aic", aic_of_init);, change
> nuc900 to nuvoton, ok?

No, I was only talking about the second argument.  The compatible
string.  For devicetree, it needs to refer to a specific model number.
I suspect 'nuc900' is equivalent to saying 'nuc9xx'.  Meaning it refers
to a family of devices.  The compatible string needs to refer
specifically to the first model that the binding is compatible with.  In
this case, I presume that would be 'nuvoton,nuc970-aic'.

thx,

Jason.

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

* [PATCH v2 02/10] irqchip: add irqchip driver for nuc900
  2016-07-14 13:54       ` Jason Cooper
@ 2016-07-15  5:15         ` Wan Zongshun
  2016-07-15  7:00           ` Arnd Bergmann
  0 siblings, 1 reply; 45+ messages in thread
From: Wan Zongshun @ 2016-07-15  5:15 UTC (permalink / raw)
  To: linux-arm-kernel



On 2016?07?14? 21:54, Jason Cooper wrote:
> Hi Wan Zongshun,
>
> On Thu, Jul 14, 2016 at 11:36:53AM +0800, Wan Zongshun wrote:
>> On 2016?07?14? 04:09, Jason Cooper wrote:
>>> On Sun, Jul 10, 2016 at 03:27:22PM +0800, Wan Zongshun wrote:
>>>> This patch is to add irqchip driver support for nuc900 plat,
>>>> current this driver only supports nuc970 SoC.
>>>>
>>>> Signed-off-by: Wan Zongshun <mcuos.com@gmail.com>
>>>> ---
>>>>   arch/arm/mach-w90x900/include/mach/irqs.h |   5 +
>>>>   drivers/irqchip/Makefile                  |   1 +
>>>>   drivers/irqchip/irq-nuc900.c              | 150 ++++++++++++++++++++++++++++++
>>>>   3 files changed, 156 insertions(+)
>>>>   create mode 100644 drivers/irqchip/irq-nuc900.c
>>>>
>>>> diff --git a/arch/arm/mach-w90x900/include/mach/irqs.h b/arch/arm/mach-w90x900/include/mach/irqs.h
>>>> index 9d5cba3..3b035c6 100644
>>>> --- a/arch/arm/mach-w90x900/include/mach/irqs.h
>>>> +++ b/arch/arm/mach-w90x900/include/mach/irqs.h
>>>> @@ -59,7 +59,12 @@
>>>>   #define IRQ_KPI		W90X900_IRQ(29)
>>>>   #define IRQ_P2SGROUP	W90X900_IRQ(30)
>>>>   #define IRQ_ADC		W90X900_IRQ(31)
>>>> +
>>>> +#if !defined(CONFIG_SOC_NUC900)
>>>>   #define NR_IRQS		(IRQ_ADC+1)
>>>> +#else
>>>> +#define NR_IRQS		62
>>>> +#endif
>>>
>>> Arnd already covered this...
>>>
>>>>
>>>>   /*for irq group*/
>>>>
>>>> diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
>>>> index 38853a1..9ccd5af8a 100644
>>>> --- a/drivers/irqchip/Makefile
>>>> +++ b/drivers/irqchip/Makefile
>>>> @@ -69,3 +69,4 @@ obj-$(CONFIG_PIC32_EVIC)		+= irq-pic32-evic.o
>>>>   obj-$(CONFIG_MVEBU_ODMI)		+= irq-mvebu-odmi.o
>>>>   obj-$(CONFIG_LS_SCFG_MSI)		+= irq-ls-scfg-msi.o
>>>>   obj-$(CONFIG_EZNPS_GIC)			+= irq-eznps.o
>>>> +obj-$(CONFIG_SOC_NUC970)		+= irq-nuc900.o
>>>> diff --git a/drivers/irqchip/irq-nuc900.c b/drivers/irqchip/irq-nuc900.c
>>>> new file mode 100644
>>>> index 0000000..c4b2e39
>>>> --- /dev/null
>>>> +++ b/drivers/irqchip/irq-nuc900.c
>>>> @@ -0,0 +1,150 @@
>>>> +/*
>>>> + * Copyright 2016 Wan Zongshun <mcuos.com@gmail.com>
>>>> + *
>>>> + * The code contained herein is licensed under the GNU General Public
>>>> + * License. You may obtain a copy of the GNU General Public License
>>>> + * Version 2 or later at the following locations:
>>>> + *
>>>> + * http://www.opensource.org/licenses/gpl-license.html
>>>> + * http://www.gnu.org/copyleft/gpl.html
>>>> + */
>>>> +
>>>> +#include <linux/module.h>
>>>> +#include <linux/init.h>
>>>> +#include <linux/irq.h>
>>>> +#include <linux/irqchip.h>
>>>> +#include <linux/irqdomain.h>
>>>> +#include <linux/io.h>
>>>> +#include <linux/ioport.h>
>>>> +#include <linux/of_address.h>
>>>> +#include <linux/of_irq.h>
>>>> +
>>>> +#include <asm/exception.h>
>>>> +#include <asm/hardirq.h>
>>>> +
>>>> +#define	REG_AIC_SCR1	0x00
>>>> +#define	REG_AIC_SCR2	0x04
>>>> +#define	REG_AIC_SCR3	0x08
>>>> +#define	REG_AIC_SCR4	0x0C
>>>> +#define	REG_AIC_SCR5	0x10
>>>> +#define	REG_AIC_SCR6	0x14
>>>> +#define	REG_AIC_SCR7	0x18
>>>> +#define	REG_AIC_SCR8	0x1C
>>>> +#define	REG_AIC_SCR9	0x20
>>>> +#define	REG_AIC_SCR10	0x24
>>>> +#define	REG_AIC_SCR11	0x28
>>>> +#define	REG_AIC_SCR12	0x2C
>>>> +#define	REG_AIC_SCR13	0x30
>>>> +#define	REG_AIC_SCR14	0x34
>>>> +#define	REG_AIC_SCR15	0x38
>>>> +#define	REG_AIC_IRSR	0x100
>>>> +#define	REG_AIC_IRSRH	0x104
>>>> +#define	REG_AIC_IASR	0x108
>>>> +#define	REG_AIC_IASRH	0x10C
>>>> +#define	REG_AIC_ISR	0x110
>>>> +#define	REG_AIC_ISRH	0x114
>>>> +#define	REG_AIC_IPER	0x118
>>>> +#define	REG_AIC_ISNR	0x120
>>>> +#define	REG_AIC_OISR	0x124
>>>> +#define	REG_AIC_IMR	0x128
>>>> +#define	REG_AIC_IMRH	0x12C
>>>> +#define	REG_AIC_MECR	0x130
>>>> +#define	REG_AIC_MECRH	0x134
>>>> +#define	REG_AIC_MDCR	0x138
>>>> +#define	REG_AIC_MDCRH	0x13C
>>>> +#define	REG_AIC_SSCR	0x140
>>>> +#define	REG_AIC_SSCRH	0x144
>>>> +#define	REG_AIC_SCCR	0x148
>>>> +#define	REG_AIC_SCCRH	0x14C
>>>> +#define	REG_AIC_EOSCR	0x150
>>>
>>> Please remove unused defines.
>>
>> Okay.
>>
>>>
>>>> +
>>>> +static void __iomem *aic_base;
>>>> +static struct irq_domain *aic_domain;
>>>> +
>>>> +static void nuc900_irq_mask(struct irq_data *d)
>>>> +{
>>>> +	if (d->irq < 32)
>>>> +		writel(1 << (d->irq), aic_base + REG_AIC_MDCR);
>>>> +	else
>>>> +		writel(1 << (d->irq - 32), aic_base + REG_AIC_MDCRH);
>>>> +}
>>>> +
>>>> +static void nuc900_irq_ack(struct irq_data *d)
>>>> +{
>>>> +	writel(0x01, aic_base + REG_AIC_EOSCR);
>>>> +}
>>>> +
>>>> +static void nuc900_irq_unmask(struct irq_data *d)
>>>> +{
>>>> +	if (d->irq < 32)
>>>> +		writel(1 << (d->irq), aic_base + REG_AIC_MECR);
>>>> +	else
>>>> +		writel(1 << (d->irq - 32), aic_base + REG_AIC_MECRH);
>>>> +}
>>>> +
>>>> +static struct irq_chip nuc900_irq_chip = {
>>>> +	.irq_ack	= nuc900_irq_ack,
>>>> +	.irq_mask	= nuc900_irq_mask,
>>>> +	.irq_unmask	= nuc900_irq_unmask,
>>>> +};
>>>> +
>>>> +void __exception_irq_entry aic_handle_irq(struct pt_regs *regs)
>>>> +{
>>>> +	u32 hwirq;
>>>> +
>>>> +	hwirq = readl(aic_base + REG_AIC_IPER);
>>>> +	hwirq = readl(aic_base + REG_AIC_ISNR);
>>>> +	if (!hwirq)
>>>> +		writel(0x01, aic_base + REG_AIC_EOSCR);
>>>
>>> Could you explain what's going on here?
>>
>> AIC_IPER, When the AIC generates the interrupt, VECTOR represents
>> the interrupt channel number that is active, enabled, and has the
>> highest priority.
>>
>> The value of VECTOR is copied to the register AIC_ISNR thereafter by
>> the AIC. This register was restored a value 0 after it was read by
>> the
>> interrupt handler.
>
> So, iiuc, the first readl() of AIC_IPER kicks the AIC to copy the value
> of VECTOR into AIC_ISNR?  Then we can read it?
>
> If so, please add a comment above the code explaining that.
>
>> So I must read two registers for one irq number, after read IPER,
>> the ISNR(bit0:5) will be updated. ISNR value has no need do offset,
>> it is better than read IPER(bit2:7).
>
> But you aren't using the value from the first readl(...AIC_IPER)?  You
> overwrite hwirq with the value from the second readl(...AIC_ISNR)
> ...
>
> The first part of your explaination makes sense, but this part isn't
> clear to me.

Actually, I have two choice to implement this function:

option1:

void __exception_irq_entry aic_handle_irq(struct pt_regs *regs)
{
	u32 hwirq;

	(void)readl(aic_base + REG_AIC_IPER);
	hwirq = readl(aic_base + REG_AIC_ISNR);

	handle_IRQ((irq_find_mapping(aic_domain, hwirq)), regs);
}

option2:

void __exception_irq_entry aic_handle_irq(struct pt_regs *regs)
{
	u32 hwirq;

	hwirq = readl(aic_base + REG_AIC_IPER);
	hwirq <<= 2;

	handle_IRQ((irq_find_mapping(aic_domain, hwirq)), regs);
}

Though the option2 do shift for hwirq, but it seems better than do io 
operation by readl,so I prefer to option2, agree?

>
>
>> ?writel(0x01, aic_base + REG_AIC_EOSCR);??seems not necessary here,
>> since irqchip has the ack interface. I will remove it.
>
> Ok, thanks.
>
>> This AIC_EOSCR register is used by the interrupt service routine to
>> indicate that it is completely served. Thus, the
>> interrupt handler can write any value to this register to indicate
>> the end of its interrupt service.
>
> A short comment in the ack routine would be helpful.
>
>
>>>> +IRQCHIP_DECLARE(nuc900, "nuvoton,nuc900-aic", aic_of_init);
>>>
>>> afaict, there is no 'nuc900', that's a family.  If so, this compatible
>>> needs to be 'nuvoton,nuc970-aic'.
>>>
>>
>> IRQCHIP_DECLARE(nuvoton, "nuvoton,nuc900-aic", aic_of_init);, change
>> nuc900 to nuvoton, ok?
>
> No, I was only talking about the second argument.  The compatible
> string.  For devicetree, it needs to refer to a specific model number.
> I suspect 'nuc900' is equivalent to saying 'nuc9xx'.  Meaning it refers
> to a family of devices.  The compatible string needs to refer
> specifically to the first model that the binding is compatible with.  In
> this case, I presume that would be 'nuvoton,nuc970-aic'.
>
> thx,
>
> Jason.
>
>

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

* [PATCH v2 02/10] irqchip: add irqchip driver for nuc900
  2016-07-15  5:15         ` Wan Zongshun
@ 2016-07-15  7:00           ` Arnd Bergmann
  2016-07-15  9:44             ` Wan ZongShun
  0 siblings, 1 reply; 45+ messages in thread
From: Arnd Bergmann @ 2016-07-15  7:00 UTC (permalink / raw)
  To: linux-arm-kernel

On Friday, July 15, 2016 1:15:58 PM CEST Wan Zongshun wrote:
> 
> Actually, I have two choice to implement this function:
> 
> option1:
> 
> void __exception_irq_entry aic_handle_irq(struct pt_regs *regs)
> {
>         u32 hwirq;
> 
>         (void)readl(aic_base + REG_AIC_IPER);
>         hwirq = readl(aic_base + REG_AIC_ISNR);
> 
>         handle_IRQ((irq_find_mapping(aic_domain, hwirq)), regs);
> }

(side note: I think you want handle_domain_irq())

> option2:
> 
> void __exception_irq_entry aic_handle_irq(struct pt_regs *regs)
> {
>         u32 hwirq;
> 
>         hwirq = readl(aic_base + REG_AIC_IPER);
>         hwirq <<= 2;
> 
>         handle_IRQ((irq_find_mapping(aic_domain, hwirq)), regs);
> }
> 
> Though the option2 do shift for hwirq, but it seems better than do io 
> operation by readl,so I prefer to option2, agree?

That will only return an irq number that is a multiple of four, which
seems wrong since the numbers are not that. Did you mean to write

	hwirq = ilog2(hwirq);   ?

That assumes that REG_AIC_IPER contains a 32-bit value with one single
bit set to indicate which IRQ was triggered.

If the difference is only in performance, you could try measuring which
of the two ends up being faster.

	Arnd

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

* [PATCH v2 02/10] irqchip: add irqchip driver for nuc900
  2016-07-15  7:00           ` Arnd Bergmann
@ 2016-07-15  9:44             ` Wan ZongShun
  2016-07-15 10:02               ` Arnd Bergmann
  2016-07-15 15:45               ` Jason Cooper
  0 siblings, 2 replies; 45+ messages in thread
From: Wan ZongShun @ 2016-07-15  9:44 UTC (permalink / raw)
  To: linux-arm-kernel

2016-07-15 15:00 GMT+08:00 Arnd Bergmann <arnd@arndb.de>:
> On Friday, July 15, 2016 1:15:58 PM CEST Wan Zongshun wrote:
>>
>> Actually, I have two choice to implement this function:
>>
>> option1:
>>
>> void __exception_irq_entry aic_handle_irq(struct pt_regs *regs)
>> {
>>         u32 hwirq;
>>
>>         (void)readl(aic_base + REG_AIC_IPER);
>>         hwirq = readl(aic_base + REG_AIC_ISNR);
>>
>>         handle_IRQ((irq_find_mapping(aic_domain, hwirq)), regs);
>> }
>
> (side note: I think you want handle_domain_irq())
>
>> option2:
>>
>> void __exception_irq_entry aic_handle_irq(struct pt_regs *regs)
>> {
>>         u32 hwirq;
>>
>>         hwirq = readl(aic_base + REG_AIC_IPER);
>>         hwirq <<= 2;
>>
>>         handle_IRQ((irq_find_mapping(aic_domain, hwirq)), regs);
>> }
>>
>> Though the option2 do shift for hwirq, but it seems better than do io
>> operation by readl,so I prefer to option2, agree?
>
> That will only return an irq number that is a multiple of four, which
> seems wrong since the numbers are not that. Did you mean to write
>
>         hwirq = ilog2(hwirq);   ?

Sorry, my fault, I mean hwirq >>= 2, bit[7:2] indicates which irq is triggering.
so I have to do right shift 2 for IPER value.

>
> That assumes that REG_AIC_IPER contains a 32-bit value with one single
> bit set to indicate which IRQ was triggered.
>
> If the difference is only in performance, you could try measuring which
> of the two ends up being faster.

It seems hard to measure. I think Do IO operation should be slower
than shift 2. :)

>
>         Arnd



-- 
---
Vincent Wan(Zongshun)
www.mcuos.com

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

* [PATCH v2 02/10] irqchip: add irqchip driver for nuc900
  2016-07-15  9:44             ` Wan ZongShun
@ 2016-07-15 10:02               ` Arnd Bergmann
  2016-07-21 18:45                 ` Jason Cooper
  2016-07-15 15:45               ` Jason Cooper
  1 sibling, 1 reply; 45+ messages in thread
From: Arnd Bergmann @ 2016-07-15 10:02 UTC (permalink / raw)
  To: linux-arm-kernel

On Friday, July 15, 2016 5:44:50 PM CEST Wan ZongShun wrote:
> 2016-07-15 15:00 GMT+08:00 Arnd Bergmann <arnd@arndb.de>:
> > On Friday, July 15, 2016 1:15:58 PM CEST Wan Zongshun wrote:
> >>
> >> Actually, I have two choice to implement this function:
> >>
> >> option1:
> >>
> >> void __exception_irq_entry aic_handle_irq(struct pt_regs *regs)
> >> {
> >>         u32 hwirq;
> >>
> >>         (void)readl(aic_base + REG_AIC_IPER);
> >>         hwirq = readl(aic_base + REG_AIC_ISNR);
> >>
> >>         handle_IRQ((irq_find_mapping(aic_domain, hwirq)), regs);
> >> }
> >
> > (side note: I think you want handle_domain_irq())
> >
> >> option2:
> >>
> >> void __exception_irq_entry aic_handle_irq(struct pt_regs *regs)
> >> {
> >>         u32 hwirq;
> >>
> >>         hwirq = readl(aic_base + REG_AIC_IPER);
> >>         hwirq <<= 2;
> >>
> >>         handle_IRQ((irq_find_mapping(aic_domain, hwirq)), regs);
> >> }
> >>
> >> Though the option2 do shift for hwirq, but it seems better than do io
> >> operation by readl,so I prefer to option2, agree?
> >
> > That will only return an irq number that is a multiple of four, which
> > seems wrong since the numbers are not that. Did you mean to write
> >
> >         hwirq = ilog2(hwirq);   ?
> 
> Sorry, my fault, I mean hwirq >>= 2, bit[7:2] indicates which irq is triggering.
> so I have to do right shift 2 for IPER value.

Ok, got it.

> > That assumes that REG_AIC_IPER contains a 32-bit value with one single
> > bit set to indicate which IRQ was triggered.
> >
> > If the difference is only in performance, you could try measuring which
> > of the two ends up being faster.
> 
> It seems hard to measure. I think Do IO operation should be slower
> than shift 2. 

It depends on how fast that particular I/O path is. A lot of readl()
operations are awfully slow, but the hardware design for the interrupt
controller may in fact have optimized this to be reasonably fast.

Another option would be to avoid the shift and just use the raw value
of the REG_AIC_IPER register as the hwirq, with a custom map()
callback that turns shifts the number read from the DT two bits
so it matches the register value.

	Arnd

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

* [PATCH v2 02/10] irqchip: add irqchip driver for nuc900
  2016-07-15  9:44             ` Wan ZongShun
  2016-07-15 10:02               ` Arnd Bergmann
@ 2016-07-15 15:45               ` Jason Cooper
  1 sibling, 0 replies; 45+ messages in thread
From: Jason Cooper @ 2016-07-15 15:45 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jul 15, 2016 at 05:44:50PM +0800, Wan ZongShun wrote:
> 2016-07-15 15:00 GMT+08:00 Arnd Bergmann <arnd@arndb.de>:
> > On Friday, July 15, 2016 1:15:58 PM CEST Wan Zongshun wrote:
> >>
> >> Actually, I have two choice to implement this function:
> >>
> >> option1:
> >>
> >> void __exception_irq_entry aic_handle_irq(struct pt_regs *regs)
> >> {
> >>         u32 hwirq;
> >>
> >>         (void)readl(aic_base + REG_AIC_IPER);
> >>         hwirq = readl(aic_base + REG_AIC_ISNR);
> >>
> >>         handle_IRQ((irq_find_mapping(aic_domain, hwirq)), regs);
> >> }
> >
> > (side note: I think you want handle_domain_irq())
> >
> >> option2:
> >>
> >> void __exception_irq_entry aic_handle_irq(struct pt_regs *regs)
> >> {
> >>         u32 hwirq;
> >>
> >>         hwirq = readl(aic_base + REG_AIC_IPER);
> >>         hwirq <<= 2;
> >>
> >>         handle_IRQ((irq_find_mapping(aic_domain, hwirq)), regs);
> >> }
> >>
> >> Though the option2 do shift for hwirq, but it seems better than do io
> >> operation by readl,so I prefer to option2, agree?
> >
> > That will only return an irq number that is a multiple of four, which
> > seems wrong since the numbers are not that. Did you mean to write
> >
> >         hwirq = ilog2(hwirq);   ?
> 
> Sorry, my fault, I mean hwirq >>= 2, bit[7:2] indicates which irq is triggering.
> so I have to do right shift 2 for IPER value.

Ok, this makes a lot more sense now. :)

> > That assumes that REG_AIC_IPER contains a 32-bit value with one single
> > bit set to indicate which IRQ was triggered.
> >
> > If the difference is only in performance, you could try measuring which
> > of the two ends up being faster.
> 
> It seems hard to measure. I think Do IO operation should be slower
> than shift 2. :)

Agreed.

thx,

Jason.

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

* [PATCH v2 03/10] Clocksource: add nuc970 clocksource driver
  2016-07-12  8:28       ` Arnd Bergmann
@ 2016-07-21 12:52         ` Daniel Lezcano
  2016-07-21 12:54           ` Arnd Bergmann
  0 siblings, 1 reply; 45+ messages in thread
From: Daniel Lezcano @ 2016-07-21 12:52 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Jul 12, 2016 at 10:28:35AM +0200, Arnd Bergmann wrote:

[ ... ]

> > > Also the init function has changed its return type in linux-next:
> > >
> > >> +static void __init nuc970_timer_of_init(struct device_node *node)
> > >
> > > This now needs to return an error code or we get:
> > >
> > > ../include/linux/of.h:1004:20: error: comparison of distinct pointer types lacks a cast [-Werror]
> > >          .data = (fn == (fn_type)NULL) ? fn : fn  }
> > >
> > > Daniel Lezcano seems to have implemented a migration strategy, but I
> > > can't see what you are supposed to do here, since the
> > > CLOCKSOURCE_OF_DECLARE_RET macro is no longer part of linux-next.
> > 
> > Wait for Daniel's comments? or what should I do now?
> 
> Yes, let's see what he says. I guess from the timing, this will probably
> have to wait for linux-4.9 anyway, and then we have no problem because the
> API change will make it into 4.8.

CLOCKSOURCE_OF_DECLARE_RET was renamed back to CLOCKSOURCE_OF_DECLARE but it 
expects now an init function returning an 'int'.

These changes are now in tip/timers/core, so in linux-next.

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

* [PATCH v2 03/10] Clocksource: add nuc970 clocksource driver
  2016-07-21 12:52         ` Daniel Lezcano
@ 2016-07-21 12:54           ` Arnd Bergmann
  0 siblings, 0 replies; 45+ messages in thread
From: Arnd Bergmann @ 2016-07-21 12:54 UTC (permalink / raw)
  To: linux-arm-kernel

On Thursday, July 21, 2016 2:52:24 PM CEST Daniel Lezcano wrote:
> On Tue, Jul 12, 2016 at 10:28:35AM +0200, Arnd Bergmann wrote:
> 
> [ ... ]
> 
> > > > Also the init function has changed its return type in linux-next:
> > > >
> > > >> +static void __init nuc970_timer_of_init(struct device_node *node)
> > > >
> > > > This now needs to return an error code or we get:
> > > >
> > > > ../include/linux/of.h:1004:20: error: comparison of distinct pointer types lacks a cast [-Werror]
> > > >          .data = (fn == (fn_type)NULL) ? fn : fn  }
> > > >
> > > > Daniel Lezcano seems to have implemented a migration strategy, but I
> > > > can't see what you are supposed to do here, since the
> > > > CLOCKSOURCE_OF_DECLARE_RET macro is no longer part of linux-next.
> > > 
> > > Wait for Daniel's comments? or what should I do now?
> > 
> > Yes, let's see what he says. I guess from the timing, this will probably
> > have to wait for linux-4.9 anyway, and then we have no problem because the
> > API change will make it into 4.8.
> 
> CLOCKSOURCE_OF_DECLARE_RET was renamed back to CLOCKSOURCE_OF_DECLARE but it 
> expects now an init function returning an 'int'.
> 
> These changes are now in tip/timers/core, so in linux-next.

Ok, so the driver could be merged on top of that, but it's really
late for 4.8 now, so we'd just wait until after the merge window
anyway.

	Arnd

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

* [PATCH v2 02/10] irqchip: add irqchip driver for nuc900
  2016-07-15 10:02               ` Arnd Bergmann
@ 2016-07-21 18:45                 ` Jason Cooper
  0 siblings, 0 replies; 45+ messages in thread
From: Jason Cooper @ 2016-07-21 18:45 UTC (permalink / raw)
  To: linux-arm-kernel

Wan ZongShun,

On Fri, Jul 15, 2016 at 12:02:55PM +0200, Arnd Bergmann wrote:
> On Friday, July 15, 2016 5:44:50 PM CEST Wan ZongShun wrote:
> > 2016-07-15 15:00 GMT+08:00 Arnd Bergmann <arnd@arndb.de>:
> > > On Friday, July 15, 2016 1:15:58 PM CEST Wan Zongshun wrote:
...
> > > That assumes that REG_AIC_IPER contains a 32-bit value with one single
> > > bit set to indicate which IRQ was triggered.
> > >
> > > If the difference is only in performance, you could try measuring which
> > > of the two ends up being faster.
> > 
> > It seems hard to measure. I think Do IO operation should be slower
> > than shift 2. 
> 
> It depends on how fast that particular I/O path is. A lot of readl()
> operations are awfully slow, but the hardware design for the interrupt
> controller may in fact have optimized this to be reasonably fast.
> 
> Another option would be to avoid the shift and just use the raw value
> of the REG_AIC_IPER register as the hwirq, with a custom map()
> callback that turns shifts the number read from the DT two bits
> so it matches the register value.

Good idea.  Are the two lsb bits constant or do they need to be masked?

thx,

Jason.

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

end of thread, other threads:[~2016-07-21 18:45 UTC | newest]

Thread overview: 45+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-07-10  7:27 [PATCH v2 00/10] ARM: NUC900: Add NUC970 SoC support Wan Zongshun
2016-07-10  7:27 ` [PATCH v2 01/10] ARM: NUC900: Add nuc970 machine support Wan Zongshun
2016-07-10 22:11   ` Arnd Bergmann
2016-07-11 16:04   ` Arnd Bergmann
2016-07-12  4:30     ` Wan Zongshun
2016-07-12  7:14       ` Wan Zongshun
2016-07-12  8:23         ` Arnd Bergmann
2016-07-10  7:27 ` [PATCH v2 02/10] irqchip: add irqchip driver for nuc900 Wan Zongshun
2016-07-10 21:51   ` Paul Gortmaker
2016-07-11  2:19     ` Wan Zongshun
2016-07-11 15:46   ` Arnd Bergmann
2016-07-12  7:04     ` Wan Zongshun
2016-07-12  8:26       ` Arnd Bergmann
2016-07-14  8:52         ` Wan Zongshun
2016-07-14 11:09           ` Arnd Bergmann
2016-07-13 20:09   ` Jason Cooper
2016-07-14  3:36     ` Wan Zongshun
2016-07-14 13:54       ` Jason Cooper
2016-07-15  5:15         ` Wan Zongshun
2016-07-15  7:00           ` Arnd Bergmann
2016-07-15  9:44             ` Wan ZongShun
2016-07-15 10:02               ` Arnd Bergmann
2016-07-21 18:45                 ` Jason Cooper
2016-07-15 15:45               ` Jason Cooper
2016-07-10  7:27 ` [PATCH v2 03/10] Clocksource: add nuc970 clocksource driver Wan Zongshun
2016-07-11 15:36   ` Arnd Bergmann
2016-07-12  7:32     ` Wan Zongshun
2016-07-12  8:28       ` Arnd Bergmann
2016-07-21 12:52         ` Daniel Lezcano
2016-07-21 12:54           ` Arnd Bergmann
2016-07-10  7:27 ` [PATCH v2 04/10] clk: add Clock driver for nuc970 Wan Zongshun
2016-07-11 22:14   ` Michael Turquette
2016-07-10  7:27 ` [PATCH v2 05/10] power/reset: Add reset driver support for nuc900 Wan Zongshun
2016-07-10 21:56   ` Paul Gortmaker
2016-07-11  2:30     ` Wan Zongshun
2016-07-11  2:58       ` Paul Gortmaker
2016-07-10  7:27 ` [PATCH v2 06/10] soc: Add SoC specific " Wan Zongshun
2016-07-11  8:03   ` Arnd Bergmann
2016-07-11  9:07     ` Wan Zongshun
2016-07-11 10:24       ` Arnd Bergmann
2016-07-11 10:28         ` Wan ZongShun
2016-07-11 10:36           ` Arnd Bergmann
2016-07-12  9:06     ` Wan Zongshun
2016-07-12  9:50       ` Arnd Bergmann
2016-07-10  7:27 ` [PATCH v2 07/10] ARM: dts: Add clock header file into dt-bindings Wan Zongshun

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