aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2/timer.c
diff options
context:
space:
mode:
authorJon Hunter <jon-hunter@ti.com>2012-05-14 11:41:37 -0400
committerJon Hunter <jon-hunter@ti.com>2012-11-02 14:16:30 -0400
commit9725f4451a9ccd159b1d13f63e05896cd9bce07d (patch)
treef158dc234b62a4d0cebc989e9e532f290f5d8784 /arch/arm/mach-omap2/timer.c
parent7dd9d502b6cb9f82c9726ea601276b666a93e95d (diff)
ARM: OMAP: Add DT support for timer driver
In order to add device-tree support to the timer driver the following changes were made ... 1. Allocate system timers (used for clock-events and clock-source) based upon timer properties rather than using an hard-coded timer instance ID. To allow this a new helper function called omap_dmtimer_find_by_property() has been added for finding a timer with the particular properties in the device-tree blob. Please note that this is an internal helper function for system timers only to find a timer in the device-tree blob. This cannot be used by device drivers, another API has been added for that (see below). Timers that are allocated for system timers are dynamically disabled at boot time by adding a status property with the value "disabled" to the timer's device-tree node. Please note that when allocating system timers we now pass a timer ID and timer property. The timer ID is only be used for allocating a timer when booting without device-tree. Once device-tree migration is complete, all the timer ID references will be removed. 2. System timer resources (memory and interrupts) are directly obtained from the device-tree timer node when booting with device-tree, so that system timers are no longer reliant upon the OMAP HWMOD framework to provide these resources. 3. If DT blob is present, then let device-tree create the timer devices dynamically. 4. When device-tree is present the "id" field in the platform_device structure (pdev->id) is initialised to -1 and hence cannot be used to identify a timer instance. Due to this the following changes were made ... a). The API omap_dm_timer_request_specific() is not supported when using device-tree, because it uses the device ID to request a specific timer. This function will return an error if called when device-tree is present. Users of this API should use omap_dm_timer_request_by_cap() instead. b). When removing the DMTIMER driver, the timer "id" was used to identify the timer instance. The remove function has been modified to use the device name instead of the "id". 5. When device-tree is present the platform_data structure will be NULL and so check for this. 6. The OMAP timer device tree binding has the following optional parameters ... a). ti,timer-alwon --> Timer is in an always-on power domain b). ti,timer-dsp --> Timer can generate an interrupt to the on-chip DSP c). ti,timer-pwm --> Timer can generate a PWM output d). ti,timer-secure --> Timer is reserved on a secure OMAP device Search for the above parameters and set the appropriate timer attribute flags. Signed-off-by: Jon Hunter <jon-hunter@ti.com>
Diffstat (limited to 'arch/arm/mach-omap2/timer.c')
-rw-r--r--arch/arm/mach-omap2/timer.c147
1 files changed, 111 insertions, 36 deletions
diff --git a/arch/arm/mach-omap2/timer.c b/arch/arm/mach-omap2/timer.c
index def9a0ebe42d..92447cd7a41a 100644
--- a/arch/arm/mach-omap2/timer.c
+++ b/arch/arm/mach-omap2/timer.c
@@ -37,6 +37,8 @@
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>
40 42
41#include <asm/mach/time.h> 43#include <asm/mach/time.h>
42#include <asm/smp_twd.h> 44#include <asm/smp_twd.h>
@@ -66,11 +68,13 @@
66#define OMAP3_CLKEV_SOURCE OMAP3_32K_SOURCE 68#define OMAP3_CLKEV_SOURCE OMAP3_32K_SOURCE
67#define OMAP4_CLKEV_SOURCE OMAP4_32K_SOURCE 69#define OMAP4_CLKEV_SOURCE OMAP4_32K_SOURCE
68#define OMAP3_SECURE_TIMER 12 70#define OMAP3_SECURE_TIMER 12
71#define TIMER_PROP_SECURE "ti,timer-secure"
69#else 72#else
70#define OMAP2_CLKEV_SOURCE OMAP2_MPU_SOURCE 73#define OMAP2_CLKEV_SOURCE OMAP2_MPU_SOURCE
71#define OMAP3_CLKEV_SOURCE OMAP3_MPU_SOURCE 74#define OMAP3_CLKEV_SOURCE OMAP3_MPU_SOURCE
72#define OMAP4_CLKEV_SOURCE OMAP4_MPU_SOURCE 75#define OMAP4_CLKEV_SOURCE OMAP4_MPU_SOURCE
73#define OMAP3_SECURE_TIMER 1 76#define OMAP3_SECURE_TIMER 1
77#define TIMER_PROP_SECURE "ti,timer-alwon"
74#endif 78#endif
75 79
76#define REALTIME_COUNTER_BASE 0x48243200 80#define REALTIME_COUNTER_BASE 0x48243200
@@ -156,6 +160,40 @@ static struct of_device_id omap_timer_match[] __initdata = {
156}; 160};
157 161
158/** 162/**
163 * omap_get_timer_dt - get a timer using device-tree
164 * @match - device-tree match structure for matching a device type
165 * @property - optional timer property to match
166 *
167 * Helper function to get a timer during early boot using device-tree for use
168 * as kernel system timer. Optionally, the property argument can be used to
169 * select a timer with a specific property. Once a timer is found then mark
170 * the timer node in device-tree as disabled, to prevent the kernel from
171 * registering this timer as a platform device and so no one else can use it.
172 */
173static struct device_node * __init omap_get_timer_dt(struct of_device_id *match,
174 const char *property)
175{
176 struct device_node *np;
177
178 for_each_matching_node(np, match) {
179 if (!of_device_is_available(np)) {
180 of_node_put(np);
181 continue;
182 }
183
184 if (property && !of_get_property(np, property, NULL)) {
185 of_node_put(np);
186 continue;
187 }
188
189 prom_add_property(np, &device_disabled);
190 return np;
191 }
192
193 return NULL;
194}
195
196/**
159 * omap_dmtimer_init - initialisation function when device tree is used 197 * omap_dmtimer_init - initialisation function when device tree is used
160 * 198 *
161 * For secure OMAP3 devices, timers with device type "timer-secure" cannot 199 * For secure OMAP3 devices, timers with device type "timer-secure" cannot
@@ -172,43 +210,74 @@ void __init omap_dmtimer_init(void)
172 210
173 /* If we are a secure device, remove any secure timer nodes */ 211 /* If we are a secure device, remove any secure timer nodes */
174 if ((omap_type() != OMAP2_DEVICE_TYPE_GP)) { 212 if ((omap_type() != OMAP2_DEVICE_TYPE_GP)) {
175 for_each_matching_node(np, omap_timer_match) { 213 np = omap_get_timer_dt(omap_timer_match, "ti,timer-secure");
176 if (of_get_property(np, "ti,timer-secure", NULL)) 214 if (np)
177 prom_add_property(np, &device_disabled); 215 of_node_put(np);
178 }
179 } 216 }
180} 217}
181 218
182static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, 219static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
183 int gptimer_id, 220 int gptimer_id,
184 const char *fck_source) 221 const char *fck_source,
222 const char *property)
185{ 223{
186 char name[10]; /* 10 = sizeof("gptXX_Xck0") */ 224 char name[10]; /* 10 = sizeof("gptXX_Xck0") */
225 const char *oh_name;
226 struct device_node *np;
187 struct omap_hwmod *oh; 227 struct omap_hwmod *oh;
188 struct resource irq_rsrc, mem_rsrc; 228 struct resource irq_rsrc, mem_rsrc;
189 size_t size; 229 size_t size;
190 int res = 0; 230 int res = 0;
191 int r; 231 int r;
192 232
193 sprintf(name, "timer%d", gptimer_id); 233 if (of_have_populated_dt()) {
194 omap_hwmod_setup_one(name); 234 np = omap_get_timer_dt(omap_timer_match, NULL);
195 oh = omap_hwmod_lookup(name); 235 if (!np)
236 return -ENODEV;
237
238 of_property_read_string_index(np, "ti,hwmods", 0, &oh_name);
239 if (!oh_name)
240 return -ENODEV;
241
242 timer->irq = irq_of_parse_and_map(np, 0);
243 if (!timer->irq)
244 return -ENXIO;
245
246 timer->io_base = of_iomap(np, 0);
247
248 of_node_put(np);
249 } else {
250 if (omap_dm_timer_reserve_systimer(gptimer_id))
251 return -ENODEV;
252
253 sprintf(name, "timer%d", gptimer_id);
254 oh_name = name;
255 }
256
257 omap_hwmod_setup_one(oh_name);
258 oh = omap_hwmod_lookup(oh_name);
259
196 if (!oh) 260 if (!oh)
197 return -ENODEV; 261 return -ENODEV;
198 262
199 r = omap_hwmod_get_resource_byname(oh, IORESOURCE_IRQ, NULL, &irq_rsrc); 263 if (!of_have_populated_dt()) {
200 if (r) 264 r = omap_hwmod_get_resource_byname(oh, IORESOURCE_IRQ, NULL,
201 return -ENXIO; 265 &irq_rsrc);
202 timer->irq = irq_rsrc.start; 266 if (r)
203 267 return -ENXIO;
204 r = omap_hwmod_get_resource_byname(oh, IORESOURCE_MEM, NULL, &mem_rsrc); 268 timer->irq = irq_rsrc.start;
205 if (r) 269
206 return -ENXIO; 270 r = omap_hwmod_get_resource_byname(oh, IORESOURCE_MEM, NULL,
207 timer->phys_base = mem_rsrc.start; 271 &mem_rsrc);
208 size = mem_rsrc.end - mem_rsrc.start; 272 if (r)
273 return -ENXIO;
274 timer->phys_base = mem_rsrc.start;
275 size = mem_rsrc.end - mem_rsrc.start;
276
277 /* Static mapping, never released */
278 timer->io_base = ioremap(timer->phys_base, size);
279 }
209 280
210 /* Static mapping, never released */
211 timer->io_base = ioremap(timer->phys_base, size);
212 if (!timer->io_base) 281 if (!timer->io_base)
213 return -ENXIO; 282 return -ENXIO;
214 283
@@ -219,9 +288,7 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
219 288
220 omap_hwmod_enable(oh); 289 omap_hwmod_enable(oh);
221 290
222 if (omap_dm_timer_reserve_systimer(gptimer_id)) 291 /* FIXME: Need to remove hard-coded test on timer ID */
223 return -ENODEV;
224
225 if (gptimer_id != 12) { 292 if (gptimer_id != 12) {
226 struct clk *src; 293 struct clk *src;
227 294
@@ -231,8 +298,8 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
231 } else { 298 } else {
232 res = __omap_dm_timer_set_source(timer->fclk, src); 299 res = __omap_dm_timer_set_source(timer->fclk, src);
233 if (IS_ERR_VALUE(res)) 300 if (IS_ERR_VALUE(res))
234 pr_warning("%s: timer%i cannot set source\n", 301 pr_warn("%s: %s cannot set source\n",
235 __func__, gptimer_id); 302 __func__, oh->name);
236 clk_put(src); 303 clk_put(src);
237 } 304 }
238 } 305 }
@@ -248,11 +315,12 @@ static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer,
248} 315}
249 316
250static void __init omap2_gp_clockevent_init(int gptimer_id, 317static void __init omap2_gp_clockevent_init(int gptimer_id,
251 const char *fck_source) 318 const char *fck_source,
319 const char *property)
252{ 320{
253 int res; 321 int res;
254 322
255 res = omap_dm_timer_init_one(&clkev, gptimer_id, fck_source); 323 res = omap_dm_timer_init_one(&clkev, gptimer_id, fck_source, property);
256 BUG_ON(res); 324 BUG_ON(res);
257 325
258 omap2_gp_timer_irq.dev_id = &clkev; 326 omap2_gp_timer_irq.dev_id = &clkev;
@@ -356,7 +424,7 @@ static void __init omap2_gptimer_clocksource_init(int gptimer_id,
356{ 424{
357 int res; 425 int res;
358 426
359 res = omap_dm_timer_init_one(&clksrc, gptimer_id, fck_source); 427 res = omap_dm_timer_init_one(&clksrc, gptimer_id, fck_source, NULL);
360 BUG_ON(res); 428 BUG_ON(res);
361 429
362 __omap_dm_timer_load_start(&clksrc, 430 __omap_dm_timer_load_start(&clksrc,
@@ -468,12 +536,12 @@ static inline void __init realtime_counter_init(void)
468{} 536{}
469#endif 537#endif
470 538
471#define OMAP_SYS_TIMER_INIT(name, clkev_nr, clkev_src, \ 539#define OMAP_SYS_TIMER_INIT(name, clkev_nr, clkev_src, clkev_prop, \
472 clksrc_nr, clksrc_src) \ 540 clksrc_nr, clksrc_src) \
473static void __init omap##name##_timer_init(void) \ 541static void __init omap##name##_timer_init(void) \
474{ \ 542{ \
475 omap_dmtimer_init(); \ 543 omap_dmtimer_init(); \
476 omap2_gp_clockevent_init((clkev_nr), clkev_src); \ 544 omap2_gp_clockevent_init((clkev_nr), clkev_src, clkev_prop); \
477 omap2_clocksource_init((clksrc_nr), clksrc_src); \ 545 omap2_clocksource_init((clksrc_nr), clksrc_src); \
478} 546}
479 547
@@ -483,20 +551,23 @@ struct sys_timer omap##name##_timer = { \
483}; 551};
484 552
485#ifdef CONFIG_ARCH_OMAP2 553#ifdef CONFIG_ARCH_OMAP2
486OMAP_SYS_TIMER_INIT(2, 1, OMAP2_CLKEV_SOURCE, 2, OMAP2_MPU_SOURCE) 554OMAP_SYS_TIMER_INIT(2, 1, OMAP2_CLKEV_SOURCE, "ti,timer-alwon",
555 2, OMAP2_MPU_SOURCE)
487OMAP_SYS_TIMER(2) 556OMAP_SYS_TIMER(2)
488#endif 557#endif
489 558
490#ifdef CONFIG_ARCH_OMAP3 559#ifdef CONFIG_ARCH_OMAP3
491OMAP_SYS_TIMER_INIT(3, 1, OMAP3_CLKEV_SOURCE, 2, OMAP3_MPU_SOURCE) 560OMAP_SYS_TIMER_INIT(3, 1, OMAP3_CLKEV_SOURCE, "ti,timer-alwon",
561 2, OMAP3_MPU_SOURCE)
492OMAP_SYS_TIMER(3) 562OMAP_SYS_TIMER(3)
493OMAP_SYS_TIMER_INIT(3_secure, OMAP3_SECURE_TIMER, OMAP3_CLKEV_SOURCE, 563OMAP_SYS_TIMER_INIT(3_secure, OMAP3_SECURE_TIMER, OMAP3_CLKEV_SOURCE,
494 2, OMAP3_MPU_SOURCE) 564 TIMER_PROP_SECURE, 2, OMAP3_MPU_SOURCE)
495OMAP_SYS_TIMER(3_secure) 565OMAP_SYS_TIMER(3_secure)
496#endif 566#endif
497 567
498#ifdef CONFIG_SOC_AM33XX 568#ifdef CONFIG_SOC_AM33XX
499OMAP_SYS_TIMER_INIT(3_am33xx, 1, OMAP4_MPU_SOURCE, 2, OMAP4_MPU_SOURCE) 569OMAP_SYS_TIMER_INIT(3_am33xx, 1, OMAP4_MPU_SOURCE, "ti,timer-alwon",
570 2, OMAP4_MPU_SOURCE)
500OMAP_SYS_TIMER(3_am33xx) 571OMAP_SYS_TIMER(3_am33xx)
501#endif 572#endif
502 573
@@ -508,7 +579,7 @@ static DEFINE_TWD_LOCAL_TIMER(twd_local_timer,
508 579
509static void __init omap4_timer_init(void) 580static void __init omap4_timer_init(void)
510{ 581{
511 omap2_gp_clockevent_init(1, OMAP4_CLKEV_SOURCE); 582 omap2_gp_clockevent_init(1, OMAP4_CLKEV_SOURCE, "ti,timer-alwon");
512 omap2_clocksource_init(2, OMAP4_MPU_SOURCE); 583 omap2_clocksource_init(2, OMAP4_MPU_SOURCE);
513#ifdef CONFIG_LOCAL_TIMERS 584#ifdef CONFIG_LOCAL_TIMERS
514 /* Local timers are not supprted on OMAP4430 ES1.0 */ 585 /* Local timers are not supprted on OMAP4430 ES1.0 */
@@ -534,7 +605,7 @@ static void __init omap5_timer_init(void)
534{ 605{
535 int err; 606 int err;
536 607
537 omap2_gp_clockevent_init(1, OMAP4_CLKEV_SOURCE); 608 omap2_gp_clockevent_init(1, OMAP4_CLKEV_SOURCE, "ti,timer-alwon");
538 omap2_clocksource_init(2, OMAP4_MPU_SOURCE); 609 omap2_clocksource_init(2, OMAP4_MPU_SOURCE);
539 realtime_counter_init(); 610 realtime_counter_init();
540 611
@@ -619,6 +690,10 @@ static int __init omap2_dm_timer_init(void)
619{ 690{
620 int ret; 691 int ret;
621 692
693 /* If dtb is there, the devices will be created dynamically */
694 if (of_have_populated_dt())
695 return -ENODEV;
696
622 ret = omap_hwmod_for_each_by_class("timer", omap_timer_init, NULL); 697 ret = omap_hwmod_for_each_by_class("timer", omap_timer_init, NULL);
623 if (unlikely(ret)) { 698 if (unlikely(ret)) {
624 pr_err("%s: device registration failed.\n", __func__); 699 pr_err("%s: device registration failed.\n", __func__);