xref: /OK3568_Linux_fs/kernel/arch/powerpc/sysdev/mpic_timer.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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