xref: /rk3399_ARM-atf/drivers/st/mce/stm32_mce.c (revision 3ba36ea07ca22c748b5adcf5d9bff00e752681d7)
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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 
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, &region) != 0) {
394 			panic();
395 		}
396 	}
397 
398 	return 0;
399 }
400 
401 FCONF_REGISTER_POPULATOR(FW_CONFIG, mce_config, fconf_populate_mce);
402