diff options
Diffstat (limited to 'arch/arm/mach-omap2/timer.c')
-rw-r--r-- | arch/arm/mach-omap2/timer.c | 391 |
1 files changed, 271 insertions, 120 deletions
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c index 69e46631a7cd..7016637b531c 100644 --- a/arch/arm/mach-omap2/timer.c +++ b/arch/arm/mach-omap2/timer.c | |||
@@ -37,16 +37,21 @@ | |||
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> |
43 | #include <asm/sched_clock.h> | 47 | #include <asm/sched_clock.h> |
44 | 48 | ||
45 | #include <asm/arch_timer.h> | 49 | #include <asm/arch_timer.h> |
46 | #include <plat/omap_hwmod.h> | 50 | #include "omap_hwmod.h" |
47 | #include <plat/omap_device.h> | 51 | #include "omap_device.h" |
52 | #include <plat/counter-32k.h> | ||
48 | #include <plat/dmtimer.h> | 53 | #include <plat/dmtimer.h> |
49 | #include <plat/omap-pm.h> | 54 | #include "omap-pm.h" |
50 | 55 | ||
51 | #include "soc.h" | 56 | #include "soc.h" |
52 | #include "common.h" | 57 | #include "common.h" |
@@ -61,18 +66,6 @@ | |||
61 | #define OMAP3_32K_SOURCE "omap_32k_fck" | 66 | #define OMAP3_32K_SOURCE "omap_32k_fck" |
62 | #define OMAP4_32K_SOURCE "sys_32k_ck" | 67 | #define OMAP4_32K_SOURCE "sys_32k_ck" |
63 | 68 | ||
64 | #ifdef CONFIG_OMAP_32K_TIMER | ||
65 | #define OMAP2_CLKEV_SOURCE OMAP2_32K_SOURCE | ||
66 | #define OMAP3_CLKEV_SOURCE OMAP3_32K_SOURCE | ||
67 | #define OMAP4_CLKEV_SOURCE OMAP4_32K_SOURCE | ||
68 | #define OMAP3_SECURE_TIMER 12 | ||
69 | #else | ||
70 | #define OMAP2_CLKEV_SOURCE OMAP2_MPU_SOURCE | ||
71 | #define OMAP3_CLKEV_SOURCE OMAP3_MPU_SOURCE | ||
72 | #define OMAP4_CLKEV_SOURCE OMAP4_MPU_SOURCE | ||
73 | #define OMAP3_SECURE_TIMER 1 | ||
74 | #endif | ||
75 | |||
76 | #define REALTIME_COUNTER_BASE 0x48243200 | 69 | #define REALTIME_COUNTER_BASE 0x48243200 |
77 | #define INCREMENTER_NUMERATOR_OFFSET 0x10 | 70 | #define INCREMENTER_NUMERATOR_OFFSET 0x10 |
78 | #define INCREMENTER_DENUMERATOR_RELOAD_OFFSET 0x14 | 71 | #define INCREMENTER_DENUMERATOR_RELOAD_OFFSET 0x14 |
@@ -103,7 +96,7 @@ static int omap2_gp_timer_set_next_event(unsigned long cycles, | |||
103 | struct clock_event_device *evt) | 96 | struct clock_event_device *evt) |
104 | { | 97 | { |
105 | __omap_dm_timer_load_start(&clkev, OMAP_TIMER_CTRL_ST, | 98 | __omap_dm_timer_load_start(&clkev, OMAP_TIMER_CTRL_ST, |
106 | 0xffffffff - cycles, 1); | 99 | 0xffffffff - cycles, OMAP_TIMER_POSTED); |
107 | 100 | ||
108 | return 0; | 101 | return 0; |
109 | } | 102 | } |
@@ -113,7 +106,7 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode, | |||
113 | { | 106 | { |
114 | u32 period; | 107 | u32 period; |
115 | 108 | ||
116 | __omap_dm_timer_stop(&clkev, 1, clkev.rate); | 109 | __omap_dm_timer_stop(&clkev, OMAP_TIMER_POSTED, clkev.rate); |
117 | 110 | ||
118 | switch (mode) { | 111 | switch (mode) { |
119 | case CLOCK_EVT_MODE_PERIODIC: | 112 | case CLOCK_EVT_MODE_PERIODIC: |
@@ -121,10 +114,10 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode, | |||
121 | period -= 1; | 114 | period -= 1; |
122 | /* Looks like we need to first set the load value separately */ | 115 | /* Looks like we need to first set the load value separately */ |
123 | __omap_dm_timer_write(&clkev, OMAP_TIMER_LOAD_REG, | 116 | __omap_dm_timer_write(&clkev, OMAP_TIMER_LOAD_REG, |
124 | 0xffffffff - period, 1); | 117 | 0xffffffff - period, OMAP_TIMER_POSTED); |
125 | __omap_dm_timer_load_start(&clkev, | 118 | __omap_dm_timer_load_start(&clkev, |
126 | OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST, | 119 | OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST, |
127 | 0xffffffff - period, 1); | 120 | 0xffffffff - period, OMAP_TIMER_POSTED); |
128 | break; | 121 | break; |
129 | case CLOCK_EVT_MODE_ONESHOT: | 122 | case CLOCK_EVT_MODE_ONESHOT: |
130 | break; | 123 | break; |
@@ -144,36 +137,144 @@ static struct clock_event_device clockevent_gpt = { | |||
144 | .set_mode = omap2_gp_timer_set_mode, | 137 | .set_mode = omap2_gp_timer_set_mode, |
145 | }; | 138 | }; |
146 | 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 | |||
147 | 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, |
148 | int gptimer_id, | 222 | int gptimer_id, |
149 | const char *fck_source) | 223 | const char *fck_source, |
224 | const char *property, | ||
225 | int posted) | ||
150 | { | 226 | { |
151 | 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; | ||
152 | struct omap_hwmod *oh; | 230 | struct omap_hwmod *oh; |
153 | struct resource irq_rsrc, mem_rsrc; | 231 | struct resource irq, mem; |
154 | size_t size; | 232 | int r = 0; |
155 | int res = 0; | 233 | |
156 | int r; | 234 | if (of_have_populated_dt()) { |
157 | 235 | np = omap_get_timer_dt(omap_timer_match, NULL); | |
158 | sprintf(name, "timer%d", gptimer_id); | 236 | if (!np) |
159 | omap_hwmod_setup_one(name); | 237 | return -ENODEV; |
160 | 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); | ||
161 | if (!oh) | 259 | if (!oh) |
162 | return -ENODEV; | 260 | return -ENODEV; |
163 | 261 | ||
164 | r = omap_hwmod_get_resource_byname(oh, IORESOURCE_IRQ, NULL, &irq_rsrc); | 262 | if (!of_have_populated_dt()) { |
165 | if (r) | 263 | r = omap_hwmod_get_resource_byname(oh, IORESOURCE_IRQ, NULL, |
166 | return -ENXIO; | 264 | &irq); |
167 | timer->irq = irq_rsrc.start; | 265 | if (r) |
266 | return -ENXIO; | ||
267 | timer->irq = irq.start; | ||
168 | 268 | ||
169 | r = omap_hwmod_get_resource_byname(oh, IORESOURCE_MEM, NULL, &mem_rsrc); | 269 | r = omap_hwmod_get_resource_byname(oh, IORESOURCE_MEM, NULL, |
170 | if (r) | 270 | &mem); |
171 | return -ENXIO; | 271 | if (r) |
172 | timer->phys_base = mem_rsrc.start; | 272 | return -ENXIO; |
173 | 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 | } | ||
174 | 277 | ||
175 | /* Static mapping, never released */ | ||
176 | timer->io_base = ioremap(timer->phys_base, size); | ||
177 | if (!timer->io_base) | 278 | if (!timer->io_base) |
178 | return -ENXIO; | 279 | return -ENXIO; |
179 | 280 | ||
@@ -182,42 +283,56 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, | |||
182 | if (IS_ERR(timer->fclk)) | 283 | if (IS_ERR(timer->fclk)) |
183 | return -ENODEV; | 284 | return -ENODEV; |
184 | 285 | ||
185 | omap_hwmod_enable(oh); | 286 | /* FIXME: Need to remove hard-coded test on timer ID */ |
186 | |||
187 | if (omap_dm_timer_reserve_systimer(gptimer_id)) | ||
188 | return -ENODEV; | ||
189 | |||
190 | if (gptimer_id != 12) { | 287 | if (gptimer_id != 12) { |
191 | struct clk *src; | 288 | struct clk *src; |
192 | 289 | ||
193 | src = clk_get(NULL, fck_source); | 290 | src = clk_get(NULL, fck_source); |
194 | if (IS_ERR(src)) { | 291 | if (IS_ERR(src)) { |
195 | res = -EINVAL; | 292 | r = -EINVAL; |
196 | } else { | 293 | } else { |
197 | res = __omap_dm_timer_set_source(timer->fclk, src); | 294 | r = clk_set_parent(timer->fclk, src); |
198 | if (IS_ERR_VALUE(res)) | 295 | if (IS_ERR_VALUE(r)) |
199 | pr_warning("%s: timer%i cannot set source\n", | 296 | pr_warn("%s: %s cannot set source\n", |
200 | __func__, gptimer_id); | 297 | __func__, oh->name); |
201 | clk_put(src); | 298 | clk_put(src); |
202 | } | 299 | } |
203 | } | 300 | } |
301 | |||
302 | omap_hwmod_setup_one(oh_name); | ||
303 | omap_hwmod_enable(oh); | ||
204 | __omap_dm_timer_init_regs(timer); | 304 | __omap_dm_timer_init_regs(timer); |
205 | __omap_dm_timer_reset(timer, 1, 1); | ||
206 | timer->posted = 1; | ||
207 | 305 | ||
208 | 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; | ||
209 | 312 | ||
313 | timer->rate = clk_get_rate(timer->fclk); | ||
210 | timer->reserved = 1; | 314 | timer->reserved = 1; |
211 | 315 | ||
212 | return res; | 316 | return r; |
213 | } | 317 | } |
214 | 318 | ||
215 | static void __init omap2_gp_clockevent_init(int gptimer_id, | 319 | static void __init omap2_gp_clockevent_init(int gptimer_id, |
216 | const char *fck_source) | 320 | const char *fck_source, |
321 | const char *property) | ||
217 | { | 322 | { |
218 | int res; | 323 | int res; |
219 | 324 | ||
220 | 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); | ||
221 | BUG_ON(res); | 336 | BUG_ON(res); |
222 | 337 | ||
223 | omap2_gp_timer_irq.dev_id = &clkev; | 338 | omap2_gp_timer_irq.dev_id = &clkev; |
@@ -250,7 +365,8 @@ static bool use_gptimer_clksrc; | |||
250 | */ | 365 | */ |
251 | static cycle_t clocksource_read_cycles(struct clocksource *cs) | 366 | static cycle_t clocksource_read_cycles(struct clocksource *cs) |
252 | { | 367 | { |
253 | return (cycle_t)__omap_dm_timer_read_counter(&clksrc, 1); | 368 | return (cycle_t)__omap_dm_timer_read_counter(&clksrc, |
369 | OMAP_TIMER_NONPOSTED); | ||
254 | } | 370 | } |
255 | 371 | ||
256 | static struct clocksource clocksource_gpt = { | 372 | static struct clocksource clocksource_gpt = { |
@@ -264,21 +380,41 @@ static struct clocksource clocksource_gpt = { | |||
264 | static u32 notrace dmtimer_read_sched_clock(void) | 380 | static u32 notrace dmtimer_read_sched_clock(void) |
265 | { | 381 | { |
266 | if (clksrc.reserved) | 382 | if (clksrc.reserved) |
267 | return __omap_dm_timer_read_counter(&clksrc, 1); | 383 | return __omap_dm_timer_read_counter(&clksrc, |
384 | OMAP_TIMER_NONPOSTED); | ||
268 | 385 | ||
269 | return 0; | 386 | return 0; |
270 | } | 387 | } |
271 | 388 | ||
272 | #ifdef CONFIG_OMAP_32K_TIMER | 389 | static struct of_device_id omap_counter_match[] __initdata = { |
390 | { .compatible = "ti,omap-counter32k", }, | ||
391 | { } | ||
392 | }; | ||
393 | |||
273 | /* Setup free-running counter for clocksource */ | 394 | /* Setup free-running counter for clocksource */ |
274 | static int __init omap2_sync32k_clocksource_init(void) | 395 | static int __init omap2_sync32k_clocksource_init(void) |
275 | { | 396 | { |
276 | int ret; | 397 | int ret; |
398 | struct device_node *np = NULL; | ||
277 | struct omap_hwmod *oh; | 399 | struct omap_hwmod *oh; |
278 | void __iomem *vbase; | 400 | void __iomem *vbase; |
279 | const char *oh_name = "counter_32k"; | 401 | const char *oh_name = "counter_32k"; |
280 | 402 | ||
281 | /* | 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 | /* | ||
282 | * First check hwmod data is available for sync32k counter | 418 | * First check hwmod data is available for sync32k counter |
283 | */ | 419 | */ |
284 | oh = omap_hwmod_lookup(oh_name); | 420 | oh = omap_hwmod_lookup(oh_name); |
@@ -287,7 +423,13 @@ static int __init omap2_sync32k_clocksource_init(void) | |||
287 | 423 | ||
288 | omap_hwmod_setup_one(oh_name); | 424 | omap_hwmod_setup_one(oh_name); |
289 | 425 | ||
290 | 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 | |||
291 | if (!vbase) { | 433 | if (!vbase) { |
292 | pr_warn("%s: failed to get counter_32k resource\n", __func__); | 434 | pr_warn("%s: failed to get counter_32k resource\n", __func__); |
293 | return -ENXIO; | 435 | return -ENXIO; |
@@ -309,23 +451,21 @@ static int __init omap2_sync32k_clocksource_init(void) | |||
309 | 451 | ||
310 | return ret; | 452 | return ret; |
311 | } | 453 | } |
312 | #else | ||
313 | static inline int omap2_sync32k_clocksource_init(void) | ||
314 | { | ||
315 | return -ENODEV; | ||
316 | } | ||
317 | #endif | ||
318 | 454 | ||
319 | static void __init omap2_gptimer_clocksource_init(int gptimer_id, | 455 | static void __init omap2_gptimer_clocksource_init(int gptimer_id, |
320 | const char *fck_source) | 456 | const char *fck_source) |
321 | { | 457 | { |
322 | int res; | 458 | int res; |
323 | 459 | ||
324 | 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); | ||
325 | BUG_ON(res); | 464 | BUG_ON(res); |
326 | 465 | ||
327 | __omap_dm_timer_load_start(&clksrc, | 466 | __omap_dm_timer_load_start(&clksrc, |
328 | OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, 1); | 467 | OMAP_TIMER_CTRL_ST | OMAP_TIMER_CTRL_AR, 0, |
468 | OMAP_TIMER_NONPOSTED); | ||
329 | setup_sched_clock(dmtimer_read_sched_clock, 32, clksrc.rate); | 469 | setup_sched_clock(dmtimer_read_sched_clock, 32, clksrc.rate); |
330 | 470 | ||
331 | if (clocksource_register_hz(&clocksource_gpt, clksrc.rate)) | 471 | if (clocksource_register_hz(&clocksource_gpt, clksrc.rate)) |
@@ -336,25 +476,6 @@ static void __init omap2_gptimer_clocksource_init(int gptimer_id, | |||
336 | gptimer_id, clksrc.rate); | 476 | gptimer_id, clksrc.rate); |
337 | } | 477 | } |
338 | 478 | ||
339 | static void __init omap2_clocksource_init(int gptimer_id, | ||
340 | const char *fck_source) | ||
341 | { | ||
342 | /* | ||
343 | * First give preference to kernel parameter configuration | ||
344 | * by user (clocksource="gp_timer"). | ||
345 | * | ||
346 | * In case of missing kernel parameter for clocksource, | ||
347 | * first check for availability for 32k-sync timer, in case | ||
348 | * of failure in finding 32k_counter module or registering | ||
349 | * it as clocksource, execution will fallback to gp-timer. | ||
350 | */ | ||
351 | if (use_gptimer_clksrc == true) | ||
352 | omap2_gptimer_clocksource_init(gptimer_id, fck_source); | ||
353 | else if (omap2_sync32k_clocksource_init()) | ||
354 | /* Fall back to gp-timer code */ | ||
355 | omap2_gptimer_clocksource_init(gptimer_id, fck_source); | ||
356 | } | ||
357 | |||
358 | #ifdef CONFIG_SOC_HAS_REALTIME_COUNTER | 479 | #ifdef CONFIG_SOC_HAS_REALTIME_COUNTER |
359 | /* | 480 | /* |
360 | * The realtime counter also called master counter, is a free-running | 481 | * The realtime counter also called master counter, is a free-running |
@@ -433,48 +554,65 @@ static inline void __init realtime_counter_init(void) | |||
433 | {} | 554 | {} |
434 | #endif | 555 | #endif |
435 | 556 | ||
436 | #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, \ | ||
437 | clksrc_nr, clksrc_src) \ | 567 | clksrc_nr, clksrc_src) \ |
438 | static void __init omap##name##_timer_init(void) \ | 568 | static void __init omap##name##_sync32k_timer_init(void) \ |
439 | { \ | 569 | { \ |
440 | omap2_gp_clockevent_init((clkev_nr), clkev_src); \ | 570 | omap_dmtimer_init(); \ |
441 | 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(); \ | ||
442 | } | 577 | } |
443 | 578 | ||
444 | #define OMAP_SYS_TIMER(name) \ | 579 | #define OMAP_SYS_TIMER(name, clksrc) \ |
445 | struct sys_timer omap##name##_timer = { \ | 580 | struct sys_timer omap##name##_timer = { \ |
446 | .init = omap##name##_timer_init, \ | 581 | .init = omap##name##_##clksrc##_timer_init, \ |
447 | }; | 582 | }; |
448 | 583 | ||
449 | #ifdef CONFIG_ARCH_OMAP2 | 584 | #ifdef CONFIG_ARCH_OMAP2 |
450 | 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", |
451 | OMAP_SYS_TIMER(2) | 586 | 2, OMAP2_MPU_SOURCE); |
452 | #endif | 587 | OMAP_SYS_TIMER(2, sync32k); |
588 | #endif /* CONFIG_ARCH_OMAP2 */ | ||
453 | 589 | ||
454 | #ifdef CONFIG_ARCH_OMAP3 | 590 | #ifdef CONFIG_ARCH_OMAP3 |
455 | 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", |
456 | OMAP_SYS_TIMER(3) | 592 | 2, OMAP3_MPU_SOURCE); |
457 | OMAP_SYS_TIMER_INIT(3_secure, OMAP3_SECURE_TIMER, OMAP3_CLKEV_SOURCE, | 593 | OMAP_SYS_TIMER(3, sync32k); |
458 | 2, OMAP3_MPU_SOURCE) | 594 | OMAP_SYS_32K_TIMER_INIT(3_secure, 12, OMAP3_32K_SOURCE, "ti,timer-secure", |
459 | OMAP_SYS_TIMER(3_secure) | 595 | 2, OMAP3_MPU_SOURCE); |
460 | #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 */ | ||
461 | 601 | ||
462 | #ifdef CONFIG_SOC_AM33XX | 602 | #ifdef CONFIG_SOC_AM33XX |
463 | 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", |
464 | OMAP_SYS_TIMER(3_am33xx) | 604 | 2, OMAP4_MPU_SOURCE); |
465 | #endif | 605 | OMAP_SYS_TIMER(3_am33xx, gptimer); |
606 | #endif /* CONFIG_SOC_AM33XX */ | ||
466 | 607 | ||
467 | #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); | ||
468 | #ifdef CONFIG_LOCAL_TIMERS | 611 | #ifdef CONFIG_LOCAL_TIMERS |
469 | static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, | 612 | static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, OMAP44XX_LOCAL_TWD_BASE, 29); |
470 | OMAP44XX_LOCAL_TWD_BASE, 29); | 613 | static void __init omap4_local_timer_init(void) |
471 | #endif | ||
472 | |||
473 | static void __init omap4_timer_init(void) | ||
474 | { | 614 | { |
475 | omap2_gp_clockevent_init(1, OMAP4_CLKEV_SOURCE); | 615 | omap4_sync32k_timer_init(); |
476 | omap2_clocksource_init(2, OMAP4_MPU_SOURCE); | ||
477 | #ifdef CONFIG_LOCAL_TIMERS | ||
478 | /* Local timers are not supprted on OMAP4430 ES1.0 */ | 616 | /* Local timers are not supprted on OMAP4430 ES1.0 */ |
479 | if (omap_rev() != OMAP4430_REV_ES1_0) { | 617 | if (omap_rev() != OMAP4430_REV_ES1_0) { |
480 | int err; | 618 | int err; |
@@ -488,26 +626,32 @@ static void __init omap4_timer_init(void) | |||
488 | if (err) | 626 | if (err) |
489 | pr_err("twd_local_timer_register failed %d\n", err); | 627 | pr_err("twd_local_timer_register failed %d\n", err); |
490 | } | 628 | } |
491 | #endif | ||
492 | } | 629 | } |
493 | OMAP_SYS_TIMER(4) | 630 | #else /* CONFIG_LOCAL_TIMERS */ |
494 | #endif | 631 | static void __init omap4_local_timer_init(void) |
632 | { | ||
633 | omap4_sync32k_timer_init(); | ||
634 | } | ||
635 | #endif /* CONFIG_LOCAL_TIMERS */ | ||
636 | OMAP_SYS_TIMER(4, local); | ||
637 | #endif /* CONFIG_ARCH_OMAP4 */ | ||
495 | 638 | ||
496 | #ifdef CONFIG_SOC_OMAP5 | 639 | #ifdef CONFIG_SOC_OMAP5 |
497 | 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) | ||
498 | { | 643 | { |
499 | int err; | 644 | int err; |
500 | 645 | ||
501 | omap2_gp_clockevent_init(1, OMAP4_CLKEV_SOURCE); | 646 | omap5_sync32k_timer_init(); |
502 | omap2_clocksource_init(2, OMAP4_MPU_SOURCE); | ||
503 | realtime_counter_init(); | 647 | realtime_counter_init(); |
504 | 648 | ||
505 | err = arch_timer_of_register(); | 649 | err = arch_timer_of_register(); |
506 | if (err) | 650 | if (err) |
507 | pr_err("%s: arch_timer_register failed %d\n", __func__, err); | 651 | pr_err("%s: arch_timer_register failed %d\n", __func__, err); |
508 | } | 652 | } |
509 | OMAP_SYS_TIMER(5) | 653 | OMAP_SYS_TIMER(5, realtime); |
510 | #endif | 654 | #endif /* CONFIG_SOC_OMAP5 */ |
511 | 655 | ||
512 | /** | 656 | /** |
513 | * omap_timer_init - build and register timer device with an | 657 | * omap_timer_init - build and register timer device with an |
@@ -559,6 +703,9 @@ static int __init omap_timer_init(struct omap_hwmod *oh, void *unused) | |||
559 | if (timer_dev_attr) | 703 | if (timer_dev_attr) |
560 | pdata->timer_capability = timer_dev_attr->timer_capability; | 704 | pdata->timer_capability = timer_dev_attr->timer_capability; |
561 | 705 | ||
706 | pdata->timer_errata = omap_dm_timer_get_errata(); | ||
707 | pdata->get_context_loss_count = omap_pm_get_dev_context_loss_count; | ||
708 | |||
562 | pdev = omap_device_build(name, id, oh, pdata, sizeof(*pdata), | 709 | pdev = omap_device_build(name, id, oh, pdata, sizeof(*pdata), |
563 | NULL, 0, 0); | 710 | NULL, 0, 0); |
564 | 711 | ||
@@ -583,6 +730,10 @@ static int __init omap2_dm_timer_init(void) | |||
583 | { | 730 | { |
584 | int ret; | 731 | int ret; |
585 | 732 | ||
733 | /* If dtb is there, the devices will be created dynamically */ | ||
734 | if (of_have_populated_dt()) | ||
735 | return -ENODEV; | ||
736 | |||
586 | 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); |
587 | if (unlikely(ret)) { | 738 | if (unlikely(ret)) { |
588 | pr_err("%s: device registration failed.\n", __func__); | 739 | pr_err("%s: device registration failed.\n", __func__); |