Commit | Line | Data |
---|---|---|
9952f691 | 1 | // SPDX-License-Identifier: GPL-2.0-only |
89355274 NA |
2 | /* |
3 | * drivers/clocksource/timer-oxnas-rps.c | |
4 | * | |
5 | * Copyright (C) 2009 Oxford Semiconductor Ltd | |
6 | * Copyright (C) 2013 Ma Haijun <mahaijuns@gmail.com> | |
7 | * Copyright (C) 2016 Neil Armstrong <narmstrong@baylibre.com> | |
89355274 NA |
8 | */ |
9 | ||
10 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
11 | ||
12 | #include <linux/init.h> | |
13 | #include <linux/irq.h> | |
14 | #include <linux/io.h> | |
15 | #include <linux/clk.h> | |
16 | #include <linux/slab.h> | |
17 | #include <linux/interrupt.h> | |
18 | #include <linux/of_irq.h> | |
19 | #include <linux/of_address.h> | |
20 | #include <linux/clockchips.h> | |
21 | #include <linux/sched_clock.h> | |
22 | ||
23 | /* TIMER1 used as tick | |
24 | * TIMER2 used as clocksource | |
25 | */ | |
26 | ||
27 | /* Registers definitions */ | |
28 | ||
29 | #define TIMER_LOAD_REG 0x0 | |
30 | #define TIMER_CURR_REG 0x4 | |
31 | #define TIMER_CTRL_REG 0x8 | |
32 | #define TIMER_CLRINT_REG 0xC | |
33 | ||
34 | #define TIMER_BITS 24 | |
35 | ||
36 | #define TIMER_MAX_VAL (BIT(TIMER_BITS) - 1) | |
37 | ||
38 | #define TIMER_PERIODIC BIT(6) | |
39 | #define TIMER_ENABLE BIT(7) | |
40 | ||
41 | #define TIMER_DIV1 (0) | |
42 | #define TIMER_DIV16 (1 << 2) | |
43 | #define TIMER_DIV256 (2 << 2) | |
44 | ||
45 | #define TIMER1_REG_OFFSET 0 | |
46 | #define TIMER2_REG_OFFSET 0x20 | |
47 | ||
48 | /* Clockevent & Clocksource data */ | |
49 | ||
50 | struct oxnas_rps_timer { | |
51 | struct clock_event_device clkevent; | |
52 | void __iomem *clksrc_base; | |
53 | void __iomem *clkevt_base; | |
54 | unsigned long timer_period; | |
55 | unsigned int timer_prescaler; | |
56 | struct clk *clk; | |
57 | int irq; | |
58 | }; | |
59 | ||
60 | static irqreturn_t oxnas_rps_timer_irq(int irq, void *dev_id) | |
61 | { | |
62 | struct oxnas_rps_timer *rps = dev_id; | |
63 | ||
64 | writel_relaxed(0, rps->clkevt_base + TIMER_CLRINT_REG); | |
65 | ||
66 | rps->clkevent.event_handler(&rps->clkevent); | |
67 | ||
68 | return IRQ_HANDLED; | |
69 | } | |
70 | ||
71 | static void oxnas_rps_timer_config(struct oxnas_rps_timer *rps, | |
72 | unsigned long period, | |
73 | unsigned int periodic) | |
74 | { | |
75 | uint32_t cfg = rps->timer_prescaler; | |
76 | ||
77 | if (period) | |
78 | cfg |= TIMER_ENABLE; | |
79 | ||
80 | if (periodic) | |
81 | cfg |= TIMER_PERIODIC; | |
82 | ||
83 | writel_relaxed(period, rps->clkevt_base + TIMER_LOAD_REG); | |
84 | writel_relaxed(cfg, rps->clkevt_base + TIMER_CTRL_REG); | |
85 | } | |
86 | ||
87 | static int oxnas_rps_timer_shutdown(struct clock_event_device *evt) | |
88 | { | |
89 | struct oxnas_rps_timer *rps = | |
90 | container_of(evt, struct oxnas_rps_timer, clkevent); | |
91 | ||
92 | oxnas_rps_timer_config(rps, 0, 0); | |
93 | ||
94 | return 0; | |
95 | } | |
96 | ||
97 | static int oxnas_rps_timer_set_periodic(struct clock_event_device *evt) | |
98 | { | |
99 | struct oxnas_rps_timer *rps = | |
100 | container_of(evt, struct oxnas_rps_timer, clkevent); | |
101 | ||
102 | oxnas_rps_timer_config(rps, rps->timer_period, 1); | |
103 | ||
104 | return 0; | |
105 | } | |
106 | ||
107 | static int oxnas_rps_timer_set_oneshot(struct clock_event_device *evt) | |
108 | { | |
109 | struct oxnas_rps_timer *rps = | |
110 | container_of(evt, struct oxnas_rps_timer, clkevent); | |
111 | ||
112 | oxnas_rps_timer_config(rps, rps->timer_period, 0); | |
113 | ||
114 | return 0; | |
115 | } | |
116 | ||
117 | static int oxnas_rps_timer_next_event(unsigned long delta, | |
118 | struct clock_event_device *evt) | |
119 | { | |
120 | struct oxnas_rps_timer *rps = | |
121 | container_of(evt, struct oxnas_rps_timer, clkevent); | |
122 | ||
123 | oxnas_rps_timer_config(rps, delta, 0); | |
124 | ||
125 | return 0; | |
126 | } | |
127 | ||
128 | static int __init oxnas_rps_clockevent_init(struct oxnas_rps_timer *rps) | |
129 | { | |
130 | ulong clk_rate = clk_get_rate(rps->clk); | |
131 | ulong timer_rate; | |
132 | ||
133 | /* Start with prescaler 1 */ | |
134 | rps->timer_prescaler = TIMER_DIV1; | |
135 | rps->timer_period = DIV_ROUND_UP(clk_rate, HZ); | |
136 | timer_rate = clk_rate; | |
137 | ||
138 | if (rps->timer_period > TIMER_MAX_VAL) { | |
139 | rps->timer_prescaler = TIMER_DIV16; | |
140 | timer_rate = clk_rate / 16; | |
141 | rps->timer_period = DIV_ROUND_UP(timer_rate, HZ); | |
142 | } | |
143 | if (rps->timer_period > TIMER_MAX_VAL) { | |
144 | rps->timer_prescaler = TIMER_DIV256; | |
145 | timer_rate = clk_rate / 256; | |
146 | rps->timer_period = DIV_ROUND_UP(timer_rate, HZ); | |
147 | } | |
148 | ||
149 | rps->clkevent.name = "oxnas-rps"; | |
150 | rps->clkevent.features = CLOCK_EVT_FEAT_PERIODIC | | |
151 | CLOCK_EVT_FEAT_ONESHOT | | |
152 | CLOCK_EVT_FEAT_DYNIRQ; | |
153 | rps->clkevent.tick_resume = oxnas_rps_timer_shutdown; | |
154 | rps->clkevent.set_state_shutdown = oxnas_rps_timer_shutdown; | |
155 | rps->clkevent.set_state_periodic = oxnas_rps_timer_set_periodic; | |
156 | rps->clkevent.set_state_oneshot = oxnas_rps_timer_set_oneshot; | |
157 | rps->clkevent.set_next_event = oxnas_rps_timer_next_event; | |
158 | rps->clkevent.rating = 200; | |
159 | rps->clkevent.cpumask = cpu_possible_mask; | |
160 | rps->clkevent.irq = rps->irq; | |
161 | clockevents_config_and_register(&rps->clkevent, | |
162 | timer_rate, | |
163 | 1, | |
164 | TIMER_MAX_VAL); | |
165 | ||
166 | pr_info("Registered clock event rate %luHz prescaler %x period %lu\n", | |
167 | clk_rate, | |
168 | rps->timer_prescaler, | |
169 | rps->timer_period); | |
170 | ||
171 | return 0; | |
172 | } | |
173 | ||
174 | /* Clocksource */ | |
175 | ||
176 | static void __iomem *timer_sched_base; | |
177 | ||
178 | static u64 notrace oxnas_rps_read_sched_clock(void) | |
179 | { | |
180 | return ~readl_relaxed(timer_sched_base); | |
181 | } | |
182 | ||
183 | static int __init oxnas_rps_clocksource_init(struct oxnas_rps_timer *rps) | |
184 | { | |
185 | ulong clk_rate = clk_get_rate(rps->clk); | |
186 | int ret; | |
187 | ||
188 | /* use prescale 16 */ | |
189 | clk_rate = clk_rate / 16; | |
190 | ||
191 | writel_relaxed(TIMER_MAX_VAL, rps->clksrc_base + TIMER_LOAD_REG); | |
192 | writel_relaxed(TIMER_PERIODIC | TIMER_ENABLE | TIMER_DIV16, | |
193 | rps->clksrc_base + TIMER_CTRL_REG); | |
194 | ||
195 | timer_sched_base = rps->clksrc_base + TIMER_CURR_REG; | |
196 | sched_clock_register(oxnas_rps_read_sched_clock, | |
197 | TIMER_BITS, clk_rate); | |
198 | ret = clocksource_mmio_init(timer_sched_base, | |
199 | "oxnas_rps_clocksource_timer", | |
200 | clk_rate, 250, TIMER_BITS, | |
201 | clocksource_mmio_readl_down); | |
202 | if (WARN_ON(ret)) { | |
203 | pr_err("can't register clocksource\n"); | |
204 | return ret; | |
205 | } | |
206 | ||
207 | pr_info("Registered clocksource rate %luHz\n", clk_rate); | |
208 | ||
209 | return 0; | |
210 | } | |
211 | ||
8595b1ba | 212 | static int __init oxnas_rps_timer_init(struct device_node *np) |
89355274 NA |
213 | { |
214 | struct oxnas_rps_timer *rps; | |
215 | void __iomem *base; | |
216 | int ret; | |
217 | ||
218 | rps = kzalloc(sizeof(*rps), GFP_KERNEL); | |
8595b1ba DL |
219 | if (!rps) |
220 | return -ENOMEM; | |
89355274 NA |
221 | |
222 | rps->clk = of_clk_get(np, 0); | |
8595b1ba DL |
223 | if (IS_ERR(rps->clk)) { |
224 | ret = PTR_ERR(rps->clk); | |
89355274 | 225 | goto err_alloc; |
8595b1ba | 226 | } |
89355274 | 227 | |
8595b1ba DL |
228 | ret = clk_prepare_enable(rps->clk); |
229 | if (ret) | |
89355274 NA |
230 | goto err_clk; |
231 | ||
232 | base = of_iomap(np, 0); | |
8595b1ba DL |
233 | if (!base) { |
234 | ret = -ENXIO; | |
89355274 | 235 | goto err_clk_prepare; |
8595b1ba | 236 | } |
89355274 NA |
237 | |
238 | rps->irq = irq_of_parse_and_map(np, 0); | |
8595b1ba DL |
239 | if (rps->irq < 0) { |
240 | ret = -EINVAL; | |
89355274 | 241 | goto err_iomap; |
8595b1ba | 242 | } |
89355274 NA |
243 | |
244 | rps->clkevt_base = base + TIMER1_REG_OFFSET; | |
245 | rps->clksrc_base = base + TIMER2_REG_OFFSET; | |
246 | ||
247 | /* Disable timers */ | |
248 | writel_relaxed(0, rps->clkevt_base + TIMER_CTRL_REG); | |
249 | writel_relaxed(0, rps->clksrc_base + TIMER_CTRL_REG); | |
250 | writel_relaxed(0, rps->clkevt_base + TIMER_LOAD_REG); | |
251 | writel_relaxed(0, rps->clksrc_base + TIMER_LOAD_REG); | |
252 | writel_relaxed(0, rps->clkevt_base + TIMER_CLRINT_REG); | |
253 | writel_relaxed(0, rps->clksrc_base + TIMER_CLRINT_REG); | |
254 | ||
255 | ret = request_irq(rps->irq, oxnas_rps_timer_irq, | |
256 | IRQF_TIMER | IRQF_IRQPOLL, | |
257 | "rps-timer", rps); | |
8595b1ba | 258 | if (ret) |
89355274 NA |
259 | goto err_iomap; |
260 | ||
261 | ret = oxnas_rps_clocksource_init(rps); | |
262 | if (ret) | |
263 | goto err_irqreq; | |
264 | ||
265 | ret = oxnas_rps_clockevent_init(rps); | |
266 | if (ret) | |
267 | goto err_irqreq; | |
268 | ||
8595b1ba | 269 | return 0; |
89355274 NA |
270 | |
271 | err_irqreq: | |
272 | free_irq(rps->irq, rps); | |
273 | err_iomap: | |
274 | iounmap(base); | |
275 | err_clk_prepare: | |
276 | clk_disable_unprepare(rps->clk); | |
277 | err_clk: | |
278 | clk_put(rps->clk); | |
279 | err_alloc: | |
280 | kfree(rps); | |
8595b1ba DL |
281 | |
282 | return ret; | |
89355274 NA |
283 | } |
284 | ||
17273395 | 285 | TIMER_OF_DECLARE(ox810se_rps, |
177cf6e5 | 286 | "oxsemi,ox810se-rps-timer", oxnas_rps_timer_init); |
17273395 | 287 | TIMER_OF_DECLARE(ox820_rps, |
fbc87aa0 | 288 | "oxsemi,ox820-rps-timer", oxnas_rps_timer_init); |