command: Remove the cmd_tbl_t typedef
[oweals/u-boot.git] / drivers / watchdog / wdt-uclass.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2017 Google, Inc
4  */
5
6 #include <common.h>
7 #include <dm.h>
8 #include <errno.h>
9 #include <hang.h>
10 #include <time.h>
11 #include <wdt.h>
12 #include <dm/device-internal.h>
13 #include <dm/lists.h>
14
15 DECLARE_GLOBAL_DATA_PTR;
16
17 #define WATCHDOG_TIMEOUT_SECS   (CONFIG_WATCHDOG_TIMEOUT_MSECS / 1000)
18
19 /*
20  * Reset every 1000ms, or however often is required as indicated by a
21  * hw_margin_ms property.
22  */
23 static ulong reset_period = 1000;
24
25 int initr_watchdog(void)
26 {
27         u32 timeout = WATCHDOG_TIMEOUT_SECS;
28
29         /*
30          * Init watchdog: This will call the probe function of the
31          * watchdog driver, enabling the use of the device
32          */
33         if (uclass_get_device_by_seq(UCLASS_WDT, 0,
34                                      (struct udevice **)&gd->watchdog_dev)) {
35                 debug("WDT:   Not found by seq!\n");
36                 if (uclass_get_device(UCLASS_WDT, 0,
37                                       (struct udevice **)&gd->watchdog_dev)) {
38                         printf("WDT:   Not found!\n");
39                         return 0;
40                 }
41         }
42
43         if (CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)) {
44                 timeout = dev_read_u32_default(gd->watchdog_dev, "timeout-sec",
45                                                WATCHDOG_TIMEOUT_SECS);
46                 reset_period = dev_read_u32_default(gd->watchdog_dev,
47                                                     "hw_margin_ms",
48                                                     4 * reset_period) / 4;
49         }
50
51         wdt_start(gd->watchdog_dev, timeout * 1000, 0);
52         gd->flags |= GD_FLG_WDT_READY;
53         printf("WDT:   Started with%s servicing (%ds timeout)\n",
54                IS_ENABLED(CONFIG_WATCHDOG) ? "" : "out", timeout);
55
56         return 0;
57 }
58
59 int wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
60 {
61         const struct wdt_ops *ops = device_get_ops(dev);
62
63         if (!ops->start)
64                 return -ENOSYS;
65
66         return ops->start(dev, timeout_ms, flags);
67 }
68
69 int wdt_stop(struct udevice *dev)
70 {
71         const struct wdt_ops *ops = device_get_ops(dev);
72
73         if (!ops->stop)
74                 return -ENOSYS;
75
76         return ops->stop(dev);
77 }
78
79 int wdt_reset(struct udevice *dev)
80 {
81         const struct wdt_ops *ops = device_get_ops(dev);
82
83         if (!ops->reset)
84                 return -ENOSYS;
85
86         return ops->reset(dev);
87 }
88
89 int wdt_expire_now(struct udevice *dev, ulong flags)
90 {
91         int ret = 0;
92         const struct wdt_ops *ops;
93
94         debug("WDT Resetting: %lu\n", flags);
95         ops = device_get_ops(dev);
96         if (ops->expire_now) {
97                 return ops->expire_now(dev, flags);
98         } else {
99                 if (!ops->start)
100                         return -ENOSYS;
101
102                 ret = ops->start(dev, 1, flags);
103                 if (ret < 0)
104                         return ret;
105
106                 hang();
107         }
108
109         return ret;
110 }
111
112 #if defined(CONFIG_WATCHDOG)
113 /*
114  * Called by macro WATCHDOG_RESET. This function be called *very* early,
115  * so we need to make sure, that the watchdog driver is ready before using
116  * it in this function.
117  */
118 void watchdog_reset(void)
119 {
120         static ulong next_reset;
121         ulong now;
122
123         /* Exit if GD is not ready or watchdog is not initialized yet */
124         if (!gd || !(gd->flags & GD_FLG_WDT_READY))
125                 return;
126
127         /* Do not reset the watchdog too often */
128         now = get_timer(0);
129         if (time_after(now, next_reset)) {
130                 next_reset = now + reset_period;
131                 wdt_reset(gd->watchdog_dev);
132         }
133 }
134 #endif
135
136 static int wdt_post_bind(struct udevice *dev)
137 {
138 #if defined(CONFIG_NEEDS_MANUAL_RELOC)
139         struct wdt_ops *ops = (struct wdt_ops *)device_get_ops(dev);
140         static int reloc_done;
141
142         if (!reloc_done) {
143                 if (ops->start)
144                         ops->start += gd->reloc_off;
145                 if (ops->stop)
146                         ops->stop += gd->reloc_off;
147                 if (ops->reset)
148                         ops->reset += gd->reloc_off;
149                 if (ops->expire_now)
150                         ops->expire_now += gd->reloc_off;
151
152                 reloc_done++;
153         }
154 #endif
155         return 0;
156 }
157
158 UCLASS_DRIVER(wdt) = {
159         .id             = UCLASS_WDT,
160         .name           = "watchdog",
161         .flags          = DM_UC_FLAG_SEQ_ALIAS,
162         .post_bind      = wdt_post_bind,
163 };