forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-10-09 244b2c5ca8b14627e4a17755e5922221e121c771
kernel/drivers/watchdog/lantiq_wdt.c
....@@ -1,18 +1,13 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
2
- * This program is free software; you can redistribute it and/or modify it
3
- * under the terms of the GNU General Public License version 2 as published
4
- * by the Free Software Foundation.
53 *
64 * Copyright (C) 2010 John Crispin <john@phrozen.org>
75 * Copyright (C) 2017 Hauke Mehrtens <hauke@hauke-m.de>
86 * Based on EP93xx wdt driver
97 */
108
11
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
12
-
139 #include <linux/module.h>
14
-#include <linux/fs.h>
15
-#include <linux/miscdevice.h>
10
+#include <linux/bitops.h>
1611 #include <linux/watchdog.h>
1712 #include <linux/of_platform.h>
1813 #include <linux/uaccess.h>
....@@ -40,169 +35,128 @@
4035 * essentially the following two magic passwords need to be written to allow
4136 * IO access to the WDT core
4237 */
43
-#define LTQ_WDT_PW1 0x00BE0000
44
-#define LTQ_WDT_PW2 0x00DC0000
38
+#define LTQ_WDT_CR_PW1 0x00BE0000
39
+#define LTQ_WDT_CR_PW2 0x00DC0000
4540
46
-#define LTQ_WDT_CR 0x0 /* watchdog control register */
47
-#define LTQ_WDT_SR 0x8 /* watchdog status register */
41
+#define LTQ_WDT_CR 0x0 /* watchdog control register */
42
+#define LTQ_WDT_CR_GEN BIT(31) /* enable bit */
43
+/* Pre-warning limit set to 1/16 of max WDT period */
44
+#define LTQ_WDT_CR_PWL (0x3 << 26)
45
+/* set clock divider to 0x40000 */
46
+#define LTQ_WDT_CR_CLKDIV (0x3 << 24)
47
+#define LTQ_WDT_CR_PW_MASK GENMASK(23, 16) /* Password field */
48
+#define LTQ_WDT_CR_MAX_TIMEOUT ((1 << 16) - 1) /* The reload field is 16 bit */
49
+#define LTQ_WDT_SR 0x8 /* watchdog status register */
50
+#define LTQ_WDT_SR_EN BIT(31) /* Enable */
51
+#define LTQ_WDT_SR_VALUE_MASK GENMASK(15, 0) /* Timer value */
4852
49
-#define LTQ_WDT_SR_EN (0x1 << 31) /* enable bit */
50
-#define LTQ_WDT_SR_PWD (0x3 << 26) /* turn on power */
51
-#define LTQ_WDT_SR_CLKDIV (0x3 << 24) /* turn on clock and set */
52
- /* divider to 0x40000 */
5353 #define LTQ_WDT_DIVIDER 0x40000
54
-#define LTQ_MAX_TIMEOUT ((1 << 16) - 1) /* the reload field is 16 bit */
5554
5655 static bool nowayout = WATCHDOG_NOWAYOUT;
5756
58
-static void __iomem *ltq_wdt_membase;
59
-static unsigned long ltq_io_region_clk_rate;
57
+struct ltq_wdt_hw {
58
+ int (*bootstatus_get)(struct device *dev);
59
+};
6060
61
-static unsigned long ltq_wdt_bootstatus;
62
-static unsigned long ltq_wdt_in_use;
63
-static int ltq_wdt_timeout = 30;
64
-static int ltq_wdt_ok_to_close;
61
+struct ltq_wdt_priv {
62
+ struct watchdog_device wdt;
63
+ void __iomem *membase;
64
+ unsigned long clk_rate;
65
+};
6566
66
-static void
67
-ltq_wdt_enable(void)
67
+static u32 ltq_wdt_r32(struct ltq_wdt_priv *priv, u32 offset)
6868 {
69
- unsigned long int timeout = ltq_wdt_timeout *
70
- (ltq_io_region_clk_rate / LTQ_WDT_DIVIDER) + 0x1000;
71
- if (timeout > LTQ_MAX_TIMEOUT)
72
- timeout = LTQ_MAX_TIMEOUT;
73
-
74
- /* write the first password magic */
75
- ltq_w32(LTQ_WDT_PW1, ltq_wdt_membase + LTQ_WDT_CR);
76
- /* write the second magic plus the configuration and new timeout */
77
- ltq_w32(LTQ_WDT_SR_EN | LTQ_WDT_SR_PWD | LTQ_WDT_SR_CLKDIV |
78
- LTQ_WDT_PW2 | timeout, ltq_wdt_membase + LTQ_WDT_CR);
69
+ return __raw_readl(priv->membase + offset);
7970 }
8071
81
-static void
82
-ltq_wdt_disable(void)
72
+static void ltq_wdt_w32(struct ltq_wdt_priv *priv, u32 val, u32 offset)
8373 {
84
- /* write the first password magic */
85
- ltq_w32(LTQ_WDT_PW1, ltq_wdt_membase + LTQ_WDT_CR);
86
- /*
87
- * write the second password magic with no config
88
- * this turns the watchdog off
89
- */
90
- ltq_w32(LTQ_WDT_PW2, ltq_wdt_membase + LTQ_WDT_CR);
74
+ __raw_writel(val, priv->membase + offset);
9175 }
9276
93
-static ssize_t
94
-ltq_wdt_write(struct file *file, const char __user *data,
95
- size_t len, loff_t *ppos)
77
+static void ltq_wdt_mask(struct ltq_wdt_priv *priv, u32 clear, u32 set,
78
+ u32 offset)
9679 {
97
- if (len) {
98
- if (!nowayout) {
99
- size_t i;
80
+ u32 val = ltq_wdt_r32(priv, offset);
10081
101
- ltq_wdt_ok_to_close = 0;
102
- for (i = 0; i != len; i++) {
103
- char c;
104
-
105
- if (get_user(c, data + i))
106
- return -EFAULT;
107
- if (c == 'V')
108
- ltq_wdt_ok_to_close = 1;
109
- else
110
- ltq_wdt_ok_to_close = 0;
111
- }
112
- }
113
- ltq_wdt_enable();
114
- }
115
-
116
- return len;
82
+ val &= ~(clear);
83
+ val |= set;
84
+ ltq_wdt_w32(priv, val, offset);
11785 }
11886
119
-static struct watchdog_info ident = {
87
+static struct ltq_wdt_priv *ltq_wdt_get_priv(struct watchdog_device *wdt)
88
+{
89
+ return container_of(wdt, struct ltq_wdt_priv, wdt);
90
+}
91
+
92
+static struct watchdog_info ltq_wdt_info = {
12093 .options = WDIOF_MAGICCLOSE | WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
121
- WDIOF_CARDRESET,
94
+ WDIOF_CARDRESET,
12295 .identity = "ltq_wdt",
12396 };
12497
125
-static long
126
-ltq_wdt_ioctl(struct file *file,
127
- unsigned int cmd, unsigned long arg)
98
+static int ltq_wdt_start(struct watchdog_device *wdt)
12899 {
129
- int ret = -ENOTTY;
100
+ struct ltq_wdt_priv *priv = ltq_wdt_get_priv(wdt);
101
+ u32 timeout;
130102
131
- switch (cmd) {
132
- case WDIOC_GETSUPPORT:
133
- ret = copy_to_user((struct watchdog_info __user *)arg, &ident,
134
- sizeof(ident)) ? -EFAULT : 0;
135
- break;
103
+ timeout = wdt->timeout * priv->clk_rate;
136104
137
- case WDIOC_GETBOOTSTATUS:
138
- ret = put_user(ltq_wdt_bootstatus, (int __user *)arg);
139
- break;
140
-
141
- case WDIOC_GETSTATUS:
142
- ret = put_user(0, (int __user *)arg);
143
- break;
144
-
145
- case WDIOC_SETTIMEOUT:
146
- ret = get_user(ltq_wdt_timeout, (int __user *)arg);
147
- if (!ret)
148
- ltq_wdt_enable();
149
- /* intentional drop through */
150
- case WDIOC_GETTIMEOUT:
151
- ret = put_user(ltq_wdt_timeout, (int __user *)arg);
152
- break;
153
-
154
- case WDIOC_KEEPALIVE:
155
- ltq_wdt_enable();
156
- ret = 0;
157
- break;
158
- }
159
- return ret;
160
-}
161
-
162
-static int
163
-ltq_wdt_open(struct inode *inode, struct file *file)
164
-{
165
- if (test_and_set_bit(0, &ltq_wdt_in_use))
166
- return -EBUSY;
167
- ltq_wdt_in_use = 1;
168
- ltq_wdt_enable();
169
-
170
- return nonseekable_open(inode, file);
171
-}
172
-
173
-static int
174
-ltq_wdt_release(struct inode *inode, struct file *file)
175
-{
176
- if (ltq_wdt_ok_to_close)
177
- ltq_wdt_disable();
178
- else
179
- pr_err("watchdog closed without warning\n");
180
- ltq_wdt_ok_to_close = 0;
181
- clear_bit(0, &ltq_wdt_in_use);
105
+ ltq_wdt_mask(priv, LTQ_WDT_CR_PW_MASK, LTQ_WDT_CR_PW1, LTQ_WDT_CR);
106
+ /* write the second magic plus the configuration and new timeout */
107
+ ltq_wdt_mask(priv, LTQ_WDT_CR_PW_MASK | LTQ_WDT_CR_MAX_TIMEOUT,
108
+ LTQ_WDT_CR_GEN | LTQ_WDT_CR_PWL | LTQ_WDT_CR_CLKDIV |
109
+ LTQ_WDT_CR_PW2 | timeout,
110
+ LTQ_WDT_CR);
182111
183112 return 0;
184113 }
185114
186
-static const struct file_operations ltq_wdt_fops = {
187
- .owner = THIS_MODULE,
188
- .write = ltq_wdt_write,
189
- .unlocked_ioctl = ltq_wdt_ioctl,
190
- .open = ltq_wdt_open,
191
- .release = ltq_wdt_release,
192
- .llseek = no_llseek,
193
-};
194
-
195
-static struct miscdevice ltq_wdt_miscdev = {
196
- .minor = WATCHDOG_MINOR,
197
- .name = "watchdog",
198
- .fops = &ltq_wdt_fops,
199
-};
200
-
201
-typedef int (*ltq_wdt_bootstatus_set)(struct platform_device *pdev);
202
-
203
-static int ltq_wdt_bootstatus_xrx(struct platform_device *pdev)
115
+static int ltq_wdt_stop(struct watchdog_device *wdt)
204116 {
205
- struct device *dev = &pdev->dev;
117
+ struct ltq_wdt_priv *priv = ltq_wdt_get_priv(wdt);
118
+
119
+ ltq_wdt_mask(priv, LTQ_WDT_CR_PW_MASK, LTQ_WDT_CR_PW1, LTQ_WDT_CR);
120
+ ltq_wdt_mask(priv, LTQ_WDT_CR_GEN | LTQ_WDT_CR_PW_MASK,
121
+ LTQ_WDT_CR_PW2, LTQ_WDT_CR);
122
+
123
+ return 0;
124
+}
125
+
126
+static int ltq_wdt_ping(struct watchdog_device *wdt)
127
+{
128
+ struct ltq_wdt_priv *priv = ltq_wdt_get_priv(wdt);
129
+ u32 timeout;
130
+
131
+ timeout = wdt->timeout * priv->clk_rate;
132
+
133
+ ltq_wdt_mask(priv, LTQ_WDT_CR_PW_MASK, LTQ_WDT_CR_PW1, LTQ_WDT_CR);
134
+ /* write the second magic plus the configuration and new timeout */
135
+ ltq_wdt_mask(priv, LTQ_WDT_CR_PW_MASK | LTQ_WDT_CR_MAX_TIMEOUT,
136
+ LTQ_WDT_CR_PW2 | timeout, LTQ_WDT_CR);
137
+
138
+ return 0;
139
+}
140
+
141
+static unsigned int ltq_wdt_get_timeleft(struct watchdog_device *wdt)
142
+{
143
+ struct ltq_wdt_priv *priv = ltq_wdt_get_priv(wdt);
144
+ u64 timeout;
145
+
146
+ timeout = ltq_wdt_r32(priv, LTQ_WDT_SR) & LTQ_WDT_SR_VALUE_MASK;
147
+ return do_div(timeout, priv->clk_rate);
148
+}
149
+
150
+static const struct watchdog_ops ltq_wdt_ops = {
151
+ .owner = THIS_MODULE,
152
+ .start = ltq_wdt_start,
153
+ .stop = ltq_wdt_stop,
154
+ .ping = ltq_wdt_ping,
155
+ .get_timeleft = ltq_wdt_get_timeleft,
156
+};
157
+
158
+static int ltq_wdt_xrx_bootstatus_get(struct device *dev)
159
+{
206160 struct regmap *rcu_regmap;
207161 u32 val;
208162 int err;
....@@ -216,14 +170,13 @@
216170 return err;
217171
218172 if (val & LTQ_XRX_RCU_RST_STAT_WDT)
219
- ltq_wdt_bootstatus = WDIOF_CARDRESET;
173
+ return WDIOF_CARDRESET;
220174
221175 return 0;
222176 }
223177
224
-static int ltq_wdt_bootstatus_falcon(struct platform_device *pdev)
178
+static int ltq_wdt_falcon_bootstatus_get(struct device *dev)
225179 {
226
- struct device *dev = &pdev->dev;
227180 struct regmap *rcu_regmap;
228181 u32 val;
229182 int err;
....@@ -238,62 +191,88 @@
238191 return err;
239192
240193 if ((val & LTQ_FALCON_SYS1_CPU0RS_MASK) == LTQ_FALCON_SYS1_CPU0RS_WDT)
241
- ltq_wdt_bootstatus = WDIOF_CARDRESET;
194
+ return WDIOF_CARDRESET;
242195
243196 return 0;
244197 }
245198
246
-static int
247
-ltq_wdt_probe(struct platform_device *pdev)
199
+static int ltq_wdt_probe(struct platform_device *pdev)
248200 {
249
- struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
201
+ struct device *dev = &pdev->dev;
202
+ struct ltq_wdt_priv *priv;
203
+ struct watchdog_device *wdt;
250204 struct clk *clk;
251
- ltq_wdt_bootstatus_set ltq_wdt_bootstatus_set;
205
+ const struct ltq_wdt_hw *ltq_wdt_hw;
252206 int ret;
207
+ u32 status;
253208
254
- ltq_wdt_membase = devm_ioremap_resource(&pdev->dev, res);
255
- if (IS_ERR(ltq_wdt_membase))
256
- return PTR_ERR(ltq_wdt_membase);
209
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
210
+ if (!priv)
211
+ return -ENOMEM;
257212
258
- ltq_wdt_bootstatus_set = of_device_get_match_data(&pdev->dev);
259
- if (ltq_wdt_bootstatus_set) {
260
- ret = ltq_wdt_bootstatus_set(pdev);
261
- if (ret)
262
- return ret;
263
- }
213
+ priv->membase = devm_platform_ioremap_resource(pdev, 0);
214
+ if (IS_ERR(priv->membase))
215
+ return PTR_ERR(priv->membase);
264216
265217 /* we do not need to enable the clock as it is always running */
266218 clk = clk_get_io();
267
- if (IS_ERR(clk)) {
268
- dev_err(&pdev->dev, "Failed to get clock\n");
269
- return -ENOENT;
219
+ priv->clk_rate = clk_get_rate(clk) / LTQ_WDT_DIVIDER;
220
+ if (!priv->clk_rate) {
221
+ dev_err(dev, "clock rate less than divider %i\n",
222
+ LTQ_WDT_DIVIDER);
223
+ return -EINVAL;
270224 }
271
- ltq_io_region_clk_rate = clk_get_rate(clk);
272
- clk_put(clk);
273225
274
- dev_info(&pdev->dev, "Init done\n");
275
- return misc_register(&ltq_wdt_miscdev);
226
+ wdt = &priv->wdt;
227
+ wdt->info = &ltq_wdt_info;
228
+ wdt->ops = &ltq_wdt_ops;
229
+ wdt->min_timeout = 1;
230
+ wdt->max_timeout = LTQ_WDT_CR_MAX_TIMEOUT / priv->clk_rate;
231
+ wdt->timeout = wdt->max_timeout;
232
+ wdt->parent = dev;
233
+
234
+ ltq_wdt_hw = of_device_get_match_data(dev);
235
+ if (ltq_wdt_hw && ltq_wdt_hw->bootstatus_get) {
236
+ ret = ltq_wdt_hw->bootstatus_get(dev);
237
+ if (ret >= 0)
238
+ wdt->bootstatus = ret;
239
+ }
240
+
241
+ watchdog_set_nowayout(wdt, nowayout);
242
+ watchdog_init_timeout(wdt, 0, dev);
243
+
244
+ status = ltq_wdt_r32(priv, LTQ_WDT_SR);
245
+ if (status & LTQ_WDT_SR_EN) {
246
+ /*
247
+ * If the watchdog is already running overwrite it with our
248
+ * new settings. Stop is not needed as the start call will
249
+ * replace all settings anyway.
250
+ */
251
+ ltq_wdt_start(wdt);
252
+ set_bit(WDOG_HW_RUNNING, &wdt->status);
253
+ }
254
+
255
+ return devm_watchdog_register_device(dev, wdt);
276256 }
277257
278
-static int
279
-ltq_wdt_remove(struct platform_device *pdev)
280
-{
281
- misc_deregister(&ltq_wdt_miscdev);
258
+static const struct ltq_wdt_hw ltq_wdt_xrx100 = {
259
+ .bootstatus_get = ltq_wdt_xrx_bootstatus_get,
260
+};
282261
283
- return 0;
284
-}
262
+static const struct ltq_wdt_hw ltq_wdt_falcon = {
263
+ .bootstatus_get = ltq_wdt_falcon_bootstatus_get,
264
+};
285265
286266 static const struct of_device_id ltq_wdt_match[] = {
287
- { .compatible = "lantiq,wdt", .data = NULL},
288
- { .compatible = "lantiq,xrx100-wdt", .data = ltq_wdt_bootstatus_xrx },
289
- { .compatible = "lantiq,falcon-wdt", .data = ltq_wdt_bootstatus_falcon },
267
+ { .compatible = "lantiq,wdt", .data = NULL },
268
+ { .compatible = "lantiq,xrx100-wdt", .data = &ltq_wdt_xrx100 },
269
+ { .compatible = "lantiq,falcon-wdt", .data = &ltq_wdt_falcon },
290270 {},
291271 };
292272 MODULE_DEVICE_TABLE(of, ltq_wdt_match);
293273
294274 static struct platform_driver ltq_wdt_driver = {
295275 .probe = ltq_wdt_probe,
296
- .remove = ltq_wdt_remove,
297276 .driver = {
298277 .name = "wdt",
299278 .of_match_table = ltq_wdt_match,