1
2
3
4
5
6
7
8
9
10
11
12#include <dt-bindings/reset-controller/mt2712-resets.h>
13#include <dt-bindings/reset-controller/mt8183-resets.h>
14#include <dt-bindings/reset-controller/mt8192-resets.h>
15#include <linux/delay.h>
16#include <linux/err.h>
17#include <linux/init.h>
18#include <linux/io.h>
19#include <linux/kernel.h>
20#include <linux/module.h>
21#include <linux/moduleparam.h>
22#include <linux/of.h>
23#include <linux/of_device.h>
24#include <linux/platform_device.h>
25#include <linux/reset-controller.h>
26#include <linux/types.h>
27#include <linux/watchdog.h>
28#include <linux/interrupt.h>
29
30#define WDT_MAX_TIMEOUT 31
31#define WDT_MIN_TIMEOUT 2
32#define WDT_LENGTH_TIMEOUT(n) ((n) << 5)
33
34#define WDT_LENGTH 0x04
35#define WDT_LENGTH_KEY 0x8
36
37#define WDT_RST 0x08
38#define WDT_RST_RELOAD 0x1971
39
40#define WDT_MODE 0x00
41#define WDT_MODE_EN (1 << 0)
42#define WDT_MODE_EXT_POL_LOW (0 << 1)
43#define WDT_MODE_EXT_POL_HIGH (1 << 1)
44#define WDT_MODE_EXRST_EN (1 << 2)
45#define WDT_MODE_IRQ_EN (1 << 3)
46#define WDT_MODE_AUTO_START (1 << 4)
47#define WDT_MODE_DUAL_EN (1 << 6)
48#define WDT_MODE_KEY 0x22000000
49
50#define WDT_SWRST 0x14
51#define WDT_SWRST_KEY 0x1209
52
53#define WDT_SWSYSRST 0x18U
54#define WDT_SWSYS_RST_KEY 0x88000000
55
56#define DRV_NAME "mtk-wdt"
57#define DRV_VERSION "1.0"
58
59static bool nowayout = WATCHDOG_NOWAYOUT;
60static unsigned int timeout;
61
62struct mtk_wdt_dev {
63 struct watchdog_device wdt_dev;
64 void __iomem *wdt_base;
65 spinlock_t lock;
66 struct reset_controller_dev rcdev;
67};
68
69struct mtk_wdt_data {
70 int toprgu_sw_rst_num;
71};
72
73static const struct mtk_wdt_data mt2712_data = {
74 .toprgu_sw_rst_num = MT2712_TOPRGU_SW_RST_NUM,
75};
76
77static const struct mtk_wdt_data mt8183_data = {
78 .toprgu_sw_rst_num = MT8183_TOPRGU_SW_RST_NUM,
79};
80
81static const struct mtk_wdt_data mt8192_data = {
82 .toprgu_sw_rst_num = MT8192_TOPRGU_SW_RST_NUM,
83};
84
85static int toprgu_reset_update(struct reset_controller_dev *rcdev,
86 unsigned long id, bool assert)
87{
88 unsigned int tmp;
89 unsigned long flags;
90 struct mtk_wdt_dev *data =
91 container_of(rcdev, struct mtk_wdt_dev, rcdev);
92
93 spin_lock_irqsave(&data->lock, flags);
94
95 tmp = readl(data->wdt_base + WDT_SWSYSRST);
96 if (assert)
97 tmp |= BIT(id);
98 else
99 tmp &= ~BIT(id);
100 tmp |= WDT_SWSYS_RST_KEY;
101 writel(tmp, data->wdt_base + WDT_SWSYSRST);
102
103 spin_unlock_irqrestore(&data->lock, flags);
104
105 return 0;
106}
107
108static int toprgu_reset_assert(struct reset_controller_dev *rcdev,
109 unsigned long id)
110{
111 return toprgu_reset_update(rcdev, id, true);
112}
113
114static int toprgu_reset_deassert(struct reset_controller_dev *rcdev,
115 unsigned long id)
116{
117 return toprgu_reset_update(rcdev, id, false);
118}
119
120static int toprgu_reset(struct reset_controller_dev *rcdev,
121 unsigned long id)
122{
123 int ret;
124
125 ret = toprgu_reset_assert(rcdev, id);
126 if (ret)
127 return ret;
128
129 return toprgu_reset_deassert(rcdev, id);
130}
131
132static const struct reset_control_ops toprgu_reset_ops = {
133 .assert = toprgu_reset_assert,
134 .deassert = toprgu_reset_deassert,
135 .reset = toprgu_reset,
136};
137
138static int toprgu_register_reset_controller(struct platform_device *pdev,
139 int rst_num)
140{
141 int ret;
142 struct mtk_wdt_dev *mtk_wdt = platform_get_drvdata(pdev);
143
144 spin_lock_init(&mtk_wdt->lock);
145
146 mtk_wdt->rcdev.owner = THIS_MODULE;
147 mtk_wdt->rcdev.nr_resets = rst_num;
148 mtk_wdt->rcdev.ops = &toprgu_reset_ops;
149 mtk_wdt->rcdev.of_node = pdev->dev.of_node;
150 ret = devm_reset_controller_register(&pdev->dev, &mtk_wdt->rcdev);
151 if (ret != 0)
152 dev_err(&pdev->dev,
153 "couldn't register wdt reset controller: %d\n", ret);
154 return ret;
155}
156
157static int mtk_wdt_restart(struct watchdog_device *wdt_dev,
158 unsigned long action, void *data)
159{
160 struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev);
161 void __iomem *wdt_base;
162
163 wdt_base = mtk_wdt->wdt_base;
164
165 while (1) {
166 writel(WDT_SWRST_KEY, wdt_base + WDT_SWRST);
167 mdelay(5);
168 }
169
170 return 0;
171}
172
173static int mtk_wdt_ping(struct watchdog_device *wdt_dev)
174{
175 struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev);
176 void __iomem *wdt_base = mtk_wdt->wdt_base;
177
178 iowrite32(WDT_RST_RELOAD, wdt_base + WDT_RST);
179
180 return 0;
181}
182
183static int mtk_wdt_set_timeout(struct watchdog_device *wdt_dev,
184 unsigned int timeout)
185{
186 struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev);
187 void __iomem *wdt_base = mtk_wdt->wdt_base;
188 u32 reg;
189
190 wdt_dev->timeout = timeout;
191
192
193
194
195 if (wdt_dev->pretimeout)
196 wdt_dev->pretimeout = timeout / 2;
197
198
199
200
201
202 reg = WDT_LENGTH_TIMEOUT((timeout - wdt_dev->pretimeout) << 6)
203 | WDT_LENGTH_KEY;
204 iowrite32(reg, wdt_base + WDT_LENGTH);
205
206 mtk_wdt_ping(wdt_dev);
207
208 return 0;
209}
210
211static void mtk_wdt_init(struct watchdog_device *wdt_dev)
212{
213 struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev);
214 void __iomem *wdt_base;
215
216 wdt_base = mtk_wdt->wdt_base;
217
218 if (readl(wdt_base + WDT_MODE) & WDT_MODE_EN) {
219 set_bit(WDOG_HW_RUNNING, &wdt_dev->status);
220 mtk_wdt_set_timeout(wdt_dev, wdt_dev->timeout);
221 }
222}
223
224static int mtk_wdt_stop(struct watchdog_device *wdt_dev)
225{
226 struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev);
227 void __iomem *wdt_base = mtk_wdt->wdt_base;
228 u32 reg;
229
230 reg = readl(wdt_base + WDT_MODE);
231 reg &= ~WDT_MODE_EN;
232 reg |= WDT_MODE_KEY;
233 iowrite32(reg, wdt_base + WDT_MODE);
234
235 return 0;
236}
237
238static int mtk_wdt_start(struct watchdog_device *wdt_dev)
239{
240 u32 reg;
241 struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev);
242 void __iomem *wdt_base = mtk_wdt->wdt_base;
243 int ret;
244
245 ret = mtk_wdt_set_timeout(wdt_dev, wdt_dev->timeout);
246 if (ret < 0)
247 return ret;
248
249 reg = ioread32(wdt_base + WDT_MODE);
250 if (wdt_dev->pretimeout)
251 reg |= (WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN);
252 else
253 reg &= ~(WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN);
254 reg |= (WDT_MODE_EN | WDT_MODE_KEY);
255 iowrite32(reg, wdt_base + WDT_MODE);
256
257 return 0;
258}
259
260static int mtk_wdt_set_pretimeout(struct watchdog_device *wdd,
261 unsigned int timeout)
262{
263 struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdd);
264 void __iomem *wdt_base = mtk_wdt->wdt_base;
265 u32 reg = ioread32(wdt_base + WDT_MODE);
266
267 if (timeout && !wdd->pretimeout) {
268 wdd->pretimeout = wdd->timeout / 2;
269 reg |= (WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN);
270 } else if (!timeout && wdd->pretimeout) {
271 wdd->pretimeout = 0;
272 reg &= ~(WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN);
273 } else {
274 return 0;
275 }
276
277 reg |= WDT_MODE_KEY;
278 iowrite32(reg, wdt_base + WDT_MODE);
279
280 return mtk_wdt_set_timeout(wdd, wdd->timeout);
281}
282
283static irqreturn_t mtk_wdt_isr(int irq, void *arg)
284{
285 struct watchdog_device *wdd = arg;
286
287 watchdog_notify_pretimeout(wdd);
288
289 return IRQ_HANDLED;
290}
291
292static const struct watchdog_info mtk_wdt_info = {
293 .identity = DRV_NAME,
294 .options = WDIOF_SETTIMEOUT |
295 WDIOF_KEEPALIVEPING |
296 WDIOF_MAGICCLOSE,
297};
298
299static const struct watchdog_info mtk_wdt_pt_info = {
300 .identity = DRV_NAME,
301 .options = WDIOF_SETTIMEOUT |
302 WDIOF_PRETIMEOUT |
303 WDIOF_KEEPALIVEPING |
304 WDIOF_MAGICCLOSE,
305};
306
307static const struct watchdog_ops mtk_wdt_ops = {
308 .owner = THIS_MODULE,
309 .start = mtk_wdt_start,
310 .stop = mtk_wdt_stop,
311 .ping = mtk_wdt_ping,
312 .set_timeout = mtk_wdt_set_timeout,
313 .set_pretimeout = mtk_wdt_set_pretimeout,
314 .restart = mtk_wdt_restart,
315};
316
317static int mtk_wdt_probe(struct platform_device *pdev)
318{
319 struct device *dev = &pdev->dev;
320 struct mtk_wdt_dev *mtk_wdt;
321 const struct mtk_wdt_data *wdt_data;
322 int err, irq;
323
324 mtk_wdt = devm_kzalloc(dev, sizeof(*mtk_wdt), GFP_KERNEL);
325 if (!mtk_wdt)
326 return -ENOMEM;
327
328 platform_set_drvdata(pdev, mtk_wdt);
329
330 mtk_wdt->wdt_base = devm_platform_ioremap_resource(pdev, 0);
331 if (IS_ERR(mtk_wdt->wdt_base))
332 return PTR_ERR(mtk_wdt->wdt_base);
333
334 irq = platform_get_irq(pdev, 0);
335 if (irq > 0) {
336 err = devm_request_irq(&pdev->dev, irq, mtk_wdt_isr, 0, "wdt_bark",
337 &mtk_wdt->wdt_dev);
338 if (err)
339 return err;
340
341 mtk_wdt->wdt_dev.info = &mtk_wdt_pt_info;
342 mtk_wdt->wdt_dev.pretimeout = WDT_MAX_TIMEOUT / 2;
343 } else {
344 if (irq == -EPROBE_DEFER)
345 return -EPROBE_DEFER;
346
347 mtk_wdt->wdt_dev.info = &mtk_wdt_info;
348 }
349
350 mtk_wdt->wdt_dev.ops = &mtk_wdt_ops;
351 mtk_wdt->wdt_dev.timeout = WDT_MAX_TIMEOUT;
352 mtk_wdt->wdt_dev.max_hw_heartbeat_ms = WDT_MAX_TIMEOUT * 1000;
353 mtk_wdt->wdt_dev.min_timeout = WDT_MIN_TIMEOUT;
354 mtk_wdt->wdt_dev.parent = dev;
355
356 watchdog_init_timeout(&mtk_wdt->wdt_dev, timeout, dev);
357 watchdog_set_nowayout(&mtk_wdt->wdt_dev, nowayout);
358 watchdog_set_restart_priority(&mtk_wdt->wdt_dev, 128);
359
360 watchdog_set_drvdata(&mtk_wdt->wdt_dev, mtk_wdt);
361
362 mtk_wdt_init(&mtk_wdt->wdt_dev);
363
364 watchdog_stop_on_reboot(&mtk_wdt->wdt_dev);
365 err = devm_watchdog_register_device(dev, &mtk_wdt->wdt_dev);
366 if (unlikely(err))
367 return err;
368
369 dev_info(dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)\n",
370 mtk_wdt->wdt_dev.timeout, nowayout);
371
372 wdt_data = of_device_get_match_data(dev);
373 if (wdt_data) {
374 err = toprgu_register_reset_controller(pdev,
375 wdt_data->toprgu_sw_rst_num);
376 if (err)
377 return err;
378 }
379 return 0;
380}
381
382#ifdef CONFIG_PM_SLEEP
383static int mtk_wdt_suspend(struct device *dev)
384{
385 struct mtk_wdt_dev *mtk_wdt = dev_get_drvdata(dev);
386
387 if (watchdog_active(&mtk_wdt->wdt_dev))
388 mtk_wdt_stop(&mtk_wdt->wdt_dev);
389
390 return 0;
391}
392
393static int mtk_wdt_resume(struct device *dev)
394{
395 struct mtk_wdt_dev *mtk_wdt = dev_get_drvdata(dev);
396
397 if (watchdog_active(&mtk_wdt->wdt_dev)) {
398 mtk_wdt_start(&mtk_wdt->wdt_dev);
399 mtk_wdt_ping(&mtk_wdt->wdt_dev);
400 }
401
402 return 0;
403}
404#endif
405
406static const struct of_device_id mtk_wdt_dt_ids[] = {
407 { .compatible = "mediatek,mt2712-wdt", .data = &mt2712_data },
408 { .compatible = "mediatek,mt6589-wdt" },
409 { .compatible = "mediatek,mt8183-wdt", .data = &mt8183_data },
410 { .compatible = "mediatek,mt8192-wdt", .data = &mt8192_data },
411 { }
412};
413MODULE_DEVICE_TABLE(of, mtk_wdt_dt_ids);
414
415static const struct dev_pm_ops mtk_wdt_pm_ops = {
416 SET_SYSTEM_SLEEP_PM_OPS(mtk_wdt_suspend,
417 mtk_wdt_resume)
418};
419
420static struct platform_driver mtk_wdt_driver = {
421 .probe = mtk_wdt_probe,
422 .driver = {
423 .name = DRV_NAME,
424 .pm = &mtk_wdt_pm_ops,
425 .of_match_table = mtk_wdt_dt_ids,
426 },
427};
428
429module_platform_driver(mtk_wdt_driver);
430
431module_param(timeout, uint, 0);
432MODULE_PARM_DESC(timeout, "Watchdog heartbeat in seconds");
433
434module_param(nowayout, bool, 0);
435MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
436 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
437
438MODULE_LICENSE("GPL");
439MODULE_AUTHOR("Matthias Brugger <matthias.bgg@gmail.com>");
440MODULE_DESCRIPTION("Mediatek WatchDog Timer Driver");
441MODULE_VERSION(DRV_VERSION);
442