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