Peng Fan | aca2f88 | 2025-04-28 18:37:34 +0800 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0+ |
| 2 | /* |
| 3 | * Copyright 2025 NXP |
| 4 | * |
| 5 | * Peng Fan <peng.fan@nxp.com> |
| 6 | */ |
| 7 | |
| 8 | #include <asm/arch/clock.h> |
| 9 | #include <asm/arch/ddr.h> |
| 10 | #include <asm/arch/sys_proto.h> |
| 11 | #include <asm/armv8/mmu.h> |
| 12 | #include <asm/mach-imx/boot_mode.h> |
| 13 | #include <asm/mach-imx/ele_api.h> |
| 14 | #include <asm/setup.h> |
| 15 | #include <dm/uclass.h> |
| 16 | #include <dm/device.h> |
| 17 | #include <env_internal.h> |
| 18 | #include <fuse.h> |
| 19 | #include <imx_thermal.h> |
| 20 | #include <linux/iopoll.h> |
| 21 | #include <scmi_agent.h> |
| 22 | |
| 23 | DECLARE_GLOBAL_DATA_PTR; |
| 24 | |
| 25 | static rom_passover_t rom_passover_data = {0}; |
| 26 | |
| 27 | uint32_t scmi_get_rom_data(rom_passover_t *rom_data) |
| 28 | { |
| 29 | /* Read ROM passover data */ |
| 30 | struct scmi_rom_passover_get_out out; |
| 31 | struct scmi_msg msg = { |
| 32 | .protocol_id = SCMI_PROTOCOL_ID_IMX_MISC, |
| 33 | .message_id = SCMI_MISC_ROM_PASSOVER_GET, |
| 34 | .in_msg = (u8 *)NULL, |
| 35 | .in_msg_sz = 0, |
| 36 | .out_msg = (u8 *)&out, |
| 37 | .out_msg_sz = sizeof(out), |
| 38 | }; |
| 39 | int ret; |
| 40 | struct udevice *dev; |
| 41 | |
| 42 | ret = uclass_get_device_by_name(UCLASS_CLK, "protocol@14", &dev); |
| 43 | if (ret) |
| 44 | return ret; |
| 45 | |
| 46 | ret = devm_scmi_process_msg(dev, &msg); |
| 47 | if (ret == 0 && out.status == 0) { |
| 48 | memcpy(rom_data, (struct rom_passover_t *)out.passover, sizeof(rom_passover_t)); |
| 49 | } else { |
| 50 | printf("Failed to get ROM passover data, scmi_err = %d, size_of(out) = %ld\n", |
| 51 | out.status, sizeof(out)); |
| 52 | return -EINVAL; |
| 53 | } |
| 54 | |
| 55 | return 0; |
| 56 | } |
| 57 | |
| 58 | #if IS_ENABLED(CONFIG_ENV_IS_IN_MMC) |
| 59 | __weak int board_mmc_get_env_dev(int devno) |
| 60 | { |
| 61 | return devno; |
| 62 | } |
| 63 | |
| 64 | int mmc_get_env_dev(void) |
| 65 | { |
| 66 | int ret; |
| 67 | u16 boot_type; |
| 68 | u8 boot_instance; |
| 69 | |
| 70 | volatile gd_t *pgd = gd; |
| 71 | rom_passover_t *rdata; |
| 72 | |
| 73 | #if IS_ENABLED(CONFIG_XPL_BUILD) |
| 74 | rdata = &rom_passover_data; |
| 75 | #else |
| 76 | rom_passover_t rom_data = {0}; |
| 77 | |
| 78 | if (!pgd->reloc_off) |
| 79 | rdata = &rom_data; |
| 80 | else |
| 81 | rdata = &rom_passover_data; |
| 82 | #endif |
| 83 | if (rdata->tag == 0) { |
| 84 | ret = scmi_get_rom_data(rdata); |
| 85 | if (ret != 0) { |
| 86 | puts("SCMI: failure at rom_boot_info\n"); |
Marek Vasut | 30cf71d | 2025-06-09 21:26:39 +0200 | [diff] [blame^] | 87 | return CONFIG_ENV_MMC_DEVICE_INDEX; |
Peng Fan | aca2f88 | 2025-04-28 18:37:34 +0800 | [diff] [blame] | 88 | } |
| 89 | } |
| 90 | boot_type = rdata->boot_dev_type; |
| 91 | boot_instance = rdata->boot_dev_inst; |
| 92 | set_gd(pgd); |
| 93 | |
| 94 | debug("boot_type %d, instance %d\n", boot_type, boot_instance); |
| 95 | |
| 96 | /* If not boot from sd/mmc, use default value */ |
| 97 | if (boot_type != BOOT_TYPE_SD && boot_type != BOOT_TYPE_MMC) |
Marek Vasut | 30cf71d | 2025-06-09 21:26:39 +0200 | [diff] [blame^] | 98 | return env_get_ulong("mmcdev", 10, CONFIG_ENV_MMC_DEVICE_INDEX); |
Peng Fan | aca2f88 | 2025-04-28 18:37:34 +0800 | [diff] [blame] | 99 | |
| 100 | return board_mmc_get_env_dev(boot_instance); |
| 101 | } |
| 102 | #endif |
| 103 | |
| 104 | u32 get_cpu_speed_grade_hz(void) |
| 105 | { |
| 106 | u32 speed, max_speed; |
| 107 | int ret; |
| 108 | u32 val, word, offset; |
| 109 | |
| 110 | word = 17; |
| 111 | offset = 14; |
| 112 | |
| 113 | ret = fuse_read(word / 8, word % 8, &val); |
| 114 | if (ret) |
| 115 | val = 0; /* If read fuse failed, return as blank fuse */ |
| 116 | |
| 117 | val >>= offset; |
| 118 | val &= 0xf; |
| 119 | |
| 120 | max_speed = 2300000000; |
| 121 | speed = max_speed - val * 100000000; |
| 122 | |
| 123 | if (is_imx95()) |
| 124 | max_speed = 2000000000; |
| 125 | |
| 126 | /* In case the fuse of speed grade not programmed */ |
| 127 | if (speed > max_speed) |
| 128 | speed = max_speed; |
| 129 | |
| 130 | return speed; |
| 131 | } |
| 132 | |
| 133 | u32 get_cpu_temp_grade(int *minc, int *maxc) |
| 134 | { |
| 135 | int ret; |
| 136 | u32 val, word, offset; |
| 137 | |
| 138 | word = 17; |
| 139 | offset = 12; |
| 140 | |
| 141 | ret = fuse_read(word / 8, word % 8, &val); |
| 142 | if (ret) |
| 143 | val = 0; /* If read fuse failed, return as blank fuse */ |
| 144 | |
| 145 | val >>= offset; |
| 146 | val &= 0x3; |
| 147 | |
| 148 | if (minc && maxc) { |
| 149 | if (val == TEMP_AUTOMOTIVE) { |
| 150 | *minc = -40; |
| 151 | *maxc = 125; |
| 152 | } else if (val == TEMP_INDUSTRIAL) { |
| 153 | *minc = -40; |
| 154 | *maxc = 105; |
| 155 | } else if (val == TEMP_EXTCOMMERCIAL) { |
| 156 | *minc = -20; |
| 157 | *maxc = 105; |
| 158 | } else { |
| 159 | *minc = 0; |
| 160 | *maxc = 95; |
| 161 | } |
| 162 | } |
| 163 | return val; |
| 164 | } |
| 165 | |
| 166 | static void set_cpu_info(struct ele_get_info_data *info) |
| 167 | { |
| 168 | gd->arch.soc_rev = info->soc; |
| 169 | gd->arch.lifecycle = info->lc; |
| 170 | memcpy((void *)&gd->arch.uid, &info->uid, 4 * sizeof(u32)); |
| 171 | } |
| 172 | |
| 173 | u32 get_cpu_rev(void) |
| 174 | { |
| 175 | u32 rev = (gd->arch.soc_rev >> 24) - 0xa0; |
| 176 | |
| 177 | return (MXC_CPU_IMX95 << 12) | (CHIP_REV_1_0 + rev); |
| 178 | } |
| 179 | |
| 180 | #define UNLOCK_WORD 0xD928C520 |
| 181 | #define REFRESH_WORD 0xB480A602 |
| 182 | |
| 183 | static void disable_wdog(void __iomem *wdog_base) |
| 184 | { |
| 185 | u32 val_cs = readl(wdog_base + 0x00); |
| 186 | int ret = 0; |
| 187 | |
| 188 | if (!(val_cs & 0x80)) |
| 189 | return; |
| 190 | |
| 191 | /* default is 32bits cmd */ |
| 192 | writel(REFRESH_WORD, (wdog_base + 0x04)); /* Refresh the CNT */ |
| 193 | |
| 194 | if (!(val_cs & 0x800)) { |
| 195 | writel(UNLOCK_WORD, (wdog_base + 0x04)); |
| 196 | while (!(readl(wdog_base + 0x00) & 0x800)) |
| 197 | ; |
| 198 | } |
| 199 | writel(0x0, (wdog_base + 0x0C)); /* Set WIN to 0 */ |
| 200 | writel(0x400, (wdog_base + 0x08)); /* Set timeout to default 0x400 */ |
| 201 | writel(0x2120, (wdog_base + 0x00)); /* Disable it and set update */ |
| 202 | |
| 203 | ret = readl_poll_timeout(wdog_base, val_cs, val_cs & 0x400, 100000); |
| 204 | if (ret < 0) |
| 205 | debug("%s timeout\n", __func__); |
| 206 | } |
| 207 | |
| 208 | static struct mm_region imx9_mem_map[] = { |
| 209 | { |
| 210 | /* M7 TCM */ |
| 211 | .virt = 0x203c0000UL, |
| 212 | .phys = 0x203c0000UL, |
| 213 | .size = 0x80000UL, |
| 214 | .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | |
| 215 | PTE_BLOCK_NON_SHARE | |
| 216 | PTE_BLOCK_PXN | PTE_BLOCK_UXN |
| 217 | }, { |
| 218 | /* OCRAM */ |
| 219 | .virt = 0x20480000UL, |
| 220 | .phys = 0x20480000UL, |
| 221 | .size = 0xA0000UL, |
| 222 | .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | |
| 223 | PTE_BLOCK_OUTER_SHARE |
| 224 | }, { |
| 225 | /* AIPS */ |
| 226 | .virt = 0x40000000UL, |
| 227 | .phys = 0x40000000UL, |
| 228 | .size = 0x40000000UL, |
| 229 | .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | |
| 230 | PTE_BLOCK_NON_SHARE | |
| 231 | PTE_BLOCK_PXN | PTE_BLOCK_UXN |
| 232 | }, { |
| 233 | /* Flexible Serial Peripheral Interface */ |
| 234 | .virt = 0x28000000UL, |
| 235 | .phys = 0x28000000UL, |
| 236 | .size = 0x8000000UL, |
| 237 | .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | |
| 238 | PTE_BLOCK_NON_SHARE | |
| 239 | PTE_BLOCK_PXN | PTE_BLOCK_UXN |
| 240 | }, { |
| 241 | /* DRAM1 */ |
| 242 | .virt = PHYS_SDRAM, |
| 243 | .phys = PHYS_SDRAM, |
| 244 | .size = PHYS_SDRAM_SIZE, |
| 245 | .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | |
| 246 | PTE_BLOCK_OUTER_SHARE |
| 247 | }, { |
| 248 | #ifdef PHYS_SDRAM_2_SIZE |
| 249 | /* DRAM2 */ |
| 250 | .virt = 0x100000000UL, |
| 251 | .phys = 0x100000000UL, |
| 252 | .size = PHYS_SDRAM_2_SIZE, |
| 253 | .attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) | |
| 254 | PTE_BLOCK_OUTER_SHARE |
| 255 | }, { |
| 256 | #endif |
| 257 | /* empty entry to split table entry 5 if needed when TEEs are used */ |
| 258 | 0, |
| 259 | }, { |
| 260 | /* List terminator */ |
| 261 | 0, |
| 262 | } |
| 263 | }; |
| 264 | |
| 265 | struct mm_region *mem_map = imx9_mem_map; |
| 266 | |
| 267 | static unsigned int imx9_find_dram_entry_in_mem_map(void) |
| 268 | { |
| 269 | int i; |
| 270 | |
| 271 | for (i = 0; i < ARRAY_SIZE(imx9_mem_map); i++) |
| 272 | if (imx9_mem_map[i].phys == CFG_SYS_SDRAM_BASE) |
| 273 | return i; |
| 274 | |
| 275 | hang(); /* Entry not found, this must never happen. */ |
| 276 | } |
| 277 | |
| 278 | void enable_caches(void) |
| 279 | { |
| 280 | /* If OPTEE runs, remove OPTEE memory from MMU table to avoid speculative prefetch |
| 281 | * If OPTEE does not run, still update the MMU table according to dram banks structure |
| 282 | * to set correct dram size from board_phys_sdram_size |
| 283 | */ |
| 284 | int i = 0; |
| 285 | /* |
| 286 | * please make sure that entry initial value matches |
| 287 | * imx9_mem_map for DRAM1 |
| 288 | */ |
| 289 | int entry = imx9_find_dram_entry_in_mem_map(); |
| 290 | u64 attrs = imx9_mem_map[entry].attrs; |
| 291 | |
| 292 | while (i < CONFIG_NR_DRAM_BANKS && |
| 293 | entry < ARRAY_SIZE(imx9_mem_map)) { |
| 294 | if (gd->bd->bi_dram[i].start == 0) |
| 295 | break; |
| 296 | imx9_mem_map[entry].phys = gd->bd->bi_dram[i].start; |
| 297 | imx9_mem_map[entry].virt = gd->bd->bi_dram[i].start; |
| 298 | imx9_mem_map[entry].size = gd->bd->bi_dram[i].size; |
| 299 | imx9_mem_map[entry].attrs = attrs; |
| 300 | debug("Added memory mapping (%d): %llx %llx\n", entry, |
| 301 | imx9_mem_map[entry].phys, imx9_mem_map[entry].size); |
| 302 | i++; entry++; |
| 303 | } |
| 304 | |
| 305 | icache_enable(); |
| 306 | dcache_enable(); |
| 307 | } |
| 308 | |
| 309 | __weak int board_phys_sdram_size(phys_size_t *size) |
| 310 | { |
| 311 | phys_size_t start, end; |
| 312 | phys_size_t val; |
| 313 | |
| 314 | if (!size) |
| 315 | return -EINVAL; |
| 316 | |
| 317 | val = readl(REG_DDR_CS0_BNDS); |
| 318 | start = (val >> 16) << 24; |
| 319 | end = (val & 0xFFFF); |
| 320 | end = end ? end + 1 : 0; |
| 321 | end = end << 24; |
| 322 | *size = end - start; |
| 323 | |
| 324 | val = readl(REG_DDR_CS1_BNDS); |
| 325 | start = (val >> 16) << 24; |
| 326 | end = (val & 0xFFFF); |
| 327 | end = end ? end + 1 : 0; |
| 328 | end = end << 24; |
| 329 | *size += end - start; |
| 330 | |
| 331 | return 0; |
| 332 | } |
| 333 | |
| 334 | int dram_init(void) |
| 335 | { |
| 336 | phys_size_t sdram_size; |
| 337 | int ret; |
| 338 | |
| 339 | ret = board_phys_sdram_size(&sdram_size); |
| 340 | if (ret) |
| 341 | return ret; |
| 342 | |
| 343 | /* rom_pointer[1] contains the size of TEE occupies */ |
| 344 | if (rom_pointer[1] && PHYS_SDRAM < (phys_addr_t)rom_pointer[0]) |
| 345 | gd->ram_size = sdram_size - rom_pointer[1]; |
| 346 | else |
| 347 | gd->ram_size = sdram_size; |
| 348 | |
| 349 | return 0; |
| 350 | } |
| 351 | |
| 352 | int dram_init_banksize(void) |
| 353 | { |
| 354 | int bank = 0; |
| 355 | int ret; |
| 356 | phys_size_t sdram_size; |
| 357 | phys_size_t sdram_b1_size, sdram_b2_size; |
| 358 | |
| 359 | ret = board_phys_sdram_size(&sdram_size); |
| 360 | if (ret) |
| 361 | return ret; |
| 362 | |
| 363 | /* Bank 1 can't cross over 4GB space */ |
| 364 | if (sdram_size > 0x80000000) { |
| 365 | sdram_b1_size = 0x100000000UL - PHYS_SDRAM; |
| 366 | sdram_b2_size = sdram_size - sdram_b1_size; |
| 367 | } else { |
| 368 | sdram_b1_size = sdram_size; |
| 369 | sdram_b2_size = 0; |
| 370 | } |
| 371 | |
| 372 | gd->bd->bi_dram[bank].start = PHYS_SDRAM; |
| 373 | if (rom_pointer[1] && PHYS_SDRAM < (phys_addr_t)rom_pointer[0]) { |
| 374 | phys_addr_t optee_start = (phys_addr_t)rom_pointer[0]; |
| 375 | phys_size_t optee_size = (size_t)rom_pointer[1]; |
| 376 | |
| 377 | gd->bd->bi_dram[bank].size = optee_start - gd->bd->bi_dram[bank].start; |
| 378 | if ((optee_start + optee_size) < (PHYS_SDRAM + sdram_b1_size)) { |
| 379 | if (++bank >= CONFIG_NR_DRAM_BANKS) { |
| 380 | puts("CONFIG_NR_DRAM_BANKS is not enough\n"); |
| 381 | return -1; |
| 382 | } |
| 383 | |
| 384 | gd->bd->bi_dram[bank].start = optee_start + optee_size; |
| 385 | gd->bd->bi_dram[bank].size = PHYS_SDRAM + |
| 386 | sdram_b1_size - gd->bd->bi_dram[bank].start; |
| 387 | } |
| 388 | } else { |
| 389 | gd->bd->bi_dram[bank].size = sdram_b1_size; |
| 390 | } |
| 391 | |
| 392 | if (sdram_b2_size) { |
| 393 | if (++bank >= CONFIG_NR_DRAM_BANKS) { |
| 394 | puts("CONFIG_NR_DRAM_BANKS is not enough for SDRAM_2\n"); |
| 395 | return -1; |
| 396 | } |
| 397 | gd->bd->bi_dram[bank].start = 0x100000000UL; |
| 398 | gd->bd->bi_dram[bank].size = sdram_b2_size; |
| 399 | } |
| 400 | |
| 401 | return 0; |
| 402 | } |
| 403 | |
| 404 | phys_size_t get_effective_memsize(void) |
| 405 | { |
| 406 | int ret; |
| 407 | phys_size_t sdram_size; |
| 408 | phys_size_t sdram_b1_size; |
| 409 | |
| 410 | ret = board_phys_sdram_size(&sdram_size); |
| 411 | if (!ret) { |
| 412 | /* Bank 1 can't cross over 4GB space */ |
| 413 | if (sdram_size > 0x80000000) |
| 414 | sdram_b1_size = 0x100000000UL - PHYS_SDRAM; |
| 415 | else |
| 416 | sdram_b1_size = sdram_size; |
| 417 | |
| 418 | if (rom_pointer[1]) { |
| 419 | /* We will relocate u-boot to Top of dram1. Tee position has three cases: |
| 420 | * 1. At the top of dram1, Then return the size removed optee size. |
| 421 | * 2. In the middle of dram1, return the size of dram1. |
| 422 | * 3. Not in the scope of dram1, return the size of dram1. |
| 423 | */ |
| 424 | if ((rom_pointer[0] + rom_pointer[1]) == (PHYS_SDRAM + sdram_b1_size)) |
| 425 | return ((phys_addr_t)rom_pointer[0] - PHYS_SDRAM); |
| 426 | } |
| 427 | |
| 428 | return sdram_b1_size; |
| 429 | } else { |
| 430 | return PHYS_SDRAM_SIZE; |
| 431 | } |
| 432 | } |
| 433 | |
| 434 | void imx_get_mac_from_fuse(int dev_id, unsigned char *mac) |
| 435 | { |
| 436 | u32 val[2] = {}; |
| 437 | int ret, num_of_macs; |
| 438 | |
| 439 | ret = fuse_read(40, 5, &val[0]); |
| 440 | if (ret) |
| 441 | goto err; |
| 442 | |
| 443 | ret = fuse_read(40, 6, &val[1]); |
| 444 | if (ret) |
| 445 | goto err; |
| 446 | |
| 447 | num_of_macs = (val[1] >> 24) & 0xff; |
| 448 | if (num_of_macs <= (dev_id * 3)) { |
| 449 | printf("WARNING: no MAC address assigned for MAC%d\n", dev_id); |
| 450 | goto err; |
| 451 | } |
| 452 | |
| 453 | mac[0] = val[0] & 0xff; |
| 454 | mac[1] = (val[0] >> 8) & 0xff; |
| 455 | mac[2] = (val[0] >> 16) & 0xff; |
| 456 | mac[3] = (val[0] >> 24) & 0xff; |
| 457 | mac[4] = val[1] & 0xff; |
| 458 | mac[5] = (val[1] >> 8) & 0xff; |
| 459 | if (dev_id == 1) |
| 460 | mac[5] = mac[5] + 3; |
| 461 | if (dev_id == 2) |
| 462 | mac[5] = mac[5] + 6; |
| 463 | |
| 464 | debug("%s: MAC%d: %pM\n", __func__, dev_id, mac); |
| 465 | return; |
| 466 | err: |
| 467 | memset(mac, 0, 6); |
| 468 | printf("%s: fuse read err: %d\n", __func__, ret); |
| 469 | } |
| 470 | |
| 471 | const char *get_imx_type(u32 imxtype) |
| 472 | { |
| 473 | switch (imxtype) { |
| 474 | case MXC_CPU_IMX95: |
| 475 | return "95";/* iMX95 FULL */ |
| 476 | default: |
| 477 | return "??"; |
| 478 | } |
| 479 | } |
| 480 | |
| 481 | void build_info(void) |
| 482 | { |
| 483 | u32 fw_version, sha1, res = 0, status; |
| 484 | int ret; |
| 485 | |
| 486 | printf("\nBuildInfo:\n"); |
| 487 | |
| 488 | ret = ele_get_fw_status(&status, &res); |
| 489 | if (ret) { |
| 490 | printf(" - ELE firmware status failed %d, 0x%x\n", ret, res); |
| 491 | } else if ((status & 0xff) == 1) { |
| 492 | ret = ele_get_fw_version(&fw_version, &sha1, &res); |
| 493 | if (ret) { |
| 494 | printf(" - ELE firmware version failed %d, 0x%x\n", ret, res); |
| 495 | } else { |
| 496 | printf(" - ELE firmware version %u.%u.%u-%x", |
| 497 | (fw_version & (0x00ff0000)) >> 16, |
| 498 | (fw_version & (0x0000fff0)) >> 4, |
| 499 | (fw_version & (0x0000000f)), sha1); |
| 500 | ((fw_version & (0x80000000)) >> 31) == 1 ? puts("-dirty\n") : puts("\n"); |
| 501 | } |
| 502 | } else { |
| 503 | printf(" - ELE firmware not included\n"); |
| 504 | } |
| 505 | puts("\n"); |
| 506 | } |
| 507 | |
| 508 | int arch_misc_init(void) |
| 509 | { |
| 510 | build_info(); |
| 511 | return 0; |
| 512 | } |
| 513 | |
| 514 | #if defined(CONFIG_OF_BOARD_FIXUP) && !defined(CONFIG_SPL_BUILD) |
| 515 | int board_fix_fdt(void *fdt) |
| 516 | { |
| 517 | return 0; |
| 518 | } |
| 519 | #endif |
| 520 | |
| 521 | int ft_system_setup(void *blob, struct bd_info *bd) |
| 522 | { |
| 523 | return 0; |
| 524 | } |
| 525 | |
| 526 | #if IS_ENABLED(CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG) |
| 527 | void get_board_serial(struct tag_serialnr *serialnr) |
| 528 | { |
| 529 | printf("UID: %08x%08x%08x%08x\n", __be32_to_cpu(gd->arch.uid[0]), |
| 530 | __be32_to_cpu(gd->arch.uid[1]), __be32_to_cpu(gd->arch.uid[2]), |
| 531 | __be32_to_cpu(gd->arch.uid[3])); |
| 532 | |
| 533 | serialnr->low = __be32_to_cpu(gd->arch.uid[1]); |
| 534 | serialnr->high = __be32_to_cpu(gd->arch.uid[0]); |
| 535 | } |
| 536 | #endif |
| 537 | |
| 538 | static void gpio_reset(ulong gpio_base) |
| 539 | { |
| 540 | writel(0, gpio_base + 0x10); |
| 541 | writel(0, gpio_base + 0x14); |
| 542 | writel(0, gpio_base + 0x18); |
| 543 | writel(0, gpio_base + 0x1c); |
| 544 | } |
| 545 | |
| 546 | int arch_cpu_init(void) |
| 547 | { |
| 548 | if (IS_ENABLED(CONFIG_SPL_BUILD)) { |
| 549 | disable_wdog((void __iomem *)WDG3_BASE_ADDR); |
| 550 | disable_wdog((void __iomem *)WDG4_BASE_ADDR); |
| 551 | |
| 552 | gpio_reset(GPIO2_BASE_ADDR); |
| 553 | gpio_reset(GPIO3_BASE_ADDR); |
| 554 | gpio_reset(GPIO4_BASE_ADDR); |
| 555 | gpio_reset(GPIO5_BASE_ADDR); |
| 556 | } |
| 557 | |
| 558 | return 0; |
| 559 | } |
| 560 | |
| 561 | int imx9_probe_mu(void) |
| 562 | { |
| 563 | struct udevice *dev; |
| 564 | int ret; |
| 565 | u32 res; |
| 566 | struct ele_get_info_data info; |
| 567 | |
| 568 | ret = uclass_get_device_by_driver(UCLASS_SCMI_AGENT, DM_DRIVER_GET(scmi_mbox), &dev); |
| 569 | if (ret) |
| 570 | return ret; |
| 571 | |
| 572 | ret = uclass_get_device_by_name(UCLASS_CLK, "protocol@14", &dev); |
| 573 | if (ret) |
| 574 | return ret; |
| 575 | |
| 576 | ret = devm_scmi_of_get_channel(dev); |
| 577 | if (ret) |
| 578 | return ret; |
| 579 | |
| 580 | ret = uclass_get_device_by_name(UCLASS_PINCTRL, "protocol@19", &dev); |
| 581 | if (ret) |
| 582 | return ret; |
| 583 | |
| 584 | #if defined(CONFIG_SPL_BUILD) |
| 585 | ret = uclass_get_device_by_name(UCLASS_MISC, "mailbox@47530000", &dev); |
| 586 | #else |
| 587 | ret = uclass_get_device_by_name(UCLASS_MISC, "mailbox@47550000", &dev); |
| 588 | #endif |
| 589 | if (ret) |
| 590 | return ret; |
| 591 | |
| 592 | if (gd->flags & GD_FLG_RELOC) |
| 593 | return 0; |
| 594 | |
| 595 | ret = ele_get_info(&info, &res); |
| 596 | if (ret) |
| 597 | return ret; |
| 598 | |
| 599 | set_cpu_info(&info); |
| 600 | |
| 601 | return 0; |
| 602 | } |
| 603 | |
| 604 | EVENT_SPY_SIMPLE(EVT_DM_POST_INIT_F, imx9_probe_mu); |
| 605 | EVENT_SPY_SIMPLE(EVT_DM_POST_INIT_R, imx9_probe_mu); |
| 606 | |
| 607 | int timer_init(void) |
| 608 | { |
| 609 | gd->arch.tbl = 0; |
| 610 | gd->arch.tbu = 0; |
| 611 | |
| 612 | if (IS_ENABLED(CONFIG_SPL_BUILD)) { |
| 613 | unsigned long freq = 24000000; |
| 614 | |
| 615 | asm volatile("msr cntfrq_el0, %0" : : "r" (freq) : "memory"); |
| 616 | |
| 617 | /* Clear the compare frame interrupt */ |
| 618 | unsigned long sctr_cmpcr_addr = SYSCNT_CMP_BASE_ADDR + 0x2c; |
| 619 | unsigned long sctr_cmpcr = readl(sctr_cmpcr_addr); |
| 620 | |
| 621 | sctr_cmpcr &= ~0x1; |
| 622 | writel(sctr_cmpcr, sctr_cmpcr_addr); |
| 623 | } |
| 624 | |
| 625 | return 0; |
| 626 | } |
| 627 | |
| 628 | enum env_location env_get_location(enum env_operation op, int prio) |
| 629 | { |
| 630 | enum boot_device dev = get_boot_device(); |
| 631 | enum env_location env_loc = ENVL_UNKNOWN; |
| 632 | |
| 633 | if (prio) |
| 634 | return env_loc; |
| 635 | |
| 636 | switch (dev) { |
| 637 | case QSPI_BOOT: |
| 638 | env_loc = ENVL_SPI_FLASH; |
| 639 | break; |
| 640 | case SD1_BOOT: |
| 641 | case SD2_BOOT: |
| 642 | case SD3_BOOT: |
| 643 | case MMC1_BOOT: |
| 644 | case MMC2_BOOT: |
| 645 | case MMC3_BOOT: |
| 646 | env_loc = ENVL_MMC; |
| 647 | break; |
| 648 | default: |
| 649 | env_loc = ENVL_NOWHERE; |
| 650 | break; |
| 651 | } |
| 652 | |
| 653 | return env_loc; |
| 654 | } |
| 655 | |
| 656 | enum imx9_soc_voltage_mode soc_target_voltage_mode(void) |
| 657 | { |
| 658 | u32 speed = get_cpu_speed_grade_hz(); |
| 659 | enum imx9_soc_voltage_mode voltage = VOLT_OVER_DRIVE; |
| 660 | |
| 661 | if (is_imx95()) { |
| 662 | if (speed == 2000000000) |
| 663 | voltage = VOLT_SUPER_OVER_DRIVE; |
| 664 | else if (speed == 1800000000) |
| 665 | voltage = VOLT_OVER_DRIVE; |
| 666 | else if (speed == 1400000000) |
| 667 | voltage = VOLT_NOMINAL_DRIVE; |
| 668 | else /* boot not support low drive mode according to AS */ |
| 669 | printf("Unexpected A55 freq %u, default to OD\n", speed); |
| 670 | } |
| 671 | |
| 672 | return voltage; |
| 673 | } |
| 674 | |
| 675 | #if IS_ENABLED(CONFIG_SCMI_FIRMWARE) |
| 676 | enum boot_device get_boot_device(void) |
| 677 | { |
| 678 | volatile gd_t *pgd = gd; |
| 679 | int ret; |
| 680 | u16 boot_type; |
| 681 | u8 boot_instance; |
| 682 | enum boot_device boot_dev = 0; |
| 683 | rom_passover_t *rdata; |
| 684 | |
| 685 | #if IS_ENABLED(CONFIG_SPL_BUILD) |
| 686 | rdata = &rom_passover_data; |
| 687 | #else |
| 688 | rom_passover_t rom_data = {0}; |
| 689 | |
| 690 | if (pgd->reloc_off == 0) |
| 691 | rdata = &rom_data; |
| 692 | else |
| 693 | rdata = &rom_passover_data; |
| 694 | #endif |
| 695 | if (rdata->tag == 0) { |
| 696 | ret = scmi_get_rom_data(rdata); |
| 697 | if (ret != 0) { |
| 698 | puts("SCMI: failure at rom_boot_info\n"); |
| 699 | return -1; |
| 700 | } |
| 701 | } |
| 702 | boot_type = rdata->boot_dev_type; |
| 703 | boot_instance = rdata->boot_dev_inst; |
| 704 | |
| 705 | set_gd(pgd); |
| 706 | |
| 707 | switch (boot_type) { |
| 708 | case BT_DEV_TYPE_SD: |
| 709 | boot_dev = boot_instance + SD1_BOOT; |
| 710 | break; |
| 711 | case BT_DEV_TYPE_MMC: |
| 712 | boot_dev = boot_instance + MMC1_BOOT; |
| 713 | break; |
| 714 | case BT_DEV_TYPE_NAND: |
| 715 | boot_dev = NAND_BOOT; |
| 716 | break; |
| 717 | case BT_DEV_TYPE_FLEXSPINOR: |
| 718 | boot_dev = QSPI_BOOT; |
| 719 | break; |
| 720 | case BT_DEV_TYPE_USB: |
| 721 | boot_dev = boot_instance + USB_BOOT; |
| 722 | if (IS_ENABLED(CONFIG_IMX95)) |
| 723 | boot_dev -= 3; //iMX95 usb instance start at 3 |
| 724 | break; |
| 725 | default: |
| 726 | break; |
| 727 | } |
| 728 | |
| 729 | return boot_dev; |
| 730 | } |
| 731 | #endif |
Ye Li | 87178ed | 2025-04-28 18:37:36 +0800 | [diff] [blame] | 732 | |
| 733 | bool arch_check_dst_in_secure(void *start, ulong size) |
| 734 | { |
| 735 | ulong ns_end = CFG_SYS_SDRAM_BASE + PHYS_SDRAM_SIZE; |
| 736 | #ifdef PHYS_SDRAM_2_SIZE |
| 737 | ns_end += PHYS_SDRAM_2_SIZE; |
| 738 | #endif |
| 739 | |
| 740 | if ((ulong)start < CFG_SYS_SDRAM_BASE || (ulong)start + size > ns_end) |
| 741 | return true; |
| 742 | |
| 743 | return false; |
| 744 | } |
| 745 | |
| 746 | void *arch_get_container_trampoline(void) |
| 747 | { |
| 748 | return (void *)((ulong)CFG_SYS_SDRAM_BASE + PHYS_SDRAM_SIZE - SZ_16M); |
| 749 | } |