aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/sysdev/mpic_timer.c
diff options
context:
space:
mode:
authorDongsheng.wang@freescale.com <Dongsheng.wang@freescale.com>2013-04-08 22:22:30 -0400
committerScott Wood <scottwood@freescale.com>2013-07-01 19:38:41 -0400
commit36ca09be6ff77a4e5b54b8b68ed7be7aa184250b (patch)
tree599bddca2be47f3c115f9afb58bf3b9386a03104 /arch/powerpc/sysdev/mpic_timer.c
parent5ff04b7287d87c1db74f47360365905ed9a97ff7 (diff)
powerpc/mpic: add global timer support
The MPIC global timer is a hardware timer inside the Freescale PIC complying with OpenPIC standard. When the specified interval times out, the hardware timer generates an interrupt. The driver currently is only tested on fsl chip, but it can potentially support other global timers complying to OpenPIC standard. The two independent groups of global timer on fsl chip, group A and group B, are identical in their functionality, except that they appear at different locations within the PIC register map. The hardware timer can be cascaded to create timers larger than the default 31-bit global timers. Timer cascade fields allow configuration of up to two 63-bit timers. But These two groups of timers cannot be cascaded together. It can be used as a wakeup source for low power modes. It also could be used as periodical timer for protocols, drivers and etc. Signed-off-by: Wang Dongsheng <dongsheng.wang@freescale.com> Signed-off-by: Li Yang <leoli@freescale.com> Signed-off-by: Scott Wood <scottwood@freescale.com>
Diffstat (limited to 'arch/powerpc/sysdev/mpic_timer.c')
-rw-r--r--arch/powerpc/sysdev/mpic_timer.c593
1 files changed, 593 insertions, 0 deletions
diff --git a/arch/powerpc/sysdev/mpic_timer.c b/arch/powerpc/sysdev/mpic_timer.c
new file mode 100644
index 000000000000..c06db92a4fb1
--- /dev/null
+++ b/arch/powerpc/sysdev/mpic_timer.c
@@ -0,0 +1,593 @@
1/*
2 * MPIC timer driver
3 *
4 * Copyright 2013 Freescale Semiconductor, Inc.
5 * Author: Dongsheng Wang <Dongsheng.Wang@freescale.com>
6 * Li Yang <leoli@freescale.com>
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version.
12 */
13
14#include <linux/kernel.h>
15#include <linux/init.h>
16#include <linux/module.h>
17#include <linux/errno.h>
18#include <linux/mm.h>
19#include <linux/interrupt.h>
20#include <linux/slab.h>
21#include <linux/of.h>
22#include <linux/of_device.h>
23#include <linux/syscore_ops.h>
24#include <sysdev/fsl_soc.h>
25#include <asm/io.h>
26
27#include <asm/mpic_timer.h>
28
29#define FSL_GLOBAL_TIMER 0x1
30
31/* Clock Ratio
32 * Divide by 64 0x00000300
33 * Divide by 32 0x00000200
34 * Divide by 16 0x00000100
35 * Divide by 8 0x00000000 (Hardware default div)
36 */
37#define MPIC_TIMER_TCR_CLKDIV 0x00000300
38
39#define MPIC_TIMER_TCR_ROVR_OFFSET 24
40
41#define TIMER_STOP 0x80000000
42#define TIMERS_PER_GROUP 4
43#define MAX_TICKS (~0U >> 1)
44#define MAX_TICKS_CASCADE (~0U)
45#define TIMER_OFFSET(num) (1 << (TIMERS_PER_GROUP - 1 - num))
46
47/* tv_usec should be less than ONE_SECOND, otherwise use tv_sec */
48#define ONE_SECOND 1000000
49
50struct timer_regs {
51 u32 gtccr;
52 u32 res0[3];
53 u32 gtbcr;
54 u32 res1[3];
55 u32 gtvpr;
56 u32 res2[3];
57 u32 gtdr;
58 u32 res3[3];
59};
60
61struct cascade_priv {
62 u32 tcr_value; /* TCR register: CASC & ROVR value */
63 unsigned int cascade_map; /* cascade map */
64 unsigned int timer_num; /* cascade control timer */
65};
66
67struct timer_group_priv {
68 struct timer_regs __iomem *regs;
69 struct mpic_timer timer[TIMERS_PER_GROUP];
70 struct list_head node;
71 unsigned int timerfreq;
72 unsigned int idle;
73 unsigned int flags;
74 spinlock_t lock;
75 void __iomem *group_tcr;
76};
77
78static struct cascade_priv cascade_timer[] = {
79 /* cascade timer 0 and 1 */
80 {0x1, 0xc, 0x1},
81 /* cascade timer 1 and 2 */
82 {0x2, 0x6, 0x2},
83 /* cascade timer 2 and 3 */
84 {0x4, 0x3, 0x3}
85};
86
87static LIST_HEAD(timer_group_list);
88
89static void convert_ticks_to_time(struct timer_group_priv *priv,
90 const u64 ticks, struct timeval *time)
91{
92 u64 tmp_sec;
93
94 time->tv_sec = (__kernel_time_t)div_u64(ticks, priv->timerfreq);
95 tmp_sec = (u64)time->tv_sec * (u64)priv->timerfreq;
96
97 time->tv_usec = (__kernel_suseconds_t)
98 div_u64((ticks - tmp_sec) * 1000000, priv->timerfreq);
99
100 return;
101}
102
103/* the time set by the user is converted to "ticks" */
104static int convert_time_to_ticks(struct timer_group_priv *priv,
105 const struct timeval *time, u64 *ticks)
106{
107 u64 max_value; /* prevent u64 overflow */
108 u64 tmp = 0;
109
110 u64 tmp_sec;
111 u64 tmp_ms;
112 u64 tmp_us;
113
114 max_value = div_u64(ULLONG_MAX, priv->timerfreq);
115
116 if (time->tv_sec > max_value ||
117 (time->tv_sec == max_value && time->tv_usec > 0))
118 return -EINVAL;
119
120 tmp_sec = (u64)time->tv_sec * (u64)priv->timerfreq;
121 tmp += tmp_sec;
122
123 tmp_ms = time->tv_usec / 1000;
124 tmp_ms = div_u64((u64)tmp_ms * (u64)priv->timerfreq, 1000);
125 tmp += tmp_ms;
126
127 tmp_us = time->tv_usec % 1000;
128 tmp_us = div_u64((u64)tmp_us * (u64)priv->timerfreq, 1000000);
129 tmp += tmp_us;
130
131 *ticks = tmp;
132
133 return 0;
134}
135
136/* detect whether there is a cascade timer available */
137static struct mpic_timer *detect_idle_cascade_timer(
138 struct timer_group_priv *priv)
139{
140 struct cascade_priv *casc_priv;
141 unsigned int map;
142 unsigned int array_size = ARRAY_SIZE(cascade_timer);
143 unsigned int num;
144 unsigned int i;
145 unsigned long flags;
146
147 casc_priv = cascade_timer;
148 for (i = 0; i < array_size; i++) {
149 spin_lock_irqsave(&priv->lock, flags);
150 map = casc_priv->cascade_map & priv->idle;
151 if (map == casc_priv->cascade_map) {
152 num = casc_priv->timer_num;
153 priv->timer[num].cascade_handle = casc_priv;
154
155 /* set timer busy */
156 priv->idle &= ~casc_priv->cascade_map;
157 spin_unlock_irqrestore(&priv->lock, flags);
158 return &priv->timer[num];
159 }
160 spin_unlock_irqrestore(&priv->lock, flags);
161 casc_priv++;
162 }
163
164 return NULL;
165}
166
167static int set_cascade_timer(struct timer_group_priv *priv, u64 ticks,
168 unsigned int num)
169{
170 struct cascade_priv *casc_priv;
171 u32 tcr;
172 u32 tmp_ticks;
173 u32 rem_ticks;
174
175 /* set group tcr reg for cascade */
176 casc_priv = priv->timer[num].cascade_handle;
177 if (!casc_priv)
178 return -EINVAL;
179
180 tcr = casc_priv->tcr_value |
181 (casc_priv->tcr_value << MPIC_TIMER_TCR_ROVR_OFFSET);
182 setbits32(priv->group_tcr, tcr);
183
184 tmp_ticks = div_u64_rem(ticks, MAX_TICKS_CASCADE, &rem_ticks);
185
186 out_be32(&priv->regs[num].gtccr, 0);
187 out_be32(&priv->regs[num].gtbcr, tmp_ticks | TIMER_STOP);
188
189 out_be32(&priv->regs[num - 1].gtccr, 0);
190 out_be32(&priv->regs[num - 1].gtbcr, rem_ticks);
191
192 return 0;
193}
194
195static struct mpic_timer *get_cascade_timer(struct timer_group_priv *priv,
196 u64 ticks)
197{
198 struct mpic_timer *allocated_timer;
199
200 /* Two cascade timers: Support the maximum time */
201 const u64 max_ticks = (u64)MAX_TICKS * (u64)MAX_TICKS_CASCADE;
202 int ret;
203
204 if (ticks > max_ticks)
205 return NULL;
206
207 /* detect idle timer */
208 allocated_timer = detect_idle_cascade_timer(priv);
209 if (!allocated_timer)
210 return NULL;
211
212 /* set ticks to timer */
213 ret = set_cascade_timer(priv, ticks, allocated_timer->num);
214 if (ret < 0)
215 return NULL;
216
217 return allocated_timer;
218}
219
220static struct mpic_timer *get_timer(const struct timeval *time)
221{
222 struct timer_group_priv *priv;
223 struct mpic_timer *timer;
224
225 u64 ticks;
226 unsigned int num;
227 unsigned int i;
228 unsigned long flags;
229 int ret;
230
231 list_for_each_entry(priv, &timer_group_list, node) {
232 ret = convert_time_to_ticks(priv, time, &ticks);
233 if (ret < 0)
234 return NULL;
235
236 if (ticks > MAX_TICKS) {
237 if (!(priv->flags & FSL_GLOBAL_TIMER))
238 return NULL;
239
240 timer = get_cascade_timer(priv, ticks);
241 if (!timer)
242 continue;
243
244 return timer;
245 }
246
247 for (i = 0; i < TIMERS_PER_GROUP; i++) {
248 /* one timer: Reverse allocation */
249 num = TIMERS_PER_GROUP - 1 - i;
250 spin_lock_irqsave(&priv->lock, flags);
251 if (priv->idle & (1 << i)) {
252 /* set timer busy */
253 priv->idle &= ~(1 << i);
254 /* set ticks & stop timer */
255 out_be32(&priv->regs[num].gtbcr,
256 ticks | TIMER_STOP);
257 out_be32(&priv->regs[num].gtccr, 0);
258 priv->timer[num].cascade_handle = NULL;
259 spin_unlock_irqrestore(&priv->lock, flags);
260 return &priv->timer[num];
261 }
262 spin_unlock_irqrestore(&priv->lock, flags);
263 }
264 }
265
266 return NULL;
267}
268
269/**
270 * mpic_start_timer - start hardware timer
271 * @handle: the timer to be started.
272 *
273 * It will do ->fn(->dev) callback from the hardware interrupt at
274 * the ->timeval point in the future.
275 */
276void mpic_start_timer(struct mpic_timer *handle)
277{
278 struct timer_group_priv *priv = container_of(handle,
279 struct timer_group_priv, timer[handle->num]);
280
281 clrbits32(&priv->regs[handle->num].gtbcr, TIMER_STOP);
282}
283EXPORT_SYMBOL(mpic_start_timer);
284
285/**
286 * mpic_stop_timer - stop hardware timer
287 * @handle: the timer to be stoped
288 *
289 * The timer periodically generates an interrupt. Unless user stops the timer.
290 */
291void mpic_stop_timer(struct mpic_timer *handle)
292{
293 struct timer_group_priv *priv = container_of(handle,
294 struct timer_group_priv, timer[handle->num]);
295 struct cascade_priv *casc_priv;
296
297 setbits32(&priv->regs[handle->num].gtbcr, TIMER_STOP);
298
299 casc_priv = priv->timer[handle->num].cascade_handle;
300 if (casc_priv) {
301 out_be32(&priv->regs[handle->num].gtccr, 0);
302 out_be32(&priv->regs[handle->num - 1].gtccr, 0);
303 } else {
304 out_be32(&priv->regs[handle->num].gtccr, 0);
305 }
306}
307EXPORT_SYMBOL(mpic_stop_timer);
308
309/**
310 * mpic_get_remain_time - get timer time
311 * @handle: the timer to be selected.
312 * @time: time for timer
313 *
314 * Query timer remaining time.
315 */
316void mpic_get_remain_time(struct mpic_timer *handle, struct timeval *time)
317{
318 struct timer_group_priv *priv = container_of(handle,
319 struct timer_group_priv, timer[handle->num]);
320 struct cascade_priv *casc_priv;
321
322 u64 ticks;
323 u32 tmp_ticks;
324
325 casc_priv = priv->timer[handle->num].cascade_handle;
326 if (casc_priv) {
327 tmp_ticks = in_be32(&priv->regs[handle->num].gtccr);
328 ticks = ((u64)tmp_ticks & UINT_MAX) * (u64)MAX_TICKS_CASCADE;
329 tmp_ticks = in_be32(&priv->regs[handle->num - 1].gtccr);
330 ticks += tmp_ticks;
331 } else {
332 ticks = in_be32(&priv->regs[handle->num].gtccr);
333 }
334
335 convert_ticks_to_time(priv, ticks, time);
336}
337EXPORT_SYMBOL(mpic_get_remain_time);
338
339/**
340 * mpic_free_timer - free hardware timer
341 * @handle: the timer to be removed.
342 *
343 * Free the timer.
344 *
345 * Note: can not be used in interrupt context.
346 */
347void mpic_free_timer(struct mpic_timer *handle)
348{
349 struct timer_group_priv *priv = container_of(handle,
350 struct timer_group_priv, timer[handle->num]);
351
352 struct cascade_priv *casc_priv;
353 unsigned long flags;
354
355 mpic_stop_timer(handle);
356
357 casc_priv = priv->timer[handle->num].cascade_handle;
358
359 free_irq(priv->timer[handle->num].irq, priv->timer[handle->num].dev);
360
361 spin_lock_irqsave(&priv->lock, flags);
362 if (casc_priv) {
363 u32 tcr;
364 tcr = casc_priv->tcr_value | (casc_priv->tcr_value <<
365 MPIC_TIMER_TCR_ROVR_OFFSET);
366 clrbits32(priv->group_tcr, tcr);
367 priv->idle |= casc_priv->cascade_map;
368 priv->timer[handle->num].cascade_handle = NULL;
369 } else {
370 priv->idle |= TIMER_OFFSET(handle->num);
371 }
372 spin_unlock_irqrestore(&priv->lock, flags);
373}
374EXPORT_SYMBOL(mpic_free_timer);
375
376/**
377 * mpic_request_timer - get a hardware timer
378 * @fn: interrupt handler function
379 * @dev: callback function of the data
380 * @time: time for timer
381 *
382 * This executes the "request_irq", returning NULL
383 * else "handle" on success.
384 */
385struct mpic_timer *mpic_request_timer(irq_handler_t fn, void *dev,
386 const struct timeval *time)
387{
388 struct mpic_timer *allocated_timer;
389 int ret;
390
391 if (list_empty(&timer_group_list))
392 return NULL;
393
394 if (!(time->tv_sec + time->tv_usec) ||
395 time->tv_sec < 0 || time->tv_usec < 0)
396 return NULL;
397
398 if (time->tv_usec > ONE_SECOND)
399 return NULL;
400
401 allocated_timer = get_timer(time);
402 if (!allocated_timer)
403 return NULL;
404
405 ret = request_irq(allocated_timer->irq, fn,
406 IRQF_TRIGGER_LOW, "global-timer", dev);
407 if (ret) {
408 mpic_free_timer(allocated_timer);
409 return NULL;
410 }
411
412 allocated_timer->dev = dev;
413
414 return allocated_timer;
415}
416EXPORT_SYMBOL(mpic_request_timer);
417
418static int timer_group_get_freq(struct device_node *np,
419 struct timer_group_priv *priv)
420{
421 u32 div;
422
423 if (priv->flags & FSL_GLOBAL_TIMER) {
424 struct device_node *dn;
425
426 dn = of_find_compatible_node(NULL, NULL, "fsl,mpic");
427 if (dn) {
428 of_property_read_u32(dn, "clock-frequency",
429 &priv->timerfreq);
430 of_node_put(dn);
431 }
432 }
433
434 if (priv->timerfreq <= 0)
435 return -EINVAL;
436
437 if (priv->flags & FSL_GLOBAL_TIMER) {
438 div = (1 << (MPIC_TIMER_TCR_CLKDIV >> 8)) * 8;
439 priv->timerfreq /= div;
440 }
441
442 return 0;
443}
444
445static int timer_group_get_irq(struct device_node *np,
446 struct timer_group_priv *priv)
447{
448 const u32 all_timer[] = { 0, TIMERS_PER_GROUP };
449 const u32 *p;
450 u32 offset;
451 u32 count;
452
453 unsigned int i;
454 unsigned int j;
455 unsigned int irq_index = 0;
456 unsigned int irq;
457 int len;
458
459 p = of_get_property(np, "fsl,available-ranges", &len);
460 if (p && len % (2 * sizeof(u32)) != 0) {
461 pr_err("%s: malformed available-ranges property.\n",
462 np->full_name);
463 return -EINVAL;
464 }
465
466 if (!p) {
467 p = all_timer;
468 len = sizeof(all_timer);
469 }
470
471 len /= 2 * sizeof(u32);
472
473 for (i = 0; i < len; i++) {
474 offset = p[i * 2];
475 count = p[i * 2 + 1];
476 for (j = 0; j < count; j++) {
477 irq = irq_of_parse_and_map(np, irq_index);
478 if (!irq) {
479 pr_err("%s: irq parse and map failed.\n",
480 np->full_name);
481 return -EINVAL;
482 }
483
484 /* Set timer idle */
485 priv->idle |= TIMER_OFFSET((offset + j));
486 priv->timer[offset + j].irq = irq;
487 priv->timer[offset + j].num = offset + j;
488 irq_index++;
489 }
490 }
491
492 return 0;
493}
494
495static void timer_group_init(struct device_node *np)
496{
497 struct timer_group_priv *priv;
498 unsigned int i = 0;
499 int ret;
500
501 priv = kzalloc(sizeof(struct timer_group_priv), GFP_KERNEL);
502 if (!priv) {
503 pr_err("%s: cannot allocate memory for group.\n",
504 np->full_name);
505 return;
506 }
507
508 if (of_device_is_compatible(np, "fsl,mpic-global-timer"))
509 priv->flags |= FSL_GLOBAL_TIMER;
510
511 priv->regs = of_iomap(np, i++);
512 if (!priv->regs) {
513 pr_err("%s: cannot ioremap timer register address.\n",
514 np->full_name);
515 goto out;
516 }
517
518 if (priv->flags & FSL_GLOBAL_TIMER) {
519 priv->group_tcr = of_iomap(np, i++);
520 if (!priv->group_tcr) {
521 pr_err("%s: cannot ioremap tcr address.\n",
522 np->full_name);
523 goto out;
524 }
525 }
526
527 ret = timer_group_get_freq(np, priv);
528 if (ret < 0) {
529 pr_err("%s: cannot get timer frequency.\n", np->full_name);
530 goto out;
531 }
532
533 ret = timer_group_get_irq(np, priv);
534 if (ret < 0) {
535 pr_err("%s: cannot get timer irqs.\n", np->full_name);
536 goto out;
537 }
538
539 spin_lock_init(&priv->lock);
540
541 /* Init FSL timer hardware */
542 if (priv->flags & FSL_GLOBAL_TIMER)
543 setbits32(priv->group_tcr, MPIC_TIMER_TCR_CLKDIV);
544
545 list_add_tail(&priv->node, &timer_group_list);
546
547 return;
548
549out:
550 if (priv->regs)
551 iounmap(priv->regs);
552
553 if (priv->group_tcr)
554 iounmap(priv->group_tcr);
555
556 kfree(priv);
557}
558
559static void mpic_timer_resume(void)
560{
561 struct timer_group_priv *priv;
562
563 list_for_each_entry(priv, &timer_group_list, node) {
564 /* Init FSL timer hardware */
565 if (priv->flags & FSL_GLOBAL_TIMER)
566 setbits32(priv->group_tcr, MPIC_TIMER_TCR_CLKDIV);
567 }
568}
569
570static const struct of_device_id mpic_timer_ids[] = {
571 { .compatible = "fsl,mpic-global-timer", },
572 {},
573};
574
575static struct syscore_ops mpic_timer_syscore_ops = {
576 .resume = mpic_timer_resume,
577};
578
579static int __init mpic_timer_init(void)
580{
581 struct device_node *np = NULL;
582
583 for_each_matching_node(np, mpic_timer_ids)
584 timer_group_init(np);
585
586 register_syscore_ops(&mpic_timer_syscore_ops);
587
588 if (list_empty(&timer_group_list))
589 return -ENODEV;
590
591 return 0;
592}
593subsys_initcall(mpic_timer_init);