1 /*
2 * Copyright (c) 2022 Talkweb Co., Ltd.
3 *
4 * HDF is dual licensed: you can use it either under the terms of
5 * the GPL, or the BSD license, at your option.
6 * See the LICENSE file in the root of this repository for complete details.
7 */
8
9 #include <stdlib.h>
10 #include <stdio.h>
11 #ifdef LOSCFG_DRIVERS_HDF_CONFIG_MACRO
12 #include "hcs_macro.h"
13 #include "hdf_config_macro.h"
14 #else
15 #include "device_resource_if.h"
16 #endif
17 #include "hdf_device_desc.h"
18 #include "hdf_log.h"
19 #include "watchdog_core.h"
20 #include "watchdog_if.h"
21
22 #define WATCHDOG_MIN_TIMEOUT 1
23 #define WATCHDOG_MAX_TIMEOUT 4096
24 #define WATCHDOG_UPDATE_TIME (((6UL * 256UL * 1000UL) / LSI_VALUE) + ((LSI_STARTUP_TIME / 1000UL) + 1UL))
25
26 typedef struct {
27 int watchdogId;
28 int timeout; // Maximum interval between watchdog feeding, unit: ms
29 } WatchdogDeviceInfo;
30
31 static IWDG_TypeDef *hdf_iwdg = NULL;
32 static int g_watchdogStart = 0;
33 static int g_watchdogTimeout = 0;
34
35 static int32_t WatchdogDevStart(struct WatchdogCntlr *watchdogCntlr);
36 static int32_t WatchdogDevStop(struct WatchdogCntlr *watchdogCntlr);
37 static int32_t WatchdogDevSetTimeout(struct WatchdogCntlr *watchdogCntlr, uint32_t seconds);
38 static int32_t WatchdogDevGetTimeout(struct WatchdogCntlr *watchdogCntlr, uint32_t *seconds);
39 static int32_t WatchdogDevGetStatus(struct WatchdogCntlr *watchdogCntlr, uint32_t *status);
40 static int32_t WatchdogDevFeed(struct WatchdogCntlr *watchdogCntlr);
41
42 struct WatchdogMethod g_WatchdogCntlrMethod = {
43 .getStatus = WatchdogDevGetStatus,
44 .setTimeout = WatchdogDevSetTimeout,
45 .getTimeout = WatchdogDevGetTimeout,
46 .start = WatchdogDevStart,
47 .stop = WatchdogDevStop,
48 .feed = WatchdogDevFeed,
49 .getPriv = NULL,
50 .releasePriv = NULL,
51 };
52
InitWatchdogDeviceInfo(const WatchdogDeviceInfo * watchdogdeviceinfo)53 static int InitWatchdogDeviceInfo(const WatchdogDeviceInfo *watchdogdeviceinfo)
54 {
55 if (watchdogdeviceinfo == NULL) {
56 HDF_LOGE("%s: invaild parameter\r\n", __func__);
57 return HDF_ERR_INVALID_PARAM;
58 }
59 return HDF_SUCCESS;
60 }
61
62 #ifdef LOSCFG_DRIVERS_HDF_CONFIG_MACRO
63 #define WATCHDOG_FIND_CONFIG(node, name, device) \
64 do { \
65 if (strcmp(HCS_PROP(node, match_attr), name) == 0) { \
66 device->watchdogId = HCS_PROP(node, id); \
67 device->timeout = HCS_PROP(node, timeout); \
68 result = HDF_SUCCESS; \
69 } \
70 } while (0)
71 #define PLATFORM_CONFIG HCS_NODE(HCS_ROOT, platform)
72 #define PLATFORM_WATCHDOG_CONFIG HCS_NODE(HCS_NODE(HCS_ROOT, platform), watchdog_config)
GetWatchdogDeviceInfoResource(WatchdogDeviceInfo * device,const char * deviceMatchAttr)73 static uint32_t GetWatchdogDeviceInfoResource(WatchdogDeviceInfo *device, const char *deviceMatchAttr)
74 {
75 int32_t result = HDF_FAILURE;
76 if (device == NULL || deviceMatchAttr == NULL) {
77 HDF_LOGE("device or deviceMatchAttr is NULL\r\n");
78 return HDF_ERR_INVALID_PARAM;
79 }
80 #if HCS_NODE_HAS_PROP(PLATFORM_CONFIG, watchdog_config)
81 HCS_FOREACH_CHILD_VARGS(PLATFORM_WATCHDOG_CONFIG, WATCHDOG_FIND_CONFIG, deviceMatchAttr, device);
82 #endif
83 if (result != HDF_SUCCESS) {
84 HDF_LOGE("resourceNode %s is NULL\r\n", deviceMatchAttr);
85 return result;
86 }
87
88 return HDF_SUCCESS;
89 }
90 #else
GetWatchdogDeviceInfoResource(WatchdogDeviceInfo * device,const struct DeviceResourceNode * resourceNode)91 static uint32_t GetWatchdogDeviceInfoResource(WatchdogDeviceInfo *device, const struct DeviceResourceNode *resourceNode)
92 {
93 struct DeviceResourceIface *dri = NULL;
94 if (device == NULL || resourceNode == NULL) {
95 HDF_LOGE("resource or device is NULL\r\n");
96 return HDF_ERR_INVALID_PARAM;
97 }
98
99 dri = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
100 if (dri == NULL || dri->GetUint32 == NULL) {
101 HDF_LOGE("DeviceResourceIface is invalid\r\n");
102 return HDF_ERR_INVALID_OBJECT;
103 }
104
105 if (dri->GetUint32(resourceNode, "id", &device->watchdogId, 0) != HDF_SUCCESS) {
106 HDF_LOGE("read watchdogId fail\r\n");
107 return HDF_FAILURE;
108 }
109 if (dri->GetUint32(resourceNode, "timeout", &device->timeout, 0) != HDF_SUCCESS) {
110 HDF_LOGE("read watchdogId fail\r\n");
111 return HDF_FAILURE;
112 }
113
114 HDF_LOGI("watchdogId = %d\n", device->watchdogId);
115 HDF_LOGI("timeout = %dms\n", device->timeout);
116
117 return HDF_SUCCESS;
118 }
119 #endif
120
AttachWatchdogDeviceInfo(struct WatchdogCntlr * watchdogCntlr,struct HdfDeviceObject * device)121 static int32_t AttachWatchdogDeviceInfo(struct WatchdogCntlr *watchdogCntlr, struct HdfDeviceObject *device)
122 {
123 int32_t ret;
124 WatchdogDeviceInfo *watchdogdeviceinfo = NULL;
125
126 #ifdef LOSCFG_DRIVERS_HDF_CONFIG_MACRO
127 if (device == NULL || device->deviceMatchAttr == NULL) {
128 #else
129 if (device == NULL || device->property == NULL) {
130 #endif
131 HDF_LOGE("%s: param is NULL\r\n", __func__);
132 return HDF_FAILURE;
133 }
134
135 watchdogdeviceinfo = (WatchdogDeviceInfo *)OsalMemAlloc(sizeof(WatchdogDeviceInfo));
136 if (watchdogdeviceinfo == NULL) {
137 HDF_LOGE("%s: OsalMemAlloc WatchdogDeviceInfo error\r\n", __func__);
138 return HDF_ERR_MALLOC_FAIL;
139 }
140
141 #ifdef LOSCFG_DRIVERS_HDF_CONFIG_MACRO
142 ret = GetWatchdogDeviceInfoResource(watchdogdeviceinfo, device->deviceMatchAttr);
143 #else
144 ret = GetWatchdogDeviceInfoResource(watchdogdeviceinfo, device->property);
145 #endif
146 if (ret != HDF_SUCCESS) {
147 (void)OsalMemFree(watchdogdeviceinfo);
148 return HDF_FAILURE;
149 }
150
151 (void)OsalMutexInit(&watchdogCntlr->lock);
152
153 watchdogCntlr->priv = watchdogdeviceinfo;
154 watchdogCntlr->wdtId = watchdogdeviceinfo->watchdogId;
155
156 return InitWatchdogDeviceInfo(watchdogdeviceinfo);
157 }
158 /* HdfDriverEntry method definitions */
159 static int32_t WatchdogDriverBind(struct HdfDeviceObject *device);
160 static int32_t WatchdogDriverInit(struct HdfDeviceObject *device);
161 static void WatchdogDriverRelease(struct HdfDeviceObject *device);
162
163 /* HdfDriverEntry definitions */
164 struct HdfDriverEntry g_watchdogDriverEntry = {
165 .moduleVersion = 1,
166 .moduleName = "ST_WATCHDOG_MODULE_HDF",
167 .Bind = WatchdogDriverBind,
168 .Init = WatchdogDriverInit,
169 .Release = WatchdogDriverRelease,
170 };
171
172 // Initialize HdfDriverEntry
173 HDF_INIT(g_watchdogDriverEntry);
174
175 static int32_t WatchdogDriverBind(struct HdfDeviceObject *device)
176 {
177 struct WatchdogCntlr *watchdogCntlr = NULL;
178
179 if (device == NULL) {
180 HDF_LOGE("hdfDevice object is null!\r\n");
181 return HDF_FAILURE;
182 }
183
184 watchdogCntlr = (struct WatchdogCntlr *)OsalMemAlloc(sizeof(struct WatchdogCntlr));
185 if (watchdogCntlr == NULL) {
186 HDF_LOGE("%s: OsalMemAlloc watchdogCntlr error\r\n", __func__);
187 return HDF_ERR_MALLOC_FAIL;
188 }
189
190 HDF_LOGI("Enter %s\r\n", __func__);
191 device->service = &watchdogCntlr->service;
192 watchdogCntlr->device = device;
193 watchdogCntlr->priv = NULL;
194 return HDF_SUCCESS;
195 }
196
197 static int32_t WatchdogDriverInit(struct HdfDeviceObject *device)
198 {
199 int32_t ret;
200 struct WatchdogCntlr *watchdogCntlr = NULL;
201
202 if (device == NULL) {
203 HDF_LOGE("%s: device is NULL\r\n", __func__);
204 return HDF_ERR_INVALID_OBJECT;
205 }
206
207 HDF_LOGI("Enter %s:\r\n", __func__);
208
209 watchdogCntlr = WatchdogCntlrFromDevice(device);
210 if (watchdogCntlr == NULL) {
211 HDF_LOGE("%s: watchdogCntlr is NULL\r\n", __func__);
212 return HDF_ERR_INVALID_PARAM;
213 }
214
215 ret = AttachWatchdogDeviceInfo(watchdogCntlr, device);
216 if (ret != HDF_SUCCESS) {
217 OsalMemFree(watchdogCntlr);
218 HDF_LOGE("%s:attach error\r\n", __func__);
219 return HDF_ERR_INVALID_PARAM;
220 }
221
222 watchdogCntlr->ops = &g_WatchdogCntlrMethod;
223
224 HDF_LOGI("WatchdogDriverInit success!\r\n");
225 return ret;
226 }
227
228 static void WatchdogDriverRelease(struct HdfDeviceObject *device)
229 {
230 struct WatchdogCntlr *watchdogCntlr = NULL;
231 WatchdogDeviceInfo *watchdogdeviceinfo = NULL;
232
233 if (device == NULL) {
234 HDF_LOGE("device is null\r\n");
235 return;
236 }
237
238 watchdogCntlr = WatchdogCntlrFromDevice(device);
239 if (watchdogCntlr == NULL || watchdogCntlr->priv == NULL) {
240 HDF_LOGE("%s: watchdogCntlr is NULL\r\n", __func__);
241 return;
242 }
243
244 watchdogdeviceinfo = (WatchdogDeviceInfo *)watchdogCntlr->priv;
245 OsalMemFree(watchdogdeviceinfo);
246 return;
247 }
248
249 static int32_t WatchdogDevStart(struct WatchdogCntlr *watchdogCntlr)
250 {
251 WatchdogDeviceInfo *watchdogdeviceinfo = NULL;
252 int32_t watchdogId = 0;
253 int32_t timeout = 0;
254 unsigned long long tickstart = 0;
255
256 if (watchdogCntlr == NULL || watchdogCntlr->priv == NULL) {
257 HDF_LOGE("%s: watchdogCntlr is NULL\r\n", __func__);
258 return HDF_ERR_INVALID_PARAM;
259 }
260
261 watchdogdeviceinfo = (WatchdogDeviceInfo *)watchdogCntlr->priv;
262 watchdogId = watchdogdeviceinfo->watchdogId;
263 timeout = watchdogdeviceinfo->timeout;
264
265 if (timeout < WATCHDOG_MIN_TIMEOUT) {
266 HDF_LOGW("%s: watchdog timeout must >= 1, set the timeout to 1ms\r\n", __func__);
267 timeout = WATCHDOG_MIN_TIMEOUT;
268 }
269 if (timeout > WATCHDOG_MAX_TIMEOUT) {
270 HDF_LOGW("%s: watchdog timeout must <= 1, set the timeout to 4096ms\r\n", __func__);
271 timeout = WATCHDOG_MAX_TIMEOUT;
272 }
273
274 HDF_LOGI("%s: watchdog Started! timeout: %dms\r\n", __func__, timeout);
275
276 hdf_iwdg = IWDG; // Point to watchdog register
277 hdf_iwdg->KR = IWDG_KEY_ENABLE;
278 hdf_iwdg->KR = IWDG_KEY_WRITE_ACCESS_ENABLE;
279 hdf_iwdg->PR = IWDG_PRESCALER_32; // 32 frequency division
280 hdf_iwdg->RLR = timeout - 1; // 32K crystal oscillator corresponds to 1-4096ms under 32 prescaled frequency
281
282 tickstart = (unsigned long long)LOS_TickCountGet();
283 // Wait for the register value to be updated and confirm that the watchdog is started successfully
284 while ((hdf_iwdg->SR & (IWDG_SR_RVU | IWDG_SR_PVU)) != 0x00u) {
285 if ((LOS_TickCountGet() - tickstart) > WATCHDOG_UPDATE_TIME) {
286 if ((hdf_iwdg->SR & (IWDG_SR_RVU | IWDG_SR_PVU)) != 0x00u) {
287 return HDF_FAILURE;
288 }
289 }
290 }
291 hdf_iwdg->KR = IWDG_KEY_RELOAD; // Reload initial value
292
293 g_watchdogStart = 1;
294 return HDF_SUCCESS;
295 }
296
297 static int32_t WatchdogDevStop(struct WatchdogCntlr *watchdogCntlr)
298 {
299 HDF_LOGW("%s: WatchdogDevStop fail,because of soc not support!!\r\n", __func__);
300 return HDF_FAILURE;
301 }
302
303 static int32_t WatchdogDevSetTimeout(struct WatchdogCntlr *watchdogCntlr, uint32_t seconds)
304 {
305 WatchdogDeviceInfo *watchdogdeviceinfo = NULL;
306
307 if (watchdogCntlr == NULL || watchdogCntlr->priv == NULL) {
308 HDF_LOGE("%s: watchdogCntlr is NULL\r\n", __func__);
309 return HDF_ERR_INVALID_PARAM;
310 }
311
312 watchdogdeviceinfo = (WatchdogDeviceInfo *)watchdogCntlr->priv;
313 watchdogdeviceinfo->timeout = seconds;
314 return HDF_SUCCESS;
315 }
316
317 static int32_t WatchdogDevGetTimeout(struct WatchdogCntlr *watchdogCntlr, uint32_t *seconds)
318 {
319 WatchdogDeviceInfo *watchdogdeviceinfo = NULL;
320
321 if (watchdogCntlr == NULL || seconds == NULL) {
322 HDF_LOGE("%s: PARAM is NULL\r\n", __func__);
323 return HDF_ERR_INVALID_PARAM;
324 }
325
326 watchdogdeviceinfo = (WatchdogDeviceInfo *)watchdogCntlr->priv;
327 if (watchdogdeviceinfo == NULL) {
328 HDF_LOGE("%s: OBJECT is NULL\r\n", __func__);
329 return HDF_ERR_INVALID_OBJECT;
330 }
331
332 *seconds = watchdogdeviceinfo->timeout;
333 return HDF_SUCCESS;
334 }
335
336 static int32_t WatchdogDevGetStatus(struct WatchdogCntlr *watchdogCntlr, uint32_t *status)
337 {
338 if (watchdogCntlr == NULL || status == NULL) {
339 HDF_LOGE("%s: PARAM is NULL\r\n", __func__);
340 return HDF_ERR_INVALID_PARAM;
341 }
342 if (g_watchdogStart == 1) {
343 *status = WATCHDOG_START;
344 } else {
345 *status = WATCHDOG_STOP;
346 }
347 return HDF_SUCCESS;
348 }
349
350 static int32_t WatchdogDevFeed(struct WatchdogCntlr *watchdogCntlr)
351 {
352 (void)watchdogCntlr;
353 if (hdf_iwdg != NULL)
354 hdf_iwdg->KR = IWDG_KEY_RELOAD; // Reload initial value
355 return HDF_SUCCESS;
356 }
357
358 static int32_t WatchdogDevGetPriv(struct WatchdogCntlr *watchdogCntlr)
359 {
360 (void)watchdogCntlr;
361 return HDF_SUCCESS;
362 }
363
364 static int32_t WatchdogDevReleasePriv(struct WatchdogCntlr *watchdogCntlr)
365 {
366 (void)watchdogCntlr;
367 return HDF_SUCCESS;
368 }