diff options
author | Kukjin Kim <kgene.kim@samsung.com> | 2013-03-09 02:56:34 -0500 |
---|---|---|
committer | Kukjin Kim <kgene.kim@samsung.com> | 2013-03-09 02:56:34 -0500 |
commit | 8ec46b97f24d60645c8f708c87e0caecebd25d77 (patch) | |
tree | 3663c411f7a4e7a9bfc0a8e720679b93a5860b7c | |
parent | b85b64cc22122adca695e0f8c340cc677ad92e8c (diff) | |
parent | 6938d75a8c1a1752f9fa7ef14a0c570036c7b73b (diff) |
Merge branch 'next/mct-exynos' into next/clk-exynos
Conflicts:
arch/arm/mach-exynos/mach-exynos4-dt.c
23 files changed, 309 insertions, 149 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/Kconfig b/arch/arm/Kconfig index 46fcfa8805f8..ee414be31b4d 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -1655,7 +1655,7 @@ config LOCAL_TIMERS | |||
1655 | bool "Use local timer interrupts" | 1655 | bool "Use local timer interrupts" |
1656 | depends on SMP | 1656 | depends on SMP |
1657 | default y | 1657 | default y |
1658 | select HAVE_ARM_TWD if (!ARCH_MSM_SCORPIONMP && !EXYNOS4_MCT) | 1658 | select HAVE_ARM_TWD if (!ARCH_MSM_SCORPIONMP && !CLKSRC_EXYNOS_MCT) |
1659 | help | 1659 | help |
1660 | Enable support for local timers on SMP platforms, rather then the | 1660 | Enable support for local timers on SMP platforms, rather then the |
1661 | legacy IPI broadcast method. Local timers allows the system | 1661 | legacy IPI broadcast method. Local timers allows the system |
diff --git a/arch/arm/boot/dts/exynos4210.dtsi b/arch/arm/boot/dts/exynos4210.dtsi index 2feffc70814c..49a2786e00b9 100644 --- a/arch/arm/boot/dts/exynos4210.dtsi +++ b/arch/arm/boot/dts/exynos4210.dtsi | |||
@@ -47,6 +47,28 @@ | |||
47 | <0 12 0>, <0 13 0>, <0 14 0>, <0 15 0>; | 47 | <0 12 0>, <0 13 0>, <0 14 0>, <0 15 0>; |
48 | }; | 48 | }; |
49 | 49 | ||
50 | mct@10050000 { | ||
51 | compatible = "samsung,exynos4210-mct"; | ||
52 | reg = <0x10050000 0x800>; | ||
53 | interrupt-controller; | ||
54 | #interrups-cells = <2>; | ||
55 | interrupt-parent = <&mct_map>; | ||
56 | interrupts = <0 0>, <1 0>, <2 0>, <3 0>, | ||
57 | <4 0>, <5 0>; | ||
58 | |||
59 | mct_map: mct-map { | ||
60 | #interrupt-cells = <2>; | ||
61 | #address-cells = <0>; | ||
62 | #size-cells = <0>; | ||
63 | interrupt-map = <0x0 0 &gic 0 57 0>, | ||
64 | <0x1 0 &gic 0 69 0>, | ||
65 | <0x2 0 &combiner 12 6>, | ||
66 | <0x3 0 &combiner 12 7>, | ||
67 | <0x4 0 &gic 0 42 0>, | ||
68 | <0x5 0 &gic 0 48 0>; | ||
69 | }; | ||
70 | }; | ||
71 | |||
50 | pinctrl_0: pinctrl@11400000 { | 72 | pinctrl_0: pinctrl@11400000 { |
51 | compatible = "samsung,exynos4210-pinctrl"; | 73 | compatible = "samsung,exynos4210-pinctrl"; |
52 | reg = <0x11400000 0x1000>; | 74 | reg = <0x11400000 0x1000>; |
diff --git a/arch/arm/boot/dts/exynos4212.dtsi b/arch/arm/boot/dts/exynos4212.dtsi index c6ae2005961f..36d4299789ef 100644 --- a/arch/arm/boot/dts/exynos4212.dtsi +++ b/arch/arm/boot/dts/exynos4212.dtsi | |||
@@ -25,4 +25,26 @@ | |||
25 | gic:interrupt-controller@10490000 { | 25 | gic:interrupt-controller@10490000 { |
26 | cpu-offset = <0x8000>; | 26 | cpu-offset = <0x8000>; |
27 | }; | 27 | }; |
28 | |||
29 | mct@10050000 { | ||
30 | compatible = "samsung,exynos4412-mct"; | ||
31 | reg = <0x10050000 0x800>; | ||
32 | interrupt-controller; | ||
33 | #interrups-cells = <2>; | ||
34 | interrupt-parent = <&mct_map>; | ||
35 | interrupts = <0 0>, <1 0>, <2 0>, <3 0>, | ||
36 | <4 0>, <5 0>; | ||
37 | |||
38 | mct_map: mct-map { | ||
39 | #interrupt-cells = <2>; | ||
40 | #address-cells = <0>; | ||
41 | #size-cells = <0>; | ||
42 | interrupt-map = <0x0 0 &gic 0 57 0>, | ||
43 | <0x1 0 &combiner 12 5>, | ||
44 | <0x2 0 &combiner 12 6>, | ||
45 | <0x3 0 &combiner 12 7>, | ||
46 | <0x4 0 &gic 1 12 0>, | ||
47 | <0x5 0 &gic 1 12 0>; | ||
48 | }; | ||
49 | }; | ||
28 | }; | 50 | }; |
diff --git a/arch/arm/boot/dts/exynos4412.dtsi b/arch/arm/boot/dts/exynos4412.dtsi index d7dfe312772a..821c9fdd1e3b 100644 --- a/arch/arm/boot/dts/exynos4412.dtsi +++ b/arch/arm/boot/dts/exynos4412.dtsi | |||
@@ -25,4 +25,28 @@ | |||
25 | gic:interrupt-controller@10490000 { | 25 | gic:interrupt-controller@10490000 { |
26 | cpu-offset = <0x4000>; | 26 | cpu-offset = <0x4000>; |
27 | }; | 27 | }; |
28 | |||
29 | mct@10050000 { | ||
30 | compatible = "samsung,exynos4412-mct"; | ||
31 | reg = <0x10050000 0x800>; | ||
32 | interrupt-controller; | ||
33 | #interrups-cells = <2>; | ||
34 | interrupt-parent = <&mct_map>; | ||
35 | interrupts = <0 0>, <1 0>, <2 0>, <3 0>, | ||
36 | <4 0>, <5 0>, <6 0>, <7 0>; | ||
37 | |||
38 | mct_map: mct-map { | ||
39 | #interrupt-cells = <2>; | ||
40 | #address-cells = <0>; | ||
41 | #size-cells = <0>; | ||
42 | interrupt-map = <0x0 0 &gic 0 57 0>, | ||
43 | <0x1 0 &combiner 12 5>, | ||
44 | <0x2 0 &combiner 12 6>, | ||
45 | <0x3 0 &combiner 12 7>, | ||
46 | <0x4 0 &gic 1 12 0>, | ||
47 | <0x5 0 &gic 1 12 0>, | ||
48 | <0x6 0 &gic 1 12 0>, | ||
49 | <0x7 0 &gic 1 12 0>; | ||
50 | }; | ||
51 | }; | ||
28 | }; | 52 | }; |
diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi index 37a90dd6a4d2..4fe76bf299fb 100644 --- a/arch/arm/boot/dts/exynos5250.dtsi +++ b/arch/arm/boot/dts/exynos5250.dtsi | |||
@@ -79,6 +79,28 @@ | |||
79 | <0 28 0>, <0 29 0>, <0 30 0>, <0 31 0>; | 79 | <0 28 0>, <0 29 0>, <0 30 0>, <0 31 0>; |
80 | }; | 80 | }; |
81 | 81 | ||
82 | mct@101C0000 { | ||
83 | compatible = "samsung,exynos4210-mct"; | ||
84 | reg = <0x101C0000 0x800>; | ||
85 | interrupt-controller; | ||
86 | #interrups-cells = <2>; | ||
87 | interrupt-parent = <&mct_map>; | ||
88 | interrupts = <0 0>, <1 0>, <2 0>, <3 0>, | ||
89 | <4 0>, <5 0>; | ||
90 | |||
91 | mct_map: mct-map { | ||
92 | #interrupt-cells = <2>; | ||
93 | #address-cells = <0>; | ||
94 | #size-cells = <0>; | ||
95 | interrupt-map = <0x0 0 &combiner 23 3>, | ||
96 | <0x1 0 &combiner 23 4>, | ||
97 | <0x2 0 &combiner 25 2>, | ||
98 | <0x3 0 &combiner 25 3>, | ||
99 | <0x4 0 &gic 0 120 0>, | ||
100 | <0x5 0 &gic 0 121 0>; | ||
101 | }; | ||
102 | }; | ||
103 | |||
82 | watchdog { | 104 | watchdog { |
83 | compatible = "samsung,s3c2410-wdt"; | 105 | compatible = "samsung,s3c2410-wdt"; |
84 | reg = <0x101D0000 0x100>; | 106 | reg = <0x101D0000 0x100>; |
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index bc15b9ee8174..ef3b69a6277c 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig | |||
@@ -80,12 +80,6 @@ config SOC_EXYNOS5440 | |||
80 | help | 80 | help |
81 | Enable EXYNOS5440 SoC support | 81 | Enable EXYNOS5440 SoC support |
82 | 82 | ||
83 | config EXYNOS4_MCT | ||
84 | bool | ||
85 | default y | ||
86 | help | ||
87 | Use MCT (Multi Core Timer) as kernel timers | ||
88 | |||
89 | config EXYNOS_DEV_DMA | 83 | config EXYNOS_DEV_DMA |
90 | bool | 84 | bool |
91 | help | 85 | help |
@@ -407,6 +401,7 @@ config MACH_EXYNOS4_DT | |||
407 | bool "Samsung Exynos4 Machine using device tree" | 401 | bool "Samsung Exynos4 Machine using device tree" |
408 | depends on ARCH_EXYNOS4 | 402 | depends on ARCH_EXYNOS4 |
409 | select ARM_AMBA | 403 | select ARM_AMBA |
404 | select CLKSRC_OF | ||
410 | select CPU_EXYNOS4210 | 405 | select CPU_EXYNOS4210 |
411 | select HAVE_SAMSUNG_KEYPAD if INPUT_KEYBOARD | 406 | select HAVE_SAMSUNG_KEYPAD if INPUT_KEYBOARD |
412 | select PINCTRL | 407 | select PINCTRL |
@@ -424,6 +419,7 @@ config MACH_EXYNOS5_DT | |||
424 | default y | 419 | default y |
425 | depends on ARCH_EXYNOS5 | 420 | depends on ARCH_EXYNOS5 |
426 | select ARM_AMBA | 421 | select ARM_AMBA |
422 | select CLKSRC_OF | ||
427 | select USE_OF | 423 | select USE_OF |
428 | help | 424 | help |
429 | Machine support for Samsung EXYNOS5 machine with device tree enabled. | 425 | Machine support for Samsung EXYNOS5 machine with device tree enabled. |
diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile index 435757e57bb4..daf289b21486 100644 --- a/arch/arm/mach-exynos/Makefile +++ b/arch/arm/mach-exynos/Makefile | |||
@@ -26,8 +26,6 @@ obj-$(CONFIG_ARCH_EXYNOS) += pmu.o | |||
26 | 26 | ||
27 | obj-$(CONFIG_SMP) += platsmp.o headsmp.o | 27 | obj-$(CONFIG_SMP) += platsmp.o headsmp.o |
28 | 28 | ||
29 | obj-$(CONFIG_EXYNOS4_MCT) += mct.o | ||
30 | |||
31 | obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o | 29 | obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o |
32 | 30 | ||
33 | # machine support | 31 | # machine support |
diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c index d63d399c7bae..f91dad6fe9a3 100644 --- a/arch/arm/mach-exynos/common.c +++ b/arch/arm/mach-exynos/common.c | |||
@@ -257,11 +257,6 @@ static struct map_desc exynos5_iodesc[] __initdata = { | |||
257 | .length = SZ_4K, | 257 | .length = SZ_4K, |
258 | .type = MT_DEVICE, | 258 | .type = MT_DEVICE, |
259 | }, { | 259 | }, { |
260 | .virtual = (unsigned long)S5P_VA_SYSTIMER, | ||
261 | .pfn = __phys_to_pfn(EXYNOS5_PA_SYSTIMER), | ||
262 | .length = SZ_4K, | ||
263 | .type = MT_DEVICE, | ||
264 | }, { | ||
265 | .virtual = (unsigned long)S5P_VA_SYSRAM, | 260 | .virtual = (unsigned long)S5P_VA_SYSRAM, |
266 | .pfn = __phys_to_pfn(EXYNOS5_PA_SYSRAM), | 261 | .pfn = __phys_to_pfn(EXYNOS5_PA_SYSRAM), |
267 | .length = SZ_4K, | 262 | .length = SZ_4K, |
diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h index 9339bb8954be..3b186eaaaa7b 100644 --- a/arch/arm/mach-exynos/common.h +++ b/arch/arm/mach-exynos/common.h | |||
@@ -12,7 +12,7 @@ | |||
12 | #ifndef __ARCH_ARM_MACH_EXYNOS_COMMON_H | 12 | #ifndef __ARCH_ARM_MACH_EXYNOS_COMMON_H |
13 | #define __ARCH_ARM_MACH_EXYNOS_COMMON_H | 13 | #define __ARCH_ARM_MACH_EXYNOS_COMMON_H |
14 | 14 | ||
15 | extern void exynos4_timer_init(void); | 15 | extern void mct_init(void); |
16 | 16 | ||
17 | struct map_desc; | 17 | struct map_desc; |
18 | void exynos_init_io(struct map_desc *mach_desc, int size); | 18 | void exynos_init_io(struct map_desc *mach_desc, int size); |
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/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h index 1df6abbf53b8..7f99b7b187d6 100644 --- a/arch/arm/mach-exynos/include/mach/map.h +++ b/arch/arm/mach-exynos/include/mach/map.h | |||
@@ -65,7 +65,6 @@ | |||
65 | #define EXYNOS5_PA_CMU 0x10010000 | 65 | #define EXYNOS5_PA_CMU 0x10010000 |
66 | 66 | ||
67 | #define EXYNOS4_PA_SYSTIMER 0x10050000 | 67 | #define EXYNOS4_PA_SYSTIMER 0x10050000 |
68 | #define EXYNOS5_PA_SYSTIMER 0x101C0000 | ||
69 | 68 | ||
70 | #define EXYNOS4_PA_WATCHDOG 0x10060000 | 69 | #define EXYNOS4_PA_WATCHDOG 0x10060000 |
71 | #define EXYNOS5_PA_WATCHDOG 0x101D0000 | 70 | #define EXYNOS5_PA_WATCHDOG 0x101D0000 |
diff --git a/arch/arm/mach-exynos/include/mach/regs-mct.h b/arch/arm/mach-exynos/include/mach/regs-mct.h deleted file mode 100644 index 80dd02ad6d61..000000000000 --- a/arch/arm/mach-exynos/include/mach/regs-mct.h +++ /dev/null | |||
@@ -1,53 +0,0 @@ | |||
1 | /* arch/arm/mach-exynos4/include/mach/regs-mct.h | ||
2 | * | ||
3 | * Copyright (c) 2011 Samsung Electronics Co., Ltd. | ||
4 | * http://www.samsung.com | ||
5 | * | ||
6 | * EXYNOS4 MCT configutation | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef __ASM_ARCH_REGS_MCT_H | ||
14 | #define __ASM_ARCH_REGS_MCT_H __FILE__ | ||
15 | |||
16 | #include <mach/map.h> | ||
17 | |||
18 | #define EXYNOS4_MCTREG(x) (S5P_VA_SYSTIMER + (x)) | ||
19 | |||
20 | #define EXYNOS4_MCT_G_CNT_L EXYNOS4_MCTREG(0x100) | ||
21 | #define EXYNOS4_MCT_G_CNT_U EXYNOS4_MCTREG(0x104) | ||
22 | #define EXYNOS4_MCT_G_CNT_WSTAT EXYNOS4_MCTREG(0x110) | ||
23 | |||
24 | #define EXYNOS4_MCT_G_COMP0_L EXYNOS4_MCTREG(0x200) | ||
25 | #define EXYNOS4_MCT_G_COMP0_U EXYNOS4_MCTREG(0x204) | ||
26 | #define EXYNOS4_MCT_G_COMP0_ADD_INCR EXYNOS4_MCTREG(0x208) | ||
27 | |||
28 | #define EXYNOS4_MCT_G_TCON EXYNOS4_MCTREG(0x240) | ||
29 | |||
30 | #define EXYNOS4_MCT_G_INT_CSTAT EXYNOS4_MCTREG(0x244) | ||
31 | #define EXYNOS4_MCT_G_INT_ENB EXYNOS4_MCTREG(0x248) | ||
32 | #define EXYNOS4_MCT_G_WSTAT EXYNOS4_MCTREG(0x24C) | ||
33 | |||
34 | #define _EXYNOS4_MCT_L_BASE EXYNOS4_MCTREG(0x300) | ||
35 | #define EXYNOS4_MCT_L_BASE(x) (_EXYNOS4_MCT_L_BASE + (0x100 * x)) | ||
36 | #define EXYNOS4_MCT_L_MASK (0xffffff00) | ||
37 | |||
38 | #define MCT_L_TCNTB_OFFSET (0x00) | ||
39 | #define MCT_L_ICNTB_OFFSET (0x08) | ||
40 | #define MCT_L_TCON_OFFSET (0x20) | ||
41 | #define MCT_L_INT_CSTAT_OFFSET (0x30) | ||
42 | #define MCT_L_INT_ENB_OFFSET (0x34) | ||
43 | #define MCT_L_WSTAT_OFFSET (0x40) | ||
44 | |||
45 | #define MCT_G_TCON_START (1 << 8) | ||
46 | #define MCT_G_TCON_COMP0_AUTO_INC (1 << 1) | ||
47 | #define MCT_G_TCON_COMP0_ENABLE (1 << 0) | ||
48 | |||
49 | #define MCT_L_TCON_INTERVAL_MODE (1 << 2) | ||
50 | #define MCT_L_TCON_INT_START (1 << 1) | ||
51 | #define MCT_L_TCON_TIMER_START (1 << 0) | ||
52 | |||
53 | #endif /* __ASM_ARCH_REGS_MCT_H */ | ||
diff --git a/arch/arm/mach-exynos/mach-armlex4210.c b/arch/arm/mach-exynos/mach-armlex4210.c index 685f29173afa..3b1a34742679 100644 --- a/arch/arm/mach-exynos/mach-armlex4210.c +++ b/arch/arm/mach-exynos/mach-armlex4210.c | |||
@@ -202,6 +202,6 @@ MACHINE_START(ARMLEX4210, "ARMLEX4210") | |||
202 | .map_io = armlex4210_map_io, | 202 | .map_io = armlex4210_map_io, |
203 | .init_machine = armlex4210_machine_init, | 203 | .init_machine = armlex4210_machine_init, |
204 | .init_late = exynos_init_late, | 204 | .init_late = exynos_init_late, |
205 | .init_time = exynos4_timer_init, | 205 | .init_time = mct_init, |
206 | .restart = exynos4_restart, | 206 | .restart = exynos4_restart, |
207 | MACHINE_END | 207 | MACHINE_END |
diff --git a/arch/arm/mach-exynos/mach-exynos4-dt.c b/arch/arm/mach-exynos/mach-exynos4-dt.c index fad268f8548c..daa7b0da9a2d 100644 --- a/arch/arm/mach-exynos/mach-exynos4-dt.c +++ b/arch/arm/mach-exynos/mach-exynos4-dt.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/of_fdt.h> | 15 | #include <linux/of_fdt.h> |
16 | #include <linux/serial_core.h> | 16 | #include <linux/serial_core.h> |
17 | #include <linux/memblock.h> | 17 | #include <linux/memblock.h> |
18 | #include <linux/clocksource.h> | ||
18 | 19 | ||
19 | #include <asm/mach/arch.h> | 20 | #include <asm/mach/arch.h> |
20 | #include <mach/map.h> | 21 | #include <mach/map.h> |
@@ -158,7 +159,7 @@ DT_MACHINE_START(EXYNOS4210_DT, "Samsung Exynos4 (Flattened Device Tree)") | |||
158 | .map_io = exynos4_dt_map_io, | 159 | .map_io = exynos4_dt_map_io, |
159 | .init_machine = exynos4_dt_machine_init, | 160 | .init_machine = exynos4_dt_machine_init, |
160 | .init_late = exynos_init_late, | 161 | .init_late = exynos_init_late, |
161 | .init_time = exynos4_timer_init, | 162 | .init_time = clocksource_of_init, |
162 | .dt_compat = exynos4_dt_compat, | 163 | .dt_compat = exynos4_dt_compat, |
163 | .restart = exynos4_restart, | 164 | .restart = exynos4_restart, |
164 | .reserve = exynos4_reserve, | 165 | .reserve = exynos4_reserve, |
diff --git a/arch/arm/mach-exynos/mach-exynos5-dt.c b/arch/arm/mach-exynos/mach-exynos5-dt.c index 8ef895745175..62d43dacf636 100644 --- a/arch/arm/mach-exynos/mach-exynos5-dt.c +++ b/arch/arm/mach-exynos/mach-exynos5-dt.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/serial_core.h> | 14 | #include <linux/serial_core.h> |
15 | #include <linux/memblock.h> | 15 | #include <linux/memblock.h> |
16 | #include <linux/io.h> | 16 | #include <linux/io.h> |
17 | #include <linux/clocksource.h> | ||
17 | 18 | ||
18 | #include <asm/mach/arch.h> | 19 | #include <asm/mach/arch.h> |
19 | #include <mach/map.h> | 20 | #include <mach/map.h> |
@@ -217,7 +218,7 @@ DT_MACHINE_START(EXYNOS5_DT, "SAMSUNG EXYNOS5 (Flattened Device Tree)") | |||
217 | .map_io = exynos5_dt_map_io, | 218 | .map_io = exynos5_dt_map_io, |
218 | .init_machine = exynos5_dt_machine_init, | 219 | .init_machine = exynos5_dt_machine_init, |
219 | .init_late = exynos_init_late, | 220 | .init_late = exynos_init_late, |
220 | .init_time = exynos4_timer_init, | 221 | .init_time = clocksource_of_init, |
221 | .dt_compat = exynos5_dt_compat, | 222 | .dt_compat = exynos5_dt_compat, |
222 | .restart = exynos5_restart, | 223 | .restart = exynos5_restart, |
223 | .reserve = exynos5_reserve, | 224 | .reserve = exynos5_reserve, |
diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c index 1ea79730187f..da3605d15110 100644 --- a/arch/arm/mach-exynos/mach-nuri.c +++ b/arch/arm/mach-exynos/mach-nuri.c | |||
@@ -1380,7 +1380,7 @@ MACHINE_START(NURI, "NURI") | |||
1380 | .map_io = nuri_map_io, | 1380 | .map_io = nuri_map_io, |
1381 | .init_machine = nuri_machine_init, | 1381 | .init_machine = nuri_machine_init, |
1382 | .init_late = exynos_init_late, | 1382 | .init_late = exynos_init_late, |
1383 | .init_time = exynos4_timer_init, | 1383 | .init_time = mct_init, |
1384 | .reserve = &nuri_reserve, | 1384 | .reserve = &nuri_reserve, |
1385 | .restart = exynos4_restart, | 1385 | .restart = exynos4_restart, |
1386 | MACHINE_END | 1386 | MACHINE_END |
diff --git a/arch/arm/mach-exynos/mach-origen.c b/arch/arm/mach-exynos/mach-origen.c index 579d2d171daa..1772cd284f4c 100644 --- a/arch/arm/mach-exynos/mach-origen.c +++ b/arch/arm/mach-exynos/mach-origen.c | |||
@@ -815,7 +815,7 @@ MACHINE_START(ORIGEN, "ORIGEN") | |||
815 | .map_io = origen_map_io, | 815 | .map_io = origen_map_io, |
816 | .init_machine = origen_machine_init, | 816 | .init_machine = origen_machine_init, |
817 | .init_late = exynos_init_late, | 817 | .init_late = exynos_init_late, |
818 | .init_time = exynos4_timer_init, | 818 | .init_time = mct_init, |
819 | .reserve = &origen_reserve, | 819 | .reserve = &origen_reserve, |
820 | .restart = exynos4_restart, | 820 | .restart = exynos4_restart, |
821 | MACHINE_END | 821 | MACHINE_END |
diff --git a/arch/arm/mach-exynos/mach-smdk4x12.c b/arch/arm/mach-exynos/mach-smdk4x12.c index fe6149624b84..34a6356364eb 100644 --- a/arch/arm/mach-exynos/mach-smdk4x12.c +++ b/arch/arm/mach-exynos/mach-smdk4x12.c | |||
@@ -376,7 +376,7 @@ MACHINE_START(SMDK4212, "SMDK4212") | |||
376 | .init_irq = exynos4_init_irq, | 376 | .init_irq = exynos4_init_irq, |
377 | .map_io = smdk4x12_map_io, | 377 | .map_io = smdk4x12_map_io, |
378 | .init_machine = smdk4x12_machine_init, | 378 | .init_machine = smdk4x12_machine_init, |
379 | .init_time = exynos4_timer_init, | 379 | .init_time = mct_init, |
380 | .restart = exynos4_restart, | 380 | .restart = exynos4_restart, |
381 | .reserve = &smdk4x12_reserve, | 381 | .reserve = &smdk4x12_reserve, |
382 | MACHINE_END | 382 | MACHINE_END |
@@ -390,7 +390,7 @@ MACHINE_START(SMDK4412, "SMDK4412") | |||
390 | .map_io = smdk4x12_map_io, | 390 | .map_io = smdk4x12_map_io, |
391 | .init_machine = smdk4x12_machine_init, | 391 | .init_machine = smdk4x12_machine_init, |
392 | .init_late = exynos_init_late, | 392 | .init_late = exynos_init_late, |
393 | .init_time = exynos4_timer_init, | 393 | .init_time = mct_init, |
394 | .restart = exynos4_restart, | 394 | .restart = exynos4_restart, |
395 | .reserve = &smdk4x12_reserve, | 395 | .reserve = &smdk4x12_reserve, |
396 | MACHINE_END | 396 | MACHINE_END |
diff --git a/arch/arm/mach-exynos/mach-smdkv310.c b/arch/arm/mach-exynos/mach-smdkv310.c index d71672922b19..893b14e8c62a 100644 --- a/arch/arm/mach-exynos/mach-smdkv310.c +++ b/arch/arm/mach-exynos/mach-smdkv310.c | |||
@@ -423,7 +423,7 @@ MACHINE_START(SMDKV310, "SMDKV310") | |||
423 | .init_irq = exynos4_init_irq, | 423 | .init_irq = exynos4_init_irq, |
424 | .map_io = smdkv310_map_io, | 424 | .map_io = smdkv310_map_io, |
425 | .init_machine = smdkv310_machine_init, | 425 | .init_machine = smdkv310_machine_init, |
426 | .init_time = exynos4_timer_init, | 426 | .init_time = mct_init, |
427 | .reserve = &smdkv310_reserve, | 427 | .reserve = &smdkv310_reserve, |
428 | .restart = exynos4_restart, | 428 | .restart = exynos4_restart, |
429 | MACHINE_END | 429 | MACHINE_END |
@@ -436,7 +436,7 @@ MACHINE_START(SMDKC210, "SMDKC210") | |||
436 | .map_io = smdkv310_map_io, | 436 | .map_io = smdkv310_map_io, |
437 | .init_machine = smdkv310_machine_init, | 437 | .init_machine = smdkv310_machine_init, |
438 | .init_late = exynos_init_late, | 438 | .init_late = exynos_init_late, |
439 | .init_time = exynos4_timer_init, | 439 | .init_time = mct_init, |
440 | .reserve = &smdkv310_reserve, | 440 | .reserve = &smdkv310_reserve, |
441 | .restart = exynos4_restart, | 441 | .restart = exynos4_restart, |
442 | MACHINE_END | 442 | MACHINE_END |
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index e507ab7df60b..e8c453285151 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig | |||
@@ -67,3 +67,8 @@ config CLKSRC_METAG_GENERIC | |||
67 | def_bool y if METAG | 67 | def_bool y if METAG |
68 | help | 68 | help |
69 | This option enables support for the Meta per-thread timers. | 69 | This option enables support for the Meta per-thread timers. |
70 | |||
71 | config CLKSRC_EXYNOS_MCT | ||
72 | def_bool y if ARCH_EXYNOS | ||
73 | help | ||
74 | Support for Multi Core Timer controller on Exynos SoCs. | ||
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index 4d8283aec5b5..1c1b15db7c4d 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile | |||
@@ -19,6 +19,7 @@ obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o | |||
19 | obj-$(CONFIG_SUNXI_TIMER) += sunxi_timer.o | 19 | obj-$(CONFIG_SUNXI_TIMER) += sunxi_timer.o |
20 | obj-$(CONFIG_ARCH_TEGRA) += tegra20_timer.o | 20 | obj-$(CONFIG_ARCH_TEGRA) += tegra20_timer.o |
21 | obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o | 21 | obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o |
22 | obj-$(CONFIG_CLKSRC_EXYNOS_MCT) += exynos_mct.o | ||
22 | 23 | ||
23 | obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o | 24 | obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o |
24 | obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o | 25 | obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o |
diff --git a/arch/arm/mach-exynos/mct.c b/drivers/clocksource/exynos_mct.c index c9d6650f9b5d..545c98976e93 100644 --- a/arch/arm/mach-exynos/mct.c +++ b/drivers/clocksource/exynos_mct.c | |||
@@ -20,6 +20,9 @@ | |||
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> | ||
25 | #include <linux/clocksource.h> | ||
23 | 26 | ||
24 | #include <asm/arch_timer.h> | 27 | #include <asm/arch_timer.h> |
25 | #include <asm/localtimer.h> | 28 | #include <asm/localtimer.h> |
@@ -28,9 +31,36 @@ | |||
28 | 31 | ||
29 | #include <mach/map.h> | 32 | #include <mach/map.h> |
30 | #include <mach/irqs.h> | 33 | #include <mach/irqs.h> |
31 | #include <mach/regs-mct.h> | ||
32 | #include <asm/mach/time.h> | 34 | #include <asm/mach/time.h> |
33 | 35 | ||
36 | #define EXYNOS4_MCTREG(x) (x) | ||
37 | #define EXYNOS4_MCT_G_CNT_L EXYNOS4_MCTREG(0x100) | ||
38 | #define EXYNOS4_MCT_G_CNT_U EXYNOS4_MCTREG(0x104) | ||
39 | #define EXYNOS4_MCT_G_CNT_WSTAT EXYNOS4_MCTREG(0x110) | ||
40 | #define EXYNOS4_MCT_G_COMP0_L EXYNOS4_MCTREG(0x200) | ||
41 | #define EXYNOS4_MCT_G_COMP0_U EXYNOS4_MCTREG(0x204) | ||
42 | #define EXYNOS4_MCT_G_COMP0_ADD_INCR EXYNOS4_MCTREG(0x208) | ||
43 | #define EXYNOS4_MCT_G_TCON EXYNOS4_MCTREG(0x240) | ||
44 | #define EXYNOS4_MCT_G_INT_CSTAT EXYNOS4_MCTREG(0x244) | ||
45 | #define EXYNOS4_MCT_G_INT_ENB EXYNOS4_MCTREG(0x248) | ||
46 | #define EXYNOS4_MCT_G_WSTAT EXYNOS4_MCTREG(0x24C) | ||
47 | #define _EXYNOS4_MCT_L_BASE EXYNOS4_MCTREG(0x300) | ||
48 | #define EXYNOS4_MCT_L_BASE(x) (_EXYNOS4_MCT_L_BASE + (0x100 * x)) | ||
49 | #define EXYNOS4_MCT_L_MASK (0xffffff00) | ||
50 | |||
51 | #define MCT_L_TCNTB_OFFSET (0x00) | ||
52 | #define MCT_L_ICNTB_OFFSET (0x08) | ||
53 | #define MCT_L_TCON_OFFSET (0x20) | ||
54 | #define MCT_L_INT_CSTAT_OFFSET (0x30) | ||
55 | #define MCT_L_INT_ENB_OFFSET (0x34) | ||
56 | #define MCT_L_WSTAT_OFFSET (0x40) | ||
57 | #define MCT_G_TCON_START (1 << 8) | ||
58 | #define MCT_G_TCON_COMP0_AUTO_INC (1 << 1) | ||
59 | #define MCT_G_TCON_COMP0_ENABLE (1 << 0) | ||
60 | #define MCT_L_TCON_INTERVAL_MODE (1 << 2) | ||
61 | #define MCT_L_TCON_INT_START (1 << 1) | ||
62 | #define MCT_L_TCON_TIMER_START (1 << 0) | ||
63 | |||
34 | #define TICK_BASE_CNT 1 | 64 | #define TICK_BASE_CNT 1 |
35 | 65 | ||
36 | enum { | 66 | enum { |
@@ -38,64 +68,75 @@ enum { | |||
38 | MCT_INT_PPI | 68 | MCT_INT_PPI |
39 | }; | 69 | }; |
40 | 70 | ||
71 | enum { | ||
72 | MCT_G0_IRQ, | ||
73 | MCT_G1_IRQ, | ||
74 | MCT_G2_IRQ, | ||
75 | MCT_G3_IRQ, | ||
76 | MCT_L0_IRQ, | ||
77 | MCT_L1_IRQ, | ||
78 | MCT_L2_IRQ, | ||
79 | MCT_L3_IRQ, | ||
80 | MCT_NR_IRQS, | ||
81 | }; | ||
82 | |||
83 | static void __iomem *reg_base; | ||
41 | static unsigned long clk_rate; | 84 | static unsigned long clk_rate; |
42 | static unsigned int mct_int_type; | 85 | static unsigned int mct_int_type; |
86 | static int mct_irqs[MCT_NR_IRQS]; | ||
43 | 87 | ||
44 | struct mct_clock_event_device { | 88 | struct mct_clock_event_device { |
45 | struct clock_event_device *evt; | 89 | struct clock_event_device *evt; |
46 | void __iomem *base; | 90 | unsigned long base; |
47 | char name[10]; | 91 | char name[10]; |
48 | }; | 92 | }; |
49 | 93 | ||
50 | static void exynos4_mct_write(unsigned int value, void *addr) | 94 | static void exynos4_mct_write(unsigned int value, unsigned long offset) |
51 | { | 95 | { |
52 | void __iomem *stat_addr; | 96 | unsigned long stat_addr; |
53 | u32 mask; | 97 | u32 mask; |
54 | u32 i; | 98 | u32 i; |
55 | 99 | ||
56 | __raw_writel(value, addr); | 100 | __raw_writel(value, reg_base + offset); |
57 | 101 | ||
58 | if (likely(addr >= EXYNOS4_MCT_L_BASE(0))) { | 102 | if (likely(offset >= EXYNOS4_MCT_L_BASE(0))) { |
59 | u32 base = (u32) addr & EXYNOS4_MCT_L_MASK; | 103 | stat_addr = (offset & ~EXYNOS4_MCT_L_MASK) + MCT_L_WSTAT_OFFSET; |
60 | switch ((u32) addr & ~EXYNOS4_MCT_L_MASK) { | 104 | switch (offset & EXYNOS4_MCT_L_MASK) { |
61 | case (u32) MCT_L_TCON_OFFSET: | 105 | case MCT_L_TCON_OFFSET: |
62 | stat_addr = (void __iomem *) base + MCT_L_WSTAT_OFFSET; | ||
63 | mask = 1 << 3; /* L_TCON write status */ | 106 | mask = 1 << 3; /* L_TCON write status */ |
64 | break; | 107 | break; |
65 | case (u32) MCT_L_ICNTB_OFFSET: | 108 | case MCT_L_ICNTB_OFFSET: |
66 | stat_addr = (void __iomem *) base + MCT_L_WSTAT_OFFSET; | ||
67 | mask = 1 << 1; /* L_ICNTB write status */ | 109 | mask = 1 << 1; /* L_ICNTB write status */ |
68 | break; | 110 | break; |
69 | case (u32) MCT_L_TCNTB_OFFSET: | 111 | case MCT_L_TCNTB_OFFSET: |
70 | stat_addr = (void __iomem *) base + MCT_L_WSTAT_OFFSET; | ||
71 | mask = 1 << 0; /* L_TCNTB write status */ | 112 | mask = 1 << 0; /* L_TCNTB write status */ |
72 | break; | 113 | break; |
73 | default: | 114 | default: |
74 | return; | 115 | return; |
75 | } | 116 | } |
76 | } else { | 117 | } else { |
77 | switch ((u32) addr) { | 118 | switch (offset) { |
78 | case (u32) EXYNOS4_MCT_G_TCON: | 119 | case EXYNOS4_MCT_G_TCON: |
79 | stat_addr = EXYNOS4_MCT_G_WSTAT; | 120 | stat_addr = EXYNOS4_MCT_G_WSTAT; |
80 | mask = 1 << 16; /* G_TCON write status */ | 121 | mask = 1 << 16; /* G_TCON write status */ |
81 | break; | 122 | break; |
82 | case (u32) EXYNOS4_MCT_G_COMP0_L: | 123 | case EXYNOS4_MCT_G_COMP0_L: |
83 | stat_addr = EXYNOS4_MCT_G_WSTAT; | 124 | stat_addr = EXYNOS4_MCT_G_WSTAT; |
84 | mask = 1 << 0; /* G_COMP0_L write status */ | 125 | mask = 1 << 0; /* G_COMP0_L write status */ |
85 | break; | 126 | break; |
86 | case (u32) EXYNOS4_MCT_G_COMP0_U: | 127 | case EXYNOS4_MCT_G_COMP0_U: |
87 | stat_addr = EXYNOS4_MCT_G_WSTAT; | 128 | stat_addr = EXYNOS4_MCT_G_WSTAT; |
88 | mask = 1 << 1; /* G_COMP0_U write status */ | 129 | mask = 1 << 1; /* G_COMP0_U write status */ |
89 | break; | 130 | break; |
90 | case (u32) EXYNOS4_MCT_G_COMP0_ADD_INCR: | 131 | case EXYNOS4_MCT_G_COMP0_ADD_INCR: |
91 | stat_addr = EXYNOS4_MCT_G_WSTAT; | 132 | stat_addr = EXYNOS4_MCT_G_WSTAT; |
92 | mask = 1 << 2; /* G_COMP0_ADD_INCR w status */ | 133 | mask = 1 << 2; /* G_COMP0_ADD_INCR w status */ |
93 | break; | 134 | break; |
94 | case (u32) EXYNOS4_MCT_G_CNT_L: | 135 | case EXYNOS4_MCT_G_CNT_L: |
95 | stat_addr = EXYNOS4_MCT_G_CNT_WSTAT; | 136 | stat_addr = EXYNOS4_MCT_G_CNT_WSTAT; |
96 | mask = 1 << 0; /* G_CNT_L write status */ | 137 | mask = 1 << 0; /* G_CNT_L write status */ |
97 | break; | 138 | break; |
98 | case (u32) EXYNOS4_MCT_G_CNT_U: | 139 | case EXYNOS4_MCT_G_CNT_U: |
99 | stat_addr = EXYNOS4_MCT_G_CNT_WSTAT; | 140 | stat_addr = EXYNOS4_MCT_G_CNT_WSTAT; |
100 | mask = 1 << 1; /* G_CNT_U write status */ | 141 | mask = 1 << 1; /* G_CNT_U write status */ |
101 | break; | 142 | break; |
@@ -106,12 +147,12 @@ static void exynos4_mct_write(unsigned int value, void *addr) | |||
106 | 147 | ||
107 | /* Wait maximum 1 ms until written values are applied */ | 148 | /* Wait maximum 1 ms until written values are applied */ |
108 | for (i = 0; i < loops_per_jiffy / 1000 * HZ; i++) | 149 | for (i = 0; i < loops_per_jiffy / 1000 * HZ; i++) |
109 | if (__raw_readl(stat_addr) & mask) { | 150 | if (__raw_readl(reg_base + stat_addr) & mask) { |
110 | __raw_writel(mask, stat_addr); | 151 | __raw_writel(mask, reg_base + stat_addr); |
111 | return; | 152 | return; |
112 | } | 153 | } |
113 | 154 | ||
114 | panic("MCT hangs after writing %d (addr:0x%08x)\n", value, (u32)addr); | 155 | panic("MCT hangs after writing %d (offset:0x%lx)\n", value, offset); |
115 | } | 156 | } |
116 | 157 | ||
117 | /* Clocksource handling */ | 158 | /* Clocksource handling */ |
@@ -122,7 +163,7 @@ static void exynos4_mct_frc_start(u32 hi, u32 lo) | |||
122 | exynos4_mct_write(lo, EXYNOS4_MCT_G_CNT_L); | 163 | exynos4_mct_write(lo, EXYNOS4_MCT_G_CNT_L); |
123 | exynos4_mct_write(hi, EXYNOS4_MCT_G_CNT_U); | 164 | exynos4_mct_write(hi, EXYNOS4_MCT_G_CNT_U); |
124 | 165 | ||
125 | reg = __raw_readl(EXYNOS4_MCT_G_TCON); | 166 | reg = __raw_readl(reg_base + EXYNOS4_MCT_G_TCON); |
126 | reg |= MCT_G_TCON_START; | 167 | reg |= MCT_G_TCON_START; |
127 | exynos4_mct_write(reg, EXYNOS4_MCT_G_TCON); | 168 | exynos4_mct_write(reg, EXYNOS4_MCT_G_TCON); |
128 | } | 169 | } |
@@ -130,12 +171,12 @@ static void exynos4_mct_frc_start(u32 hi, u32 lo) | |||
130 | static cycle_t exynos4_frc_read(struct clocksource *cs) | 171 | static cycle_t exynos4_frc_read(struct clocksource *cs) |
131 | { | 172 | { |
132 | unsigned int lo, hi; | 173 | unsigned int lo, hi; |
133 | u32 hi2 = __raw_readl(EXYNOS4_MCT_G_CNT_U); | 174 | u32 hi2 = __raw_readl(reg_base + EXYNOS4_MCT_G_CNT_U); |
134 | 175 | ||
135 | do { | 176 | do { |
136 | hi = hi2; | 177 | hi = hi2; |
137 | lo = __raw_readl(EXYNOS4_MCT_G_CNT_L); | 178 | lo = __raw_readl(reg_base + EXYNOS4_MCT_G_CNT_L); |
138 | hi2 = __raw_readl(EXYNOS4_MCT_G_CNT_U); | 179 | hi2 = __raw_readl(reg_base + EXYNOS4_MCT_G_CNT_U); |
139 | } while (hi != hi2); | 180 | } while (hi != hi2); |
140 | 181 | ||
141 | return ((cycle_t)hi << 32) | lo; | 182 | return ((cycle_t)hi << 32) | lo; |
@@ -167,7 +208,7 @@ static void exynos4_mct_comp0_stop(void) | |||
167 | { | 208 | { |
168 | unsigned int tcon; | 209 | unsigned int tcon; |
169 | 210 | ||
170 | tcon = __raw_readl(EXYNOS4_MCT_G_TCON); | 211 | tcon = __raw_readl(reg_base + EXYNOS4_MCT_G_TCON); |
171 | tcon &= ~(MCT_G_TCON_COMP0_ENABLE | MCT_G_TCON_COMP0_AUTO_INC); | 212 | tcon &= ~(MCT_G_TCON_COMP0_ENABLE | MCT_G_TCON_COMP0_AUTO_INC); |
172 | 213 | ||
173 | exynos4_mct_write(tcon, EXYNOS4_MCT_G_TCON); | 214 | exynos4_mct_write(tcon, EXYNOS4_MCT_G_TCON); |
@@ -180,7 +221,7 @@ static void exynos4_mct_comp0_start(enum clock_event_mode mode, | |||
180 | unsigned int tcon; | 221 | unsigned int tcon; |
181 | cycle_t comp_cycle; | 222 | cycle_t comp_cycle; |
182 | 223 | ||
183 | tcon = __raw_readl(EXYNOS4_MCT_G_TCON); | 224 | tcon = __raw_readl(reg_base + EXYNOS4_MCT_G_TCON); |
184 | 225 | ||
185 | if (mode == CLOCK_EVT_MODE_PERIODIC) { | 226 | if (mode == CLOCK_EVT_MODE_PERIODIC) { |
186 | tcon |= MCT_G_TCON_COMP0_AUTO_INC; | 227 | tcon |= MCT_G_TCON_COMP0_AUTO_INC; |
@@ -257,11 +298,7 @@ static void exynos4_clockevent_init(void) | |||
257 | mct_comp_device.cpumask = cpumask_of(0); | 298 | mct_comp_device.cpumask = cpumask_of(0); |
258 | clockevents_config_and_register(&mct_comp_device, clk_rate, | 299 | clockevents_config_and_register(&mct_comp_device, clk_rate, |
259 | 0xf, 0xffffffff); | 300 | 0xf, 0xffffffff); |
260 | 301 | setup_irq(mct_irqs[MCT_G0_IRQ], &mct_comp_event_irq); | |
261 | if (soc_is_exynos5250()) | ||
262 | setup_irq(EXYNOS5_IRQ_MCT_G0, &mct_comp_event_irq); | ||
263 | else | ||
264 | setup_irq(EXYNOS4_IRQ_MCT_G0, &mct_comp_event_irq); | ||
265 | } | 302 | } |
266 | 303 | ||
267 | #ifdef CONFIG_LOCAL_TIMERS | 304 | #ifdef CONFIG_LOCAL_TIMERS |
@@ -273,12 +310,12 @@ static void exynos4_mct_tick_stop(struct mct_clock_event_device *mevt) | |||
273 | { | 310 | { |
274 | unsigned long tmp; | 311 | unsigned long tmp; |
275 | unsigned long mask = MCT_L_TCON_INT_START | MCT_L_TCON_TIMER_START; | 312 | unsigned long mask = MCT_L_TCON_INT_START | MCT_L_TCON_TIMER_START; |
276 | void __iomem *addr = mevt->base + MCT_L_TCON_OFFSET; | 313 | unsigned long offset = mevt->base + MCT_L_TCON_OFFSET; |
277 | 314 | ||
278 | tmp = __raw_readl(addr); | 315 | tmp = __raw_readl(reg_base + offset); |
279 | if (tmp & mask) { | 316 | if (tmp & mask) { |
280 | tmp &= ~mask; | 317 | tmp &= ~mask; |
281 | exynos4_mct_write(tmp, addr); | 318 | exynos4_mct_write(tmp, offset); |
282 | } | 319 | } |
283 | } | 320 | } |
284 | 321 | ||
@@ -297,7 +334,7 @@ static void exynos4_mct_tick_start(unsigned long cycles, | |||
297 | /* enable MCT tick interrupt */ | 334 | /* enable MCT tick interrupt */ |
298 | exynos4_mct_write(0x1, mevt->base + MCT_L_INT_ENB_OFFSET); | 335 | exynos4_mct_write(0x1, mevt->base + MCT_L_INT_ENB_OFFSET); |
299 | 336 | ||
300 | tmp = __raw_readl(mevt->base + MCT_L_TCON_OFFSET); | 337 | tmp = __raw_readl(reg_base + mevt->base + MCT_L_TCON_OFFSET); |
301 | tmp |= MCT_L_TCON_INT_START | MCT_L_TCON_TIMER_START | | 338 | tmp |= MCT_L_TCON_INT_START | MCT_L_TCON_TIMER_START | |
302 | MCT_L_TCON_INTERVAL_MODE; | 339 | MCT_L_TCON_INTERVAL_MODE; |
303 | exynos4_mct_write(tmp, mevt->base + MCT_L_TCON_OFFSET); | 340 | exynos4_mct_write(tmp, mevt->base + MCT_L_TCON_OFFSET); |
@@ -349,7 +386,7 @@ static int exynos4_mct_tick_clear(struct mct_clock_event_device *mevt) | |||
349 | exynos4_mct_tick_stop(mevt); | 386 | exynos4_mct_tick_stop(mevt); |
350 | 387 | ||
351 | /* Clear the MCT tick interrupt */ | 388 | /* Clear the MCT tick interrupt */ |
352 | if (__raw_readl(mevt->base + MCT_L_INT_CSTAT_OFFSET) & 1) { | 389 | if (__raw_readl(reg_base + mevt->base + MCT_L_INT_CSTAT_OFFSET) & 1) { |
353 | exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET); | 390 | exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET); |
354 | return 1; | 391 | return 1; |
355 | } else { | 392 | } else { |
@@ -385,7 +422,6 @@ static int __cpuinit exynos4_local_timer_setup(struct clock_event_device *evt) | |||
385 | { | 422 | { |
386 | struct mct_clock_event_device *mevt; | 423 | struct mct_clock_event_device *mevt; |
387 | unsigned int cpu = smp_processor_id(); | 424 | unsigned int cpu = smp_processor_id(); |
388 | int mct_lx_irq; | ||
389 | 425 | ||
390 | mevt = this_cpu_ptr(&percpu_mct_tick); | 426 | mevt = this_cpu_ptr(&percpu_mct_tick); |
391 | mevt->evt = evt; | 427 | mevt->evt = evt; |
@@ -406,21 +442,17 @@ static int __cpuinit exynos4_local_timer_setup(struct clock_event_device *evt) | |||
406 | 442 | ||
407 | if (mct_int_type == MCT_INT_SPI) { | 443 | if (mct_int_type == MCT_INT_SPI) { |
408 | if (cpu == 0) { | 444 | if (cpu == 0) { |
409 | mct_lx_irq = soc_is_exynos4210() ? EXYNOS4_IRQ_MCT_L0 : | ||
410 | EXYNOS5_IRQ_MCT_L0; | ||
411 | mct_tick0_event_irq.dev_id = mevt; | 445 | mct_tick0_event_irq.dev_id = mevt; |
412 | evt->irq = mct_lx_irq; | 446 | evt->irq = mct_irqs[MCT_L0_IRQ]; |
413 | setup_irq(mct_lx_irq, &mct_tick0_event_irq); | 447 | setup_irq(evt->irq, &mct_tick0_event_irq); |
414 | } else { | 448 | } else { |
415 | mct_lx_irq = soc_is_exynos4210() ? EXYNOS4_IRQ_MCT_L1 : | ||
416 | EXYNOS5_IRQ_MCT_L1; | ||
417 | mct_tick1_event_irq.dev_id = mevt; | 449 | mct_tick1_event_irq.dev_id = mevt; |
418 | evt->irq = mct_lx_irq; | 450 | evt->irq = mct_irqs[MCT_L1_IRQ]; |
419 | setup_irq(mct_lx_irq, &mct_tick1_event_irq); | 451 | setup_irq(evt->irq, &mct_tick1_event_irq); |
420 | irq_set_affinity(mct_lx_irq, cpumask_of(1)); | 452 | irq_set_affinity(evt->irq, cpumask_of(1)); |
421 | } | 453 | } |
422 | } else { | 454 | } else { |
423 | enable_percpu_irq(EXYNOS_IRQ_MCT_LOCALTIMER, 0); | 455 | enable_percpu_irq(mct_irqs[MCT_L0_IRQ], 0); |
424 | } | 456 | } |
425 | 457 | ||
426 | return 0; | 458 | return 0; |
@@ -436,7 +468,7 @@ static void exynos4_local_timer_stop(struct clock_event_device *evt) | |||
436 | else | 468 | else |
437 | remove_irq(evt->irq, &mct_tick1_event_irq); | 469 | remove_irq(evt->irq, &mct_tick1_event_irq); |
438 | else | 470 | else |
439 | disable_percpu_irq(EXYNOS_IRQ_MCT_LOCALTIMER); | 471 | disable_percpu_irq(mct_irqs[MCT_L0_IRQ]); |
440 | } | 472 | } |
441 | 473 | ||
442 | static struct local_timer_ops exynos4_mct_tick_ops __cpuinitdata = { | 474 | static struct local_timer_ops exynos4_mct_tick_ops __cpuinitdata = { |
@@ -445,41 +477,74 @@ static struct local_timer_ops exynos4_mct_tick_ops __cpuinitdata = { | |||
445 | }; | 477 | }; |
446 | #endif /* CONFIG_LOCAL_TIMERS */ | 478 | #endif /* CONFIG_LOCAL_TIMERS */ |
447 | 479 | ||
448 | static void __init exynos4_timer_resources(void) | 480 | static void __init exynos4_timer_resources(struct device_node *np) |
449 | { | 481 | { |
450 | struct clk *mct_clk; | 482 | struct clk *mct_clk; |
451 | mct_clk = clk_get(NULL, "xtal"); | 483 | mct_clk = clk_get(NULL, "xtal"); |
452 | 484 | ||
453 | clk_rate = clk_get_rate(mct_clk); | 485 | clk_rate = clk_get_rate(mct_clk); |
454 | 486 | ||
487 | reg_base = np ? of_iomap(np, 0) : S5P_VA_SYSTIMER; | ||
488 | if (!reg_base) | ||
489 | panic("%s: unable to ioremap mct address space\n", __func__); | ||
490 | |||
455 | #ifdef CONFIG_LOCAL_TIMERS | 491 | #ifdef CONFIG_LOCAL_TIMERS |
456 | if (mct_int_type == MCT_INT_PPI) { | 492 | if (mct_int_type == MCT_INT_PPI) { |
457 | int err; | 493 | int err; |
458 | 494 | ||
459 | err = request_percpu_irq(EXYNOS_IRQ_MCT_LOCALTIMER, | 495 | err = request_percpu_irq(mct_irqs[MCT_L0_IRQ], |
460 | exynos4_mct_tick_isr, "MCT", | 496 | exynos4_mct_tick_isr, "MCT", |
461 | &percpu_mct_tick); | 497 | &percpu_mct_tick); |
462 | WARN(err, "MCT: can't request IRQ %d (%d)\n", | 498 | WARN(err, "MCT: can't request IRQ %d (%d)\n", |
463 | EXYNOS_IRQ_MCT_LOCALTIMER, err); | 499 | mct_irqs[MCT_L0_IRQ], err); |
464 | } | 500 | } |
465 | 501 | ||
466 | local_timer_register(&exynos4_mct_tick_ops); | 502 | local_timer_register(&exynos4_mct_tick_ops); |
467 | #endif /* CONFIG_LOCAL_TIMERS */ | 503 | #endif /* CONFIG_LOCAL_TIMERS */ |
468 | } | 504 | } |
469 | 505 | ||
470 | void __init exynos4_timer_init(void) | 506 | static const struct of_device_id exynos_mct_ids[] = { |
471 | { | 507 | { .compatible = "samsung,exynos4210-mct", .data = (void *)MCT_INT_SPI }, |
472 | if (soc_is_exynos5440()) { | 508 | { .compatible = "samsung,exynos4412-mct", .data = (void *)MCT_INT_PPI }, |
473 | arch_timer_of_register(); | 509 | }; |
474 | return; | ||
475 | } | ||
476 | 510 | ||
477 | if ((soc_is_exynos4210()) || (soc_is_exynos5250())) | 511 | void __init mct_init(void) |
512 | { | ||
513 | struct device_node *np = NULL; | ||
514 | const struct of_device_id *match; | ||
515 | u32 nr_irqs, i; | ||
516 | |||
517 | #ifdef CONFIG_OF | ||
518 | np = of_find_matching_node_and_match(NULL, exynos_mct_ids, &match); | ||
519 | #endif | ||
520 | if (np) { | ||
521 | mct_int_type = (u32)(match->data); | ||
522 | |||
523 | /* This driver uses only one global timer interrupt */ | ||
524 | mct_irqs[MCT_G0_IRQ] = irq_of_parse_and_map(np, MCT_G0_IRQ); | ||
525 | |||
526 | /* | ||
527 | * Find out the number of local irqs specified. The local | ||
528 | * timer irqs are specified after the four global timer | ||
529 | * irqs are specified. | ||
530 | */ | ||
531 | #ifdef CONFIG_OF | ||
532 | nr_irqs = of_irq_count(np); | ||
533 | #endif | ||
534 | for (i = MCT_L0_IRQ; i < nr_irqs; i++) | ||
535 | mct_irqs[i] = irq_of_parse_and_map(np, i); | ||
536 | } else if (soc_is_exynos4210()) { | ||
537 | mct_irqs[MCT_G0_IRQ] = EXYNOS4_IRQ_MCT_G0; | ||
538 | mct_irqs[MCT_L0_IRQ] = EXYNOS4_IRQ_MCT_L0; | ||
539 | mct_irqs[MCT_L1_IRQ] = EXYNOS4_IRQ_MCT_L1; | ||
478 | mct_int_type = MCT_INT_SPI; | 540 | mct_int_type = MCT_INT_SPI; |
479 | else | 541 | } else { |
480 | mct_int_type = MCT_INT_PPI; | 542 | panic("unable to determine mct controller type\n"); |
543 | } | ||
481 | 544 | ||
482 | exynos4_timer_resources(); | 545 | exynos4_timer_resources(np); |
483 | exynos4_clocksource_init(); | 546 | exynos4_clocksource_init(); |
484 | exynos4_clockevent_init(); | 547 | exynos4_clockevent_init(); |
485 | } | 548 | } |
549 | CLOCKSOURCE_OF_DECLARE(exynos4210, "samsung,exynos4210-mct", mct_init) | ||
550 | CLOCKSOURCE_OF_DECLARE(exynos4412, "samsung,exynos4412-mct", mct_init) | ||