diff options
author | Catalin Marinas <catalin.marinas@arm.com> | 2008-02-04 11:24:54 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2008-02-04 12:52:16 -0500 |
commit | 85802afeb010502471f64dccf9839f60995c8579 (patch) | |
tree | cfeb1aa57a7c0f1691301ccd14fc4da044aa5157 | |
parent | ae9458d6a0956aa21cb49e1251e35a8d4dacbe6e (diff) |
[ARM] 4811/1: RealView: clocksource support for the RealView platforms
The patch updates the RealView platform code to use the generic
clocksource infrastructure for basic time keeping. Based on the
Versatile implementation by Kevin Hilman.
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r-- | arch/arm/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/mach-realview/core.c | 73 |
2 files changed, 32 insertions, 42 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 4b1a8e3d292c..a2b7e4a52f73 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -168,6 +168,7 @@ config ARCH_REALVIEW | |||
168 | bool "ARM Ltd. RealView family" | 168 | bool "ARM Ltd. RealView family" |
169 | select ARM_AMBA | 169 | select ARM_AMBA |
170 | select ICST307 | 170 | select ICST307 |
171 | select GENERIC_TIME | ||
171 | help | 172 | help |
172 | This enables support for ARM Ltd RealView boards. | 173 | This enables support for ARM Ltd RealView boards. |
173 | 174 | ||
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c index 61d70218f1e8..f805840f6f44 100644 --- a/arch/arm/mach-realview/core.c +++ b/arch/arm/mach-realview/core.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
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 | 29 | ||
29 | #include <asm/system.h> | 30 | #include <asm/system.h> |
30 | #include <asm/hardware.h> | 31 | #include <asm/hardware.h> |
@@ -485,47 +486,6 @@ void realview_leds_event(led_event_t ledevt) | |||
485 | #endif | 486 | #endif |
486 | 487 | ||
487 | /* | 488 | /* |
488 | * Returns number of ms since last clock interrupt. Note that interrupts | ||
489 | * will have been disabled by do_gettimeoffset() | ||
490 | */ | ||
491 | static unsigned long realview_gettimeoffset(void) | ||
492 | { | ||
493 | unsigned long ticks1, ticks2, status; | ||
494 | |||
495 | /* | ||
496 | * Get the current number of ticks. Note that there is a race | ||
497 | * condition between us reading the timer and checking for | ||
498 | * an interrupt. We get around this by ensuring that the | ||
499 | * counter has not reloaded between our two reads. | ||
500 | */ | ||
501 | ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff; | ||
502 | do { | ||
503 | ticks1 = ticks2; | ||
504 | status = __raw_readl(__io_address(REALVIEW_GIC_DIST_BASE + GIC_DIST_PENDING_SET) | ||
505 | + ((IRQ_TIMERINT0_1 >> 5) << 2)); | ||
506 | ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff; | ||
507 | } while (ticks2 > ticks1); | ||
508 | |||
509 | /* | ||
510 | * Number of ticks since last interrupt. | ||
511 | */ | ||
512 | ticks1 = TIMER_RELOAD - ticks2; | ||
513 | |||
514 | /* | ||
515 | * Interrupt pending? If so, we've reloaded once already. | ||
516 | * | ||
517 | * FIXME: Need to check this is effectively timer 0 that expires | ||
518 | */ | ||
519 | if (status & IRQMASK_TIMERINT0_1) | ||
520 | ticks1 += TIMER_RELOAD; | ||
521 | |||
522 | /* | ||
523 | * Convert the ticks to usecs | ||
524 | */ | ||
525 | return TICKS2USECS(ticks1); | ||
526 | } | ||
527 | |||
528 | /* | ||
529 | * IRQ handler for the timer | 489 | * IRQ handler for the timer |
530 | */ | 490 | */ |
531 | static irqreturn_t realview_timer_interrupt(int irq, void *dev_id) | 491 | static irqreturn_t realview_timer_interrupt(int irq, void *dev_id) |
@@ -549,6 +509,34 @@ static struct irqaction realview_timer_irq = { | |||
549 | .handler = realview_timer_interrupt, | 509 | .handler = realview_timer_interrupt, |
550 | }; | 510 | }; |
551 | 511 | ||
512 | static cycle_t realview_get_cycles(void) | ||
513 | { | ||
514 | return ~readl(TIMER3_VA_BASE + TIMER_VALUE); | ||
515 | } | ||
516 | |||
517 | static struct clocksource clocksource_realview = { | ||
518 | .name = "timer3", | ||
519 | .rating = 200, | ||
520 | .read = realview_get_cycles, | ||
521 | .mask = CLOCKSOURCE_MASK(32), | ||
522 | .shift = 20, | ||
523 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
524 | }; | ||
525 | |||
526 | static void __init realview_clocksource_init(void) | ||
527 | { | ||
528 | /* setup timer 0 as free-running clocksource */ | ||
529 | writel(0, TIMER3_VA_BASE + TIMER_CTRL); | ||
530 | writel(0xffffffff, TIMER3_VA_BASE + TIMER_LOAD); | ||
531 | writel(0xffffffff, TIMER3_VA_BASE + TIMER_VALUE); | ||
532 | writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC, | ||
533 | TIMER3_VA_BASE + TIMER_CTRL); | ||
534 | |||
535 | clocksource_realview.mult = | ||
536 | clocksource_khz2mult(1000, clocksource_realview.shift); | ||
537 | clocksource_register(&clocksource_realview); | ||
538 | } | ||
539 | |||
552 | /* | 540 | /* |
553 | * Set up timer interrupt, and return the current time in seconds. | 541 | * Set up timer interrupt, and return the current time in seconds. |
554 | */ | 542 | */ |
@@ -585,9 +573,10 @@ static void __init realview_timer_init(void) | |||
585 | * Make irqs happen for the system timer | 573 | * Make irqs happen for the system timer |
586 | */ | 574 | */ |
587 | setup_irq(IRQ_TIMERINT0_1, &realview_timer_irq); | 575 | setup_irq(IRQ_TIMERINT0_1, &realview_timer_irq); |
576 | |||
577 | realview_clocksource_init(); | ||
588 | } | 578 | } |
589 | 579 | ||
590 | struct sys_timer realview_timer = { | 580 | struct sys_timer realview_timer = { |
591 | .init = realview_timer_init, | 581 | .init = realview_timer_init, |
592 | .offset = realview_gettimeoffset, | ||
593 | }; | 582 | }; |