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