summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Abraham <thomas.abraham@linaro.org>2013-03-09 16:01:52 +0900
committerKukjin Kim <kgene.kim@samsung.com>2013-03-09 16:01:52 +0900
commit36ba5d527e9567ed303bad6e86a5f3c2723470f6 (patch)
tree45729298d0d331a4cea1bd248dc33329dc149726
parentc371dc60aebf7ada4d5b4585ea8f46a3a06f8f04 (diff)
downloadlinux-3.10-36ba5d527e9567ed303bad6e86a5f3c2723470f6.tar.gz
linux-3.10-36ba5d527e9567ed303bad6e86a5f3c2723470f6.tar.bz2
linux-3.10-36ba5d527e9567ed303bad6e86a5f3c2723470f6.zip
ARM: EXYNOS: add device tree support for MCT controller driver
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>
-rw-r--r--Documentation/devicetree/bindings/timer/samsung,exynos4210-mct.txt68
-rw-r--r--arch/arm/mach-exynos/include/mach/irqs.h6
-rw-r--r--arch/arm/mach-exynos/mct.c49
3 files changed, 105 insertions, 18 deletions
diff --git a/Documentation/devicetree/bindings/timer/samsung,exynos4210-mct.txt b/Documentation/devicetree/bindings/timer/samsung,exynos4210-mct.txt
new file mode 100644
index 00000000000..cb47bfbcaee
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/samsung,exynos4210-mct.txt
@@ -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>;
+ };
+ };
diff --git a/arch/arm/mach-exynos/include/mach/irqs.h b/arch/arm/mach-exynos/include/mach/irqs.h
index 1f4dc35cd4b..c0e75d8dd73 100644
--- a/arch/arm/mach-exynos/include/mach/irqs.h
+++ b/arch/arm/mach-exynos/include/mach/irqs.h
@@ -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 */
@@ -323,8 +321,6 @@
#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)
@@ -419,8 +415,6 @@
#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)
diff --git a/arch/arm/mach-exynos/mct.c b/arch/arm/mach-exynos/mct.c
index 1061db4118a..f34c933314f 100644
--- a/arch/arm/mach-exynos/mct.c
+++ b/arch/arm/mach-exynos/mct.c
@@ -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();
}