dbf556467d3c3a5331187c8bac4d1912a8aef8fd
[platform/kernel/u-boot.git] / drivers / watchdog / wdt-uclass.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2017 Google, Inc
4  */
5
6 #define LOG_CATEGORY UCLASS_WDT
7
8 #include <common.h>
9 #include <dm.h>
10 #include <errno.h>
11 #include <hang.h>
12 #include <log.h>
13 #include <sysreset.h>
14 #include <time.h>
15 #include <wdt.h>
16 #include <asm/global_data.h>
17 #include <dm/device-internal.h>
18 #include <dm/lists.h>
19
20 DECLARE_GLOBAL_DATA_PTR;
21
22 #define WATCHDOG_TIMEOUT_SECS   (CONFIG_WATCHDOG_TIMEOUT_MSECS / 1000)
23
24 struct wdt_priv {
25         /* Timeout, in seconds, to configure this device to. */
26         u32 timeout;
27         /*
28          * Time, in milliseconds, between calling the device's ->reset()
29          * method from watchdog_reset().
30          */
31         ulong reset_period;
32         /*
33          * Next time (as returned by get_timer(0)) to call
34          * ->reset().
35          */
36         ulong next_reset;
37         /* Whether watchdog_start() has been called on the device. */
38         bool running;
39         /* No autostart */
40         bool noautostart;
41 };
42
43 static void init_watchdog_dev(struct udevice *dev)
44 {
45         struct wdt_priv *priv;
46         int ret;
47
48         priv = dev_get_uclass_priv(dev);
49
50         if (IS_ENABLED(CONFIG_SYSRESET_WATCHDOG_AUTO)) {
51                 ret = sysreset_register_wdt(dev);
52                 if (ret)
53                         printf("WDT:   Failed to register %s for sysreset\n",
54                                dev->name);
55         }
56
57         if (!IS_ENABLED(CONFIG_WATCHDOG_AUTOSTART) || priv->noautostart) {
58                 printf("WDT:   Not starting %s\n", dev->name);
59                 return;
60         }
61
62         ret = wdt_start(dev, priv->timeout * 1000, 0);
63         if (ret != 0) {
64                 printf("WDT:   Failed to start %s\n", dev->name);
65                 return;
66         }
67
68         printf("WDT:   Started %s with%s servicing (%ds timeout)\n", dev->name,
69                IS_ENABLED(CONFIG_WATCHDOG) ? "" : "out", priv->timeout);
70 }
71
72 int initr_watchdog(void)
73 {
74         struct udevice *dev;
75         struct uclass *uc;
76         int ret;
77
78         ret = uclass_get(UCLASS_WDT, &uc);
79         if (ret) {
80                 log_debug("Error getting UCLASS_WDT: %d\n", ret);
81                 return 0;
82         }
83
84         uclass_foreach_dev(dev, uc) {
85                 ret = device_probe(dev);
86                 if (ret) {
87                         log_debug("Error probing %s: %d\n", dev->name, ret);
88                         continue;
89                 }
90                 init_watchdog_dev(dev);
91         }
92
93         gd->flags |= GD_FLG_WDT_READY;
94         return 0;
95 }
96
97 int wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
98 {
99         const struct wdt_ops *ops = device_get_ops(dev);
100         int ret;
101
102         if (!ops->start)
103                 return -ENOSYS;
104
105         ret = ops->start(dev, timeout_ms, flags);
106         if (ret == 0) {
107                 struct wdt_priv *priv = dev_get_uclass_priv(dev);
108
109                 priv->running = true;
110         }
111
112         return ret;
113 }
114
115 int wdt_stop(struct udevice *dev)
116 {
117         const struct wdt_ops *ops = device_get_ops(dev);
118         int ret;
119
120         if (!ops->stop)
121                 return -ENOSYS;
122
123         ret = ops->stop(dev);
124         if (ret == 0) {
125                 struct wdt_priv *priv = dev_get_uclass_priv(dev);
126
127                 priv->running = false;
128         }
129
130         return ret;
131 }
132
133 int wdt_stop_all(void)
134 {
135         struct wdt_priv *priv;
136         struct udevice *dev;
137         struct uclass *uc;
138         int ret, err;
139
140         ret = uclass_get(UCLASS_WDT, &uc);
141         if (ret)
142                 return ret;
143
144         uclass_foreach_dev(dev, uc) {
145                 if (!device_active(dev))
146                         continue;
147                 priv = dev_get_uclass_priv(dev);
148                 if (!priv->running)
149                         continue;
150                 err = wdt_stop(dev);
151                 if (!ret)
152                         ret = err;
153         }
154
155         return ret;
156 }
157
158 int wdt_reset(struct udevice *dev)
159 {
160         const struct wdt_ops *ops = device_get_ops(dev);
161
162         if (!ops->reset)
163                 return -ENOSYS;
164
165         return ops->reset(dev);
166 }
167
168 int wdt_expire_now(struct udevice *dev, ulong flags)
169 {
170         int ret = 0;
171         const struct wdt_ops *ops;
172
173         debug("WDT Resetting: %lu\n", flags);
174         ops = device_get_ops(dev);
175         if (ops->expire_now) {
176                 return ops->expire_now(dev, flags);
177         } else {
178                 ret = wdt_start(dev, 1, flags);
179
180                 if (ret < 0)
181                         return ret;
182
183                 hang();
184         }
185
186         return ret;
187 }
188
189 #if defined(CONFIG_WATCHDOG)
190 /*
191  * Called by macro WATCHDOG_RESET. This function be called *very* early,
192  * so we need to make sure, that the watchdog driver is ready before using
193  * it in this function.
194  */
195 void watchdog_reset(void)
196 {
197         struct wdt_priv *priv;
198         struct udevice *dev;
199         struct uclass *uc;
200         ulong now;
201
202         /* Exit if GD is not ready or watchdog is not initialized yet */
203         if (!gd || !(gd->flags & GD_FLG_WDT_READY))
204                 return;
205
206         if (uclass_get(UCLASS_WDT, &uc))
207                 return;
208
209         /*
210          * All devices bound to the wdt uclass should have been probed
211          * in initr_watchdog(). But just in case something went wrong,
212          * check device_active() before accessing the uclass private
213          * data.
214          */
215         uclass_foreach_dev(dev, uc) {
216                 if (!device_active(dev))
217                         continue;
218                 priv = dev_get_uclass_priv(dev);
219                 if (!priv->running)
220                         continue;
221                 /* Do not reset the watchdog too often */
222                 now = get_timer(0);
223                 if (time_after_eq(now, priv->next_reset)) {
224                         priv->next_reset = now + priv->reset_period;
225                         wdt_reset(dev);
226                 }
227         }
228 }
229 #endif
230
231 static int wdt_post_bind(struct udevice *dev)
232 {
233 #if defined(CONFIG_NEEDS_MANUAL_RELOC)
234         struct wdt_ops *ops = (struct wdt_ops *)device_get_ops(dev);
235         static int reloc_done;
236
237         if (!reloc_done) {
238                 if (ops->start)
239                         ops->start += gd->reloc_off;
240                 if (ops->stop)
241                         ops->stop += gd->reloc_off;
242                 if (ops->reset)
243                         ops->reset += gd->reloc_off;
244                 if (ops->expire_now)
245                         ops->expire_now += gd->reloc_off;
246
247                 reloc_done++;
248         }
249 #endif
250         return 0;
251 }
252
253 static int wdt_pre_probe(struct udevice *dev)
254 {
255         u32 timeout = WATCHDOG_TIMEOUT_SECS;
256         /*
257          * Reset every 1000ms, or however often is required as
258          * indicated by a hw_margin_ms property.
259          */
260         ulong reset_period = 1000;
261         bool noautostart = false;
262         struct wdt_priv *priv;
263
264         if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) {
265                 timeout = dev_read_u32_default(dev, "timeout-sec", timeout);
266                 reset_period = dev_read_u32_default(dev, "hw_margin_ms",
267                                                     4 * reset_period) / 4;
268                 noautostart = dev_read_bool(dev, "u-boot,noautostart");
269         }
270         priv = dev_get_uclass_priv(dev);
271         priv->timeout = timeout;
272         priv->reset_period = reset_period;
273         priv->noautostart = noautostart;
274         /*
275          * Pretend this device was last reset "long" ago so the first
276          * watchdog_reset will actually call its ->reset method.
277          */
278         priv->next_reset = get_timer(0);
279
280         return 0;
281 }
282
283 UCLASS_DRIVER(wdt) = {
284         .id                     = UCLASS_WDT,
285         .name                   = "watchdog",
286         .flags                  = DM_UC_FLAG_SEQ_ALIAS,
287         .post_bind              = wdt_post_bind,
288         .pre_probe              = wdt_pre_probe,
289         .per_device_auto        = sizeof(struct wdt_priv),
290 };