ARM: EXYNOS: add device tree support for MCT controller driver
authorThomas Abraham <thomas.abraham@linaro.org>
Sat, 9 Mar 2013 07:01:52 +0000 (16:01 +0900)
committerKukjin Kim <kgene.kim@samsung.com>
Sat, 9 Mar 2013 07:01:52 +0000 (16:01 +0900)
Allow the MCT controller base address and interrupts to be
obtained from device tree and remove unused static definitions
of these. The non-dt support for Exynos5250 is removed but
retained for Exynos4210 based platforms.

Cc: Changhwan Youn <chaos.youn@samsung.com>
Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
Reviewed-by: Stephen Warren <swarren@nvidia.com>
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
Documentation/devicetree/bindings/timer/samsung,exynos4210-mct.txt [new file with mode: 0644]
arch/arm/mach-exynos/include/mach/irqs.h
arch/arm/mach-exynos/mct.c

diff --git a/Documentation/devicetree/bindings/timer/samsung,exynos4210-mct.txt b/Documentation/devicetree/bindings/timer/samsung,exynos4210-mct.txt
new file mode 100644 (file)
index 0000000..cb47bfb
--- /dev/null
@@ -0,0 +1,68 @@
+Samsung's Multi Core Timer (MCT)
+
+The Samsung's Multi Core Timer (MCT) module includes two main blocks, the
+global timer and CPU local timers. The global timer is a 64-bit free running
+up-counter and can generate 4 interrupts when the counter reaches one of the
+four preset counter values. The CPU local timers are 32-bit free running
+down-counters and generate an interrupt when the counter expires. There is
+one CPU local timer instantiated in MCT for every CPU in the system.
+
+Required properties:
+
+- compatible: should be "samsung,exynos4210-mct".
+  (a) "samsung,exynos4210-mct", for mct compatible with Exynos4210 mct.
+  (b) "samsung,exynos4412-mct", for mct compatible with Exynos4412 mct.
+
+- reg: base address of the mct controller and length of the address space
+  it occupies.
+
+- interrupts: the list of interrupts generated by the controller. The following
+  should be the order of the interrupts specified. The local timer interrupts
+  should be specified after the four global timer interrupts have been
+  specified.
+
+       0: Global Timer Interrupt 0
+       1: Global Timer Interrupt 1
+       2: Global Timer Interrupt 2
+       3: Global Timer Interrupt 3
+       4: Local Timer Interrupt 0
+       5: Local Timer Interrupt 1
+       6: ..
+       7: ..
+       i: Local Timer Interrupt n
+
+Example 1: In this example, the system uses only the first global timer
+          interrupt generated by MCT and the remaining three global timer
+          interrupts are unused. Two local timer interrupts have been
+          specified.
+
+       mct@10050000 {
+               compatible = "samsung,exynos4210-mct";
+               reg = <0x10050000 0x800>;
+               interrupts = <0 57 0>, <0 0 0>, <0 0 0>, <0 0 0>,
+                            <0 42 0>, <0 48 0>;
+       };
+
+Example 2: In this example, the MCT global and local timer interrupts are
+          connected to two seperate interrupt controllers. Hence, an
+          interrupt-map is created to map the interrupts to the respective
+          interrupt controllers.
+
+       mct@101C0000 {
+               compatible = "samsung,exynos4210-mct";
+               reg = <0x101C0000 0x800>;
+               interrupt-controller;
+               #interrups-cells = <2>;
+               interrupt-parent = <&mct_map>;
+               interrupts = <0 0>, <1 0>, <2 0>, <3 0>,
+                            <4 0>, <5 0>;
+
+               mct_map: mct-map {
+                       #interrupt-cells = <2>;
+                       #address-cells = <0>;
+                       #size-cells = <0>;
+                       interrupt-map = <0x0 0 &combiner 23 3>,
+                                       <0x4 0 &gic 0 120 0>,
+                                       <0x5 0 &gic 0 121 0>;
+               };
+       };
index 1f4dc35..c0e75d8 100644 (file)
@@ -30,8 +30,6 @@
 
 /* For EXYNOS4 and EXYNOS5 */
 
-#define EXYNOS_IRQ_MCT_LOCALTIMER      IRQ_PPI(12)
-
 #define EXYNOS_IRQ_EINT16_31           IRQ_SPI(32)
 
 /* For EXYNOS4 SoCs */
 #define EXYNOS5_IRQ_CEC                        IRQ_SPI(114)
 #define EXYNOS5_IRQ_SATA               IRQ_SPI(115)
 
-#define EXYNOS5_IRQ_MCT_L0             IRQ_SPI(120)
-#define EXYNOS5_IRQ_MCT_L1             IRQ_SPI(121)
 #define EXYNOS5_IRQ_MMC44              IRQ_SPI(123)
 #define EXYNOS5_IRQ_MDMA1              IRQ_SPI(124)
 #define EXYNOS5_IRQ_FIMC_LITE0         IRQ_SPI(125)
 #define EXYNOS5_IRQ_PMU_CPU1           COMBINER_IRQ(22, 4)
 
 #define EXYNOS5_IRQ_EINT0              COMBINER_IRQ(23, 0)
-#define EXYNOS5_IRQ_MCT_G0             COMBINER_IRQ(23, 3)
-#define EXYNOS5_IRQ_MCT_G1             COMBINER_IRQ(23, 4)
 
 #define EXYNOS5_IRQ_EINT1              COMBINER_IRQ(24, 0)
 #define EXYNOS5_IRQ_SYSMMU_LITE1_0     COMBINER_IRQ(24, 1)
index 1061db4..f34c933 100644 (file)
@@ -20,6 +20,8 @@
 #include <linux/delay.h>
 #include <linux/percpu.h>
 #include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
 
 #include <asm/arch_timer.h>
 #include <asm/localtimer.h>
@@ -474,14 +476,16 @@ static struct local_timer_ops exynos4_mct_tick_ops __cpuinitdata = {
 };
 #endif /* CONFIG_LOCAL_TIMERS */
 
-static void __init exynos4_timer_resources(void)
+static void __init exynos4_timer_resources(struct device_node *np)
 {
        struct clk *mct_clk;
        mct_clk = clk_get(NULL, "xtal");
 
        clk_rate = clk_get_rate(mct_clk);
 
-       reg_base = S5P_VA_SYSTIMER;
+       reg_base = np ? of_iomap(np, 0) : S5P_VA_SYSTIMER;
+       if (!reg_base)
+               panic("%s: unable to ioremap mct address space\n", __func__);
 
 #ifdef CONFIG_LOCAL_TIMERS
        if (mct_int_type == MCT_INT_PPI) {
@@ -498,30 +502,51 @@ static void __init exynos4_timer_resources(void)
 #endif /* CONFIG_LOCAL_TIMERS */
 }
 
+static const struct of_device_id exynos_mct_ids[] = {
+       { .compatible = "samsung,exynos4210-mct", .data = (void *)MCT_INT_SPI },
+       { .compatible = "samsung,exynos4412-mct", .data = (void *)MCT_INT_PPI },
+};
+
 void __init exynos4_timer_init(void)
 {
+       struct device_node *np = NULL;
+       const struct of_device_id *match;
+       u32 nr_irqs, i;
+
        if (soc_is_exynos5440()) {
                arch_timer_of_register();
                return;
        }
 
-       if (soc_is_exynos4210()) {
+#ifdef CONFIG_OF
+       np = of_find_matching_node_and_match(NULL, exynos_mct_ids, &match);
+#endif
+       if (np) {
+               mct_int_type = (u32)(match->data);
+
+               /* This driver uses only one global timer interrupt */
+               mct_irqs[MCT_G0_IRQ] = irq_of_parse_and_map(np, MCT_G0_IRQ);
+
+               /*
+                * Find out the number of local irqs specified. The local
+                * timer irqs are specified after the four global timer
+                * irqs are specified.
+                */
+#ifdef CONFIG_OF
+               nr_irqs = of_irq_count(np);
+#endif
+               for (i = MCT_L0_IRQ; i < nr_irqs; i++)
+                       mct_irqs[i] = irq_of_parse_and_map(np, i);
+       } else if (soc_is_exynos4210()) {
                mct_irqs[MCT_G0_IRQ] = EXYNOS4_IRQ_MCT_G0;
                mct_irqs[MCT_L0_IRQ] = EXYNOS4_IRQ_MCT_L0;
                mct_irqs[MCT_L1_IRQ] = EXYNOS4_IRQ_MCT_L1;
                mct_int_type = MCT_INT_SPI;
-       } else if (soc_is_exynos5250()) {
-               mct_irqs[MCT_G0_IRQ] = EXYNOS5_IRQ_MCT_G0;
-               mct_irqs[MCT_L0_IRQ] = EXYNOS5_IRQ_MCT_L0;
-               mct_irqs[MCT_L1_IRQ] = EXYNOS5_IRQ_MCT_L1;
-               mct_int_type = MCT_INT_SPI;
        } else {
-               mct_irqs[MCT_G0_IRQ] = EXYNOS4_IRQ_MCT_G0;
-               mct_irqs[MCT_L0_IRQ] = EXYNOS_IRQ_MCT_LOCALTIMER;
-               mct_int_type = MCT_INT_PPI;
+               panic("unable to determine mct controller type\n");
        }
 
-       exynos4_timer_resources();
+       exynos4_timer_resources(np);
        exynos4_clocksource_init();
        exynos4_clockevent_init();
 }