Jacky Bai | 7ec9451 | 2023-09-21 14:01:37 +0800 | [diff] [blame] | 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 | /* Enable the eDMA2 MP clock for MDA16 access */ |
| 307 | mmio_write_32(IMX_PCC5_BASE + 0x0, 0xc0000000); |
| 308 | return xrdc_apply_config(xrdc_check_lpav); |
| 309 | } |
| 310 | |
| 311 | int xrdc_apply_hifi_config(void) |
| 312 | { |
| 313 | return xrdc_apply_config(xrdc_check_hifi); |
| 314 | } |
| 315 | |
| 316 | int xrdc_apply_apd_config(void) |
| 317 | { |
| 318 | return xrdc_apply_config(xrdc_check_ad); |
| 319 | } |
| 320 | |
| 321 | void xrdc_enable(void) |
| 322 | { |
| 323 | mmio_write_32(XRDC_ADDR, BIT(14) | BIT(15) | BIT(0)); |
| 324 | } |