diff options
Diffstat (limited to 'arch/arm/mach-omap2/timer.c')
-rw-r--r-- | arch/arm/mach-omap2/timer.c | 382 |
1 files changed, 265 insertions, 117 deletions
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index c5bc2cb4d8d3..b9cff72ceaec 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c | |||
@@ -37,6 +37,10 @@ | |||
37 | #include <linux/clockchips.h> | 37 | #include <linux/clockchips.h> |
38 | #include <linux/slab.h> | 38 | #include <linux/slab.h> |
39 | #include <linux/of.h> | 39 | #include <linux/of.h> |
40 | #include <linux/of_address.h> | ||
41 | #include <linux/of_irq.h> | ||
42 | #include <linux/platform_device.h> | ||
43 | #include <linux/platform_data/dmtimer-omap.h> | ||
40 | 44 | ||
41 | #include <asm/mach/time.h> | 45 | #include <asm/mach/time.h> |
42 | #include <asm/smp_twd.h> | 46 | #include <asm/smp_twd.h> |
@@ -62,18 +66,6 @@ | |||
62 | #define OMAP3_32K_SOURCE "omap_32k_fck" | 66 | #define OMAP3_32K_SOURCE "omap_32k_fck" |
63 | #define OMAP4_32K_SOURCE "sys_32k_ck" | 67 | #define OMAP4_32K_SOURCE "sys_32k_ck" |
64 | 68 | ||
65 | #ifdef CONFIG_OMAP_32K_TIMER | ||
66 | #define OMAP2_CLKEV_SOURCE OMAP2_32K_SOURCE | ||
67 | #define OMAP3_CLKEV_SOURCE OMAP3_32K_SOURCE | ||
68 | #define OMAP4_CLKEV_SOURCE OMAP4_32K_SOURCE | ||
69 | #define OMAP3_SECURE_TIMER 12 | ||
70 | #else | ||
71 | #define OMAP2_CLKEV_SOURCE OMAP2_MPU_SOURCE | ||
72 | #define OMAP3_CLKEV_SOURCE OMAP3_MPU_SOURCE | ||
73 | #define OMAP4_CLKEV_SOURCE OMAP4_MPU_SOURCE | ||
74 | #define OMAP3_SECURE_TIMER 1 | ||
75 | #endif | ||
76 | |||
77 | #define REALTIME_COUNTER_BASE 0x48243200 | 69 | #define REALTIME_COUNTER_BASE 0x48243200 |
78 | #define INCREMENTER_NUMERATOR_OFFSET 0x10 | 70 | #define INCREMENTER_NUMERATOR_OFFSET 0x10 |
79 | #define INCREMENTER_DENUMERATOR_RELOAD_OFFSET 0x14 | 71 | #define INCREMENTER_DENUMERATOR_RELOAD_OFFSET 0x14 |
@@ -104,7 +96,7 @@ static int omap2_gp_timer_set_next_event(unsigned long cycles, | |||
104 | struct clock_event_device *evt) | 96 | struct clock_event_device *evt) |
105 | { | 97 | { |
106 | __omap_dm_timer_load_start(&clkev, OMAP_TIMER_CTRL_ST, | 98 | __omap_dm_timer_load_start(&clkev, OMAP_TIMER_CTRL_ST, |
107 | 0xffffffff - cycles, 1); | 99 | 0xffffffff - cycles, OMAP_TIMER_POSTED); |
108 | 100 | ||
109 | return 0; | 101 | return 0; |
110 | } | 102 | } |
@@ -114,7 +106,7 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode, | |||
114 | { | 106 | { |
115 | u32 period; | 107 | u32 period; |
116 | 108 | ||
117 | __omap_dm_timer_stop(&clkev, 1, clkev.rate); | 109 | __omap_dm_timer_stop(&clkev, OMAP_TIMER_POSTED, clkev.rate); |
118 | 110 | ||
119 | switch (mode) { | 111 | switch (mode) { |
120 | case CLOCK_EVT_MODE_PERIODIC: | 112 | case CLOCK_EVT_MODE_PERIODIC: |
@@ -122,10 +114,10 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode, | |||
122 | period -= 1; | 114 | period -= 1; |
123 | /* Looks like we need to first set the load value separately */ | 115 | /* Looks like we need to first set the load value separately */ |
124 | __omap_dm_timer_write(&clkev, OMAP_TIMER_LOAD_REG, | 116 | __omap_dm_timer_write(&clkev, OMAP_TIMER_LOAD_REG, |
125 | 0xffffffff - period, 1); | 117 | 0xffffffff - period, OMAP_TIMER_POSTED); |
126 | __omap_dm_timer_load_start(&clkev, | 118 | __omap_dm_timer_load_start(&clkev, |
127 | OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST, | 119 | OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST, |
128 | 0xffffffff - period, 1); | 120 | 0xffffffff - period, OMAP_TIMER_POSTED); |
129 | break; | 121 | break; |
130 | case CLOCK_EVT_MODE_ONESHOT: | 122 | case CLOCK_EVT_MODE_ONESHOT: |
131 | break; | 123 | break; |
@@ -145,36 +137,144 @@ static struct clock_event_device clockevent_gpt = { | |||
145 | .set_mode = omap2_gp_timer_set_mode, | 137 | .set_mode = omap2_gp_timer_set_mode, |
146 | }; | 138 | }; |
147 | 139 | ||
140 | static struct property device_disabled = { | ||
141 | .name = "status", | ||
142 | .length = sizeof("disabled"), | ||
143 | .value = "disabled", | ||
144 | }; | ||
145 | |||
146 | static struct of_device_id omap_timer_match[] __initdata = { | ||
147 | { .compatible = "ti,omap2-timer", }, | ||
148 | { } | ||
149 | }; | ||
150 | |||
151 | /** | ||
152 | * omap_get_timer_dt - get a timer using device-tree | ||
153 | * @match - device-tree match structure for matching a device type | ||
154 | * @property - optional timer property to match | ||
155 | * | ||
156 | * Helper function to get a timer during early boot using device-tree for use | ||
157 | * as kernel system timer. Optionally, the property argument can be used to | ||
158 | * select a timer with a specific property. Once a timer is found then mark | ||
159 | * the timer node in device-tree as disabled, to prevent the kernel from | ||
160 | * registering this timer as a platform device and so no one else can use it. | ||
161 | */ | ||
162 | static struct device_node * __init omap_get_timer_dt(struct of_device_id *match, | ||
163 | const char *property) | ||
164 | { | ||
165 | struct device_node *np; | ||
166 | |||
167 | for_each_matching_node(np, match) { | ||
168 | if (!of_device_is_available(np)) { | ||
169 | of_node_put(np); | ||
170 | continue; | ||
171 | } | ||
172 | |||
173 | if (property && !of_get_property(np, property, NULL)) { | ||
174 | of_node_put(np); | ||
175 | continue; | ||
176 | } | ||
177 | |||
178 | prom_add_property(np, &device_disabled); | ||
179 | return np; | ||
180 | } | ||
181 | |||
182 | return NULL; | ||
183 | } | ||
184 | |||
185 | /** | ||
186 | * omap_dmtimer_init - initialisation function when device tree is used | ||
187 | * | ||
188 | * For secure OMAP3 devices, timers with device type "timer-secure" cannot | ||
189 | * be used by the kernel as they are reserved. Therefore, to prevent the | ||
190 | * kernel registering these devices remove them dynamically from the device | ||
191 | * tree on boot. | ||
192 | */ | ||
193 | void __init omap_dmtimer_init(void) | ||
194 | { | ||
195 | struct device_node *np; | ||
196 | |||
197 | if (!cpu_is_omap34xx()) | ||
198 | return; | ||
199 | |||
200 | /* If we are a secure device, remove any secure timer nodes */ | ||
201 | if ((omap_type() != OMAP2_DEVICE_TYPE_GP)) { | ||
202 | np = omap_get_timer_dt(omap_timer_match, "ti,timer-secure"); | ||
203 | if (np) | ||
204 | of_node_put(np); | ||
205 | } | ||
206 | } | ||
207 | |||
208 | /** | ||
209 | * omap_dm_timer_get_errata - get errata flags for a timer | ||
210 | * | ||
211 | * Get the timer errata flags that are specific to the OMAP device being used. | ||
212 | */ | ||
213 | u32 __init omap_dm_timer_get_errata(void) | ||
214 | { | ||
215 | if (cpu_is_omap24xx()) | ||
216 | return 0; | ||
217 | |||
218 | return OMAP_TIMER_ERRATA_I103_I767; | ||
219 | } | ||
220 | |||
148 | static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, | 221 | static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, |
149 | int gptimer_id, | 222 | int gptimer_id, |
150 | const char *fck_source) | 223 | const char *fck_source, |
224 | const char *property, | ||
225 | int posted) | ||
151 | { | 226 | { |
152 | char name[10]; /* 10 = sizeof("gptXX_Xck0") */ | 227 | char name[10]; /* 10 = sizeof("gptXX_Xck0") */ |
228 | const char *oh_name; | ||
229 | struct device_node *np; | ||
153 | struct omap_hwmod *oh; | 230 | struct omap_hwmod *oh; |
154 | struct resource irq_rsrc, mem_rsrc; | 231 | struct resource irq, mem; |
155 | size_t size; | 232 | int r = 0; |
156 | int res = 0; | 233 | |
157 | int r; | 234 | if (of_have_populated_dt()) { |
158 | 235 | np = omap_get_timer_dt(omap_timer_match, NULL); | |
159 | sprintf(name, "timer%d", gptimer_id); | 236 | if (!np) |
160 | omap_hwmod_setup_one(name); | 237 | return -ENODEV; |
161 | oh = omap_hwmod_lookup(name); | 238 | |
239 | of_property_read_string_index(np, "ti,hwmods", 0, &oh_name); | ||
240 | if (!oh_name) | ||
241 | return -ENODEV; | ||
242 | |||
243 | timer->irq = irq_of_parse_and_map(np, 0); | ||
244 | if (!timer->irq) | ||
245 | return -ENXIO; | ||
246 | |||
247 | timer->io_base = of_iomap(np, 0); | ||
248 | |||
249 | of_node_put(np); | ||
250 | } else { | ||
251 | if (omap_dm_timer_reserve_systimer(gptimer_id)) | ||
252 | return -ENODEV; | ||
253 | |||
254 | sprintf(name, "timer%d", gptimer_id); | ||
255 | oh_name = name; | ||
256 | } | ||
257 | |||
258 | oh = omap_hwmod_lookup(oh_name); | ||
162 | if (!oh) | 259 | if (!oh) |
163 | return -ENODEV; | 260 | return -ENODEV; |
164 | 261 | ||
165 | r = omap_hwmod_get_resource_byname(oh, IORESOURCE_IRQ, NULL, &irq_rsrc); | 262 | if (!of_have_populated_dt()) { |
166 | if (r) | 263 | r = omap_hwmod_get_resource_byname(oh, IORESOURCE_IRQ, NULL, |
167 | return -ENXIO; | 264 | &irq); |
168 | timer->irq = irq_rsrc.start; | 265 | if (r) |
266 | return -ENXIO; | ||
267 | timer->irq = irq.start; | ||
169 | 268 | ||
170 | r = omap_hwmod_get_resource_byname(oh, IORESOURCE_MEM, NULL, &mem_rsrc); | 269 | r = omap_hwmod_get_resource_byname(oh, IORESOURCE_MEM, NULL, |
171 | if (r) | 270 | &mem); |
172 | return -ENXIO; | 271 | if (r) |
173 | timer->phys_base = mem_rsrc.start; | 272 | return -ENXIO; |
174 | size = mem_rsrc.end - mem_rsrc.start; | 273 | |
274 | /* Static mapping, never released */ | ||
275 | timer->io_base = ioremap(mem.start, mem.end - mem.start); | ||
276 | } | ||
175 | 277 | ||
176 | /* Static mapping, never released */ | ||
177 | timer->io_base = ioremap(timer->phys_base, size); | ||
178 | if (!timer->io_base) | 278 | if (!timer->io_base) |
179 | return -ENXIO; | 279 | return -ENXIO; |
180 | 280 | ||
@@ -183,42 +283,56 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, | |||
183 | if (IS_ERR(timer->fclk)) | 283 | if (IS_ERR(timer->fclk)) |
184 | return -ENODEV; | 284 | return -ENODEV; |
185 | 285 | ||
186 | omap_hwmod_enable(oh); | 286 | /* FIXME: Need to remove hard-coded test on timer ID */ |
187 | |||
188 | if (omap_dm_timer_reserve_systimer(gptimer_id)) | ||
189 | return -ENODEV; | ||
190 | |||
191 | if (gptimer_id != 12) { | 287 | if (gptimer_id != 12) { |
192 | struct clk *src; | 288 | struct clk *src; |
193 | 289 | ||
194 | src = clk_get(NULL, fck_source); | 290 | src = clk_get(NULL, fck_source); |
195 | if (IS_ERR(src)) { | 291 | if (IS_ERR(src)) { |
196 | res = -EINVAL; | 292 | r = -EINVAL; |
197 | } else { | 293 | } else { |
198 | res = __omap_dm_timer_set_source(timer->fclk, src); | 294 | r = clk_set_parent(timer->fclk, src); |
199 | if (IS_ERR_VALUE(res)) | 295 | if (IS_ERR_VALUE(r)) |
200 | pr_warning("%s: timer%i cannot set source\n", | 296 | pr_warn("%s: %s cannot set source\n", |
201 | __func__, gptimer_id); | 297 | __func__, oh->name); |
202 | clk_put(src); | 298 | clk_put(src); |
203 | } | 299 | } |
204 | } | 300 | } |
301 | |||
302 | omap_hwmod_setup_one(oh_name); | ||
303 | omap_hwmod_enable(oh); | ||
205 | __omap_dm_timer_init_regs(timer); | 304 | __omap_dm_timer_init_regs(timer); |
206 | __omap_dm_timer_reset(timer, 1, 1); | ||
207 | timer->posted = 1; | ||
208 | 305 | ||
209 | timer->rate = clk_get_rate(timer->fclk); | 306 | if (posted) |
307 | __omap_dm_timer_enable_posted(timer); | ||
308 | |||
309 | /* Check that the intended posted configuration matches the actual */ | ||
310 | if (posted != timer->posted) | ||
311 | return -EINVAL; | ||
210 | 312 | ||
313 | timer->rate = clk_get_rate(timer->fclk); | ||
211 | timer->reserved = 1; | 314 | timer->reserved = 1; |
212 | 315 | ||
213 | return res; | 316 | return r; |
214 | } | 317 | } |
215 | 318 | ||
216 | static void __init omap2_gp_clockevent_init(int gptimer_id, | 319 | static void __init omap2_gp_clockevent_init(int gptimer_id, |
217 | const char *fck_source) | 320 | const char *fck_source, |
321 | const char *property) | ||
218 | { | 322 | { |
219 | int res; | 323 | int res; |
220 | 324 | ||
221 | res = omap_dm_timer_init_one(&clkev, gptimer_id, fck_source); | 325 | clkev.errata = omap_dm_timer_get_errata(); |
326 | |||
327 | /* | ||
328 | * For clock-event timers we never read the timer counter and | ||
329 | * so we are not impacted by errata i103 and i767. Therefore, | ||
330 | * we can safely ignore this errata for clock-event timers. | ||
331 | */ | ||
332 | __omap_dm_timer_override_errata(&clkev, OMAP_TIMER_ERRATA_I103_I767); | ||
333 | |||
334 | res = omap_dm_timer_init_one(&clkev, gptimer_id, fck_source, property, | ||
335 | OMAP_TIMER_POSTED); | ||
222 | BUG_ON(res); | 336 | BUG_ON(res); |
223 | 337 | ||
224 | omap2_gp_timer_irq.dev_id = &clkev; | 338 | omap2_gp_timer_irq.dev_id = &clkev; |
@@ -251,7 +365,8 @@ static bool use_gptimer_clksrc; | |||
251 | */ | 365 | */ |
252 | static cycle_t clocksource_read_cycles(struct clocksource *cs) | 366 | static cycle_t clocksource_read_cycles(struct clocksource *cs) |
253 | { | 367 | { |
254 | return (cycle_t)__omap_dm_timer_read_counter(&clksrc, 1); | 368 | return (cycle_t)__omap_dm_timer_read_counter(&clksrc, |
369 | OMAP_TIMER_NONPOSTED); | ||
255 | } | 370 | } |
256 | 371 | ||
257 | static struct clocksource clocksource_gpt = { | 372 | static struct clocksource clocksource_gpt = { |
@@ -265,21 +380,41 @@ static struct clocksource clocksource_gpt = { | |||
265 | static u32 notrace dmtimer_read_sched_clock(void) | 380 | static u32 notrace dmtimer_read_sched_clock(void) |
266 | { | 381 | { |
267 | if (clksrc.reserved) | 382 | if (clksrc.reserved) |
268 | return __omap_dm_timer_read_counter(&clksrc, 1); | 383 | return __omap_dm_timer_read_counter(&clksrc, |
384 | OMAP_TIMER_NONPOSTED); | ||
269 | 385 | ||
270 | return 0; | 386 | return 0; |
271 | } | 387 | } |
272 | 388 | ||
273 | #ifdef CONFIG_OMAP_32K_TIMER | 389 | static struct of_device_id omap_counter_match[] __initdata = { |
390 | { .compatible = "ti,omap-counter32k", }, | ||
391 | { } | ||
392 | }; | ||
393 | |||
274 | /* Setup free-running counter for clocksource */ | 394 | /* Setup free-running counter for clocksource */ |
275 | static int __init omap2_sync32k_clocksource_init(void) | 395 | static int __init omap2_sync32k_clocksource_init(void) |
276 | { | 396 | { |
277 | int ret; | 397 | int ret; |
398 | struct device_node *np = NULL; | ||
278 | struct omap_hwmod *oh; | 399 | struct omap_hwmod *oh; |
279 | void __iomem *vbase; | 400 | void __iomem *vbase; |
280 | const char *oh_name = "counter_32k"; | 401 | const char *oh_name = "counter_32k"; |
281 | 402 | ||
282 | /* | 403 | /* |
404 | * If device-tree is present, then search the DT blob | ||
405 | * to see if the 32kHz counter is supported. | ||
406 | */ | ||
407 | if (of_have_populated_dt()) { | ||
408 | np = omap_get_timer_dt(omap_counter_match, NULL); | ||
409 | if (!np) | ||
410 | return -ENODEV; | ||
411 | |||
412 | of_property_read_string_index(np, "ti,hwmods", 0, &oh_name); | ||
413 | if (!oh_name) | ||
414 | return -ENODEV; | ||
415 | } | ||
416 | |||
417 | /* | ||
283 | * First check hwmod data is available for sync32k counter | 418 | * First check hwmod data is available for sync32k counter |
284 | */ | 419 | */ |
285 | oh = omap_hwmod_lookup(oh_name); | 420 | oh = omap_hwmod_lookup(oh_name); |
@@ -288,7 +423,13 @@ static int __init omap2_sync32k_clocksource_init(void) | |||
288 | 423 | ||
289 | omap_hwmod_setup_one(oh_name); | 424 | omap_hwmod_setup_one(oh_name); |
290 | 425 | ||
291 | vbase = omap_hwmod_get_mpu_rt_va(oh); | 426 | if (np) { |
427 | vbase = of_iomap(np, 0); | ||
428 | of_node_put(np); | ||
429 | } else { | ||
430 | vbase = omap_hwmod_get_mpu_rt_va(oh); | ||
431 | } | ||
432 | |||
292 | if (!vbase) { | 433 | if (!vbase) { |
293 | pr_warn("%s: failed to get counter_32k resource\n", __func__); | 434 | pr_warn("%s: failed to get counter_32k resource\n", __func__); |
294 | return -ENXIO; | 435 | return -ENXIO; |
@@ -310,23 +451,21 @@ static int __init omap2_sync32k_clocksource_init(void) | |||
310 | 451 | ||
311 | return ret; | 452 | return ret; |
312 | } | 453 | } |
313 | #else | ||
314 | static inline int omap2_sync32k_clocksource_init(void) | ||
315 | { | ||
316 | return -ENODEV; | ||
317 | } | ||
318 | #endif | ||
319 | 454 | ||
320 | static void __init omap2_gptimer_clocksource_init(int gptimer_id, | 455 | static void __init omap2_gptimer_clocksource_init(int gptimer_id, |
321 | const char *fck_source) | 456 | const char *fck_source) |
322 | { | 457 | { |
323 | int res; | 458 | int res; |
324 | 459 | ||
325 | res = omap_dm_timer_init_one(&clksrc, gptimer_id, fck_source); | 460 | clksrc.errata = omap_dm_timer_get_errata(); |
461 | |||
462 | res = omap_dm_timer_init_one(&clksrc, gptimer_id, fck_source, NULL, | ||
463 | OMAP_TIMER_NONPOSTED); | ||
326 | BUG_ON(res); | 464 | BUG_ON(res); |
327 | 465 | ||
328 | __omap_dm_timer_load_start(&clksrc, | 466 | __omap_dm_timer_load_start(&clksrc, |
329 | OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 1); | 467 | OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, |
468 | OMAP_TIMER_NONPOSTED); | ||
330 | setup_sched_clock(dmtimer_read_sched_clock, 32, clksrc.rate); | 469 | setup_sched_clock(dmtimer_read_sched_clock, 32, clksrc.rate); |
331 | 470 | ||
332 | if (clocksource_register_hz(&clocksource_gpt, clksrc.rate)) | 471 | if (clocksource_register_hz(&clocksource_gpt, clksrc.rate)) |
@@ -337,25 +476,6 @@ static void __init omap2_gptimer_clocksource_init(int gptimer_id, | |||
337 | gptimer_id, clksrc.rate); | 476 | gptimer_id, clksrc.rate); |
338 | } | 477 | } |
339 | 478 | ||
340 | static void __init omap2_clocksource_init(int gptimer_id, | ||
341 | const char *fck_source) | ||
342 | { | ||
343 | /* | ||
344 | * First give preference to kernel parameter configuration | ||
345 | * by user (clocksource="gp_timer"). | ||
346 | * | ||
347 | * In case of missing kernel parameter for clocksource, | ||
348 | * first check for availability for 32k-sync timer, in case | ||
349 | * of failure in finding 32k_counter module or registering | ||
350 | * it as clocksource, execution will fallback to gp-timer. | ||
351 | */ | ||
352 | if (use_gptimer_clksrc == true) | ||
353 | omap2_gptimer_clocksource_init(gptimer_id, fck_source); | ||
354 | else if (omap2_sync32k_clocksource_init()) | ||
355 | /* Fall back to gp-timer code */ | ||
356 | omap2_gptimer_clocksource_init(gptimer_id, fck_source); | ||
357 | } | ||
358 | |||
359 | #ifdef CONFIG_SOC_HAS_REALTIME_COUNTER | 479 | #ifdef CONFIG_SOC_HAS_REALTIME_COUNTER |
360 | /* | 480 | /* |
361 | * The realtime counter also called master counter, is a free-running | 481 | * The realtime counter also called master counter, is a free-running |
@@ -434,48 +554,65 @@ static inline void __init realtime_counter_init(void) | |||
434 | {} | 554 | {} |
435 | #endif | 555 | #endif |
436 | 556 | ||
437 | #define OMAP_SYS_TIMER_INIT(name, clkev_nr, clkev_src, \ | 557 | #define OMAP_SYS_GP_TIMER_INIT(name, clkev_nr, clkev_src, clkev_prop, \ |
558 | clksrc_nr, clksrc_src) \ | ||
559 | static void __init omap##name##_gptimer_timer_init(void) \ | ||
560 | { \ | ||
561 | omap_dmtimer_init(); \ | ||
562 | omap2_gp_clockevent_init((clkev_nr), clkev_src, clkev_prop); \ | ||
563 | omap2_gptimer_clocksource_init((clksrc_nr), clksrc_src); \ | ||
564 | } | ||
565 | |||
566 | #define OMAP_SYS_32K_TIMER_INIT(name, clkev_nr, clkev_src, clkev_prop, \ | ||
438 | clksrc_nr, clksrc_src) \ | 567 | clksrc_nr, clksrc_src) \ |
439 | static void __init omap##name##_timer_init(void) \ | 568 | static void __init omap##name##_sync32k_timer_init(void) \ |
440 | { \ | 569 | { \ |
441 | omap2_gp_clockevent_init((clkev_nr), clkev_src); \ | 570 | omap_dmtimer_init(); \ |
442 | omap2_clocksource_init((clksrc_nr), clksrc_src); \ | 571 | omap2_gp_clockevent_init((clkev_nr), clkev_src, clkev_prop); \ |
572 | /* Enable the use of clocksource="gp_timer" kernel parameter */ \ | ||
573 | if (use_gptimer_clksrc) \ | ||
574 | omap2_gptimer_clocksource_init((clksrc_nr), clksrc_src);\ | ||
575 | else \ | ||
576 | omap2_sync32k_clocksource_init(); \ | ||
443 | } | 577 | } |
444 | 578 | ||
445 | #define OMAP_SYS_TIMER(name) \ | 579 | #define OMAP_SYS_TIMER(name, clksrc) \ |
446 | struct sys_timer omap##name##_timer = { \ | 580 | struct sys_timer omap##name##_timer = { \ |
447 | .init = omap##name##_timer_init, \ | 581 | .init = omap##name##_##clksrc##_timer_init, \ |
448 | }; | 582 | }; |
449 | 583 | ||
450 | #ifdef CONFIG_ARCH_OMAP2 | 584 | #ifdef CONFIG_ARCH_OMAP2 |
451 | OMAP_SYS_TIMER_INIT(2, 1, OMAP2_CLKEV_SOURCE, 2, OMAP2_MPU_SOURCE) | 585 | OMAP_SYS_32K_TIMER_INIT(2, 1, OMAP2_32K_SOURCE, "ti,timer-alwon", |
452 | OMAP_SYS_TIMER(2) | 586 | 2, OMAP2_MPU_SOURCE); |
453 | #endif | 587 | OMAP_SYS_TIMER(2, sync32k); |
588 | #endif /* CONFIG_ARCH_OMAP2 */ | ||
454 | 589 | ||
455 | #ifdef CONFIG_ARCH_OMAP3 | 590 | #ifdef CONFIG_ARCH_OMAP3 |
456 | OMAP_SYS_TIMER_INIT(3, 1, OMAP3_CLKEV_SOURCE, 2, OMAP3_MPU_SOURCE) | 591 | OMAP_SYS_32K_TIMER_INIT(3, 1, OMAP3_32K_SOURCE, "ti,timer-alwon", |
457 | OMAP_SYS_TIMER(3) | 592 | 2, OMAP3_MPU_SOURCE); |
458 | OMAP_SYS_TIMER_INIT(3_secure, OMAP3_SECURE_TIMER, OMAP3_CLKEV_SOURCE, | 593 | OMAP_SYS_TIMER(3, sync32k); |
459 | 2, OMAP3_MPU_SOURCE) | 594 | OMAP_SYS_32K_TIMER_INIT(3_secure, 12, OMAP3_32K_SOURCE, "ti,timer-secure", |
460 | OMAP_SYS_TIMER(3_secure) | 595 | 2, OMAP3_MPU_SOURCE); |
461 | #endif | 596 | OMAP_SYS_TIMER(3_secure, sync32k); |
597 | OMAP_SYS_GP_TIMER_INIT(3_gp, 1, OMAP3_MPU_SOURCE, "ti,timer-alwon", | ||
598 | 2, OMAP3_MPU_SOURCE); | ||
599 | OMAP_SYS_TIMER(3_gp, gptimer); | ||
600 | #endif /* CONFIG_ARCH_OMAP3 */ | ||
462 | 601 | ||
463 | #ifdef CONFIG_SOC_AM33XX | 602 | #ifdef CONFIG_SOC_AM33XX |
464 | OMAP_SYS_TIMER_INIT(3_am33xx, 1, OMAP4_MPU_SOURCE, 2, OMAP4_MPU_SOURCE) | 603 | OMAP_SYS_GP_TIMER_INIT(3_am33xx, 1, OMAP4_MPU_SOURCE, "ti,timer-alwon", |
465 | OMAP_SYS_TIMER(3_am33xx) | 604 | 2, OMAP4_MPU_SOURCE); |
466 | #endif | 605 | OMAP_SYS_TIMER(3_am33xx, gptimer); |
606 | #endif /* CONFIG_SOC_AM33XX */ | ||
467 | 607 | ||
468 | #ifdef CONFIG_ARCH_OMAP4 | 608 | #ifdef CONFIG_ARCH_OMAP4 |
609 | OMAP_SYS_32K_TIMER_INIT(4, 1, OMAP4_32K_SOURCE, "ti,timer-alwon", | ||
610 | 2, OMAP4_MPU_SOURCE); | ||
469 | #ifdef CONFIG_LOCAL_TIMERS | 611 | #ifdef CONFIG_LOCAL_TIMERS |
470 | static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, | 612 | static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, OMAP44XX_LOCAL_TWD_BASE, 29); |
471 | OMAP44XX_LOCAL_TWD_BASE, 29); | 613 | static void __init omap4_local_timer_init(void) |
472 | #endif | ||
473 | |||
474 | static void __init omap4_timer_init(void) | ||
475 | { | 614 | { |
476 | omap2_gp_clockevent_init(1, OMAP4_CLKEV_SOURCE); | 615 | omap4_sync32k_timer_init(); |
477 | omap2_clocksource_init(2, OMAP4_MPU_SOURCE); | ||
478 | #ifdef CONFIG_LOCAL_TIMERS | ||
479 | /* Local timers are not supprted on OMAP4430 ES1.0 */ | 616 | /* Local timers are not supprted on OMAP4430 ES1.0 */ |
480 | if (omap_rev() != OMAP4430_REV_ES1_0) { | 617 | if (omap_rev() != OMAP4430_REV_ES1_0) { |
481 | int err; | 618 | int err; |
@@ -489,26 +626,32 @@ static void __init omap4_timer_init(void) | |||
489 | if (err) | 626 | if (err) |
490 | pr_err("twd_local_timer_register failed %d\n", err); | 627 | pr_err("twd_local_timer_register failed %d\n", err); |
491 | } | 628 | } |
492 | #endif | ||
493 | } | 629 | } |
494 | OMAP_SYS_TIMER(4) | 630 | #else /* CONFIG_LOCAL_TIMERS */ |
495 | #endif | 631 | static inline void omap4_local_timer_init(void) |
632 | { | ||
633 | omap4_sync32_timer_init(); | ||
634 | } | ||
635 | #endif /* CONFIG_LOCAL_TIMERS */ | ||
636 | OMAP_SYS_TIMER(4, local); | ||
637 | #endif /* CONFIG_ARCH_OMAP4 */ | ||
496 | 638 | ||
497 | #ifdef CONFIG_SOC_OMAP5 | 639 | #ifdef CONFIG_SOC_OMAP5 |
498 | static void __init omap5_timer_init(void) | 640 | OMAP_SYS_32K_TIMER_INIT(5, 1, OMAP4_32K_SOURCE, "ti,timer-alwon", |
641 | 2, OMAP4_MPU_SOURCE); | ||
642 | static void __init omap5_realtime_timer_init(void) | ||
499 | { | 643 | { |
500 | int err; | 644 | int err; |
501 | 645 | ||
502 | omap2_gp_clockevent_init(1, OMAP4_CLKEV_SOURCE); | 646 | omap5_sync32k_timer_init(); |
503 | omap2_clocksource_init(2, OMAP4_MPU_SOURCE); | ||
504 | realtime_counter_init(); | 647 | realtime_counter_init(); |
505 | 648 | ||
506 | err = arch_timer_of_register(); | 649 | err = arch_timer_of_register(); |
507 | if (err) | 650 | if (err) |
508 | pr_err("%s: arch_timer_register failed %d\n", __func__, err); | 651 | pr_err("%s: arch_timer_register failed %d\n", __func__, err); |
509 | } | 652 | } |
510 | OMAP_SYS_TIMER(5) | 653 | OMAP_SYS_TIMER(5, realtime); |
511 | #endif | 654 | #endif /* CONFIG_SOC_OMAP5 */ |
512 | 655 | ||
513 | /** | 656 | /** |
514 | * omap_timer_init - build and register timer device with an | 657 | * omap_timer_init - build and register timer device with an |
@@ -560,6 +703,7 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused) | |||
560 | if (timer_dev_attr) | 703 | if (timer_dev_attr) |
561 | pdata->timer_capability = timer_dev_attr->timer_capability; | 704 | pdata->timer_capability = timer_dev_attr->timer_capability; |
562 | 705 | ||
706 | pdata->timer_errata = omap_dm_timer_get_errata(); | ||
563 | pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count; | 707 | pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count; |
564 | 708 | ||
565 | pdev = omap_device_build(name, id, oh, pdata, sizeof(*pdata), | 709 | pdev = omap_device_build(name, id, oh, pdata, sizeof(*pdata), |
@@ -586,6 +730,10 @@ static int __init omap2_dm_timer_init(void) | |||
586 | { | 730 | { |
587 | int ret; | 731 | int ret; |
588 | 732 | ||
733 | /* If dtb is there, the devices will be created dynamically */ | ||
734 | if (of_have_populated_dt()) | ||
735 | return -ENODEV; | ||
736 | |||
589 | ret = omap_hwmod_for_each_by_class("timer", omap_timer_init, NULL); | 737 | ret = omap_hwmod_for_each_by_class("timer", omap_timer_init, NULL); |
590 | if (unlikely(ret)) { | 738 | if (unlikely(ret)) { |
591 | pr_err("%s: device registration failed.\n", __func__); | 739 | pr_err("%s: device registration failed.\n", __func__); |