diff options
-rw-r--r-- | Documentation/devicetree/bindings/timer/samsung,exynos4210-mct.txt | 68 | ||||
-rw-r--r-- | arch/arm/mach-exynos/include/mach/irqs.h | 6 | ||||
-rw-r--r-- | arch/arm/mach-exynos/mct.c | 49 |
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 000000000000..cb47bfbcaeea --- /dev/null +++ b/Documentation/devicetree/bindings/timer/samsung,exynos4210-mct.txt | |||
@@ -0,0 +1,68 @@ | |||
1 | Samsung's Multi Core Timer (MCT) | ||
2 | |||
3 | The Samsung's Multi Core Timer (MCT) module includes two main blocks, the | ||
4 | global timer and CPU local timers. The global timer is a 64-bit free running | ||
5 | up-counter and can generate 4 interrupts when the counter reaches one of the | ||
6 | four preset counter values. The CPU local timers are 32-bit free running | ||
7 | down-counters and generate an interrupt when the counter expires. There is | ||
8 | one CPU local timer instantiated in MCT for every CPU in the system. | ||
9 | |||
10 | Required properties: | ||
11 | |||
12 | - compatible: should be "samsung,exynos4210-mct". | ||
13 | (a) "samsung,exynos4210-mct", for mct compatible with Exynos4210 mct. | ||
14 | (b) "samsung,exynos4412-mct", for mct compatible with Exynos4412 mct. | ||
15 | |||
16 | - reg: base address of the mct controller and length of the address space | ||
17 | it occupies. | ||
18 | |||
19 | - interrupts: the list of interrupts generated by the controller. The following | ||
20 | should be the order of the interrupts specified. The local timer interrupts | ||
21 | should be specified after the four global timer interrupts have been | ||
22 | specified. | ||
23 | |||
24 | 0: Global Timer Interrupt 0 | ||
25 | 1: Global Timer Interrupt 1 | ||
26 | 2: Global Timer Interrupt 2 | ||
27 | 3: Global Timer Interrupt 3 | ||
28 | 4: Local Timer Interrupt 0 | ||
29 | 5: Local Timer Interrupt 1 | ||
30 | 6: .. | ||
31 | 7: .. | ||
32 | i: Local Timer Interrupt n | ||
33 | |||
34 | Example 1: In this example, the system uses only the first global timer | ||
35 | interrupt generated by MCT and the remaining three global timer | ||
36 | interrupts are unused. Two local timer interrupts have been | ||
37 | specified. | ||
38 | |||
39 | mct@10050000 { | ||
40 | compatible = "samsung,exynos4210-mct"; | ||
41 | reg = <0x10050000 0x800>; | ||
42 | interrupts = <0 57 0>, <0 0 0>, <0 0 0>, <0 0 0>, | ||
43 | <0 42 0>, <0 48 0>; | ||
44 | }; | ||
45 | |||
46 | Example 2: In this example, the MCT global and local timer interrupts are | ||
47 | connected to two seperate interrupt controllers. Hence, an | ||
48 | interrupt-map is created to map the interrupts to the respective | ||
49 | interrupt controllers. | ||
50 | |||
51 | mct@101C0000 { | ||
52 | compatible = "samsung,exynos4210-mct"; | ||
53 | reg = <0x101C0000 0x800>; | ||
54 | interrupt-controller; | ||
55 | #interrups-cells = <2>; | ||
56 | interrupt-parent = <&mct_map>; | ||
57 | interrupts = <0 0>, <1 0>, <2 0>, <3 0>, | ||
58 | <4 0>, <5 0>; | ||
59 | |||
60 | mct_map: mct-map { | ||
61 | #interrupt-cells = <2>; | ||
62 | #address-cells = <0>; | ||
63 | #size-cells = <0>; | ||
64 | interrupt-map = <0x0 0 &combiner 23 3>, | ||
65 | <0x4 0 &gic 0 120 0>, | ||
66 | <0x5 0 &gic 0 121 0>; | ||
67 | }; | ||
68 | }; | ||
diff --git a/arch/arm/mach-exynos/include/mach/irqs.h b/arch/arm/mach-exynos/include/mach/irqs.h index 1f4dc35cd4b9..c0e75d8dd737 100644 --- a/arch/arm/mach-exynos/include/mach/irqs.h +++ b/arch/arm/mach-exynos/include/mach/irqs.h | |||
@@ -30,8 +30,6 @@ | |||
30 | 30 | ||
31 | /* For EXYNOS4 and EXYNOS5 */ | 31 | /* For EXYNOS4 and EXYNOS5 */ |
32 | 32 | ||
33 | #define EXYNOS_IRQ_MCT_LOCALTIMER IRQ_PPI(12) | ||
34 | |||
35 | #define EXYNOS_IRQ_EINT16_31 IRQ_SPI(32) | 33 | #define EXYNOS_IRQ_EINT16_31 IRQ_SPI(32) |
36 | 34 | ||
37 | /* For EXYNOS4 SoCs */ | 35 | /* For EXYNOS4 SoCs */ |
@@ -323,8 +321,6 @@ | |||
323 | #define EXYNOS5_IRQ_CEC IRQ_SPI(114) | 321 | #define EXYNOS5_IRQ_CEC IRQ_SPI(114) |
324 | #define EXYNOS5_IRQ_SATA IRQ_SPI(115) | 322 | #define EXYNOS5_IRQ_SATA IRQ_SPI(115) |
325 | 323 | ||
326 | #define EXYNOS5_IRQ_MCT_L0 IRQ_SPI(120) | ||
327 | #define EXYNOS5_IRQ_MCT_L1 IRQ_SPI(121) | ||
328 | #define EXYNOS5_IRQ_MMC44 IRQ_SPI(123) | 324 | #define EXYNOS5_IRQ_MMC44 IRQ_SPI(123) |
329 | #define EXYNOS5_IRQ_MDMA1 IRQ_SPI(124) | 325 | #define EXYNOS5_IRQ_MDMA1 IRQ_SPI(124) |
330 | #define EXYNOS5_IRQ_FIMC_LITE0 IRQ_SPI(125) | 326 | #define EXYNOS5_IRQ_FIMC_LITE0 IRQ_SPI(125) |
@@ -419,8 +415,6 @@ | |||
419 | #define EXYNOS5_IRQ_PMU_CPU1 COMBINER_IRQ(22, 4) | 415 | #define EXYNOS5_IRQ_PMU_CPU1 COMBINER_IRQ(22, 4) |
420 | 416 | ||
421 | #define EXYNOS5_IRQ_EINT0 COMBINER_IRQ(23, 0) | 417 | #define EXYNOS5_IRQ_EINT0 COMBINER_IRQ(23, 0) |
422 | #define EXYNOS5_IRQ_MCT_G0 COMBINER_IRQ(23, 3) | ||
423 | #define EXYNOS5_IRQ_MCT_G1 COMBINER_IRQ(23, 4) | ||
424 | 418 | ||
425 | #define EXYNOS5_IRQ_EINT1 COMBINER_IRQ(24, 0) | 419 | #define EXYNOS5_IRQ_EINT1 COMBINER_IRQ(24, 0) |
426 | #define EXYNOS5_IRQ_SYSMMU_LITE1_0 COMBINER_IRQ(24, 1) | 420 | #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 1061db4118aa..f34c933314f3 100644 --- a/arch/arm/mach-exynos/mct.c +++ b/arch/arm/mach-exynos/mct.c | |||
@@ -20,6 +20,8 @@ | |||
20 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
21 | #include <linux/percpu.h> | 21 | #include <linux/percpu.h> |
22 | #include <linux/of.h> | 22 | #include <linux/of.h> |
23 | #include <linux/of_irq.h> | ||
24 | #include <linux/of_address.h> | ||
23 | 25 | ||
24 | #include <asm/arch_timer.h> | 26 | #include <asm/arch_timer.h> |
25 | #include <asm/localtimer.h> | 27 | #include <asm/localtimer.h> |
@@ -474,14 +476,16 @@ static struct local_timer_ops exynos4_mct_tick_ops __cpuinitdata = { | |||
474 | }; | 476 | }; |
475 | #endif /* CONFIG_LOCAL_TIMERS */ | 477 | #endif /* CONFIG_LOCAL_TIMERS */ |
476 | 478 | ||
477 | static void __init exynos4_timer_resources(void) | 479 | static void __init exynos4_timer_resources(struct device_node *np) |
478 | { | 480 | { |
479 | struct clk *mct_clk; | 481 | struct clk *mct_clk; |
480 | mct_clk = clk_get(NULL, "xtal"); | 482 | mct_clk = clk_get(NULL, "xtal"); |
481 | 483 | ||
482 | clk_rate = clk_get_rate(mct_clk); | 484 | clk_rate = clk_get_rate(mct_clk); |
483 | 485 | ||
484 | reg_base = S5P_VA_SYSTIMER; | 486 | reg_base = np ? of_iomap(np, 0) : S5P_VA_SYSTIMER; |
487 | if (!reg_base) | ||
488 | panic("%s: unable to ioremap mct address space\n", __func__); | ||
485 | 489 | ||
486 | #ifdef CONFIG_LOCAL_TIMERS | 490 | #ifdef CONFIG_LOCAL_TIMERS |
487 | if (mct_int_type == MCT_INT_PPI) { | 491 | if (mct_int_type == MCT_INT_PPI) { |
@@ -498,30 +502,51 @@ static void __init exynos4_timer_resources(void) | |||
498 | #endif /* CONFIG_LOCAL_TIMERS */ | 502 | #endif /* CONFIG_LOCAL_TIMERS */ |
499 | } | 503 | } |
500 | 504 | ||
505 | static const struct of_device_id exynos_mct_ids[] = { | ||
506 | { .compatible = "samsung,exynos4210-mct", .data = (void *)MCT_INT_SPI }, | ||
507 | { .compatible = "samsung,exynos4412-mct", .data = (void *)MCT_INT_PPI }, | ||
508 | }; | ||
509 | |||
501 | void __init exynos4_timer_init(void) | 510 | void __init exynos4_timer_init(void) |
502 | { | 511 | { |
512 | struct device_node *np = NULL; | ||
513 | const struct of_device_id *match; | ||
514 | u32 nr_irqs, i; | ||
515 | |||
503 | if (soc_is_exynos5440()) { | 516 | if (soc_is_exynos5440()) { |
504 | arch_timer_of_register(); | 517 | arch_timer_of_register(); |
505 | return; | 518 | return; |
506 | } | 519 | } |
507 | 520 | ||
508 | if (soc_is_exynos4210()) { | 521 | #ifdef CONFIG_OF |
522 | np = of_find_matching_node_and_match(NULL, exynos_mct_ids, &match); | ||
523 | #endif | ||
524 | if (np) { | ||
525 | mct_int_type = (u32)(match->data); | ||
526 | |||
527 | /* This driver uses only one global timer interrupt */ | ||
528 | mct_irqs[MCT_G0_IRQ] = irq_of_parse_and_map(np, MCT_G0_IRQ); | ||
529 | |||
530 | /* | ||
531 | * Find out the number of local irqs specified. The local | ||
532 | * timer irqs are specified after the four global timer | ||
533 | * irqs are specified. | ||
534 | */ | ||
535 | #ifdef CONFIG_OF | ||
536 | nr_irqs = of_irq_count(np); | ||
537 | #endif | ||
538 | for (i = MCT_L0_IRQ; i < nr_irqs; i++) | ||
539 | mct_irqs[i] = irq_of_parse_and_map(np, i); | ||
540 | } else if (soc_is_exynos4210()) { | ||
509 | mct_irqs[MCT_G0_IRQ] = EXYNOS4_IRQ_MCT_G0; | 541 | mct_irqs[MCT_G0_IRQ] = EXYNOS4_IRQ_MCT_G0; |
510 | mct_irqs[MCT_L0_IRQ] = EXYNOS4_IRQ_MCT_L0; | 542 | mct_irqs[MCT_L0_IRQ] = EXYNOS4_IRQ_MCT_L0; |
511 | mct_irqs[MCT_L1_IRQ] = EXYNOS4_IRQ_MCT_L1; | 543 | mct_irqs[MCT_L1_IRQ] = EXYNOS4_IRQ_MCT_L1; |
512 | mct_int_type = MCT_INT_SPI; | 544 | mct_int_type = MCT_INT_SPI; |
513 | } else if (soc_is_exynos5250()) { | ||
514 | mct_irqs[MCT_G0_IRQ] = EXYNOS5_IRQ_MCT_G0; | ||
515 | mct_irqs[MCT_L0_IRQ] = EXYNOS5_IRQ_MCT_L0; | ||
516 | mct_irqs[MCT_L1_IRQ] = EXYNOS5_IRQ_MCT_L1; | ||
517 | mct_int_type = MCT_INT_SPI; | ||
518 | } else { | 545 | } else { |
519 | mct_irqs[MCT_G0_IRQ] = EXYNOS4_IRQ_MCT_G0; | 546 | panic("unable to determine mct controller type\n"); |
520 | mct_irqs[MCT_L0_IRQ] = EXYNOS_IRQ_MCT_LOCALTIMER; | ||
521 | mct_int_type = MCT_INT_PPI; | ||
522 | } | 547 | } |
523 | 548 | ||
524 | exynos4_timer_resources(); | 549 | exynos4_timer_resources(np); |
525 | exynos4_clocksource_init(); | 550 | exynos4_clocksource_init(); |
526 | exynos4_clockevent_init(); | 551 | exynos4_clockevent_init(); |
527 | } | 552 | } |