1 /*
2 * Copyright (c) 2022 Hunan OpenValley Digital Industry Development Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include "hcs_macro.h"
19 #include "hdf_config_macro.h"
20 #include "hdf_device_desc.h"
21 #include "hdf_log.h"
22 #include "watchdog_core.h"
23 #include "watchdog_if.h"
24
25 #define REG32_READ(reg) (*(volatile uint32_t *)(reg))
26 #define REG32_WRITE(reg, value) (*(volatile uint32_t *)(reg) = value)
27
28 #define RWDT_PROTECT_KEY 0x50d83aa1
29 #define RWDT_PROTECT 0x3ff480a4
30 #define RWDT_CFG0 0x3ff4808c
31 #define RWDT_CFG0_VALUE ((1 << 10) | (7 << 11) | (3 << 28) | (1 << 31))
32 #define RWDT_CFG1 0x3ff48090
33 #define RWDT_FEED 0x3ff480a0
34 #define RWDT_TICK_BASE 0x3ff48070
35 #define RWDT_TICK ((REG32_READ(RWDT_TICK_BASE) >> 30) & 3)
36 #define RWDT_WOG() REG32_WRITE(RWDT_FEED, (1 << 31))
37 #define RWDT_IS_RUN() (REG32_READ(RWDT_CFG0) & (1 << 31))
38
39 #define SLOW_CK_TICK (150 * 1000)
40 #define XTAL_32K_TICK (32768)
41 #define CK8M_D256_OUT_TICK (8 * 1000 * 1000 / 256)
42
43 typedef struct {
44 int watchdogId;
45 int timeout; // Maximum interval between watchdog feeding, unit: ms
46 } WatchdogDeviceInfo;
47
48 static int g_watchdogStart = 0;
49 static int g_watchdogTimeout = 0;
50
51 static int32_t WatchdogDevStart(struct WatchdogCntlr *watchdogCntlr);
52 static int32_t WatchdogDevStop(struct WatchdogCntlr *watchdogCntlr);
53 static int32_t WatchdogDevSetTimeout(struct WatchdogCntlr *watchdogCntlr, uint32_t seconds);
54 static int32_t WatchdogDevGetTimeout(struct WatchdogCntlr *watchdogCntlr, uint32_t *seconds);
55 static int32_t WatchdogDevGetStatus(struct WatchdogCntlr *watchdogCntlr, uint32_t *status);
56 static int32_t WatchdogDevFeed(struct WatchdogCntlr *watchdogCntlr);
57
58 struct WatchdogMethod g_WatchdogCntlrMethod = {
59 .getStatus = WatchdogDevGetStatus,
60 .setTimeout = WatchdogDevSetTimeout,
61 .getTimeout = WatchdogDevGetTimeout,
62 .start = WatchdogDevStart,
63 .stop = WatchdogDevStop,
64 .feed = WatchdogDevFeed,
65 .getPriv = NULL,
66 .releasePriv = NULL,
67 };
68
69 #define WATCHDOG_FIND_CONFIG(node, name, device) \
70 do { \
71 if (strcmp(HCS_PROP(node, match_attr), name) == 0) { \
72 (device)->watchdogId = HCS_PROP(node, id); \
73 (device)->timeout = HCS_PROP(node, timeout); \
74 result = HDF_SUCCESS; \
75 } \
76 } while (0)
77
78 #define PLATFORM_CONFIG HCS_NODE(HCS_ROOT, platform)
79 #define PLATFORM_WATCHDOG_CONFIG HCS_NODE(HCS_NODE(HCS_ROOT, platform), watchdog_config)
80
GetWatchdogDeviceInfoResource(WatchdogDeviceInfo * device,const char * deviceMatchAttr)81 static uint32_t GetWatchdogDeviceInfoResource(WatchdogDeviceInfo *device, const char *deviceMatchAttr)
82 {
83 int32_t result = HDF_FAILURE;
84 if (device == NULL || deviceMatchAttr == NULL) {
85 HDF_LOGE("device or deviceMatchAttr is NULL");
86 return HDF_ERR_INVALID_PARAM;
87 }
88
89 HCS_FOREACH_CHILD_VARGS(PLATFORM_WATCHDOG_CONFIG, WATCHDOG_FIND_CONFIG, deviceMatchAttr, device);
90
91 if (result != HDF_SUCCESS) {
92 HDF_LOGE("resourceNode %s is NULL", deviceMatchAttr);
93 return result;
94 }
95
96 return HDF_SUCCESS;
97 }
98
AttachWatchdogDeviceInfo(struct WatchdogCntlr * watchdogCntlr,struct HdfDeviceObject * device)99 static int32_t AttachWatchdogDeviceInfo(struct WatchdogCntlr *watchdogCntlr, struct HdfDeviceObject *device)
100 {
101 int32_t ret;
102 WatchdogDeviceInfo *watchdogdeviceinfo = NULL;
103
104 if (device == NULL || device->deviceMatchAttr == NULL) {
105 HDF_LOGE("%s: param is NULL", __func__);
106 return HDF_FAILURE;
107 }
108
109 watchdogdeviceinfo = (WatchdogDeviceInfo *)OsalMemAlloc(sizeof(WatchdogDeviceInfo));
110 if (watchdogdeviceinfo == NULL) {
111 HDF_LOGE("%s: OsalMemAlloc WatchdogDeviceInfo error", __func__);
112 return HDF_ERR_MALLOC_FAIL;
113 }
114
115 ret = GetWatchdogDeviceInfoResource(watchdogdeviceinfo, device->deviceMatchAttr);
116 if (ret != HDF_SUCCESS) {
117 (void)OsalMemFree(watchdogdeviceinfo);
118 return HDF_FAILURE;
119 }
120
121 (void)OsalMutexInit(&watchdogCntlr->lock);
122
123 watchdogCntlr->priv = watchdogdeviceinfo;
124 watchdogCntlr->wdtId = watchdogdeviceinfo->watchdogId;
125
126 return HDF_SUCCESS;
127 }
128
129 /* HdfDriverEntry method definitions */
130 static int32_t WatchdogDriverBind(struct HdfDeviceObject *device);
131 static int32_t WatchdogDriverInit(struct HdfDeviceObject *device);
132 static void WatchdogDriverRelease(struct HdfDeviceObject *device);
133
134 /* HdfDriverEntry definitions */
135 struct HdfDriverEntry g_watchdogDriverEntry = {
136 .moduleVersion = 1,
137 .moduleName = "ESP32U4_WATCHDOG_MODULE_HDF",
138 .Bind = WatchdogDriverBind,
139 .Init = WatchdogDriverInit,
140 .Release = WatchdogDriverRelease,
141 };
142
143 // Initialize HdfDriverEntry
144 HDF_INIT(g_watchdogDriverEntry);
145
WatchdogDriverBind(struct HdfDeviceObject * device)146 static int32_t WatchdogDriverBind(struct HdfDeviceObject *device)
147 {
148 struct WatchdogCntlr *watchdogCntlr = NULL;
149 if (device == NULL) {
150 HDF_LOGE("hdfDevice object is null!");
151 return HDF_FAILURE;
152 }
153
154 watchdogCntlr = (struct WatchdogCntlr *)OsalMemAlloc(sizeof(struct WatchdogCntlr));
155 if (watchdogCntlr == NULL) {
156 HDF_LOGE("%s: OsalMemAlloc watchdogCntlr error", __func__);
157 return HDF_ERR_MALLOC_FAIL;
158 }
159
160 device->service = &watchdogCntlr->service;
161 watchdogCntlr->device = device;
162 watchdogCntlr->priv = NULL;
163 return HDF_SUCCESS;
164 }
165
WatchdogDriverInit(struct HdfDeviceObject * device)166 static int32_t WatchdogDriverInit(struct HdfDeviceObject *device)
167 {
168 int32_t ret;
169 struct WatchdogCntlr *watchdogCntlr = NULL;
170
171 if (device == NULL) {
172 HDF_LOGE("%s: device is NULL", __func__);
173 return HDF_ERR_INVALID_OBJECT;
174 }
175
176 watchdogCntlr = WatchdogCntlrFromDevice(device);
177 if (watchdogCntlr == NULL) {
178 HDF_LOGE("%s: watchdogCntlr is NULL", __func__);
179 return HDF_ERR_INVALID_PARAM;
180 }
181
182 ret = AttachWatchdogDeviceInfo(watchdogCntlr, device);
183 if (ret != HDF_SUCCESS) {
184 OsalMemFree(watchdogCntlr);
185 HDF_LOGE("%s:attach error", __func__);
186 return HDF_ERR_INVALID_PARAM;
187 }
188
189 watchdogCntlr->ops = &g_WatchdogCntlrMethod;
190 HDF_LOGI("WatchdogDriverInit success!");
191 return ret;
192 }
193
WatchdogDriverRelease(struct HdfDeviceObject * device)194 static void WatchdogDriverRelease(struct HdfDeviceObject *device)
195 {
196 struct WatchdogCntlr *watchdogCntlr = NULL;
197 WatchdogDeviceInfo *watchdogdeviceinfo = NULL;
198
199 if (device == NULL) {
200 HDF_LOGE("device is null");
201 return;
202 }
203
204 watchdogCntlr = WatchdogCntlrFromDevice(device);
205 if (watchdogCntlr == NULL || watchdogCntlr->priv == NULL) {
206 HDF_LOGE("%s: watchdogCntlr is NULL", __func__);
207 return;
208 }
209
210 watchdogdeviceinfo = (WatchdogDeviceInfo *)watchdogCntlr->priv;
211 if (watchdogdeviceinfo != NULL) {
212 OsalMemFree(watchdogdeviceinfo);
213 }
214 return;
215 }
216
217 #define XTAL_TICK 1
218 #define CK8M_TICK 2
219
WatchdogDevStart(struct WatchdogCntlr * watchdogCntlr)220 static int32_t WatchdogDevStart(struct WatchdogCntlr *watchdogCntlr)
221 {
222 WatchdogDeviceInfo *watchdogdeviceinfo = NULL;
223 int32_t watchdogId = 0;
224 int32_t timeout = 0;
225 int32_t ticks = 0;
226 if (watchdogCntlr == NULL || watchdogCntlr->priv == NULL) {
227 HDF_LOGE("%s: watchdogCntlr is NULL", __func__);
228 return HDF_ERR_INVALID_PARAM;
229 }
230
231 watchdogdeviceinfo = (WatchdogDeviceInfo *)watchdogCntlr->priv;
232 if (watchdogdeviceinfo == NULL) {
233 HDF_LOGE("%s: OBJECT is NULL", __func__);
234 return HDF_ERR_INVALID_OBJECT;
235 }
236
237 watchdogId = watchdogdeviceinfo->watchdogId;
238 timeout = watchdogdeviceinfo->timeout;
239
240 switch (RWDT_TICK) {
241 case XTAL_TICK:
242 ticks = XTAL_32K_TICK;
243 break;
244 case CK8M_TICK:
245 ticks = CK8M_D256_OUT_TICK;
246 break;
247 default:
248 ticks = SLOW_CK_TICK;
249 break;
250 }
251 REG32_WRITE(RWDT_PROTECT, RWDT_PROTECT_KEY);
252 RWDT_WOG();
253 REG32_WRITE(RWDT_CFG0, RWDT_CFG0_VALUE);
254 REG32_WRITE(RWDT_CFG1, (timeout * ticks));
255 REG32_WRITE(RWDT_PROTECT, 0);
256
257 HDF_LOGI("Watchdog Started! timeout: %d second", timeout);
258 g_watchdogStart = 1;
259 return HDF_SUCCESS;
260 }
261
WatchdogDevStop(struct WatchdogCntlr * watchdogCntlr)262 static int32_t WatchdogDevStop(struct WatchdogCntlr *watchdogCntlr)
263 {
264 if (!watchdogCntlr) {
265 return HDF_FAILURE;
266 }
267 if (!RWDT_IS_RUN()) {
268 return HDF_SUCCESS;
269 }
270 REG32_WRITE(RWDT_PROTECT, RWDT_PROTECT_KEY);
271 RWDT_WOG();
272 REG32_WRITE(RWDT_CFG0, 0);
273 REG32_WRITE(RWDT_PROTECT, 0);
274 return HDF_SUCCESS;
275 }
276
WatchdogDevSetTimeout(struct WatchdogCntlr * watchdogCntlr,uint32_t seconds)277 static int32_t WatchdogDevSetTimeout(struct WatchdogCntlr *watchdogCntlr, uint32_t seconds)
278 {
279 WatchdogDeviceInfo *watchdogdeviceinfo = NULL;
280 if (watchdogCntlr == NULL || watchdogCntlr->priv == NULL) {
281 HDF_LOGE("%s: watchdogCntlr is NULL", __func__);
282 return HDF_ERR_INVALID_PARAM;
283 }
284
285 watchdogdeviceinfo = (WatchdogDeviceInfo *)watchdogCntlr->priv;
286 if (watchdogdeviceinfo == NULL) {
287 HDF_LOGE("%s: OBJECT is NULL", __func__);
288 return HDF_ERR_INVALID_OBJECT;
289 }
290
291 watchdogdeviceinfo->timeout = seconds;
292
293 return HDF_SUCCESS;
294 }
295
WatchdogDevGetTimeout(struct WatchdogCntlr * watchdogCntlr,uint32_t * seconds)296 static int32_t WatchdogDevGetTimeout(struct WatchdogCntlr *watchdogCntlr, uint32_t *seconds)
297 {
298 WatchdogDeviceInfo *watchdogdeviceinfo = NULL;
299 if (watchdogCntlr == NULL || seconds == NULL) {
300 HDF_LOGE("%s: PARAM is NULL", __func__);
301 return HDF_ERR_INVALID_PARAM;
302 }
303
304 watchdogdeviceinfo = (WatchdogDeviceInfo *)watchdogCntlr->priv;
305 if (watchdogdeviceinfo == NULL) {
306 HDF_LOGE("%s: OBJECT is NULL", __func__);
307 return HDF_ERR_INVALID_OBJECT;
308 }
309
310 *seconds = watchdogdeviceinfo->timeout;
311 return HDF_SUCCESS;
312 }
313
WatchdogDevGetStatus(struct WatchdogCntlr * watchdogCntlr,uint32_t * status)314 static int32_t WatchdogDevGetStatus(struct WatchdogCntlr *watchdogCntlr, uint32_t *status)
315 {
316 if (watchdogCntlr == NULL || status == NULL) {
317 HDF_LOGE("%s: PARAM is NULL", __func__);
318 return HDF_ERR_INVALID_PARAM;
319 }
320 if (g_watchdogStart == 1) {
321 *status = WATCHDOG_START;
322 } else {
323 *status = WATCHDOG_STOP;
324 }
325 return HDF_SUCCESS;
326 }
327
WatchdogDevFeed(struct WatchdogCntlr * watchdogCntlr)328 static int32_t WatchdogDevFeed(struct WatchdogCntlr *watchdogCntlr)
329 {
330 if (!watchdogCntlr) {
331 return HDF_FAILURE;
332 }
333 REG32_WRITE(RWDT_PROTECT, RWDT_PROTECT_KEY);
334 RWDT_WOG();
335 REG32_WRITE(RWDT_PROTECT, 0);
336 return HDF_SUCCESS;
337 }