hc
2024-10-22 8ac6c7a54ed1b98d142dce24b11c6de6a1e239a5
kernel/drivers/watchdog/aspeed_wdt.c
....@@ -1,12 +1,8 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * Copyright 2016 IBM Corporation
34 *
45 * Joel Stanley <joel@jms.id.au>
5
- *
6
- * This program is free software; you can redistribute it and/or
7
- * modify it under the terms of the GNU General Public License
8
- * as published by the Free Software Foundation; either version
9
- * 2 of the License, or (at your option) any later version.
106 */
117
128 #include <linux/delay.h>
....@@ -58,6 +54,8 @@
5854 #define WDT_CTRL_ENABLE BIT(0)
5955 #define WDT_TIMEOUT_STATUS 0x10
6056 #define WDT_TIMEOUT_STATUS_BOOT_SECONDARY BIT(1)
57
+#define WDT_CLEAR_TIMEOUT_STATUS 0x14
58
+#define WDT_CLEAR_TIMEOUT_AND_BOOT_CODE_SELECTION BIT(0)
6159
6260 /*
6361 * WDT_RESET_WIDTH controls the characteristics of the external pulse (if
....@@ -170,6 +168,60 @@
170168 return 0;
171169 }
172170
171
+/* access_cs0 shows if cs0 is accessible, hence the reverted bit */
172
+static ssize_t access_cs0_show(struct device *dev,
173
+ struct device_attribute *attr, char *buf)
174
+{
175
+ struct aspeed_wdt *wdt = dev_get_drvdata(dev);
176
+ u32 status = readl(wdt->base + WDT_TIMEOUT_STATUS);
177
+
178
+ return sprintf(buf, "%u\n",
179
+ !(status & WDT_TIMEOUT_STATUS_BOOT_SECONDARY));
180
+}
181
+
182
+static ssize_t access_cs0_store(struct device *dev,
183
+ struct device_attribute *attr, const char *buf,
184
+ size_t size)
185
+{
186
+ struct aspeed_wdt *wdt = dev_get_drvdata(dev);
187
+ unsigned long val;
188
+
189
+ if (kstrtoul(buf, 10, &val))
190
+ return -EINVAL;
191
+
192
+ if (val)
193
+ writel(WDT_CLEAR_TIMEOUT_AND_BOOT_CODE_SELECTION,
194
+ wdt->base + WDT_CLEAR_TIMEOUT_STATUS);
195
+
196
+ return size;
197
+}
198
+
199
+/*
200
+ * This attribute exists only if the system has booted from the alternate
201
+ * flash with 'alt-boot' option.
202
+ *
203
+ * At alternate flash the 'access_cs0' sysfs node provides:
204
+ * ast2400: a way to get access to the primary SPI flash chip at CS0
205
+ * after booting from the alternate chip at CS1.
206
+ * ast2500: a way to restore the normal address mapping from
207
+ * (CS0->CS1, CS1->CS0) to (CS0->CS0, CS1->CS1).
208
+ *
209
+ * Clearing the boot code selection and timeout counter also resets to the
210
+ * initial state the chip select line mapping. When the SoC is in normal
211
+ * mapping state (i.e. booted from CS0), clearing those bits does nothing for
212
+ * both versions of the SoC. For alternate boot mode (booted from CS1 due to
213
+ * wdt2 expiration) the behavior differs as described above.
214
+ *
215
+ * This option can be used with wdt2 (watchdog1) only.
216
+ */
217
+static DEVICE_ATTR_RW(access_cs0);
218
+
219
+static struct attribute *bswitch_attrs[] = {
220
+ &dev_attr_access_cs0.attr,
221
+ NULL
222
+};
223
+ATTRIBUTE_GROUPS(bswitch);
224
+
173225 static const struct watchdog_ops aspeed_wdt_ops = {
174226 .start = aspeed_wdt_start,
175227 .stop = aspeed_wdt_stop,
....@@ -188,34 +240,33 @@
188240
189241 static int aspeed_wdt_probe(struct platform_device *pdev)
190242 {
243
+ struct device *dev = &pdev->dev;
191244 const struct aspeed_wdt_config *config;
192245 const struct of_device_id *ofdid;
193246 struct aspeed_wdt *wdt;
194
- struct resource *res;
195247 struct device_node *np;
196248 const char *reset_type;
197249 u32 duration;
198250 u32 status;
199251 int ret;
200252
201
- wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
253
+ wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
202254 if (!wdt)
203255 return -ENOMEM;
204256
205
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
206
- wdt->base = devm_ioremap_resource(&pdev->dev, res);
257
+ wdt->base = devm_platform_ioremap_resource(pdev, 0);
207258 if (IS_ERR(wdt->base))
208259 return PTR_ERR(wdt->base);
209260
210261 wdt->wdd.info = &aspeed_wdt_info;
211262 wdt->wdd.ops = &aspeed_wdt_ops;
212263 wdt->wdd.max_hw_heartbeat_ms = WDT_MAX_TIMEOUT_MS;
213
- wdt->wdd.parent = &pdev->dev;
264
+ wdt->wdd.parent = dev;
214265
215266 wdt->wdd.timeout = WDT_DEFAULT_TIMEOUT;
216
- watchdog_init_timeout(&wdt->wdd, 0, &pdev->dev);
267
+ watchdog_init_timeout(&wdt->wdd, 0, dev);
217268
218
- np = pdev->dev.of_node;
269
+ np = dev->of_node;
219270
220271 ofdid = of_match_node(aspeed_wdt_of_table, np);
221272 if (!ofdid)
....@@ -294,11 +345,11 @@
294345 u32 max_duration = config->ext_pulse_width_mask + 1;
295346
296347 if (duration == 0 || duration > max_duration) {
297
- dev_err(&pdev->dev, "Invalid pulse duration: %uus\n",
298
- duration);
348
+ dev_err(dev, "Invalid pulse duration: %uus\n",
349
+ duration);
299350 duration = max(1U, min(max_duration, duration));
300
- dev_info(&pdev->dev, "Pulse duration set to %uus\n",
301
- duration);
351
+ dev_info(dev, "Pulse duration set to %uus\n",
352
+ duration);
302353 }
303354
304355 /*
....@@ -317,16 +368,17 @@
317368 }
318369
319370 status = readl(wdt->base + WDT_TIMEOUT_STATUS);
320
- if (status & WDT_TIMEOUT_STATUS_BOOT_SECONDARY)
371
+ if (status & WDT_TIMEOUT_STATUS_BOOT_SECONDARY) {
321372 wdt->wdd.bootstatus = WDIOF_CARDRESET;
322373
323
- ret = devm_watchdog_register_device(&pdev->dev, &wdt->wdd);
324
- if (ret) {
325
- dev_err(&pdev->dev, "failed to register\n");
326
- return ret;
374
+ if (of_device_is_compatible(np, "aspeed,ast2400-wdt") ||
375
+ of_device_is_compatible(np, "aspeed,ast2500-wdt"))
376
+ wdt->wdd.groups = bswitch_groups;
327377 }
328378
329
- return 0;
379
+ dev_set_drvdata(dev, wdt);
380
+
381
+ return devm_watchdog_register_device(dev, &wdt->wdd);
330382 }
331383
332384 static struct platform_driver aspeed_watchdog_driver = {