aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-exynos
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-exynos')
-rw-r--r--arch/arm/mach-exynos/Kconfig8
-rw-r--r--arch/arm/mach-exynos/Makefile2
-rw-r--r--arch/arm/mach-exynos/common.c5
-rw-r--r--arch/arm/mach-exynos/common.h2
-rw-r--r--arch/arm/mach-exynos/include/mach/irqs.h6
-rw-r--r--arch/arm/mach-exynos/include/mach/map.h1
-rw-r--r--arch/arm/mach-exynos/include/mach/regs-mct.h53
-rw-r--r--arch/arm/mach-exynos/mach-armlex4210.c2
-rw-r--r--arch/arm/mach-exynos/mach-exynos4-dt.c3
-rw-r--r--arch/arm/mach-exynos/mach-exynos5-dt.c3
-rw-r--r--arch/arm/mach-exynos/mach-nuri.c2
-rw-r--r--arch/arm/mach-exynos/mach-origen.c2
-rw-r--r--arch/arm/mach-exynos/mach-smdk4x12.c4
-rw-r--r--arch/arm/mach-exynos/mach-smdkv310.c4
-rw-r--r--arch/arm/mach-exynos/mct.c485
15 files changed, 14 insertions, 568 deletions
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index bc15b9ee8174..ef3b69a6277c 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -80,12 +80,6 @@ config SOC_EXYNOS5440
80 help 80 help
81 Enable EXYNOS5440 SoC support 81 Enable EXYNOS5440 SoC support
82 82
83config EXYNOS4_MCT
84 bool
85 default y
86 help
87 Use MCT (Multi Core Timer) as kernel timers
88
89config EXYNOS_DEV_DMA 83config EXYNOS_DEV_DMA
90 bool 84 bool
91 help 85 help
@@ -407,6 +401,7 @@ config MACH_EXYNOS4_DT
407 bool "Samsung Exynos4 Machine using device tree" 401 bool "Samsung Exynos4 Machine using device tree"
408 depends on ARCH_EXYNOS4 402 depends on ARCH_EXYNOS4
409 select ARM_AMBA 403 select ARM_AMBA
404 select CLKSRC_OF
410 select CPU_EXYNOS4210 405 select CPU_EXYNOS4210
411 select HAVE_SAMSUNG_KEYPAD if INPUT_KEYBOARD 406 select HAVE_SAMSUNG_KEYPAD if INPUT_KEYBOARD
412 select PINCTRL 407 select PINCTRL
@@ -424,6 +419,7 @@ config MACH_EXYNOS5_DT
424 default y 419 default y
425 depends on ARCH_EXYNOS5 420 depends on ARCH_EXYNOS5
426 select ARM_AMBA 421 select ARM_AMBA
422 select CLKSRC_OF
427 select USE_OF 423 select USE_OF
428 help 424 help
429 Machine support for Samsung EXYNOS5 machine with device tree enabled. 425 Machine support for Samsung EXYNOS5 machine with device tree enabled.
diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile
index 435757e57bb4..daf289b21486 100644
--- a/arch/arm/mach-exynos/Makefile
+++ b/arch/arm/mach-exynos/Makefile
@@ -26,8 +26,6 @@ obj-$(CONFIG_ARCH_EXYNOS) += pmu.o
26 26
27obj-$(CONFIG_SMP) += platsmp.o headsmp.o 27obj-$(CONFIG_SMP) += platsmp.o headsmp.o
28 28
29obj-$(CONFIG_EXYNOS4_MCT) += mct.o
30
31obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o 29obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
32 30
33# machine support 31# machine support
diff --git a/arch/arm/mach-exynos/common.c b/arch/arm/mach-exynos/common.c
index d63d399c7bae..f91dad6fe9a3 100644
--- a/arch/arm/mach-exynos/common.c
+++ b/arch/arm/mach-exynos/common.c
@@ -257,11 +257,6 @@ static struct map_desc exynos5_iodesc[] __initdata = {
257 .length = SZ_4K, 257 .length = SZ_4K,
258 .type = MT_DEVICE, 258 .type = MT_DEVICE,
259 }, { 259 }, {
260 .virtual = (unsigned long)S5P_VA_SYSTIMER,
261 .pfn = __phys_to_pfn(EXYNOS5_PA_SYSTIMER),
262 .length = SZ_4K,
263 .type = MT_DEVICE,
264 }, {
265 .virtual = (unsigned long)S5P_VA_SYSRAM, 260 .virtual = (unsigned long)S5P_VA_SYSRAM,
266 .pfn = __phys_to_pfn(EXYNOS5_PA_SYSRAM), 261 .pfn = __phys_to_pfn(EXYNOS5_PA_SYSRAM),
267 .length = SZ_4K, 262 .length = SZ_4K,
diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h
index 9339bb8954be..3b186eaaaa7b 100644
--- a/arch/arm/mach-exynos/common.h
+++ b/arch/arm/mach-exynos/common.h
@@ -12,7 +12,7 @@
12#ifndef __ARCH_ARM_MACH_EXYNOS_COMMON_H 12#ifndef __ARCH_ARM_MACH_EXYNOS_COMMON_H
13#define __ARCH_ARM_MACH_EXYNOS_COMMON_H 13#define __ARCH_ARM_MACH_EXYNOS_COMMON_H
14 14
15extern void exynos4_timer_init(void); 15extern void mct_init(void);
16 16
17struct map_desc; 17struct map_desc;
18void exynos_init_io(struct map_desc *mach_desc, int size); 18void 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,
207MACHINE_END 207MACHINE_END
diff --git a/arch/arm/mach-exynos/mach-exynos4-dt.c b/arch/arm/mach-exynos/mach-exynos4-dt.c
index fad268f8548c..daa7b0da9a2d 100644
--- a/arch/arm/mach-exynos/mach-exynos4-dt.c
+++ b/arch/arm/mach-exynos/mach-exynos4-dt.c
@@ -15,6 +15,7 @@
15#include <linux/of_fdt.h> 15#include <linux/of_fdt.h>
16#include <linux/serial_core.h> 16#include <linux/serial_core.h>
17#include <linux/memblock.h> 17#include <linux/memblock.h>
18#include <linux/clocksource.h>
18 19
19#include <asm/mach/arch.h> 20#include <asm/mach/arch.h>
20#include <mach/map.h> 21#include <mach/map.h>
@@ -158,7 +159,7 @@ DT_MACHINE_START(EXYNOS4210_DT, "Samsung Exynos4 (Flattened Device Tree)")
158 .map_io = exynos4_dt_map_io, 159 .map_io = exynos4_dt_map_io,
159 .init_machine = exynos4_dt_machine_init, 160 .init_machine = exynos4_dt_machine_init,
160 .init_late = exynos_init_late, 161 .init_late = exynos_init_late,
161 .init_time = exynos4_timer_init, 162 .init_time = clocksource_of_init,
162 .dt_compat = exynos4_dt_compat, 163 .dt_compat = exynos4_dt_compat,
163 .restart = exynos4_restart, 164 .restart = exynos4_restart,
164 .reserve = exynos4_reserve, 165 .reserve = exynos4_reserve,
diff --git a/arch/arm/mach-exynos/mach-exynos5-dt.c b/arch/arm/mach-exynos/mach-exynos5-dt.c
index 8ef895745175..62d43dacf636 100644
--- a/arch/arm/mach-exynos/mach-exynos5-dt.c
+++ b/arch/arm/mach-exynos/mach-exynos5-dt.c
@@ -14,6 +14,7 @@
14#include <linux/serial_core.h> 14#include <linux/serial_core.h>
15#include <linux/memblock.h> 15#include <linux/memblock.h>
16#include <linux/io.h> 16#include <linux/io.h>
17#include <linux/clocksource.h>
17 18
18#include <asm/mach/arch.h> 19#include <asm/mach/arch.h>
19#include <mach/map.h> 20#include <mach/map.h>
@@ -217,7 +218,7 @@ DT_MACHINE_START(EXYNOS5_DT, "SAMSUNG EXYNOS5 (Flattened Device Tree)")
217 .map_io = exynos5_dt_map_io, 218 .map_io = exynos5_dt_map_io,
218 .init_machine = exynos5_dt_machine_init, 219 .init_machine = exynos5_dt_machine_init,
219 .init_late = exynos_init_late, 220 .init_late = exynos_init_late,
220 .init_time = exynos4_timer_init, 221 .init_time = clocksource_of_init,
221 .dt_compat = exynos5_dt_compat, 222 .dt_compat = exynos5_dt_compat,
222 .restart = exynos5_restart, 223 .restart = exynos5_restart,
223 .reserve = exynos5_reserve, 224 .reserve = exynos5_reserve,
diff --git a/arch/arm/mach-exynos/mach-nuri.c b/arch/arm/mach-exynos/mach-nuri.c
index 1ea79730187f..da3605d15110 100644
--- a/arch/arm/mach-exynos/mach-nuri.c
+++ b/arch/arm/mach-exynos/mach-nuri.c
@@ -1380,7 +1380,7 @@ MACHINE_START(NURI, "NURI")
1380 .map_io = nuri_map_io, 1380 .map_io = nuri_map_io,
1381 .init_machine = nuri_machine_init, 1381 .init_machine = nuri_machine_init,
1382 .init_late = exynos_init_late, 1382 .init_late = exynos_init_late,
1383 .init_time = exynos4_timer_init, 1383 .init_time = mct_init,
1384 .reserve = &nuri_reserve, 1384 .reserve = &nuri_reserve,
1385 .restart = exynos4_restart, 1385 .restart = exynos4_restart,
1386MACHINE_END 1386MACHINE_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,
821MACHINE_END 821MACHINE_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,
382MACHINE_END 382MACHINE_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,
396MACHINE_END 396MACHINE_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,
429MACHINE_END 429MACHINE_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,
442MACHINE_END 442MACHINE_END
diff --git a/arch/arm/mach-exynos/mct.c b/arch/arm/mach-exynos/mct.c
deleted file mode 100644
index c9d6650f9b5d..000000000000
--- a/arch/arm/mach-exynos/mct.c
+++ /dev/null
@@ -1,485 +0,0 @@
1/* linux/arch/arm/mach-exynos4/mct.c
2 *
3 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com
5 *
6 * EXYNOS4 MCT(Multi-Core Timer) support
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#include <linux/sched.h>
14#include <linux/interrupt.h>
15#include <linux/irq.h>
16#include <linux/err.h>
17#include <linux/clk.h>
18#include <linux/clockchips.h>
19#include <linux/platform_device.h>
20#include <linux/delay.h>
21#include <linux/percpu.h>
22#include <linux/of.h>
23
24#include <asm/arch_timer.h>
25#include <asm/localtimer.h>
26
27#include <plat/cpu.h>
28
29#include <mach/map.h>
30#include <mach/irqs.h>
31#include <mach/regs-mct.h>
32#include <asm/mach/time.h>
33
34#define TICK_BASE_CNT 1
35
36enum {
37 MCT_INT_SPI,
38 MCT_INT_PPI
39};
40
41static unsigned long clk_rate;
42static unsigned int mct_int_type;
43
44struct mct_clock_event_device {
45 struct clock_event_device *evt;
46 void __iomem *base;
47 char name[10];
48};
49
50static void exynos4_mct_write(unsigned int value, void *addr)
51{
52 void __iomem *stat_addr;
53 u32 mask;
54 u32 i;
55
56 __raw_writel(value, addr);
57
58 if (likely(addr >= EXYNOS4_MCT_L_BASE(0))) {
59 u32 base = (u32) addr & EXYNOS4_MCT_L_MASK;
60 switch ((u32) addr & ~EXYNOS4_MCT_L_MASK) {
61 case (u32) MCT_L_TCON_OFFSET:
62 stat_addr = (void __iomem *) base + MCT_L_WSTAT_OFFSET;
63 mask = 1 << 3; /* L_TCON write status */
64 break;
65 case (u32) MCT_L_ICNTB_OFFSET:
66 stat_addr = (void __iomem *) base + MCT_L_WSTAT_OFFSET;
67 mask = 1 << 1; /* L_ICNTB write status */
68 break;
69 case (u32) MCT_L_TCNTB_OFFSET:
70 stat_addr = (void __iomem *) base + MCT_L_WSTAT_OFFSET;
71 mask = 1 << 0; /* L_TCNTB write status */
72 break;
73 default:
74 return;
75 }
76 } else {
77 switch ((u32) addr) {
78 case (u32) EXYNOS4_MCT_G_TCON:
79 stat_addr = EXYNOS4_MCT_G_WSTAT;
80 mask = 1 << 16; /* G_TCON write status */
81 break;
82 case (u32) EXYNOS4_MCT_G_COMP0_L:
83 stat_addr = EXYNOS4_MCT_G_WSTAT;
84 mask = 1 << 0; /* G_COMP0_L write status */
85 break;
86 case (u32) EXYNOS4_MCT_G_COMP0_U:
87 stat_addr = EXYNOS4_MCT_G_WSTAT;
88 mask = 1 << 1; /* G_COMP0_U write status */
89 break;
90 case (u32) EXYNOS4_MCT_G_COMP0_ADD_INCR:
91 stat_addr = EXYNOS4_MCT_G_WSTAT;
92 mask = 1 << 2; /* G_COMP0_ADD_INCR w status */
93 break;
94 case (u32) EXYNOS4_MCT_G_CNT_L:
95 stat_addr = EXYNOS4_MCT_G_CNT_WSTAT;
96 mask = 1 << 0; /* G_CNT_L write status */
97 break;
98 case (u32) EXYNOS4_MCT_G_CNT_U:
99 stat_addr = EXYNOS4_MCT_G_CNT_WSTAT;
100 mask = 1 << 1; /* G_CNT_U write status */
101 break;
102 default:
103 return;
104 }
105 }
106
107 /* Wait maximum 1 ms until written values are applied */
108 for (i = 0; i < loops_per_jiffy / 1000 * HZ; i++)
109 if (__raw_readl(stat_addr) & mask) {
110 __raw_writel(mask, stat_addr);
111 return;
112 }
113
114 panic("MCT hangs after writing %d (addr:0x%08x)\n", value, (u32)addr);
115}
116
117/* Clocksource handling */
118static void exynos4_mct_frc_start(u32 hi, u32 lo)
119{
120 u32 reg;
121
122 exynos4_mct_write(lo, EXYNOS4_MCT_G_CNT_L);
123 exynos4_mct_write(hi, EXYNOS4_MCT_G_CNT_U);
124
125 reg = __raw_readl(EXYNOS4_MCT_G_TCON);
126 reg |= MCT_G_TCON_START;
127 exynos4_mct_write(reg, EXYNOS4_MCT_G_TCON);
128}
129
130static cycle_t exynos4_frc_read(struct clocksource *cs)
131{
132 unsigned int lo, hi;
133 u32 hi2 = __raw_readl(EXYNOS4_MCT_G_CNT_U);
134
135 do {
136 hi = hi2;
137 lo = __raw_readl(EXYNOS4_MCT_G_CNT_L);
138 hi2 = __raw_readl(EXYNOS4_MCT_G_CNT_U);
139 } while (hi != hi2);
140
141 return ((cycle_t)hi << 32) | lo;
142}
143
144static void exynos4_frc_resume(struct clocksource *cs)
145{
146 exynos4_mct_frc_start(0, 0);
147}
148
149struct clocksource mct_frc = {
150 .name = "mct-frc",
151 .rating = 400,
152 .read = exynos4_frc_read,
153 .mask = CLOCKSOURCE_MASK(64),
154 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
155 .resume = exynos4_frc_resume,
156};
157
158static void __init exynos4_clocksource_init(void)
159{
160 exynos4_mct_frc_start(0, 0);
161
162 if (clocksource_register_hz(&mct_frc, clk_rate))
163 panic("%s: can't register clocksource\n", mct_frc.name);
164}
165
166static void exynos4_mct_comp0_stop(void)
167{
168 unsigned int tcon;
169
170 tcon = __raw_readl(EXYNOS4_MCT_G_TCON);
171 tcon &= ~(MCT_G_TCON_COMP0_ENABLE | MCT_G_TCON_COMP0_AUTO_INC);
172
173 exynos4_mct_write(tcon, EXYNOS4_MCT_G_TCON);
174 exynos4_mct_write(0, EXYNOS4_MCT_G_INT_ENB);
175}
176
177static void exynos4_mct_comp0_start(enum clock_event_mode mode,
178 unsigned long cycles)
179{
180 unsigned int tcon;
181 cycle_t comp_cycle;
182
183 tcon = __raw_readl(EXYNOS4_MCT_G_TCON);
184
185 if (mode == CLOCK_EVT_MODE_PERIODIC) {
186 tcon |= MCT_G_TCON_COMP0_AUTO_INC;
187 exynos4_mct_write(cycles, EXYNOS4_MCT_G_COMP0_ADD_INCR);
188 }
189
190 comp_cycle = exynos4_frc_read(&mct_frc) + cycles;
191 exynos4_mct_write((u32)comp_cycle, EXYNOS4_MCT_G_COMP0_L);
192 exynos4_mct_write((u32)(comp_cycle >> 32), EXYNOS4_MCT_G_COMP0_U);
193
194 exynos4_mct_write(0x1, EXYNOS4_MCT_G_INT_ENB);
195
196 tcon |= MCT_G_TCON_COMP0_ENABLE;
197 exynos4_mct_write(tcon , EXYNOS4_MCT_G_TCON);
198}
199
200static int exynos4_comp_set_next_event(unsigned long cycles,
201 struct clock_event_device *evt)
202{
203 exynos4_mct_comp0_start(evt->mode, cycles);
204
205 return 0;
206}
207
208static void exynos4_comp_set_mode(enum clock_event_mode mode,
209 struct clock_event_device *evt)
210{
211 unsigned long cycles_per_jiffy;
212 exynos4_mct_comp0_stop();
213
214 switch (mode) {
215 case CLOCK_EVT_MODE_PERIODIC:
216 cycles_per_jiffy =
217 (((unsigned long long) NSEC_PER_SEC / HZ * evt->mult) >> evt->shift);
218 exynos4_mct_comp0_start(mode, cycles_per_jiffy);
219 break;
220
221 case CLOCK_EVT_MODE_ONESHOT:
222 case CLOCK_EVT_MODE_UNUSED:
223 case CLOCK_EVT_MODE_SHUTDOWN:
224 case CLOCK_EVT_MODE_RESUME:
225 break;
226 }
227}
228
229static struct clock_event_device mct_comp_device = {
230 .name = "mct-comp",
231 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
232 .rating = 250,
233 .set_next_event = exynos4_comp_set_next_event,
234 .set_mode = exynos4_comp_set_mode,
235};
236
237static irqreturn_t exynos4_mct_comp_isr(int irq, void *dev_id)
238{
239 struct clock_event_device *evt = dev_id;
240
241 exynos4_mct_write(0x1, EXYNOS4_MCT_G_INT_CSTAT);
242
243 evt->event_handler(evt);
244
245 return IRQ_HANDLED;
246}
247
248static struct irqaction mct_comp_event_irq = {
249 .name = "mct_comp_irq",
250 .flags = IRQF_TIMER | IRQF_IRQPOLL,
251 .handler = exynos4_mct_comp_isr,
252 .dev_id = &mct_comp_device,
253};
254
255static void exynos4_clockevent_init(void)
256{
257 mct_comp_device.cpumask = cpumask_of(0);
258 clockevents_config_and_register(&mct_comp_device, clk_rate,
259 0xf, 0xffffffff);
260
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}
266
267#ifdef CONFIG_LOCAL_TIMERS
268
269static DEFINE_PER_CPU(struct mct_clock_event_device, percpu_mct_tick);
270
271/* Clock event handling */
272static void exynos4_mct_tick_stop(struct mct_clock_event_device *mevt)
273{
274 unsigned long tmp;
275 unsigned long mask = MCT_L_TCON_INT_START | MCT_L_TCON_TIMER_START;
276 void __iomem *addr = mevt->base + MCT_L_TCON_OFFSET;
277
278 tmp = __raw_readl(addr);
279 if (tmp & mask) {
280 tmp &= ~mask;
281 exynos4_mct_write(tmp, addr);
282 }
283}
284
285static void exynos4_mct_tick_start(unsigned long cycles,
286 struct mct_clock_event_device *mevt)
287{
288 unsigned long tmp;
289
290 exynos4_mct_tick_stop(mevt);
291
292 tmp = (1 << 31) | cycles; /* MCT_L_UPDATE_ICNTB */
293
294 /* update interrupt count buffer */
295 exynos4_mct_write(tmp, mevt->base + MCT_L_ICNTB_OFFSET);
296
297 /* enable MCT tick interrupt */
298 exynos4_mct_write(0x1, mevt->base + MCT_L_INT_ENB_OFFSET);
299
300 tmp = __raw_readl(mevt->base + MCT_L_TCON_OFFSET);
301 tmp |= MCT_L_TCON_INT_START | MCT_L_TCON_TIMER_START |
302 MCT_L_TCON_INTERVAL_MODE;
303 exynos4_mct_write(tmp, mevt->base + MCT_L_TCON_OFFSET);
304}
305
306static int exynos4_tick_set_next_event(unsigned long cycles,
307 struct clock_event_device *evt)
308{
309 struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick);
310
311 exynos4_mct_tick_start(cycles, mevt);
312
313 return 0;
314}
315
316static inline void exynos4_tick_set_mode(enum clock_event_mode mode,
317 struct clock_event_device *evt)
318{
319 struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick);
320 unsigned long cycles_per_jiffy;
321
322 exynos4_mct_tick_stop(mevt);
323
324 switch (mode) {
325 case CLOCK_EVT_MODE_PERIODIC:
326 cycles_per_jiffy =
327 (((unsigned long long) NSEC_PER_SEC / HZ * evt->mult) >> evt->shift);
328 exynos4_mct_tick_start(cycles_per_jiffy, mevt);
329 break;
330
331 case CLOCK_EVT_MODE_ONESHOT:
332 case CLOCK_EVT_MODE_UNUSED:
333 case CLOCK_EVT_MODE_SHUTDOWN:
334 case CLOCK_EVT_MODE_RESUME:
335 break;
336 }
337}
338
339static int exynos4_mct_tick_clear(struct mct_clock_event_device *mevt)
340{
341 struct clock_event_device *evt = mevt->evt;
342
343 /*
344 * This is for supporting oneshot mode.
345 * Mct would generate interrupt periodically
346 * without explicit stopping.
347 */
348 if (evt->mode != CLOCK_EVT_MODE_PERIODIC)
349 exynos4_mct_tick_stop(mevt);
350
351 /* Clear the MCT tick interrupt */
352 if (__raw_readl(mevt->base + MCT_L_INT_CSTAT_OFFSET) & 1) {
353 exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET);
354 return 1;
355 } else {
356 return 0;
357 }
358}
359
360static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id)
361{
362 struct mct_clock_event_device *mevt = dev_id;
363 struct clock_event_device *evt = mevt->evt;
364
365 exynos4_mct_tick_clear(mevt);
366
367 evt->event_handler(evt);
368
369 return IRQ_HANDLED;
370}
371
372static struct irqaction mct_tick0_event_irq = {
373 .name = "mct_tick0_irq",
374 .flags = IRQF_TIMER | IRQF_NOBALANCING,
375 .handler = exynos4_mct_tick_isr,
376};
377
378static struct irqaction mct_tick1_event_irq = {
379 .name = "mct_tick1_irq",
380 .flags = IRQF_TIMER | IRQF_NOBALANCING,
381 .handler = exynos4_mct_tick_isr,
382};
383
384static int __cpuinit exynos4_local_timer_setup(struct clock_event_device *evt)
385{
386 struct mct_clock_event_device *mevt;
387 unsigned int cpu = smp_processor_id();
388 int mct_lx_irq;
389
390 mevt = this_cpu_ptr(&percpu_mct_tick);
391 mevt->evt = evt;
392
393 mevt->base = EXYNOS4_MCT_L_BASE(cpu);
394 sprintf(mevt->name, "mct_tick%d", cpu);
395
396 evt->name = mevt->name;
397 evt->cpumask = cpumask_of(cpu);
398 evt->set_next_event = exynos4_tick_set_next_event;
399 evt->set_mode = exynos4_tick_set_mode;
400 evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
401 evt->rating = 450;
402 clockevents_config_and_register(evt, clk_rate / (TICK_BASE_CNT + 1),
403 0xf, 0x7fffffff);
404
405 exynos4_mct_write(TICK_BASE_CNT, mevt->base + MCT_L_TCNTB_OFFSET);
406
407 if (mct_int_type == MCT_INT_SPI) {
408 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;
412 evt->irq = mct_lx_irq;
413 setup_irq(mct_lx_irq, &mct_tick0_event_irq);
414 } 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;
418 evt->irq = mct_lx_irq;
419 setup_irq(mct_lx_irq, &mct_tick1_event_irq);
420 irq_set_affinity(mct_lx_irq, cpumask_of(1));
421 }
422 } else {
423 enable_percpu_irq(EXYNOS_IRQ_MCT_LOCALTIMER, 0);
424 }
425
426 return 0;
427}
428
429static void exynos4_local_timer_stop(struct clock_event_device *evt)
430{
431 unsigned int cpu = smp_processor_id();
432 evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
433 if (mct_int_type == MCT_INT_SPI)
434 if (cpu == 0)
435 remove_irq(evt->irq, &mct_tick0_event_irq);
436 else
437 remove_irq(evt->irq, &mct_tick1_event_irq);
438 else
439 disable_percpu_irq(EXYNOS_IRQ_MCT_LOCALTIMER);
440}
441
442static struct local_timer_ops exynos4_mct_tick_ops __cpuinitdata = {
443 .setup = exynos4_local_timer_setup,
444 .stop = exynos4_local_timer_stop,
445};
446#endif /* CONFIG_LOCAL_TIMERS */
447
448static void __init exynos4_timer_resources(void)
449{
450 struct clk *mct_clk;
451 mct_clk = clk_get(NULL, "xtal");
452
453 clk_rate = clk_get_rate(mct_clk);
454
455#ifdef CONFIG_LOCAL_TIMERS
456 if (mct_int_type == MCT_INT_PPI) {
457 int err;
458
459 err = request_percpu_irq(EXYNOS_IRQ_MCT_LOCALTIMER,
460 exynos4_mct_tick_isr, "MCT",
461 &percpu_mct_tick);
462 WARN(err, "MCT: can't request IRQ %d (%d)\n",
463 EXYNOS_IRQ_MCT_LOCALTIMER, err);
464 }
465
466 local_timer_register(&exynos4_mct_tick_ops);
467#endif /* CONFIG_LOCAL_TIMERS */
468}
469
470void __init exynos4_timer_init(void)
471{
472 if (soc_is_exynos5440()) {
473 arch_timer_of_register();
474 return;
475 }
476
477 if ((soc_is_exynos4210()) || (soc_is_exynos5250()))
478 mct_int_type = MCT_INT_SPI;
479 else
480 mct_int_type = MCT_INT_PPI;
481
482 exynos4_timer_resources();
483 exynos4_clocksource_init();
484 exynos4_clockevent_init();
485}