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