1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Mediatek SoCs General-Purpose Timer handling. |
4 | * |
5 | * Copyright (C) 2014 Matthias Brugger |
6 | * |
7 | * Matthias Brugger <matthias.bgg@gmail.com> |
8 | */ |
9 | |
10 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
11 | |
12 | #include <linux/clockchips.h> |
13 | #include <linux/clocksource.h> |
14 | #include <linux/interrupt.h> |
15 | #include <linux/irqreturn.h> |
16 | #include <linux/sched_clock.h> |
17 | #include <linux/slab.h> |
18 | #include "timer-of.h" |
19 | |
20 | #define TIMER_CLK_EVT (1) |
21 | #define TIMER_CLK_SRC (2) |
22 | |
23 | #define TIMER_SYNC_TICKS (3) |
24 | |
25 | /* gpt */ |
26 | #define GPT_IRQ_EN_REG 0x00 |
27 | #define GPT_IRQ_ENABLE(val) BIT((val) - 1) |
28 | #define GPT_IRQ_ACK_REG 0x08 |
29 | #define GPT_IRQ_ACK(val) BIT((val) - 1) |
30 | |
31 | #define GPT_CTRL_REG(val) (0x10 * (val)) |
32 | #define GPT_CTRL_OP(val) (((val) & 0x3) << 4) |
33 | #define GPT_CTRL_OP_ONESHOT (0) |
34 | #define GPT_CTRL_OP_REPEAT (1) |
35 | #define GPT_CTRL_OP_FREERUN (3) |
36 | #define GPT_CTRL_CLEAR (2) |
37 | #define GPT_CTRL_ENABLE (1) |
38 | #define GPT_CTRL_DISABLE (0) |
39 | |
40 | #define GPT_CLK_REG(val) (0x04 + (0x10 * (val))) |
41 | #define GPT_CLK_SRC(val) (((val) & 0x1) << 4) |
42 | #define GPT_CLK_SRC_SYS13M (0) |
43 | #define GPT_CLK_SRC_RTC32K (1) |
44 | #define GPT_CLK_DIV1 (0x0) |
45 | #define GPT_CLK_DIV2 (0x1) |
46 | |
47 | #define GPT_CNT_REG(val) (0x08 + (0x10 * (val))) |
48 | #define GPT_CMP_REG(val) (0x0C + (0x10 * (val))) |
49 | |
50 | /* system timer */ |
51 | #define SYST_BASE (0x40) |
52 | |
53 | #define SYST_CON (SYST_BASE + 0x0) |
54 | #define SYST_VAL (SYST_BASE + 0x4) |
55 | |
56 | #define SYST_CON_REG(to) (timer_of_base(to) + SYST_CON) |
57 | #define SYST_VAL_REG(to) (timer_of_base(to) + SYST_VAL) |
58 | |
59 | /* |
60 | * SYST_CON_EN: Clock enable. Shall be set to |
61 | * - Start timer countdown. |
62 | * - Allow timeout ticks being updated. |
63 | * - Allow changing interrupt status,like clear irq pending. |
64 | * |
65 | * SYST_CON_IRQ_EN: Set to enable interrupt. |
66 | * |
67 | * SYST_CON_IRQ_CLR: Set to clear interrupt. |
68 | */ |
69 | #define SYST_CON_EN BIT(0) |
70 | #define SYST_CON_IRQ_EN BIT(1) |
71 | #define SYST_CON_IRQ_CLR BIT(4) |
72 | |
73 | static void __iomem *gpt_sched_reg __read_mostly; |
74 | |
75 | static void mtk_syst_ack_irq(struct timer_of *to) |
76 | { |
77 | /* Clear and disable interrupt */ |
78 | writel(SYST_CON_EN, SYST_CON_REG(to)); |
79 | writel(SYST_CON_IRQ_CLR | SYST_CON_EN, SYST_CON_REG(to)); |
80 | } |
81 | |
82 | static irqreturn_t mtk_syst_handler(int irq, void *dev_id) |
83 | { |
84 | struct clock_event_device *clkevt = dev_id; |
85 | struct timer_of *to = to_timer_of(clkevt); |
86 | |
87 | mtk_syst_ack_irq(to); |
88 | clkevt->event_handler(clkevt); |
89 | |
90 | return IRQ_HANDLED; |
91 | } |
92 | |
93 | static int mtk_syst_clkevt_next_event(unsigned long ticks, |
94 | struct clock_event_device *clkevt) |
95 | { |
96 | struct timer_of *to = to_timer_of(clkevt); |
97 | |
98 | /* Enable clock to allow timeout tick update later */ |
99 | writel(SYST_CON_EN, SYST_CON_REG(to)); |
100 | |
101 | /* |
102 | * Write new timeout ticks. Timer shall start countdown |
103 | * after timeout ticks are updated. |
104 | */ |
105 | writel(val: ticks, SYST_VAL_REG(to)); |
106 | |
107 | /* Enable interrupt */ |
108 | writel(SYST_CON_EN | SYST_CON_IRQ_EN, SYST_CON_REG(to)); |
109 | |
110 | return 0; |
111 | } |
112 | |
113 | static int mtk_syst_clkevt_shutdown(struct clock_event_device *clkevt) |
114 | { |
115 | /* Clear any irq */ |
116 | mtk_syst_ack_irq(to: to_timer_of(clkevt)); |
117 | |
118 | /* Disable timer */ |
119 | writel(val: 0, SYST_CON_REG(to_timer_of(clkevt))); |
120 | |
121 | return 0; |
122 | } |
123 | |
124 | static int mtk_syst_clkevt_resume(struct clock_event_device *clkevt) |
125 | { |
126 | return mtk_syst_clkevt_shutdown(clkevt); |
127 | } |
128 | |
129 | static int mtk_syst_clkevt_oneshot(struct clock_event_device *clkevt) |
130 | { |
131 | return 0; |
132 | } |
133 | |
134 | static u64 notrace mtk_gpt_read_sched_clock(void) |
135 | { |
136 | return readl_relaxed(gpt_sched_reg); |
137 | } |
138 | |
139 | static void mtk_gpt_clkevt_time_stop(struct timer_of *to, u8 timer) |
140 | { |
141 | u32 val; |
142 | |
143 | val = readl(addr: timer_of_base(to) + GPT_CTRL_REG(timer)); |
144 | writel(val: val & ~GPT_CTRL_ENABLE, addr: timer_of_base(to) + |
145 | GPT_CTRL_REG(timer)); |
146 | } |
147 | |
148 | static void mtk_gpt_clkevt_time_setup(struct timer_of *to, |
149 | unsigned long delay, u8 timer) |
150 | { |
151 | writel(val: delay, addr: timer_of_base(to) + GPT_CMP_REG(timer)); |
152 | } |
153 | |
154 | static void mtk_gpt_clkevt_time_start(struct timer_of *to, |
155 | bool periodic, u8 timer) |
156 | { |
157 | u32 val; |
158 | |
159 | /* Acknowledge interrupt */ |
160 | writel(GPT_IRQ_ACK(timer), addr: timer_of_base(to) + GPT_IRQ_ACK_REG); |
161 | |
162 | val = readl(addr: timer_of_base(to) + GPT_CTRL_REG(timer)); |
163 | |
164 | /* Clear 2 bit timer operation mode field */ |
165 | val &= ~GPT_CTRL_OP(0x3); |
166 | |
167 | if (periodic) |
168 | val |= GPT_CTRL_OP(GPT_CTRL_OP_REPEAT); |
169 | else |
170 | val |= GPT_CTRL_OP(GPT_CTRL_OP_ONESHOT); |
171 | |
172 | writel(val: val | GPT_CTRL_ENABLE | GPT_CTRL_CLEAR, |
173 | addr: timer_of_base(to) + GPT_CTRL_REG(timer)); |
174 | } |
175 | |
176 | static int mtk_gpt_clkevt_shutdown(struct clock_event_device *clk) |
177 | { |
178 | mtk_gpt_clkevt_time_stop(to: to_timer_of(clkevt: clk), TIMER_CLK_EVT); |
179 | |
180 | return 0; |
181 | } |
182 | |
183 | static int mtk_gpt_clkevt_set_periodic(struct clock_event_device *clk) |
184 | { |
185 | struct timer_of *to = to_timer_of(clkevt: clk); |
186 | |
187 | mtk_gpt_clkevt_time_stop(to, TIMER_CLK_EVT); |
188 | mtk_gpt_clkevt_time_setup(to, delay: to->of_clk.period, TIMER_CLK_EVT); |
189 | mtk_gpt_clkevt_time_start(to, periodic: true, TIMER_CLK_EVT); |
190 | |
191 | return 0; |
192 | } |
193 | |
194 | static int mtk_gpt_clkevt_next_event(unsigned long event, |
195 | struct clock_event_device *clk) |
196 | { |
197 | struct timer_of *to = to_timer_of(clkevt: clk); |
198 | |
199 | mtk_gpt_clkevt_time_stop(to, TIMER_CLK_EVT); |
200 | mtk_gpt_clkevt_time_setup(to, delay: event, TIMER_CLK_EVT); |
201 | mtk_gpt_clkevt_time_start(to, periodic: false, TIMER_CLK_EVT); |
202 | |
203 | return 0; |
204 | } |
205 | |
206 | static irqreturn_t mtk_gpt_interrupt(int irq, void *dev_id) |
207 | { |
208 | struct clock_event_device *clkevt = (struct clock_event_device *)dev_id; |
209 | struct timer_of *to = to_timer_of(clkevt); |
210 | |
211 | /* Acknowledge timer0 irq */ |
212 | writel(GPT_IRQ_ACK(TIMER_CLK_EVT), addr: timer_of_base(to) + GPT_IRQ_ACK_REG); |
213 | clkevt->event_handler(clkevt); |
214 | |
215 | return IRQ_HANDLED; |
216 | } |
217 | |
218 | static void |
219 | __init mtk_gpt_setup(struct timer_of *to, u8 timer, u8 option) |
220 | { |
221 | writel(GPT_CTRL_CLEAR | GPT_CTRL_DISABLE, |
222 | addr: timer_of_base(to) + GPT_CTRL_REG(timer)); |
223 | |
224 | writel(GPT_CLK_SRC(GPT_CLK_SRC_SYS13M) | GPT_CLK_DIV1, |
225 | addr: timer_of_base(to) + GPT_CLK_REG(timer)); |
226 | |
227 | writel(val: 0x0, addr: timer_of_base(to) + GPT_CMP_REG(timer)); |
228 | |
229 | writel(GPT_CTRL_OP(option) | GPT_CTRL_ENABLE, |
230 | addr: timer_of_base(to) + GPT_CTRL_REG(timer)); |
231 | } |
232 | |
233 | static void mtk_gpt_enable_irq(struct timer_of *to, u8 timer) |
234 | { |
235 | u32 val; |
236 | |
237 | /* Disable all interrupts */ |
238 | writel(val: 0x0, addr: timer_of_base(to) + GPT_IRQ_EN_REG); |
239 | |
240 | /* Acknowledge all spurious pending interrupts */ |
241 | writel(val: 0x3f, addr: timer_of_base(to) + GPT_IRQ_ACK_REG); |
242 | |
243 | val = readl(addr: timer_of_base(to) + GPT_IRQ_EN_REG); |
244 | writel(val: val | GPT_IRQ_ENABLE(timer), |
245 | addr: timer_of_base(to) + GPT_IRQ_EN_REG); |
246 | } |
247 | |
248 | static void mtk_gpt_resume(struct clock_event_device *clk) |
249 | { |
250 | struct timer_of *to = to_timer_of(clkevt: clk); |
251 | |
252 | mtk_gpt_enable_irq(to, TIMER_CLK_EVT); |
253 | } |
254 | |
255 | static void mtk_gpt_suspend(struct clock_event_device *clk) |
256 | { |
257 | struct timer_of *to = to_timer_of(clkevt: clk); |
258 | |
259 | /* Disable all interrupts */ |
260 | writel(val: 0x0, addr: timer_of_base(to) + GPT_IRQ_EN_REG); |
261 | |
262 | /* |
263 | * This is called with interrupts disabled, |
264 | * so we need to ack any interrupt that is pending |
265 | * or for example ATF will prevent a suspend from completing. |
266 | */ |
267 | writel(val: 0x3f, addr: timer_of_base(to) + GPT_IRQ_ACK_REG); |
268 | } |
269 | |
270 | static struct timer_of to = { |
271 | .flags = TIMER_OF_IRQ | TIMER_OF_BASE | TIMER_OF_CLOCK, |
272 | |
273 | .clkevt = { |
274 | .name = "mtk-clkevt" , |
275 | .rating = 300, |
276 | .cpumask = cpu_possible_mask, |
277 | }, |
278 | |
279 | .of_irq = { |
280 | .flags = IRQF_TIMER | IRQF_IRQPOLL, |
281 | }, |
282 | }; |
283 | |
284 | static int __init mtk_syst_init(struct device_node *node) |
285 | { |
286 | int ret; |
287 | |
288 | to.clkevt.features = CLOCK_EVT_FEAT_DYNIRQ | CLOCK_EVT_FEAT_ONESHOT; |
289 | to.clkevt.set_state_shutdown = mtk_syst_clkevt_shutdown; |
290 | to.clkevt.set_state_oneshot = mtk_syst_clkevt_oneshot; |
291 | to.clkevt.tick_resume = mtk_syst_clkevt_resume; |
292 | to.clkevt.set_next_event = mtk_syst_clkevt_next_event; |
293 | to.of_irq.handler = mtk_syst_handler; |
294 | |
295 | ret = timer_of_init(np: node, to: &to); |
296 | if (ret) |
297 | return ret; |
298 | |
299 | clockevents_config_and_register(dev: &to.clkevt, freq: timer_of_rate(to: &to), |
300 | TIMER_SYNC_TICKS, max_delta: 0xffffffff); |
301 | |
302 | return 0; |
303 | } |
304 | |
305 | static int __init mtk_gpt_init(struct device_node *node) |
306 | { |
307 | int ret; |
308 | |
309 | to.clkevt.features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; |
310 | to.clkevt.set_state_shutdown = mtk_gpt_clkevt_shutdown; |
311 | to.clkevt.set_state_periodic = mtk_gpt_clkevt_set_periodic; |
312 | to.clkevt.set_state_oneshot = mtk_gpt_clkevt_shutdown; |
313 | to.clkevt.tick_resume = mtk_gpt_clkevt_shutdown; |
314 | to.clkevt.set_next_event = mtk_gpt_clkevt_next_event; |
315 | to.clkevt.suspend = mtk_gpt_suspend; |
316 | to.clkevt.resume = mtk_gpt_resume; |
317 | to.of_irq.handler = mtk_gpt_interrupt; |
318 | |
319 | ret = timer_of_init(np: node, to: &to); |
320 | if (ret) |
321 | return ret; |
322 | |
323 | /* Configure clock source */ |
324 | mtk_gpt_setup(to: &to, TIMER_CLK_SRC, GPT_CTRL_OP_FREERUN); |
325 | clocksource_mmio_init(timer_of_base(to: &to) + GPT_CNT_REG(TIMER_CLK_SRC), |
326 | node->name, timer_of_rate(to: &to), 300, 32, |
327 | clocksource_mmio_readl_up); |
328 | gpt_sched_reg = timer_of_base(to: &to) + GPT_CNT_REG(TIMER_CLK_SRC); |
329 | sched_clock_register(read: mtk_gpt_read_sched_clock, bits: 32, rate: timer_of_rate(to: &to)); |
330 | |
331 | /* Configure clock event */ |
332 | mtk_gpt_setup(to: &to, TIMER_CLK_EVT, GPT_CTRL_OP_REPEAT); |
333 | clockevents_config_and_register(dev: &to.clkevt, freq: timer_of_rate(to: &to), |
334 | TIMER_SYNC_TICKS, max_delta: 0xffffffff); |
335 | |
336 | mtk_gpt_enable_irq(to: &to, TIMER_CLK_EVT); |
337 | |
338 | return 0; |
339 | } |
340 | TIMER_OF_DECLARE(mtk_mt6577, "mediatek,mt6577-timer" , mtk_gpt_init); |
341 | TIMER_OF_DECLARE(mtk_mt6765, "mediatek,mt6765-timer" , mtk_syst_init); |
342 | |