xref: /optee_os/core/drivers/stm32_iwdg.c (revision c3deb3d6f3b13d0e17fc9efe5880aec039e47594)
1 // SPDX-License-Identifier: BSD-3-Clause
2 /*
3  * Copyright (c) 2017-2022, 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(1000)
31 #define IWDG_CNT_MASK		GENMASK_32(11, 0)
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 
40 #define IWDG_KR_ACCESS_KEY	U(0x5555)
41 #define IWDG_KR_RELOAD_KEY	U(0xAAAA)
42 #define IWDG_KR_START_KEY	U(0xCCCC)
43 
44 /* Use a fixed prescaler divider of 256 */
45 #define IWDG_PRESCALER_256	U(256)
46 #define IWDG_PR_DIV_256		U(0x06)
47 #define IWDG_PR_DIV_MASK	GENMASK_32(3, 0)
48 
49 #define IWDG_SR_PVU		BIT(0)
50 #define IWDG_SR_RVU		BIT(1)
51 #define IWDG_SR_WVU		BIT(2)
52 #define IWDG_SR_EWU		BIT(3)
53 #define IWDG_SR_UPDATE_MASK	(IWDG_SR_PVU | IWDG_SR_RVU | IWDG_SR_WVU | \
54 				 IWDG_SR_EWU)
55 
56 #define IWDG_EWCR_EWIE		BIT(15)
57 #define IWDG_EWCR_EWIC		BIT(14)
58 
59 /*
60  * Values for struct stm32_iwdg_device::flags
61  * IWDG_FLAGS_HW_ENABLED                Watchdog is enabled by BootROM
62  * IWDG_FLAGS_DISABLE_ON_STOP           Watchdog is freezed in SoC STOP mode
63  * IWDG_FLAGS_DISABLE_ON_STANDBY        Watchdog is freezed in SoC STANDBY mode
64  * IWDG_FLAGS_ENABLED			Watchdog has been enabled
65  */
66 #define IWDG_FLAGS_HW_ENABLED			BIT(0)
67 #define IWDG_FLAGS_DISABLE_ON_STOP		BIT(1)
68 #define IWDG_FLAGS_DISABLE_ON_STANDBY		BIT(2)
69 #define IWDG_FLAGS_ENABLED			BIT(3)
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  * @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 	struct wdt_chip wdt_chip;
87 };
88 
89 static vaddr_t get_base(struct stm32_iwdg_device *iwdg)
90 {
91 	return io_pa_or_va(&iwdg->base, 1);
92 }
93 
94 static void iwdg_wdt_set_enabled(struct stm32_iwdg_device *iwdg)
95 {
96 	iwdg->flags |= IWDG_FLAGS_ENABLED;
97 }
98 
99 static bool iwdg_wdt_is_enabled(struct stm32_iwdg_device *iwdg)
100 {
101 	return iwdg->flags & IWDG_FLAGS_ENABLED;
102 }
103 
104 /* Return counter value to related to input timeout in seconds, or 0 on error */
105 static uint32_t iwdg_timeout_cnt(struct stm32_iwdg_device *iwdg,
106 				 unsigned long to_sec)
107 {
108 	uint64_t reload = (uint64_t)to_sec * clk_get_rate(iwdg->clk_lsi);
109 	uint64_t cnt = (reload / IWDG_PRESCALER_256) - 1;
110 
111 	/* Be safe and expect any counter to be above 2 */
112 	if (cnt > IWDG_CNT_MASK || cnt < 3)
113 		return 0;
114 
115 	return cnt;
116 }
117 
118 /* Wait IWDG programming completes */
119 static TEE_Result iwdg_wait_sync(struct stm32_iwdg_device *iwdg)
120 {
121 	uint64_t timeout_ref = timeout_init_us(IWDG_TIMEOUT_US);
122 	vaddr_t iwdg_base = get_base(iwdg);
123 
124 	while (io_read32(iwdg_base + IWDG_SR_OFFSET) & IWDG_SR_UPDATE_MASK)
125 		if (timeout_elapsed(timeout_ref))
126 			break;
127 
128 	if (io_read32(iwdg_base + IWDG_SR_OFFSET) & IWDG_SR_UPDATE_MASK)
129 		return TEE_ERROR_GENERIC;
130 
131 	return TEE_SUCCESS;
132 }
133 
134 static TEE_Result configure_timeout(struct stm32_iwdg_device *iwdg)
135 {
136 	TEE_Result res = TEE_ERROR_GENERIC;
137 	vaddr_t iwdg_base = get_base(iwdg);
138 	uint32_t rlr_value = 0;
139 
140 	assert(iwdg_wdt_is_enabled(iwdg));
141 
142 	rlr_value = iwdg_timeout_cnt(iwdg, iwdg->timeout);
143 	if (!rlr_value)
144 		return TEE_ERROR_GENERIC;
145 
146 	io_write32(iwdg_base + IWDG_KR_OFFSET, IWDG_KR_ACCESS_KEY);
147 	io_write32(iwdg_base + IWDG_PR_OFFSET, IWDG_PR_DIV_256);
148 	io_write32(iwdg_base + IWDG_RLR_OFFSET, rlr_value);
149 	io_write32(iwdg_base + IWDG_KR_OFFSET, IWDG_KR_RELOAD_KEY);
150 
151 	res = iwdg_wait_sync(iwdg);
152 
153 	return res;
154 }
155 
156 static void iwdg_start(struct stm32_iwdg_device *iwdg)
157 {
158 	io_write32(get_base(iwdg) + IWDG_KR_OFFSET, IWDG_KR_START_KEY);
159 
160 	iwdg_wdt_set_enabled(iwdg);
161 }
162 
163 static void iwdg_refresh(struct stm32_iwdg_device *iwdg)
164 {
165 	io_write32(get_base(iwdg) + IWDG_KR_OFFSET, IWDG_KR_RELOAD_KEY);
166 }
167 
168 /* Operators for watchdog OP-TEE interface */
169 static struct stm32_iwdg_device *wdt_chip_to_iwdg(struct wdt_chip *chip)
170 {
171 	return container_of(chip, struct stm32_iwdg_device, wdt_chip);
172 }
173 
174 static TEE_Result iwdg_wdt_init(struct wdt_chip *chip,
175 				unsigned long *min_timeout,
176 				unsigned long *max_timeout)
177 {
178 	struct stm32_iwdg_device *iwdg = wdt_chip_to_iwdg(chip);
179 	unsigned long rate = clk_get_rate(iwdg->clk_lsi);
180 
181 	if (!rate)
182 		return TEE_ERROR_GENERIC;
183 
184 	/* Be safe and expect any counter to be above 2 */
185 	*min_timeout = 3 * IWDG_PRESCALER_256 / rate;
186 	*max_timeout = (IWDG_CNT_MASK + 1) * IWDG_PRESCALER_256 / rate;
187 
188 	return TEE_SUCCESS;
189 }
190 
191 static void iwdg_wdt_start(struct wdt_chip *chip)
192 {
193 	struct stm32_iwdg_device *iwdg = wdt_chip_to_iwdg(chip);
194 
195 	iwdg_start(iwdg);
196 
197 	if (configure_timeout(iwdg))
198 		panic();
199 }
200 
201 static void iwdg_wdt_refresh(struct wdt_chip *chip)
202 {
203 	struct stm32_iwdg_device *iwdg = wdt_chip_to_iwdg(chip);
204 
205 	iwdg_refresh(iwdg);
206 }
207 
208 static TEE_Result iwdg_wdt_set_timeout(struct wdt_chip *chip,
209 				       unsigned long timeout)
210 {
211 	struct stm32_iwdg_device *iwdg = wdt_chip_to_iwdg(chip);
212 
213 	if (!iwdg_timeout_cnt(iwdg, timeout))
214 		return TEE_ERROR_BAD_PARAMETERS;
215 
216 	iwdg->timeout = timeout;
217 
218 	if (iwdg_wdt_is_enabled(iwdg)) {
219 		TEE_Result res = TEE_ERROR_GENERIC;
220 
221 		res = configure_timeout(iwdg);
222 		if (res)
223 			return res;
224 	}
225 
226 	return TEE_SUCCESS;
227 }
228 
229 static const struct wdt_ops stm32_iwdg_ops = {
230 	.init = iwdg_wdt_init,
231 	.start = iwdg_wdt_start,
232 	.ping = iwdg_wdt_refresh,
233 	.set_timeout = iwdg_wdt_set_timeout,
234 };
235 DECLARE_KEEP_PAGER(stm32_iwdg_ops);
236 
237 /* Driver initialization */
238 static TEE_Result stm32_iwdg_parse_fdt(struct stm32_iwdg_device *iwdg,
239 				       const void *fdt, int node)
240 {
241 	TEE_Result res = TEE_ERROR_GENERIC;
242 	struct dt_node_info dt_info = { };
243 	const fdt32_t *cuint = NULL;
244 
245 	fdt_fill_device_info(fdt, &dt_info, node);
246 
247 	if (dt_info.reg == DT_INFO_INVALID_REG ||
248 	    dt_info.reg_size == DT_INFO_INVALID_REG_SIZE)
249 		panic();
250 
251 	res = clk_dt_get_by_name(fdt, node, "pclk", &iwdg->clk_pclk);
252 	if (res)
253 		return res;
254 
255 	res = clk_dt_get_by_name(fdt, node, "lsi", &iwdg->clk_lsi);
256 	if (res)
257 		return res;
258 
259 	/* Get IOMEM address */
260 	iwdg->base.pa = dt_info.reg;
261 	io_pa_or_va_secure(&iwdg->base, dt_info.reg_size);
262 	assert(iwdg->base.va);
263 
264 	/* Get and check timeout value */
265 	cuint = fdt_getprop(fdt, node, "timeout-sec", NULL);
266 	if (!cuint)
267 		return TEE_ERROR_BAD_PARAMETERS;
268 
269 	iwdg->timeout = (int)fdt32_to_cpu(*cuint);
270 	if (!iwdg->timeout)
271 		return TEE_ERROR_BAD_PARAMETERS;
272 
273 	if (!iwdg_timeout_cnt(iwdg, iwdg->timeout)) {
274 		EMSG("Timeout %lu not applicable", iwdg->timeout);
275 		return TEE_ERROR_BAD_PARAMETERS;
276 	}
277 
278 	/* DT can specify low power cases */
279 	if (!fdt_getprop(fdt, node, "stm32,enable-on-stop", NULL))
280 		iwdg->flags |= IWDG_FLAGS_DISABLE_ON_STOP;
281 
282 	if (!fdt_getprop(fdt, node, "stm32,enable-on-standby", NULL))
283 		iwdg->flags |= IWDG_FLAGS_DISABLE_ON_STANDBY;
284 
285 	return TEE_SUCCESS;
286 }
287 
288 /* Platform should override this function to provide IWDG fuses configuration */
289 TEE_Result __weak stm32_get_iwdg_otp_config(paddr_t pbase __unused,
290 					    struct stm32_iwdg_otp_data *otp_d)
291 {
292 	otp_d->hw_enabled = false;
293 	otp_d->disable_on_stop = false;
294 	otp_d->disable_on_standby = false;
295 
296 	return TEE_SUCCESS;
297 }
298 
299 static TEE_Result stm32_iwdg_setup(struct stm32_iwdg_device *iwdg,
300 				   const void *fdt, int node)
301 {
302 	struct stm32_iwdg_otp_data otp_data = { };
303 	TEE_Result res = TEE_SUCCESS;
304 
305 	res = stm32_iwdg_parse_fdt(iwdg, fdt, node);
306 	if (res)
307 		return res;
308 
309 	res = stm32_get_iwdg_otp_config(iwdg->base.pa, &otp_data);
310 	if (res)
311 		return res;
312 
313 	if (otp_data.hw_enabled)
314 		iwdg->flags |= IWDG_FLAGS_HW_ENABLED;
315 	if (otp_data.disable_on_stop)
316 		iwdg->flags |= IWDG_FLAGS_DISABLE_ON_STOP;
317 	if (otp_data.disable_on_standby)
318 		iwdg->flags |= IWDG_FLAGS_DISABLE_ON_STANDBY;
319 
320 	/* Enable watchdog source and bus clocks once for all */
321 	clk_enable(iwdg->clk_lsi);
322 	clk_enable(iwdg->clk_pclk);
323 
324 	if (otp_data.hw_enabled) {
325 		iwdg->flags |= IWDG_FLAGS_ENABLED;
326 
327 		/* Configure timeout if watchdog is already enabled */
328 		res = configure_timeout(iwdg);
329 		if (res)
330 			return res;
331 
332 		iwdg_refresh(iwdg);
333 	}
334 
335 	return TEE_SUCCESS;
336 }
337 
338 static TEE_Result stm32_iwdg_probe(const void *fdt, int node,
339 				   const void *compat_data __unused)
340 {
341 	struct stm32_iwdg_device *iwdg = NULL;
342 	TEE_Result res = TEE_SUCCESS;
343 
344 	iwdg = calloc(1, sizeof(*iwdg));
345 	if (!iwdg)
346 		return TEE_ERROR_OUT_OF_MEMORY;
347 
348 	res = stm32_iwdg_setup(iwdg, fdt, node);
349 	if (res)
350 		goto out;
351 
352 	iwdg->wdt_chip.ops = &stm32_iwdg_ops;
353 
354 	res = watchdog_register(&iwdg->wdt_chip);
355 
356 out:
357 	if (res)
358 		free(iwdg);
359 
360 	return res;
361 }
362 
363 static const struct dt_device_match stm32_iwdg_match_table[] = {
364 	{ .compatible = "st,stm32mp1-iwdg" },
365 	{ }
366 };
367 
368 DEFINE_DT_DRIVER(stm32_iwdg_dt_driver) = {
369 	.name = "stm32-iwdg",
370 	.match_table = stm32_iwdg_match_table,
371 	.probe = stm32_iwdg_probe,
372 };
373