Blame view

arch/arm/mach-exynos/mct.c 11.5 KB
30d8bead5   Changhwan Youn   ARM: EXYNOS4: Imp...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  /* linux/arch/arm/mach-exynos4/mct.c
   *
   * Copyright (c) 2011 Samsung Electronics Co., Ltd.
   *		http://www.samsung.com
   *
   * EXYNOS4 MCT(Multi-Core Timer) support
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
  */
  
  #include <linux/sched.h>
  #include <linux/interrupt.h>
  #include <linux/irq.h>
  #include <linux/err.h>
  #include <linux/clk.h>
  #include <linux/clockchips.h>
  #include <linux/platform_device.h>
  #include <linux/delay.h>
  #include <linux/percpu.h>
3a0622811   Changhwan Youn   ARM: EXYNOS4: Add...
22
23
24
  #include <asm/hardware/gic.h>
  
  #include <plat/cpu.h>
30d8bead5   Changhwan Youn   ARM: EXYNOS4: Imp...
25
  #include <mach/map.h>
3a0622811   Changhwan Youn   ARM: EXYNOS4: Add...
26
  #include <mach/irqs.h>
30d8bead5   Changhwan Youn   ARM: EXYNOS4: Imp...
27
28
  #include <mach/regs-mct.h>
  #include <asm/mach/time.h>
3a0622811   Changhwan Youn   ARM: EXYNOS4: Add...
29
30
31
32
  enum {
  	MCT_INT_SPI,
  	MCT_INT_PPI
  };
30d8bead5   Changhwan Youn   ARM: EXYNOS4: Imp...
33
34
  static unsigned long clk_cnt_per_tick;
  static unsigned long clk_rate;
3a0622811   Changhwan Youn   ARM: EXYNOS4: Add...
35
  static unsigned int mct_int_type;
30d8bead5   Changhwan Youn   ARM: EXYNOS4: Imp...
36
37
38
39
  
  struct mct_clock_event_device {
  	struct clock_event_device *evt;
  	void __iomem *base;
c8987470a   Changhwan Youn   ARM: EXYNOS4: Add...
40
  	char name[10];
30d8bead5   Changhwan Youn   ARM: EXYNOS4: Imp...
41
  };
30d8bead5   Changhwan Youn   ARM: EXYNOS4: Imp...
42
43
44
45
46
47
48
  static void exynos4_mct_write(unsigned int value, void *addr)
  {
  	void __iomem *stat_addr;
  	u32 mask;
  	u32 i;
  
  	__raw_writel(value, addr);
c8987470a   Changhwan Youn   ARM: EXYNOS4: Add...
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
  	if (likely(addr >= EXYNOS4_MCT_L_BASE(0))) {
  		u32 base = (u32) addr & EXYNOS4_MCT_L_MASK;
  		switch ((u32) addr & ~EXYNOS4_MCT_L_MASK) {
  		case (u32) MCT_L_TCON_OFFSET:
  			stat_addr = (void __iomem *) base + MCT_L_WSTAT_OFFSET;
  			mask = 1 << 3;		/* L_TCON write status */
  			break;
  		case (u32) MCT_L_ICNTB_OFFSET:
  			stat_addr = (void __iomem *) base + MCT_L_WSTAT_OFFSET;
  			mask = 1 << 1;		/* L_ICNTB write status */
  			break;
  		case (u32) MCT_L_TCNTB_OFFSET:
  			stat_addr = (void __iomem *) base + MCT_L_WSTAT_OFFSET;
  			mask = 1 << 0;		/* L_TCNTB write status */
  			break;
  		default:
  			return;
  		}
  	} else {
  		switch ((u32) addr) {
  		case (u32) EXYNOS4_MCT_G_TCON:
  			stat_addr = EXYNOS4_MCT_G_WSTAT;
  			mask = 1 << 16;		/* G_TCON write status */
  			break;
  		case (u32) EXYNOS4_MCT_G_COMP0_L:
  			stat_addr = EXYNOS4_MCT_G_WSTAT;
  			mask = 1 << 0;		/* G_COMP0_L write status */
  			break;
  		case (u32) EXYNOS4_MCT_G_COMP0_U:
  			stat_addr = EXYNOS4_MCT_G_WSTAT;
  			mask = 1 << 1;		/* G_COMP0_U write status */
  			break;
  		case (u32) EXYNOS4_MCT_G_COMP0_ADD_INCR:
  			stat_addr = EXYNOS4_MCT_G_WSTAT;
  			mask = 1 << 2;		/* G_COMP0_ADD_INCR w status */
  			break;
  		case (u32) EXYNOS4_MCT_G_CNT_L:
  			stat_addr = EXYNOS4_MCT_G_CNT_WSTAT;
  			mask = 1 << 0;		/* G_CNT_L write status */
  			break;
  		case (u32) EXYNOS4_MCT_G_CNT_U:
  			stat_addr = EXYNOS4_MCT_G_CNT_WSTAT;
  			mask = 1 << 1;		/* G_CNT_U write status */
  			break;
  		default:
  			return;
  		}
30d8bead5   Changhwan Youn   ARM: EXYNOS4: Imp...
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
  	}
  
  	/* Wait maximum 1 ms until written values are applied */
  	for (i = 0; i < loops_per_jiffy / 1000 * HZ; i++)
  		if (__raw_readl(stat_addr) & mask) {
  			__raw_writel(mask, stat_addr);
  			return;
  		}
  
  	panic("MCT hangs after writing %d (addr:0x%08x)
  ", value, (u32)addr);
  }
  
  /* Clocksource handling */
  static void exynos4_mct_frc_start(u32 hi, u32 lo)
  {
  	u32 reg;
  
  	exynos4_mct_write(lo, EXYNOS4_MCT_G_CNT_L);
  	exynos4_mct_write(hi, EXYNOS4_MCT_G_CNT_U);
  
  	reg = __raw_readl(EXYNOS4_MCT_G_TCON);
  	reg |= MCT_G_TCON_START;
  	exynos4_mct_write(reg, EXYNOS4_MCT_G_TCON);
  }
  
  static cycle_t exynos4_frc_read(struct clocksource *cs)
  {
  	unsigned int lo, hi;
  	u32 hi2 = __raw_readl(EXYNOS4_MCT_G_CNT_U);
  
  	do {
  		hi = hi2;
  		lo = __raw_readl(EXYNOS4_MCT_G_CNT_L);
  		hi2 = __raw_readl(EXYNOS4_MCT_G_CNT_U);
  	} while (hi != hi2);
  
  	return ((cycle_t)hi << 32) | lo;
  }
aa421c13a   Changhwan Youn   ARM: EXYNOS4: res...
135
136
137
138
  static void exynos4_frc_resume(struct clocksource *cs)
  {
  	exynos4_mct_frc_start(0, 0);
  }
30d8bead5   Changhwan Youn   ARM: EXYNOS4: Imp...
139
140
141
142
143
144
  struct clocksource mct_frc = {
  	.name		= "mct-frc",
  	.rating		= 400,
  	.read		= exynos4_frc_read,
  	.mask		= CLOCKSOURCE_MASK(64),
  	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
aa421c13a   Changhwan Youn   ARM: EXYNOS4: res...
145
  	.resume		= exynos4_frc_resume,
30d8bead5   Changhwan Youn   ARM: EXYNOS4: Imp...
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
  };
  
  static void __init exynos4_clocksource_init(void)
  {
  	exynos4_mct_frc_start(0, 0);
  
  	if (clocksource_register_hz(&mct_frc, clk_rate))
  		panic("%s: can't register clocksource
  ", mct_frc.name);
  }
  
  static void exynos4_mct_comp0_stop(void)
  {
  	unsigned int tcon;
  
  	tcon = __raw_readl(EXYNOS4_MCT_G_TCON);
  	tcon &= ~(MCT_G_TCON_COMP0_ENABLE | MCT_G_TCON_COMP0_AUTO_INC);
  
  	exynos4_mct_write(tcon, EXYNOS4_MCT_G_TCON);
  	exynos4_mct_write(0, EXYNOS4_MCT_G_INT_ENB);
  }
  
  static void exynos4_mct_comp0_start(enum clock_event_mode mode,
  				    unsigned long cycles)
  {
  	unsigned int tcon;
  	cycle_t comp_cycle;
  
  	tcon = __raw_readl(EXYNOS4_MCT_G_TCON);
  
  	if (mode == CLOCK_EVT_MODE_PERIODIC) {
  		tcon |= MCT_G_TCON_COMP0_AUTO_INC;
  		exynos4_mct_write(cycles, EXYNOS4_MCT_G_COMP0_ADD_INCR);
  	}
  
  	comp_cycle = exynos4_frc_read(&mct_frc) + cycles;
  	exynos4_mct_write((u32)comp_cycle, EXYNOS4_MCT_G_COMP0_L);
  	exynos4_mct_write((u32)(comp_cycle >> 32), EXYNOS4_MCT_G_COMP0_U);
  
  	exynos4_mct_write(0x1, EXYNOS4_MCT_G_INT_ENB);
  
  	tcon |= MCT_G_TCON_COMP0_ENABLE;
  	exynos4_mct_write(tcon , EXYNOS4_MCT_G_TCON);
  }
  
  static int exynos4_comp_set_next_event(unsigned long cycles,
  				       struct clock_event_device *evt)
  {
  	exynos4_mct_comp0_start(evt->mode, cycles);
  
  	return 0;
  }
  
  static void exynos4_comp_set_mode(enum clock_event_mode mode,
  				  struct clock_event_device *evt)
  {
  	exynos4_mct_comp0_stop();
  
  	switch (mode) {
  	case CLOCK_EVT_MODE_PERIODIC:
  		exynos4_mct_comp0_start(mode, clk_cnt_per_tick);
  		break;
  
  	case CLOCK_EVT_MODE_ONESHOT:
  	case CLOCK_EVT_MODE_UNUSED:
  	case CLOCK_EVT_MODE_SHUTDOWN:
  	case CLOCK_EVT_MODE_RESUME:
  		break;
  	}
  }
  
  static struct clock_event_device mct_comp_device = {
  	.name		= "mct-comp",
  	.features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
  	.rating		= 250,
  	.set_next_event	= exynos4_comp_set_next_event,
  	.set_mode	= exynos4_comp_set_mode,
  };
  
  static irqreturn_t exynos4_mct_comp_isr(int irq, void *dev_id)
  {
  	struct clock_event_device *evt = dev_id;
  
  	exynos4_mct_write(0x1, EXYNOS4_MCT_G_INT_CSTAT);
  
  	evt->event_handler(evt);
  
  	return IRQ_HANDLED;
  }
  
  static struct irqaction mct_comp_event_irq = {
  	.name		= "mct_comp_irq",
  	.flags		= IRQF_TIMER | IRQF_IRQPOLL,
  	.handler	= exynos4_mct_comp_isr,
  	.dev_id		= &mct_comp_device,
  };
  
  static void exynos4_clockevent_init(void)
  {
  	clk_cnt_per_tick = clk_rate / 2	/ HZ;
  
  	clockevents_calc_mult_shift(&mct_comp_device, clk_rate / 2, 5);
  	mct_comp_device.max_delta_ns =
  		clockevent_delta2ns(0xffffffff, &mct_comp_device);
  	mct_comp_device.min_delta_ns =
  		clockevent_delta2ns(0xf, &mct_comp_device);
  	mct_comp_device.cpumask = cpumask_of(0);
  	clockevents_register_device(&mct_comp_device);
  
  	setup_irq(IRQ_MCT_G0, &mct_comp_event_irq);
  }
  
  #ifdef CONFIG_LOCAL_TIMERS
991a6c7d9   Kukjin Kim   ARM: EXYNOS: Fix ...
259
260
  
  static DEFINE_PER_CPU(struct mct_clock_event_device, percpu_mct_tick);
30d8bead5   Changhwan Youn   ARM: EXYNOS4: Imp...
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
  /* Clock event handling */
  static void exynos4_mct_tick_stop(struct mct_clock_event_device *mevt)
  {
  	unsigned long tmp;
  	unsigned long mask = MCT_L_TCON_INT_START | MCT_L_TCON_TIMER_START;
  	void __iomem *addr = mevt->base + MCT_L_TCON_OFFSET;
  
  	tmp = __raw_readl(addr);
  	if (tmp & mask) {
  		tmp &= ~mask;
  		exynos4_mct_write(tmp, addr);
  	}
  }
  
  static void exynos4_mct_tick_start(unsigned long cycles,
  				   struct mct_clock_event_device *mevt)
  {
  	unsigned long tmp;
  
  	exynos4_mct_tick_stop(mevt);
  
  	tmp = (1 << 31) | cycles;	/* MCT_L_UPDATE_ICNTB */
  
  	/* update interrupt count buffer */
  	exynos4_mct_write(tmp, mevt->base + MCT_L_ICNTB_OFFSET);
25985edce   Lucas De Marchi   Fix common misspe...
286
  	/* enable MCT tick interrupt */
30d8bead5   Changhwan Youn   ARM: EXYNOS4: Imp...
287
288
289
290
291
292
293
294
295
296
297
  	exynos4_mct_write(0x1, mevt->base + MCT_L_INT_ENB_OFFSET);
  
  	tmp = __raw_readl(mevt->base + MCT_L_TCON_OFFSET);
  	tmp |= MCT_L_TCON_INT_START | MCT_L_TCON_TIMER_START |
  	       MCT_L_TCON_INTERVAL_MODE;
  	exynos4_mct_write(tmp, mevt->base + MCT_L_TCON_OFFSET);
  }
  
  static int exynos4_tick_set_next_event(unsigned long cycles,
  				       struct clock_event_device *evt)
  {
e700e41d9   Marc Zyngier   ARM: EXYNOS4: con...
298
  	struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick);
30d8bead5   Changhwan Youn   ARM: EXYNOS4: Imp...
299
300
301
302
303
304
305
306
307
  
  	exynos4_mct_tick_start(cycles, mevt);
  
  	return 0;
  }
  
  static inline void exynos4_tick_set_mode(enum clock_event_mode mode,
  					 struct clock_event_device *evt)
  {
e700e41d9   Marc Zyngier   ARM: EXYNOS4: con...
308
  	struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick);
30d8bead5   Changhwan Youn   ARM: EXYNOS4: Imp...
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
  
  	exynos4_mct_tick_stop(mevt);
  
  	switch (mode) {
  	case CLOCK_EVT_MODE_PERIODIC:
  		exynos4_mct_tick_start(clk_cnt_per_tick, mevt);
  		break;
  
  	case CLOCK_EVT_MODE_ONESHOT:
  	case CLOCK_EVT_MODE_UNUSED:
  	case CLOCK_EVT_MODE_SHUTDOWN:
  	case CLOCK_EVT_MODE_RESUME:
  		break;
  	}
  }
c8987470a   Changhwan Youn   ARM: EXYNOS4: Add...
324
  static int exynos4_mct_tick_clear(struct mct_clock_event_device *mevt)
30d8bead5   Changhwan Youn   ARM: EXYNOS4: Imp...
325
  {
30d8bead5   Changhwan Youn   ARM: EXYNOS4: Imp...
326
327
328
329
330
331
332
333
334
335
336
  	struct clock_event_device *evt = mevt->evt;
  
  	/*
  	 * This is for supporting oneshot mode.
  	 * Mct would generate interrupt periodically
  	 * without explicit stopping.
  	 */
  	if (evt->mode != CLOCK_EVT_MODE_PERIODIC)
  		exynos4_mct_tick_stop(mevt);
  
  	/* Clear the MCT tick interrupt */
3a0622811   Changhwan Youn   ARM: EXYNOS4: Add...
337
338
339
340
341
342
343
344
345
346
347
348
349
350
  	if (__raw_readl(mevt->base + MCT_L_INT_CSTAT_OFFSET) & 1) {
  		exynos4_mct_write(0x1, mevt->base + MCT_L_INT_CSTAT_OFFSET);
  		return 1;
  	} else {
  		return 0;
  	}
  }
  
  static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id)
  {
  	struct mct_clock_event_device *mevt = dev_id;
  	struct clock_event_device *evt = mevt->evt;
  
  	exynos4_mct_tick_clear(mevt);
30d8bead5   Changhwan Youn   ARM: EXYNOS4: Imp...
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
  
  	evt->event_handler(evt);
  
  	return IRQ_HANDLED;
  }
  
  static struct irqaction mct_tick0_event_irq = {
  	.name		= "mct_tick0_irq",
  	.flags		= IRQF_TIMER | IRQF_NOBALANCING,
  	.handler	= exynos4_mct_tick_isr,
  };
  
  static struct irqaction mct_tick1_event_irq = {
  	.name		= "mct_tick1_irq",
  	.flags		= IRQF_TIMER | IRQF_NOBALANCING,
  	.handler	= exynos4_mct_tick_isr,
  };
  
  static void exynos4_mct_tick_init(struct clock_event_device *evt)
  {
e700e41d9   Marc Zyngier   ARM: EXYNOS4: con...
371
  	struct mct_clock_event_device *mevt;
30d8bead5   Changhwan Youn   ARM: EXYNOS4: Imp...
372
  	unsigned int cpu = smp_processor_id();
e700e41d9   Marc Zyngier   ARM: EXYNOS4: con...
373
374
  	mevt = this_cpu_ptr(&percpu_mct_tick);
  	mevt->evt = evt;
30d8bead5   Changhwan Youn   ARM: EXYNOS4: Imp...
375

e700e41d9   Marc Zyngier   ARM: EXYNOS4: con...
376
377
  	mevt->base = EXYNOS4_MCT_L_BASE(cpu);
  	sprintf(mevt->name, "mct_tick%d", cpu);
30d8bead5   Changhwan Youn   ARM: EXYNOS4: Imp...
378

e700e41d9   Marc Zyngier   ARM: EXYNOS4: con...
379
  	evt->name = mevt->name;
30d8bead5   Changhwan Youn   ARM: EXYNOS4: Imp...
380
381
382
383
384
385
386
387
388
389
390
391
392
  	evt->cpumask = cpumask_of(cpu);
  	evt->set_next_event = exynos4_tick_set_next_event;
  	evt->set_mode = exynos4_tick_set_mode;
  	evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
  	evt->rating = 450;
  
  	clockevents_calc_mult_shift(evt, clk_rate / 2, 5);
  	evt->max_delta_ns =
  		clockevent_delta2ns(0x7fffffff, evt);
  	evt->min_delta_ns =
  		clockevent_delta2ns(0xf, evt);
  
  	clockevents_register_device(evt);
e700e41d9   Marc Zyngier   ARM: EXYNOS4: con...
393
  	exynos4_mct_write(0x1, mevt->base + MCT_L_TCNTB_OFFSET);
30d8bead5   Changhwan Youn   ARM: EXYNOS4: Imp...
394

3a0622811   Changhwan Youn   ARM: EXYNOS4: Add...
395
396
  	if (mct_int_type == MCT_INT_SPI) {
  		if (cpu == 0) {
e700e41d9   Marc Zyngier   ARM: EXYNOS4: con...
397
  			mct_tick0_event_irq.dev_id = mevt;
a7fadac10   Arnd Bergmann   Merge branch 'dep...
398
  			evt->irq = IRQ_MCT_L0;
3a0622811   Changhwan Youn   ARM: EXYNOS4: Add...
399
400
  			setup_irq(IRQ_MCT_L0, &mct_tick0_event_irq);
  		} else {
e700e41d9   Marc Zyngier   ARM: EXYNOS4: con...
401
  			mct_tick1_event_irq.dev_id = mevt;
a7fadac10   Arnd Bergmann   Merge branch 'dep...
402
  			evt->irq = IRQ_MCT_L1;
3a0622811   Changhwan Youn   ARM: EXYNOS4: Add...
403
404
405
  			setup_irq(IRQ_MCT_L1, &mct_tick1_event_irq);
  			irq_set_affinity(IRQ_MCT_L1, cpumask_of(1));
  		}
30d8bead5   Changhwan Youn   ARM: EXYNOS4: Imp...
406
  	} else {
e700e41d9   Marc Zyngier   ARM: EXYNOS4: con...
407
  		enable_percpu_irq(IRQ_MCT_LOCALTIMER, 0);
30d8bead5   Changhwan Youn   ARM: EXYNOS4: Imp...
408
409
410
411
  	}
  }
  
  /* Setup the local clock events for a CPU */
4d487d7ed   Kukjin Kim   ARM: EXYNOS4: Fix...
412
  int __cpuinit local_timer_setup(struct clock_event_device *evt)
30d8bead5   Changhwan Youn   ARM: EXYNOS4: Imp...
413
414
  {
  	exynos4_mct_tick_init(evt);
4d487d7ed   Kukjin Kim   ARM: EXYNOS4: Fix...
415
416
  
  	return 0;
30d8bead5   Changhwan Youn   ARM: EXYNOS4: Imp...
417
  }
28af690a2   Marc Zyngier   ARM: gic, local t...
418
  void local_timer_stop(struct clock_event_device *evt)
30d8bead5   Changhwan Youn   ARM: EXYNOS4: Imp...
419
  {
e248cd5d5   Amit Daniel Kachhap   ARM: EXYNOS: Fix ...
420
  	unsigned int cpu = smp_processor_id();
28af690a2   Marc Zyngier   ARM: gic, local t...
421
  	evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt);
e700e41d9   Marc Zyngier   ARM: EXYNOS4: con...
422
  	if (mct_int_type == MCT_INT_SPI)
e248cd5d5   Amit Daniel Kachhap   ARM: EXYNOS: Fix ...
423
424
425
426
  		if (cpu == 0)
  			remove_irq(evt->irq, &mct_tick0_event_irq);
  		else
  			remove_irq(evt->irq, &mct_tick1_event_irq);
e700e41d9   Marc Zyngier   ARM: EXYNOS4: con...
427
428
  	else
  		disable_percpu_irq(IRQ_MCT_LOCALTIMER);
30d8bead5   Changhwan Youn   ARM: EXYNOS4: Imp...
429
  }
30d8bead5   Changhwan Youn   ARM: EXYNOS4: Imp...
430
431
432
433
434
435
436
437
  #endif /* CONFIG_LOCAL_TIMERS */
  
  static void __init exynos4_timer_resources(void)
  {
  	struct clk *mct_clk;
  	mct_clk = clk_get(NULL, "xtal");
  
  	clk_rate = clk_get_rate(mct_clk);
e700e41d9   Marc Zyngier   ARM: EXYNOS4: con...
438

991a6c7d9   Kukjin Kim   ARM: EXYNOS: Fix ...
439
  #ifdef CONFIG_LOCAL_TIMERS
e700e41d9   Marc Zyngier   ARM: EXYNOS4: con...
440
441
442
443
444
445
446
447
448
449
  	if (mct_int_type == MCT_INT_PPI) {
  		int err;
  
  		err = request_percpu_irq(IRQ_MCT_LOCALTIMER,
  					 exynos4_mct_tick_isr, "MCT",
  					 &percpu_mct_tick);
  		WARN(err, "MCT: can't request IRQ %d (%d)
  ",
  		     IRQ_MCT_LOCALTIMER, err);
  	}
991a6c7d9   Kukjin Kim   ARM: EXYNOS: Fix ...
450
  #endif /* CONFIG_LOCAL_TIMERS */
30d8bead5   Changhwan Youn   ARM: EXYNOS4: Imp...
451
452
453
454
  }
  
  static void __init exynos4_timer_init(void)
  {
3a0622811   Changhwan Youn   ARM: EXYNOS4: Add...
455
456
457
458
  	if (soc_is_exynos4210())
  		mct_int_type = MCT_INT_SPI;
  	else
  		mct_int_type = MCT_INT_PPI;
30d8bead5   Changhwan Youn   ARM: EXYNOS4: Imp...
459
460
461
462
463
464
465
466
  	exynos4_timer_resources();
  	exynos4_clocksource_init();
  	exynos4_clockevent_init();
  }
  
  struct sys_timer exynos4_timer = {
  	.init		= exynos4_timer_init,
  };