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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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