diff options
author | Mark A. Greer <mgreer@mvista.com> | 2009-04-15 15:40:11 -0400 |
---|---|---|
committer | Kevin Hilman <khilman@deeprootsystems.com> | 2009-05-26 11:19:04 -0400 |
commit | f64691b3ab795268072e76ddb89290b6277cdf33 (patch) | |
tree | cc8de5ab3c90674905f6d8e141bcf345a81121f4 /arch/arm/mach-davinci/time.c | |
parent | 673dd36f0d0cf8893d6b46d524ad80e81076b885 (diff) |
davinci: Add base address and timer flexibility
The davinci timer code currently hardcodes the timer register
base addresses, the timer irq numbers, and the timers to use
for clock events and clocksource. This won't work for some
a new SoC so put those values into the soc_info structure
and set them up in the SoC-specific files.
Signed-off-by: Mark A. Greer <mgreer@mvista.com>
Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
Diffstat (limited to 'arch/arm/mach-davinci/time.c')
-rw-r--r-- | arch/arm/mach-davinci/time.c | 100 |
1 files changed, 45 insertions, 55 deletions
diff --git a/arch/arm/mach-davinci/time.c b/arch/arm/mach-davinci/time.c index efbbc2ac63b4..faafb897f4bd 100644 --- a/arch/arm/mach-davinci/time.c +++ b/arch/arm/mach-davinci/time.c | |||
@@ -29,42 +29,23 @@ | |||
29 | #include <asm/errno.h> | 29 | #include <asm/errno.h> |
30 | #include <mach/io.h> | 30 | #include <mach/io.h> |
31 | #include <mach/cputype.h> | 31 | #include <mach/cputype.h> |
32 | #include <mach/time.h> | ||
32 | #include "clock.h" | 33 | #include "clock.h" |
33 | 34 | ||
34 | static struct clock_event_device clockevent_davinci; | 35 | static struct clock_event_device clockevent_davinci; |
35 | static unsigned int davinci_clock_tick_rate; | 36 | static unsigned int davinci_clock_tick_rate; |
36 | 37 | ||
37 | #define DAVINCI_TIMER0_BASE (IO_PHYS + 0x21400) | ||
38 | #define DAVINCI_TIMER1_BASE (IO_PHYS + 0x21800) | ||
39 | #define DAVINCI_WDOG_BASE (IO_PHYS + 0x21C00) | 38 | #define DAVINCI_WDOG_BASE (IO_PHYS + 0x21C00) |
40 | 39 | ||
41 | enum { | ||
42 | T0_BOT = 0, T0_TOP, T1_BOT, T1_TOP, NUM_TIMERS, | ||
43 | }; | ||
44 | |||
45 | #define IS_TIMER1(id) (id & 0x2) | ||
46 | #define IS_TIMER0(id) (!IS_TIMER1(id)) | ||
47 | #define IS_TIMER_TOP(id) ((id & 0x1)) | ||
48 | #define IS_TIMER_BOT(id) (!IS_TIMER_TOP(id)) | ||
49 | |||
50 | static int timer_irqs[NUM_TIMERS] = { | ||
51 | IRQ_TINT0_TINT12, | ||
52 | IRQ_TINT0_TINT34, | ||
53 | IRQ_TINT1_TINT12, | ||
54 | IRQ_TINT1_TINT34, | ||
55 | }; | ||
56 | |||
57 | /* | 40 | /* |
58 | * This driver configures the 2 64-bit count-up timers as 4 independent | 41 | * This driver configures the 2 64-bit count-up timers as 4 independent |
59 | * 32-bit count-up timers used as follows: | 42 | * 32-bit count-up timers used as follows: |
60 | * | ||
61 | * T0_BOT: Timer 0, bottom: clockevent source for hrtimers | ||
62 | * T0_TOP: Timer 0, top : clocksource for generic timekeeping | ||
63 | * T1_BOT: Timer 1, bottom: (used by DSP in TI DSPLink code) | ||
64 | * T1_TOP: Timer 1, top : <unused> | ||
65 | */ | 43 | */ |
66 | #define TID_CLOCKEVENT T0_BOT | 44 | |
67 | #define TID_CLOCKSOURCE T0_TOP | 45 | enum { |
46 | TID_CLOCKEVENT, | ||
47 | TID_CLOCKSOURCE, | ||
48 | }; | ||
68 | 49 | ||
69 | /* Timer register offsets */ | 50 | /* Timer register offsets */ |
70 | #define PID12 0x0 | 51 | #define PID12 0x0 |
@@ -119,6 +100,13 @@ static struct timer_s timers[]; | |||
119 | #define TIMER_OPTS_ONESHOT 0x01 | 100 | #define TIMER_OPTS_ONESHOT 0x01 |
120 | #define TIMER_OPTS_PERIODIC 0x02 | 101 | #define TIMER_OPTS_PERIODIC 0x02 |
121 | 102 | ||
103 | static char *id_to_name[] = { | ||
104 | [T0_BOT] = "timer0_0", | ||
105 | [T0_TOP] = "timer0_1", | ||
106 | [T1_BOT] = "timer1_0", | ||
107 | [T1_TOP] = "timer1_1", | ||
108 | }; | ||
109 | |||
122 | static int timer32_config(struct timer_s *t) | 110 | static int timer32_config(struct timer_s *t) |
123 | { | 111 | { |
124 | u32 tcr = __raw_readl(t->base + TCR); | 112 | u32 tcr = __raw_readl(t->base + TCR); |
@@ -183,13 +171,14 @@ static struct timer_s timers[] = { | |||
183 | 171 | ||
184 | static void __init timer_init(void) | 172 | static void __init timer_init(void) |
185 | { | 173 | { |
186 | u32 phys_bases[] = {DAVINCI_TIMER0_BASE, DAVINCI_TIMER1_BASE}; | 174 | struct davinci_soc_info *soc_info = &davinci_soc_info; |
175 | struct davinci_timer_instance *dtip = soc_info->timer_info->timers; | ||
187 | int i; | 176 | int i; |
188 | 177 | ||
189 | /* Global init of each 64-bit timer as a whole */ | 178 | /* Global init of each 64-bit timer as a whole */ |
190 | for(i=0; i<2; i++) { | 179 | for(i=0; i<2; i++) { |
191 | u32 tgcr; | 180 | u32 tgcr; |
192 | void __iomem *base = IO_ADDRESS(phys_bases[i]); | 181 | void __iomem *base = dtip[i].base; |
193 | 182 | ||
194 | /* Disabled, Internal clock source */ | 183 | /* Disabled, Internal clock source */ |
195 | __raw_writel(0, base + TCR); | 184 | __raw_writel(0, base + TCR); |
@@ -215,33 +204,30 @@ static void __init timer_init(void) | |||
215 | /* Init of each timer as a 32-bit timer */ | 204 | /* Init of each timer as a 32-bit timer */ |
216 | for (i=0; i< ARRAY_SIZE(timers); i++) { | 205 | for (i=0; i< ARRAY_SIZE(timers); i++) { |
217 | struct timer_s *t = &timers[i]; | 206 | struct timer_s *t = &timers[i]; |
218 | u32 phys_base; | 207 | int timer = ID_TO_TIMER(t->id); |
219 | 208 | u32 irq; | |
220 | if (t->name) { | 209 | |
221 | t->id = i; | 210 | t->base = dtip[timer].base; |
222 | phys_base = (IS_TIMER1(t->id) ? | 211 | |
223 | DAVINCI_TIMER1_BASE : DAVINCI_TIMER0_BASE); | 212 | if (IS_TIMER_BOT(t->id)) { |
224 | t->base = IO_ADDRESS(phys_base); | 213 | t->enamode_shift = 6; |
225 | 214 | t->tim_off = TIM12; | |
226 | if (IS_TIMER_BOT(t->id)) { | 215 | t->prd_off = PRD12; |
227 | t->enamode_shift = 6; | 216 | irq = dtip[timer].bottom_irq; |
228 | t->tim_off = TIM12; | 217 | } else { |
229 | t->prd_off = PRD12; | 218 | t->enamode_shift = 22; |
230 | } else { | 219 | t->tim_off = TIM34; |
231 | t->enamode_shift = 22; | 220 | t->prd_off = PRD34; |
232 | t->tim_off = TIM34; | 221 | irq = dtip[timer].top_irq; |
233 | t->prd_off = PRD34; | ||
234 | } | ||
235 | |||
236 | /* Register interrupt */ | ||
237 | t->irqaction.name = t->name; | ||
238 | t->irqaction.dev_id = (void *)t; | ||
239 | if (t->irqaction.handler != NULL) { | ||
240 | setup_irq(timer_irqs[t->id], &t->irqaction); | ||
241 | } | ||
242 | |||
243 | timer32_config(&timers[i]); | ||
244 | } | 222 | } |
223 | |||
224 | /* Register interrupt */ | ||
225 | t->irqaction.name = t->name; | ||
226 | t->irqaction.dev_id = (void *)t; | ||
227 | if (t->irqaction.handler != NULL) | ||
228 | setup_irq(irq, &t->irqaction); | ||
229 | |||
230 | timer32_config(&timers[i]); | ||
245 | } | 231 | } |
246 | } | 232 | } |
247 | 233 | ||
@@ -256,7 +242,6 @@ static cycle_t read_cycles(struct clocksource *cs) | |||
256 | } | 242 | } |
257 | 243 | ||
258 | static struct clocksource clocksource_davinci = { | 244 | static struct clocksource clocksource_davinci = { |
259 | .name = "timer0_1", | ||
260 | .rating = 300, | 245 | .rating = 300, |
261 | .read = read_cycles, | 246 | .read = read_cycles, |
262 | .mask = CLOCKSOURCE_MASK(32), | 247 | .mask = CLOCKSOURCE_MASK(32), |
@@ -301,7 +286,6 @@ static void davinci_set_mode(enum clock_event_mode mode, | |||
301 | } | 286 | } |
302 | 287 | ||
303 | static struct clock_event_device clockevent_davinci = { | 288 | static struct clock_event_device clockevent_davinci = { |
304 | .name = "timer0_0", | ||
305 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | 289 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, |
306 | .shift = 32, | 290 | .shift = 32, |
307 | .set_next_event = davinci_set_next_event, | 291 | .set_next_event = davinci_set_next_event, |
@@ -312,10 +296,14 @@ static struct clock_event_device clockevent_davinci = { | |||
312 | static void __init davinci_timer_init(void) | 296 | static void __init davinci_timer_init(void) |
313 | { | 297 | { |
314 | struct clk *timer_clk; | 298 | struct clk *timer_clk; |
299 | struct davinci_soc_info *soc_info = &davinci_soc_info; | ||
315 | 300 | ||
316 | static char err[] __initdata = KERN_ERR | 301 | static char err[] __initdata = KERN_ERR |
317 | "%s: can't register clocksource!\n"; | 302 | "%s: can't register clocksource!\n"; |
318 | 303 | ||
304 | timers[TID_CLOCKEVENT].id = soc_info->timer_info->clockevent_id; | ||
305 | timers[TID_CLOCKSOURCE].id = soc_info->timer_info->clocksource_id; | ||
306 | |||
319 | /* init timer hw */ | 307 | /* init timer hw */ |
320 | timer_init(); | 308 | timer_init(); |
321 | 309 | ||
@@ -326,6 +314,7 @@ static void __init davinci_timer_init(void) | |||
326 | davinci_clock_tick_rate = clk_get_rate(timer_clk); | 314 | davinci_clock_tick_rate = clk_get_rate(timer_clk); |
327 | 315 | ||
328 | /* setup clocksource */ | 316 | /* setup clocksource */ |
317 | clocksource_davinci.name = id_to_name[timers[TID_CLOCKSOURCE].id]; | ||
329 | clocksource_davinci.mult = | 318 | clocksource_davinci.mult = |
330 | clocksource_khz2mult(davinci_clock_tick_rate/1000, | 319 | clocksource_khz2mult(davinci_clock_tick_rate/1000, |
331 | clocksource_davinci.shift); | 320 | clocksource_davinci.shift); |
@@ -333,6 +322,7 @@ static void __init davinci_timer_init(void) | |||
333 | printk(err, clocksource_davinci.name); | 322 | printk(err, clocksource_davinci.name); |
334 | 323 | ||
335 | /* setup clockevent */ | 324 | /* setup clockevent */ |
325 | clockevent_davinci.name = id_to_name[timers[TID_CLOCKEVENT].id]; | ||
336 | clockevent_davinci.mult = div_sc(davinci_clock_tick_rate, NSEC_PER_SEC, | 326 | clockevent_davinci.mult = div_sc(davinci_clock_tick_rate, NSEC_PER_SEC, |
337 | clockevent_davinci.shift); | 327 | clockevent_davinci.shift); |
338 | clockevent_davinci.max_delta_ns = | 328 | clockevent_davinci.max_delta_ns = |