1 /* 2 * Copyright 2020-2024 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/debug.h> 12 #include <lib/mmio.h> 13 #include <plat/common/platform.h> 14 #include <platform_def.h> 15 16 #include "xrdc_config.h" 17 18 #define XRDC_ADDR 0x292f0000 19 #define MRC_OFFSET 0x2000 20 #define MRC_STEP 0x200 21 22 #define XRDC_MGR_PAC_ID U(0) 23 #define XRDC_MGR_PAC_SLOT U(47) 24 25 enum xrdc_comp_type { 26 MDA_TYPE = (1 << 16), 27 MRC_TYPE = (2 << 16), 28 PAC_TYPE = (3 << 16), 29 MSC_TYPE = (4 << 16), 30 }; 31 32 enum xrdc_pd_type { 33 XRDC_AD_PD, 34 XRDC_HIFI_PD, 35 XRDC_AV_PD, 36 }; 37 38 #define XRDC_TYPE_MASK (0x7 << 16) 39 #define XRDC_ID_MASK 0xFFFF 40 #define XRDC_ID(id) ((id) & XRDC_ID_MASK) 41 42 typedef bool (*xrdc_check_func)(enum xrdc_comp_type type, uint16_t id); 43 44 /* Access below XRDC needs enable PS 8 45 * and HIFI clocks and release HIFI firstly 46 */ 47 uint32_t hifi_xrdc_list[] = { 48 (MDA_TYPE | XRDC_ID(9)), 49 (MRC_TYPE | XRDC_ID(7)), 50 (MRC_TYPE | XRDC_ID(9)), 51 (MRC_TYPE | XRDC_ID(11)), 52 }; 53 54 /* Access below XRDC needs enable PS 16 firstly */ 55 uint32_t av_periph_xrdc_list[] = { 56 (MDA_TYPE | XRDC_ID(10)), 57 (MDA_TYPE | XRDC_ID(11)), 58 (MDA_TYPE | XRDC_ID(12)), 59 (MDA_TYPE | XRDC_ID(13)), 60 (MDA_TYPE | XRDC_ID(14)), 61 (MDA_TYPE | XRDC_ID(15)), 62 (MDA_TYPE | XRDC_ID(16)), 63 64 (PAC_TYPE | XRDC_ID(2)), 65 66 (MRC_TYPE | XRDC_ID(6)), 67 (MRC_TYPE | XRDC_ID(8)), 68 (MRC_TYPE | XRDC_ID(10)), 69 70 (MSC_TYPE | XRDC_ID(1)), 71 (MSC_TYPE | XRDC_ID(2)), 72 }; 73 74 uint32_t imx8ulp_pac_slots[] = { 75 61, 23, 53 76 }; 77 78 uint32_t imx8ulp_msc_slots[] = { 79 2, 1, 7 80 }; 81 82 static int xrdc_config_mrc_w0_w1(uint32_t mrc_con, uint32_t region, uint32_t w0, uint32_t size) 83 { 84 85 uint32_t w0_addr, w1_addr; 86 87 w0_addr = XRDC_ADDR + MRC_OFFSET + mrc_con * 0x200 + region * 0x20; 88 w1_addr = w0_addr + 4; 89 90 if ((size % 32) != 0) { 91 return -EINVAL; 92 } 93 94 mmio_write_32(w0_addr, w0 & ~0x1f); 95 mmio_write_32(w1_addr, w0 + size - 1); 96 97 return 0; 98 } 99 100 static int xrdc_config_mrc_w2(uint32_t mrc_con, uint32_t region, uint32_t dxsel_all) 101 { 102 uint32_t w2_addr; 103 104 w2_addr = XRDC_ADDR + MRC_OFFSET + mrc_con * 0x200 + region * 0x20 + 0x8; 105 106 mmio_write_32(w2_addr, dxsel_all); 107 108 return 0; 109 } 110 111 static int xrdc_config_mrc_w3_w4(uint32_t mrc_con, uint32_t region, uint32_t w3, uint32_t w4) 112 { 113 uint32_t w3_addr = XRDC_ADDR + MRC_OFFSET + mrc_con * 0x200 + region * 0x20 + 0xC; 114 uint32_t w4_addr = w3_addr + 4; 115 116 mmio_write_32(w3_addr, w3); 117 mmio_write_32(w4_addr, w4); 118 119 return 0; 120 } 121 122 static int xrdc_config_pac(uint32_t pac, uint32_t index, uint32_t dxacp) 123 { 124 uint32_t w0_addr; 125 uint32_t val; 126 127 if (pac > 2U) { 128 return -EINVAL; 129 } 130 131 /* Skip the PAC slot for XRDC MGR, use Sentinel configuration */ 132 if (pac == XRDC_MGR_PAC_ID && index == XRDC_MGR_PAC_SLOT) { 133 return 0; 134 } 135 136 w0_addr = XRDC_ADDR + 0x1000 + 0x400 * pac + 0x8 * index; 137 138 mmio_write_32(w0_addr, dxacp); 139 140 val = mmio_read_32(w0_addr + 4); 141 mmio_write_32(w0_addr + 4, val | BIT_32(31)); 142 143 return 0; 144 } 145 146 static int xrdc_config_msc(uint32_t msc, uint32_t index, uint32_t dxacp) 147 { 148 uint32_t w0_addr; 149 uint32_t val; 150 151 if (msc > 2) { 152 return -EINVAL; 153 } 154 155 w0_addr = XRDC_ADDR + 0x4000 + 0x400 * msc + 0x8 * index; 156 157 mmio_write_32(w0_addr, dxacp); 158 159 val = mmio_read_32(w0_addr + 4); 160 mmio_write_32(w0_addr + 4, val | BIT_32(31)); 161 162 return 0; 163 } 164 165 static int xrdc_config_mda(uint32_t mda_con, uint32_t dom, enum xrdc_mda_sa sa) 166 { 167 uint32_t w0_addr; 168 uint32_t val; 169 170 w0_addr = XRDC_ADDR + 0x800 + mda_con * 0x20; 171 172 val = mmio_read_32(w0_addr); 173 174 if (val & BIT_32(29)) { 175 mmio_write_32(w0_addr, (val & (~0xFF)) | dom | 176 BIT_32(31) | 0x20 | ((sa & 0x3) << 6)); 177 } else { 178 mmio_write_32(w0_addr, dom | BIT_32(31)); 179 mmio_write_32(w0_addr + 0x4, dom | BIT_32(31)); 180 } 181 182 return 0; 183 } 184 185 static bool xrdc_check_pd(enum xrdc_comp_type type, 186 uint16_t id, enum xrdc_pd_type pd) 187 { 188 unsigned int i, size; 189 uint32_t item = type | XRDC_ID(id); 190 uint32_t *list; 191 192 if (pd == XRDC_HIFI_PD) { 193 size = ARRAY_SIZE(hifi_xrdc_list); 194 list = hifi_xrdc_list; 195 } else if (pd == XRDC_AV_PD) { 196 size = ARRAY_SIZE(av_periph_xrdc_list); 197 list = av_periph_xrdc_list; 198 } else { 199 return false; 200 } 201 202 for (i = 0U; i < size; i++) { 203 if (item == list[i]) { 204 return true; 205 } 206 } 207 208 return false; 209 } 210 211 static bool xrdc_check_lpav(enum xrdc_comp_type type, uint16_t id) 212 { 213 return xrdc_check_pd(type, id, XRDC_AV_PD); 214 } 215 216 static bool xrdc_check_hifi(enum xrdc_comp_type type, uint16_t id) 217 { 218 return xrdc_check_pd(type, id, XRDC_HIFI_PD); 219 } 220 221 static bool xrdc_check_ad(enum xrdc_comp_type type, uint16_t id) 222 { 223 return (!xrdc_check_pd(type, id, XRDC_HIFI_PD) && 224 !xrdc_check_pd(type, id, XRDC_AV_PD)); 225 } 226 227 static int xrdc_apply_config(xrdc_check_func check_func) 228 { 229 unsigned int i, j; 230 uint32_t val; 231 232 for (i = 0U; i < ARRAY_SIZE(imx8ulp_mda); i++) { 233 if (check_func(MDA_TYPE, imx8ulp_mda[i].mda_id)) { 234 xrdc_config_mda(imx8ulp_mda[i].mda_id, 235 imx8ulp_mda[i].did, imx8ulp_mda[i].sa); 236 } 237 } 238 239 for (i = 0U; i < ARRAY_SIZE(imx8ulp_mrc); i++) { 240 if (check_func(MRC_TYPE, imx8ulp_mrc[i].mrc_id)) { 241 xrdc_config_mrc_w0_w1(imx8ulp_mrc[i].mrc_id, 242 imx8ulp_mrc[i].region_id, 243 imx8ulp_mrc[i].region_start, 244 imx8ulp_mrc[i].region_size); 245 246 val = 0; 247 for (j = 0U; j < DID_MAX; j++) { 248 val |= imx8ulp_mrc[i].dsel[j] << (3 * j); 249 } 250 251 xrdc_config_mrc_w2(imx8ulp_mrc[i].mrc_id, imx8ulp_mrc[i].region_id, val); 252 xrdc_config_mrc_w3_w4(imx8ulp_mrc[i].mrc_id, imx8ulp_mrc[i].region_id, 253 0, imx8ulp_mrc[i].accset[0] | (imx8ulp_mrc[i].accset[1] << 16) | BIT_32(31)); 254 } 255 } 256 257 for (i = 0U; i < ARRAY_SIZE(imx8ulp_pdac); i++) { 258 if (check_func(PAC_TYPE, imx8ulp_pdac[i].pac_msc_id)) { 259 val = 0; 260 for (j = 0U; j < DID_MAX; j++) { 261 val |= imx8ulp_pdac[i].dsel[j] << (3 * j); 262 } 263 264 if (imx8ulp_pdac[i].slot_id == PAC_SLOT_ALL) { 265 /* Apply to all slots*/ 266 for (j = 0U; j < imx8ulp_pac_slots[imx8ulp_pdac[i].pac_msc_id]; j++) { 267 xrdc_config_pac(imx8ulp_pdac[i].pac_msc_id, j, val); 268 } 269 } else { 270 if (imx8ulp_pdac[i].slot_id >= imx8ulp_pac_slots[imx8ulp_pdac[i].pac_msc_id]) { 271 return -EINVAL; 272 } 273 274 xrdc_config_pac(imx8ulp_pdac[i].pac_msc_id, imx8ulp_pdac[i].slot_id, val); 275 } 276 } 277 } 278 279 for (i = 0U; i < ARRAY_SIZE(imx8ulp_msc); i++) { 280 if (check_func(MSC_TYPE, imx8ulp_msc[i].pac_msc_id)) { 281 val = 0; 282 for (j = 0U; j < DID_MAX; j++) { 283 val |= imx8ulp_msc[i].dsel[j] << (3 * j); 284 } 285 286 if (imx8ulp_msc[i].slot_id == MSC_SLOT_ALL) { 287 /* Apply to all slots*/ 288 for (j = 0U; j < imx8ulp_msc_slots[imx8ulp_msc[i].pac_msc_id]; j++) { 289 xrdc_config_msc(imx8ulp_msc[i].pac_msc_id, j, val); 290 } 291 } else { 292 if (imx8ulp_msc[i].slot_id >= imx8ulp_msc_slots[imx8ulp_msc[i].pac_msc_id]) { 293 return -EINVAL; 294 } 295 296 xrdc_config_msc(imx8ulp_msc[i].pac_msc_id, imx8ulp_msc[i].slot_id, val); 297 } 298 } 299 } 300 301 return 0; 302 } 303 304 int xrdc_apply_lpav_config(void) 305 { 306 /* Configure PAC2 to allow to access PCC5 */ 307 xrdc_config_pac(2, 39, 0xe00000); 308 309 /* Enable the eDMA2 MP clock for MDA16 access */ 310 mmio_write_32(IMX_PCC5_BASE + 0x0, 0xc0000000); 311 return xrdc_apply_config(xrdc_check_lpav); 312 } 313 314 int xrdc_apply_hifi_config(void) 315 { 316 return xrdc_apply_config(xrdc_check_hifi); 317 } 318 319 int xrdc_apply_apd_config(void) 320 { 321 return xrdc_apply_config(xrdc_check_ad); 322 } 323 324 void xrdc_enable(void) 325 { 326 mmio_write_32(XRDC_ADDR, BIT(14) | BIT(15) | BIT(0)); 327 } 328