1 /* 2 * Copyright 2022-2023 NXP 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <errno.h> 9 #include <stdbool.h> 10 11 #include <common/bl_common.h> 12 #include <common/debug.h> 13 #include <drivers/nxp/trdc/imx_trdc.h> 14 #include <lib/mmio.h> 15 16 17 int trdc_mda_set_cpu(uintptr_t trdc_base, uint32_t mda_inst, 18 uint32_t mda_reg, uint8_t sa, uint8_t dids, 19 uint8_t did, uint8_t pe, uint8_t pidm, uint8_t pid) 20 { 21 uint32_t val = mmio_read_32(trdc_base + MDAC_W_X(mda_inst, mda_reg)); 22 /* invalid: config non-cpu master with cpu config format. */ 23 if ((val & MDA_DFMT) != 0U) { 24 return -EINVAL; 25 } 26 27 val = MDA_VLD | MDA_DFMT0_DID(pid) | MDA_DFMT0_PIDM(pidm) | MDA_DFMT0_PE(pe) | 28 MDA_DFMT0_SA(sa) | MDA_DFMT0_DIDS(dids) | MDA_DFMT0_DID(did); 29 30 mmio_write_32(trdc_base + MDAC_W_X(mda_inst, mda_reg), val); 31 32 return 0; 33 } 34 35 int trdc_mda_set_noncpu(uintptr_t trdc_base, uint32_t mda_inst, 36 bool did_bypass, uint8_t sa, uint8_t pa, 37 uint8_t did) 38 { 39 uint32_t val = mmio_read_32(trdc_base + MDAC_W_X(mda_inst, 0)); 40 41 /* invalid: config cpu master with non-cpu config format. */ 42 if ((val & MDA_DFMT) == 0U) { 43 return -EINVAL; 44 } 45 46 val = MDA_VLD | MDA_DFMT1_SA(sa) | MDA_DFMT1_PA(pa) | MDA_DFMT1_DID(did) | 47 MDA_DFMT1_DIDB(did_bypass ? 1U : 0U); 48 49 mmio_write_32(trdc_base + MDAC_W_X(mda_inst, 0), val); 50 51 return 0; 52 } 53 54 static uintptr_t trdc_get_mbc_base(uintptr_t trdc_reg, uint32_t mbc_x) 55 { 56 struct trdc_mgr *trdc_base = (struct trdc_mgr *)trdc_reg; 57 uint32_t mbc_num = MBC_NUM(trdc_base->trdc_hwcfg0); 58 59 if (mbc_x >= mbc_num) { 60 return 0U; 61 } 62 63 return trdc_reg + 0x10000 + 0x2000 * mbc_x; 64 } 65 66 static uintptr_t trdc_get_mrc_base(uintptr_t trdc_reg, uint32_t mrc_x) 67 { 68 struct trdc_mgr *trdc_base = (struct trdc_mgr *)trdc_reg; 69 uint32_t mbc_num = MBC_NUM(trdc_base->trdc_hwcfg0); 70 uint32_t mrc_num = MRC_NUM(trdc_base->trdc_hwcfg0); 71 72 if (mrc_x >= mrc_num) { 73 return 0U; 74 } 75 76 return trdc_reg + 0x10000 + 0x2000 * mbc_num + 0x1000 * mrc_x; 77 } 78 79 uint32_t trdc_mbc_blk_num(uintptr_t trdc_reg, uint32_t mbc_x, uint32_t mem_x) 80 { 81 uint32_t glbcfg; 82 struct mbc_mem_dom *mbc_dom; 83 struct trdc_mbc *mbc_base = (struct trdc_mbc *)trdc_get_mbc_base(trdc_reg, mbc_x); 84 85 if (mbc_base == NULL) { 86 return 0; 87 } 88 89 /* only first dom has the glbcfg */ 90 mbc_dom = &mbc_base->mem_dom[0]; 91 glbcfg = mmio_read_32((uintptr_t)&mbc_dom->mem_glbcfg[mem_x]); 92 93 return MBC_BLK_NUM(glbcfg); 94 } 95 96 uint32_t trdc_mrc_rgn_num(uintptr_t trdc_reg, uint32_t mrc_x) 97 { 98 uint32_t glbcfg; 99 struct mrc_rgn_dom *mrc_dom; 100 struct trdc_mrc *mrc_base = (struct trdc_mrc *)trdc_get_mrc_base(trdc_reg, mrc_x); 101 102 if (mrc_base == NULL) { 103 return 0; 104 } 105 106 /* only first dom has the glbcfg */ 107 mrc_dom = &mrc_base->mrc_dom[0]; 108 glbcfg = mmio_read_32((uintptr_t)&mrc_dom->mrc_glbcfg[0]); 109 110 return MBC_BLK_NUM(glbcfg); 111 } 112 113 int trdc_mbc_set_control(uintptr_t trdc_reg, uint32_t mbc_x, 114 uint32_t glbac_id, uint32_t glbac_val) 115 { 116 struct mbc_mem_dom *mbc_dom; 117 struct trdc_mbc *mbc_base = (struct trdc_mbc *)trdc_get_mbc_base(trdc_reg, mbc_x); 118 119 if (mbc_base == NULL || glbac_id >= GLBAC_NUM) { 120 return -EINVAL; 121 } 122 123 /* only first dom has the glbac */ 124 mbc_dom = &mbc_base->mem_dom[0]; 125 126 mmio_write_32((uintptr_t)&mbc_dom->memn_glbac[glbac_id], glbac_val); 127 128 return 0; 129 } 130 131 int trdc_mbc_blk_config(uintptr_t trdc_reg, uint32_t mbc_x, 132 uint32_t dom_x, uint32_t mem_x, uint32_t blk_x, 133 bool sec_access, uint32_t glbac_id) 134 { 135 uint32_t *cfg_w; 136 uint32_t index, offset, val; 137 struct mbc_mem_dom *mbc_dom; 138 struct trdc_mbc *mbc_base = (struct trdc_mbc *)trdc_get_mbc_base(trdc_reg, mbc_x); 139 140 if (mbc_base == NULL || glbac_id >= GLBAC_NUM) { 141 return -EINVAL; 142 } 143 144 mbc_dom = &mbc_base->mem_dom[dom_x]; 145 146 switch (mem_x) { 147 case 0: 148 cfg_w = &mbc_dom->mem0_blk_cfg_w[blk_x / 8]; 149 break; 150 case 1: 151 cfg_w = &mbc_dom->mem1_blk_cfg_w[blk_x / 8]; 152 break; 153 case 2: 154 cfg_w = &mbc_dom->mem2_blk_cfg_w[blk_x / 8]; 155 break; 156 case 3: 157 cfg_w = &mbc_dom->mem3_blk_cfg_w[blk_x / 8]; 158 break; 159 default: 160 return -EINVAL; 161 }; 162 163 index = blk_x % 8; 164 offset = index * 4; 165 166 val = mmio_read_32((uintptr_t)cfg_w); 167 val &= ~(0xF << offset); 168 169 /* 170 * MBC0-3 171 * Global 0, 0x7777 secure pri/user read/write/execute, 172 * S400 has already set it. So select MBC0_MEMN_GLBAC0 173 */ 174 if (sec_access) { 175 val |= ((0x0 | (glbac_id & 0x7)) << offset); 176 mmio_write_32((uintptr_t)cfg_w, val); 177 } else { 178 /* nse bit set */ 179 val |= ((0x8 | (glbac_id & 0x7)) << offset); 180 mmio_write_32((uintptr_t)cfg_w, val); 181 } 182 183 return 0; 184 } 185 186 int trdc_mrc_set_control(uintptr_t trdc_reg, uint32_t mrc_x, 187 uint32_t glbac_id, uint32_t glbac_val) 188 { 189 struct mrc_rgn_dom *mrc_dom; 190 struct trdc_mrc *mrc_base = (struct trdc_mrc *)trdc_get_mrc_base(trdc_reg, mrc_x); 191 192 if (mrc_base == NULL || glbac_id >= GLBAC_NUM) { 193 return -EINVAL; 194 } 195 196 /* only first dom has the glbac */ 197 mrc_dom = &mrc_base->mrc_dom[0]; 198 199 mmio_write_32((uintptr_t)&mrc_dom->memn_glbac[glbac_id], glbac_val); 200 201 return 0; 202 } 203 204 int trdc_mrc_rgn_config(uintptr_t trdc_reg, uint32_t mrc_x, 205 uint32_t dom_x, uint32_t rgn_id, 206 uint32_t addr_start, uint32_t addr_size, 207 bool sec_access, uint32_t glbac_id) 208 { 209 uint32_t *desc_w; 210 uint32_t addr_end; 211 struct mrc_rgn_dom *mrc_dom; 212 struct trdc_mrc *mrc_base = (struct trdc_mrc *)trdc_get_mrc_base(trdc_reg, mrc_x); 213 214 if (mrc_base == NULL || glbac_id >= GLBAC_NUM || rgn_id >= MRC_REG_ALL) { 215 return -EINVAL; 216 } 217 218 mrc_dom = &mrc_base->mrc_dom[dom_x]; 219 220 addr_end = addr_start + addr_size - 1; 221 addr_start &= ~0x3fff; 222 addr_end &= ~0x3fff; 223 224 desc_w = &mrc_dom->rgn_desc_words[rgn_id][0]; 225 226 if (sec_access) { 227 mmio_write_32((uintptr_t)desc_w, addr_start | (glbac_id & 0x7)); 228 mmio_write_32((uintptr_t)(desc_w + 1), addr_end | 0x1); 229 } else { 230 mmio_write_32((uintptr_t)desc_w, addr_start | (glbac_id & 0x7)); 231 mmio_write_32((uintptr_t)(desc_w + 1), (addr_end | 0x1 | 0x10)); 232 } 233 234 return 0; 235 } 236 237 bool trdc_mrc_enabled(uintptr_t mrc_base) 238 { 239 return (mmio_read_32(mrc_base) & BIT(15)); 240 } 241 242 bool trdc_mbc_enabled(uintptr_t mbc_base) 243 { 244 return (mmio_read_32(mbc_base) & BIT(14)); 245 } 246 247 static bool is_trdc_mgr_slot(uintptr_t trdc_base, uint8_t mbc_id, 248 uint8_t mem_id, uint16_t blk_id) 249 { 250 unsigned int i; 251 252 for (i = 0U; i < trdc_mgr_num; i++) { 253 if (trdc_mgr_blks[i].trdc_base == trdc_base) { 254 if (mbc_id == trdc_mgr_blks[i].mbc_id && 255 mem_id == trdc_mgr_blks[i].mbc_mem_id && 256 (blk_id == trdc_mgr_blks[i].blk_mgr || 257 blk_id == trdc_mgr_blks[i].blk_mc)) { 258 return true; 259 } 260 } 261 } 262 263 return false; 264 } 265 266 /* 267 * config the TRDC MGR & MC's access policy. only the secure privilege 268 * mode SW can access it. 269 */ 270 void trdc_mgr_mbc_setup(struct trdc_mgr_info *mgr) 271 { 272 unsigned int i; 273 274 /* 275 * If the MBC is global enabled, need to cconfigure the MBCs of 276 * TRDC MGR & MC correctly. 277 */ 278 if (trdc_mbc_enabled(mgr->trdc_base)) { 279 /* ONLY secure privilige can access */ 280 trdc_mbc_set_control(mgr->trdc_base, mgr->mbc_id, 7, 0x6000); 281 for (i = 0U; i < 16U; i++) { 282 trdc_mbc_blk_config(mgr->trdc_base, mgr->mbc_id, i, 283 mgr->mbc_mem_id, mgr->blk_mgr, true, 7); 284 285 trdc_mbc_blk_config(mgr->trdc_base, mgr->mbc_id, i, 286 mgr->mbc_mem_id, mgr->blk_mc, true, 7); 287 } 288 } 289 } 290 291 /* 292 * Set up the TRDC access policy for all the resources under 293 * the TRDC control. 294 */ 295 void trdc_setup(struct trdc_config_info *cfg) 296 { 297 unsigned int i, j, num; 298 bool is_mgr; 299 300 /* config the MRCs */ 301 if (trdc_mrc_enabled(cfg->trdc_base)) { 302 /* set global access policy */ 303 for (i = 0U; i < cfg->num_mrc_glbac; i++) { 304 trdc_mrc_set_control(cfg->trdc_base, 305 cfg->mrc_glbac[i].mbc_mrc_id, 306 cfg->mrc_glbac[i].glbac_id, 307 cfg->mrc_glbac[i].glbac_val); 308 } 309 310 /* set each MRC region access policy */ 311 for (i = 0U; i < cfg->num_mrc_cfg; i++) { 312 trdc_mrc_rgn_config(cfg->trdc_base, cfg->mrc_cfg[i].mrc_id, 313 cfg->mrc_cfg[i].dom_id, 314 cfg->mrc_cfg[i].region_id, 315 cfg->mrc_cfg[i].region_start, 316 cfg->mrc_cfg[i].region_size, 317 cfg->mrc_cfg[i].secure, 318 cfg->mrc_cfg[i].glbac_id); 319 } 320 } 321 322 /* config the MBCs */ 323 if (trdc_mbc_enabled(cfg->trdc_base)) { 324 /* set MBC global access policy */ 325 for (i = 0U; i < cfg->num_mbc_glbac; i++) { 326 trdc_mbc_set_control(cfg->trdc_base, 327 cfg->mbc_glbac[i].mbc_mrc_id, 328 cfg->mbc_glbac[i].glbac_id, 329 cfg->mbc_glbac[i].glbac_val); 330 } 331 332 for (i = 0U; i < cfg->num_mbc_cfg; i++) { 333 if (cfg->mbc_cfg[i].blk_id == MBC_BLK_ALL) { 334 num = trdc_mbc_blk_num(cfg->trdc_base, 335 cfg->mbc_cfg[i].mbc_id, 336 cfg->mbc_cfg[i].mem_id); 337 338 for (j = 0U; j < num; j++) { 339 /* Skip mgr and mc */ 340 is_mgr = is_trdc_mgr_slot(cfg->trdc_base, 341 cfg->mbc_cfg[i].mbc_id, 342 cfg->mbc_cfg[i].mem_id, j); 343 if (is_mgr) { 344 continue; 345 } 346 347 trdc_mbc_blk_config(cfg->trdc_base, 348 cfg->mbc_cfg[i].mbc_id, 349 cfg->mbc_cfg[i].dom_id, 350 cfg->mbc_cfg[i].mem_id, j, 351 cfg->mbc_cfg[i].secure, 352 cfg->mbc_cfg[i].glbac_id); 353 } 354 } else { 355 trdc_mbc_blk_config(cfg->trdc_base, 356 cfg->mbc_cfg[i].mbc_id, 357 cfg->mbc_cfg[i].dom_id, 358 cfg->mbc_cfg[i].mem_id, 359 cfg->mbc_cfg[i].blk_id, 360 cfg->mbc_cfg[i].secure, 361 cfg->mbc_cfg[i].glbac_id); 362 } 363 } 364 } 365 } 366