1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | |
3 | /* |
4 | * Realtek Otto MIPS platform watchdog |
5 | * |
6 | * Watchdog timer that will reset the system after timeout, using the selected |
7 | * reset mode. |
8 | * |
9 | * Counter scaling and timeouts: |
10 | * - Base prescale of (2 << 25), providing tick duration T_0: 168ms @ 200MHz |
11 | * - PRESCALE: logarithmic prescaler adding a factor of {1, 2, 4, 8} |
12 | * - Phase 1: Times out after (PHASE1 + 1) × PRESCALE × T_0 |
13 | * Generates an interrupt, WDT cannot be stopped after phase 1 |
14 | * - Phase 2: starts after phase 1, times out after (PHASE2 + 1) × PRESCALE × T_0 |
15 | * Resets the system according to RST_MODE |
16 | */ |
17 | |
18 | #include <linux/bits.h> |
19 | #include <linux/bitfield.h> |
20 | #include <linux/clk.h> |
21 | #include <linux/delay.h> |
22 | #include <linux/interrupt.h> |
23 | #include <linux/io.h> |
24 | #include <linux/math.h> |
25 | #include <linux/minmax.h> |
26 | #include <linux/module.h> |
27 | #include <linux/mod_devicetable.h> |
28 | #include <linux/platform_device.h> |
29 | #include <linux/property.h> |
30 | #include <linux/reboot.h> |
31 | #include <linux/watchdog.h> |
32 | |
33 | #define OTTO_WDT_REG_CNTR 0x0 |
34 | #define OTTO_WDT_CNTR_PING BIT(31) |
35 | |
36 | #define OTTO_WDT_REG_INTR 0x4 |
37 | #define OTTO_WDT_INTR_PHASE_1 BIT(31) |
38 | #define OTTO_WDT_INTR_PHASE_2 BIT(30) |
39 | |
40 | #define OTTO_WDT_REG_CTRL 0x8 |
41 | #define OTTO_WDT_CTRL_ENABLE BIT(31) |
42 | #define OTTO_WDT_CTRL_PRESCALE GENMASK(30, 29) |
43 | #define OTTO_WDT_CTRL_PHASE1 GENMASK(26, 22) |
44 | #define OTTO_WDT_CTRL_PHASE2 GENMASK(19, 15) |
45 | #define OTTO_WDT_CTRL_RST_MODE GENMASK(1, 0) |
46 | #define OTTO_WDT_MODE_SOC 0 |
47 | #define OTTO_WDT_MODE_CPU 1 |
48 | #define OTTO_WDT_MODE_SOFTWARE 2 |
49 | #define OTTO_WDT_CTRL_DEFAULT OTTO_WDT_MODE_CPU |
50 | |
51 | #define OTTO_WDT_PRESCALE_MAX 3 |
52 | |
53 | /* |
54 | * One higher than the max values contained in PHASE{1,2}, since a value of 0 |
55 | * corresponds to one tick. |
56 | */ |
57 | #define OTTO_WDT_PHASE_TICKS_MAX 32 |
58 | |
59 | /* |
60 | * The maximum reset delay is actually 2×32 ticks, but that would require large |
61 | * pretimeout values for timeouts longer than 32 ticks. Limit the maximum timeout |
62 | * to 32 + 1 to ensure small pretimeout values can be configured as expected. |
63 | */ |
64 | #define OTTO_WDT_TIMEOUT_TICKS_MAX (OTTO_WDT_PHASE_TICKS_MAX + 1) |
65 | |
66 | struct otto_wdt_ctrl { |
67 | struct watchdog_device wdev; |
68 | struct device *dev; |
69 | void __iomem *base; |
70 | unsigned int clk_rate_khz; |
71 | int irq_phase1; |
72 | }; |
73 | |
74 | static int otto_wdt_start(struct watchdog_device *wdev) |
75 | { |
76 | struct otto_wdt_ctrl *ctrl = watchdog_get_drvdata(wdd: wdev); |
77 | u32 v; |
78 | |
79 | v = ioread32(ctrl->base + OTTO_WDT_REG_CTRL); |
80 | v |= OTTO_WDT_CTRL_ENABLE; |
81 | iowrite32(v, ctrl->base + OTTO_WDT_REG_CTRL); |
82 | |
83 | return 0; |
84 | } |
85 | |
86 | static int otto_wdt_stop(struct watchdog_device *wdev) |
87 | { |
88 | struct otto_wdt_ctrl *ctrl = watchdog_get_drvdata(wdd: wdev); |
89 | u32 v; |
90 | |
91 | v = ioread32(ctrl->base + OTTO_WDT_REG_CTRL); |
92 | v &= ~OTTO_WDT_CTRL_ENABLE; |
93 | iowrite32(v, ctrl->base + OTTO_WDT_REG_CTRL); |
94 | |
95 | return 0; |
96 | } |
97 | |
98 | static int otto_wdt_ping(struct watchdog_device *wdev) |
99 | { |
100 | struct otto_wdt_ctrl *ctrl = watchdog_get_drvdata(wdd: wdev); |
101 | |
102 | iowrite32(OTTO_WDT_CNTR_PING, ctrl->base + OTTO_WDT_REG_CNTR); |
103 | |
104 | return 0; |
105 | } |
106 | |
107 | static int otto_wdt_tick_ms(struct otto_wdt_ctrl *ctrl, int prescale) |
108 | { |
109 | return DIV_ROUND_CLOSEST(1 << (25 + prescale), ctrl->clk_rate_khz); |
110 | } |
111 | |
112 | /* |
113 | * The timer asserts the PHASE1/PHASE2 IRQs when the number of ticks exceeds |
114 | * the value stored in those fields. This means each phase will run for at least |
115 | * one tick, so small values need to be clamped to correctly reflect the timeout. |
116 | */ |
117 | static inline unsigned int div_round_ticks(unsigned int val, unsigned int tick_duration, |
118 | unsigned int min_ticks) |
119 | { |
120 | return max(min_ticks, DIV_ROUND_UP(val, tick_duration)); |
121 | } |
122 | |
123 | static int otto_wdt_determine_timeouts(struct watchdog_device *wdev, unsigned int timeout, |
124 | unsigned int pretimeout) |
125 | { |
126 | struct otto_wdt_ctrl *ctrl = watchdog_get_drvdata(wdd: wdev); |
127 | unsigned int pretimeout_ms = pretimeout * 1000; |
128 | unsigned int timeout_ms = timeout * 1000; |
129 | unsigned int prescale_next = 0; |
130 | unsigned int phase1_ticks; |
131 | unsigned int phase2_ticks; |
132 | unsigned int total_ticks; |
133 | unsigned int prescale; |
134 | unsigned int tick_ms; |
135 | u32 v; |
136 | |
137 | do { |
138 | prescale = prescale_next; |
139 | if (prescale > OTTO_WDT_PRESCALE_MAX) |
140 | return -EINVAL; |
141 | |
142 | tick_ms = otto_wdt_tick_ms(ctrl, prescale); |
143 | total_ticks = div_round_ticks(val: timeout_ms, tick_duration: tick_ms, min_ticks: 2); |
144 | phase1_ticks = div_round_ticks(val: timeout_ms - pretimeout_ms, tick_duration: tick_ms, min_ticks: 1); |
145 | phase2_ticks = total_ticks - phase1_ticks; |
146 | |
147 | prescale_next++; |
148 | } while (phase1_ticks > OTTO_WDT_PHASE_TICKS_MAX |
149 | || phase2_ticks > OTTO_WDT_PHASE_TICKS_MAX); |
150 | |
151 | v = ioread32(ctrl->base + OTTO_WDT_REG_CTRL); |
152 | |
153 | v &= ~(OTTO_WDT_CTRL_PRESCALE | OTTO_WDT_CTRL_PHASE1 | OTTO_WDT_CTRL_PHASE2); |
154 | v |= FIELD_PREP(OTTO_WDT_CTRL_PHASE1, phase1_ticks - 1); |
155 | v |= FIELD_PREP(OTTO_WDT_CTRL_PHASE2, phase2_ticks - 1); |
156 | v |= FIELD_PREP(OTTO_WDT_CTRL_PRESCALE, prescale); |
157 | |
158 | iowrite32(v, ctrl->base + OTTO_WDT_REG_CTRL); |
159 | |
160 | timeout_ms = total_ticks * tick_ms; |
161 | ctrl->wdev.timeout = timeout_ms / 1000; |
162 | |
163 | pretimeout_ms = phase2_ticks * tick_ms; |
164 | ctrl->wdev.pretimeout = pretimeout_ms / 1000; |
165 | |
166 | return 0; |
167 | } |
168 | |
169 | static int otto_wdt_set_timeout(struct watchdog_device *wdev, unsigned int val) |
170 | { |
171 | return otto_wdt_determine_timeouts(wdev, timeout: val, min(wdev->pretimeout, val - 1)); |
172 | } |
173 | |
174 | static int otto_wdt_set_pretimeout(struct watchdog_device *wdev, unsigned int val) |
175 | { |
176 | return otto_wdt_determine_timeouts(wdev, timeout: wdev->timeout, pretimeout: val); |
177 | } |
178 | |
179 | static int otto_wdt_restart(struct watchdog_device *wdev, unsigned long reboot_mode, |
180 | void *data) |
181 | { |
182 | struct otto_wdt_ctrl *ctrl = watchdog_get_drvdata(wdd: wdev); |
183 | u32 reset_mode; |
184 | u32 v; |
185 | |
186 | disable_irq(irq: ctrl->irq_phase1); |
187 | |
188 | switch (reboot_mode) { |
189 | case REBOOT_SOFT: |
190 | reset_mode = OTTO_WDT_MODE_SOFTWARE; |
191 | break; |
192 | case REBOOT_WARM: |
193 | reset_mode = OTTO_WDT_MODE_CPU; |
194 | break; |
195 | default: |
196 | reset_mode = OTTO_WDT_MODE_SOC; |
197 | break; |
198 | } |
199 | |
200 | /* Configure for shortest timeout and wait for reset to occur */ |
201 | v = FIELD_PREP(OTTO_WDT_CTRL_RST_MODE, reset_mode) | OTTO_WDT_CTRL_ENABLE; |
202 | iowrite32(v, ctrl->base + OTTO_WDT_REG_CTRL); |
203 | |
204 | mdelay(3 * otto_wdt_tick_ms(ctrl, 0)); |
205 | |
206 | return 0; |
207 | } |
208 | |
209 | static irqreturn_t otto_wdt_phase1_isr(int irq, void *dev_id) |
210 | { |
211 | struct otto_wdt_ctrl *ctrl = dev_id; |
212 | |
213 | iowrite32(OTTO_WDT_INTR_PHASE_1, ctrl->base + OTTO_WDT_REG_INTR); |
214 | dev_crit(ctrl->dev, "phase 1 timeout\n" ); |
215 | watchdog_notify_pretimeout(wdd: &ctrl->wdev); |
216 | |
217 | return IRQ_HANDLED; |
218 | } |
219 | |
220 | static const struct watchdog_ops otto_wdt_ops = { |
221 | .owner = THIS_MODULE, |
222 | .start = otto_wdt_start, |
223 | .stop = otto_wdt_stop, |
224 | .ping = otto_wdt_ping, |
225 | .set_timeout = otto_wdt_set_timeout, |
226 | .set_pretimeout = otto_wdt_set_pretimeout, |
227 | .restart = otto_wdt_restart, |
228 | }; |
229 | |
230 | static const struct watchdog_info otto_wdt_info = { |
231 | .identity = "Realtek Otto watchdog timer" , |
232 | .options = WDIOF_KEEPALIVEPING | |
233 | WDIOF_MAGICCLOSE | |
234 | WDIOF_SETTIMEOUT | |
235 | WDIOF_PRETIMEOUT, |
236 | }; |
237 | |
238 | static int otto_wdt_probe_clk(struct otto_wdt_ctrl *ctrl) |
239 | { |
240 | struct clk *clk; |
241 | |
242 | clk = devm_clk_get_enabled(dev: ctrl->dev, NULL); |
243 | if (IS_ERR(ptr: clk)) |
244 | return dev_err_probe(dev: ctrl->dev, err: PTR_ERR(ptr: clk), fmt: "Failed to get clock\n" ); |
245 | |
246 | ctrl->clk_rate_khz = clk_get_rate(clk) / 1000; |
247 | if (ctrl->clk_rate_khz == 0) |
248 | return dev_err_probe(dev: ctrl->dev, err: -ENXIO, fmt: "Failed to get clock rate\n" ); |
249 | |
250 | return 0; |
251 | } |
252 | |
253 | static int otto_wdt_probe_reset_mode(struct otto_wdt_ctrl *ctrl) |
254 | { |
255 | static const char *mode_property = "realtek,reset-mode" ; |
256 | const struct fwnode_handle *node = ctrl->dev->fwnode; |
257 | int mode_count; |
258 | u32 mode; |
259 | u32 v; |
260 | |
261 | if (!node) |
262 | return -ENXIO; |
263 | |
264 | mode_count = fwnode_property_string_array_count(fwnode: node, propname: mode_property); |
265 | if (mode_count < 0) |
266 | return mode_count; |
267 | else if (mode_count == 0) |
268 | return 0; |
269 | else if (mode_count != 1) |
270 | return -EINVAL; |
271 | |
272 | if (fwnode_property_match_string(fwnode: node, propname: mode_property, string: "soc" ) == 0) |
273 | mode = OTTO_WDT_MODE_SOC; |
274 | else if (fwnode_property_match_string(fwnode: node, propname: mode_property, string: "cpu" ) == 0) |
275 | mode = OTTO_WDT_MODE_CPU; |
276 | else if (fwnode_property_match_string(fwnode: node, propname: mode_property, string: "software" ) == 0) |
277 | mode = OTTO_WDT_MODE_SOFTWARE; |
278 | else |
279 | return -EINVAL; |
280 | |
281 | v = ioread32(ctrl->base + OTTO_WDT_REG_CTRL); |
282 | v &= ~OTTO_WDT_CTRL_RST_MODE; |
283 | v |= FIELD_PREP(OTTO_WDT_CTRL_RST_MODE, mode); |
284 | iowrite32(v, ctrl->base + OTTO_WDT_REG_CTRL); |
285 | |
286 | return 0; |
287 | } |
288 | |
289 | static int otto_wdt_probe(struct platform_device *pdev) |
290 | { |
291 | struct device *dev = &pdev->dev; |
292 | struct otto_wdt_ctrl *ctrl; |
293 | unsigned int max_tick_ms; |
294 | int ret; |
295 | |
296 | ctrl = devm_kzalloc(dev, size: sizeof(*ctrl), GFP_KERNEL); |
297 | if (!ctrl) |
298 | return -ENOMEM; |
299 | |
300 | ctrl->dev = dev; |
301 | ctrl->base = devm_platform_ioremap_resource(pdev, index: 0); |
302 | if (IS_ERR(ptr: ctrl->base)) |
303 | return PTR_ERR(ptr: ctrl->base); |
304 | |
305 | /* Clear any old interrupts and reset initial state */ |
306 | iowrite32(OTTO_WDT_INTR_PHASE_1 | OTTO_WDT_INTR_PHASE_2, |
307 | ctrl->base + OTTO_WDT_REG_INTR); |
308 | iowrite32(OTTO_WDT_CTRL_DEFAULT, ctrl->base + OTTO_WDT_REG_CTRL); |
309 | |
310 | ret = otto_wdt_probe_clk(ctrl); |
311 | if (ret) |
312 | return ret; |
313 | |
314 | ctrl->irq_phase1 = platform_get_irq_byname(pdev, "phase1" ); |
315 | if (ctrl->irq_phase1 < 0) |
316 | return ctrl->irq_phase1; |
317 | |
318 | ret = devm_request_irq(dev, irq: ctrl->irq_phase1, handler: otto_wdt_phase1_isr, irqflags: 0, |
319 | devname: "realtek-otto-wdt" , dev_id: ctrl); |
320 | if (ret) |
321 | return dev_err_probe(dev, err: ret, fmt: "Failed to get IRQ for phase1\n" ); |
322 | |
323 | ret = otto_wdt_probe_reset_mode(ctrl); |
324 | if (ret) |
325 | return dev_err_probe(dev, err: ret, fmt: "Invalid reset mode specified\n" ); |
326 | |
327 | ctrl->wdev.parent = dev; |
328 | ctrl->wdev.info = &otto_wdt_info; |
329 | ctrl->wdev.ops = &otto_wdt_ops; |
330 | |
331 | /* |
332 | * Since pretimeout cannot be disabled, min. timeout is twice the |
333 | * subsystem resolution. Max. timeout is ca. 43s at a bus clock of 200MHz. |
334 | */ |
335 | ctrl->wdev.min_timeout = 2; |
336 | max_tick_ms = otto_wdt_tick_ms(ctrl, OTTO_WDT_PRESCALE_MAX); |
337 | ctrl->wdev.max_hw_heartbeat_ms = max_tick_ms * OTTO_WDT_TIMEOUT_TICKS_MAX; |
338 | ctrl->wdev.timeout = min(30U, ctrl->wdev.max_hw_heartbeat_ms / 1000); |
339 | |
340 | watchdog_set_drvdata(wdd: &ctrl->wdev, data: ctrl); |
341 | watchdog_init_timeout(wdd: &ctrl->wdev, timeout_parm: 0, dev); |
342 | watchdog_stop_on_reboot(wdd: &ctrl->wdev); |
343 | watchdog_set_restart_priority(wdd: &ctrl->wdev, priority: 128); |
344 | |
345 | ret = otto_wdt_determine_timeouts(wdev: &ctrl->wdev, timeout: ctrl->wdev.timeout, pretimeout: 1); |
346 | if (ret) |
347 | return dev_err_probe(dev, err: ret, fmt: "Failed to set timeout\n" ); |
348 | |
349 | return devm_watchdog_register_device(dev, &ctrl->wdev); |
350 | } |
351 | |
352 | static const struct of_device_id otto_wdt_ids[] = { |
353 | { .compatible = "realtek,rtl8380-wdt" }, |
354 | { .compatible = "realtek,rtl8390-wdt" }, |
355 | { .compatible = "realtek,rtl9300-wdt" }, |
356 | { .compatible = "realtek,rtl9310-wdt" }, |
357 | { } |
358 | }; |
359 | MODULE_DEVICE_TABLE(of, otto_wdt_ids); |
360 | |
361 | static struct platform_driver otto_wdt_driver = { |
362 | .probe = otto_wdt_probe, |
363 | .driver = { |
364 | .name = "realtek-otto-watchdog" , |
365 | .of_match_table = otto_wdt_ids, |
366 | }, |
367 | }; |
368 | module_platform_driver(otto_wdt_driver); |
369 | |
370 | MODULE_LICENSE("GPL v2" ); |
371 | MODULE_AUTHOR("Sander Vanheule <sander@svanheule.net>" ); |
372 | MODULE_DESCRIPTION("Realtek Otto watchdog timer driver" ); |
373 | |