1 /*
2 * Copyright (c) 2025, STMicroelectronics - All Rights Reserved
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7 #include <assert.h>
8 #include <errno.h>
9
10 #include <drivers/clk.h>
11 #include <drivers/delay_timer.h>
12 #include <drivers/st/stm32_mce.h>
13 #include <lib/mmio.h>
14 #include <lib/mmio_poll.h>
15 #include <libfdt.h>
16
17 #include <platform_def.h>
18 #include <stm32mp_fconf_getter.h>
19
20 /* MCE registers (base relative) */
21 #define MCE_CR U(0x0000) /* MCE configuration register */
22 #define MCE_SR U(0x0004) /* MCE status register */
23 #define MCE_IASR U(0x0008) /* MCE illegal access status register */
24 #define MCE_IACR U(0x000C) /* MCE illegal access clear register */
25 #define MCE_IAIER U(0x0010) /* MCE illegal access interrupt enable reg */
26 #define MCE_PRIVCFGR U(0x001C) /* MCE privileged configuration register */
27 #define MCE_REGCR U(0x0040) /* MCE region configuration register */
28 #define MCE_SADDR U(0x0044) /* MCE start address for region register */
29 #define MCE_EADDR U(0x0048) /* MCE end address for region register */
30 #define MCE_MKEYR U(0x0200) /* MCE master key register offset */
31 #define MCE_HWCFGR3 U(0x03E8) /* MCE hardware configuration register 3 */
32 #define MCE_HWCFGR2 U(0x03EC) /* MCE hardware configuration register 2 */
33 #define MCE_HWCFGR1 U(0x03F0) /* MCE hardware configuration register 1 */
34 #define MCE_VERR U(0x03F4) /* MCE version register */
35 #define MCE_IPIDR U(0x03F8) /* MCE identification register */
36 #define MCE_SIDR U(0x03FC) /* MCE size ID register */
37
38 /* MCE configuration register */
39 #define MCE_CR_GLOCK BIT(0)
40 #define MCE_CR_MKLOCK BIT(1)
41
42 /* MCE status register */
43 #define MCE_SR_MKVALID BIT(0)
44 #define MCE_SR_ENCDIS BIT(4)
45
46 /* MCE privileged configuration register */
47 #define MCE_PRIVCFGR_PRIV BIT(0)
48
49 /* MCE region configuration register */
50 #define MCE_REGCR_BREN BIT(0)
51 #define MCE_REGCR_ENC BIT(15)
52
53 /* MCE start address for region register */
54 #define MCE_SADDR_BADDSTART_MASK GENMASK(31, 16)
55
56 /* MCE end address for region register */
57 #define MCE_EADDR_BADDEND_MASK GENMASK(31, 16)
58
59 /* MCE version register */
60 #define MCE_VERR_MINREV_MASK GENMASK(3, 0)
61 #define MCE_VERR_MINREV_SHIFT 0
62 #define MCE_VERR_MAJREV_MASK GENMASK(7, 4)
63 #define MCE_VERR_MAJREV_SHIFT 4
64
65 /* IP configuration */
66 #define MCE_MAJREV 1U
67 #define MCE_MINREV 0U
68 #define MCE_IP_ID 0x00170081U
69 #define MCE_SIZE_ID 0xA3C5DD01U
70 #define MCE_ADDR_GRANULARITY 0x10000U
71
72 /* Other definitions */
73 #define MCE_TIMEOUT_1MS_IN_US 1000U
74 #define DDR_BASE_EXTRA_MASK GENMASK_32(31, 30)
75 #define MCE_REGION_PARAMS 3U
76
77 struct mce_version_s {
78 uint32_t major;
79 uint32_t minor;
80 uint32_t ip_id;
81 uint32_t size_id;
82 };
83
84 struct mce_dt_id_attr {
85 fdt32_t id_attr[MCE_IP_MAX_REGION_NB];
86 };
87
88 /*
89 * @brief Configure privileged access to the MCE registers.
90 * @param privilege: Only privileged (true) or all (false) access are granted.
91 * @retval None.
92 */
configure_privilege(bool privilege)93 static void configure_privilege(bool privilege)
94 {
95 if (privilege) {
96 mmio_setbits_32(MCE_BASE + MCE_PRIVCFGR, MCE_PRIVCFGR_PRIV);
97 } else {
98 mmio_clrbits_32(MCE_BASE + MCE_PRIVCFGR, MCE_PRIVCFGR_PRIV);
99 }
100 }
101
102 /*
103 * @brief Check consistency of region settings.
104 * @param config: Ref to the region configuration structure.
105 * @retval 0 if OK, negative value else.
106 */
check_region_settings(struct stm32_mce_region_s * config)107 static int check_region_settings(struct stm32_mce_region_s *config)
108 {
109 uint32_t end;
110
111 if (config->encrypt_mode > MCE_ENCRYPTION_MODE_MAX) {
112 ERROR("MCE: encryption mode out of range error\n");
113 return -EINVAL;
114 }
115
116 if ((config->start_address < STM32MP_DDR_BASE) ||
117 (config->end_address < STM32MP_DDR_BASE)) {
118 ERROR("MCE: start/end address lower than DDR base\n");
119 return -EINVAL;
120 }
121
122 end = STM32MP_DDR_BASE + dt_get_ddr_size() - 1U;
123 if ((config->start_address > end) || (config->end_address > end)) {
124 ERROR("MCE: start/end address higher than physical end\n");
125 return -EINVAL;
126 }
127
128 if (config->start_address >= config->end_address) {
129 ERROR("MCE: start address higher than or equal to end one\n");
130 return -EINVAL;
131 }
132
133 if (((config->start_address % MCE_ADDR_GRANULARITY) != 0U) ||
134 (((config->end_address + 1U) % MCE_ADDR_GRANULARITY) != 0U)) {
135 ERROR("MCE: start/end address granularity not respected\n");
136 return -EINVAL;
137 }
138
139 return 0;
140 }
141
142 /*
143 * @brief Configure (and enable) the MCE region.
144 * @param index: Region index (first region is 0).
145 * @param config: Ref to the region configuration structure.
146 * @retval 0 if OK, negative value else.
147 */
stm32_mce_configure_region(uint32_t index,struct stm32_mce_region_s * config)148 static int stm32_mce_configure_region(uint32_t index, struct stm32_mce_region_s *config)
149 {
150 int ret;
151
152 if ((index >= MCE_IP_MAX_REGION_NB) || (config == NULL)) {
153 return -EINVAL;
154 }
155
156 ret = check_region_settings(config);
157 if (ret != 0) {
158 return ret;
159 }
160
161 mmio_clrbits_32(MCE_BASE + MCE_REGCR, MCE_REGCR_BREN);
162
163 mmio_clrsetbits_32(MCE_BASE + MCE_SADDR, MCE_SADDR_BADDSTART_MASK,
164 config->start_address & MCE_SADDR_BADDSTART_MASK);
165 mmio_clrsetbits_32(MCE_BASE + MCE_EADDR, MCE_EADDR_BADDEND_MASK,
166 config->end_address & MCE_EADDR_BADDEND_MASK);
167
168 if (config->encrypt_mode == MCE_ENCRYPT_MODE) {
169 mmio_setbits_32(MCE_BASE + MCE_REGCR, MCE_REGCR_BREN | MCE_REGCR_ENC);
170
171 if (!stm32_mce_is_hw_encryption_functional()) {
172 ERROR("MCE: encryption feature error\n");
173 return -EIO;
174 }
175 } else {
176 mmio_clrbits_32(MCE_BASE + MCE_REGCR, MCE_REGCR_ENC);
177 mmio_setbits_32(MCE_BASE + MCE_REGCR, MCE_REGCR_BREN);
178 }
179
180 return 0;
181 }
182
183 /*
184 * @brief Initialize the MCE driver.
185 * @param None.
186 * @retval None.
187 */
stm32_mce_init(void)188 void stm32_mce_init(void)
189 {
190 const struct mce_version_s exp_version = {
191 .major = MCE_MAJREV,
192 .minor = MCE_MINREV,
193 .ip_id = MCE_IP_ID,
194 .size_id = MCE_SIZE_ID
195 };
196 struct mce_version_s version;
197
198 if (clk_enable(MCE) != 0) {
199 panic();
200 }
201
202 version = (struct mce_version_s) {
203 .major = (mmio_read_32(MCE_BASE + MCE_VERR) &
204 MCE_VERR_MAJREV_MASK) >> MCE_VERR_MAJREV_SHIFT,
205 .minor = (mmio_read_32(MCE_BASE + MCE_VERR) &
206 MCE_VERR_MINREV_MASK) >> MCE_VERR_MINREV_SHIFT,
207 .ip_id = mmio_read_32(MCE_BASE + MCE_IPIDR),
208 .size_id = mmio_read_32(MCE_BASE + MCE_SIDR)
209 };
210
211 if ((version.major != exp_version.major) ||
212 (version.minor != exp_version.minor) ||
213 (version.ip_id != exp_version.ip_id) ||
214 (version.size_id != exp_version.size_id)) {
215 ERROR("MCE: unexpected IP version { 0x%x, 0x%x, 0x%x, 0x%x }\n",
216 version.major, version.minor, version.ip_id, version.size_id);
217 panic();
218 }
219
220 configure_privilege(true);
221 }
222
223 /*
224 * @brief Write the MCE master key.
225 * @param mkey: Pointer to the master key buffer.
226 * @retval 0 if OK, negative value else.
227 */
stm32_mce_write_master_key(uint8_t * mkey)228 int stm32_mce_write_master_key(uint8_t *mkey)
229 {
230 uint8_t i;
231 uint32_t mce_sr;
232
233 if (mkey == NULL) {
234 return -EINVAL;
235 }
236
237 if ((mmio_read_32(MCE_BASE + MCE_CR) & MCE_CR_MKLOCK) == MCE_CR_MKLOCK) {
238 return -EPERM;
239 }
240
241 for (i = 0U; i < MCE_KEY_SIZE_IN_BYTES; i += sizeof(uint32_t)) {
242 uint32_t key_val = 0U;
243
244 (void)memcpy(&key_val, mkey + i, sizeof(uint32_t));
245
246 mmio_write_32(MCE_BASE + MCE_MKEYR + i, key_val);
247 }
248
249 return mmio_read_32_poll_timeout((MCE_BASE + MCE_SR), mce_sr,
250 ((mce_sr & MCE_SR_MKVALID) == MCE_SR_MKVALID),
251 MCE_TIMEOUT_1MS_IN_US);
252 }
253
254 /*
255 * @brief Lock the MCE master key.
256 * @param None.
257 * @retval None.
258 */
stm32_mce_lock_master_key(void)259 void stm32_mce_lock_master_key(void)
260 {
261 mmio_setbits_32(MCE_BASE + MCE_CR, MCE_CR_MKLOCK);
262 }
263
264 /*
265 * @brief Get the MCE master key lock state.
266 * @param None.
267 * @retval True if locked, false else.
268 */
stm32_mce_is_master_key_locked(void)269 bool stm32_mce_is_master_key_locked(void)
270 {
271 return (mmio_read_32(MCE_BASE + MCE_CR) & MCE_CR_MKLOCK) == MCE_CR_MKLOCK;
272 }
273
274 /*
275 * @brief Lock the MCE IP registers.
276 * @param None.
277 * @retval None.
278 */
stm32_mce_lock_global(void)279 void stm32_mce_lock_global(void)
280 {
281 mmio_setbits_32(MCE_BASE + MCE_CR, MCE_CR_GLOCK);
282 }
283
284 /*
285 * @brief Get the MCE global lock state.
286 * @param None.
287 * @retval True if locked, false else.
288 */
stm32_mce_is_globally_locked(void)289 bool stm32_mce_is_globally_locked(void)
290 {
291 return (mmio_read_32(MCE_BASE + MCE_CR) & MCE_CR_GLOCK) == MCE_CR_GLOCK;
292 }
293
294 /*
295 * @brief Get the MCE encryption HW feature state.
296 * @param None.
297 * @retval True if functional, false else.
298 */
stm32_mce_is_hw_encryption_functional(void)299 bool stm32_mce_is_hw_encryption_functional(void)
300 {
301 return (mmio_read_32(MCE_BASE + MCE_SR) & MCE_SR_ENCDIS) != MCE_SR_ENCDIS;
302 }
303
304 /*
305 * @brief Get the encryption state of an address.
306 * @param index: Memory address.
307 * @param state: Ref to the encryption state.
308 * @retval 0 if OK, negative value else.
309 */
stm32_mce_get_address_encryption_state(uint32_t address,uint32_t * state)310 int stm32_mce_get_address_encryption_state(uint32_t address, uint32_t *state)
311 {
312 struct stm32_mce_region_s config;
313
314 if ((address < STM32MP_DDR_BASE) ||
315 (address > (STM32MP_DDR_BASE + dt_get_ddr_size() - 1U)) ||
316 (state == NULL)) {
317 return -EINVAL;
318 }
319
320 if ((mmio_read_32(MCE_BASE + MCE_REGCR) & MCE_REGCR_ENC) != MCE_REGCR_ENC) {
321 /* No encrypted region, all DDR area is in plain text */
322 *state = MCE_BYPASS_MODE;
323 return 0;
324 }
325
326 if (!stm32_mce_is_hw_encryption_functional()) {
327 ERROR("MCE: encryption feature error\n");
328 return -EIO;
329 }
330
331 /*
332 * When MCE_SADDR and MCE_EADDR are accessed in read, the 2 MSB bits
333 * return zeros. So DDR base address mask has to be ORed.
334 */
335 config.start_address = mmio_read_32(MCE_BASE + MCE_SADDR) |
336 (STM32MP_DDR_BASE & DDR_BASE_EXTRA_MASK);
337
338 config.end_address = mmio_read_32(MCE_BASE + MCE_EADDR) |
339 (STM32MP_DDR_BASE & DDR_BASE_EXTRA_MASK);
340
341 if ((address >= config.start_address) && (address <= config.end_address)) {
342 *state = MCE_ENCRYPT_MODE;
343 } else {
344 *state = MCE_BYPASS_MODE;
345 }
346
347 return 0;
348 }
349
fconf_populate_mce(uintptr_t config)350 static int fconf_populate_mce(uintptr_t config)
351 {
352 int node, len;
353 unsigned int i;
354 const struct mce_dt_id_attr *conf_list;
355 const void *dtb = (const void *)config;
356
357 /* Check the node offset point to "st,mem-encrypt" compatible property */
358 const char *compatible_str = "st,mem-encrypt";
359
360 if ((stm32mp_check_closed_device() == STM32MP_CHIP_SEC_OPEN) &&
361 !stm32mp_is_auth_supported()) {
362 return 0;
363 }
364
365 node = fdt_node_offset_by_compatible(dtb, -1, compatible_str);
366 if (node < 0) {
367 ERROR("FCONF: Can't find %s compatible in dtb\n", compatible_str);
368 return node;
369 }
370
371 conf_list = (const struct mce_dt_id_attr *)fdt_getprop(dtb, node, "memory-ranges", &len);
372 if (conf_list == NULL) {
373 WARN("FCONF: Read cell failed for %s\n", "memory-ranges");
374 return -1;
375 }
376
377 /* Consider only complete set of values */
378 len -= len % MCE_REGION_PARAMS;
379
380 /* Locate the memory cells and read all values */
381 for (i = 0U; i < ((unsigned int)len / (sizeof(uint32_t) * MCE_REGION_PARAMS)); i++) {
382 uint32_t size;
383 struct stm32_mce_region_s region;
384
385 region.start_address = fdt32_to_cpu(conf_list->id_attr[i * MCE_REGION_PARAMS]);
386 size = fdt32_to_cpu(conf_list->id_attr[i * MCE_REGION_PARAMS + 1U]);
387 region.end_address = region.start_address + size - 1U;
388 region.encrypt_mode = fdt32_to_cpu(conf_list->id_attr[i * MCE_REGION_PARAMS + 2U]);
389
390 VERBOSE("FCONF: mce cell found with value = 0x%x 0x%x 0x%x\n",
391 region.start_address, size, region.encrypt_mode);
392
393 if (stm32_mce_configure_region(i, ®ion) != 0) {
394 panic();
395 }
396 }
397
398 return 0;
399 }
400
401 FCONF_REGISTER_POPULATOR(FW_CONFIG, mce_config, fconf_populate_mce);
402