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