Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[ARM] 3991/1: i.MX/MX1 high resolution time source

Enhanced resolution for time measurement functions.

Signed-off-by: Pavel Pisa <pisa@cmp.felk.cvut.cz>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

authored by

Pavel Pisa and committed by
Russell King
86987d5b 5c894cd1

+51 -38
+50 -36
arch/arm/mach-imx/time.c
··· 14 14 #include <linux/interrupt.h> 15 15 #include <linux/irq.h> 16 16 #include <linux/time.h> 17 + #include <linux/clocksource.h> 17 18 18 19 #include <asm/hardware.h> 19 20 #include <asm/io.h> ··· 25 24 /* Use timer 1 as system timer */ 26 25 #define TIMER_BASE IMX_TIM1_BASE 27 26 28 - /* 29 - * Returns number of us since last clock interrupt. Note that interrupts 30 - * will have been disabled by do_gettimeoffset() 31 - */ 32 - static unsigned long imx_gettimeoffset(void) 33 - { 34 - unsigned long ticks; 35 - 36 - /* 37 - * Get the current number of ticks. Note that there is a race 38 - * condition between us reading the timer and checking for 39 - * an interrupt. We get around this by ensuring that the 40 - * counter has not reloaded between our two reads. 41 - */ 42 - ticks = IMX_TCN(TIMER_BASE); 43 - 44 - /* 45 - * Interrupt pending? If so, we've reloaded once already. 46 - */ 47 - if (IMX_TSTAT(TIMER_BASE) & TSTAT_COMP) 48 - ticks += LATCH; 49 - 50 - /* 51 - * Convert the ticks to usecs 52 - */ 53 - return (1000000 / CLK32) * ticks; 54 - } 27 + static unsigned long evt_diff; 55 28 56 29 /* 57 30 * IRQ handler for the timer ··· 33 58 static irqreturn_t 34 59 imx_timer_interrupt(int irq, void *dev_id) 35 60 { 36 - write_seqlock(&xtime_lock); 61 + uint32_t tstat; 37 62 38 63 /* clear the interrupt */ 39 - if (IMX_TSTAT(TIMER_BASE)) 40 - IMX_TSTAT(TIMER_BASE) = 0; 64 + tstat = IMX_TSTAT(TIMER_BASE); 65 + IMX_TSTAT(TIMER_BASE) = 0; 41 66 42 - timer_tick(); 43 - write_sequnlock(&xtime_lock); 67 + if (tstat & TSTAT_COMP) { 68 + do { 69 + 70 + write_seqlock(&xtime_lock); 71 + timer_tick(); 72 + write_sequnlock(&xtime_lock); 73 + IMX_TCMP(TIMER_BASE) += evt_diff; 74 + 75 + } while (unlikely((int32_t)(IMX_TCMP(TIMER_BASE) 76 + - IMX_TCN(TIMER_BASE)) < 0)); 77 + } 44 78 45 79 return IRQ_HANDLED; 46 80 } ··· 61 77 }; 62 78 63 79 /* 64 - * Set up timer interrupt, and return the current time in seconds. 80 + * Set up timer hardware into expected mode and state. 65 81 */ 66 - static void __init imx_timer_init(void) 82 + static void __init imx_timer_hardware_init(void) 67 83 { 68 84 /* 69 85 * Initialise to a known state (all timers off, and timing reset) ··· 71 87 IMX_TCTL(TIMER_BASE) = 0; 72 88 IMX_TPRER(TIMER_BASE) = 0; 73 89 IMX_TCMP(TIMER_BASE) = LATCH - 1; 74 - IMX_TCTL(TIMER_BASE) = TCTL_CLK_32 | TCTL_IRQEN | TCTL_TEN; 90 + 91 + IMX_TCTL(TIMER_BASE) = TCTL_FRR | TCTL_CLK_PCLK1 | TCTL_IRQEN | TCTL_TEN; 92 + evt_diff = LATCH; 93 + } 94 + 95 + cycle_t imx_get_cycles(void) 96 + { 97 + return IMX_TCN(TIMER_BASE); 98 + } 99 + 100 + static struct clocksource clocksource_imx = { 101 + .name = "imx_timer1", 102 + .rating = 200, 103 + .read = imx_get_cycles, 104 + .mask = 0xFFFFFFFF, 105 + .shift = 20, 106 + .is_continuous = 1, 107 + }; 108 + 109 + static int __init imx_clocksource_init(void) 110 + { 111 + clocksource_imx.mult = 112 + clocksource_hz2mult(imx_get_perclk1(), clocksource_imx.shift); 113 + clocksource_register(&clocksource_imx); 114 + 115 + return 0; 116 + } 117 + 118 + static void __init imx_timer_init(void) 119 + { 120 + imx_timer_hardware_init(); 121 + imx_clocksource_init(); 75 122 76 123 /* 77 124 * Make irqs happen for the system timer ··· 112 97 113 98 struct sys_timer imx_timer = { 114 99 .init = imx_timer_init, 115 - .offset = imx_gettimeoffset, 116 100 };
+1 -2
include/asm-arm/arch-imx/timex.h
··· 21 21 #ifndef __ASM_ARCH_TIMEX_H 22 22 #define __ASM_ARCH_TIMEX_H 23 23 24 - #include <asm/hardware.h> 25 - #define CLOCK_TICK_RATE (CLK32) 24 + #define CLOCK_TICK_RATE (16000000) 26 25 27 26 #endif