Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
mct.c
Go to the documentation of this file.
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 
23 #include <asm/hardware/gic.h>
24 #include <asm/localtimer.h>
25 
26 #include <plat/cpu.h>
27 
28 #include <mach/map.h>
29 #include <mach/irqs.h>
30 #include <mach/regs-mct.h>
31 #include <asm/mach/time.h>
32 
33 #define TICK_BASE_CNT 1
34 
35 enum {
38 };
39 
40 static unsigned long clk_rate;
41 static unsigned int mct_int_type;
42 
44  struct clock_event_device *evt;
45  void __iomem *base;
46  char name[10];
47 };
48 
49 static void exynos4_mct_write(unsigned int value, void *addr)
50 {
51  void __iomem *stat_addr;
52  u32 mask;
53  u32 i;
54 
55  __raw_writel(value, addr);
56 
57  if (likely(addr >= EXYNOS4_MCT_L_BASE(0))) {
58  u32 base = (u32) addr & EXYNOS4_MCT_L_MASK;
59  switch ((u32) addr & ~EXYNOS4_MCT_L_MASK) {
60  case (u32) MCT_L_TCON_OFFSET:
61  stat_addr = (void __iomem *) base + MCT_L_WSTAT_OFFSET;
62  mask = 1 << 3; /* L_TCON write status */
63  break;
64  case (u32) MCT_L_ICNTB_OFFSET:
65  stat_addr = (void __iomem *) base + MCT_L_WSTAT_OFFSET;
66  mask = 1 << 1; /* L_ICNTB write status */
67  break;
68  case (u32) MCT_L_TCNTB_OFFSET:
69  stat_addr = (void __iomem *) base + MCT_L_WSTAT_OFFSET;
70  mask = 1 << 0; /* L_TCNTB write status */
71  break;
72  default:
73  return;
74  }
75  } else {
76  switch ((u32) addr) {
77  case (u32) EXYNOS4_MCT_G_TCON:
78  stat_addr = EXYNOS4_MCT_G_WSTAT;
79  mask = 1 << 16; /* G_TCON write status */
80  break;
82  stat_addr = EXYNOS4_MCT_G_WSTAT;
83  mask = 1 << 0; /* G_COMP0_L write status */
84  break;
86  stat_addr = EXYNOS4_MCT_G_WSTAT;
87  mask = 1 << 1; /* G_COMP0_U write status */
88  break;
90  stat_addr = EXYNOS4_MCT_G_WSTAT;
91  mask = 1 << 2; /* G_COMP0_ADD_INCR w status */
92  break;
93  case (u32) EXYNOS4_MCT_G_CNT_L:
94  stat_addr = EXYNOS4_MCT_G_CNT_WSTAT;
95  mask = 1 << 0; /* G_CNT_L write status */
96  break;
97  case (u32) EXYNOS4_MCT_G_CNT_U:
98  stat_addr = EXYNOS4_MCT_G_CNT_WSTAT;
99  mask = 1 << 1; /* G_CNT_U write status */
100  break;
101  default:
102  return;
103  }
104  }
105 
106  /* Wait maximum 1 ms until written values are applied */
107  for (i = 0; i < loops_per_jiffy / 1000 * HZ; i++)
108  if (__raw_readl(stat_addr) & mask) {
109  __raw_writel(mask, stat_addr);
110  return;
111  }
112 
113  panic("MCT hangs after writing %d (addr:0x%08x)\n", value, (u32)addr);
114 }
115 
116 /* Clocksource handling */
117 static void exynos4_mct_frc_start(u32 hi, u32 lo)
118 {
119  u32 reg;
120 
121  exynos4_mct_write(lo, EXYNOS4_MCT_G_CNT_L);
122  exynos4_mct_write(hi, EXYNOS4_MCT_G_CNT_U);
123 
125  reg |= MCT_G_TCON_START;
126  exynos4_mct_write(reg, EXYNOS4_MCT_G_TCON);
127 }
128 
129 static cycle_t exynos4_frc_read(struct clocksource *cs)
130 {
131  unsigned int lo, hi;
133 
134  do {
135  hi = hi2;
138  } while (hi != hi2);
139 
140  return ((cycle_t)hi << 32) | lo;
141 }
142 
143 static void exynos4_frc_resume(struct clocksource *cs)
144 {
145  exynos4_mct_frc_start(0, 0);
146 }
147 
149  .name = "mct-frc",
150  .rating = 400,
151  .read = exynos4_frc_read,
152  .mask = CLOCKSOURCE_MASK(64),
154  .resume = exynos4_frc_resume,
155 };
156 
157 static void __init exynos4_clocksource_init(void)
158 {
159  exynos4_mct_frc_start(0, 0);
160 
161  if (clocksource_register_hz(&mct_frc, clk_rate))
162  panic("%s: can't register clocksource\n", mct_frc.name);
163 }
164 
165 static void exynos4_mct_comp0_stop(void)
166 {
167  unsigned int tcon;
168 
171 
172  exynos4_mct_write(tcon, EXYNOS4_MCT_G_TCON);
173  exynos4_mct_write(0, EXYNOS4_MCT_G_INT_ENB);
174 }
175 
176 static void exynos4_mct_comp0_start(enum clock_event_mode mode,
177  unsigned long cycles)
178 {
179  unsigned int tcon;
180  cycle_t comp_cycle;
181 
183 
184  if (mode == CLOCK_EVT_MODE_PERIODIC) {
186  exynos4_mct_write(cycles, EXYNOS4_MCT_G_COMP0_ADD_INCR);
187  }
188 
189  comp_cycle = exynos4_frc_read(&mct_frc) + cycles;
190  exynos4_mct_write((u32)comp_cycle, EXYNOS4_MCT_G_COMP0_L);
191  exynos4_mct_write((u32)(comp_cycle >> 32), EXYNOS4_MCT_G_COMP0_U);
192 
193  exynos4_mct_write(0x1, EXYNOS4_MCT_G_INT_ENB);
194 
195  tcon |= MCT_G_TCON_COMP0_ENABLE;
196  exynos4_mct_write(tcon , EXYNOS4_MCT_G_TCON);
197 }
198 
199 static int exynos4_comp_set_next_event(unsigned long cycles,
200  struct clock_event_device *evt)
201 {
202  exynos4_mct_comp0_start(evt->mode, cycles);
203 
204  return 0;
205 }
206 
207 static void exynos4_comp_set_mode(enum clock_event_mode mode,
208  struct clock_event_device *evt)
209 {
210  unsigned long cycles_per_jiffy;
211  exynos4_mct_comp0_stop();
212 
213  switch (mode) {
214  case CLOCK_EVT_MODE_PERIODIC:
215  cycles_per_jiffy =
216  (((unsigned long long) NSEC_PER_SEC / HZ * evt->mult) >> evt->shift);
217  exynos4_mct_comp0_start(mode, cycles_per_jiffy);
218  break;
219 
220  case CLOCK_EVT_MODE_ONESHOT:
221  case CLOCK_EVT_MODE_UNUSED:
222  case CLOCK_EVT_MODE_SHUTDOWN:
223  case CLOCK_EVT_MODE_RESUME:
224  break;
225  }
226 }
227 
228 static struct clock_event_device mct_comp_device = {
229  .name = "mct-comp",
230  .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
231  .rating = 250,
232  .set_next_event = exynos4_comp_set_next_event,
233  .set_mode = exynos4_comp_set_mode,
234 };
235 
236 static irqreturn_t exynos4_mct_comp_isr(int irq, void *dev_id)
237 {
238  struct clock_event_device *evt = dev_id;
239 
240  exynos4_mct_write(0x1, EXYNOS4_MCT_G_INT_CSTAT);
241 
242  evt->event_handler(evt);
243 
244  return IRQ_HANDLED;
245 }
246 
247 static struct irqaction mct_comp_event_irq = {
248  .name = "mct_comp_irq",
249  .flags = IRQF_TIMER | IRQF_IRQPOLL,
250  .handler = exynos4_mct_comp_isr,
251  .dev_id = &mct_comp_device,
252 };
253 
254 static void exynos4_clockevent_init(void)
255 {
256  clockevents_calc_mult_shift(&mct_comp_device, clk_rate, 5);
257  mct_comp_device.max_delta_ns =
258  clockevent_delta2ns(0xffffffff, &mct_comp_device);
259  mct_comp_device.min_delta_ns =
260  clockevent_delta2ns(0xf, &mct_comp_device);
261  mct_comp_device.cpumask = cpumask_of(0);
262  clockevents_register_device(&mct_comp_device);
263 
264  if (soc_is_exynos5250())
265  setup_irq(EXYNOS5_IRQ_MCT_G0, &mct_comp_event_irq);
266  else
267  setup_irq(EXYNOS4_IRQ_MCT_G0, &mct_comp_event_irq);
268 }
269 
270 #ifdef CONFIG_LOCAL_TIMERS
271 
272 static DEFINE_PER_CPU(struct mct_clock_event_device, percpu_mct_tick);
273 
274 /* Clock event handling */
275 static void exynos4_mct_tick_stop(struct mct_clock_event_device *mevt)
276 {
277  unsigned long tmp;
278  unsigned long mask = MCT_L_TCON_INT_START | MCT_L_TCON_TIMER_START;
279  void __iomem *addr = mevt->base + MCT_L_TCON_OFFSET;
280 
281  tmp = __raw_readl(addr);
282  if (tmp & mask) {
283  tmp &= ~mask;
284  exynos4_mct_write(tmp, addr);
285  }
286 }
287 
288 static void exynos4_mct_tick_start(unsigned long cycles,
289  struct mct_clock_event_device *mevt)
290 {
291  unsigned long tmp;
292 
293  exynos4_mct_tick_stop(mevt);
294 
295  tmp = (1 << 31) | cycles; /* MCT_L_UPDATE_ICNTB */
296 
297  /* update interrupt count buffer */
298  exynos4_mct_write(tmp, mevt->base + MCT_L_ICNTB_OFFSET);
299 
300  /* enable MCT tick interrupt */
301  exynos4_mct_write(0x1, mevt->base + MCT_L_INT_ENB_OFFSET);
302 
303  tmp = __raw_readl(mevt->base + MCT_L_TCON_OFFSET);
306  exynos4_mct_write(tmp, mevt->base + MCT_L_TCON_OFFSET);
307 }
308 
309 static int exynos4_tick_set_next_event(unsigned long cycles,
310  struct clock_event_device *evt)
311 {
312  struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick);
313 
314  exynos4_mct_tick_start(cycles, mevt);
315 
316  return 0;
317 }
318 
319 static inline void exynos4_tick_set_mode(enum clock_event_mode mode,
320  struct clock_event_device *evt)
321 {
322  struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick);
323  unsigned long cycles_per_jiffy;
324 
325  exynos4_mct_tick_stop(mevt);
326 
327  switch (mode) {
328  case CLOCK_EVT_MODE_PERIODIC:
329  cycles_per_jiffy =
330  (((unsigned long long) NSEC_PER_SEC / HZ * evt->mult) >> evt->shift);
331  exynos4_mct_tick_start(cycles_per_jiffy, mevt);
332  break;
333 
334  case CLOCK_EVT_MODE_ONESHOT:
335  case CLOCK_EVT_MODE_UNUSED:
336  case CLOCK_EVT_MODE_SHUTDOWN:
337  case CLOCK_EVT_MODE_RESUME:
338  break;
339  }
340 }
341 
342 static int exynos4_mct_tick_clear(struct mct_clock_event_device *mevt)
343 {
344  struct clock_event_device *evt = mevt->evt;
345 
346  /*
347  * This is for supporting oneshot mode.
348  * Mct would generate interrupt periodically
349  * without explicit stopping.
350  */
351  if (evt->mode != CLOCK_EVT_MODE_PERIODIC)
352  exynos4_mct_tick_stop(mevt);
353 
354  /* Clear the MCT tick interrupt */
355  if (__raw_readl(mevt->base + MCT_L_INT_CSTAT_OFFSET) & 1) {
356  exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET);
357  return 1;
358  } else {
359  return 0;
360  }
361 }
362 
363 static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id)
364 {
365  struct mct_clock_event_device *mevt = dev_id;
366  struct clock_event_device *evt = mevt->evt;
367 
368  exynos4_mct_tick_clear(mevt);
369 
370  evt->event_handler(evt);
371 
372  return IRQ_HANDLED;
373 }
374 
375 static struct irqaction mct_tick0_event_irq = {
376  .name = "mct_tick0_irq",
377  .flags = IRQF_TIMER | IRQF_NOBALANCING,
378  .handler = exynos4_mct_tick_isr,
379 };
380 
381 static struct irqaction mct_tick1_event_irq = {
382  .name = "mct_tick1_irq",
383  .flags = IRQF_TIMER | IRQF_NOBALANCING,
384  .handler = exynos4_mct_tick_isr,
385 };
386 
387 static int __cpuinit exynos4_local_timer_setup(struct clock_event_device *evt)
388 {
389  struct mct_clock_event_device *mevt;
390  unsigned int cpu = smp_processor_id();
391  int mct_lx_irq;
392 
393  mevt = this_cpu_ptr(&percpu_mct_tick);
394  mevt->evt = evt;
395 
396  mevt->base = EXYNOS4_MCT_L_BASE(cpu);
397  sprintf(mevt->name, "mct_tick%d", cpu);
398 
399  evt->name = mevt->name;
400  evt->cpumask = cpumask_of(cpu);
401  evt->set_next_event = exynos4_tick_set_next_event;
402  evt->set_mode = exynos4_tick_set_mode;
403  evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
404  evt->rating = 450;
405 
406  clockevents_calc_mult_shift(evt, clk_rate / (TICK_BASE_CNT + 1), 5);
407  evt->max_delta_ns =
408  clockevent_delta2ns(0x7fffffff, evt);
409  evt->min_delta_ns =
410  clockevent_delta2ns(0xf, evt);
411 
413 
414  exynos4_mct_write(TICK_BASE_CNT, mevt->base + MCT_L_TCNTB_OFFSET);
415 
416  if (mct_int_type == MCT_INT_SPI) {
417  if (cpu == 0) {
418  mct_lx_irq = soc_is_exynos4210() ? EXYNOS4_IRQ_MCT_L0 :
420  mct_tick0_event_irq.dev_id = mevt;
421  evt->irq = mct_lx_irq;
422  setup_irq(mct_lx_irq, &mct_tick0_event_irq);
423  } else {
424  mct_lx_irq = soc_is_exynos4210() ? EXYNOS4_IRQ_MCT_L1 :
426  mct_tick1_event_irq.dev_id = mevt;
427  evt->irq = mct_lx_irq;
428  setup_irq(mct_lx_irq, &mct_tick1_event_irq);
429  irq_set_affinity(mct_lx_irq, cpumask_of(1));
430  }
431  } else {
433  }
434 
435  return 0;
436 }
437 
438 static void exynos4_local_timer_stop(struct clock_event_device *evt)
439 {
440  unsigned int cpu = smp_processor_id();
441  evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
442  if (mct_int_type == MCT_INT_SPI)
443  if (cpu == 0)
444  remove_irq(evt->irq, &mct_tick0_event_irq);
445  else
446  remove_irq(evt->irq, &mct_tick1_event_irq);
447  else
449 }
450 
451 static struct local_timer_ops exynos4_mct_tick_ops __cpuinitdata = {
452  .setup = exynos4_local_timer_setup,
453  .stop = exynos4_local_timer_stop,
454 };
455 #endif /* CONFIG_LOCAL_TIMERS */
456 
457 static void __init exynos4_timer_resources(void)
458 {
459  struct clk *mct_clk;
460  mct_clk = clk_get(NULL, "xtal");
461 
462  clk_rate = clk_get_rate(mct_clk);
463 
464 #ifdef CONFIG_LOCAL_TIMERS
465  if (mct_int_type == MCT_INT_PPI) {
466  int err;
467 
469  exynos4_mct_tick_isr, "MCT",
470  &percpu_mct_tick);
471  WARN(err, "MCT: can't request IRQ %d (%d)\n",
473  }
474 
475  local_timer_register(&exynos4_mct_tick_ops);
476 #endif /* CONFIG_LOCAL_TIMERS */
477 }
478 
479 static void __init exynos4_timer_init(void)
480 {
481  if ((soc_is_exynos4210()) || (soc_is_exynos5250()))
482  mct_int_type = MCT_INT_SPI;
483  else
484  mct_int_type = MCT_INT_PPI;
485 
486  exynos4_timer_resources();
487  exynos4_clocksource_init();
488  exynos4_clockevent_init();
489 }
490 
492  .init = exynos4_timer_init,
493 };