• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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