diff options
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/mach-realview/core.c | 78 |
2 files changed, 67 insertions, 12 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index a2b7e4a52f73..b82828e768ad 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -169,6 +169,7 @@ config ARCH_REALVIEW | |||
169 | select ARM_AMBA | 169 | select ARM_AMBA |
170 | select ICST307 | 170 | select ICST307 |
171 | select GENERIC_TIME | 171 | select GENERIC_TIME |
172 | select GENERIC_CLOCKEVENTS | ||
172 | help | 173 | help |
173 | This enables support for ARM Ltd RealView boards. | 174 | This enables support for ARM Ltd RealView boards. |
174 | 175 | ||
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c index f805840f6f44..6c68deed84dc 100644 --- a/arch/arm/mach-realview/core.c +++ b/arch/arm/mach-realview/core.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/amba/bus.h> | 26 | #include <linux/amba/bus.h> |
27 | #include <linux/amba/clcd.h> | 27 | #include <linux/amba/clcd.h> |
28 | #include <linux/clocksource.h> | 28 | #include <linux/clocksource.h> |
29 | #include <linux/clockchips.h> | ||
29 | 30 | ||
30 | #include <asm/system.h> | 31 | #include <asm/system.h> |
31 | #include <asm/hardware.h> | 32 | #include <asm/hardware.h> |
@@ -485,20 +486,77 @@ void realview_leds_event(led_event_t ledevt) | |||
485 | #define TICKS2USECS(x) ((x) / TICKS_PER_uSEC) | 486 | #define TICKS2USECS(x) ((x) / TICKS_PER_uSEC) |
486 | #endif | 487 | #endif |
487 | 488 | ||
489 | static void timer_set_mode(enum clock_event_mode mode, | ||
490 | struct clock_event_device *clk) | ||
491 | { | ||
492 | unsigned long ctrl; | ||
493 | |||
494 | switch(mode) { | ||
495 | case CLOCK_EVT_MODE_PERIODIC: | ||
496 | writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD); | ||
497 | |||
498 | ctrl = TIMER_CTRL_PERIODIC; | ||
499 | ctrl |= TIMER_CTRL_32BIT | TIMER_CTRL_IE | TIMER_CTRL_ENABLE; | ||
500 | break; | ||
501 | case CLOCK_EVT_MODE_ONESHOT: | ||
502 | /* period set, and timer enabled in 'next_event' hook */ | ||
503 | ctrl = TIMER_CTRL_ONESHOT; | ||
504 | ctrl |= TIMER_CTRL_32BIT | TIMER_CTRL_IE; | ||
505 | break; | ||
506 | case CLOCK_EVT_MODE_UNUSED: | ||
507 | case CLOCK_EVT_MODE_SHUTDOWN: | ||
508 | default: | ||
509 | ctrl = 0; | ||
510 | } | ||
511 | |||
512 | writel(ctrl, TIMER0_VA_BASE + TIMER_CTRL); | ||
513 | } | ||
514 | |||
515 | static int timer_set_next_event(unsigned long evt, | ||
516 | struct clock_event_device *unused) | ||
517 | { | ||
518 | unsigned long ctrl = readl(TIMER0_VA_BASE + TIMER_CTRL); | ||
519 | |||
520 | writel(evt, TIMER0_VA_BASE + TIMER_LOAD); | ||
521 | writel(ctrl | TIMER_CTRL_ENABLE, TIMER0_VA_BASE + TIMER_CTRL); | ||
522 | |||
523 | return 0; | ||
524 | } | ||
525 | |||
526 | static struct clock_event_device timer0_clockevent = { | ||
527 | .name = "timer0", | ||
528 | .shift = 32, | ||
529 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | ||
530 | .set_mode = timer_set_mode, | ||
531 | .set_next_event = timer_set_next_event, | ||
532 | .rating = 300, | ||
533 | .irq = IRQ_TIMERINT0_1, | ||
534 | .cpumask = CPU_MASK_ALL, | ||
535 | }; | ||
536 | |||
537 | static void __init realview_clockevents_init(void) | ||
538 | { | ||
539 | timer0_clockevent.mult = | ||
540 | div_sc(1000000, NSEC_PER_SEC, timer0_clockevent.shift); | ||
541 | timer0_clockevent.max_delta_ns = | ||
542 | clockevent_delta2ns(0xffffffff, &timer0_clockevent); | ||
543 | timer0_clockevent.min_delta_ns = | ||
544 | clockevent_delta2ns(0xf, &timer0_clockevent); | ||
545 | |||
546 | clockevents_register_device(&timer0_clockevent); | ||
547 | } | ||
548 | |||
488 | /* | 549 | /* |
489 | * IRQ handler for the timer | 550 | * IRQ handler for the timer |
490 | */ | 551 | */ |
491 | static irqreturn_t realview_timer_interrupt(int irq, void *dev_id) | 552 | static irqreturn_t realview_timer_interrupt(int irq, void *dev_id) |
492 | { | 553 | { |
493 | // ...clear the interrupt | 554 | struct clock_event_device *evt = &timer0_clockevent; |
494 | writel(1, TIMER0_VA_BASE + TIMER_INTCLR); | ||
495 | 555 | ||
496 | timer_tick(); | 556 | /* clear the interrupt */ |
557 | writel(1, TIMER0_VA_BASE + TIMER_INTCLR); | ||
497 | 558 | ||
498 | #if defined(CONFIG_SMP) && !defined(CONFIG_LOCAL_TIMERS) | 559 | evt->event_handler(evt); |
499 | smp_send_timer(); | ||
500 | update_process_times(user_mode(get_irq_regs())); | ||
501 | #endif | ||
502 | 560 | ||
503 | return IRQ_HANDLED; | 561 | return IRQ_HANDLED; |
504 | } | 562 | } |
@@ -564,17 +622,13 @@ static void __init realview_timer_init(void) | |||
564 | writel(0, TIMER2_VA_BASE + TIMER_CTRL); | 622 | writel(0, TIMER2_VA_BASE + TIMER_CTRL); |
565 | writel(0, TIMER3_VA_BASE + TIMER_CTRL); | 623 | writel(0, TIMER3_VA_BASE + TIMER_CTRL); |
566 | 624 | ||
567 | writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD); | ||
568 | writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_VALUE); | ||
569 | writel(TIMER_DIVISOR | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC | | ||
570 | TIMER_CTRL_IE, TIMER0_VA_BASE + TIMER_CTRL); | ||
571 | |||
572 | /* | 625 | /* |
573 | * Make irqs happen for the system timer | 626 | * Make irqs happen for the system timer |
574 | */ | 627 | */ |
575 | setup_irq(IRQ_TIMERINT0_1, &realview_timer_irq); | 628 | setup_irq(IRQ_TIMERINT0_1, &realview_timer_irq); |
576 | 629 | ||
577 | realview_clocksource_init(); | 630 | realview_clocksource_init(); |
631 | realview_clockevents_init(); | ||
578 | } | 632 | } |
579 | 633 | ||
580 | struct sys_timer realview_timer = { | 634 | struct sys_timer realview_timer = { |