diff options
Diffstat (limited to 'arch/arm/mach-exynos4/mct.c')
-rw-r--r-- | arch/arm/mach-exynos4/mct.c | 165 |
1 files changed, 95 insertions, 70 deletions
diff --git a/arch/arm/mach-exynos4/mct.c b/arch/arm/mach-exynos4/mct.c index 582b874aab0e..f191608b28d6 100644 --- a/arch/arm/mach-exynos4/mct.c +++ b/arch/arm/mach-exynos4/mct.c | |||
@@ -20,19 +20,31 @@ | |||
20 | #include <linux/delay.h> | 20 | #include <linux/delay.h> |
21 | #include <linux/percpu.h> | 21 | #include <linux/percpu.h> |
22 | 22 | ||
23 | #include <asm/hardware/gic.h> | ||
24 | |||
25 | #include <plat/cpu.h> | ||
26 | |||
23 | #include <mach/map.h> | 27 | #include <mach/map.h> |
28 | #include <mach/irqs.h> | ||
24 | #include <mach/regs-mct.h> | 29 | #include <mach/regs-mct.h> |
25 | #include <asm/mach/time.h> | 30 | #include <asm/mach/time.h> |
26 | 31 | ||
32 | enum { | ||
33 | MCT_INT_SPI, | ||
34 | MCT_INT_PPI | ||
35 | }; | ||
36 | |||
27 | static unsigned long clk_cnt_per_tick; | 37 | static unsigned long clk_cnt_per_tick; |
28 | static unsigned long clk_rate; | 38 | static unsigned long clk_rate; |
39 | static unsigned int mct_int_type; | ||
29 | 40 | ||
30 | struct mct_clock_event_device { | 41 | struct mct_clock_event_device { |
31 | struct clock_event_device *evt; | 42 | struct clock_event_device *evt; |
32 | void __iomem *base; | 43 | void __iomem *base; |
44 | char name[10]; | ||
33 | }; | 45 | }; |
34 | 46 | ||
35 | struct mct_clock_event_device mct_tick[2]; | 47 | struct mct_clock_event_device mct_tick[NR_CPUS]; |
36 | 48 | ||
37 | static void exynos4_mct_write(unsigned int value, void *addr) | 49 | static void exynos4_mct_write(unsigned int value, void *addr) |
38 | { | 50 | { |
@@ -42,57 +54,53 @@ static void exynos4_mct_write(unsigned int value, void *addr) | |||
42 | 54 | ||
43 | __raw_writel(value, addr); | 55 | __raw_writel(value, addr); |
44 | 56 | ||
45 | switch ((u32) addr) { | 57 | if (likely(addr >= EXYNOS4_MCT_L_BASE(0))) { |
46 | case (u32) EXYNOS4_MCT_G_TCON: | 58 | u32 base = (u32) addr & EXYNOS4_MCT_L_MASK; |
47 | stat_addr = EXYNOS4_MCT_G_WSTAT; | 59 | switch ((u32) addr & ~EXYNOS4_MCT_L_MASK) { |
48 | mask = 1 << 16; /* G_TCON write status */ | 60 | case (u32) MCT_L_TCON_OFFSET: |
49 | break; | 61 | stat_addr = (void __iomem *) base + MCT_L_WSTAT_OFFSET; |
50 | case (u32) EXYNOS4_MCT_G_COMP0_L: | 62 | mask = 1 << 3; /* L_TCON write status */ |
51 | stat_addr = EXYNOS4_MCT_G_WSTAT; | 63 | break; |
52 | mask = 1 << 0; /* G_COMP0_L write status */ | 64 | case (u32) MCT_L_ICNTB_OFFSET: |
53 | break; | 65 | stat_addr = (void __iomem *) base + MCT_L_WSTAT_OFFSET; |
54 | case (u32) EXYNOS4_MCT_G_COMP0_U: | 66 | mask = 1 << 1; /* L_ICNTB write status */ |
55 | stat_addr = EXYNOS4_MCT_G_WSTAT; | 67 | break; |
56 | mask = 1 << 1; /* G_COMP0_U write status */ | 68 | case (u32) MCT_L_TCNTB_OFFSET: |
57 | break; | 69 | stat_addr = (void __iomem *) base + MCT_L_WSTAT_OFFSET; |
58 | case (u32) EXYNOS4_MCT_G_COMP0_ADD_INCR: | 70 | mask = 1 << 0; /* L_TCNTB write status */ |
59 | stat_addr = EXYNOS4_MCT_G_WSTAT; | 71 | break; |
60 | mask = 1 << 2; /* G_COMP0_ADD_INCR write status */ | 72 | default: |
61 | break; | 73 | return; |
62 | case (u32) EXYNOS4_MCT_G_CNT_L: | 74 | } |
63 | stat_addr = EXYNOS4_MCT_G_CNT_WSTAT; | 75 | } else { |
64 | mask = 1 << 0; /* G_CNT_L write status */ | 76 | switch ((u32) addr) { |
65 | break; | 77 | case (u32) EXYNOS4_MCT_G_TCON: |
66 | case (u32) EXYNOS4_MCT_G_CNT_U: | 78 | stat_addr = EXYNOS4_MCT_G_WSTAT; |
67 | stat_addr = EXYNOS4_MCT_G_CNT_WSTAT; | 79 | mask = 1 << 16; /* G_TCON write status */ |
68 | mask = 1 << 1; /* G_CNT_U write status */ | 80 | break; |
69 | break; | 81 | case (u32) EXYNOS4_MCT_G_COMP0_L: |
70 | case (u32)(EXYNOS4_MCT_L0_BASE + MCT_L_TCON_OFFSET): | 82 | stat_addr = EXYNOS4_MCT_G_WSTAT; |
71 | stat_addr = EXYNOS4_MCT_L0_BASE + MCT_L_WSTAT_OFFSET; | 83 | mask = 1 << 0; /* G_COMP0_L write status */ |
72 | mask = 1 << 3; /* L0_TCON write status */ | 84 | break; |
73 | break; | 85 | case (u32) EXYNOS4_MCT_G_COMP0_U: |
74 | case (u32)(EXYNOS4_MCT_L1_BASE + MCT_L_TCON_OFFSET): | 86 | stat_addr = EXYNOS4_MCT_G_WSTAT; |
75 | stat_addr = EXYNOS4_MCT_L1_BASE + MCT_L_WSTAT_OFFSET; | 87 | mask = 1 << 1; /* G_COMP0_U write status */ |
76 | mask = 1 << 3; /* L1_TCON write status */ | 88 | break; |
77 | break; | 89 | case (u32) EXYNOS4_MCT_G_COMP0_ADD_INCR: |
78 | case (u32)(EXYNOS4_MCT_L0_BASE + MCT_L_TCNTB_OFFSET): | 90 | stat_addr = EXYNOS4_MCT_G_WSTAT; |
79 | stat_addr = EXYNOS4_MCT_L0_BASE + MCT_L_WSTAT_OFFSET; | 91 | mask = 1 << 2; /* G_COMP0_ADD_INCR w status */ |
80 | mask = 1 << 0; /* L0_TCNTB write status */ | 92 | break; |
81 | break; | 93 | case (u32) EXYNOS4_MCT_G_CNT_L: |
82 | case (u32)(EXYNOS4_MCT_L1_BASE + MCT_L_TCNTB_OFFSET): | 94 | stat_addr = EXYNOS4_MCT_G_CNT_WSTAT; |
83 | stat_addr = EXYNOS4_MCT_L1_BASE + MCT_L_WSTAT_OFFSET; | 95 | mask = 1 << 0; /* G_CNT_L write status */ |
84 | mask = 1 << 0; /* L1_TCNTB write status */ | 96 | break; |
85 | break; | 97 | case (u32) EXYNOS4_MCT_G_CNT_U: |
86 | case (u32)(EXYNOS4_MCT_L0_BASE + MCT_L_ICNTB_OFFSET): | 98 | stat_addr = EXYNOS4_MCT_G_CNT_WSTAT; |
87 | stat_addr = EXYNOS4_MCT_L0_BASE + MCT_L_WSTAT_OFFSET; | 99 | mask = 1 << 1; /* G_CNT_U write status */ |
88 | mask = 1 << 1; /* L0_ICNTB write status */ | 100 | break; |
89 | break; | 101 | default: |
90 | case (u32)(EXYNOS4_MCT_L1_BASE + MCT_L_ICNTB_OFFSET): | 102 | return; |
91 | stat_addr = EXYNOS4_MCT_L1_BASE + MCT_L_WSTAT_OFFSET; | 103 | } |
92 | mask = 1 << 1; /* L1_ICNTB write status */ | ||
93 | break; | ||
94 | default: | ||
95 | return; | ||
96 | } | 104 | } |
97 | 105 | ||
98 | /* Wait maximum 1 ms until written values are applied */ | 106 | /* Wait maximum 1 ms until written values are applied */ |
@@ -321,9 +329,8 @@ static inline void exynos4_tick_set_mode(enum clock_event_mode mode, | |||
321 | } | 329 | } |
322 | } | 330 | } |
323 | 331 | ||
324 | static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id) | 332 | static int exynos4_mct_tick_clear(struct mct_clock_event_device *mevt) |
325 | { | 333 | { |
326 | struct mct_clock_event_device *mevt = dev_id; | ||
327 | struct clock_event_device *evt = mevt->evt; | 334 | struct clock_event_device *evt = mevt->evt; |
328 | 335 | ||
329 | /* | 336 | /* |
@@ -335,7 +342,20 @@ static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id) | |||
335 | exynos4_mct_tick_stop(mevt); | 342 | exynos4_mct_tick_stop(mevt); |
336 | 343 | ||
337 | /* Clear the MCT tick interrupt */ | 344 | /* Clear the MCT tick interrupt */ |
338 | exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET); | 345 | if (__raw_readl(mevt->base + MCT_L_INT_CSTAT_OFFSET) & 1) { |
346 | exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET); | ||
347 | return 1; | ||
348 | } else { | ||
349 | return 0; | ||
350 | } | ||
351 | } | ||
352 | |||
353 | static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id) | ||
354 | { | ||
355 | struct mct_clock_event_device *mevt = dev_id; | ||
356 | struct clock_event_device *evt = mevt->evt; | ||
357 | |||
358 | exynos4_mct_tick_clear(mevt); | ||
339 | 359 | ||
340 | evt->event_handler(evt); | 360 | evt->event_handler(evt); |
341 | 361 | ||
@@ -360,14 +380,10 @@ static void exynos4_mct_tick_init(struct clock_event_device *evt) | |||
360 | 380 | ||
361 | mct_tick[cpu].evt = evt; | 381 | mct_tick[cpu].evt = evt; |
362 | 382 | ||
363 | if (cpu == 0) { | 383 | mct_tick[cpu].base = EXYNOS4_MCT_L_BASE(cpu); |
364 | mct_tick[cpu].base = EXYNOS4_MCT_L0_BASE; | 384 | sprintf(mct_tick[cpu].name, "mct_tick%d", cpu); |
365 | evt->name = "mct_tick0"; | ||
366 | } else { | ||
367 | mct_tick[cpu].base = EXYNOS4_MCT_L1_BASE; | ||
368 | evt->name = "mct_tick1"; | ||
369 | } | ||
370 | 385 | ||
386 | evt->name = mct_tick[cpu].name; | ||
371 | evt->cpumask = cpumask_of(cpu); | 387 | evt->cpumask = cpumask_of(cpu); |
372 | evt->set_next_event = exynos4_tick_set_next_event; | 388 | evt->set_next_event = exynos4_tick_set_next_event; |
373 | evt->set_mode = exynos4_tick_set_mode; | 389 | evt->set_mode = exynos4_tick_set_mode; |
@@ -384,15 +400,19 @@ static void exynos4_mct_tick_init(struct clock_event_device *evt) | |||
384 | 400 | ||
385 | exynos4_mct_write(0x1, mct_tick[cpu].base + MCT_L_TCNTB_OFFSET); | 401 | exynos4_mct_write(0x1, mct_tick[cpu].base + MCT_L_TCNTB_OFFSET); |
386 | 402 | ||
387 | if (cpu == 0) { | 403 | if (mct_int_type == MCT_INT_SPI) { |
388 | mct_tick0_event_irq.dev_id = &mct_tick[cpu]; | 404 | if (cpu == 0) { |
389 | evt->irq = IRQ_MCT_L0; | 405 | mct_tick0_event_irq.dev_id = &mct_tick[cpu]; |
390 | setup_irq(IRQ_MCT_L0, &mct_tick0_event_irq); | 406 | evt->irq = IRQ_MCT_L0; |
407 | setup_irq(IRQ_MCT_L0, &mct_tick0_event_irq); | ||
408 | } else { | ||
409 | mct_tick1_event_irq.dev_id = &mct_tick[cpu]; | ||
410 | evt->irq = IRQ_MCT_L1; | ||
411 | setup_irq(IRQ_MCT_L1, &mct_tick1_event_irq); | ||
412 | irq_set_affinity(IRQ_MCT_L1, cpumask_of(1)); | ||
413 | } | ||
391 | } else { | 414 | } else { |
392 | mct_tick1_event_irq.dev_id = &mct_tick[cpu]; | 415 | gic_enable_ppi(IRQ_MCT_LOCALTIMER); |
393 | evt->irq = IRQ_MCT_L1; | ||
394 | setup_irq(IRQ_MCT_L1, &mct_tick1_event_irq); | ||
395 | irq_set_affinity(IRQ_MCT_L1, cpumask_of(1)); | ||
396 | } | 416 | } |
397 | } | 417 | } |
398 | 418 | ||
@@ -422,6 +442,11 @@ static void __init exynos4_timer_resources(void) | |||
422 | 442 | ||
423 | static void __init exynos4_timer_init(void) | 443 | static void __init exynos4_timer_init(void) |
424 | { | 444 | { |
445 | if (soc_is_exynos4210()) | ||
446 | mct_int_type = MCT_INT_SPI; | ||
447 | else | ||
448 | mct_int_type = MCT_INT_PPI; | ||
449 | |||
425 | exynos4_timer_resources(); | 450 | exynos4_timer_resources(); |
426 | exynos4_clocksource_init(); | 451 | exynos4_clocksource_init(); |
427 | exynos4_clockevent_init(); | 452 | exynos4_clockevent_init(); |