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, ®ion) != 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