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); | ||
