]> Git Repo - J-u-boot.git/blame - drivers/watchdog/wdt-uclass.c
net: dwc_eth_qos: Remove obsolete imx8 includes
[J-u-boot.git] / drivers / watchdog / wdt-uclass.c
CommitLineData
83d290c5 1// SPDX-License-Identifier: GPL-2.0+
0753bc2d 2/*
3 * Copyright 2017 Google, Inc
0753bc2d 4 */
5
b953ec2b
PD
6#define LOG_CATEGORY UCLASS_WDT
7
c2fd0ca1 8#include <cyclic.h>
a341a0e0 9#include <div64.h>
0753bc2d 10#include <dm.h>
11#include <errno.h>
db41d65a 12#include <hang.h>
f7ae49fc 13#include <log.h>
a8f63d18 14#include <sysreset.h>
6d8eae9a 15#include <time.h>
0753bc2d 16#include <wdt.h>
401d1c4f 17#include <asm/global_data.h>
0753bc2d 18#include <dm/device-internal.h>
19#include <dm/lists.h>
008c4b3c 20#include <linux/kernel.h>
0753bc2d 21
06985289
SR
22DECLARE_GLOBAL_DATA_PTR;
23
b4d9452c
RV
24#define WATCHDOG_TIMEOUT_SECS (CONFIG_WATCHDOG_TIMEOUT_MSECS / 1000)
25
6d24dc89 26struct wdt_priv {
008c4b3c
RV
27 /* The udevice owning this wdt_priv. */
28 struct udevice *dev;
6d24dc89
RV
29 /* Timeout, in seconds, to configure this device to. */
30 u32 timeout;
31 /*
32 * Time, in milliseconds, between calling the device's ->reset()
4388ada7 33 * method from schedule().
6d24dc89
RV
34 */
35 ulong reset_period;
36 /*
37 * Next time (as returned by get_timer(0)) to call
38 * ->reset().
39 */
40 ulong next_reset;
f1b112af
RV
41 /* Whether watchdog_start() has been called on the device. */
42 bool running;
27836705
RV
43 /* autostart */
44 bool autostart;
c2fd0ca1 45
008c4b3c 46 struct cyclic_info cyclic;
6d24dc89 47};
40d7f3c8 48
008c4b3c 49static void wdt_cyclic(struct cyclic_info *c)
c2fd0ca1 50{
008c4b3c
RV
51 struct wdt_priv *priv = container_of(c, struct wdt_priv, cyclic);
52 struct udevice *dev = priv->dev;
c2fd0ca1
SR
53
54 if (!device_active(dev))
55 return;
56
c2fd0ca1
SR
57 if (!priv->running)
58 return;
59
60 wdt_reset(dev);
61}
62
3eaf6e2e 63static void init_watchdog_dev(struct udevice *dev)
b4d9452c 64{
6d24dc89 65 struct wdt_priv *priv;
25e20e34 66 int ret;
b4d9452c 67
3eaf6e2e
RV
68 priv = dev_get_uclass_priv(dev);
69
a8f63d18
SH
70 if (IS_ENABLED(CONFIG_SYSRESET_WATCHDOG_AUTO)) {
71 ret = sysreset_register_wdt(dev);
72 if (ret)
73 printf("WDT: Failed to register %s for sysreset\n",
74 dev->name);
75 }
76
27836705 77 if (!priv->autostart) {
3eaf6e2e
RV
78 printf("WDT: Not starting %s\n", dev->name);
79 return;
80 }
81
82 ret = wdt_start(dev, priv->timeout * 1000, 0);
83 if (ret != 0) {
84 printf("WDT: Failed to start %s\n", dev->name);
85 return;
86 }
3eaf6e2e
RV
87}
88
89int initr_watchdog(void)
90{
492ee6b8
RV
91 struct udevice *dev;
92 struct uclass *uc;
93 int ret;
94
95 ret = uclass_get(UCLASS_WDT, &uc);
96 if (ret) {
97 log_debug("Error getting UCLASS_WDT: %d\n", ret);
98 return 0;
99 }
100
101 uclass_foreach_dev(dev, uc) {
102 ret = device_probe(dev);
103 if (ret) {
104 log_debug("Error probing %s: %d\n", dev->name, ret);
105 continue;
b4d9452c 106 }
492ee6b8 107 init_watchdog_dev(dev);
b4d9452c 108 }
b4d9452c
RV
109
110 return 0;
111}
112
ffdec300 113int wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
0753bc2d 114{
115 const struct wdt_ops *ops = device_get_ops(dev);
9c44ff1c 116 int ret;
0753bc2d 117
118 if (!ops->start)
119 return -ENOSYS;
120
9c44ff1c 121 ret = ops->start(dev, timeout_ms, flags);
f1b112af
RV
122 if (ret == 0) {
123 struct wdt_priv *priv = dev_get_uclass_priv(dev);
c2fd0ca1 124 char str[16];
f1b112af 125
c2fd0ca1
SR
126 memset(str, 0, 16);
127 if (IS_ENABLED(CONFIG_WATCHDOG)) {
df2b3829 128 if (priv->running)
008c4b3c 129 cyclic_unregister(&priv->cyclic);
df2b3829 130
c2fd0ca1 131 /* Register the watchdog driver as a cyclic function */
008c4b3c
RV
132 cyclic_register(&priv->cyclic, wdt_cyclic,
133 priv->reset_period * 1000,
134 dev->name);
135
136 snprintf(str, 16, "every %ldms", priv->reset_period);
c2fd0ca1
SR
137 }
138
df2b3829 139 priv->running = true;
c2fd0ca1
SR
140 printf("WDT: Started %s with%s servicing %s (%ds timeout)\n",
141 dev->name, IS_ENABLED(CONFIG_WATCHDOG) ? "" : "out",
a341a0e0 142 str, (u32)lldiv(timeout_ms, 1000));
f1b112af 143 }
9c44ff1c
T
144
145 return ret;
0753bc2d 146}
147
148int wdt_stop(struct udevice *dev)
149{
150 const struct wdt_ops *ops = device_get_ops(dev);
9c44ff1c 151 int ret;
0753bc2d 152
153 if (!ops->stop)
154 return -ENOSYS;
155
9c44ff1c 156 ret = ops->stop(dev);
f1b112af
RV
157 if (ret == 0) {
158 struct wdt_priv *priv = dev_get_uclass_priv(dev);
159
df2b3829 160 if (IS_ENABLED(CONFIG_WATCHDOG) && priv->running)
008c4b3c 161 cyclic_unregister(&priv->cyclic);
df2b3829 162
f1b112af
RV
163 priv->running = false;
164 }
9c44ff1c
T
165
166 return ret;
0753bc2d 167}
168
90555dc8
RV
169int wdt_stop_all(void)
170{
171 struct wdt_priv *priv;
172 struct udevice *dev;
173 struct uclass *uc;
174 int ret, err;
175
176 ret = uclass_get(UCLASS_WDT, &uc);
177 if (ret)
178 return ret;
179
180 uclass_foreach_dev(dev, uc) {
181 if (!device_active(dev))
182 continue;
183 priv = dev_get_uclass_priv(dev);
184 if (!priv->running)
185 continue;
186 err = wdt_stop(dev);
187 if (!ret)
188 ret = err;
189 }
190
191 return ret;
192}
193
0753bc2d 194int wdt_reset(struct udevice *dev)
195{
196 const struct wdt_ops *ops = device_get_ops(dev);
197
198 if (!ops->reset)
199 return -ENOSYS;
200
201 return ops->reset(dev);
202}
203
204int wdt_expire_now(struct udevice *dev, ulong flags)
205{
206 int ret = 0;
207 const struct wdt_ops *ops;
208
b71e0c1a 209 debug("WDT Resetting: %lu\n", flags);
0753bc2d 210 ops = device_get_ops(dev);
211 if (ops->expire_now) {
212 return ops->expire_now(dev, flags);
213 } else {
8967ebb6 214 ret = wdt_start(dev, 1, flags);
0753bc2d 215
0753bc2d 216 if (ret < 0)
217 return ret;
218
219 hang();
220 }
221
222 return ret;
223}
224
6d24dc89
RV
225static int wdt_pre_probe(struct udevice *dev)
226{
227 u32 timeout = WATCHDOG_TIMEOUT_SECS;
228 /*
229 * Reset every 1000ms, or however often is required as
230 * indicated by a hw_margin_ms property.
231 */
232 ulong reset_period = 1000;
27836705 233 bool autostart = IS_ENABLED(CONFIG_WATCHDOG_AUTOSTART);
6d24dc89
RV
234 struct wdt_priv *priv;
235
236 if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) {
237 timeout = dev_read_u32_default(dev, "timeout-sec", timeout);
238 reset_period = dev_read_u32_default(dev, "hw_margin_ms",
239 4 * reset_period) / 4;
27836705
RV
240 if (dev_read_bool(dev, "u-boot,noautostart"))
241 autostart = false;
242 else if (dev_read_bool(dev, "u-boot,autostart"))
243 autostart = true;
6d24dc89
RV
244 }
245 priv = dev_get_uclass_priv(dev);
008c4b3c 246 priv->dev = dev;
6d24dc89
RV
247 priv->timeout = timeout;
248 priv->reset_period = reset_period;
27836705 249 priv->autostart = autostart;
6d24dc89
RV
250 /*
251 * Pretend this device was last reset "long" ago so the first
4388ada7 252 * schedule() will actually call its ->reset method.
6d24dc89
RV
253 */
254 priv->next_reset = get_timer(0);
255
256 return 0;
257}
258
0753bc2d 259UCLASS_DRIVER(wdt) = {
068f8eaf
RV
260 .id = UCLASS_WDT,
261 .name = "watchdog",
262 .flags = DM_UC_FLAG_SEQ_ALIAS,
6d24dc89
RV
263 .pre_probe = wdt_pre_probe,
264 .per_device_auto = sizeof(struct wdt_priv),
0753bc2d 265};
This page took 0.3289 seconds and 4 git commands to generate.