xref: /linux/drivers/clocksource/timer-nxp-stm.c (revision 6376c0770656f3bdf7f411faf068371b6932aeca)
1*cec32ac7SDaniel Lezcano // SPDX-License-Identifier: GPL-2.0-or-later
2*cec32ac7SDaniel Lezcano /*
3*cec32ac7SDaniel Lezcano  * Copyright 2016 Freescale Semiconductor, Inc.
4*cec32ac7SDaniel Lezcano  * Copyright 2018,2021-2025 NXP
5*cec32ac7SDaniel Lezcano  *
6*cec32ac7SDaniel Lezcano  * NXP System Timer Module:
7*cec32ac7SDaniel Lezcano  *
8*cec32ac7SDaniel Lezcano  *  STM supports commonly required system and application software
9*cec32ac7SDaniel Lezcano  *  timing functions. STM includes a 32-bit count-up timer and four
10*cec32ac7SDaniel Lezcano  *  32-bit compare channels with a separate interrupt source for each
11*cec32ac7SDaniel Lezcano  *  channel. The timer is driven by the STM module clock divided by an
12*cec32ac7SDaniel Lezcano  *  8-bit prescale value (1 to 256). It has ability to stop the timer
13*cec32ac7SDaniel Lezcano  *  in Debug mode
14*cec32ac7SDaniel Lezcano  */
15*cec32ac7SDaniel Lezcano #include <linux/clk.h>
16*cec32ac7SDaniel Lezcano #include <linux/clockchips.h>
17*cec32ac7SDaniel Lezcano #include <linux/cpuhotplug.h>
18*cec32ac7SDaniel Lezcano #include <linux/interrupt.h>
19*cec32ac7SDaniel Lezcano #include <linux/module.h>
20*cec32ac7SDaniel Lezcano #include <linux/of_irq.h>
21*cec32ac7SDaniel Lezcano #include <linux/platform_device.h>
22*cec32ac7SDaniel Lezcano #include <linux/sched_clock.h>
23*cec32ac7SDaniel Lezcano #include <linux/units.h>
24*cec32ac7SDaniel Lezcano 
25*cec32ac7SDaniel Lezcano #define STM_CR(__base)		(__base)
26*cec32ac7SDaniel Lezcano 
27*cec32ac7SDaniel Lezcano #define STM_CR_TEN		BIT(0)
28*cec32ac7SDaniel Lezcano #define STM_CR_FRZ		BIT(1)
29*cec32ac7SDaniel Lezcano #define STM_CR_CPS_OFFSET	8u
30*cec32ac7SDaniel Lezcano #define STM_CR_CPS_MASK		GENMASK(15, STM_CR_CPS_OFFSET)
31*cec32ac7SDaniel Lezcano 
32*cec32ac7SDaniel Lezcano #define STM_CNT(__base)		((__base) + 0x04)
33*cec32ac7SDaniel Lezcano 
34*cec32ac7SDaniel Lezcano #define STM_CCR0(__base)	((__base) + 0x10)
35*cec32ac7SDaniel Lezcano #define STM_CCR1(__base)	((__base) + 0x20)
36*cec32ac7SDaniel Lezcano #define STM_CCR2(__base)	((__base) + 0x30)
37*cec32ac7SDaniel Lezcano #define STM_CCR3(__base)	((__base) + 0x40)
38*cec32ac7SDaniel Lezcano 
39*cec32ac7SDaniel Lezcano #define STM_CCR_CEN		BIT(0)
40*cec32ac7SDaniel Lezcano 
41*cec32ac7SDaniel Lezcano #define STM_CIR0(__base)	((__base) + 0x14)
42*cec32ac7SDaniel Lezcano #define STM_CIR1(__base)	((__base) + 0x24)
43*cec32ac7SDaniel Lezcano #define STM_CIR2(__base)	((__base) + 0x34)
44*cec32ac7SDaniel Lezcano #define STM_CIR3(__base)	((__base) + 0x44)
45*cec32ac7SDaniel Lezcano 
46*cec32ac7SDaniel Lezcano #define STM_CIR_CIF		BIT(0)
47*cec32ac7SDaniel Lezcano 
48*cec32ac7SDaniel Lezcano #define STM_CMP0(__base)	((__base) + 0x18)
49*cec32ac7SDaniel Lezcano #define STM_CMP1(__base)	((__base) + 0x28)
50*cec32ac7SDaniel Lezcano #define STM_CMP2(__base)	((__base) + 0x38)
51*cec32ac7SDaniel Lezcano #define STM_CMP3(__base)	((__base) + 0x48)
52*cec32ac7SDaniel Lezcano 
53*cec32ac7SDaniel Lezcano #define STM_ENABLE_MASK	(STM_CR_FRZ | STM_CR_TEN)
54*cec32ac7SDaniel Lezcano 
55*cec32ac7SDaniel Lezcano struct stm_timer {
56*cec32ac7SDaniel Lezcano 	void __iomem *base;
57*cec32ac7SDaniel Lezcano 	unsigned long rate;
58*cec32ac7SDaniel Lezcano 	unsigned long delta;
59*cec32ac7SDaniel Lezcano 	unsigned long counter;
60*cec32ac7SDaniel Lezcano 	struct clock_event_device ced;
61*cec32ac7SDaniel Lezcano 	struct clocksource cs;
62*cec32ac7SDaniel Lezcano 	atomic_t refcnt;
63*cec32ac7SDaniel Lezcano };
64*cec32ac7SDaniel Lezcano 
65*cec32ac7SDaniel Lezcano static DEFINE_PER_CPU(struct stm_timer *, stm_timers);
66*cec32ac7SDaniel Lezcano 
67*cec32ac7SDaniel Lezcano static struct stm_timer *stm_sched_clock;
68*cec32ac7SDaniel Lezcano 
69*cec32ac7SDaniel Lezcano /*
70*cec32ac7SDaniel Lezcano  * Global structure for multiple STMs initialization
71*cec32ac7SDaniel Lezcano  */
72*cec32ac7SDaniel Lezcano static int stm_instances;
73*cec32ac7SDaniel Lezcano 
74*cec32ac7SDaniel Lezcano /*
75*cec32ac7SDaniel Lezcano  * This global lock is used to prevent race conditions with the
76*cec32ac7SDaniel Lezcano  * stm_instances in case the driver is using the ASYNC option
77*cec32ac7SDaniel Lezcano  */
78*cec32ac7SDaniel Lezcano static DEFINE_MUTEX(stm_instances_lock);
79*cec32ac7SDaniel Lezcano 
DEFINE_GUARD(stm_instances,struct mutex *,mutex_lock (_T),mutex_unlock (_T))80*cec32ac7SDaniel Lezcano DEFINE_GUARD(stm_instances, struct mutex *, mutex_lock(_T), mutex_unlock(_T))
81*cec32ac7SDaniel Lezcano 
82*cec32ac7SDaniel Lezcano static struct stm_timer *cs_to_stm(struct clocksource *cs)
83*cec32ac7SDaniel Lezcano {
84*cec32ac7SDaniel Lezcano 	return container_of(cs, struct stm_timer, cs);
85*cec32ac7SDaniel Lezcano }
86*cec32ac7SDaniel Lezcano 
ced_to_stm(struct clock_event_device * ced)87*cec32ac7SDaniel Lezcano static struct stm_timer *ced_to_stm(struct clock_event_device *ced)
88*cec32ac7SDaniel Lezcano {
89*cec32ac7SDaniel Lezcano 	return container_of(ced, struct stm_timer, ced);
90*cec32ac7SDaniel Lezcano }
91*cec32ac7SDaniel Lezcano 
nxp_stm_read_sched_clock(void)92*cec32ac7SDaniel Lezcano static u64 notrace nxp_stm_read_sched_clock(void)
93*cec32ac7SDaniel Lezcano {
94*cec32ac7SDaniel Lezcano 	return readl(STM_CNT(stm_sched_clock->base));
95*cec32ac7SDaniel Lezcano }
96*cec32ac7SDaniel Lezcano 
nxp_stm_clocksource_getcnt(struct stm_timer * stm_timer)97*cec32ac7SDaniel Lezcano static u32 nxp_stm_clocksource_getcnt(struct stm_timer *stm_timer)
98*cec32ac7SDaniel Lezcano {
99*cec32ac7SDaniel Lezcano 	return readl(STM_CNT(stm_timer->base));
100*cec32ac7SDaniel Lezcano }
101*cec32ac7SDaniel Lezcano 
nxp_stm_clocksource_setcnt(struct stm_timer * stm_timer,u32 cnt)102*cec32ac7SDaniel Lezcano static void nxp_stm_clocksource_setcnt(struct stm_timer *stm_timer, u32 cnt)
103*cec32ac7SDaniel Lezcano {
104*cec32ac7SDaniel Lezcano 	writel(cnt, STM_CNT(stm_timer->base));
105*cec32ac7SDaniel Lezcano }
106*cec32ac7SDaniel Lezcano 
nxp_stm_clocksource_read(struct clocksource * cs)107*cec32ac7SDaniel Lezcano static u64 nxp_stm_clocksource_read(struct clocksource *cs)
108*cec32ac7SDaniel Lezcano {
109*cec32ac7SDaniel Lezcano 	struct stm_timer *stm_timer = cs_to_stm(cs);
110*cec32ac7SDaniel Lezcano 
111*cec32ac7SDaniel Lezcano 	return (u64)nxp_stm_clocksource_getcnt(stm_timer);
112*cec32ac7SDaniel Lezcano }
113*cec32ac7SDaniel Lezcano 
nxp_stm_module_enable(struct stm_timer * stm_timer)114*cec32ac7SDaniel Lezcano static void nxp_stm_module_enable(struct stm_timer *stm_timer)
115*cec32ac7SDaniel Lezcano {
116*cec32ac7SDaniel Lezcano 	u32 reg;
117*cec32ac7SDaniel Lezcano 
118*cec32ac7SDaniel Lezcano 	reg = readl(STM_CR(stm_timer->base));
119*cec32ac7SDaniel Lezcano 
120*cec32ac7SDaniel Lezcano 	reg |= STM_ENABLE_MASK;
121*cec32ac7SDaniel Lezcano 
122*cec32ac7SDaniel Lezcano 	writel(reg, STM_CR(stm_timer->base));
123*cec32ac7SDaniel Lezcano }
124*cec32ac7SDaniel Lezcano 
nxp_stm_module_disable(struct stm_timer * stm_timer)125*cec32ac7SDaniel Lezcano static void nxp_stm_module_disable(struct stm_timer *stm_timer)
126*cec32ac7SDaniel Lezcano {
127*cec32ac7SDaniel Lezcano 	u32 reg;
128*cec32ac7SDaniel Lezcano 
129*cec32ac7SDaniel Lezcano 	reg = readl(STM_CR(stm_timer->base));
130*cec32ac7SDaniel Lezcano 
131*cec32ac7SDaniel Lezcano 	reg &= ~STM_ENABLE_MASK;
132*cec32ac7SDaniel Lezcano 
133*cec32ac7SDaniel Lezcano 	writel(reg, STM_CR(stm_timer->base));
134*cec32ac7SDaniel Lezcano }
135*cec32ac7SDaniel Lezcano 
nxp_stm_module_put(struct stm_timer * stm_timer)136*cec32ac7SDaniel Lezcano static void nxp_stm_module_put(struct stm_timer *stm_timer)
137*cec32ac7SDaniel Lezcano {
138*cec32ac7SDaniel Lezcano 	if (atomic_dec_and_test(&stm_timer->refcnt))
139*cec32ac7SDaniel Lezcano 		nxp_stm_module_disable(stm_timer);
140*cec32ac7SDaniel Lezcano }
141*cec32ac7SDaniel Lezcano 
nxp_stm_module_get(struct stm_timer * stm_timer)142*cec32ac7SDaniel Lezcano static void nxp_stm_module_get(struct stm_timer *stm_timer)
143*cec32ac7SDaniel Lezcano {
144*cec32ac7SDaniel Lezcano 	if (atomic_inc_return(&stm_timer->refcnt) == 1)
145*cec32ac7SDaniel Lezcano 		nxp_stm_module_enable(stm_timer);
146*cec32ac7SDaniel Lezcano }
147*cec32ac7SDaniel Lezcano 
nxp_stm_clocksource_enable(struct clocksource * cs)148*cec32ac7SDaniel Lezcano static int nxp_stm_clocksource_enable(struct clocksource *cs)
149*cec32ac7SDaniel Lezcano {
150*cec32ac7SDaniel Lezcano 	struct stm_timer *stm_timer = cs_to_stm(cs);
151*cec32ac7SDaniel Lezcano 
152*cec32ac7SDaniel Lezcano 	nxp_stm_module_get(stm_timer);
153*cec32ac7SDaniel Lezcano 
154*cec32ac7SDaniel Lezcano 	return 0;
155*cec32ac7SDaniel Lezcano }
156*cec32ac7SDaniel Lezcano 
nxp_stm_clocksource_disable(struct clocksource * cs)157*cec32ac7SDaniel Lezcano static void nxp_stm_clocksource_disable(struct clocksource *cs)
158*cec32ac7SDaniel Lezcano {
159*cec32ac7SDaniel Lezcano 	struct stm_timer *stm_timer = cs_to_stm(cs);
160*cec32ac7SDaniel Lezcano 
161*cec32ac7SDaniel Lezcano 	nxp_stm_module_put(stm_timer);
162*cec32ac7SDaniel Lezcano }
163*cec32ac7SDaniel Lezcano 
nxp_stm_clocksource_suspend(struct clocksource * cs)164*cec32ac7SDaniel Lezcano static void nxp_stm_clocksource_suspend(struct clocksource *cs)
165*cec32ac7SDaniel Lezcano {
166*cec32ac7SDaniel Lezcano 	struct stm_timer *stm_timer = cs_to_stm(cs);
167*cec32ac7SDaniel Lezcano 
168*cec32ac7SDaniel Lezcano 	nxp_stm_clocksource_disable(cs);
169*cec32ac7SDaniel Lezcano 	stm_timer->counter = nxp_stm_clocksource_getcnt(stm_timer);
170*cec32ac7SDaniel Lezcano }
171*cec32ac7SDaniel Lezcano 
nxp_stm_clocksource_resume(struct clocksource * cs)172*cec32ac7SDaniel Lezcano static void nxp_stm_clocksource_resume(struct clocksource *cs)
173*cec32ac7SDaniel Lezcano {
174*cec32ac7SDaniel Lezcano 	struct stm_timer *stm_timer = cs_to_stm(cs);
175*cec32ac7SDaniel Lezcano 
176*cec32ac7SDaniel Lezcano 	nxp_stm_clocksource_setcnt(stm_timer, stm_timer->counter);
177*cec32ac7SDaniel Lezcano 	nxp_stm_clocksource_enable(cs);
178*cec32ac7SDaniel Lezcano }
179*cec32ac7SDaniel Lezcano 
devm_clocksource_unregister(void * data)180*cec32ac7SDaniel Lezcano static void __init devm_clocksource_unregister(void *data)
181*cec32ac7SDaniel Lezcano {
182*cec32ac7SDaniel Lezcano 	struct stm_timer *stm_timer = data;
183*cec32ac7SDaniel Lezcano 
184*cec32ac7SDaniel Lezcano 	clocksource_unregister(&stm_timer->cs);
185*cec32ac7SDaniel Lezcano }
186*cec32ac7SDaniel Lezcano 
nxp_stm_clocksource_init(struct device * dev,struct stm_timer * stm_timer,const char * name,void __iomem * base,struct clk * clk)187*cec32ac7SDaniel Lezcano static int __init nxp_stm_clocksource_init(struct device *dev, struct stm_timer *stm_timer,
188*cec32ac7SDaniel Lezcano 					   const char *name, void __iomem *base, struct clk *clk)
189*cec32ac7SDaniel Lezcano {
190*cec32ac7SDaniel Lezcano 	int ret;
191*cec32ac7SDaniel Lezcano 
192*cec32ac7SDaniel Lezcano 	stm_timer->base = base;
193*cec32ac7SDaniel Lezcano 	stm_timer->rate = clk_get_rate(clk);
194*cec32ac7SDaniel Lezcano 
195*cec32ac7SDaniel Lezcano 	stm_timer->cs.name = name;
196*cec32ac7SDaniel Lezcano 	stm_timer->cs.rating = 460;
197*cec32ac7SDaniel Lezcano 	stm_timer->cs.read = nxp_stm_clocksource_read;
198*cec32ac7SDaniel Lezcano 	stm_timer->cs.enable = nxp_stm_clocksource_enable;
199*cec32ac7SDaniel Lezcano 	stm_timer->cs.disable = nxp_stm_clocksource_disable;
200*cec32ac7SDaniel Lezcano 	stm_timer->cs.suspend = nxp_stm_clocksource_suspend;
201*cec32ac7SDaniel Lezcano 	stm_timer->cs.resume = nxp_stm_clocksource_resume;
202*cec32ac7SDaniel Lezcano 	stm_timer->cs.mask = CLOCKSOURCE_MASK(32);
203*cec32ac7SDaniel Lezcano 	stm_timer->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS;
204*cec32ac7SDaniel Lezcano 
205*cec32ac7SDaniel Lezcano 	ret = clocksource_register_hz(&stm_timer->cs, stm_timer->rate);
206*cec32ac7SDaniel Lezcano 	if (ret)
207*cec32ac7SDaniel Lezcano 		return ret;
208*cec32ac7SDaniel Lezcano 
209*cec32ac7SDaniel Lezcano 	ret = devm_add_action_or_reset(dev, devm_clocksource_unregister, stm_timer);
210*cec32ac7SDaniel Lezcano 	if (ret) {
211*cec32ac7SDaniel Lezcano 		clocksource_unregister(&stm_timer->cs);
212*cec32ac7SDaniel Lezcano 		return ret;
213*cec32ac7SDaniel Lezcano 	}
214*cec32ac7SDaniel Lezcano 
215*cec32ac7SDaniel Lezcano 	stm_sched_clock = stm_timer;
216*cec32ac7SDaniel Lezcano 
217*cec32ac7SDaniel Lezcano 	sched_clock_register(nxp_stm_read_sched_clock, 32, stm_timer->rate);
218*cec32ac7SDaniel Lezcano 
219*cec32ac7SDaniel Lezcano 	dev_dbg(dev, "Registered clocksource %s\n", name);
220*cec32ac7SDaniel Lezcano 
221*cec32ac7SDaniel Lezcano 	return 0;
222*cec32ac7SDaniel Lezcano }
223*cec32ac7SDaniel Lezcano 
nxp_stm_clockevent_read_counter(struct stm_timer * stm_timer)224*cec32ac7SDaniel Lezcano static int nxp_stm_clockevent_read_counter(struct stm_timer *stm_timer)
225*cec32ac7SDaniel Lezcano {
226*cec32ac7SDaniel Lezcano 	return readl(STM_CNT(stm_timer->base));
227*cec32ac7SDaniel Lezcano }
228*cec32ac7SDaniel Lezcano 
nxp_stm_clockevent_disable(struct stm_timer * stm_timer)229*cec32ac7SDaniel Lezcano static void nxp_stm_clockevent_disable(struct stm_timer *stm_timer)
230*cec32ac7SDaniel Lezcano {
231*cec32ac7SDaniel Lezcano 	writel(0, STM_CCR0(stm_timer->base));
232*cec32ac7SDaniel Lezcano }
233*cec32ac7SDaniel Lezcano 
nxp_stm_clockevent_enable(struct stm_timer * stm_timer)234*cec32ac7SDaniel Lezcano static void nxp_stm_clockevent_enable(struct stm_timer *stm_timer)
235*cec32ac7SDaniel Lezcano {
236*cec32ac7SDaniel Lezcano 	writel(STM_CCR_CEN, STM_CCR0(stm_timer->base));
237*cec32ac7SDaniel Lezcano }
238*cec32ac7SDaniel Lezcano 
nxp_stm_clockevent_shutdown(struct clock_event_device * ced)239*cec32ac7SDaniel Lezcano static int nxp_stm_clockevent_shutdown(struct clock_event_device *ced)
240*cec32ac7SDaniel Lezcano {
241*cec32ac7SDaniel Lezcano 	struct stm_timer *stm_timer = ced_to_stm(ced);
242*cec32ac7SDaniel Lezcano 
243*cec32ac7SDaniel Lezcano 	nxp_stm_clockevent_disable(stm_timer);
244*cec32ac7SDaniel Lezcano 
245*cec32ac7SDaniel Lezcano 	return 0;
246*cec32ac7SDaniel Lezcano }
247*cec32ac7SDaniel Lezcano 
nxp_stm_clockevent_set_next_event(unsigned long delta,struct clock_event_device * ced)248*cec32ac7SDaniel Lezcano static int nxp_stm_clockevent_set_next_event(unsigned long delta, struct clock_event_device *ced)
249*cec32ac7SDaniel Lezcano {
250*cec32ac7SDaniel Lezcano 	struct stm_timer *stm_timer = ced_to_stm(ced);
251*cec32ac7SDaniel Lezcano 	u32 val;
252*cec32ac7SDaniel Lezcano 
253*cec32ac7SDaniel Lezcano 	nxp_stm_clockevent_disable(stm_timer);
254*cec32ac7SDaniel Lezcano 
255*cec32ac7SDaniel Lezcano 	stm_timer->delta = delta;
256*cec32ac7SDaniel Lezcano 
257*cec32ac7SDaniel Lezcano 	val = nxp_stm_clockevent_read_counter(stm_timer) + delta;
258*cec32ac7SDaniel Lezcano 
259*cec32ac7SDaniel Lezcano 	writel(val, STM_CMP0(stm_timer->base));
260*cec32ac7SDaniel Lezcano 
261*cec32ac7SDaniel Lezcano 	/*
262*cec32ac7SDaniel Lezcano 	 * The counter is shared across the channels and can not be
263*cec32ac7SDaniel Lezcano 	 * stopped while we are setting the next event. If the delta
264*cec32ac7SDaniel Lezcano 	 * is very small it is possible the counter increases above
265*cec32ac7SDaniel Lezcano 	 * the computed 'val'. The min_delta value specified when
266*cec32ac7SDaniel Lezcano 	 * registering the clockevent will prevent that. The second
267*cec32ac7SDaniel Lezcano 	 * case is if the counter wraps while we compute the 'val' and
268*cec32ac7SDaniel Lezcano 	 * before writing the comparator register. We read the counter,
269*cec32ac7SDaniel Lezcano 	 * check if we are back in time and abort the timer with -ETIME.
270*cec32ac7SDaniel Lezcano 	 */
271*cec32ac7SDaniel Lezcano 	if (val > nxp_stm_clockevent_read_counter(stm_timer) + delta)
272*cec32ac7SDaniel Lezcano 		return -ETIME;
273*cec32ac7SDaniel Lezcano 
274*cec32ac7SDaniel Lezcano 	nxp_stm_clockevent_enable(stm_timer);
275*cec32ac7SDaniel Lezcano 
276*cec32ac7SDaniel Lezcano 	return 0;
277*cec32ac7SDaniel Lezcano }
278*cec32ac7SDaniel Lezcano 
nxp_stm_clockevent_set_periodic(struct clock_event_device * ced)279*cec32ac7SDaniel Lezcano static int nxp_stm_clockevent_set_periodic(struct clock_event_device *ced)
280*cec32ac7SDaniel Lezcano {
281*cec32ac7SDaniel Lezcano 	struct stm_timer *stm_timer = ced_to_stm(ced);
282*cec32ac7SDaniel Lezcano 
283*cec32ac7SDaniel Lezcano 	return nxp_stm_clockevent_set_next_event(stm_timer->rate, ced);
284*cec32ac7SDaniel Lezcano }
285*cec32ac7SDaniel Lezcano 
nxp_stm_clockevent_suspend(struct clock_event_device * ced)286*cec32ac7SDaniel Lezcano static void nxp_stm_clockevent_suspend(struct clock_event_device *ced)
287*cec32ac7SDaniel Lezcano {
288*cec32ac7SDaniel Lezcano 	struct stm_timer *stm_timer = ced_to_stm(ced);
289*cec32ac7SDaniel Lezcano 
290*cec32ac7SDaniel Lezcano 	nxp_stm_module_put(stm_timer);
291*cec32ac7SDaniel Lezcano }
292*cec32ac7SDaniel Lezcano 
nxp_stm_clockevent_resume(struct clock_event_device * ced)293*cec32ac7SDaniel Lezcano static void nxp_stm_clockevent_resume(struct clock_event_device *ced)
294*cec32ac7SDaniel Lezcano {
295*cec32ac7SDaniel Lezcano 	struct stm_timer *stm_timer = ced_to_stm(ced);
296*cec32ac7SDaniel Lezcano 
297*cec32ac7SDaniel Lezcano 	nxp_stm_module_get(stm_timer);
298*cec32ac7SDaniel Lezcano }
299*cec32ac7SDaniel Lezcano 
nxp_stm_clockevent_per_cpu_init(struct device * dev,struct stm_timer * stm_timer,const char * name,void __iomem * base,int irq,struct clk * clk,int cpu)300*cec32ac7SDaniel Lezcano static int __init nxp_stm_clockevent_per_cpu_init(struct device *dev, struct stm_timer *stm_timer,
301*cec32ac7SDaniel Lezcano 						  const char *name, void __iomem *base, int irq,
302*cec32ac7SDaniel Lezcano 						  struct clk *clk, int cpu)
303*cec32ac7SDaniel Lezcano {
304*cec32ac7SDaniel Lezcano 	stm_timer->base = base;
305*cec32ac7SDaniel Lezcano 	stm_timer->rate = clk_get_rate(clk);
306*cec32ac7SDaniel Lezcano 
307*cec32ac7SDaniel Lezcano 	stm_timer->ced.name = name;
308*cec32ac7SDaniel Lezcano 	stm_timer->ced.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
309*cec32ac7SDaniel Lezcano 	stm_timer->ced.set_state_shutdown = nxp_stm_clockevent_shutdown;
310*cec32ac7SDaniel Lezcano 	stm_timer->ced.set_state_periodic = nxp_stm_clockevent_set_periodic;
311*cec32ac7SDaniel Lezcano 	stm_timer->ced.set_next_event = nxp_stm_clockevent_set_next_event;
312*cec32ac7SDaniel Lezcano 	stm_timer->ced.suspend = nxp_stm_clockevent_suspend;
313*cec32ac7SDaniel Lezcano 	stm_timer->ced.resume = nxp_stm_clockevent_resume;
314*cec32ac7SDaniel Lezcano 	stm_timer->ced.cpumask = cpumask_of(cpu);
315*cec32ac7SDaniel Lezcano 	stm_timer->ced.rating = 460;
316*cec32ac7SDaniel Lezcano 	stm_timer->ced.irq = irq;
317*cec32ac7SDaniel Lezcano 
318*cec32ac7SDaniel Lezcano 	per_cpu(stm_timers, cpu) = stm_timer;
319*cec32ac7SDaniel Lezcano 
320*cec32ac7SDaniel Lezcano 	nxp_stm_module_get(stm_timer);
321*cec32ac7SDaniel Lezcano 
322*cec32ac7SDaniel Lezcano 	dev_dbg(dev, "Initialized per cpu clockevent name=%s, irq=%d, cpu=%d\n", name, irq, cpu);
323*cec32ac7SDaniel Lezcano 
324*cec32ac7SDaniel Lezcano 	return 0;
325*cec32ac7SDaniel Lezcano }
326*cec32ac7SDaniel Lezcano 
nxp_stm_clockevent_starting_cpu(unsigned int cpu)327*cec32ac7SDaniel Lezcano static int nxp_stm_clockevent_starting_cpu(unsigned int cpu)
328*cec32ac7SDaniel Lezcano {
329*cec32ac7SDaniel Lezcano 	struct stm_timer *stm_timer = per_cpu(stm_timers, cpu);
330*cec32ac7SDaniel Lezcano 	int ret;
331*cec32ac7SDaniel Lezcano 
332*cec32ac7SDaniel Lezcano 	if (WARN_ON(!stm_timer))
333*cec32ac7SDaniel Lezcano 		return -EFAULT;
334*cec32ac7SDaniel Lezcano 
335*cec32ac7SDaniel Lezcano 	ret = irq_force_affinity(stm_timer->ced.irq, cpumask_of(cpu));
336*cec32ac7SDaniel Lezcano 	if (ret)
337*cec32ac7SDaniel Lezcano 		return ret;
338*cec32ac7SDaniel Lezcano 
339*cec32ac7SDaniel Lezcano 	/*
340*cec32ac7SDaniel Lezcano 	 * The timings measurement show reading the counter register
341*cec32ac7SDaniel Lezcano 	 * and writing to the comparator register takes as a maximum
342*cec32ac7SDaniel Lezcano 	 * value 1100 ns at 133MHz rate frequency. The timer must be
343*cec32ac7SDaniel Lezcano 	 * set above this value and to be secure we set the minimum
344*cec32ac7SDaniel Lezcano 	 * value equal to 2000ns, so 2us.
345*cec32ac7SDaniel Lezcano 	 *
346*cec32ac7SDaniel Lezcano 	 * minimum ticks = (rate / MICRO) * 2
347*cec32ac7SDaniel Lezcano 	 */
348*cec32ac7SDaniel Lezcano 	clockevents_config_and_register(&stm_timer->ced, stm_timer->rate,
349*cec32ac7SDaniel Lezcano 					(stm_timer->rate / MICRO) * 2, ULONG_MAX);
350*cec32ac7SDaniel Lezcano 
351*cec32ac7SDaniel Lezcano 	return 0;
352*cec32ac7SDaniel Lezcano }
353*cec32ac7SDaniel Lezcano 
nxp_stm_module_interrupt(int irq,void * dev_id)354*cec32ac7SDaniel Lezcano static irqreturn_t nxp_stm_module_interrupt(int irq, void *dev_id)
355*cec32ac7SDaniel Lezcano {
356*cec32ac7SDaniel Lezcano 	struct stm_timer *stm_timer = dev_id;
357*cec32ac7SDaniel Lezcano 	struct clock_event_device *ced = &stm_timer->ced;
358*cec32ac7SDaniel Lezcano 	u32 val;
359*cec32ac7SDaniel Lezcano 
360*cec32ac7SDaniel Lezcano 	/*
361*cec32ac7SDaniel Lezcano 	 * The interrupt is shared across the channels in the
362*cec32ac7SDaniel Lezcano 	 * module. But this one is configured to run only one channel,
363*cec32ac7SDaniel Lezcano 	 * consequently it is pointless to test the interrupt flags
364*cec32ac7SDaniel Lezcano 	 * before and we can directly reset the channel 0 irq flag
365*cec32ac7SDaniel Lezcano 	 * register.
366*cec32ac7SDaniel Lezcano 	 */
367*cec32ac7SDaniel Lezcano 	writel(STM_CIR_CIF, STM_CIR0(stm_timer->base));
368*cec32ac7SDaniel Lezcano 
369*cec32ac7SDaniel Lezcano 	/*
370*cec32ac7SDaniel Lezcano 	 * Update STM_CMP value using the counter value
371*cec32ac7SDaniel Lezcano 	 */
372*cec32ac7SDaniel Lezcano 	val = nxp_stm_clockevent_read_counter(stm_timer) + stm_timer->delta;
373*cec32ac7SDaniel Lezcano 
374*cec32ac7SDaniel Lezcano 	writel(val, STM_CMP0(stm_timer->base));
375*cec32ac7SDaniel Lezcano 
376*cec32ac7SDaniel Lezcano 	/*
377*cec32ac7SDaniel Lezcano 	 * stm hardware doesn't support oneshot, it will generate an
378*cec32ac7SDaniel Lezcano 	 * interrupt and start the counter again so software needs to
379*cec32ac7SDaniel Lezcano 	 * disable the timer to stop the counter loop in ONESHOT mode.
380*cec32ac7SDaniel Lezcano 	 */
381*cec32ac7SDaniel Lezcano 	if (likely(clockevent_state_oneshot(ced)))
382*cec32ac7SDaniel Lezcano 		nxp_stm_clockevent_disable(stm_timer);
383*cec32ac7SDaniel Lezcano 
384*cec32ac7SDaniel Lezcano 	ced->event_handler(ced);
385*cec32ac7SDaniel Lezcano 
386*cec32ac7SDaniel Lezcano 	return IRQ_HANDLED;
387*cec32ac7SDaniel Lezcano }
388*cec32ac7SDaniel Lezcano 
nxp_stm_timer_probe(struct platform_device * pdev)389*cec32ac7SDaniel Lezcano static int __init nxp_stm_timer_probe(struct platform_device *pdev)
390*cec32ac7SDaniel Lezcano {
391*cec32ac7SDaniel Lezcano 	struct stm_timer *stm_timer;
392*cec32ac7SDaniel Lezcano 	struct device *dev = &pdev->dev;
393*cec32ac7SDaniel Lezcano 	struct device_node *np = dev->of_node;
394*cec32ac7SDaniel Lezcano 	const char *name = of_node_full_name(np);
395*cec32ac7SDaniel Lezcano 	struct clk *clk;
396*cec32ac7SDaniel Lezcano 	void __iomem *base;
397*cec32ac7SDaniel Lezcano 	int irq, ret;
398*cec32ac7SDaniel Lezcano 
399*cec32ac7SDaniel Lezcano 	/*
400*cec32ac7SDaniel Lezcano 	 * The device tree can have multiple STM nodes described, so
401*cec32ac7SDaniel Lezcano 	 * it makes this driver a good candidate for the async probe.
402*cec32ac7SDaniel Lezcano 	 * It is still unclear if the time framework correctly handles
403*cec32ac7SDaniel Lezcano 	 * parallel loading of the timers but at least this driver is
404*cec32ac7SDaniel Lezcano 	 * ready to support the option.
405*cec32ac7SDaniel Lezcano 	 */
406*cec32ac7SDaniel Lezcano 	guard(stm_instances)(&stm_instances_lock);
407*cec32ac7SDaniel Lezcano 
408*cec32ac7SDaniel Lezcano 	/*
409*cec32ac7SDaniel Lezcano 	 * The S32Gx are SoCs featuring a diverse set of cores. Linux
410*cec32ac7SDaniel Lezcano 	 * is expected to run on Cortex-A53 cores, while other
411*cec32ac7SDaniel Lezcano 	 * software stacks will operate on Cortex-M cores. The number
412*cec32ac7SDaniel Lezcano 	 * of STM instances has been sized to include at most one
413*cec32ac7SDaniel Lezcano 	 * instance per core.
414*cec32ac7SDaniel Lezcano 	 *
415*cec32ac7SDaniel Lezcano 	 * As we need a clocksource and a clockevent per cpu, we
416*cec32ac7SDaniel Lezcano 	 * simply initialize a clocksource per cpu along with the
417*cec32ac7SDaniel Lezcano 	 * clockevent which makes the resulting code simpler.
418*cec32ac7SDaniel Lezcano 	 *
419*cec32ac7SDaniel Lezcano 	 * However if the device tree is describing more STM instances
420*cec32ac7SDaniel Lezcano 	 * than the number of cores, then we ignore them.
421*cec32ac7SDaniel Lezcano 	 */
422*cec32ac7SDaniel Lezcano 	if (stm_instances >= num_possible_cpus())
423*cec32ac7SDaniel Lezcano 		return 0;
424*cec32ac7SDaniel Lezcano 
425*cec32ac7SDaniel Lezcano 	base = devm_of_iomap(dev, np, 0, NULL);
426*cec32ac7SDaniel Lezcano 	if (IS_ERR(base))
427*cec32ac7SDaniel Lezcano 		return dev_err_probe(dev, PTR_ERR(base), "Failed to iomap %pOFn\n", np);
428*cec32ac7SDaniel Lezcano 
429*cec32ac7SDaniel Lezcano 	irq = platform_get_irq(pdev, 0);
430*cec32ac7SDaniel Lezcano 	if (irq < 0)
431*cec32ac7SDaniel Lezcano 		return dev_err_probe(dev, irq, "Failed to get IRQ\n");
432*cec32ac7SDaniel Lezcano 
433*cec32ac7SDaniel Lezcano 	clk = devm_clk_get_enabled(dev, NULL);
434*cec32ac7SDaniel Lezcano 	if (IS_ERR(clk))
435*cec32ac7SDaniel Lezcano 		return dev_err_probe(dev, PTR_ERR(clk), "Clock not found\n");
436*cec32ac7SDaniel Lezcano 
437*cec32ac7SDaniel Lezcano 	stm_timer = devm_kzalloc(dev, sizeof(*stm_timer), GFP_KERNEL);
438*cec32ac7SDaniel Lezcano 	if (!stm_timer)
439*cec32ac7SDaniel Lezcano 		return -ENOMEM;
440*cec32ac7SDaniel Lezcano 
441*cec32ac7SDaniel Lezcano 	ret = devm_request_irq(dev, irq, nxp_stm_module_interrupt,
442*cec32ac7SDaniel Lezcano 			       IRQF_TIMER | IRQF_NOBALANCING, name, stm_timer);
443*cec32ac7SDaniel Lezcano 	if (ret)
444*cec32ac7SDaniel Lezcano 		return dev_err_probe(dev, ret, "Unable to allocate interrupt line\n");
445*cec32ac7SDaniel Lezcano 
446*cec32ac7SDaniel Lezcano 	ret = nxp_stm_clocksource_init(dev, stm_timer, name, base, clk);
447*cec32ac7SDaniel Lezcano 	if (ret)
448*cec32ac7SDaniel Lezcano 		return ret;
449*cec32ac7SDaniel Lezcano 
450*cec32ac7SDaniel Lezcano 	/*
451*cec32ac7SDaniel Lezcano 	 * Next probed STM will be a per CPU clockevent, until we
452*cec32ac7SDaniel Lezcano 	 * probe as many as we have CPUs available on the system, we
453*cec32ac7SDaniel Lezcano 	 * do a partial initialization
454*cec32ac7SDaniel Lezcano 	 */
455*cec32ac7SDaniel Lezcano 	ret = nxp_stm_clockevent_per_cpu_init(dev, stm_timer, name,
456*cec32ac7SDaniel Lezcano 					      base, irq, clk,
457*cec32ac7SDaniel Lezcano 					      stm_instances);
458*cec32ac7SDaniel Lezcano 	if (ret)
459*cec32ac7SDaniel Lezcano 		return ret;
460*cec32ac7SDaniel Lezcano 
461*cec32ac7SDaniel Lezcano 	stm_instances++;
462*cec32ac7SDaniel Lezcano 
463*cec32ac7SDaniel Lezcano 	/*
464*cec32ac7SDaniel Lezcano 	 * The number of probed STMs for per CPU clockevent is
465*cec32ac7SDaniel Lezcano 	 * equal to the number of available CPUs on the
466*cec32ac7SDaniel Lezcano 	 * system. We install the cpu hotplug to finish the
467*cec32ac7SDaniel Lezcano 	 * initialization by registering the clockevents
468*cec32ac7SDaniel Lezcano 	 */
469*cec32ac7SDaniel Lezcano 	if (stm_instances == num_possible_cpus()) {
470*cec32ac7SDaniel Lezcano 		ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "STM timer:starting",
471*cec32ac7SDaniel Lezcano 					nxp_stm_clockevent_starting_cpu, NULL);
472*cec32ac7SDaniel Lezcano 		if (ret < 0)
473*cec32ac7SDaniel Lezcano 			return ret;
474*cec32ac7SDaniel Lezcano 	}
475*cec32ac7SDaniel Lezcano 
476*cec32ac7SDaniel Lezcano 	return 0;
477*cec32ac7SDaniel Lezcano }
478*cec32ac7SDaniel Lezcano 
479*cec32ac7SDaniel Lezcano static const struct of_device_id nxp_stm_of_match[] = {
480*cec32ac7SDaniel Lezcano 	{ .compatible = "nxp,s32g2-stm" },
481*cec32ac7SDaniel Lezcano 	{ }
482*cec32ac7SDaniel Lezcano };
483*cec32ac7SDaniel Lezcano MODULE_DEVICE_TABLE(of, nxp_stm_of_match);
484*cec32ac7SDaniel Lezcano 
485*cec32ac7SDaniel Lezcano static struct platform_driver nxp_stm_probe = {
486*cec32ac7SDaniel Lezcano 	.probe	= nxp_stm_timer_probe,
487*cec32ac7SDaniel Lezcano 	.driver	= {
488*cec32ac7SDaniel Lezcano 		.name		= "nxp-stm",
489*cec32ac7SDaniel Lezcano 		.of_match_table	= nxp_stm_of_match,
490*cec32ac7SDaniel Lezcano 	},
491*cec32ac7SDaniel Lezcano };
492*cec32ac7SDaniel Lezcano module_platform_driver(nxp_stm_probe);
493*cec32ac7SDaniel Lezcano 
494*cec32ac7SDaniel Lezcano MODULE_DESCRIPTION("NXP System Timer Module driver");
495*cec32ac7SDaniel Lezcano MODULE_LICENSE("GPL");
496