xref: /optee_os/core/drivers/stm32_iwdg.c (revision dff60fe87e9d146f468712f2b9e44fb0b378433f)
1 // SPDX-License-Identifier: BSD-3-Clause
2 /*
3  * Copyright (c) 2017-2025, STMicroelectronics - All Rights Reserved
4  */
5 
6 #include <assert.h>
7 #include <drivers/clk.h>
8 #include <drivers/clk_dt.h>
9 #include <drivers/rstctrl.h>
10 #include <drivers/wdt.h>
11 #include <io.h>
12 #include <keep.h>
13 #include <kernel/boot.h>
14 #include <kernel/delay.h>
15 #include <kernel/dt.h>
16 #include <kernel/dt_driver.h>
17 #include <kernel/interrupt.h>
18 #include <kernel/misc.h>
19 #include <kernel/panic.h>
20 #include <kernel/pm.h>
21 #include <kernel/spinlock.h>
22 #include <kernel/tee_time.h>
23 #include <libfdt.h>
24 #include <mm/core_memprot.h>
25 #include <sm/sm.h>
26 #include <stm32_util.h>
27 #include <string.h>
28 #include <trace.h>
29 
30 /* IWDG Compatibility */
31 #define IWDG_TIMEOUT_US		U(10000)
32 #define IWDG_CNT_MASK		GENMASK_32(11, 0)
33 #define IWDG_ONF_MIN_VER	U(0x31)
34 #define IWDG_ICR_MIN_VER	U(0x40)
35 
36 /* IWDG registers offsets */
37 #define IWDG_KR_OFFSET		U(0x00)
38 #define IWDG_PR_OFFSET		U(0x04)
39 #define IWDG_RLR_OFFSET		U(0x08)
40 #define IWDG_SR_OFFSET		U(0x0C)
41 #define IWDG_EWCR_OFFSET	U(0x14)
42 #define IWDG_ICR_OFFSET		U(0x18)
43 #define IWDG_VERR_OFFSET	U(0x3F4)
44 
45 #define IWDG_KR_WPROT_KEY	U(0x0000)
46 #define IWDG_KR_ACCESS_KEY	U(0x5555)
47 #define IWDG_KR_RELOAD_KEY	U(0xAAAA)
48 #define IWDG_KR_START_KEY	U(0xCCCC)
49 
50 /* Use a fixed prescaler divider of 256 */
51 #define IWDG_PRESCALER_256	U(256)
52 #define IWDG_PR_DIV_256		U(0x06)
53 #define IWDG_PR_DIV_MASK	GENMASK_32(3, 0)
54 
55 #define IWDG_SR_PVU		BIT(0)
56 #define IWDG_SR_RVU		BIT(1)
57 #define IWDG_SR_WVU		BIT(2)
58 #define IWDG_SR_EWU		BIT(3)
59 #define IWDG_SR_UPDATE_MASK	(IWDG_SR_PVU | IWDG_SR_RVU | IWDG_SR_WVU | \
60 				 IWDG_SR_EWU)
61 #define IWDG_SR_ONF		BIT(8)
62 #define IWDG_SR_EWIF		BIT(14)
63 #define IWDG_SR_EWIF_V40	BIT(15)
64 
65 #define IWDG_EWCR_EWIE		BIT(15)
66 #define IWDG_EWCR_EWIC		BIT(14)
67 
68 #define IWDG_ICR_EWIC		BIT(15)
69 
70 #define IWDG_VERR_REV_MASK	GENMASK_32(7, 0)
71 
72 /* Define default early timeout delay to 5 sec before timeout */
73 #define IWDG_ETIMEOUT_SEC	U(5)
74 
75 /*
76  * Values for struct stm32_iwdg_device::flags
77  * IWDG_FLAGS_ENABLED			Watchdog has been enabled
78  */
79 #define IWDG_FLAGS_ENABLED			BIT(0)
80 
81 /*
82  * IWDG watch instance data
83  * @base - IWDG interface IOMEM base address
84  * @clk_pclk - Bus clock
85  * @clk_lsi - IWDG source clock
86  * @itr_chip - Interrupt chip device
87  * @itr_num - Interrupt number for the IWDG instance
88  * @itr_handler - Interrupt handler
89  * @reset - Reset controller device used to control the ability of the watchdog
90  *          to reset the system
91  * @flags - Property flags for the IWDG instance
92  * @timeout - Watchdog elaspure timeout
93  * @hw_version - Watchdog HW version
94  * @last_refresh - Time of last watchdog refresh
95  * @wdt_chip - Wathcdog chip instance
96  */
97 struct stm32_iwdg_device {
98 	struct io_pa_va base;
99 	struct clk *clk_pclk;
100 	struct clk *clk_lsi;
101 	struct itr_chip *itr_chip;
102 	size_t itr_num;
103 	struct itr_handler *itr_handler;
104 	struct rstctrl *reset;
105 	uint32_t flags;
106 	unsigned long timeout;
107 	unsigned int hw_version;
108 	TEE_Time last_refresh;
109 	struct wdt_chip wdt_chip;
110 };
111 
112 static uint32_t sr_ewif_mask(struct stm32_iwdg_device *iwdg)
113 {
114 	if (iwdg->hw_version >= IWDG_ICR_MIN_VER)
115 		return IWDG_SR_EWIF_V40;
116 	else
117 		return IWDG_SR_EWIF;
118 }
119 
120 static vaddr_t get_base(struct stm32_iwdg_device *iwdg)
121 {
122 	return io_pa_or_va(&iwdg->base, 1);
123 }
124 
125 static void iwdg_wdt_set_enabled(struct stm32_iwdg_device *iwdg)
126 {
127 	iwdg->flags |= IWDG_FLAGS_ENABLED;
128 }
129 
130 static bool iwdg_wdt_is_enabled(struct stm32_iwdg_device *iwdg)
131 {
132 	return iwdg->flags & IWDG_FLAGS_ENABLED;
133 }
134 
135 /* Return counter value to related to input timeout in seconds, or 0 on error */
136 static uint32_t iwdg_timeout_cnt(struct stm32_iwdg_device *iwdg,
137 				 unsigned long to_sec)
138 {
139 	uint64_t reload = (uint64_t)to_sec * clk_get_rate(iwdg->clk_lsi);
140 	uint64_t cnt = (reload / IWDG_PRESCALER_256) - 1;
141 
142 	/* Be safe and expect any counter to be above 2 */
143 	if (cnt > IWDG_CNT_MASK || cnt < 3)
144 		return 0;
145 
146 	return cnt;
147 }
148 
149 /* Wait IWDG programming completes */
150 static TEE_Result iwdg_wait_sync(struct stm32_iwdg_device *iwdg)
151 {
152 	uint64_t timeout_ref = timeout_init_us(IWDG_TIMEOUT_US);
153 	vaddr_t iwdg_base = get_base(iwdg);
154 
155 	while (io_read32(iwdg_base + IWDG_SR_OFFSET) & IWDG_SR_UPDATE_MASK)
156 		if (timeout_elapsed(timeout_ref))
157 			break;
158 
159 	if (io_read32(iwdg_base + IWDG_SR_OFFSET) & IWDG_SR_UPDATE_MASK)
160 		return TEE_ERROR_GENERIC;
161 
162 	return TEE_SUCCESS;
163 }
164 
165 static void stm32_iwdg_it_ack(struct stm32_iwdg_device *iwdg)
166 {
167 	vaddr_t iwdg_base = get_base(iwdg);
168 
169 	if (iwdg->hw_version >= IWDG_ICR_MIN_VER)
170 		io_setbits32(iwdg_base + IWDG_ICR_OFFSET, IWDG_ICR_EWIC);
171 	else
172 		io_setbits32(iwdg_base + IWDG_EWCR_OFFSET, IWDG_EWCR_EWIC);
173 }
174 
175 static enum itr_return stm32_iwdg_it_handler(struct itr_handler *h)
176 {
177 	unsigned int __maybe_unused cpu = get_core_pos();
178 	struct stm32_iwdg_device *iwdg = h->data;
179 	vaddr_t iwdg_base = get_base(iwdg);
180 
181 	DMSG("CPU %u IT Watchdog %#"PRIxPA, cpu, iwdg->base.pa);
182 
183 	/* Check for spurious interrupt */
184 	if (!(io_read32(iwdg_base + IWDG_SR_OFFSET) & sr_ewif_mask(iwdg)))
185 		return ITRR_NONE;
186 
187 	/*
188 	 * Writing IWDG_EWCR_EWIT triggers a watchdog refresh.
189 	 * To prevent the watchdog refresh, write-protect all the registers;
190 	 * this makes read-only all IWDG_EWCR fields except IWDG_EWCR_EWIC.
191 	 */
192 	io_write32(iwdg_base + IWDG_KR_OFFSET, IWDG_KR_WPROT_KEY);
193 
194 	/* Disable early interrupt */
195 	stm32_iwdg_it_ack(iwdg);
196 
197 	panic("Watchdog");
198 
199 	return ITRR_HANDLED;
200 }
201 DECLARE_KEEP_PAGER(stm32_iwdg_it_handler);
202 
203 static TEE_Result configure_timeout(struct stm32_iwdg_device *iwdg)
204 {
205 	TEE_Result res = TEE_ERROR_GENERIC;
206 	vaddr_t iwdg_base = get_base(iwdg);
207 	uint32_t rlr_value = 0;
208 	uint32_t ewie_value = 0;
209 	uint32_t early_timeout = 0;
210 
211 	assert(iwdg_wdt_is_enabled(iwdg));
212 
213 	rlr_value = iwdg_timeout_cnt(iwdg, iwdg->timeout);
214 	if (!rlr_value)
215 		return TEE_ERROR_GENERIC;
216 
217 	if (iwdg->itr_handler) {
218 		if (iwdg->timeout >= 2 * IWDG_ETIMEOUT_SEC)
219 			early_timeout = IWDG_ETIMEOUT_SEC;
220 		else
221 			early_timeout = iwdg->timeout / 4;
222 		ewie_value = iwdg_timeout_cnt(iwdg, early_timeout);
223 		interrupt_enable(iwdg->itr_chip, iwdg->itr_num);
224 	}
225 
226 	io_write32(iwdg_base + IWDG_KR_OFFSET, IWDG_KR_ACCESS_KEY);
227 	io_write32(iwdg_base + IWDG_PR_OFFSET, IWDG_PR_DIV_256);
228 	io_write32(iwdg_base + IWDG_RLR_OFFSET, rlr_value);
229 	if (ewie_value &&
230 	    !(io_read32(iwdg_base + IWDG_EWCR_OFFSET) & IWDG_EWCR_EWIE))
231 		io_write32(iwdg_base + IWDG_EWCR_OFFSET,
232 			   ewie_value | IWDG_EWCR_EWIE);
233 
234 	res = iwdg_wait_sync(iwdg);
235 
236 	io_write32(iwdg_base + IWDG_KR_OFFSET, IWDG_KR_RELOAD_KEY);
237 
238 	return res;
239 }
240 
241 static void iwdg_start(struct stm32_iwdg_device *iwdg)
242 {
243 	TEE_Result res = TEE_ERROR_GENERIC;
244 
245 	res = tee_time_get_sys_time(&iwdg->last_refresh);
246 	if (res)
247 		panic();
248 
249 	io_write32(get_base(iwdg) + IWDG_KR_OFFSET, IWDG_KR_START_KEY);
250 
251 	iwdg_wdt_set_enabled(iwdg);
252 }
253 
254 static void iwdg_refresh(struct stm32_iwdg_device *iwdg)
255 {
256 	TEE_Result res = TEE_ERROR_GENERIC;
257 
258 	res = tee_time_get_sys_time(&iwdg->last_refresh);
259 	if (res)
260 		panic();
261 
262 	io_write32(get_base(iwdg) + IWDG_KR_OFFSET, IWDG_KR_RELOAD_KEY);
263 }
264 
265 /* Operators for watchdog OP-TEE interface */
266 static struct stm32_iwdg_device *wdt_chip_to_iwdg(struct wdt_chip *chip)
267 {
268 	return container_of(chip, struct stm32_iwdg_device, wdt_chip);
269 }
270 
271 static TEE_Result iwdg_wdt_init(struct wdt_chip *chip,
272 				unsigned long *min_timeout,
273 				unsigned long *max_timeout)
274 {
275 	struct stm32_iwdg_device *iwdg = wdt_chip_to_iwdg(chip);
276 	unsigned long rate = clk_get_rate(iwdg->clk_lsi);
277 
278 	if (!rate)
279 		return TEE_ERROR_GENERIC;
280 
281 	/* Be safe and expect any counter to be above 2 */
282 	*min_timeout = 3 * IWDG_PRESCALER_256 / rate;
283 	*max_timeout = (IWDG_CNT_MASK + 1) * IWDG_PRESCALER_256 / rate;
284 
285 	return TEE_SUCCESS;
286 }
287 
288 static void iwdg_wdt_start(struct wdt_chip *chip)
289 {
290 	struct stm32_iwdg_device *iwdg = wdt_chip_to_iwdg(chip);
291 
292 	iwdg_start(iwdg);
293 	if (iwdg->reset && iwdg->itr_handler)
294 		stm32_iwdg_it_ack(iwdg);
295 
296 	if (configure_timeout(iwdg))
297 		panic();
298 
299 	if (iwdg->reset)
300 		if (rstctrl_assert(iwdg->reset))
301 			panic();
302 }
303 
304 static void iwdg_wdt_stop(struct wdt_chip *chip)
305 {
306 	struct stm32_iwdg_device *iwdg = wdt_chip_to_iwdg(chip);
307 
308 	if (iwdg->reset) {
309 		if (rstctrl_deassert(iwdg->reset))
310 			panic();
311 		if (iwdg->itr_handler)
312 			interrupt_disable(iwdg->itr_chip, iwdg->itr_num);
313 	}
314 }
315 
316 static void iwdg_wdt_refresh(struct wdt_chip *chip)
317 {
318 	struct stm32_iwdg_device *iwdg = wdt_chip_to_iwdg(chip);
319 
320 	iwdg_refresh(iwdg);
321 }
322 
323 static TEE_Result iwdg_wdt_set_timeout(struct wdt_chip *chip,
324 				       unsigned long timeout)
325 {
326 	struct stm32_iwdg_device *iwdg = wdt_chip_to_iwdg(chip);
327 
328 	if (!iwdg_timeout_cnt(iwdg, timeout))
329 		return TEE_ERROR_BAD_PARAMETERS;
330 
331 	iwdg->timeout = timeout;
332 
333 	if (iwdg_wdt_is_enabled(iwdg)) {
334 		TEE_Result res = TEE_ERROR_GENERIC;
335 
336 		res = configure_timeout(iwdg);
337 		if (res)
338 			return res;
339 	}
340 
341 	return TEE_SUCCESS;
342 }
343 
344 static TEE_Result iwdg_wdt_get_timeleft(struct wdt_chip *chip, bool *is_started,
345 					unsigned long *timeleft)
346 {
347 	struct stm32_iwdg_device *iwdg = wdt_chip_to_iwdg(chip);
348 	TEE_Result res = TEE_ERROR_GENERIC;
349 	TEE_Time time = { };
350 	TEE_Time now = { };
351 
352 	*is_started = iwdg_wdt_is_enabled(iwdg);
353 
354 	if (!*is_started)
355 		return TEE_SUCCESS;
356 
357 	res = tee_time_get_sys_time(&now);
358 	if (res)
359 		panic();
360 
361 	time.seconds = iwdg->timeout;
362 	TEE_TIME_ADD(iwdg->last_refresh, time, time);
363 	if (TEE_TIME_LE(time, now)) {
364 		*timeleft = 0;
365 	} else {
366 		TEE_TIME_SUB(time, now, time);
367 		*timeleft = time.seconds;
368 	}
369 
370 	return TEE_SUCCESS;
371 }
372 
373 static const struct wdt_ops stm32_iwdg_ops = {
374 	.init = iwdg_wdt_init,
375 	.start = iwdg_wdt_start,
376 	.stop = iwdg_wdt_stop,
377 	.ping = iwdg_wdt_refresh,
378 	.set_timeout = iwdg_wdt_set_timeout,
379 	.get_timeleft = iwdg_wdt_get_timeleft,
380 };
381 DECLARE_KEEP_PAGER(stm32_iwdg_ops);
382 
383 /* Driver initialization */
384 static TEE_Result stm32_iwdg_parse_fdt(struct stm32_iwdg_device *iwdg,
385 				       const void *fdt, int node)
386 {
387 	TEE_Result res = TEE_ERROR_GENERIC;
388 	struct dt_node_info dt_info = { };
389 	const fdt32_t *cuint = NULL;
390 
391 	fdt_fill_device_info(fdt, &dt_info, node);
392 
393 	if (dt_info.reg == DT_INFO_INVALID_REG ||
394 	    dt_info.reg_size == DT_INFO_INVALID_REG_SIZE)
395 		panic();
396 
397 	res = clk_dt_get_by_name(fdt, node, "pclk", &iwdg->clk_pclk);
398 	if (res)
399 		return res;
400 
401 	res = clk_dt_get_by_name(fdt, node, "lsi", &iwdg->clk_lsi);
402 	if (res)
403 		return res;
404 
405 	res = interrupt_dt_get(fdt, node, &iwdg->itr_chip, &iwdg->itr_num);
406 	if (res && res != TEE_ERROR_ITEM_NOT_FOUND)
407 		return res;
408 	if (!res) {
409 		res = interrupt_create_handler(iwdg->itr_chip, iwdg->itr_num,
410 					       stm32_iwdg_it_handler, iwdg, 0,
411 					       &iwdg->itr_handler);
412 		if (res)
413 			return res;
414 	}
415 
416 	res = rstctrl_dt_get_by_index(fdt, node, 0, &iwdg->reset);
417 	if (res && res != TEE_ERROR_ITEM_NOT_FOUND)
418 		goto err_itr;
419 
420 	/* Get IOMEM address */
421 	iwdg->base.pa = dt_info.reg;
422 	io_pa_or_va_secure(&iwdg->base, dt_info.reg_size);
423 	assert(iwdg->base.va);
424 
425 	/* Get and check timeout value */
426 	cuint = fdt_getprop(fdt, node, "timeout-sec", NULL);
427 	if (!cuint) {
428 		res = TEE_ERROR_BAD_PARAMETERS;
429 		goto err_itr;
430 	}
431 
432 	iwdg->timeout = (int)fdt32_to_cpu(*cuint);
433 	if (!iwdg->timeout) {
434 		res = TEE_ERROR_BAD_PARAMETERS;
435 		goto err_itr;
436 	}
437 
438 	if (!iwdg_timeout_cnt(iwdg, iwdg->timeout)) {
439 		EMSG("Timeout %lu not applicable", iwdg->timeout);
440 		res = TEE_ERROR_BAD_PARAMETERS;
441 		goto err_itr;
442 	}
443 
444 	return TEE_SUCCESS;
445 
446 err_itr:
447 	interrupt_remove_free_handler(iwdg->itr_handler);
448 
449 	return res;
450 }
451 
452 static void iwdg_wdt_get_version_and_status(struct stm32_iwdg_device *iwdg)
453 {
454 	vaddr_t iwdg_base = get_base(iwdg);
455 	uint32_t rlr_value = 0;
456 
457 	iwdg->hw_version = io_read32(iwdg_base + IWDG_VERR_OFFSET) &
458 			   IWDG_VERR_REV_MASK;
459 
460 	/* Test if watchdog is already running */
461 	if (iwdg->hw_version >= IWDG_ONF_MIN_VER) {
462 		if (io_read32(iwdg_base + IWDG_SR_OFFSET) & IWDG_SR_ONF)
463 			iwdg_wdt_set_enabled(iwdg);
464 	} else {
465 		/*
466 		 * Workaround for old versions without IWDG_SR_ONF bit:
467 		 * - write in IWDG_RLR_OFFSET
468 		 * - wait for sync
469 		 * - if sync succeeds, then iwdg is running
470 		 */
471 		io_write32(iwdg_base + IWDG_KR_OFFSET, IWDG_KR_ACCESS_KEY);
472 
473 		rlr_value = io_read32(iwdg_base + IWDG_RLR_OFFSET);
474 		io_write32(iwdg_base + IWDG_RLR_OFFSET, rlr_value);
475 
476 		if (!iwdg_wait_sync(iwdg))
477 			iwdg_wdt_set_enabled(iwdg);
478 
479 		io_write32(iwdg_base + IWDG_KR_OFFSET, IWDG_KR_WPROT_KEY);
480 	}
481 
482 	DMSG("Watchdog is %sabled", iwdg_wdt_is_enabled(iwdg) ? "en" : "dis");
483 }
484 
485 static TEE_Result stm32_iwdg_setup(struct stm32_iwdg_device *iwdg,
486 				   const void *fdt, int node)
487 {
488 	TEE_Result res = TEE_SUCCESS;
489 
490 	res = stm32_iwdg_parse_fdt(iwdg, fdt, node);
491 	if (res)
492 		return res;
493 
494 	/* Enable watchdog source and bus clocks once for all */
495 	if (clk_enable(iwdg->clk_lsi))
496 		panic();
497 
498 	if (clk_enable(iwdg->clk_pclk))
499 		panic();
500 
501 	iwdg_wdt_get_version_and_status(iwdg);
502 
503 	if (iwdg_wdt_is_enabled(iwdg)) {
504 		/* Configure timeout if watchdog is already enabled */
505 		res = configure_timeout(iwdg);
506 		if (res)
507 			panic();
508 
509 		iwdg_refresh(iwdg);
510 	}
511 
512 	return TEE_SUCCESS;
513 }
514 
515 static TEE_Result stm32_iwdg_pm(enum pm_op op, unsigned int pm_hint __unused,
516 				const struct pm_callback_handle *pm_handle)
517 {
518 	struct stm32_iwdg_device *iwdg = PM_CALLBACK_GET_HANDLE(pm_handle);
519 
520 	if (op == PM_OP_RESUME) {
521 		clk_enable(iwdg->clk_lsi);
522 		clk_enable(iwdg->clk_pclk);
523 	} else {
524 		clk_disable(iwdg->clk_lsi);
525 		clk_disable(iwdg->clk_pclk);
526 	}
527 
528 	return TEE_SUCCESS;
529 }
530 DECLARE_KEEP_PAGER(stm32_iwdg_pm);
531 
532 static TEE_Result stm32_iwdg_probe(const void *fdt, int node,
533 				   const void *compat_data __unused)
534 {
535 	struct stm32_iwdg_device *iwdg = NULL;
536 	TEE_Result res = TEE_SUCCESS;
537 
538 	iwdg = calloc(1, sizeof(*iwdg));
539 	if (!iwdg)
540 		return TEE_ERROR_OUT_OF_MEMORY;
541 
542 	res = stm32_iwdg_setup(iwdg, fdt, node);
543 	if (res)
544 		goto out_free;
545 
546 	iwdg->wdt_chip.ops = &stm32_iwdg_ops;
547 
548 	register_pm_core_service_cb(stm32_iwdg_pm, iwdg, "stm32-iwdg");
549 
550 	res = watchdog_register(&iwdg->wdt_chip);
551 	if (res)
552 		goto out_pm;
553 
554 	return TEE_SUCCESS;
555 
556 out_pm:
557 	unregister_pm_core_service_cb(stm32_iwdg_pm, iwdg);
558 out_free:
559 	free(iwdg);
560 
561 	return res;
562 }
563 
564 static const struct dt_device_match stm32_iwdg_match_table[] = {
565 	{ .compatible = "st,stm32mp1-iwdg" },
566 	{ }
567 };
568 
569 DEFINE_DT_DRIVER(stm32_iwdg_dt_driver) = {
570 	.name = "stm32-iwdg",
571 	.match_table = stm32_iwdg_match_table,
572 	.probe = stm32_iwdg_probe,
573 };
574