1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * Marvell Armada 370/XP SoC timer handling. |
4 | * |
5 | * Copyright (C) 2012 Marvell |
6 | * |
7 | * Lior Amsalem <alior@marvell.com> |
8 | * Gregory CLEMENT <gregory.clement@free-electrons.com> |
9 | * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> |
10 | * |
11 | * Timer 0 is used as free-running clocksource, while timer 1 is |
12 | * used as clock_event_device. |
13 | * |
14 | * --- |
15 | * Clocksource driver for Armada 370 and Armada XP SoC. |
16 | * This driver implements one compatible string for each SoC, given |
17 | * each has its own characteristics: |
18 | * |
19 | * * Armada 370 has no 25 MHz fixed timer. |
20 | * |
21 | * * Armada XP cannot work properly without such 25 MHz fixed timer as |
22 | * doing otherwise leads to using a clocksource whose frequency varies |
23 | * when doing cpufreq frequency changes. |
24 | * |
25 | * See Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt |
26 | */ |
27 | |
28 | #include <linux/init.h> |
29 | #include <linux/platform_device.h> |
30 | #include <linux/kernel.h> |
31 | #include <linux/clk.h> |
32 | #include <linux/cpu.h> |
33 | #include <linux/timer.h> |
34 | #include <linux/clockchips.h> |
35 | #include <linux/interrupt.h> |
36 | #include <linux/of.h> |
37 | #include <linux/of_irq.h> |
38 | #include <linux/of_address.h> |
39 | #include <linux/irq.h> |
40 | #include <linux/module.h> |
41 | #include <linux/sched_clock.h> |
42 | #include <linux/percpu.h> |
43 | #include <linux/syscore_ops.h> |
44 | |
45 | #include <asm/delay.h> |
46 | |
47 | /* |
48 | * Timer block registers. |
49 | */ |
50 | #define TIMER_CTRL_OFF 0x0000 |
51 | #define TIMER0_EN BIT(0) |
52 | #define TIMER0_RELOAD_EN BIT(1) |
53 | #define TIMER0_25MHZ BIT(11) |
54 | #define TIMER0_DIV(div) ((div) << 19) |
55 | #define TIMER1_EN BIT(2) |
56 | #define TIMER1_RELOAD_EN BIT(3) |
57 | #define TIMER1_25MHZ BIT(12) |
58 | #define TIMER1_DIV(div) ((div) << 22) |
59 | #define TIMER_EVENTS_STATUS 0x0004 |
60 | #define TIMER0_CLR_MASK (~0x1) |
61 | #define TIMER1_CLR_MASK (~0x100) |
62 | #define TIMER0_RELOAD_OFF 0x0010 |
63 | #define TIMER0_VAL_OFF 0x0014 |
64 | #define TIMER1_RELOAD_OFF 0x0018 |
65 | #define TIMER1_VAL_OFF 0x001c |
66 | |
67 | #define LCL_TIMER_EVENTS_STATUS 0x0028 |
68 | /* Global timers are connected to the coherency fabric clock, and the |
69 | below divider reduces their incrementing frequency. */ |
70 | #define TIMER_DIVIDER_SHIFT 5 |
71 | #define TIMER_DIVIDER (1 << TIMER_DIVIDER_SHIFT) |
72 | |
73 | /* |
74 | * SoC-specific data. |
75 | */ |
76 | static void __iomem *timer_base, *local_base; |
77 | static unsigned int timer_clk; |
78 | static bool timer25Mhz = true; |
79 | static u32 enable_mask; |
80 | |
81 | /* |
82 | * Number of timer ticks per jiffy. |
83 | */ |
84 | static u32 ticks_per_jiffy; |
85 | |
86 | static struct clock_event_device __percpu *armada_370_xp_evt; |
87 | |
88 | static void local_timer_ctrl_clrset(u32 clr, u32 set) |
89 | { |
90 | writel(val: (readl(addr: local_base + TIMER_CTRL_OFF) & ~clr) | set, |
91 | addr: local_base + TIMER_CTRL_OFF); |
92 | } |
93 | |
94 | static u64 notrace armada_370_xp_read_sched_clock(void) |
95 | { |
96 | return ~readl(addr: timer_base + TIMER0_VAL_OFF); |
97 | } |
98 | |
99 | /* |
100 | * Clockevent handling. |
101 | */ |
102 | static int |
103 | armada_370_xp_clkevt_next_event(unsigned long delta, |
104 | struct clock_event_device *dev) |
105 | { |
106 | /* |
107 | * Clear clockevent timer interrupt. |
108 | */ |
109 | writel(TIMER0_CLR_MASK, addr: local_base + LCL_TIMER_EVENTS_STATUS); |
110 | |
111 | /* |
112 | * Setup new clockevent timer value. |
113 | */ |
114 | writel(val: delta, addr: local_base + TIMER0_VAL_OFF); |
115 | |
116 | /* |
117 | * Enable the timer. |
118 | */ |
119 | local_timer_ctrl_clrset(TIMER0_RELOAD_EN, set: enable_mask); |
120 | return 0; |
121 | } |
122 | |
123 | static int armada_370_xp_clkevt_shutdown(struct clock_event_device *evt) |
124 | { |
125 | /* |
126 | * Disable timer. |
127 | */ |
128 | local_timer_ctrl_clrset(TIMER0_EN, set: 0); |
129 | |
130 | /* |
131 | * ACK pending timer interrupt. |
132 | */ |
133 | writel(TIMER0_CLR_MASK, addr: local_base + LCL_TIMER_EVENTS_STATUS); |
134 | return 0; |
135 | } |
136 | |
137 | static int armada_370_xp_clkevt_set_periodic(struct clock_event_device *evt) |
138 | { |
139 | /* |
140 | * Setup timer to fire at 1/HZ intervals. |
141 | */ |
142 | writel(val: ticks_per_jiffy - 1, addr: local_base + TIMER0_RELOAD_OFF); |
143 | writel(val: ticks_per_jiffy - 1, addr: local_base + TIMER0_VAL_OFF); |
144 | |
145 | /* |
146 | * Enable timer. |
147 | */ |
148 | local_timer_ctrl_clrset(clr: 0, TIMER0_RELOAD_EN | enable_mask); |
149 | return 0; |
150 | } |
151 | |
152 | static int armada_370_xp_clkevt_irq; |
153 | |
154 | static irqreturn_t armada_370_xp_timer_interrupt(int irq, void *dev_id) |
155 | { |
156 | /* |
157 | * ACK timer interrupt and call event handler. |
158 | */ |
159 | struct clock_event_device *evt = dev_id; |
160 | |
161 | writel(TIMER0_CLR_MASK, addr: local_base + LCL_TIMER_EVENTS_STATUS); |
162 | evt->event_handler(evt); |
163 | |
164 | return IRQ_HANDLED; |
165 | } |
166 | |
167 | /* |
168 | * Setup the local clock events for a CPU. |
169 | */ |
170 | static int armada_370_xp_timer_starting_cpu(unsigned int cpu) |
171 | { |
172 | struct clock_event_device *evt = per_cpu_ptr(armada_370_xp_evt, cpu); |
173 | u32 clr = 0, set = 0; |
174 | |
175 | if (timer25Mhz) |
176 | set = TIMER0_25MHZ; |
177 | else |
178 | clr = TIMER0_25MHZ; |
179 | local_timer_ctrl_clrset(clr, set); |
180 | |
181 | evt->name = "armada_370_xp_per_cpu_tick" ; |
182 | evt->features = CLOCK_EVT_FEAT_ONESHOT | |
183 | CLOCK_EVT_FEAT_PERIODIC; |
184 | evt->shift = 32; |
185 | evt->rating = 300; |
186 | evt->set_next_event = armada_370_xp_clkevt_next_event; |
187 | evt->set_state_shutdown = armada_370_xp_clkevt_shutdown; |
188 | evt->set_state_periodic = armada_370_xp_clkevt_set_periodic; |
189 | evt->set_state_oneshot = armada_370_xp_clkevt_shutdown; |
190 | evt->tick_resume = armada_370_xp_clkevt_shutdown; |
191 | evt->irq = armada_370_xp_clkevt_irq; |
192 | evt->cpumask = cpumask_of(cpu); |
193 | |
194 | clockevents_config_and_register(dev: evt, freq: timer_clk, min_delta: 1, max_delta: 0xfffffffe); |
195 | enable_percpu_irq(irq: evt->irq, type: 0); |
196 | |
197 | return 0; |
198 | } |
199 | |
200 | static int armada_370_xp_timer_dying_cpu(unsigned int cpu) |
201 | { |
202 | struct clock_event_device *evt = per_cpu_ptr(armada_370_xp_evt, cpu); |
203 | |
204 | evt->set_state_shutdown(evt); |
205 | disable_percpu_irq(irq: evt->irq); |
206 | return 0; |
207 | } |
208 | |
209 | static u32 timer0_ctrl_reg, timer0_local_ctrl_reg; |
210 | |
211 | static int armada_370_xp_timer_suspend(void) |
212 | { |
213 | timer0_ctrl_reg = readl(addr: timer_base + TIMER_CTRL_OFF); |
214 | timer0_local_ctrl_reg = readl(addr: local_base + TIMER_CTRL_OFF); |
215 | return 0; |
216 | } |
217 | |
218 | static void armada_370_xp_timer_resume(void) |
219 | { |
220 | writel(val: 0xffffffff, addr: timer_base + TIMER0_VAL_OFF); |
221 | writel(val: 0xffffffff, addr: timer_base + TIMER0_RELOAD_OFF); |
222 | writel(val: timer0_ctrl_reg, addr: timer_base + TIMER_CTRL_OFF); |
223 | writel(val: timer0_local_ctrl_reg, addr: local_base + TIMER_CTRL_OFF); |
224 | } |
225 | |
226 | static struct syscore_ops armada_370_xp_timer_syscore_ops = { |
227 | .suspend = armada_370_xp_timer_suspend, |
228 | .resume = armada_370_xp_timer_resume, |
229 | }; |
230 | |
231 | static unsigned long armada_370_delay_timer_read(void) |
232 | { |
233 | return ~readl(addr: timer_base + TIMER0_VAL_OFF); |
234 | } |
235 | |
236 | static struct delay_timer armada_370_delay_timer = { |
237 | .read_current_timer = armada_370_delay_timer_read, |
238 | }; |
239 | |
240 | static int __init armada_370_xp_timer_common_init(struct device_node *np) |
241 | { |
242 | u32 clr = 0, set = 0; |
243 | int res; |
244 | |
245 | timer_base = of_iomap(node: np, index: 0); |
246 | if (!timer_base) { |
247 | pr_err("Failed to iomap\n" ); |
248 | return -ENXIO; |
249 | } |
250 | |
251 | local_base = of_iomap(node: np, index: 1); |
252 | if (!local_base) { |
253 | pr_err("Failed to iomap\n" ); |
254 | return -ENXIO; |
255 | } |
256 | |
257 | if (timer25Mhz) { |
258 | set = TIMER0_25MHZ; |
259 | enable_mask = TIMER0_EN; |
260 | } else { |
261 | clr = TIMER0_25MHZ; |
262 | enable_mask = TIMER0_EN | TIMER0_DIV(TIMER_DIVIDER_SHIFT); |
263 | } |
264 | atomic_io_modify(timer_base + TIMER_CTRL_OFF, clr | set, set); |
265 | local_timer_ctrl_clrset(clr, set); |
266 | |
267 | /* |
268 | * We use timer 0 as clocksource, and private(local) timer 0 |
269 | * for clockevents |
270 | */ |
271 | armada_370_xp_clkevt_irq = irq_of_parse_and_map(node: np, index: 4); |
272 | |
273 | ticks_per_jiffy = (timer_clk + HZ / 2) / HZ; |
274 | |
275 | /* |
276 | * Setup free-running clocksource timer (interrupts |
277 | * disabled). |
278 | */ |
279 | writel(val: 0xffffffff, addr: timer_base + TIMER0_VAL_OFF); |
280 | writel(val: 0xffffffff, addr: timer_base + TIMER0_RELOAD_OFF); |
281 | |
282 | atomic_io_modify(timer_base + TIMER_CTRL_OFF, |
283 | TIMER0_RELOAD_EN | enable_mask, |
284 | TIMER0_RELOAD_EN | enable_mask); |
285 | |
286 | armada_370_delay_timer.freq = timer_clk; |
287 | register_current_timer_delay(&armada_370_delay_timer); |
288 | |
289 | /* |
290 | * Set scale and timer for sched_clock. |
291 | */ |
292 | sched_clock_register(read: armada_370_xp_read_sched_clock, bits: 32, rate: timer_clk); |
293 | |
294 | res = clocksource_mmio_init(timer_base + TIMER0_VAL_OFF, |
295 | "armada_370_xp_clocksource" , |
296 | timer_clk, 300, 32, clocksource_mmio_readl_down); |
297 | if (res) { |
298 | pr_err("Failed to initialize clocksource mmio\n" ); |
299 | return res; |
300 | } |
301 | |
302 | armada_370_xp_evt = alloc_percpu(struct clock_event_device); |
303 | if (!armada_370_xp_evt) |
304 | return -ENOMEM; |
305 | |
306 | /* |
307 | * Setup clockevent timer (interrupt-driven). |
308 | */ |
309 | res = request_percpu_irq(irq: armada_370_xp_clkevt_irq, |
310 | handler: armada_370_xp_timer_interrupt, |
311 | devname: "armada_370_xp_per_cpu_tick" , |
312 | percpu_dev_id: armada_370_xp_evt); |
313 | /* Immediately configure the timer on the boot CPU */ |
314 | if (res) { |
315 | pr_err("Failed to request percpu irq\n" ); |
316 | return res; |
317 | } |
318 | |
319 | res = cpuhp_setup_state(state: CPUHP_AP_ARMADA_TIMER_STARTING, |
320 | name: "clockevents/armada:starting" , |
321 | startup: armada_370_xp_timer_starting_cpu, |
322 | teardown: armada_370_xp_timer_dying_cpu); |
323 | if (res) { |
324 | pr_err("Failed to setup hotplug state and timer\n" ); |
325 | return res; |
326 | } |
327 | |
328 | register_syscore_ops(ops: &armada_370_xp_timer_syscore_ops); |
329 | |
330 | return 0; |
331 | } |
332 | |
333 | static int __init armada_xp_timer_init(struct device_node *np) |
334 | { |
335 | struct clk *clk = of_clk_get_by_name(np, name: "fixed" ); |
336 | int ret; |
337 | |
338 | if (IS_ERR(ptr: clk)) { |
339 | pr_err("Failed to get clock\n" ); |
340 | return PTR_ERR(ptr: clk); |
341 | } |
342 | |
343 | ret = clk_prepare_enable(clk); |
344 | if (ret) |
345 | return ret; |
346 | |
347 | timer_clk = clk_get_rate(clk); |
348 | |
349 | return armada_370_xp_timer_common_init(np); |
350 | } |
351 | TIMER_OF_DECLARE(armada_xp, "marvell,armada-xp-timer" , |
352 | armada_xp_timer_init); |
353 | |
354 | static int __init armada_375_timer_init(struct device_node *np) |
355 | { |
356 | struct clk *clk; |
357 | int ret; |
358 | |
359 | clk = of_clk_get_by_name(np, name: "fixed" ); |
360 | if (!IS_ERR(ptr: clk)) { |
361 | ret = clk_prepare_enable(clk); |
362 | if (ret) |
363 | return ret; |
364 | timer_clk = clk_get_rate(clk); |
365 | } else { |
366 | |
367 | /* |
368 | * This fallback is required in order to retain proper |
369 | * devicetree backwards compatibility. |
370 | */ |
371 | clk = of_clk_get(np, index: 0); |
372 | |
373 | /* Must have at least a clock */ |
374 | if (IS_ERR(ptr: clk)) { |
375 | pr_err("Failed to get clock\n" ); |
376 | return PTR_ERR(ptr: clk); |
377 | } |
378 | |
379 | ret = clk_prepare_enable(clk); |
380 | if (ret) |
381 | return ret; |
382 | |
383 | timer_clk = clk_get_rate(clk) / TIMER_DIVIDER; |
384 | timer25Mhz = false; |
385 | } |
386 | |
387 | return armada_370_xp_timer_common_init(np); |
388 | } |
389 | TIMER_OF_DECLARE(armada_375, "marvell,armada-375-timer" , |
390 | armada_375_timer_init); |
391 | |
392 | static int __init armada_370_timer_init(struct device_node *np) |
393 | { |
394 | struct clk *clk; |
395 | int ret; |
396 | |
397 | clk = of_clk_get(np, index: 0); |
398 | if (IS_ERR(ptr: clk)) { |
399 | pr_err("Failed to get clock\n" ); |
400 | return PTR_ERR(ptr: clk); |
401 | } |
402 | |
403 | ret = clk_prepare_enable(clk); |
404 | if (ret) |
405 | return ret; |
406 | |
407 | timer_clk = clk_get_rate(clk) / TIMER_DIVIDER; |
408 | timer25Mhz = false; |
409 | |
410 | return armada_370_xp_timer_common_init(np); |
411 | } |
412 | TIMER_OF_DECLARE(armada_370, "marvell,armada-370-timer" , |
413 | armada_370_timer_init); |
414 | |