diff options
Diffstat (limited to 'arch/arm/mach-integrator/integrator_ap.c')
-rw-r--r-- | arch/arm/mach-integrator/integrator_ap.c | 86 |
1 files changed, 46 insertions, 40 deletions
diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c index 8cdc730dcb3..f2119908a0b 100644 --- a/arch/arm/mach-integrator/integrator_ap.c +++ b/arch/arm/mach-integrator/integrator_ap.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/interrupt.h> | 32 | #include <linux/interrupt.h> |
33 | #include <linux/io.h> | 33 | #include <linux/io.h> |
34 | #include <linux/mtd/physmap.h> | 34 | #include <linux/mtd/physmap.h> |
35 | #include <linux/clk.h> | ||
35 | #include <video/vga.h> | 36 | #include <video/vga.h> |
36 | 37 | ||
37 | #include <mach/hardware.h> | 38 | #include <mach/hardware.h> |
@@ -322,27 +323,16 @@ static void __init ap_init(void) | |||
322 | #define TIMER1_VA_BASE IO_ADDRESS(INTEGRATOR_TIMER1_BASE) | 323 | #define TIMER1_VA_BASE IO_ADDRESS(INTEGRATOR_TIMER1_BASE) |
323 | #define TIMER2_VA_BASE IO_ADDRESS(INTEGRATOR_TIMER2_BASE) | 324 | #define TIMER2_VA_BASE IO_ADDRESS(INTEGRATOR_TIMER2_BASE) |
324 | 325 | ||
325 | /* | ||
326 | * How long is the timer interval? | ||
327 | */ | ||
328 | #define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10) | ||
329 | #if TIMER_INTERVAL >= 0x100000 | ||
330 | #define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC) | ||
331 | #elif TIMER_INTERVAL >= 0x10000 | ||
332 | #define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC) | ||
333 | #else | ||
334 | #define TICKS2USECS(x) ((x) / TICKS_PER_uSEC) | ||
335 | #endif | ||
336 | |||
337 | static unsigned long timer_reload; | 326 | static unsigned long timer_reload; |
338 | 327 | ||
339 | static void integrator_clocksource_init(u32 khz) | 328 | static void integrator_clocksource_init(unsigned long inrate) |
340 | { | 329 | { |
341 | void __iomem *base = (void __iomem *)TIMER2_VA_BASE; | 330 | void __iomem *base = (void __iomem *)TIMER2_VA_BASE; |
342 | u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC; | 331 | u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC; |
332 | unsigned long rate = inrate; | ||
343 | 333 | ||
344 | if (khz >= 1500) { | 334 | if (rate >= 1500000) { |
345 | khz /= 16; | 335 | rate /= 16; |
346 | ctrl |= TIMER_CTRL_DIV16; | 336 | ctrl |= TIMER_CTRL_DIV16; |
347 | } | 337 | } |
348 | 338 | ||
@@ -350,7 +340,7 @@ static void integrator_clocksource_init(u32 khz) | |||
350 | writel(ctrl, base + TIMER_CTRL); | 340 | writel(ctrl, base + TIMER_CTRL); |
351 | 341 | ||
352 | clocksource_mmio_init(base + TIMER_VALUE, "timer2", | 342 | clocksource_mmio_init(base + TIMER_VALUE, "timer2", |
353 | khz * 1000, 200, 16, clocksource_mmio_readl_down); | 343 | rate, 200, 16, clocksource_mmio_readl_down); |
354 | } | 344 | } |
355 | 345 | ||
356 | static void __iomem * const clkevt_base = (void __iomem *)TIMER1_VA_BASE; | 346 | static void __iomem * const clkevt_base = (void __iomem *)TIMER1_VA_BASE; |
@@ -374,15 +364,29 @@ static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_devic | |||
374 | { | 364 | { |
375 | u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE; | 365 | u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE; |
376 | 366 | ||
377 | BUG_ON(mode == CLOCK_EVT_MODE_ONESHOT); | 367 | /* Disable timer */ |
368 | writel(ctrl, clkevt_base + TIMER_CTRL); | ||
378 | 369 | ||
379 | if (mode == CLOCK_EVT_MODE_PERIODIC) { | 370 | switch (mode) { |
380 | writel(ctrl, clkevt_base + TIMER_CTRL); | 371 | case CLOCK_EVT_MODE_PERIODIC: |
372 | /* Enable the timer and start the periodic tick */ | ||
381 | writel(timer_reload, clkevt_base + TIMER_LOAD); | 373 | writel(timer_reload, clkevt_base + TIMER_LOAD); |
382 | ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; | 374 | ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE; |
375 | writel(ctrl, clkevt_base + TIMER_CTRL); | ||
376 | break; | ||
377 | case CLOCK_EVT_MODE_ONESHOT: | ||
378 | /* Leave the timer disabled, .set_next_event will enable it */ | ||
379 | ctrl &= ~TIMER_CTRL_PERIODIC; | ||
380 | writel(ctrl, clkevt_base + TIMER_CTRL); | ||
381 | break; | ||
382 | case CLOCK_EVT_MODE_UNUSED: | ||
383 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
384 | case CLOCK_EVT_MODE_RESUME: | ||
385 | default: | ||
386 | /* Just leave in disabled state */ | ||
387 | break; | ||
383 | } | 388 | } |
384 | 389 | ||
385 | writel(ctrl, clkevt_base + TIMER_CTRL); | ||
386 | } | 390 | } |
387 | 391 | ||
388 | static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt) | 392 | static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt) |
@@ -398,12 +402,10 @@ static int clkevt_set_next_event(unsigned long next, struct clock_event_device * | |||
398 | 402 | ||
399 | static struct clock_event_device integrator_clockevent = { | 403 | static struct clock_event_device integrator_clockevent = { |
400 | .name = "timer1", | 404 | .name = "timer1", |
401 | .shift = 34, | 405 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, |
402 | .features = CLOCK_EVT_FEAT_PERIODIC, | ||
403 | .set_mode = clkevt_set_mode, | 406 | .set_mode = clkevt_set_mode, |
404 | .set_next_event = clkevt_set_next_event, | 407 | .set_next_event = clkevt_set_next_event, |
405 | .rating = 300, | 408 | .rating = 300, |
406 | .cpumask = cpu_all_mask, | ||
407 | }; | 409 | }; |
408 | 410 | ||
409 | static struct irqaction integrator_timer_irq = { | 411 | static struct irqaction integrator_timer_irq = { |
@@ -413,29 +415,27 @@ static struct irqaction integrator_timer_irq = { | |||
413 | .dev_id = &integrator_clockevent, | 415 | .dev_id = &integrator_clockevent, |
414 | }; | 416 | }; |
415 | 417 | ||
416 | static void integrator_clockevent_init(u32 khz) | 418 | static void integrator_clockevent_init(unsigned long inrate) |
417 | { | 419 | { |
418 | struct clock_event_device *evt = &integrator_clockevent; | 420 | unsigned long rate = inrate; |
419 | unsigned int ctrl = 0; | 421 | unsigned int ctrl = 0; |
420 | 422 | ||
421 | if (khz * 1000 > 0x100000 * HZ) { | 423 | /* Calculate and program a divisor */ |
422 | khz /= 256; | 424 | if (rate > 0x100000 * HZ) { |
425 | rate /= 256; | ||
423 | ctrl |= TIMER_CTRL_DIV256; | 426 | ctrl |= TIMER_CTRL_DIV256; |
424 | } else if (khz * 1000 > 0x10000 * HZ) { | 427 | } else if (rate > 0x10000 * HZ) { |
425 | khz /= 16; | 428 | rate /= 16; |
426 | ctrl |= TIMER_CTRL_DIV16; | 429 | ctrl |= TIMER_CTRL_DIV16; |
427 | } | 430 | } |
428 | 431 | timer_reload = rate / HZ; | |
429 | timer_reload = khz * 1000 / HZ; | ||
430 | writel(ctrl, clkevt_base + TIMER_CTRL); | 432 | writel(ctrl, clkevt_base + TIMER_CTRL); |
431 | 433 | ||
432 | evt->irq = IRQ_TIMERINT1; | ||
433 | evt->mult = div_sc(khz, NSEC_PER_MSEC, evt->shift); | ||
434 | evt->max_delta_ns = clockevent_delta2ns(0xffff, evt); | ||
435 | evt->min_delta_ns = clockevent_delta2ns(0xf, evt); | ||
436 | |||
437 | setup_irq(IRQ_TIMERINT1, &integrator_timer_irq); | 434 | setup_irq(IRQ_TIMERINT1, &integrator_timer_irq); |
438 | clockevents_register_device(evt); | 435 | clockevents_config_and_register(&integrator_clockevent, |
436 | rate, | ||
437 | 1, | ||
438 | 0xffffU); | ||
439 | } | 439 | } |
440 | 440 | ||
441 | /* | 441 | /* |
@@ -443,14 +443,20 @@ static void integrator_clockevent_init(u32 khz) | |||
443 | */ | 443 | */ |
444 | static void __init ap_init_timer(void) | 444 | static void __init ap_init_timer(void) |
445 | { | 445 | { |
446 | u32 khz = TICKS_PER_uSEC * 1000; | 446 | struct clk *clk; |
447 | unsigned long rate; | ||
448 | |||
449 | clk = clk_get_sys("ap_timer", NULL); | ||
450 | BUG_ON(IS_ERR(clk)); | ||
451 | clk_enable(clk); | ||
452 | rate = clk_get_rate(clk); | ||
447 | 453 | ||
448 | writel(0, TIMER0_VA_BASE + TIMER_CTRL); | 454 | writel(0, TIMER0_VA_BASE + TIMER_CTRL); |
449 | writel(0, TIMER1_VA_BASE + TIMER_CTRL); | 455 | writel(0, TIMER1_VA_BASE + TIMER_CTRL); |
450 | writel(0, TIMER2_VA_BASE + TIMER_CTRL); | 456 | writel(0, TIMER2_VA_BASE + TIMER_CTRL); |
451 | 457 | ||
452 | integrator_clocksource_init(khz); | 458 | integrator_clocksource_init(rate); |
453 | integrator_clockevent_init(khz); | 459 | integrator_clockevent_init(rate); |
454 | } | 460 | } |
455 | 461 | ||
456 | static struct sys_timer ap_timer = { | 462 | static struct sys_timer ap_timer = { |