blob: 2b0f9383efe5c053862fd69ba1ca0f55e5d028f7 [file] [log] [blame]
developer5d148cb2023-06-02 13:08:11 +08001From d02a2cf00764f83a9efdc08685381ee9167b0a9e Mon Sep 17 00:00:00 2001
2From: Sam Shih <sam.shih@mediatek.com>
3Date: Fri, 2 Jun 2023 13:06:04 +0800
4Subject: [PATCH] [basic-part][999-2050-watchdog-add-mt7986-assert.patch]
5
6---
7 drivers/watchdog/mtk_wdt.c | 202 +++++++++++++++++++++++++++++++++++--
8 1 file changed, 193 insertions(+), 9 deletions(-)
9
developere138bcd2021-12-06 09:20:47 +080010diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c
developer5d148cb2023-06-02 13:08:11 +080011index 9c3d00332..30127d1e7 100644
developere138bcd2021-12-06 09:20:47 +080012--- a/drivers/watchdog/mtk_wdt.c
13+++ b/drivers/watchdog/mtk_wdt.c
14@@ -9,6 +9,8 @@
15 * Based on sunxi_wdt.c
16 */
17
18+#include <dt-bindings/reset/mt7986-resets.h>
19+#include <linux/delay.h>
20 #include <linux/err.h>
21 #include <linux/init.h>
22 #include <linux/io.h>
23@@ -16,13 +18,15 @@
24 #include <linux/module.h>
25 #include <linux/moduleparam.h>
26 #include <linux/of.h>
27+#include <linux/of_device.h>
28 #include <linux/platform_device.h>
29+#include <linux/reset-controller.h>
30 #include <linux/types.h>
31 #include <linux/watchdog.h>
32-#include <linux/delay.h>
33+#include <linux/interrupt.h>
34
35 #define WDT_MAX_TIMEOUT 31
36-#define WDT_MIN_TIMEOUT 1
37+#define WDT_MIN_TIMEOUT 2
38 #define WDT_LENGTH_TIMEOUT(n) ((n) << 5)
39
40 #define WDT_LENGTH 0x04
41@@ -44,6 +48,9 @@
42 #define WDT_SWRST 0x14
43 #define WDT_SWRST_KEY 0x1209
44
45+#define WDT_SWSYSRST 0x18U
46+#define WDT_SWSYS_RST_KEY 0x88000000
47+
48 #define DRV_NAME "mtk-wdt"
49 #define DRV_VERSION "1.0"
50
51@@ -53,8 +60,91 @@ static unsigned int timeout;
52 struct mtk_wdt_dev {
53 struct watchdog_device wdt_dev;
54 void __iomem *wdt_base;
55+ spinlock_t lock; /* protects WDT_SWSYSRST reg */
56+ struct reset_controller_dev rcdev;
57+ bool disable_wdt_extrst;
58+};
59+
60+struct mtk_wdt_data {
61+ int toprgu_sw_rst_num;
62+};
63+
64+static const struct mtk_wdt_data mt7986_data = {
65+ .toprgu_sw_rst_num = MT7986_TOPRGU_SW_RST_NUM,
66+};
67+
68+static int toprgu_reset_update(struct reset_controller_dev *rcdev,
69+ unsigned long id, bool assert)
70+{
71+ unsigned int tmp;
72+ unsigned long flags;
73+ struct mtk_wdt_dev *data =
74+ container_of(rcdev, struct mtk_wdt_dev, rcdev);
75+
76+ spin_lock_irqsave(&data->lock, flags);
77+
78+ tmp = readl(data->wdt_base + WDT_SWSYSRST);
79+ if (assert)
80+ tmp |= BIT(id);
81+ else
82+ tmp &= ~BIT(id);
83+ tmp |= WDT_SWSYS_RST_KEY;
84+ writel(tmp, data->wdt_base + WDT_SWSYSRST);
85+
86+ spin_unlock_irqrestore(&data->lock, flags);
87+
88+ return 0;
89+}
90+
91+static int toprgu_reset_assert(struct reset_controller_dev *rcdev,
92+ unsigned long id)
93+{
94+ return toprgu_reset_update(rcdev, id, true);
95+}
96+
97+static int toprgu_reset_deassert(struct reset_controller_dev *rcdev,
98+ unsigned long id)
99+{
100+ return toprgu_reset_update(rcdev, id, false);
101+}
102+
103+static int toprgu_reset(struct reset_controller_dev *rcdev,
104+ unsigned long id)
105+{
106+ int ret;
107+
108+ ret = toprgu_reset_assert(rcdev, id);
109+ if (ret)
110+ return ret;
111+
112+ return toprgu_reset_deassert(rcdev, id);
113+}
114+
115+static const struct reset_control_ops toprgu_reset_ops = {
116+ .assert = toprgu_reset_assert,
117+ .deassert = toprgu_reset_deassert,
118+ .reset = toprgu_reset,
119 };
120
121+static int toprgu_register_reset_controller(struct platform_device *pdev,
122+ int rst_num)
123+{
124+ int ret;
125+ struct mtk_wdt_dev *mtk_wdt = platform_get_drvdata(pdev);
126+
127+ spin_lock_init(&mtk_wdt->lock);
128+
129+ mtk_wdt->rcdev.owner = THIS_MODULE;
130+ mtk_wdt->rcdev.nr_resets = rst_num;
131+ mtk_wdt->rcdev.ops = &toprgu_reset_ops;
132+ mtk_wdt->rcdev.of_node = pdev->dev.of_node;
133+ ret = devm_reset_controller_register(&pdev->dev, &mtk_wdt->rcdev);
134+ if (ret != 0)
135+ dev_err(&pdev->dev,
136+ "couldn't register wdt reset controller: %d\n", ret);
137+ return ret;
138+}
139+
140 static int mtk_wdt_restart(struct watchdog_device *wdt_dev,
141 unsigned long action, void *data)
142 {
143@@ -89,12 +179,19 @@ static int mtk_wdt_set_timeout(struct watchdog_device *wdt_dev,
144 u32 reg;
145
146 wdt_dev->timeout = timeout;
147+ /*
148+ * In dual mode, irq will be triggered at timeout / 2
149+ * the real timeout occurs at timeout
150+ */
151+ if (wdt_dev->pretimeout)
152+ wdt_dev->pretimeout = timeout / 2;
153
154 /*
155 * One bit is the value of 512 ticks
156 * The clock has 32 KHz
157 */
158- reg = WDT_LENGTH_TIMEOUT(timeout << 6) | WDT_LENGTH_KEY;
159+ reg = WDT_LENGTH_TIMEOUT((timeout - wdt_dev->pretimeout) << 6)
160+ | WDT_LENGTH_KEY;
161 iowrite32(reg, wdt_base + WDT_LENGTH);
162
163 mtk_wdt_ping(wdt_dev);
164@@ -102,6 +199,19 @@ static int mtk_wdt_set_timeout(struct watchdog_device *wdt_dev,
165 return 0;
166 }
167
168+static void mtk_wdt_init(struct watchdog_device *wdt_dev)
169+{
170+ struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev);
171+ void __iomem *wdt_base;
172+
173+ wdt_base = mtk_wdt->wdt_base;
174+
175+ if (readl(wdt_base + WDT_MODE) & WDT_MODE_EN) {
176+ set_bit(WDOG_HW_RUNNING, &wdt_dev->status);
177+ mtk_wdt_set_timeout(wdt_dev, wdt_dev->timeout);
178+ }
179+}
180+
181 static int mtk_wdt_stop(struct watchdog_device *wdt_dev)
182 {
183 struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev);
184@@ -128,13 +238,50 @@ static int mtk_wdt_start(struct watchdog_device *wdt_dev)
185 return ret;
186
187 reg = ioread32(wdt_base + WDT_MODE);
188- reg &= ~(WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN);
189+ if (wdt_dev->pretimeout)
190+ reg |= (WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN);
191+ else
192+ reg &= ~(WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN);
193+ if (mtk_wdt->disable_wdt_extrst)
194+ reg &= ~WDT_MODE_EXRST_EN;
195 reg |= (WDT_MODE_EN | WDT_MODE_KEY);
196 iowrite32(reg, wdt_base + WDT_MODE);
197
198 return 0;
199 }
200
201+static int mtk_wdt_set_pretimeout(struct watchdog_device *wdd,
202+ unsigned int timeout)
203+{
204+ struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdd);
205+ void __iomem *wdt_base = mtk_wdt->wdt_base;
206+ u32 reg = ioread32(wdt_base + WDT_MODE);
207+
208+ if (timeout && !wdd->pretimeout) {
209+ wdd->pretimeout = wdd->timeout / 2;
210+ reg |= (WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN);
211+ } else if (!timeout && wdd->pretimeout) {
212+ wdd->pretimeout = 0;
213+ reg &= ~(WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN);
214+ } else {
215+ return 0;
216+ }
217+
218+ reg |= WDT_MODE_KEY;
219+ iowrite32(reg, wdt_base + WDT_MODE);
220+
221+ return mtk_wdt_set_timeout(wdd, wdd->timeout);
222+}
223+
224+static irqreturn_t mtk_wdt_isr(int irq, void *arg)
225+{
226+ struct watchdog_device *wdd = arg;
227+
228+ watchdog_notify_pretimeout(wdd);
229+
230+ return IRQ_HANDLED;
231+}
232+
233 static const struct watchdog_info mtk_wdt_info = {
234 .identity = DRV_NAME,
235 .options = WDIOF_SETTIMEOUT |
236@@ -142,12 +289,21 @@ static const struct watchdog_info mtk_wdt_info = {
237 WDIOF_MAGICCLOSE,
238 };
239
240+static const struct watchdog_info mtk_wdt_pt_info = {
241+ .identity = DRV_NAME,
242+ .options = WDIOF_SETTIMEOUT |
243+ WDIOF_PRETIMEOUT |
244+ WDIOF_KEEPALIVEPING |
245+ WDIOF_MAGICCLOSE,
246+};
247+
248 static const struct watchdog_ops mtk_wdt_ops = {
249 .owner = THIS_MODULE,
250 .start = mtk_wdt_start,
251 .stop = mtk_wdt_stop,
252 .ping = mtk_wdt_ping,
253 .set_timeout = mtk_wdt_set_timeout,
254+ .set_pretimeout = mtk_wdt_set_pretimeout,
255 .restart = mtk_wdt_restart,
256 };
257
258@@ -155,7 +311,8 @@ static int mtk_wdt_probe(struct platform_device *pdev)
259 {
260 struct device *dev = &pdev->dev;
261 struct mtk_wdt_dev *mtk_wdt;
262- int err;
263+ const struct mtk_wdt_data *wdt_data;
264+ int err, irq;
265
266 mtk_wdt = devm_kzalloc(dev, sizeof(*mtk_wdt), GFP_KERNEL);
267 if (!mtk_wdt)
268@@ -167,10 +324,25 @@ static int mtk_wdt_probe(struct platform_device *pdev)
269 if (IS_ERR(mtk_wdt->wdt_base))
270 return PTR_ERR(mtk_wdt->wdt_base);
271
272- mtk_wdt->wdt_dev.info = &mtk_wdt_info;
273+ irq = platform_get_irq(pdev, 0);
274+ if (irq > 0) {
275+ err = devm_request_irq(&pdev->dev, irq, mtk_wdt_isr, 0, "wdt_bark",
276+ &mtk_wdt->wdt_dev);
277+ if (err)
278+ return err;
279+
280+ mtk_wdt->wdt_dev.info = &mtk_wdt_pt_info;
281+ mtk_wdt->wdt_dev.pretimeout = WDT_MAX_TIMEOUT / 2;
282+ } else {
283+ if (irq == -EPROBE_DEFER)
284+ return -EPROBE_DEFER;
285+
286+ mtk_wdt->wdt_dev.info = &mtk_wdt_info;
287+ }
288+
289 mtk_wdt->wdt_dev.ops = &mtk_wdt_ops;
290 mtk_wdt->wdt_dev.timeout = WDT_MAX_TIMEOUT;
291- mtk_wdt->wdt_dev.max_timeout = WDT_MAX_TIMEOUT;
292+ mtk_wdt->wdt_dev.max_hw_heartbeat_ms = WDT_MAX_TIMEOUT * 1000;
293 mtk_wdt->wdt_dev.min_timeout = WDT_MIN_TIMEOUT;
294 mtk_wdt->wdt_dev.parent = dev;
295
296@@ -180,7 +352,7 @@ static int mtk_wdt_probe(struct platform_device *pdev)
297
298 watchdog_set_drvdata(&mtk_wdt->wdt_dev, mtk_wdt);
299
300- mtk_wdt_stop(&mtk_wdt->wdt_dev);
301+ mtk_wdt_init(&mtk_wdt->wdt_dev);
302
303 watchdog_stop_on_reboot(&mtk_wdt->wdt_dev);
304 err = devm_watchdog_register_device(dev, &mtk_wdt->wdt_dev);
305@@ -190,6 +362,17 @@ static int mtk_wdt_probe(struct platform_device *pdev)
306 dev_info(dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)\n",
307 mtk_wdt->wdt_dev.timeout, nowayout);
308
309+ wdt_data = of_device_get_match_data(dev);
310+ if (wdt_data) {
311+ err = toprgu_register_reset_controller(pdev,
312+ wdt_data->toprgu_sw_rst_num);
313+ if (err)
314+ return err;
315+ }
316+
317+ mtk_wdt->disable_wdt_extrst =
318+ of_property_read_bool(dev->of_node, "mediatek,disable-extrst");
319+
320 return 0;
321 }
322
323@@ -219,6 +402,7 @@ static int mtk_wdt_resume(struct device *dev)
324
325 static const struct of_device_id mtk_wdt_dt_ids[] = {
326 { .compatible = "mediatek,mt6589-wdt" },
327+ { .compatible = "mediatek,mt7986-wdt", .data = &mt7986_data },
328 { /* sentinel */ }
329 };
330 MODULE_DEVICE_TABLE(of, mtk_wdt_dt_ids);
331@@ -249,4 +433,4 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
332 MODULE_LICENSE("GPL");
333 MODULE_AUTHOR("Matthias Brugger <matthias.bgg@gmail.com>");
334 MODULE_DESCRIPTION("Mediatek WatchDog Timer Driver");
335-MODULE_VERSION(DRV_VERSION);
336+MODULE_VERSION(DRV_VERSION);
337\ No newline at end of file
developer5d148cb2023-06-02 13:08:11 +0800338--
3392.34.1
340