xref: /arm-trusted-firmware/drivers/st/iwdg/stm32_iwdg.c (revision 91f16700b400a8c0651d24a598fc48ee2997a0d7)
1*91f16700Schasinglulu /*
2*91f16700Schasinglulu  * Copyright (c) 2017-2021, STMicroelectronics - All Rights Reserved
3*91f16700Schasinglulu  *
4*91f16700Schasinglulu  * SPDX-License-Identifier: BSD-3-Clause
5*91f16700Schasinglulu  */
6*91f16700Schasinglulu 
7*91f16700Schasinglulu #include <assert.h>
8*91f16700Schasinglulu #include <errno.h>
9*91f16700Schasinglulu #include <string.h>
10*91f16700Schasinglulu 
11*91f16700Schasinglulu #include <libfdt.h>
12*91f16700Schasinglulu 
13*91f16700Schasinglulu #include <platform_def.h>
14*91f16700Schasinglulu 
15*91f16700Schasinglulu #include <arch_helpers.h>
16*91f16700Schasinglulu #include <common/debug.h>
17*91f16700Schasinglulu #include <drivers/arm/gicv2.h>
18*91f16700Schasinglulu #include <drivers/clk.h>
19*91f16700Schasinglulu #include <drivers/delay_timer.h>
20*91f16700Schasinglulu #include <drivers/st/stm32_iwdg.h>
21*91f16700Schasinglulu #include <drivers/st/stm32mp_clkfunc.h>
22*91f16700Schasinglulu #include <lib/mmio.h>
23*91f16700Schasinglulu #include <lib/utils.h>
24*91f16700Schasinglulu #include <plat/common/platform.h>
25*91f16700Schasinglulu 
26*91f16700Schasinglulu /* IWDG registers offsets */
27*91f16700Schasinglulu #define IWDG_KR_OFFSET		0x00U
28*91f16700Schasinglulu 
29*91f16700Schasinglulu /* Registers values */
30*91f16700Schasinglulu #define IWDG_KR_RELOAD_KEY	0xAAAA
31*91f16700Schasinglulu 
32*91f16700Schasinglulu struct stm32_iwdg_instance {
33*91f16700Schasinglulu 	uintptr_t base;
34*91f16700Schasinglulu 	unsigned long clock;
35*91f16700Schasinglulu 	uint8_t flags;
36*91f16700Schasinglulu 	int num_irq;
37*91f16700Schasinglulu };
38*91f16700Schasinglulu 
39*91f16700Schasinglulu static struct stm32_iwdg_instance stm32_iwdg[IWDG_MAX_INSTANCE];
40*91f16700Schasinglulu 
41*91f16700Schasinglulu static int stm32_iwdg_get_dt_node(struct dt_node_info *info, int offset)
42*91f16700Schasinglulu {
43*91f16700Schasinglulu 	int node;
44*91f16700Schasinglulu 
45*91f16700Schasinglulu 	node = dt_get_node(info, offset, DT_IWDG_COMPAT);
46*91f16700Schasinglulu 	if (node < 0) {
47*91f16700Schasinglulu 		if (offset == -1) {
48*91f16700Schasinglulu 			VERBOSE("%s: No IDWG found\n", __func__);
49*91f16700Schasinglulu 		}
50*91f16700Schasinglulu 		return -FDT_ERR_NOTFOUND;
51*91f16700Schasinglulu 	}
52*91f16700Schasinglulu 
53*91f16700Schasinglulu 	return node;
54*91f16700Schasinglulu }
55*91f16700Schasinglulu 
56*91f16700Schasinglulu void stm32_iwdg_refresh(void)
57*91f16700Schasinglulu {
58*91f16700Schasinglulu 	uint8_t i;
59*91f16700Schasinglulu 
60*91f16700Schasinglulu 	for (i = 0U; i < IWDG_MAX_INSTANCE; i++) {
61*91f16700Schasinglulu 		struct stm32_iwdg_instance *iwdg = &stm32_iwdg[i];
62*91f16700Schasinglulu 
63*91f16700Schasinglulu 		/* 0x00000000 is not a valid address for IWDG peripherals */
64*91f16700Schasinglulu 		if (iwdg->base != 0U) {
65*91f16700Schasinglulu 			clk_enable(iwdg->clock);
66*91f16700Schasinglulu 
67*91f16700Schasinglulu 			mmio_write_32(iwdg->base + IWDG_KR_OFFSET,
68*91f16700Schasinglulu 				      IWDG_KR_RELOAD_KEY);
69*91f16700Schasinglulu 
70*91f16700Schasinglulu 			clk_disable(iwdg->clock);
71*91f16700Schasinglulu 		}
72*91f16700Schasinglulu 	}
73*91f16700Schasinglulu }
74*91f16700Schasinglulu 
75*91f16700Schasinglulu int stm32_iwdg_init(void)
76*91f16700Schasinglulu {
77*91f16700Schasinglulu 	int node = -1;
78*91f16700Schasinglulu 	struct dt_node_info dt_info;
79*91f16700Schasinglulu 	void *fdt;
80*91f16700Schasinglulu 	uint32_t __unused count = 0;
81*91f16700Schasinglulu 
82*91f16700Schasinglulu 	if (fdt_get_address(&fdt) == 0) {
83*91f16700Schasinglulu 		panic();
84*91f16700Schasinglulu 	}
85*91f16700Schasinglulu 
86*91f16700Schasinglulu 	for (node = stm32_iwdg_get_dt_node(&dt_info, node);
87*91f16700Schasinglulu 	     node != -FDT_ERR_NOTFOUND;
88*91f16700Schasinglulu 	     node = stm32_iwdg_get_dt_node(&dt_info, node)) {
89*91f16700Schasinglulu 		struct stm32_iwdg_instance *iwdg;
90*91f16700Schasinglulu 		uint32_t hw_init;
91*91f16700Schasinglulu 		uint32_t idx;
92*91f16700Schasinglulu 
93*91f16700Schasinglulu 		count++;
94*91f16700Schasinglulu 
95*91f16700Schasinglulu 		idx = stm32_iwdg_get_instance(dt_info.base);
96*91f16700Schasinglulu 		iwdg = &stm32_iwdg[idx];
97*91f16700Schasinglulu 		iwdg->base = dt_info.base;
98*91f16700Schasinglulu 		iwdg->clock = (unsigned long)dt_info.clock;
99*91f16700Schasinglulu 
100*91f16700Schasinglulu 		/* DT can specify low power cases */
101*91f16700Schasinglulu 		if (fdt_getprop(fdt, node, "stm32,enable-on-stop", NULL) ==
102*91f16700Schasinglulu 		    NULL) {
103*91f16700Schasinglulu 			iwdg->flags |= IWDG_DISABLE_ON_STOP;
104*91f16700Schasinglulu 		}
105*91f16700Schasinglulu 
106*91f16700Schasinglulu 		if (fdt_getprop(fdt, node, "stm32,enable-on-standby", NULL) ==
107*91f16700Schasinglulu 		    NULL) {
108*91f16700Schasinglulu 			iwdg->flags |= IWDG_DISABLE_ON_STANDBY;
109*91f16700Schasinglulu 		}
110*91f16700Schasinglulu 
111*91f16700Schasinglulu 		/* Explicit list of supported bit flags */
112*91f16700Schasinglulu 		hw_init = stm32_iwdg_get_otp_config(idx);
113*91f16700Schasinglulu 
114*91f16700Schasinglulu 		if ((hw_init & IWDG_HW_ENABLED) != 0) {
115*91f16700Schasinglulu 			if (dt_info.status == DT_DISABLED) {
116*91f16700Schasinglulu 				ERROR("OTP enabled but iwdg%u DT-disabled\n",
117*91f16700Schasinglulu 				      idx + 1U);
118*91f16700Schasinglulu 				panic();
119*91f16700Schasinglulu 			}
120*91f16700Schasinglulu 			iwdg->flags |= IWDG_HW_ENABLED;
121*91f16700Schasinglulu 		}
122*91f16700Schasinglulu 
123*91f16700Schasinglulu 		if (dt_info.status == DT_DISABLED) {
124*91f16700Schasinglulu 			zeromem((void *)iwdg,
125*91f16700Schasinglulu 				sizeof(struct stm32_iwdg_instance));
126*91f16700Schasinglulu 			continue;
127*91f16700Schasinglulu 		}
128*91f16700Schasinglulu 
129*91f16700Schasinglulu 		if ((hw_init & IWDG_DISABLE_ON_STOP) != 0) {
130*91f16700Schasinglulu 			iwdg->flags |= IWDG_DISABLE_ON_STOP;
131*91f16700Schasinglulu 		}
132*91f16700Schasinglulu 
133*91f16700Schasinglulu 		if ((hw_init & IWDG_DISABLE_ON_STANDBY) != 0) {
134*91f16700Schasinglulu 			iwdg->flags |= IWDG_DISABLE_ON_STANDBY;
135*91f16700Schasinglulu 		}
136*91f16700Schasinglulu 
137*91f16700Schasinglulu 		VERBOSE("IWDG%u found, %ssecure\n", idx + 1U,
138*91f16700Schasinglulu 			((dt_info.status & DT_NON_SECURE) != 0) ?
139*91f16700Schasinglulu 			"non-" : "");
140*91f16700Schasinglulu 
141*91f16700Schasinglulu 		if ((dt_info.status & DT_NON_SECURE) != 0) {
142*91f16700Schasinglulu 			stm32mp_register_non_secure_periph_iomem(iwdg->base);
143*91f16700Schasinglulu 		} else {
144*91f16700Schasinglulu 			stm32mp_register_secure_periph_iomem(iwdg->base);
145*91f16700Schasinglulu 		}
146*91f16700Schasinglulu 
147*91f16700Schasinglulu #if defined(IMAGE_BL2)
148*91f16700Schasinglulu 		if (stm32_iwdg_shadow_update(idx, iwdg->flags) != BSEC_OK) {
149*91f16700Schasinglulu 			return -1;
150*91f16700Schasinglulu 		}
151*91f16700Schasinglulu #endif
152*91f16700Schasinglulu 	}
153*91f16700Schasinglulu 
154*91f16700Schasinglulu 	VERBOSE("%u IWDG instance%s found\n", count, (count > 1U) ? "s" : "");
155*91f16700Schasinglulu 
156*91f16700Schasinglulu 	return 0;
157*91f16700Schasinglulu }
158