diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-omap2/timer-gp.c | 147 | ||||
-rw-r--r-- | arch/arm/plat-omap/include/plat/dmtimer.h | 1 |
2 files changed, 113 insertions, 35 deletions
diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c index a0d8e83594eb..62c0d5cb25f7 100644 --- a/arch/arm/mach-omap2/timer-gp.c +++ b/arch/arm/mach-omap2/timer-gp.c | |||
@@ -45,10 +45,33 @@ | |||
45 | 45 | ||
46 | #include "timer-gp.h" | 46 | #include "timer-gp.h" |
47 | 47 | ||
48 | /* Parent clocks, eventually these will come from the clock framework */ | ||
49 | |||
50 | #define OMAP2_MPU_SOURCE "sys_ck" | ||
51 | #define OMAP3_MPU_SOURCE OMAP2_MPU_SOURCE | ||
52 | #define OMAP4_MPU_SOURCE "sys_clkin_ck" | ||
53 | #define OMAP2_32K_SOURCE "func_32k_ck" | ||
54 | #define OMAP3_32K_SOURCE "omap_32k_fck" | ||
55 | #define OMAP4_32K_SOURCE "sys_32k_ck" | ||
56 | |||
57 | #ifdef CONFIG_OMAP_32K_TIMER | ||
58 | #define OMAP2_CLKEV_SOURCE OMAP2_32K_SOURCE | ||
59 | #define OMAP3_CLKEV_SOURCE OMAP3_32K_SOURCE | ||
60 | #define OMAP4_CLKEV_SOURCE OMAP4_32K_SOURCE | ||
61 | #define OMAP3_SECURE_TIMER 12 | ||
62 | #else | ||
63 | #define OMAP2_CLKEV_SOURCE OMAP2_MPU_SOURCE | ||
64 | #define OMAP3_CLKEV_SOURCE OMAP3_MPU_SOURCE | ||
65 | #define OMAP4_CLKEV_SOURCE OMAP4_MPU_SOURCE | ||
66 | #define OMAP3_SECURE_TIMER 1 | ||
67 | #endif | ||
48 | 68 | ||
49 | /* MAX_GPTIMER_ID: number of GPTIMERs on the chip */ | 69 | /* MAX_GPTIMER_ID: number of GPTIMERs on the chip */ |
50 | #define MAX_GPTIMER_ID 12 | 70 | #define MAX_GPTIMER_ID 12 |
51 | 71 | ||
72 | /* Clockevent code */ | ||
73 | |||
74 | static struct omap_dm_timer clkev; | ||
52 | static struct omap_dm_timer *gptimer; | 75 | static struct omap_dm_timer *gptimer; |
53 | static struct clock_event_device clockevent_gpt; | 76 | static struct clock_event_device clockevent_gpt; |
54 | static u8 __initdata gptimer_id = 1; | 77 | static u8 __initdata gptimer_id = 1; |
@@ -57,10 +80,9 @@ struct omap_dm_timer *gptimer_wakeup; | |||
57 | 80 | ||
58 | static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id) | 81 | static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id) |
59 | { | 82 | { |
60 | struct omap_dm_timer *gpt = (struct omap_dm_timer *)dev_id; | ||
61 | struct clock_event_device *evt = &clockevent_gpt; | 83 | struct clock_event_device *evt = &clockevent_gpt; |
62 | 84 | ||
63 | omap_dm_timer_write_status(gpt, OMAP_TIMER_INT_OVERFLOW); | 85 | __omap_dm_timer_write_status(clkev.io_base, OMAP_TIMER_INT_OVERFLOW); |
64 | 86 | ||
65 | evt->event_handler(evt); | 87 | evt->event_handler(evt); |
66 | return IRQ_HANDLED; | 88 | return IRQ_HANDLED; |
@@ -75,7 +97,8 @@ static struct irqaction omap2_gp_timer_irq = { | |||
75 | static int omap2_gp_timer_set_next_event(unsigned long cycles, | 97 | static int omap2_gp_timer_set_next_event(unsigned long cycles, |
76 | struct clock_event_device *evt) | 98 | struct clock_event_device *evt) |
77 | { | 99 | { |
78 | omap_dm_timer_set_load_start(gptimer, 0, 0xffffffff - cycles); | 100 | __omap_dm_timer_load_start(clkev.io_base, OMAP_TIMER_CTRL_ST, |
101 | 0xffffffff - cycles, 1); | ||
79 | 102 | ||
80 | return 0; | 103 | return 0; |
81 | } | 104 | } |
@@ -85,13 +108,18 @@ static void omap2_gp_timer_set_mode(enum clock_event_mode mode, | |||
85 | { | 108 | { |
86 | u32 period; | 109 | u32 period; |
87 | 110 | ||
88 | omap_dm_timer_stop(gptimer); | 111 | __omap_dm_timer_stop(clkev.io_base, 1, clkev.rate); |
89 | 112 | ||
90 | switch (mode) { | 113 | switch (mode) { |
91 | case CLOCK_EVT_MODE_PERIODIC: | 114 | case CLOCK_EVT_MODE_PERIODIC: |
92 | period = clk_get_rate(omap_dm_timer_get_fclk(gptimer)) / HZ; | 115 | period = clkev.rate / HZ; |
93 | period -= 1; | 116 | period -= 1; |
94 | omap_dm_timer_set_load_start(gptimer, 1, 0xffffffff - period); | 117 | /* Looks like we need to first set the load value separately */ |
118 | __omap_dm_timer_write(clkev.io_base, OMAP_TIMER_LOAD_REG, | ||
119 | 0xffffffff - period, 1); | ||
120 | __omap_dm_timer_load_start(clkev.io_base, | ||
121 | OMAP_TIMER_CTRL_AR | OMAP_TIMER_CTRL_ST, | ||
122 | 0xffffffff - period, 1); | ||
95 | break; | 123 | break; |
96 | case CLOCK_EVT_MODE_ONESHOT: | 124 | case CLOCK_EVT_MODE_ONESHOT: |
97 | break; | 125 | break; |
@@ -130,43 +158,89 @@ int __init omap2_gp_clockevent_set_gptimer(u8 id) | |||
130 | return 0; | 158 | return 0; |
131 | } | 159 | } |
132 | 160 | ||
133 | static void __init omap2_gp_clockevent_init(void) | 161 | static int __init omap_dm_timer_init_one(struct omap_dm_timer *timer, |
162 | int gptimer_id, | ||
163 | const char *fck_source) | ||
134 | { | 164 | { |
135 | u32 tick_rate; | 165 | char name[10]; /* 10 = sizeof("gptXX_Xck0") */ |
136 | int src; | 166 | struct omap_hwmod *oh; |
137 | char clockevent_hwmod_name[8]; /* 8 = sizeof("timerXX0") */ | 167 | size_t size; |
168 | int res = 0; | ||
169 | |||
170 | sprintf(name, "timer%d", gptimer_id); | ||
171 | omap_hwmod_setup_one(name); | ||
172 | oh = omap_hwmod_lookup(name); | ||
173 | if (!oh) | ||
174 | return -ENODEV; | ||
175 | |||
176 | timer->irq = oh->mpu_irqs[0].irq; | ||
177 | timer->phys_base = oh->slaves[0]->addr->pa_start; | ||
178 | size = oh->slaves[0]->addr->pa_end - timer->phys_base; | ||
179 | |||
180 | /* Static mapping, never released */ | ||
181 | timer->io_base = ioremap(timer->phys_base, size); | ||
182 | if (!timer->io_base) | ||
183 | return -ENXIO; | ||
184 | |||
185 | /* After the dmtimer is using hwmod these clocks won't be needed */ | ||
186 | sprintf(name, "gpt%d_fck", gptimer_id); | ||
187 | timer->fclk = clk_get(NULL, name); | ||
188 | if (IS_ERR(timer->fclk)) | ||
189 | return -ENODEV; | ||
190 | |||
191 | sprintf(name, "gpt%d_ick", gptimer_id); | ||
192 | timer->iclk = clk_get(NULL, name); | ||
193 | if (IS_ERR(timer->iclk)) { | ||
194 | clk_put(timer->fclk); | ||
195 | return -ENODEV; | ||
196 | } | ||
138 | 197 | ||
139 | inited = 1; | 198 | omap_hwmod_enable(oh); |
199 | |||
200 | if (gptimer_id != 12) { | ||
201 | struct clk *src; | ||
202 | |||
203 | src = clk_get(NULL, fck_source); | ||
204 | if (IS_ERR(src)) { | ||
205 | res = -EINVAL; | ||
206 | } else { | ||
207 | res = __omap_dm_timer_set_source(timer->fclk, src); | ||
208 | if (IS_ERR_VALUE(res)) | ||
209 | pr_warning("%s: timer%i cannot set source\n", | ||
210 | __func__, gptimer_id); | ||
211 | clk_put(src); | ||
212 | } | ||
213 | } | ||
214 | __omap_dm_timer_reset(timer->io_base, 1, 1); | ||
215 | timer->posted = 1; | ||
216 | |||
217 | timer->rate = clk_get_rate(timer->fclk); | ||
140 | 218 | ||
141 | sprintf(clockevent_hwmod_name, "timer%d", gptimer_id); | 219 | timer->reserved = 1; |
142 | omap_hwmod_setup_one(clockevent_hwmod_name); | ||
143 | 220 | ||
144 | gptimer = omap_dm_timer_request_specific(gptimer_id); | 221 | gptimer = omap_dm_timer_request_specific(gptimer_id); |
145 | BUG_ON(gptimer == NULL); | 222 | BUG_ON(gptimer == NULL); |
146 | gptimer_wakeup = gptimer; | 223 | gptimer_wakeup = gptimer; |
147 | 224 | ||
148 | #if defined(CONFIG_OMAP_32K_TIMER) | 225 | return res; |
149 | src = OMAP_TIMER_SRC_32_KHZ; | 226 | } |
150 | #else | ||
151 | src = OMAP_TIMER_SRC_SYS_CLK; | ||
152 | WARN(gptimer_id == 12, "WARNING: GPTIMER12 can only use the " | ||
153 | "secure 32KiHz clock source\n"); | ||
154 | #endif | ||
155 | 227 | ||
156 | if (gptimer_id != 12) | 228 | static void __init omap2_gp_clockevent_init(int gptimer_id, |
157 | WARN(IS_ERR_VALUE(omap_dm_timer_set_source(gptimer, src)), | 229 | const char *fck_source) |
158 | "timer-gp: omap_dm_timer_set_source() failed\n"); | 230 | { |
231 | int res; | ||
159 | 232 | ||
160 | tick_rate = clk_get_rate(omap_dm_timer_get_fclk(gptimer)); | 233 | inited = 1; |
161 | 234 | ||
162 | pr_info("OMAP clockevent source: GPTIMER%d at %u Hz\n", | 235 | res = omap_dm_timer_init_one(&clkev, gptimer_id, fck_source); |
163 | gptimer_id, tick_rate); | 236 | BUG_ON(res); |
164 | 237 | ||
165 | omap2_gp_timer_irq.dev_id = (void *)gptimer; | 238 | omap2_gp_timer_irq.dev_id = (void *)gptimer; |
166 | setup_irq(omap_dm_timer_get_irq(gptimer), &omap2_gp_timer_irq); | 239 | setup_irq(clkev.irq, &omap2_gp_timer_irq); |
167 | omap_dm_timer_set_int_enable(gptimer, OMAP_TIMER_INT_OVERFLOW); | ||
168 | 240 | ||
169 | clockevent_gpt.mult = div_sc(tick_rate, NSEC_PER_SEC, | 241 | __omap_dm_timer_int_enable(clkev.io_base, OMAP_TIMER_INT_OVERFLOW); |
242 | |||
243 | clockevent_gpt.mult = div_sc(clkev.rate, NSEC_PER_SEC, | ||
170 | clockevent_gpt.shift); | 244 | clockevent_gpt.shift); |
171 | clockevent_gpt.max_delta_ns = | 245 | clockevent_gpt.max_delta_ns = |
172 | clockevent_delta2ns(0xffffffff, &clockevent_gpt); | 246 | clockevent_delta2ns(0xffffffff, &clockevent_gpt); |
@@ -176,6 +250,9 @@ static void __init omap2_gp_clockevent_init(void) | |||
176 | 250 | ||
177 | clockevent_gpt.cpumask = cpumask_of(0); | 251 | clockevent_gpt.cpumask = cpumask_of(0); |
178 | clockevents_register_device(&clockevent_gpt); | 252 | clockevents_register_device(&clockevent_gpt); |
253 | |||
254 | pr_info("OMAP clockevent source: GPTIMER%d at %lu Hz\n", | ||
255 | gptimer_id, clkev.rate); | ||
179 | } | 256 | } |
180 | 257 | ||
181 | /* Clocksource code */ | 258 | /* Clocksource code */ |
@@ -247,11 +324,11 @@ static void __init omap2_gp_clocksource_init(void) | |||
247 | } | 324 | } |
248 | #endif | 325 | #endif |
249 | 326 | ||
250 | #define OMAP_SYS_TIMER_INIT(name) \ | 327 | #define OMAP_SYS_TIMER_INIT(name, clkev_nr, clkev_src) \ |
251 | static void __init omap##name##_timer_init(void) \ | 328 | static void __init omap##name##_timer_init(void) \ |
252 | { \ | 329 | { \ |
253 | omap_dm_timer_init(); \ | 330 | omap_dm_timer_init(); \ |
254 | omap2_gp_clockevent_init(); \ | 331 | omap2_gp_clockevent_init((clkev_nr), clkev_src); \ |
255 | omap2_gp_clocksource_init(); \ | 332 | omap2_gp_clocksource_init(); \ |
256 | } | 333 | } |
257 | 334 | ||
@@ -261,14 +338,14 @@ struct sys_timer omap##name##_timer = { \ | |||
261 | }; | 338 | }; |
262 | 339 | ||
263 | #ifdef CONFIG_ARCH_OMAP2 | 340 | #ifdef CONFIG_ARCH_OMAP2 |
264 | OMAP_SYS_TIMER_INIT(2) | 341 | OMAP_SYS_TIMER_INIT(2, 1, OMAP2_CLKEV_SOURCE) |
265 | OMAP_SYS_TIMER(2) | 342 | OMAP_SYS_TIMER(2) |
266 | #endif | 343 | #endif |
267 | 344 | ||
268 | #ifdef CONFIG_ARCH_OMAP3 | 345 | #ifdef CONFIG_ARCH_OMAP3 |
269 | OMAP_SYS_TIMER_INIT(3) | 346 | OMAP_SYS_TIMER_INIT(3, 1, OMAP3_CLKEV_SOURCE) |
270 | OMAP_SYS_TIMER(3) | 347 | OMAP_SYS_TIMER(3) |
271 | OMAP_SYS_TIMER_INIT(3_secure) | 348 | OMAP_SYS_TIMER_INIT(3_secure, OMAP3_SECURE_TIMER, OMAP3_CLKEV_SOURCE) |
272 | OMAP_SYS_TIMER(3_secure) | 349 | OMAP_SYS_TIMER(3_secure) |
273 | #endif | 350 | #endif |
274 | 351 | ||
@@ -280,7 +357,7 @@ static void __init omap4_timer_init(void) | |||
280 | BUG_ON(!twd_base); | 357 | BUG_ON(!twd_base); |
281 | #endif | 358 | #endif |
282 | omap_dm_timer_init(); | 359 | omap_dm_timer_init(); |
283 | omap2_gp_clockevent_init(); | 360 | omap2_gp_clockevent_init(1, OMAP4_CLKEV_SOURCE); |
284 | omap2_gp_clocksource_init(); | 361 | omap2_gp_clocksource_init(); |
285 | } | 362 | } |
286 | OMAP_SYS_TIMER(4) | 363 | OMAP_SYS_TIMER(4) |
diff --git a/arch/arm/plat-omap/include/plat/dmtimer.h b/arch/arm/plat-omap/include/plat/dmtimer.h index 54664a7498af..dd8b3ffb7521 100644 --- a/arch/arm/plat-omap/include/plat/dmtimer.h +++ b/arch/arm/plat-omap/include/plat/dmtimer.h | |||
@@ -216,6 +216,7 @@ struct omap_dm_timer { | |||
216 | struct clk *iclk, *fclk; | 216 | struct clk *iclk, *fclk; |
217 | #endif | 217 | #endif |
218 | void __iomem *io_base; | 218 | void __iomem *io_base; |
219 | unsigned long rate; | ||
219 | unsigned reserved:1; | 220 | unsigned reserved:1; |
220 | unsigned enabled:1; | 221 | unsigned enabled:1; |
221 | unsigned posted:1; | 222 | unsigned posted:1; |