diff options
Diffstat (limited to 'arch/arm/mach-clps711x/common.c')
-rw-r--r-- | arch/arm/mach-clps711x/common.c | 89 |
1 files changed, 62 insertions, 27 deletions
diff --git a/arch/arm/mach-clps711x/common.c b/arch/arm/mach-clps711x/common.c index 20ff50f3ccf0..f6d1746366d4 100644 --- a/arch/arm/mach-clps711x/common.c +++ b/arch/arm/mach-clps711x/common.c | |||
@@ -27,12 +27,14 @@ | |||
27 | #include <linux/clk.h> | 27 | #include <linux/clk.h> |
28 | #include <linux/clkdev.h> | 28 | #include <linux/clkdev.h> |
29 | #include <linux/clockchips.h> | 29 | #include <linux/clockchips.h> |
30 | #include <linux/clocksource.h> | ||
30 | #include <linux/clk-provider.h> | 31 | #include <linux/clk-provider.h> |
31 | 32 | ||
32 | #include <asm/exception.h> | 33 | #include <asm/exception.h> |
33 | #include <asm/mach/irq.h> | 34 | #include <asm/mach/irq.h> |
34 | #include <asm/mach/map.h> | 35 | #include <asm/mach/map.h> |
35 | #include <asm/mach/time.h> | 36 | #include <asm/mach/time.h> |
37 | #include <asm/sched_clock.h> | ||
36 | #include <asm/system_misc.h> | 38 | #include <asm/system_misc.h> |
37 | 39 | ||
38 | #include <mach/hardware.h> | 40 | #include <mach/hardware.h> |
@@ -213,7 +215,7 @@ void __init clps711x_init_irq(void) | |||
213 | } | 215 | } |
214 | } | 216 | } |
215 | 217 | ||
216 | inline u32 fls16(u32 x) | 218 | static inline u32 fls16(u32 x) |
217 | { | 219 | { |
218 | u32 r = 15; | 220 | u32 r = 15; |
219 | 221 | ||
@@ -237,27 +239,52 @@ inline u32 fls16(u32 x) | |||
237 | 239 | ||
238 | asmlinkage void __exception_irq_entry clps711x_handle_irq(struct pt_regs *regs) | 240 | asmlinkage void __exception_irq_entry clps711x_handle_irq(struct pt_regs *regs) |
239 | { | 241 | { |
240 | u32 irqstat; | 242 | do { |
241 | void __iomem *base = CLPS711X_VIRT_BASE; | 243 | u32 irqstat; |
242 | 244 | void __iomem *base = CLPS711X_VIRT_BASE; | |
243 | irqstat = readl_relaxed(base + INTSR1) & readl_relaxed(base + INTMR1); | 245 | |
244 | if (irqstat) { | 246 | irqstat = readw_relaxed(base + INTSR1) & |
245 | handle_IRQ(fls16(irqstat), regs); | 247 | readw_relaxed(base + INTMR1); |
246 | return; | 248 | if (irqstat) |
247 | } | 249 | handle_IRQ(fls16(irqstat), regs); |
250 | |||
251 | irqstat = readw_relaxed(base + INTSR2) & | ||
252 | readw_relaxed(base + INTMR2); | ||
253 | if (irqstat) { | ||
254 | handle_IRQ(fls16(irqstat) + 16, regs); | ||
255 | continue; | ||
256 | } | ||
257 | |||
258 | break; | ||
259 | } while (1); | ||
260 | } | ||
248 | 261 | ||
249 | irqstat = readl_relaxed(base + INTSR2) & readl_relaxed(base + INTMR2); | 262 | static u32 notrace clps711x_sched_clock_read(void) |
250 | if (likely(irqstat)) | 263 | { |
251 | handle_IRQ(fls16(irqstat) + 16, regs); | 264 | return ~readw_relaxed(CLPS711X_VIRT_BASE + TC1D); |
252 | } | 265 | } |
253 | 266 | ||
254 | static void clps711x_clockevent_set_mode(enum clock_event_mode mode, | 267 | static void clps711x_clockevent_set_mode(enum clock_event_mode mode, |
255 | struct clock_event_device *evt) | 268 | struct clock_event_device *evt) |
256 | { | 269 | { |
270 | disable_irq(IRQ_TC2OI); | ||
271 | |||
272 | switch (mode) { | ||
273 | case CLOCK_EVT_MODE_PERIODIC: | ||
274 | enable_irq(IRQ_TC2OI); | ||
275 | break; | ||
276 | case CLOCK_EVT_MODE_ONESHOT: | ||
277 | /* Not supported */ | ||
278 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
279 | case CLOCK_EVT_MODE_UNUSED: | ||
280 | case CLOCK_EVT_MODE_RESUME: | ||
281 | /* Left event sources disabled, no more interrupts appear */ | ||
282 | break; | ||
283 | } | ||
257 | } | 284 | } |
258 | 285 | ||
259 | static struct clock_event_device clockevent_clps711x = { | 286 | static struct clock_event_device clockevent_clps711x = { |
260 | .name = "CLPS711x Clockevents", | 287 | .name = "clps711x-clockevent", |
261 | .rating = 300, | 288 | .rating = 300, |
262 | .features = CLOCK_EVT_FEAT_PERIODIC, | 289 | .features = CLOCK_EVT_FEAT_PERIODIC, |
263 | .set_mode = clps711x_clockevent_set_mode, | 290 | .set_mode = clps711x_clockevent_set_mode, |
@@ -271,8 +298,8 @@ static irqreturn_t clps711x_timer_interrupt(int irq, void *dev_id) | |||
271 | } | 298 | } |
272 | 299 | ||
273 | static struct irqaction clps711x_timer_irq = { | 300 | static struct irqaction clps711x_timer_irq = { |
274 | .name = "CLPS711x Timer Tick", | 301 | .name = "clps711x-timer", |
275 | .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL, | 302 | .flags = IRQF_TIMER | IRQF_IRQPOLL, |
276 | .handler = clps711x_timer_interrupt, | 303 | .handler = clps711x_timer_interrupt, |
277 | }; | 304 | }; |
278 | 305 | ||
@@ -301,6 +328,7 @@ void __init clps711x_timer_init(void) | |||
301 | cpu = ext; | 328 | cpu = ext; |
302 | bus = cpu; | 329 | bus = cpu; |
303 | spi = 135400; | 330 | spi = 135400; |
331 | pll = 0; | ||
304 | } else { | 332 | } else { |
305 | cpu = pll; | 333 | cpu = pll; |
306 | if (cpu >= 36864000) | 334 | if (cpu >= 36864000) |
@@ -319,9 +347,9 @@ void __init clps711x_timer_init(void) | |||
319 | else | 347 | else |
320 | timh = 541440; | 348 | timh = 541440; |
321 | } else | 349 | } else |
322 | timh = cpu / 144; | 350 | timh = DIV_ROUND_CLOSEST(cpu, 144); |
323 | 351 | ||
324 | timl = timh / 256; | 352 | timl = DIV_ROUND_CLOSEST(timh, 256); |
325 | 353 | ||
326 | /* All clocks are fixed */ | 354 | /* All clocks are fixed */ |
327 | add_fixed_clk(clk_pll, "pll", pll); | 355 | add_fixed_clk(clk_pll, "pll", pll); |
@@ -334,13 +362,24 @@ void __init clps711x_timer_init(void) | |||
334 | 362 | ||
335 | pr_info("CPU frequency set at %i Hz.\n", cpu); | 363 | pr_info("CPU frequency set at %i Hz.\n", cpu); |
336 | 364 | ||
365 | /* Start Timer1 in free running mode (Low frequency) */ | ||
366 | tmp = clps_readl(SYSCON1) & ~(SYSCON1_TC1S | SYSCON1_TC1M); | ||
367 | clps_writel(tmp, SYSCON1); | ||
368 | |||
369 | setup_sched_clock(clps711x_sched_clock_read, 16, timl); | ||
370 | |||
371 | clocksource_mmio_init(CLPS711X_VIRT_BASE + TC1D, | ||
372 | "clps711x_clocksource", timl, 300, 16, | ||
373 | clocksource_mmio_readw_down); | ||
374 | |||
375 | /* Set Timer2 prescaler */ | ||
337 | clps_writew(DIV_ROUND_CLOSEST(timh, HZ), TC2D); | 376 | clps_writew(DIV_ROUND_CLOSEST(timh, HZ), TC2D); |
338 | 377 | ||
339 | tmp = clps_readl(SYSCON1); | 378 | /* Start Timer2 in prescale mode (High frequency)*/ |
340 | tmp |= SYSCON1_TC2S | SYSCON1_TC2M; | 379 | tmp = clps_readl(SYSCON1) | SYSCON1_TC2M | SYSCON1_TC2S; |
341 | clps_writel(tmp, SYSCON1); | 380 | clps_writel(tmp, SYSCON1); |
342 | 381 | ||
343 | clockevents_config_and_register(&clockevent_clps711x, timh, 1, 0xffff); | 382 | clockevents_config_and_register(&clockevent_clps711x, timh, 0, 0); |
344 | 383 | ||
345 | setup_irq(IRQ_TC2OI, &clps711x_timer_irq); | 384 | setup_irq(IRQ_TC2OI, &clps711x_timer_irq); |
346 | } | 385 | } |
@@ -353,15 +392,11 @@ void clps711x_restart(char mode, const char *cmd) | |||
353 | static void clps711x_idle(void) | 392 | static void clps711x_idle(void) |
354 | { | 393 | { |
355 | clps_writel(1, HALT); | 394 | clps_writel(1, HALT); |
356 | __asm__ __volatile__( | 395 | asm("mov r0, r0"); |
357 | "mov r0, r0\n\ | 396 | asm("mov r0, r0"); |
358 | mov r0, r0"); | ||
359 | } | 397 | } |
360 | 398 | ||
361 | static int __init clps711x_idle_init(void) | 399 | void __init clps711x_init_early(void) |
362 | { | 400 | { |
363 | arm_pm_idle = clps711x_idle; | 401 | arm_pm_idle = clps711x_idle; |
364 | return 0; | ||
365 | } | 402 | } |
366 | |||
367 | arch_initcall(clps711x_idle_init); | ||