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