xref: /optee_os/core/drivers/stm32_iwdg.c (revision 3d5793d28a2e734d2f7a5f2926e175b88af20c69)
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/stm32_iwdg.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 <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_HW_ENABLED                Watchdog is enabled by BootROM
68  * IWDG_FLAGS_DISABLE_ON_STOP           Watchdog is freezed in SoC STOP mode
69  * IWDG_FLAGS_DISABLE_ON_STANDBY        Watchdog is freezed in SoC STANDBY mode
70  * IWDG_FLAGS_ENABLED			Watchdog has been enabled
71  */
72 #define IWDG_FLAGS_HW_ENABLED			BIT(0)
73 #define IWDG_FLAGS_DISABLE_ON_STOP		BIT(1)
74 #define IWDG_FLAGS_DISABLE_ON_STANDBY		BIT(2)
75 #define IWDG_FLAGS_ENABLED			BIT(3)
76 
77 /*
78  * IWDG watch instance data
79  * @base - IWDG interface IOMEM base address
80  * @clk_pclk - Bus clock
81  * @clk_lsi - IWDG source clock
82  * @flags - Property flags for the IWDG instance
83  * @timeout - Watchdog elaspure timeout
84  * @hw_version - Watchdog HW version
85  * @wdt_chip - Wathcdog chip instance
86  */
87 struct stm32_iwdg_device {
88 	struct io_pa_va base;
89 	struct clk *clk_pclk;
90 	struct clk *clk_lsi;
91 	uint32_t flags;
92 	unsigned long timeout;
93 	unsigned int hw_version;
94 	struct wdt_chip wdt_chip;
95 };
96 
97 static vaddr_t get_base(struct stm32_iwdg_device *iwdg)
98 {
99 	return io_pa_or_va(&iwdg->base, 1);
100 }
101 
102 static void iwdg_wdt_set_enabled(struct stm32_iwdg_device *iwdg)
103 {
104 	iwdg->flags |= IWDG_FLAGS_ENABLED;
105 }
106 
107 static bool iwdg_wdt_is_enabled(struct stm32_iwdg_device *iwdg)
108 {
109 	return iwdg->flags & IWDG_FLAGS_ENABLED;
110 }
111 
112 /* Return counter value to related to input timeout in seconds, or 0 on error */
113 static uint32_t iwdg_timeout_cnt(struct stm32_iwdg_device *iwdg,
114 				 unsigned long to_sec)
115 {
116 	uint64_t reload = (uint64_t)to_sec * clk_get_rate(iwdg->clk_lsi);
117 	uint64_t cnt = (reload / IWDG_PRESCALER_256) - 1;
118 
119 	/* Be safe and expect any counter to be above 2 */
120 	if (cnt > IWDG_CNT_MASK || cnt < 3)
121 		return 0;
122 
123 	return cnt;
124 }
125 
126 /* Wait IWDG programming completes */
127 static TEE_Result iwdg_wait_sync(struct stm32_iwdg_device *iwdg)
128 {
129 	uint64_t timeout_ref = timeout_init_us(IWDG_TIMEOUT_US);
130 	vaddr_t iwdg_base = get_base(iwdg);
131 
132 	while (io_read32(iwdg_base + IWDG_SR_OFFSET) & IWDG_SR_UPDATE_MASK)
133 		if (timeout_elapsed(timeout_ref))
134 			break;
135 
136 	if (io_read32(iwdg_base + IWDG_SR_OFFSET) & IWDG_SR_UPDATE_MASK)
137 		return TEE_ERROR_GENERIC;
138 
139 	return TEE_SUCCESS;
140 }
141 
142 static TEE_Result configure_timeout(struct stm32_iwdg_device *iwdg)
143 {
144 	TEE_Result res = TEE_ERROR_GENERIC;
145 	vaddr_t iwdg_base = get_base(iwdg);
146 	uint32_t rlr_value = 0;
147 
148 	assert(iwdg_wdt_is_enabled(iwdg));
149 
150 	rlr_value = iwdg_timeout_cnt(iwdg, iwdg->timeout);
151 	if (!rlr_value)
152 		return TEE_ERROR_GENERIC;
153 
154 	io_write32(iwdg_base + IWDG_KR_OFFSET, IWDG_KR_ACCESS_KEY);
155 	io_write32(iwdg_base + IWDG_PR_OFFSET, IWDG_PR_DIV_256);
156 	io_write32(iwdg_base + IWDG_RLR_OFFSET, rlr_value);
157 	io_write32(iwdg_base + IWDG_KR_OFFSET, IWDG_KR_RELOAD_KEY);
158 
159 	res = iwdg_wait_sync(iwdg);
160 
161 	return res;
162 }
163 
164 static void iwdg_start(struct stm32_iwdg_device *iwdg)
165 {
166 	io_write32(get_base(iwdg) + IWDG_KR_OFFSET, IWDG_KR_START_KEY);
167 
168 	iwdg_wdt_set_enabled(iwdg);
169 }
170 
171 static void iwdg_refresh(struct stm32_iwdg_device *iwdg)
172 {
173 	io_write32(get_base(iwdg) + IWDG_KR_OFFSET, IWDG_KR_RELOAD_KEY);
174 }
175 
176 /* Operators for watchdog OP-TEE interface */
177 static struct stm32_iwdg_device *wdt_chip_to_iwdg(struct wdt_chip *chip)
178 {
179 	return container_of(chip, struct stm32_iwdg_device, wdt_chip);
180 }
181 
182 static TEE_Result iwdg_wdt_init(struct wdt_chip *chip,
183 				unsigned long *min_timeout,
184 				unsigned long *max_timeout)
185 {
186 	struct stm32_iwdg_device *iwdg = wdt_chip_to_iwdg(chip);
187 	unsigned long rate = clk_get_rate(iwdg->clk_lsi);
188 
189 	if (!rate)
190 		return TEE_ERROR_GENERIC;
191 
192 	/* Be safe and expect any counter to be above 2 */
193 	*min_timeout = 3 * IWDG_PRESCALER_256 / rate;
194 	*max_timeout = (IWDG_CNT_MASK + 1) * IWDG_PRESCALER_256 / rate;
195 
196 	return TEE_SUCCESS;
197 }
198 
199 static void iwdg_wdt_start(struct wdt_chip *chip)
200 {
201 	struct stm32_iwdg_device *iwdg = wdt_chip_to_iwdg(chip);
202 
203 	iwdg_start(iwdg);
204 
205 	if (configure_timeout(iwdg))
206 		panic();
207 }
208 
209 static void iwdg_wdt_refresh(struct wdt_chip *chip)
210 {
211 	struct stm32_iwdg_device *iwdg = wdt_chip_to_iwdg(chip);
212 
213 	iwdg_refresh(iwdg);
214 }
215 
216 static TEE_Result iwdg_wdt_set_timeout(struct wdt_chip *chip,
217 				       unsigned long timeout)
218 {
219 	struct stm32_iwdg_device *iwdg = wdt_chip_to_iwdg(chip);
220 
221 	if (!iwdg_timeout_cnt(iwdg, timeout))
222 		return TEE_ERROR_BAD_PARAMETERS;
223 
224 	iwdg->timeout = timeout;
225 
226 	if (iwdg_wdt_is_enabled(iwdg)) {
227 		TEE_Result res = TEE_ERROR_GENERIC;
228 
229 		res = configure_timeout(iwdg);
230 		if (res)
231 			return res;
232 	}
233 
234 	return TEE_SUCCESS;
235 }
236 
237 static const struct wdt_ops stm32_iwdg_ops = {
238 	.init = iwdg_wdt_init,
239 	.start = iwdg_wdt_start,
240 	.ping = iwdg_wdt_refresh,
241 	.set_timeout = iwdg_wdt_set_timeout,
242 };
243 DECLARE_KEEP_PAGER(stm32_iwdg_ops);
244 
245 /* Driver initialization */
246 static TEE_Result stm32_iwdg_parse_fdt(struct stm32_iwdg_device *iwdg,
247 				       const void *fdt, int node)
248 {
249 	TEE_Result res = TEE_ERROR_GENERIC;
250 	struct dt_node_info dt_info = { };
251 	const fdt32_t *cuint = NULL;
252 
253 	fdt_fill_device_info(fdt, &dt_info, node);
254 
255 	if (dt_info.reg == DT_INFO_INVALID_REG ||
256 	    dt_info.reg_size == DT_INFO_INVALID_REG_SIZE)
257 		panic();
258 
259 	res = clk_dt_get_by_name(fdt, node, "pclk", &iwdg->clk_pclk);
260 	if (res)
261 		return res;
262 
263 	res = clk_dt_get_by_name(fdt, node, "lsi", &iwdg->clk_lsi);
264 	if (res)
265 		return res;
266 
267 	/* Get IOMEM address */
268 	iwdg->base.pa = dt_info.reg;
269 	io_pa_or_va_secure(&iwdg->base, dt_info.reg_size);
270 	assert(iwdg->base.va);
271 
272 	/* Get and check timeout value */
273 	cuint = fdt_getprop(fdt, node, "timeout-sec", NULL);
274 	if (!cuint)
275 		return TEE_ERROR_BAD_PARAMETERS;
276 
277 	iwdg->timeout = (int)fdt32_to_cpu(*cuint);
278 	if (!iwdg->timeout)
279 		return TEE_ERROR_BAD_PARAMETERS;
280 
281 	if (!iwdg_timeout_cnt(iwdg, iwdg->timeout)) {
282 		EMSG("Timeout %lu not applicable", iwdg->timeout);
283 		return TEE_ERROR_BAD_PARAMETERS;
284 	}
285 
286 	/* DT can specify low power cases */
287 	if (!fdt_getprop(fdt, node, "stm32,enable-on-stop", NULL))
288 		iwdg->flags |= IWDG_FLAGS_DISABLE_ON_STOP;
289 
290 	if (!fdt_getprop(fdt, node, "stm32,enable-on-standby", NULL))
291 		iwdg->flags |= IWDG_FLAGS_DISABLE_ON_STANDBY;
292 
293 	return TEE_SUCCESS;
294 }
295 
296 /* Platform should override this function to provide IWDG fuses configuration */
297 TEE_Result __weak stm32_get_iwdg_otp_config(paddr_t pbase __unused,
298 					    struct stm32_iwdg_otp_data *otp_d)
299 {
300 	otp_d->hw_enabled = false;
301 	otp_d->disable_on_stop = false;
302 	otp_d->disable_on_standby = false;
303 
304 	return TEE_SUCCESS;
305 }
306 
307 static void iwdg_wdt_get_version_and_status(struct stm32_iwdg_device *iwdg)
308 {
309 	vaddr_t iwdg_base = get_base(iwdg);
310 	uint32_t rlr_value = 0;
311 
312 	iwdg->hw_version = io_read32(iwdg_base + IWDG_VERR_OFFSET) &
313 			   IWDG_VERR_REV_MASK;
314 
315 	/* Test if watchdog is already running */
316 	if (iwdg->hw_version >= IWDG_ONF_MIN_VER) {
317 		if (io_read32(iwdg_base + IWDG_SR_OFFSET) & IWDG_SR_ONF)
318 			iwdg_wdt_set_enabled(iwdg);
319 	} else {
320 		/*
321 		 * Workaround for old versions without IWDG_SR_ONF bit:
322 		 * - write in IWDG_RLR_OFFSET
323 		 * - wait for sync
324 		 * - if sync succeeds, then iwdg is running
325 		 */
326 		io_write32(iwdg_base + IWDG_KR_OFFSET, IWDG_KR_ACCESS_KEY);
327 
328 		rlr_value = io_read32(iwdg_base + IWDG_RLR_OFFSET);
329 		io_write32(iwdg_base + IWDG_RLR_OFFSET, rlr_value);
330 
331 		if (!iwdg_wait_sync(iwdg))
332 			iwdg_wdt_set_enabled(iwdg);
333 
334 		io_write32(iwdg_base + IWDG_KR_OFFSET, IWDG_KR_WPROT_KEY);
335 	}
336 
337 	DMSG("Watchdog is %sabled", iwdg_wdt_is_enabled(iwdg) ? "en" : "dis");
338 }
339 
340 static TEE_Result stm32_iwdg_setup(struct stm32_iwdg_device *iwdg,
341 				   const void *fdt, int node)
342 {
343 	struct stm32_iwdg_otp_data otp_data = { };
344 	TEE_Result res = TEE_SUCCESS;
345 
346 	res = stm32_iwdg_parse_fdt(iwdg, fdt, node);
347 	if (res)
348 		return res;
349 
350 	res = stm32_get_iwdg_otp_config(iwdg->base.pa, &otp_data);
351 	if (res)
352 		return res;
353 
354 	if (otp_data.hw_enabled)
355 		iwdg->flags |= IWDG_FLAGS_HW_ENABLED;
356 	if (otp_data.disable_on_stop)
357 		iwdg->flags |= IWDG_FLAGS_DISABLE_ON_STOP;
358 	if (otp_data.disable_on_standby)
359 		iwdg->flags |= IWDG_FLAGS_DISABLE_ON_STANDBY;
360 
361 	/* Enable watchdog source and bus clocks once for all */
362 	clk_enable(iwdg->clk_lsi);
363 	clk_enable(iwdg->clk_pclk);
364 
365 	iwdg_wdt_get_version_and_status(iwdg);
366 
367 	if (otp_data.hw_enabled)
368 		iwdg_wdt_set_enabled(iwdg);
369 
370 	if (iwdg_wdt_is_enabled(iwdg)) {
371 		/* Configure timeout if watchdog is already enabled */
372 		res = configure_timeout(iwdg);
373 		if (res)
374 			return res;
375 
376 		iwdg_refresh(iwdg);
377 	}
378 
379 	return TEE_SUCCESS;
380 }
381 
382 static TEE_Result stm32_iwdg_probe(const void *fdt, int node,
383 				   const void *compat_data __unused)
384 {
385 	struct stm32_iwdg_device *iwdg = NULL;
386 	TEE_Result res = TEE_SUCCESS;
387 
388 	iwdg = calloc(1, sizeof(*iwdg));
389 	if (!iwdg)
390 		return TEE_ERROR_OUT_OF_MEMORY;
391 
392 	res = stm32_iwdg_setup(iwdg, fdt, node);
393 	if (res)
394 		goto out;
395 
396 	iwdg->wdt_chip.ops = &stm32_iwdg_ops;
397 
398 	res = watchdog_register(&iwdg->wdt_chip);
399 
400 out:
401 	if (res)
402 		free(iwdg);
403 
404 	return res;
405 }
406 
407 static const struct dt_device_match stm32_iwdg_match_table[] = {
408 	{ .compatible = "st,stm32mp1-iwdg" },
409 	{ }
410 };
411 
412 DEFINE_DT_DRIVER(stm32_iwdg_dt_driver) = {
413 	.name = "stm32-iwdg",
414 	.match_table = stm32_iwdg_match_table,
415 	.probe = stm32_iwdg_probe,
416 };
417