diff options
| -rw-r--r-- | arch/arm/Kconfig | 1 | ||||
| -rw-r--r-- | arch/arm/mach-versatile/core.c | 75 |
2 files changed, 35 insertions, 41 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 2aadd0e1e586..cddd054676c0 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
| @@ -166,6 +166,7 @@ config ARCH_VERSATILE | |||
| 166 | select ARM_AMBA | 166 | select ARM_AMBA |
| 167 | select ARM_VIC | 167 | select ARM_VIC |
| 168 | select ICST307 | 168 | select ICST307 |
| 169 | select GENERIC_TIME | ||
| 169 | help | 170 | help |
| 170 | This enables support for ARM Ltd Versatile board. | 171 | This enables support for ARM Ltd Versatile board. |
| 171 | 172 | ||
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c index bf71507c76fd..08a9fe6eeadb 100644 --- a/arch/arm/mach-versatile/core.c +++ b/arch/arm/mach-versatile/core.c | |||
| @@ -26,6 +26,7 @@ | |||
| 26 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
| 27 | #include <linux/amba/bus.h> | 27 | #include <linux/amba/bus.h> |
| 28 | #include <linux/amba/clcd.h> | 28 | #include <linux/amba/clcd.h> |
| 29 | #include <linux/clocksource.h> | ||
| 29 | 30 | ||
| 30 | #include <asm/cnt32_to_63.h> | 31 | #include <asm/cnt32_to_63.h> |
| 31 | #include <asm/system.h> | 32 | #include <asm/system.h> |
| @@ -829,46 +830,6 @@ void __init versatile_init(void) | |||
| 829 | #endif | 830 | #endif |
| 830 | 831 | ||
| 831 | /* | 832 | /* |
| 832 | * Returns number of ms since last clock interrupt. Note that interrupts | ||
| 833 | * will have been disabled by do_gettimeoffset() | ||
| 834 | */ | ||
| 835 | static unsigned long versatile_gettimeoffset(void) | ||
| 836 | { | ||
| 837 | unsigned long ticks1, ticks2, status; | ||
| 838 | |||
| 839 | /* | ||
| 840 | * Get the current number of ticks. Note that there is a race | ||
| 841 | * condition between us reading the timer and checking for | ||
| 842 | * an interrupt. We get around this by ensuring that the | ||
| 843 | * counter has not reloaded between our two reads. | ||
| 844 | */ | ||
| 845 | ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff; | ||
| 846 | do { | ||
| 847 | ticks1 = ticks2; | ||
| 848 | status = __raw_readl(VA_IC_BASE + VIC_RAW_STATUS); | ||
| 849 | ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff; | ||
| 850 | } while (ticks2 > ticks1); | ||
| 851 | |||
| 852 | /* | ||
| 853 | * Number of ticks since last interrupt. | ||
| 854 | */ | ||
| 855 | ticks1 = TIMER_RELOAD - ticks2; | ||
| 856 | |||
| 857 | /* | ||
| 858 | * Interrupt pending? If so, we've reloaded once already. | ||
| 859 | * | ||
| 860 | * FIXME: Need to check this is effectively timer 0 that expires | ||
| 861 | */ | ||
| 862 | if (status & IRQMASK_TIMERINT0_1) | ||
| 863 | ticks1 += TIMER_RELOAD; | ||
| 864 | |||
| 865 | /* | ||
| 866 | * Convert the ticks to usecs | ||
| 867 | */ | ||
| 868 | return TICKS2USECS(ticks1); | ||
| 869 | } | ||
| 870 | |||
| 871 | /* | ||
| 872 | * IRQ handler for the timer | 833 | * IRQ handler for the timer |
| 873 | */ | 834 | */ |
| 874 | static irqreturn_t versatile_timer_interrupt(int irq, void *dev_id) | 835 | static irqreturn_t versatile_timer_interrupt(int irq, void *dev_id) |
| @@ -891,6 +852,36 @@ static struct irqaction versatile_timer_irq = { | |||
| 891 | .handler = versatile_timer_interrupt, | 852 | .handler = versatile_timer_interrupt, |
| 892 | }; | 853 | }; |
| 893 | 854 | ||
| 855 | static cycle_t versatile_get_cycles(void) | ||
| 856 | { | ||
| 857 | return ~readl(TIMER3_VA_BASE + TIMER_VALUE); | ||
| 858 | } | ||
| 859 | |||
| 860 | static struct clocksource clocksource_versatile = { | ||
| 861 | .name = "timer3", | ||
| 862 | .rating = 200, | ||
| 863 | .read = versatile_get_cycles, | ||
| 864 | .mask = CLOCKSOURCE_MASK(32), | ||
| 865 | .shift = 20, | ||
| 866 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, | ||
| 867 | }; | ||
| 868 | |||
| 869 | static int __init versatile_clocksource_init(void) | ||
| 870 | { | ||
| 871 | /* setup timer3 as free-running clocksource */ | ||
| 872 | writel(0, TIMER3_VA_BASE + TIMER_CTRL); | ||
| 873 | writel(0xffffffff, TIMER3_VA_BASE + TIMER_LOAD); | ||
| 874 | writel(0xffffffff, TIMER3_VA_BASE + TIMER_VALUE); | ||
| 875 | writel(TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC, | ||
| 876 | TIMER3_VA_BASE + TIMER_CTRL); | ||
| 877 | |||
| 878 | clocksource_versatile.mult = | ||
| 879 | clocksource_khz2mult(1000, clocksource_versatile.shift); | ||
| 880 | clocksource_register(&clocksource_versatile); | ||
| 881 | |||
| 882 | return 0; | ||
| 883 | } | ||
| 884 | |||
| 894 | /* | 885 | /* |
| 895 | * Set up timer interrupt, and return the current time in seconds. | 886 | * Set up timer interrupt, and return the current time in seconds. |
| 896 | */ | 887 | */ |
| @@ -927,9 +918,11 @@ static void __init versatile_timer_init(void) | |||
| 927 | * Make irqs happen for the system timer | 918 | * Make irqs happen for the system timer |
| 928 | */ | 919 | */ |
| 929 | setup_irq(IRQ_TIMERINT0_1, &versatile_timer_irq); | 920 | setup_irq(IRQ_TIMERINT0_1, &versatile_timer_irq); |
| 921 | |||
| 922 | versatile_clocksource_init(); | ||
| 930 | } | 923 | } |
| 931 | 924 | ||
| 932 | struct sys_timer versatile_timer = { | 925 | struct sys_timer versatile_timer = { |
| 933 | .init = versatile_timer_init, | 926 | .init = versatile_timer_init, |
| 934 | .offset = versatile_gettimeoffset, | ||
| 935 | }; | 927 | }; |
| 928 | |||
