diff options
author | Arnd Bergmann <arnd@arndb.de> | 2013-04-09 16:07:37 -0400 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2013-04-09 16:18:24 -0400 |
commit | 228e3023eb0430b4b9ed0736f8f87c96a6cd9c7a (patch) | |
tree | 4115d59b698a2a6e1953c5b263cab6d2a113d81b | |
parent | 894b7382cf20e81d38097d43b8802af6e79d48c4 (diff) | |
parent | 354599f460ba79c9fb00f220e42de5a7509ceeb4 (diff) |
Merge tag 'mct-exynos-for-v3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung into next/drivers
From Kukjin Kim <kgene.kim@samsung.com>:
add support exynos mct device tree and move into drivers/clocksource
* tag 'mct-exynos-for-v3.10' of git://git.kernel.org/pub/scm/linux/kernel/git/kgene/linux-samsung:
clocksource: mct: Add terminating entry for exynos_mct_ids table
clocksource: mct: Add missing semicolons in exynos_mct.c
ARM: EXYNOS: move mct driver to drivers/clocksource
ARM: EXYNOS: remove static io-remapping of mct registers for Exynos5
ARM: dts: add mct device tree node for all supported Exynos SoC's
ARM: EXYNOS: allow dt based discovery of mct controller using clocksource_of_init
ARM: EXYNOS: add device tree support for MCT controller driver
ARM: EXYNOS: prepare an array of MCT interrupt numbers and use it
ARM: EXYNOS: add a register base address variable in mct controller driver
Conflicts:
drivers/clocksource/Makefile
drivers/clocksource/exynos_mct.c
[arnd: adapt to CLOCKSOURCE_OF_DECLARE interface change]
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
23 files changed, 315 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 6adf79869f8c..03301cb114ac 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -1654,7 +1654,7 @@ config LOCAL_TIMERS | |||
1654 | bool "Use local timer interrupts" | 1654 | bool "Use local timer interrupts" |
1655 | depends on SMP | 1655 | depends on SMP |
1656 | default y | 1656 | default y |
1657 | select HAVE_ARM_TWD if (!ARCH_MSM_SCORPIONMP && !EXYNOS4_MCT) | 1657 | select HAVE_ARM_TWD if (!ARCH_MSM_SCORPIONMP && !CLKSRC_EXYNOS_MCT) |
1658 | help | 1658 | help |
1659 | Enable support for local timers on SMP platforms, rather then the | 1659 | Enable support for local timers on SMP platforms, rather then the |
1660 | legacy IPI broadcast method. Local timers allows the system | 1660 | 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 b1ac73e21c80..c60108e0d27e 100644 --- a/arch/arm/boot/dts/exynos5250.dtsi +++ b/arch/arm/boot/dts/exynos5250.dtsi | |||
@@ -69,6 +69,28 @@ | |||
69 | <0 28 0>, <0 29 0>, <0 30 0>, <0 31 0>; | 69 | <0 28 0>, <0 29 0>, <0 30 0>, <0 31 0>; |
70 | }; | 70 | }; |
71 | 71 | ||
72 | mct@101C0000 { | ||
73 | compatible = "samsung,exynos4210-mct"; | ||
74 | reg = <0x101C0000 0x800>; | ||
75 | interrupt-controller; | ||
76 | #interrups-cells = <2>; | ||
77 | interrupt-parent = <&mct_map>; | ||
78 | interrupts = <0 0>, <1 0>, <2 0>, <3 0>, | ||
79 | <4 0>, <5 0>; | ||
80 | |||
81 | mct_map: mct-map { | ||
82 | #interrupt-cells = <2>; | ||
83 | #address-cells = <0>; | ||
84 | #size-cells = <0>; | ||
85 | interrupt-map = <0x0 0 &combiner 23 3>, | ||
86 | <0x1 0 &combiner 23 4>, | ||
87 | <0x2 0 &combiner 25 2>, | ||
88 | <0x3 0 &combiner 25 3>, | ||
89 | <0x4 0 &gic 0 120 0>, | ||
90 | <0x5 0 &gic 0 121 0>; | ||
91 | }; | ||
92 | }; | ||
93 | |||
72 | watchdog { | 94 | watchdog { |
73 | compatible = "samsung,s3c2410-wdt"; | 95 | compatible = "samsung,s3c2410-wdt"; |
74 | reg = <0x101D0000 0x100>; | 96 | reg = <0x101D0000 0x100>; |
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig index 2f45906d6ee5..faca4326b46a 100644 --- a/arch/arm/mach-exynos/Kconfig +++ b/arch/arm/mach-exynos/Kconfig | |||
@@ -79,12 +79,6 @@ config SOC_EXYNOS5440 | |||
79 | help | 79 | help |
80 | Enable EXYNOS5440 SoC support | 80 | Enable EXYNOS5440 SoC support |
81 | 81 | ||
82 | config EXYNOS4_MCT | ||
83 | bool | ||
84 | default y | ||
85 | help | ||
86 | Use MCT (Multi Core Timer) as kernel timers | ||
87 | |||
88 | config EXYNOS_DEV_DMA | 82 | config EXYNOS_DEV_DMA |
89 | bool | 83 | bool |
90 | help | 84 | help |
@@ -406,6 +400,7 @@ config MACH_EXYNOS4_DT | |||
406 | bool "Samsung Exynos4 Machine using device tree" | 400 | bool "Samsung Exynos4 Machine using device tree" |
407 | depends on ARCH_EXYNOS4 | 401 | depends on ARCH_EXYNOS4 |
408 | select ARM_AMBA | 402 | select ARM_AMBA |
403 | select CLKSRC_OF | ||
409 | select CPU_EXYNOS4210 | 404 | select CPU_EXYNOS4210 |
410 | select HAVE_SAMSUNG_KEYPAD if INPUT_KEYBOARD | 405 | select HAVE_SAMSUNG_KEYPAD if INPUT_KEYBOARD |
411 | select PINCTRL | 406 | select PINCTRL |
@@ -422,6 +417,7 @@ config MACH_EXYNOS5_DT | |||
422 | default y | 417 | default y |
423 | depends on ARCH_EXYNOS5 | 418 | depends on ARCH_EXYNOS5 |
424 | select ARM_AMBA | 419 | select ARM_AMBA |
420 | select CLKSRC_OF | ||
425 | select USE_OF | 421 | select USE_OF |
426 | help | 422 | help |
427 | Machine support for Samsung EXYNOS5 machine with device tree enabled. | 423 | 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 bdd957978d9b..db7dbd0eb6b4 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 3358088c822a..c4ae108e192d 100644 --- a/arch/arm/mach-exynos/mach-exynos4-dt.c +++ b/arch/arm/mach-exynos/mach-exynos4-dt.c | |||
@@ -13,6 +13,7 @@ | |||
13 | 13 | ||
14 | #include <linux/of_platform.h> | 14 | #include <linux/of_platform.h> |
15 | #include <linux/serial_core.h> | 15 | #include <linux/serial_core.h> |
16 | #include <linux/clocksource.h> | ||
16 | 17 | ||
17 | #include <asm/mach/arch.h> | 18 | #include <asm/mach/arch.h> |
18 | #include <mach/map.h> | 19 | #include <mach/map.h> |
@@ -142,7 +143,7 @@ DT_MACHINE_START(EXYNOS4210_DT, "Samsung Exynos4 (Flattened Device Tree)") | |||
142 | .map_io = exynos4_dt_map_io, | 143 | .map_io = exynos4_dt_map_io, |
143 | .init_machine = exynos4_dt_machine_init, | 144 | .init_machine = exynos4_dt_machine_init, |
144 | .init_late = exynos_init_late, | 145 | .init_late = exynos_init_late, |
145 | .init_time = exynos4_timer_init, | 146 | .init_time = clocksource_of_init, |
146 | .dt_compat = exynos4_dt_compat, | 147 | .dt_compat = exynos4_dt_compat, |
147 | .restart = exynos4_restart, | 148 | .restart = exynos4_restart, |
148 | MACHINE_END | 149 | MACHINE_END |
diff --git a/arch/arm/mach-exynos/mach-exynos5-dt.c b/arch/arm/mach-exynos/mach-exynos5-dt.c index acaeb14db54b..7da4791bfb8b 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> |
@@ -216,7 +217,7 @@ DT_MACHINE_START(EXYNOS5_DT, "SAMSUNG EXYNOS5 (Flattened Device Tree)") | |||
216 | .map_io = exynos5_dt_map_io, | 217 | .map_io = exynos5_dt_map_io, |
217 | .init_machine = exynos5_dt_machine_init, | 218 | .init_machine = exynos5_dt_machine_init, |
218 | .init_late = exynos_init_late, | 219 | .init_late = exynos_init_late, |
219 | .init_time = exynos4_timer_init, | 220 | .init_time = clocksource_of_init, |
220 | .dt_compat = exynos5_dt_compat, | 221 | .dt_compat = exynos5_dt_compat, |
221 | .restart = exynos5_restart, | 222 | .restart = exynos5_restart, |
222 | .reserve = exynos5_reserve, | 223 | .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 3167fda9bbb3..73fcddb8314d 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig | |||
@@ -70,3 +70,8 @@ config CLKSRC_METAG_GENERIC | |||
70 | def_bool y if METAG | 70 | def_bool y if METAG |
71 | help | 71 | help |
72 | This option enables support for the Meta per-thread timers. | 72 | This option enables support for the Meta per-thread timers. |
73 | |||
74 | config CLKSRC_EXYNOS_MCT | ||
75 | def_bool y if ARCH_EXYNOS | ||
76 | help | ||
77 | Support for Multi Core Timer controller on Exynos SoCs. | ||
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index e74c8ce26bf0..cd1f09cbd61a 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile | |||
@@ -19,7 +19,8 @@ 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_CADENCE_TTC_TIMER) += cadence_ttc_timer.o | 22 | obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence_ttc_timer.o |
23 | obj-$(CONFIG_CLKSRC_EXYNOS_MCT) += exynos_mct.o | ||
23 | 24 | ||
24 | obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o | 25 | obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o |
25 | obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o | 26 | 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..957af8636c9d 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,80 @@ 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(void __iomem *base) |
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 = base; | ||
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 | void __init mct_init(void) |
471 | { | 507 | { |
472 | if (soc_is_exynos5440()) { | 508 | if (soc_is_exynos4210()) { |
473 | arch_timer_of_register(); | 509 | mct_irqs[MCT_G0_IRQ] = EXYNOS4_IRQ_MCT_G0; |
474 | return; | 510 | mct_irqs[MCT_L0_IRQ] = EXYNOS4_IRQ_MCT_L0; |
511 | mct_irqs[MCT_L1_IRQ] = EXYNOS4_IRQ_MCT_L1; | ||
512 | mct_int_type = MCT_INT_SPI; | ||
513 | } else { | ||
514 | panic("unable to determine mct controller type\n"); | ||
475 | } | 515 | } |
476 | 516 | ||
477 | if ((soc_is_exynos4210()) || (soc_is_exynos5250())) | 517 | exynos4_timer_resources(S5P_VA_SYSTIMER); |
478 | mct_int_type = MCT_INT_SPI; | 518 | exynos4_clocksource_init(); |
479 | else | 519 | exynos4_clockevent_init(); |
480 | mct_int_type = MCT_INT_PPI; | 520 | } |
481 | 521 | ||
482 | exynos4_timer_resources(); | 522 | static void __init mct_init_dt(struct device_node *np, unsigned int int_type) |
523 | { | ||
524 | u32 nr_irqs, i; | ||
525 | |||
526 | mct_int_type = int_type; | ||
527 | |||
528 | /* This driver uses only one global timer interrupt */ | ||
529 | mct_irqs[MCT_G0_IRQ] = irq_of_parse_and_map(np, MCT_G0_IRQ); | ||
530 | |||
531 | /* | ||
532 | * Find out the number of local irqs specified. The local | ||
533 | * timer irqs are specified after the four global timer | ||
534 | * irqs are specified. | ||
535 | */ | ||
536 | nr_irqs = of_irq_count(np); | ||
537 | for (i = MCT_L0_IRQ; i < nr_irqs; i++) | ||
538 | mct_irqs[i] = irq_of_parse_and_map(np, i); | ||
539 | |||
540 | exynos4_timer_resources(of_iomap(np, 0)); | ||
483 | exynos4_clocksource_init(); | 541 | exynos4_clocksource_init(); |
484 | exynos4_clockevent_init(); | 542 | exynos4_clockevent_init(); |
485 | } | 543 | } |
544 | |||
545 | |||
546 | static void __init mct_init_spi(struct device_node *np) | ||
547 | { | ||
548 | return mct_init_dt(np, MCT_INT_SPI); | ||
549 | } | ||
550 | |||
551 | static void __init mct_init_ppi(struct device_node *np) | ||
552 | { | ||
553 | return mct_init_dt(np, MCT_INT_PPI); | ||
554 | } | ||
555 | CLOCKSOURCE_OF_DECLARE(exynos4210, "samsung,exynos4210-mct", mct_init_spi); | ||
556 | CLOCKSOURCE_OF_DECLARE(exynos4412, "samsung,exynos4412-mct", mct_init_ppi); | ||