1 /*
2 * Copyright (c) 2021 Nanjing Xiaoxiongpai Intelligent Technology 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 #include "device_resource_if.h"
16 #include "hdf_device_desc.h"
17 #include "osal_io.h"
18 #include "osal.h"
19
20 #include "watchdog_if.h"
21 #include "watchdog_core.h"
22
23 #include "securec.h"
24
25 #define HDF_LOG_TAG Mp1xxIwdg
26
27 #define BITS_PER_LONG 32
28
29 #define GENMASK(h, l) \
30 (((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
31
32 /* IWDG registers */
33 #define IWDG_KR 0x00 /* Key register */
34 #define IWDG_PR 0x04 /* Prescaler Register */
35 #define IWDG_RLR 0x08 /* ReLoad Register */
36 #define IWDG_SR 0x0C /* Status Register */
37 #define IWDG_WINR 0x10 /* Windows Register */
38
39 /* IWDG_KR register bit mask */
40 #define KR_KEY_RELOAD 0xAAAA /* reload counter enable */
41 #define KR_KEY_ENABLE 0xCCCC /* peripheral enable */
42 #define KR_KEY_EWA 0x5555 /* write access enable */
43 #define KR_KEY_DWA 0x0000 /* write access disable */
44
45 /* IWDG_PR register */
46 #define PR_SHIFT 2
47 #define PR_MIN BIT(PR_SHIFT)
48
49 /* IWDG_RLR register values */
50 #define RLR_MIN 0x2 /* min value recommended */
51 #define RLR_MAX GENMASK(11, 0) /* max value of reload register */
52
53 /* IWDG_SR register bit mask */
54 #define SR_PVU BIT(0) /* Watchdog prescaler value update */
55 #define SR_RVU BIT(1) /* Watchdog counter reload value update */
56
57 /* set timeout to 100000 us */
58 #define TIMEOUT_US 100000
59 #define SLEEP_US 1000
60
61 #define DEFAULT_TIMEOUT (32)
62 #define DEFAULT_TASK_STACK_SIZE (0x800)
63 #define DEFAULT_CLOCK_RATE (32000)
64
65 #define DIV_ROUND_UP(n, d) (((n) + (d)-1) / (d))
66
67 /**
68 * fls - find last (most-significant) bit set
69 * @x: the word to search
70 *
71 * This is defined the same way as ffs.
72 * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
73 */
generic_fls(int x)74 static inline int generic_fls(int x)
75 {
76 int r = 32;
77
78 if (!x) {
79 return 0;
80 }
81 if (!(x & 0xffff0000u)) {
82 x <<= 16;
83 r -= 16;
84 }
85 if (!(x & 0xff000000u)) {
86 x <<= 8;
87 r -= 8;
88 }
89 if (!(x & 0xf0000000u)) {
90 x <<= 4;
91 r -= 4;
92 }
93 if (!(x & 0xc0000000u)) {
94 x <<= 2;
95 r -= 2;
96 }
97 if (!(x & 0x80000000u)) {
98 x <<= 1;
99 r -= 1;
100 }
101 return r;
102 }
103
ilog2(unsigned int x)104 static inline int ilog2(unsigned int x)
105 {
106 return generic_fls(x) - 1;
107 }
108
roundup_pow_of_two(unsigned long n)109 unsigned long roundup_pow_of_two(unsigned long n)
110 {
111 return 1UL << generic_fls(n - 1);
112 }
113
114 struct Mp1xxIwdg {
115 struct WatchdogCntlr wdt; // 控制器
116
117 uint32_t num; // 当前独立看门狗编号
118
119 void volatile *base; // 虚拟地址
120 uint32_t phy_base; // 物理地址
121 uint32_t reg_step; // 映射大小
122
123 uint32_t seconds; // 当前设置的超时值(s)
124
125 bool start; // 当前iwdg是否已经启动
126
127 uint32_t rate; // 时钟源频率
128 char *clock_source; // 时钟源名称
129
130 uint32_t min_timeout; // 最小超时时间
131 uint32_t max_hw_heartbeat_ms; // 最大超时时间
132 };
133
reg_read(void volatile * base,uint32_t reg)134 static inline uint32_t reg_read(void volatile *base, uint32_t reg)
135 {
136 return OSAL_READL((uintptr_t)base + reg);
137 }
138
reg_write(void volatile * base,uint32_t reg,uint32_t val)139 static inline void reg_write(void volatile *base, uint32_t reg, uint32_t val)
140 {
141 OSAL_WRITEL(val, (uintptr_t)base + reg);
142 }
143
144 // get clock source real rate
Mp1xxIwdgGetClockRate(struct Mp1xxIwdg * iwdg)145 static inline int32_t Mp1xxIwdgGetClockRate(struct Mp1xxIwdg *iwdg)
146 {
147 int ret = HDF_SUCCESS;
148
149 /*
150 if "clock_source" is set, use the real rate of clock source
151 otherwise, use the default clock rate
152 */
153 if (iwdg->clock_source != NULL) {
154 // get clock source real rate.
155 // ...
156 ret = HDF_SUCCESS;
157 }
158
159 return ret;
160 }
161
Mp1xxIwdgGetSr(struct Mp1xxIwdg * iwdg)162 static inline uint32_t Mp1xxIwdgGetSr(struct Mp1xxIwdg *iwdg)
163 {
164 return reg_read(iwdg->base, IWDG_SR);
165 }
166
Mp1xxIwdgStart(struct WatchdogCntlr * wdt)167 int32_t Mp1xxIwdgStart(struct WatchdogCntlr *wdt)
168 {
169 struct Mp1xxIwdg *iwdg = NULL;
170 uint32_t tout, presc, iwdg_pr, iwdg_rlr, iwdg_sr;
171 uint32_t i = 10;
172
173 if (wdt == NULL) {
174 return HDF_ERR_INVALID_OBJECT;
175 }
176 iwdg = (struct Mp1xxIwdg *)wdt->priv;
177
178 // 计算装载值
179 tout = iwdg->seconds; // 超时秒数
180
181 // 计算边界
182 if (tout > (iwdg->max_hw_heartbeat_ms * 1000)) {
183 tout = iwdg->max_hw_heartbeat_ms * 1000;
184 }
185 if (tout < iwdg->min_timeout) {
186 tout = iwdg->min_timeout;
187 }
188
189 presc = DIV_ROUND_UP(tout * iwdg->rate, RLR_MAX + 1);
190
191 /* The prescaler is align on power of 2 and start at 2 ^ PR_SHIFT. */
192 presc = roundup_pow_of_two(presc);
193 iwdg_pr = (presc <= (1 << PR_SHIFT)) ? 0 : ilog2(presc) - PR_SHIFT;
194 iwdg_rlr = ((tout * iwdg->rate) / presc) - 1;
195
196 /* enable write access */
197 reg_write(iwdg->base, IWDG_KR, KR_KEY_EWA);
198
199 /* set prescaler & reload registers */
200 reg_write(iwdg->base, IWDG_PR, iwdg_pr);
201 reg_write(iwdg->base, IWDG_RLR, iwdg_rlr);
202 reg_write(iwdg->base, IWDG_KR, KR_KEY_ENABLE);
203
204 // 等待状态寄存器 SR_PVU | SR_RVU 复位
205 while ((iwdg_sr = Mp1xxIwdgGetSr(iwdg)) & (SR_PVU | SR_RVU)) {
206 if (!(--i)) {
207 HDF_LOGE("Fail to set prescaler, reload regs.");
208 return HDF_FAILURE;
209 }
210 }
211
212 /* reload watchdog */
213 reg_write(iwdg->base, IWDG_KR, KR_KEY_RELOAD);
214
215 /* iwdg start */
216 iwdg->start = true;
217
218 return HDF_SUCCESS;
219 }
220
Mp1xxIwdgSetTimeout(struct WatchdogCntlr * wdt,uint32_t seconds)221 int32_t Mp1xxIwdgSetTimeout(struct WatchdogCntlr *wdt, uint32_t seconds)
222 {
223 struct Mp1xxIwdg *iwdg = NULL;
224
225 if (wdt == NULL) {
226 return HDF_ERR_INVALID_OBJECT;
227 }
228
229 iwdg = (struct Mp1xxIwdg *)wdt->priv;
230 iwdg->seconds = seconds;
231
232 // 如果iwdg已经是启动状态, 需要重新装载超时值并继续喂狗操作
233 if (iwdg->start) {
234 return Mp1xxIwdgStart(wdt);
235 }
236
237 return HDF_SUCCESS;
238 }
239
Mp1xxIwdgGetTimeout(struct WatchdogCntlr * wdt,uint32_t * seconds)240 int32_t Mp1xxIwdgGetTimeout(struct WatchdogCntlr *wdt, uint32_t *seconds)
241 {
242 struct Mp1xxIwdg *iwdg = NULL;
243 if (wdt == NULL || seconds == NULL) {
244 return HDF_ERR_INVALID_OBJECT;
245 }
246 iwdg = (struct Mp1xxIwdg *)wdt->priv;
247
248 *seconds = iwdg->seconds;
249
250 return HDF_SUCCESS;
251 }
252
Mp1xxIwdgFeed(struct WatchdogCntlr * wdt)253 static int32_t Mp1xxIwdgFeed(struct WatchdogCntlr *wdt)
254 {
255 struct Mp1xxIwdg *iwdg = NULL;
256
257 if (wdt == NULL) {
258 return HDF_ERR_INVALID_OBJECT;
259 }
260 iwdg = (struct Mp1xxIwdg *)wdt->priv;
261
262 /* reload watchdog */
263 reg_write(iwdg->base, IWDG_KR, KR_KEY_RELOAD);
264
265 return HDF_SUCCESS;
266 }
267
Mp1xxIwdgGetStatus(struct WatchdogCntlr * wdt,int32_t * status)268 static int32_t Mp1xxIwdgGetStatus(struct WatchdogCntlr *wdt, int32_t *status)
269 {
270 (void)status;
271 int32_t ret = WATCHDOG_STOP;
272 struct Mp1xxIwdg *iwdg = NULL;
273
274 if (wdt == NULL) {
275 return HDF_ERR_INVALID_OBJECT;
276 }
277 iwdg = (struct Mp1xxIwdg *)wdt->priv;
278
279 if (iwdg->start) {
280 ret = WATCHDOG_START;
281 }
282 return ret;
283 }
284
285 /* WatchdogOpen 的时候被调用 */
Mp1xxIwdgGetPriv(struct WatchdogCntlr * wdt)286 static int32_t Mp1xxIwdgGetPriv(struct WatchdogCntlr *wdt)
287 {
288 int32_t ret;
289 struct Mp1xxIwdg *iwdg = NULL;
290
291 if (wdt == NULL) {
292 return HDF_ERR_INVALID_OBJECT;
293 }
294 iwdg = (struct Mp1xxIwdg *)wdt->priv;
295
296 // 获取当前时钟源频率
297 ret = Mp1xxIwdgGetClockRate(iwdg);
298 if (ret != HDF_SUCCESS) {
299 HDF_LOGE("Mp1xxIwdgGetClockRate fail, ret : %#x.", ret);
300 return HDF_FAILURE;
301 }
302
303 // 计算最大最小的超时时间
304 iwdg->min_timeout = DIV_ROUND_UP((RLR_MIN + 1) * PR_MIN, iwdg->rate);
305 iwdg->max_hw_heartbeat_ms = ((RLR_MAX + 1) * 1024 * 1000) / iwdg->rate;
306
307 return ret;
308 }
309
310 /* WatchdogClose 的时候被调用 */
Mp1xxIwdgReleasePriv(struct WatchdogCntlr * wdt)311 static void Mp1xxIwdgReleasePriv(struct WatchdogCntlr *wdt)
312 {
313 (void)wdt;
314 }
315
316 static struct WatchdogMethod g_stm32mp1_iwdg_ops = {
317 .feed = Mp1xxIwdgFeed,
318 .getPriv = Mp1xxIwdgGetPriv,
319 .getStatus = Mp1xxIwdgGetStatus,
320 .getTimeout = Mp1xxIwdgGetTimeout,
321 .releasePriv = Mp1xxIwdgReleasePriv,
322 .setTimeout = Mp1xxIwdgSetTimeout,
323 .start = Mp1xxIwdgStart,
324
325 // stm32mp1的iwdg不支持软件停止
326 .stop = NULL
327 };
328
Mp1xxIwdgReadDrs(struct Mp1xxIwdg * iwdg,const struct DeviceResourceNode * node)329 static int32_t Mp1xxIwdgReadDrs(struct Mp1xxIwdg *iwdg, const struct DeviceResourceNode *node)
330 {
331 int32_t ret;
332 struct DeviceResourceIface *drsOps = NULL;
333
334 drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
335 if (drsOps == NULL || drsOps->GetUint32 == NULL) {
336 HDF_LOGE("%s: invalid drs ops!", __func__);
337 return HDF_FAILURE;
338 }
339
340 // num
341 ret = drsOps->GetUint32(node, "num", &iwdg->num, 0);
342 if (ret != HDF_SUCCESS) {
343 HDF_LOGE("%s: read num fail!", __func__);
344 return ret;
345 }
346
347 // reg_base
348 ret = drsOps->GetUint32(node, "reg_base", &iwdg->phy_base, 0);
349 if (ret != HDF_SUCCESS) {
350 HDF_LOGE("%s: read regBase fail!", __func__);
351 return ret;
352 }
353
354 // reg_step
355 ret = drsOps->GetUint32(node, "reg_step", &iwdg->reg_step, 0);
356 if (ret != HDF_SUCCESS) {
357 HDF_LOGE("%s: read regStep fail!", __func__);
358 return ret;
359 }
360
361 // default timeout
362 ret = drsOps->GetUint32(node, "timeout_sec", &iwdg->seconds, DEFAULT_TIMEOUT);
363 if (ret != HDF_SUCCESS) {
364 HDF_LOGE("%s: read timeout fail!", __func__);
365 return ret;
366 }
367
368 // default source rate
369 ret = drsOps->GetUint32(node, "clock_rate", &iwdg->rate, DEFAULT_CLOCK_RATE);
370 if (ret != HDF_SUCCESS) {
371 HDF_LOGE("%s: read clock_rate fail!", __func__);
372 return ret;
373 }
374
375 // start
376 iwdg->start = drsOps->GetBool(node, "start");
377
378 return HDF_SUCCESS;
379 }
380
Mp1xxIwdgBind(struct HdfDeviceObject * device)381 static int32_t Mp1xxIwdgBind(struct HdfDeviceObject *device)
382 {
383 int32_t ret;
384 struct Mp1xxIwdg *iwdg = NULL;
385
386 if (device == NULL || device->property == NULL) {
387 HDF_LOGE("%s: device or property is null!", __func__);
388 return HDF_ERR_INVALID_OBJECT;
389 }
390
391 // 申请内存空间
392 iwdg = (struct Mp1xxIwdg *)OsalMemCalloc(sizeof(struct Mp1xxIwdg));
393 if (iwdg == NULL) {
394 HDF_LOGE("%s: malloc iwdg fail!", __func__);
395 return HDF_ERR_MALLOC_FAIL;
396 }
397
398 // 解析配置
399 ret = Mp1xxIwdgReadDrs(iwdg, device->property);
400 if (ret != HDF_SUCCESS) {
401 HDF_LOGE("%s: read drs fail:%d", __func__, ret);
402 OsalMemFree(iwdg);
403 return ret;
404 }
405
406 // 寄存器映射
407 iwdg->base = OsalIoRemap(iwdg->phy_base, iwdg->reg_step);
408 if (iwdg->base == NULL) {
409 HDF_LOGE("%s: ioremap regbase fail!", __func__);
410 OsalMemFree(iwdg);
411 return HDF_ERR_IO;
412 }
413
414 // 填充操作符
415 iwdg->wdt.priv = (void *)iwdg;
416 iwdg->wdt.ops = &g_stm32mp1_iwdg_ops;
417 iwdg->wdt.device = device;
418 iwdg->wdt.wdtId = iwdg->num;
419
420 // add device
421 ret = WatchdogCntlrAdd(&iwdg->wdt);
422 if (ret != HDF_SUCCESS) {
423 HDF_LOGE("%s: err add watchdog:%d.", __func__, ret);
424 OsalIoUnmap((void *)iwdg->base);
425 OsalMemFree(iwdg);
426 return ret;
427 }
428
429 return HDF_SUCCESS;
430 }
431
Mp1xxIwdgInit(struct HdfDeviceObject * device)432 static int32_t Mp1xxIwdgInit(struct HdfDeviceObject *device)
433 {
434 int32_t ret;
435 struct WatchdogCntlr *wdt = NULL;
436 struct Mp1xxIwdg *iwdg = NULL;
437
438 // get WatchdogCntlr
439 wdt = WatchdogCntlrFromDevice(device);
440 if (wdt == NULL) {
441 return HDF_FAILURE;
442 }
443 iwdg = (struct Mp1xxIwdg *)wdt->priv;
444
445 // get priv data(get clock source)
446 ret = Mp1xxIwdgGetPriv(wdt);
447 if (ret != HDF_SUCCESS) {
448 HDF_LOGE("Mp1xxIwdgGetPriv fail.");
449 return HDF_FAILURE;
450 }
451
452 // set default timeout
453 ret = Mp1xxIwdgSetTimeout(wdt, iwdg->seconds);
454 if (ret != HDF_SUCCESS) {
455 HDF_LOGE("Mp1xxIwdgSetTimeout fail.");
456 return HDF_FAILURE;
457 }
458
459 return HDF_SUCCESS;
460 }
461
Mp1xxIwdgRelease(struct HdfDeviceObject * device)462 static void Mp1xxIwdgRelease(struct HdfDeviceObject *device)
463 {
464 struct WatchdogCntlr *wdt = NULL;
465 struct Mp1xxIwdg *iwdg = NULL;
466
467 if (device == NULL) {
468 return;
469 }
470
471 wdt = WatchdogCntlrFromDevice(device);
472 if (wdt == NULL) {
473 return;
474 }
475 WatchdogCntlrRemove(wdt);
476
477 iwdg = (struct Mp1xxIwdg *)wdt->priv;
478 if (iwdg->base != NULL) {
479 OsalIoUnmap((void *)iwdg->base);
480 iwdg->base = NULL;
481 }
482 OsalMemFree(iwdg);
483 }
484
485 struct HdfDriverEntry g_hdf_driver_iwdg_entry = {
486 .moduleVersion = 1,
487 .Bind = Mp1xxIwdgBind,
488 .Init = Mp1xxIwdgInit,
489 .Release = Mp1xxIwdgRelease,
490 .moduleName = "stm32mp1_iwdg",
491 };
492 HDF_INIT(g_hdf_driver_iwdg_entry);
493