* [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).