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