aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-exynos4/mct.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-exynos4/mct.c')
-rw-r--r--arch/arm/mach-exynos4/mct.c165
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
32enum {
33 MCT_INT_SPI,
34 MCT_INT_PPI
35};
36
27static unsigned long clk_cnt_per_tick; 37static unsigned long clk_cnt_per_tick;
28static unsigned long clk_rate; 38static unsigned long clk_rate;
39static unsigned int mct_int_type;
29 40
30struct mct_clock_event_device { 41struct 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
35struct mct_clock_event_device mct_tick[2]; 47struct mct_clock_event_device mct_tick[NR_CPUS];
36 48
37static void exynos4_mct_write(unsigned int value, void *addr) 49static 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
324static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id) 332static 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
353static 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
423static void __init exynos4_timer_init(void) 443static 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();