xref: /optee_os/core/drivers/stm32_iwdg.c (revision c879bd896c23a61fd25ea5e3c7c1dedc2075926b)
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/wdt.h>
10 #include <io.h>
11 #include <keep.h>
12 #include <kernel/boot.h>
13 #include <kernel/delay.h>
14 #include <kernel/dt.h>
15 #include <kernel/dt_driver.h>
16 #include <kernel/interrupt.h>
17 #include <kernel/misc.h>
18 #include <kernel/panic.h>
19 #include <kernel/pm.h>
20 #include <kernel/spinlock.h>
21 #include <kernel/tee_time.h>
22 #include <libfdt.h>
23 #include <mm/core_memprot.h>
24 #include <sm/sm.h>
25 #include <stm32_util.h>
26 #include <string.h>
27 #include <trace.h>
28 
29 /* IWDG Compatibility */
30 #define IWDG_TIMEOUT_US		U(10000)
31 #define IWDG_CNT_MASK		GENMASK_32(11, 0)
32 #define IWDG_ONF_MIN_VER	U(0x31)
33 
34 /* IWDG registers offsets */
35 #define IWDG_KR_OFFSET		U(0x00)
36 #define IWDG_PR_OFFSET		U(0x04)
37 #define IWDG_RLR_OFFSET		U(0x08)
38 #define IWDG_SR_OFFSET		U(0x0C)
39 #define IWDG_EWCR_OFFSET	U(0x14)
40 #define IWDG_VERR_OFFSET	U(0x3F4)
41 
42 #define IWDG_KR_WPROT_KEY	U(0x0000)
43 #define IWDG_KR_ACCESS_KEY	U(0x5555)
44 #define IWDG_KR_RELOAD_KEY	U(0xAAAA)
45 #define IWDG_KR_START_KEY	U(0xCCCC)
46 
47 /* Use a fixed prescaler divider of 256 */
48 #define IWDG_PRESCALER_256	U(256)
49 #define IWDG_PR_DIV_256		U(0x06)
50 #define IWDG_PR_DIV_MASK	GENMASK_32(3, 0)
51 
52 #define IWDG_SR_PVU		BIT(0)
53 #define IWDG_SR_RVU		BIT(1)
54 #define IWDG_SR_WVU		BIT(2)
55 #define IWDG_SR_EWU		BIT(3)
56 #define IWDG_SR_UPDATE_MASK	(IWDG_SR_PVU | IWDG_SR_RVU | IWDG_SR_WVU | \
57 				 IWDG_SR_EWU)
58 #define IWDG_SR_ONF		BIT(8)
59 
60 #define IWDG_EWCR_EWIE		BIT(15)
61 #define IWDG_EWCR_EWIC		BIT(14)
62 
63 #define IWDG_VERR_REV_MASK	GENMASK_32(7, 0)
64 
65 /*
66  * Values for struct stm32_iwdg_device::flags
67  * IWDG_FLAGS_ENABLED			Watchdog has been enabled
68  */
69 #define IWDG_FLAGS_ENABLED			BIT(0)
70 
71 /*
72  * IWDG watch instance data
73  * @base - IWDG interface IOMEM base address
74  * @clk_pclk - Bus clock
75  * @clk_lsi - IWDG source clock
76  * @flags - Property flags for the IWDG instance
77  * @timeout - Watchdog elaspure timeout
78  * @hw_version - Watchdog HW version
79  * @last_refresh - Time of last watchdog refresh
80  * @wdt_chip - Wathcdog chip instance
81  */
82 struct stm32_iwdg_device {
83 	struct io_pa_va base;
84 	struct clk *clk_pclk;
85 	struct clk *clk_lsi;
86 	uint32_t flags;
87 	unsigned long timeout;
88 	unsigned int hw_version;
89 	TEE_Time last_refresh;
90 	struct wdt_chip wdt_chip;
91 };
92 
93 static vaddr_t get_base(struct stm32_iwdg_device *iwdg)
94 {
95 	return io_pa_or_va(&iwdg->base, 1);
96 }
97 
98 static void iwdg_wdt_set_enabled(struct stm32_iwdg_device *iwdg)
99 {
100 	iwdg->flags |= IWDG_FLAGS_ENABLED;
101 }
102 
103 static bool iwdg_wdt_is_enabled(struct stm32_iwdg_device *iwdg)
104 {
105 	return iwdg->flags & IWDG_FLAGS_ENABLED;
106 }
107 
108 /* Return counter value to related to input timeout in seconds, or 0 on error */
109 static uint32_t iwdg_timeout_cnt(struct stm32_iwdg_device *iwdg,
110 				 unsigned long to_sec)
111 {
112 	uint64_t reload = (uint64_t)to_sec * clk_get_rate(iwdg->clk_lsi);
113 	uint64_t cnt = (reload / IWDG_PRESCALER_256) - 1;
114 
115 	/* Be safe and expect any counter to be above 2 */
116 	if (cnt > IWDG_CNT_MASK || cnt < 3)
117 		return 0;
118 
119 	return cnt;
120 }
121 
122 /* Wait IWDG programming completes */
123 static TEE_Result iwdg_wait_sync(struct stm32_iwdg_device *iwdg)
124 {
125 	uint64_t timeout_ref = timeout_init_us(IWDG_TIMEOUT_US);
126 	vaddr_t iwdg_base = get_base(iwdg);
127 
128 	while (io_read32(iwdg_base + IWDG_SR_OFFSET) & IWDG_SR_UPDATE_MASK)
129 		if (timeout_elapsed(timeout_ref))
130 			break;
131 
132 	if (io_read32(iwdg_base + IWDG_SR_OFFSET) & IWDG_SR_UPDATE_MASK)
133 		return TEE_ERROR_GENERIC;
134 
135 	return TEE_SUCCESS;
136 }
137 
138 static TEE_Result configure_timeout(struct stm32_iwdg_device *iwdg)
139 {
140 	TEE_Result res = TEE_ERROR_GENERIC;
141 	vaddr_t iwdg_base = get_base(iwdg);
142 	uint32_t rlr_value = 0;
143 
144 	assert(iwdg_wdt_is_enabled(iwdg));
145 
146 	rlr_value = iwdg_timeout_cnt(iwdg, iwdg->timeout);
147 	if (!rlr_value)
148 		return TEE_ERROR_GENERIC;
149 
150 	io_write32(iwdg_base + IWDG_KR_OFFSET, IWDG_KR_ACCESS_KEY);
151 	io_write32(iwdg_base + IWDG_PR_OFFSET, IWDG_PR_DIV_256);
152 	io_write32(iwdg_base + IWDG_RLR_OFFSET, rlr_value);
153 	io_write32(iwdg_base + IWDG_KR_OFFSET, IWDG_KR_RELOAD_KEY);
154 
155 	res = iwdg_wait_sync(iwdg);
156 
157 	return res;
158 }
159 
160 static void iwdg_start(struct stm32_iwdg_device *iwdg)
161 {
162 	TEE_Result res = TEE_ERROR_GENERIC;
163 
164 	res = tee_time_get_sys_time(&iwdg->last_refresh);
165 	if (res)
166 		panic();
167 
168 	io_write32(get_base(iwdg) + IWDG_KR_OFFSET, IWDG_KR_START_KEY);
169 
170 	iwdg_wdt_set_enabled(iwdg);
171 }
172 
173 static void iwdg_refresh(struct stm32_iwdg_device *iwdg)
174 {
175 	TEE_Result res = TEE_ERROR_GENERIC;
176 
177 	res = tee_time_get_sys_time(&iwdg->last_refresh);
178 	if (res)
179 		panic();
180 
181 	io_write32(get_base(iwdg) + IWDG_KR_OFFSET, IWDG_KR_RELOAD_KEY);
182 }
183 
184 /* Operators for watchdog OP-TEE interface */
185 static struct stm32_iwdg_device *wdt_chip_to_iwdg(struct wdt_chip *chip)
186 {
187 	return container_of(chip, struct stm32_iwdg_device, wdt_chip);
188 }
189 
190 static TEE_Result iwdg_wdt_init(struct wdt_chip *chip,
191 				unsigned long *min_timeout,
192 				unsigned long *max_timeout)
193 {
194 	struct stm32_iwdg_device *iwdg = wdt_chip_to_iwdg(chip);
195 	unsigned long rate = clk_get_rate(iwdg->clk_lsi);
196 
197 	if (!rate)
198 		return TEE_ERROR_GENERIC;
199 
200 	/* Be safe and expect any counter to be above 2 */
201 	*min_timeout = 3 * IWDG_PRESCALER_256 / rate;
202 	*max_timeout = (IWDG_CNT_MASK + 1) * IWDG_PRESCALER_256 / rate;
203 
204 	return TEE_SUCCESS;
205 }
206 
207 static void iwdg_wdt_start(struct wdt_chip *chip)
208 {
209 	struct stm32_iwdg_device *iwdg = wdt_chip_to_iwdg(chip);
210 
211 	iwdg_start(iwdg);
212 
213 	if (configure_timeout(iwdg))
214 		panic();
215 }
216 
217 static void iwdg_wdt_refresh(struct wdt_chip *chip)
218 {
219 	struct stm32_iwdg_device *iwdg = wdt_chip_to_iwdg(chip);
220 
221 	iwdg_refresh(iwdg);
222 }
223 
224 static TEE_Result iwdg_wdt_set_timeout(struct wdt_chip *chip,
225 				       unsigned long timeout)
226 {
227 	struct stm32_iwdg_device *iwdg = wdt_chip_to_iwdg(chip);
228 
229 	if (!iwdg_timeout_cnt(iwdg, timeout))
230 		return TEE_ERROR_BAD_PARAMETERS;
231 
232 	iwdg->timeout = timeout;
233 
234 	if (iwdg_wdt_is_enabled(iwdg)) {
235 		TEE_Result res = TEE_ERROR_GENERIC;
236 
237 		res = configure_timeout(iwdg);
238 		if (res)
239 			return res;
240 	}
241 
242 	return TEE_SUCCESS;
243 }
244 
245 static TEE_Result iwdg_wdt_get_timeleft(struct wdt_chip *chip, bool *is_started,
246 					unsigned long *timeleft)
247 {
248 	struct stm32_iwdg_device *iwdg = wdt_chip_to_iwdg(chip);
249 	TEE_Result res = TEE_ERROR_GENERIC;
250 	TEE_Time time = { };
251 	TEE_Time now = { };
252 
253 	*is_started = iwdg_wdt_is_enabled(iwdg);
254 
255 	if (!*is_started)
256 		return TEE_SUCCESS;
257 
258 	res = tee_time_get_sys_time(&now);
259 	if (res)
260 		panic();
261 
262 	time.seconds = iwdg->timeout;
263 	TEE_TIME_ADD(iwdg->last_refresh, time, time);
264 	if (TEE_TIME_LE(time, now)) {
265 		*timeleft = 0;
266 	} else {
267 		TEE_TIME_SUB(time, now, time);
268 		*timeleft = time.seconds;
269 	}
270 
271 	return TEE_SUCCESS;
272 }
273 
274 static const struct wdt_ops stm32_iwdg_ops = {
275 	.init = iwdg_wdt_init,
276 	.start = iwdg_wdt_start,
277 	.ping = iwdg_wdt_refresh,
278 	.set_timeout = iwdg_wdt_set_timeout,
279 	.get_timeleft = iwdg_wdt_get_timeleft,
280 };
281 DECLARE_KEEP_PAGER(stm32_iwdg_ops);
282 
283 /* Driver initialization */
284 static TEE_Result stm32_iwdg_parse_fdt(struct stm32_iwdg_device *iwdg,
285 				       const void *fdt, int node)
286 {
287 	TEE_Result res = TEE_ERROR_GENERIC;
288 	struct dt_node_info dt_info = { };
289 	const fdt32_t *cuint = NULL;
290 
291 	fdt_fill_device_info(fdt, &dt_info, node);
292 
293 	if (dt_info.reg == DT_INFO_INVALID_REG ||
294 	    dt_info.reg_size == DT_INFO_INVALID_REG_SIZE)
295 		panic();
296 
297 	res = clk_dt_get_by_name(fdt, node, "pclk", &iwdg->clk_pclk);
298 	if (res)
299 		return res;
300 
301 	res = clk_dt_get_by_name(fdt, node, "lsi", &iwdg->clk_lsi);
302 	if (res)
303 		return res;
304 
305 	/* Get IOMEM address */
306 	iwdg->base.pa = dt_info.reg;
307 	io_pa_or_va_secure(&iwdg->base, dt_info.reg_size);
308 	assert(iwdg->base.va);
309 
310 	/* Get and check timeout value */
311 	cuint = fdt_getprop(fdt, node, "timeout-sec", NULL);
312 	if (!cuint)
313 		return TEE_ERROR_BAD_PARAMETERS;
314 
315 	iwdg->timeout = (int)fdt32_to_cpu(*cuint);
316 	if (!iwdg->timeout)
317 		return TEE_ERROR_BAD_PARAMETERS;
318 
319 	if (!iwdg_timeout_cnt(iwdg, iwdg->timeout)) {
320 		EMSG("Timeout %lu not applicable", iwdg->timeout);
321 		return TEE_ERROR_BAD_PARAMETERS;
322 	}
323 
324 	return TEE_SUCCESS;
325 }
326 
327 static void iwdg_wdt_get_version_and_status(struct stm32_iwdg_device *iwdg)
328 {
329 	vaddr_t iwdg_base = get_base(iwdg);
330 	uint32_t rlr_value = 0;
331 
332 	iwdg->hw_version = io_read32(iwdg_base + IWDG_VERR_OFFSET) &
333 			   IWDG_VERR_REV_MASK;
334 
335 	/* Test if watchdog is already running */
336 	if (iwdg->hw_version >= IWDG_ONF_MIN_VER) {
337 		if (io_read32(iwdg_base + IWDG_SR_OFFSET) & IWDG_SR_ONF)
338 			iwdg_wdt_set_enabled(iwdg);
339 	} else {
340 		/*
341 		 * Workaround for old versions without IWDG_SR_ONF bit:
342 		 * - write in IWDG_RLR_OFFSET
343 		 * - wait for sync
344 		 * - if sync succeeds, then iwdg is running
345 		 */
346 		io_write32(iwdg_base + IWDG_KR_OFFSET, IWDG_KR_ACCESS_KEY);
347 
348 		rlr_value = io_read32(iwdg_base + IWDG_RLR_OFFSET);
349 		io_write32(iwdg_base + IWDG_RLR_OFFSET, rlr_value);
350 
351 		if (!iwdg_wait_sync(iwdg))
352 			iwdg_wdt_set_enabled(iwdg);
353 
354 		io_write32(iwdg_base + IWDG_KR_OFFSET, IWDG_KR_WPROT_KEY);
355 	}
356 
357 	DMSG("Watchdog is %sabled", iwdg_wdt_is_enabled(iwdg) ? "en" : "dis");
358 }
359 
360 static TEE_Result stm32_iwdg_setup(struct stm32_iwdg_device *iwdg,
361 				   const void *fdt, int node)
362 {
363 	TEE_Result res = TEE_SUCCESS;
364 
365 	res = stm32_iwdg_parse_fdt(iwdg, fdt, node);
366 	if (res)
367 		return res;
368 
369 	/* Enable watchdog source and bus clocks once for all */
370 	if (clk_enable(iwdg->clk_lsi))
371 		panic();
372 
373 	if (clk_enable(iwdg->clk_pclk))
374 		panic();
375 
376 	iwdg_wdt_get_version_and_status(iwdg);
377 
378 	if (iwdg_wdt_is_enabled(iwdg)) {
379 		/* Configure timeout if watchdog is already enabled */
380 		res = configure_timeout(iwdg);
381 		if (res)
382 			panic();
383 
384 		iwdg_refresh(iwdg);
385 	}
386 
387 	return TEE_SUCCESS;
388 }
389 
390 static TEE_Result stm32_iwdg_probe(const void *fdt, int node,
391 				   const void *compat_data __unused)
392 {
393 	struct stm32_iwdg_device *iwdg = NULL;
394 	TEE_Result res = TEE_SUCCESS;
395 
396 	iwdg = calloc(1, sizeof(*iwdg));
397 	if (!iwdg)
398 		return TEE_ERROR_OUT_OF_MEMORY;
399 
400 	res = stm32_iwdg_setup(iwdg, fdt, node);
401 	if (res)
402 		goto out;
403 
404 	iwdg->wdt_chip.ops = &stm32_iwdg_ops;
405 
406 	res = watchdog_register(&iwdg->wdt_chip);
407 
408 out:
409 	if (res)
410 		free(iwdg);
411 
412 	return res;
413 }
414 
415 static const struct dt_device_match stm32_iwdg_match_table[] = {
416 	{ .compatible = "st,stm32mp1-iwdg" },
417 	{ }
418 };
419 
420 DEFINE_DT_DRIVER(stm32_iwdg_dt_driver) = {
421 	.name = "stm32-iwdg",
422 	.match_table = stm32_iwdg_match_table,
423 	.probe = stm32_iwdg_probe,
424 };
425