1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * (C) Copyright 2009 Intel Corporation |
4 | * Author: Jacob Pan (jacob.jun.pan@intel.com) |
5 | * |
6 | * Shared with ARM platforms, Jamie Iles, Picochip 2011 |
7 | * |
8 | * Support for the Synopsys DesignWare APB Timers. |
9 | */ |
10 | #include <linux/dw_apb_timer.h> |
11 | #include <linux/delay.h> |
12 | #include <linux/kernel.h> |
13 | #include <linux/interrupt.h> |
14 | #include <linux/irq.h> |
15 | #include <linux/io.h> |
16 | #include <linux/slab.h> |
17 | |
18 | #define APBT_MIN_PERIOD 4 |
19 | #define APBT_MIN_DELTA_USEC 200 |
20 | |
21 | #define APBTMR_N_LOAD_COUNT 0x00 |
22 | #define APBTMR_N_CURRENT_VALUE 0x04 |
23 | #define APBTMR_N_CONTROL 0x08 |
24 | #define APBTMR_N_EOI 0x0c |
25 | #define APBTMR_N_INT_STATUS 0x10 |
26 | |
27 | #define APBTMRS_INT_STATUS 0xa0 |
28 | #define APBTMRS_EOI 0xa4 |
29 | #define APBTMRS_RAW_INT_STATUS 0xa8 |
30 | #define APBTMRS_COMP_VERSION 0xac |
31 | |
32 | #define APBTMR_CONTROL_ENABLE (1 << 0) |
33 | /* 1: periodic, 0:free running. */ |
34 | #define APBTMR_CONTROL_MODE_PERIODIC (1 << 1) |
35 | #define APBTMR_CONTROL_INT (1 << 2) |
36 | |
37 | static inline struct dw_apb_clock_event_device * |
38 | ced_to_dw_apb_ced(struct clock_event_device *evt) |
39 | { |
40 | return container_of(evt, struct dw_apb_clock_event_device, ced); |
41 | } |
42 | |
43 | static inline struct dw_apb_clocksource * |
44 | clocksource_to_dw_apb_clocksource(struct clocksource *cs) |
45 | { |
46 | return container_of(cs, struct dw_apb_clocksource, cs); |
47 | } |
48 | |
49 | static inline u32 apbt_readl(struct dw_apb_timer *timer, unsigned long offs) |
50 | { |
51 | return readl(addr: timer->base + offs); |
52 | } |
53 | |
54 | static inline void apbt_writel(struct dw_apb_timer *timer, u32 val, |
55 | unsigned long offs) |
56 | { |
57 | writel(val, addr: timer->base + offs); |
58 | } |
59 | |
60 | static inline u32 apbt_readl_relaxed(struct dw_apb_timer *timer, unsigned long offs) |
61 | { |
62 | return readl_relaxed(timer->base + offs); |
63 | } |
64 | |
65 | static inline void apbt_writel_relaxed(struct dw_apb_timer *timer, u32 val, |
66 | unsigned long offs) |
67 | { |
68 | writel_relaxed(val, timer->base + offs); |
69 | } |
70 | |
71 | static void apbt_disable_int(struct dw_apb_timer *timer) |
72 | { |
73 | u32 ctrl = apbt_readl(timer, APBTMR_N_CONTROL); |
74 | |
75 | ctrl |= APBTMR_CONTROL_INT; |
76 | apbt_writel(timer, val: ctrl, APBTMR_N_CONTROL); |
77 | } |
78 | |
79 | /** |
80 | * dw_apb_clockevent_pause() - stop the clock_event_device from running |
81 | * |
82 | * @dw_ced: The APB clock to stop generating events. |
83 | */ |
84 | void dw_apb_clockevent_pause(struct dw_apb_clock_event_device *dw_ced) |
85 | { |
86 | disable_irq(irq: dw_ced->timer.irq); |
87 | apbt_disable_int(timer: &dw_ced->timer); |
88 | } |
89 | |
90 | static void apbt_eoi(struct dw_apb_timer *timer) |
91 | { |
92 | apbt_readl_relaxed(timer, APBTMR_N_EOI); |
93 | } |
94 | |
95 | static irqreturn_t dw_apb_clockevent_irq(int irq, void *data) |
96 | { |
97 | struct clock_event_device *evt = data; |
98 | struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt); |
99 | |
100 | if (!evt->event_handler) { |
101 | pr_info("Spurious APBT timer interrupt %d\n" , irq); |
102 | return IRQ_NONE; |
103 | } |
104 | |
105 | if (dw_ced->eoi) |
106 | dw_ced->eoi(&dw_ced->timer); |
107 | |
108 | evt->event_handler(evt); |
109 | return IRQ_HANDLED; |
110 | } |
111 | |
112 | static void apbt_enable_int(struct dw_apb_timer *timer) |
113 | { |
114 | u32 ctrl = apbt_readl(timer, APBTMR_N_CONTROL); |
115 | /* clear pending intr */ |
116 | apbt_readl(timer, APBTMR_N_EOI); |
117 | ctrl &= ~APBTMR_CONTROL_INT; |
118 | apbt_writel(timer, val: ctrl, APBTMR_N_CONTROL); |
119 | } |
120 | |
121 | static int apbt_shutdown(struct clock_event_device *evt) |
122 | { |
123 | struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt); |
124 | u32 ctrl; |
125 | |
126 | pr_debug("%s CPU %d state=shutdown\n" , __func__, |
127 | cpumask_first(evt->cpumask)); |
128 | |
129 | ctrl = apbt_readl(timer: &dw_ced->timer, APBTMR_N_CONTROL); |
130 | ctrl &= ~APBTMR_CONTROL_ENABLE; |
131 | apbt_writel(timer: &dw_ced->timer, val: ctrl, APBTMR_N_CONTROL); |
132 | return 0; |
133 | } |
134 | |
135 | static int apbt_set_oneshot(struct clock_event_device *evt) |
136 | { |
137 | struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt); |
138 | u32 ctrl; |
139 | |
140 | pr_debug("%s CPU %d state=oneshot\n" , __func__, |
141 | cpumask_first(evt->cpumask)); |
142 | |
143 | ctrl = apbt_readl(timer: &dw_ced->timer, APBTMR_N_CONTROL); |
144 | /* |
145 | * set free running mode, this mode will let timer reload max |
146 | * timeout which will give time (3min on 25MHz clock) to rearm |
147 | * the next event, therefore emulate the one-shot mode. |
148 | */ |
149 | ctrl &= ~APBTMR_CONTROL_ENABLE; |
150 | ctrl &= ~APBTMR_CONTROL_MODE_PERIODIC; |
151 | |
152 | apbt_writel(timer: &dw_ced->timer, val: ctrl, APBTMR_N_CONTROL); |
153 | /* write again to set free running mode */ |
154 | apbt_writel(timer: &dw_ced->timer, val: ctrl, APBTMR_N_CONTROL); |
155 | |
156 | /* |
157 | * DW APB p. 46, load counter with all 1s before starting free |
158 | * running mode. |
159 | */ |
160 | apbt_writel(timer: &dw_ced->timer, val: ~0, APBTMR_N_LOAD_COUNT); |
161 | ctrl &= ~APBTMR_CONTROL_INT; |
162 | ctrl |= APBTMR_CONTROL_ENABLE; |
163 | apbt_writel(timer: &dw_ced->timer, val: ctrl, APBTMR_N_CONTROL); |
164 | return 0; |
165 | } |
166 | |
167 | static int apbt_set_periodic(struct clock_event_device *evt) |
168 | { |
169 | struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt); |
170 | unsigned long period = DIV_ROUND_UP(dw_ced->timer.freq, HZ); |
171 | u32 ctrl; |
172 | |
173 | pr_debug("%s CPU %d state=periodic\n" , __func__, |
174 | cpumask_first(evt->cpumask)); |
175 | |
176 | ctrl = apbt_readl(timer: &dw_ced->timer, APBTMR_N_CONTROL); |
177 | ctrl |= APBTMR_CONTROL_MODE_PERIODIC; |
178 | apbt_writel(timer: &dw_ced->timer, val: ctrl, APBTMR_N_CONTROL); |
179 | /* |
180 | * DW APB p. 46, have to disable timer before load counter, |
181 | * may cause sync problem. |
182 | */ |
183 | ctrl &= ~APBTMR_CONTROL_ENABLE; |
184 | apbt_writel(timer: &dw_ced->timer, val: ctrl, APBTMR_N_CONTROL); |
185 | udelay(1); |
186 | pr_debug("Setting clock period %lu for HZ %d\n" , period, HZ); |
187 | apbt_writel(timer: &dw_ced->timer, val: period, APBTMR_N_LOAD_COUNT); |
188 | ctrl |= APBTMR_CONTROL_ENABLE; |
189 | apbt_writel(timer: &dw_ced->timer, val: ctrl, APBTMR_N_CONTROL); |
190 | return 0; |
191 | } |
192 | |
193 | static int apbt_resume(struct clock_event_device *evt) |
194 | { |
195 | struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt); |
196 | |
197 | pr_debug("%s CPU %d state=resume\n" , __func__, |
198 | cpumask_first(evt->cpumask)); |
199 | |
200 | apbt_enable_int(timer: &dw_ced->timer); |
201 | return 0; |
202 | } |
203 | |
204 | static int apbt_next_event(unsigned long delta, |
205 | struct clock_event_device *evt) |
206 | { |
207 | u32 ctrl; |
208 | struct dw_apb_clock_event_device *dw_ced = ced_to_dw_apb_ced(evt); |
209 | |
210 | /* Disable timer */ |
211 | ctrl = apbt_readl_relaxed(timer: &dw_ced->timer, APBTMR_N_CONTROL); |
212 | ctrl &= ~APBTMR_CONTROL_ENABLE; |
213 | apbt_writel_relaxed(timer: &dw_ced->timer, val: ctrl, APBTMR_N_CONTROL); |
214 | /* write new count */ |
215 | apbt_writel_relaxed(timer: &dw_ced->timer, val: delta, APBTMR_N_LOAD_COUNT); |
216 | ctrl |= APBTMR_CONTROL_ENABLE; |
217 | apbt_writel_relaxed(timer: &dw_ced->timer, val: ctrl, APBTMR_N_CONTROL); |
218 | |
219 | return 0; |
220 | } |
221 | |
222 | /** |
223 | * dw_apb_clockevent_init() - use an APB timer as a clock_event_device |
224 | * |
225 | * @cpu: The CPU the events will be targeted at or -1 if CPU affiliation |
226 | * isn't required. |
227 | * @name: The name used for the timer and the IRQ for it. |
228 | * @rating: The rating to give the timer. |
229 | * @base: I/O base for the timer registers. |
230 | * @irq: The interrupt number to use for the timer. |
231 | * @freq: The frequency that the timer counts at. |
232 | * |
233 | * This creates a clock_event_device for using with the generic clock layer |
234 | * but does not start and register it. This should be done with |
235 | * dw_apb_clockevent_register() as the next step. If this is the first time |
236 | * it has been called for a timer then the IRQ will be requested, if not it |
237 | * just be enabled to allow CPU hotplug to avoid repeatedly requesting and |
238 | * releasing the IRQ. |
239 | */ |
240 | struct dw_apb_clock_event_device * |
241 | dw_apb_clockevent_init(int cpu, const char *name, unsigned rating, |
242 | void __iomem *base, int irq, unsigned long freq) |
243 | { |
244 | struct dw_apb_clock_event_device *dw_ced = |
245 | kzalloc(size: sizeof(*dw_ced), GFP_KERNEL); |
246 | int err; |
247 | |
248 | if (!dw_ced) |
249 | return NULL; |
250 | |
251 | dw_ced->timer.base = base; |
252 | dw_ced->timer.irq = irq; |
253 | dw_ced->timer.freq = freq; |
254 | |
255 | clockevents_calc_mult_shift(ce: &dw_ced->ced, freq, APBT_MIN_PERIOD); |
256 | dw_ced->ced.max_delta_ns = clockevent_delta2ns(latch: 0x7fffffff, |
257 | evt: &dw_ced->ced); |
258 | dw_ced->ced.max_delta_ticks = 0x7fffffff; |
259 | dw_ced->ced.min_delta_ns = clockevent_delta2ns(latch: 5000, evt: &dw_ced->ced); |
260 | dw_ced->ced.min_delta_ticks = 5000; |
261 | dw_ced->ced.cpumask = cpu < 0 ? cpu_possible_mask : cpumask_of(cpu); |
262 | dw_ced->ced.features = CLOCK_EVT_FEAT_PERIODIC | |
263 | CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_DYNIRQ; |
264 | dw_ced->ced.set_state_shutdown = apbt_shutdown; |
265 | dw_ced->ced.set_state_periodic = apbt_set_periodic; |
266 | dw_ced->ced.set_state_oneshot = apbt_set_oneshot; |
267 | dw_ced->ced.set_state_oneshot_stopped = apbt_shutdown; |
268 | dw_ced->ced.tick_resume = apbt_resume; |
269 | dw_ced->ced.set_next_event = apbt_next_event; |
270 | dw_ced->ced.irq = dw_ced->timer.irq; |
271 | dw_ced->ced.rating = rating; |
272 | dw_ced->ced.name = name; |
273 | |
274 | dw_ced->eoi = apbt_eoi; |
275 | err = request_irq(irq, handler: dw_apb_clockevent_irq, |
276 | IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING, |
277 | name: dw_ced->ced.name, dev: &dw_ced->ced); |
278 | if (err) { |
279 | pr_err("failed to request timer irq\n" ); |
280 | kfree(objp: dw_ced); |
281 | dw_ced = NULL; |
282 | } |
283 | |
284 | return dw_ced; |
285 | } |
286 | |
287 | /** |
288 | * dw_apb_clockevent_resume() - resume a clock that has been paused. |
289 | * |
290 | * @dw_ced: The APB clock to resume. |
291 | */ |
292 | void dw_apb_clockevent_resume(struct dw_apb_clock_event_device *dw_ced) |
293 | { |
294 | enable_irq(irq: dw_ced->timer.irq); |
295 | } |
296 | |
297 | /** |
298 | * dw_apb_clockevent_stop() - stop the clock_event_device and release the IRQ. |
299 | * |
300 | * @dw_ced: The APB clock to stop generating the events. |
301 | */ |
302 | void dw_apb_clockevent_stop(struct dw_apb_clock_event_device *dw_ced) |
303 | { |
304 | free_irq(dw_ced->timer.irq, &dw_ced->ced); |
305 | } |
306 | |
307 | /** |
308 | * dw_apb_clockevent_register() - register the clock with the generic layer |
309 | * |
310 | * @dw_ced: The APB clock to register as a clock_event_device. |
311 | */ |
312 | void dw_apb_clockevent_register(struct dw_apb_clock_event_device *dw_ced) |
313 | { |
314 | apbt_writel(timer: &dw_ced->timer, val: 0, APBTMR_N_CONTROL); |
315 | clockevents_register_device(dev: &dw_ced->ced); |
316 | apbt_enable_int(timer: &dw_ced->timer); |
317 | } |
318 | |
319 | /** |
320 | * dw_apb_clocksource_start() - start the clocksource counting. |
321 | * |
322 | * @dw_cs: The clocksource to start. |
323 | * |
324 | * This is used to start the clocksource before registration and can be used |
325 | * to enable calibration of timers. |
326 | */ |
327 | void dw_apb_clocksource_start(struct dw_apb_clocksource *dw_cs) |
328 | { |
329 | /* |
330 | * start count down from 0xffff_ffff. this is done by toggling the |
331 | * enable bit then load initial load count to ~0. |
332 | */ |
333 | u32 ctrl = apbt_readl(timer: &dw_cs->timer, APBTMR_N_CONTROL); |
334 | |
335 | ctrl &= ~APBTMR_CONTROL_ENABLE; |
336 | apbt_writel(timer: &dw_cs->timer, val: ctrl, APBTMR_N_CONTROL); |
337 | apbt_writel(timer: &dw_cs->timer, val: ~0, APBTMR_N_LOAD_COUNT); |
338 | /* enable, mask interrupt */ |
339 | ctrl &= ~APBTMR_CONTROL_MODE_PERIODIC; |
340 | ctrl |= (APBTMR_CONTROL_ENABLE | APBTMR_CONTROL_INT); |
341 | apbt_writel(timer: &dw_cs->timer, val: ctrl, APBTMR_N_CONTROL); |
342 | /* read it once to get cached counter value initialized */ |
343 | dw_apb_clocksource_read(dw_cs); |
344 | } |
345 | |
346 | static u64 __apbt_read_clocksource(struct clocksource *cs) |
347 | { |
348 | u32 current_count; |
349 | struct dw_apb_clocksource *dw_cs = |
350 | clocksource_to_dw_apb_clocksource(cs); |
351 | |
352 | current_count = apbt_readl_relaxed(timer: &dw_cs->timer, |
353 | APBTMR_N_CURRENT_VALUE); |
354 | |
355 | return (u64)~current_count; |
356 | } |
357 | |
358 | static void apbt_restart_clocksource(struct clocksource *cs) |
359 | { |
360 | struct dw_apb_clocksource *dw_cs = |
361 | clocksource_to_dw_apb_clocksource(cs); |
362 | |
363 | dw_apb_clocksource_start(dw_cs); |
364 | } |
365 | |
366 | /** |
367 | * dw_apb_clocksource_init() - use an APB timer as a clocksource. |
368 | * |
369 | * @rating: The rating to give the clocksource. |
370 | * @name: The name for the clocksource. |
371 | * @base: The I/O base for the timer registers. |
372 | * @freq: The frequency that the timer counts at. |
373 | * |
374 | * This creates a clocksource using an APB timer but does not yet register it |
375 | * with the clocksource system. This should be done with |
376 | * dw_apb_clocksource_register() as the next step. |
377 | */ |
378 | struct dw_apb_clocksource * |
379 | dw_apb_clocksource_init(unsigned rating, const char *name, void __iomem *base, |
380 | unsigned long freq) |
381 | { |
382 | struct dw_apb_clocksource *dw_cs = kzalloc(size: sizeof(*dw_cs), GFP_KERNEL); |
383 | |
384 | if (!dw_cs) |
385 | return NULL; |
386 | |
387 | dw_cs->timer.base = base; |
388 | dw_cs->timer.freq = freq; |
389 | dw_cs->cs.name = name; |
390 | dw_cs->cs.rating = rating; |
391 | dw_cs->cs.read = __apbt_read_clocksource; |
392 | dw_cs->cs.mask = CLOCKSOURCE_MASK(32); |
393 | dw_cs->cs.flags = CLOCK_SOURCE_IS_CONTINUOUS; |
394 | dw_cs->cs.resume = apbt_restart_clocksource; |
395 | |
396 | return dw_cs; |
397 | } |
398 | |
399 | /** |
400 | * dw_apb_clocksource_register() - register the APB clocksource. |
401 | * |
402 | * @dw_cs: The clocksource to register. |
403 | */ |
404 | void dw_apb_clocksource_register(struct dw_apb_clocksource *dw_cs) |
405 | { |
406 | clocksource_register_hz(cs: &dw_cs->cs, hz: dw_cs->timer.freq); |
407 | } |
408 | |
409 | /** |
410 | * dw_apb_clocksource_read() - read the current value of a clocksource. |
411 | * |
412 | * @dw_cs: The clocksource to read. |
413 | */ |
414 | u64 dw_apb_clocksource_read(struct dw_apb_clocksource *dw_cs) |
415 | { |
416 | return (u64)~apbt_readl(timer: &dw_cs->timer, APBTMR_N_CURRENT_VALUE); |
417 | } |
418 | |