17b3bd9a7SJ. German Rivera /* 27b3bd9a7SJ. German Rivera * Copyright (C) 2014 Freescale Semiconductor 37b3bd9a7SJ. German Rivera * 47b3bd9a7SJ. German Rivera * SPDX-License-Identifier: GPL-2.0+ 57b3bd9a7SJ. German Rivera */ 67b3bd9a7SJ. German Rivera 77b3bd9a7SJ. German Rivera #include <errno.h> 87b3bd9a7SJ. German Rivera #include <asm/io.h> 97b3bd9a7SJ. German Rivera #include <fsl-mc/fsl_mc.h> 107b3bd9a7SJ. German Rivera #include <fsl-mc/fsl_mc_sys.h> 117b3bd9a7SJ. German Rivera #include <fsl-mc/fsl_dpmng.h> 12*422cb08aSBhupesh Sharma #include <fsl_debug_server.h> 137b3bd9a7SJ. German Rivera 147b3bd9a7SJ. German Rivera DECLARE_GLOBAL_DATA_PTR; 157b3bd9a7SJ. German Rivera static int mc_boot_status; 167b3bd9a7SJ. German Rivera 177b3bd9a7SJ. German Rivera /** 187b3bd9a7SJ. German Rivera * Copying MC firmware or DPL image to DDR 197b3bd9a7SJ. German Rivera */ 207b3bd9a7SJ. German Rivera static int mc_copy_image(const char *title, 217b3bd9a7SJ. German Rivera u64 image_addr, u32 image_size, u64 mc_ram_addr) 227b3bd9a7SJ. German Rivera { 237b3bd9a7SJ. German Rivera debug("%s copied to address %p\n", title, (void *)mc_ram_addr); 247b3bd9a7SJ. German Rivera memcpy((void *)mc_ram_addr, (void *)image_addr, image_size); 257b3bd9a7SJ. German Rivera return 0; 267b3bd9a7SJ. German Rivera } 277b3bd9a7SJ. German Rivera 287b3bd9a7SJ. German Rivera /** 297b3bd9a7SJ. German Rivera * MC firmware FIT image parser checks if the image is in FIT 307b3bd9a7SJ. German Rivera * format, verifies integrity of the image and calculates 317b3bd9a7SJ. German Rivera * raw image address and size values. 327b3bd9a7SJ. German Rivera * Returns 0 on success and a negative errno on error. 337b3bd9a7SJ. German Rivera * task fail. 347b3bd9a7SJ. German Rivera **/ 357b3bd9a7SJ. German Rivera int parse_mc_firmware_fit_image(const void **raw_image_addr, 367b3bd9a7SJ. German Rivera size_t *raw_image_size) 377b3bd9a7SJ. German Rivera { 387b3bd9a7SJ. German Rivera int format; 397b3bd9a7SJ. German Rivera void *fit_hdr; 407b3bd9a7SJ. German Rivera int node_offset; 417b3bd9a7SJ. German Rivera const void *data; 427b3bd9a7SJ. German Rivera size_t size; 437b3bd9a7SJ. German Rivera const char *uname = "firmware"; 447b3bd9a7SJ. German Rivera 457b3bd9a7SJ. German Rivera /* Check if the image is in NOR flash */ 467b3bd9a7SJ. German Rivera #ifdef CONFIG_SYS_LS_MC_FW_IN_NOR 477b3bd9a7SJ. German Rivera fit_hdr = (void *)CONFIG_SYS_LS_MC_FW_ADDR; 487b3bd9a7SJ. German Rivera #else 497b3bd9a7SJ. German Rivera #error "No CONFIG_SYS_LS_MC_FW_IN_xxx defined" 507b3bd9a7SJ. German Rivera #endif 517b3bd9a7SJ. German Rivera 527b3bd9a7SJ. German Rivera /* Check if Image is in FIT format */ 537b3bd9a7SJ. German Rivera format = genimg_get_format(fit_hdr); 547b3bd9a7SJ. German Rivera 557b3bd9a7SJ. German Rivera if (format != IMAGE_FORMAT_FIT) { 567b3bd9a7SJ. German Rivera printf("fsl-mc: ERROR: Bad firmware image (not a FIT image)\n"); 577b3bd9a7SJ. German Rivera return -EINVAL; 587b3bd9a7SJ. German Rivera } 597b3bd9a7SJ. German Rivera 607b3bd9a7SJ. German Rivera if (!fit_check_format(fit_hdr)) { 617b3bd9a7SJ. German Rivera printf("fsl-mc: ERROR: Bad firmware image (bad FIT header)\n"); 627b3bd9a7SJ. German Rivera return -EINVAL; 637b3bd9a7SJ. German Rivera } 647b3bd9a7SJ. German Rivera 657b3bd9a7SJ. German Rivera node_offset = fit_image_get_node(fit_hdr, uname); 667b3bd9a7SJ. German Rivera 677b3bd9a7SJ. German Rivera if (node_offset < 0) { 687b3bd9a7SJ. German Rivera printf("fsl-mc: ERROR: Bad firmware image (missing subimage)\n"); 697b3bd9a7SJ. German Rivera return -ENOENT; 707b3bd9a7SJ. German Rivera } 717b3bd9a7SJ. German Rivera 727b3bd9a7SJ. German Rivera /* Verify MC firmware image */ 737b3bd9a7SJ. German Rivera if (!(fit_image_verify(fit_hdr, node_offset))) { 747b3bd9a7SJ. German Rivera printf("fsl-mc: ERROR: Bad firmware image (bad CRC)\n"); 757b3bd9a7SJ. German Rivera return -EINVAL; 767b3bd9a7SJ. German Rivera } 777b3bd9a7SJ. German Rivera 787b3bd9a7SJ. German Rivera /* Get address and size of raw image */ 797b3bd9a7SJ. German Rivera fit_image_get_data(fit_hdr, node_offset, &data, &size); 807b3bd9a7SJ. German Rivera 817b3bd9a7SJ. German Rivera *raw_image_addr = data; 827b3bd9a7SJ. German Rivera *raw_image_size = size; 837b3bd9a7SJ. German Rivera 847b3bd9a7SJ. German Rivera return 0; 857b3bd9a7SJ. German Rivera } 867b3bd9a7SJ. German Rivera 877b3bd9a7SJ. German Rivera int mc_init(bd_t *bis) 887b3bd9a7SJ. German Rivera { 897b3bd9a7SJ. German Rivera int error = 0; 907b3bd9a7SJ. German Rivera int timeout = 200000; 917b3bd9a7SJ. German Rivera struct mc_ccsr_registers __iomem *mc_ccsr_regs = MC_CCSR_BASE_ADDR; 927b3bd9a7SJ. German Rivera u64 mc_ram_addr; 937b3bd9a7SJ. German Rivera u64 mc_dpl_offset; 947b3bd9a7SJ. German Rivera u32 reg_gsr; 957b3bd9a7SJ. German Rivera u32 mc_fw_boot_status; 967b3bd9a7SJ. German Rivera void *dpl_fdt_hdr; 977b3bd9a7SJ. German Rivera int dpl_size; 987b3bd9a7SJ. German Rivera const void *raw_image_addr; 997b3bd9a7SJ. German Rivera size_t raw_image_size = 0; 1007b3bd9a7SJ. German Rivera struct fsl_mc_io mc_io; 1017b3bd9a7SJ. German Rivera int portal_id; 1027b3bd9a7SJ. German Rivera struct mc_version mc_ver_info; 1037b3bd9a7SJ. German Rivera 1047b3bd9a7SJ. German Rivera /* 1057b3bd9a7SJ. German Rivera * The MC private DRAM block was already carved at the end of DRAM 1067b3bd9a7SJ. German Rivera * by board_init_f() using CONFIG_SYS_MEM_TOP_HIDE: 1077b3bd9a7SJ. German Rivera */ 1087b3bd9a7SJ. German Rivera if (gd->bd->bi_dram[1].start) { 1097b3bd9a7SJ. German Rivera mc_ram_addr = 1107b3bd9a7SJ. German Rivera gd->bd->bi_dram[1].start + gd->bd->bi_dram[1].size; 1117b3bd9a7SJ. German Rivera } else { 1127b3bd9a7SJ. German Rivera mc_ram_addr = 1137b3bd9a7SJ. German Rivera gd->bd->bi_dram[0].start + gd->bd->bi_dram[0].size; 1147b3bd9a7SJ. German Rivera } 1157b3bd9a7SJ. German Rivera 116*422cb08aSBhupesh Sharma #ifdef CONFIG_FSL_DEBUG_SERVER 117*422cb08aSBhupesh Sharma mc_ram_addr -= debug_server_get_dram_block_size(); 118*422cb08aSBhupesh Sharma #endif 1197b3bd9a7SJ. German Rivera /* 1207b3bd9a7SJ. German Rivera * Management Complex cores should be held at reset out of POR. 1217b3bd9a7SJ. German Rivera * U-boot should be the first software to touch MC. To be safe, 1227b3bd9a7SJ. German Rivera * we reset all cores again by setting GCR1 to 0. It doesn't do 1237b3bd9a7SJ. German Rivera * anything if they are held at reset. After we setup the firmware 1247b3bd9a7SJ. German Rivera * we kick off MC by deasserting the reset bit for core 0, and 1257b3bd9a7SJ. German Rivera * deasserting the reset bits for Command Portal Managers. 1267b3bd9a7SJ. German Rivera * The stop bits are not touched here. They are used to stop the 1277b3bd9a7SJ. German Rivera * cores when they are active. Setting stop bits doesn't stop the 1287b3bd9a7SJ. German Rivera * cores from fetching instructions when they are released from 1297b3bd9a7SJ. German Rivera * reset. 1307b3bd9a7SJ. German Rivera */ 1317b3bd9a7SJ. German Rivera out_le32(&mc_ccsr_regs->reg_gcr1, 0); 1327b3bd9a7SJ. German Rivera dmb(); 1337b3bd9a7SJ. German Rivera 1347b3bd9a7SJ. German Rivera error = parse_mc_firmware_fit_image(&raw_image_addr, &raw_image_size); 1357b3bd9a7SJ. German Rivera if (error != 0) 1367b3bd9a7SJ. German Rivera goto out; 1377b3bd9a7SJ. German Rivera /* 1387b3bd9a7SJ. German Rivera * Load the MC FW at the beginning of the MC private DRAM block: 1397b3bd9a7SJ. German Rivera */ 1407b3bd9a7SJ. German Rivera mc_copy_image("MC Firmware", 1417b3bd9a7SJ. German Rivera (u64)raw_image_addr, raw_image_size, mc_ram_addr); 1427b3bd9a7SJ. German Rivera 1437b3bd9a7SJ. German Rivera /* 1447b3bd9a7SJ. German Rivera * Get address and size of the DPL blob stored in flash: 1457b3bd9a7SJ. German Rivera */ 1467b3bd9a7SJ. German Rivera #ifdef CONFIG_SYS_LS_MC_DPL_IN_NOR 1477b3bd9a7SJ. German Rivera dpl_fdt_hdr = (void *)CONFIG_SYS_LS_MC_DPL_ADDR; 1487b3bd9a7SJ. German Rivera #else 1497b3bd9a7SJ. German Rivera #error "No CONFIG_SYS_LS_MC_DPL_IN_xxx defined" 1507b3bd9a7SJ. German Rivera #endif 1517b3bd9a7SJ. German Rivera 1527b3bd9a7SJ. German Rivera error = fdt_check_header(dpl_fdt_hdr); 1537b3bd9a7SJ. German Rivera if (error != 0) { 1547b3bd9a7SJ. German Rivera printf("fsl-mc: ERROR: Bad DPL image (bad header)\n"); 1557b3bd9a7SJ. German Rivera goto out; 1567b3bd9a7SJ. German Rivera } 1577b3bd9a7SJ. German Rivera 1587b3bd9a7SJ. German Rivera dpl_size = fdt_totalsize(dpl_fdt_hdr); 1597b3bd9a7SJ. German Rivera if (dpl_size > CONFIG_SYS_LS_MC_DPL_MAX_LENGTH) { 1607b3bd9a7SJ. German Rivera printf("fsl-mc: ERROR: Bad DPL image (too large: %d)\n", 1617b3bd9a7SJ. German Rivera dpl_size); 1627b3bd9a7SJ. German Rivera error = -EINVAL; 1637b3bd9a7SJ. German Rivera goto out; 1647b3bd9a7SJ. German Rivera } 1657b3bd9a7SJ. German Rivera 1667b3bd9a7SJ. German Rivera /* 1677b3bd9a7SJ. German Rivera * Calculate offset in the MC private DRAM block at which the MC DPL 1687b3bd9a7SJ. German Rivera * blob is to be placed: 1697b3bd9a7SJ. German Rivera */ 1707b3bd9a7SJ. German Rivera #ifdef CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET 1717b3bd9a7SJ. German Rivera BUILD_BUG_ON((CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET & 0x3) != 0 || 1727b3bd9a7SJ. German Rivera CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET > 0xffffffff); 1737b3bd9a7SJ. German Rivera 1747b3bd9a7SJ. German Rivera mc_dpl_offset = CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET; 1757b3bd9a7SJ. German Rivera #else 1767b3bd9a7SJ. German Rivera mc_dpl_offset = mc_get_dram_block_size() - 1777b3bd9a7SJ. German Rivera roundup(CONFIG_SYS_LS_MC_DPL_MAX_LENGTH, 4096); 1787b3bd9a7SJ. German Rivera 1797b3bd9a7SJ. German Rivera if ((mc_dpl_offset & 0x3) != 0 || mc_dpl_offset > 0xffffffff) { 1807b3bd9a7SJ. German Rivera printf("%s: Invalid MC DPL offset: %llu\n", 1817b3bd9a7SJ. German Rivera __func__, mc_dpl_offset); 1827b3bd9a7SJ. German Rivera error = -EINVAL; 1837b3bd9a7SJ. German Rivera goto out; 1847b3bd9a7SJ. German Rivera } 1857b3bd9a7SJ. German Rivera #endif 1867b3bd9a7SJ. German Rivera 1877b3bd9a7SJ. German Rivera /* 1887b3bd9a7SJ. German Rivera * Load the MC DPL blob at the far end of the MC private DRAM block: 1897b3bd9a7SJ. German Rivera * 1907b3bd9a7SJ. German Rivera * TODO: Should we place the DPL at a different location to match 1917b3bd9a7SJ. German Rivera * assumptions of MC firmware about its memory layout? 1927b3bd9a7SJ. German Rivera */ 1937b3bd9a7SJ. German Rivera mc_copy_image("MC DPL blob", 1947b3bd9a7SJ. German Rivera (u64)dpl_fdt_hdr, dpl_size, mc_ram_addr + mc_dpl_offset); 1957b3bd9a7SJ. German Rivera 1967b3bd9a7SJ. German Rivera debug("mc_ccsr_regs %p\n", mc_ccsr_regs); 1977b3bd9a7SJ. German Rivera 1987b3bd9a7SJ. German Rivera /* 1997b3bd9a7SJ. German Rivera * Tell MC where the MC Firmware image was loaded in DDR: 2007b3bd9a7SJ. German Rivera */ 2017b3bd9a7SJ. German Rivera out_le32(&mc_ccsr_regs->reg_mcfbalr, (u32)mc_ram_addr); 2027b3bd9a7SJ. German Rivera out_le32(&mc_ccsr_regs->reg_mcfbahr, (u32)((u64)mc_ram_addr >> 32)); 2037b3bd9a7SJ. German Rivera out_le32(&mc_ccsr_regs->reg_mcfapr, MCFAPR_BYPASS_ICID_MASK); 2047b3bd9a7SJ. German Rivera 2057b3bd9a7SJ. German Rivera /* 2067b3bd9a7SJ. German Rivera * Tell MC where the DPL blob was loaded in DDR, by indicating 2077b3bd9a7SJ. German Rivera * its offset relative to the beginning of the DDR block 2087b3bd9a7SJ. German Rivera * allocated to the MC firmware. The MC firmware is responsible 2097b3bd9a7SJ. German Rivera * for checking that there is no overlap between the DPL blob 2107b3bd9a7SJ. German Rivera * and the runtime heap and stack of the MC firmware itself. 2117b3bd9a7SJ. German Rivera * 2127b3bd9a7SJ. German Rivera * NOTE: bits [31:2] of this offset need to be stored in bits [29:0] of 2137b3bd9a7SJ. German Rivera * the GSR MC CCSR register. So, this offset is assumed to be 4-byte 2147b3bd9a7SJ. German Rivera * aligned. 2157b3bd9a7SJ. German Rivera * Care must be taken not to write 1s into bits 31 and 30 of the GSR in 2167b3bd9a7SJ. German Rivera * this case as the SoC COP or PIC will be signaled. 2177b3bd9a7SJ. German Rivera */ 2187b3bd9a7SJ. German Rivera out_le32(&mc_ccsr_regs->reg_gsr, (u32)(mc_dpl_offset >> 2)); 2197b3bd9a7SJ. German Rivera 2207b3bd9a7SJ. German Rivera printf("\nfsl-mc: Booting Management Complex ...\n"); 2217b3bd9a7SJ. German Rivera 2227b3bd9a7SJ. German Rivera /* 2237b3bd9a7SJ. German Rivera * Deassert reset and release MC core 0 to run 2247b3bd9a7SJ. German Rivera */ 2257b3bd9a7SJ. German Rivera out_le32(&mc_ccsr_regs->reg_gcr1, GCR1_P1_DE_RST | GCR1_M_ALL_DE_RST); 2267b3bd9a7SJ. German Rivera dmb(); 2277b3bd9a7SJ. German Rivera debug("Polling mc_ccsr_regs->reg_gsr ...\n"); 2287b3bd9a7SJ. German Rivera 2297b3bd9a7SJ. German Rivera for (;;) { 2307b3bd9a7SJ. German Rivera reg_gsr = in_le32(&mc_ccsr_regs->reg_gsr); 2317b3bd9a7SJ. German Rivera mc_fw_boot_status = (reg_gsr & GSR_FS_MASK); 2327b3bd9a7SJ. German Rivera if (mc_fw_boot_status & 0x1) 2337b3bd9a7SJ. German Rivera break; 2347b3bd9a7SJ. German Rivera 2357b3bd9a7SJ. German Rivera udelay(1000); /* throttle polling */ 2367b3bd9a7SJ. German Rivera if (timeout-- <= 0) 2377b3bd9a7SJ. German Rivera break; 2387b3bd9a7SJ. German Rivera } 2397b3bd9a7SJ. German Rivera 2407b3bd9a7SJ. German Rivera if (timeout <= 0) { 2417b3bd9a7SJ. German Rivera printf("fsl-mc: timeout booting management complex firmware\n"); 2427b3bd9a7SJ. German Rivera 2437b3bd9a7SJ. German Rivera /* TODO: Get an error status from an MC CCSR register */ 2447b3bd9a7SJ. German Rivera error = -ETIMEDOUT; 2457b3bd9a7SJ. German Rivera goto out; 2467b3bd9a7SJ. German Rivera } 2477b3bd9a7SJ. German Rivera 2487b3bd9a7SJ. German Rivera if (mc_fw_boot_status != 0x1) { 2497b3bd9a7SJ. German Rivera /* 2507b3bd9a7SJ. German Rivera * TODO: Identify critical errors from the GSR register's FS 2517b3bd9a7SJ. German Rivera * field and for those errors, set error to -ENODEV or other 2527b3bd9a7SJ. German Rivera * appropriate errno, so that the status property is set to 2537b3bd9a7SJ. German Rivera * failure in the fsl,dprc device tree node. 2547b3bd9a7SJ. German Rivera */ 2557b3bd9a7SJ. German Rivera printf("fsl-mc: WARNING: Firmware booted with error (GSR: %#x)\n", 2567b3bd9a7SJ. German Rivera reg_gsr); 2577b3bd9a7SJ. German Rivera } 2587b3bd9a7SJ. German Rivera 2597b3bd9a7SJ. German Rivera /* 2607b3bd9a7SJ. German Rivera * TODO: need to obtain the portal_id for the root container from the 2617b3bd9a7SJ. German Rivera * DPL 2627b3bd9a7SJ. German Rivera */ 2637b3bd9a7SJ. German Rivera portal_id = 0; 2647b3bd9a7SJ. German Rivera 2657b3bd9a7SJ. German Rivera /* 2667b3bd9a7SJ. German Rivera * Check that the MC firmware is responding portal commands: 2677b3bd9a7SJ. German Rivera */ 2687b3bd9a7SJ. German Rivera mc_io.mmio_regs = SOC_MC_PORTAL_ADDR(portal_id); 2697b3bd9a7SJ. German Rivera debug("Checking access to MC portal of root DPRC container (portal_id %d, portal physical addr %p)\n", 2707b3bd9a7SJ. German Rivera portal_id, mc_io.mmio_regs); 2717b3bd9a7SJ. German Rivera 2727b3bd9a7SJ. German Rivera error = mc_get_version(&mc_io, &mc_ver_info); 2737b3bd9a7SJ. German Rivera if (error != 0) { 2747b3bd9a7SJ. German Rivera printf("fsl-mc: ERROR: Firmware version check failed (error: %d)\n", 2757b3bd9a7SJ. German Rivera error); 2767b3bd9a7SJ. German Rivera goto out; 2777b3bd9a7SJ. German Rivera } 2787b3bd9a7SJ. German Rivera 2797b3bd9a7SJ. German Rivera if (MC_VER_MAJOR != mc_ver_info.major) 2807b3bd9a7SJ. German Rivera printf("fsl-mc: ERROR: Firmware major version mismatch (found: %d, expected: %d)\n", 2817b3bd9a7SJ. German Rivera mc_ver_info.major, MC_VER_MAJOR); 2827b3bd9a7SJ. German Rivera 2837b3bd9a7SJ. German Rivera if (MC_VER_MINOR != mc_ver_info.minor) 2847b3bd9a7SJ. German Rivera printf("fsl-mc: WARNING: Firmware minor version mismatch (found: %d, expected: %d)\n", 2857b3bd9a7SJ. German Rivera mc_ver_info.minor, MC_VER_MINOR); 2867b3bd9a7SJ. German Rivera 2877b3bd9a7SJ. German Rivera printf("fsl-mc: Management Complex booted (version: %d.%d.%d, boot status: %#x)\n", 2887b3bd9a7SJ. German Rivera mc_ver_info.major, mc_ver_info.minor, mc_ver_info.revision, 2897b3bd9a7SJ. German Rivera mc_fw_boot_status); 2907b3bd9a7SJ. German Rivera out: 2917b3bd9a7SJ. German Rivera if (error != 0) 2927b3bd9a7SJ. German Rivera mc_boot_status = -error; 2937b3bd9a7SJ. German Rivera else 2947b3bd9a7SJ. German Rivera mc_boot_status = 0; 2957b3bd9a7SJ. German Rivera 2967b3bd9a7SJ. German Rivera return error; 2977b3bd9a7SJ. German Rivera } 2987b3bd9a7SJ. German Rivera 2997b3bd9a7SJ. German Rivera int get_mc_boot_status(void) 3007b3bd9a7SJ. German Rivera { 3017b3bd9a7SJ. German Rivera return mc_boot_status; 3027b3bd9a7SJ. German Rivera } 3037b3bd9a7SJ. German Rivera 3047b3bd9a7SJ. German Rivera /** 3057b3bd9a7SJ. German Rivera * Return the actual size of the MC private DRAM block. 3067b3bd9a7SJ. German Rivera * 3077b3bd9a7SJ. German Rivera * NOTE: For now this function always returns the minimum required size, 3087b3bd9a7SJ. German Rivera * However, in the future, the actual size may be obtained from an environment 3097b3bd9a7SJ. German Rivera * variable. 3107b3bd9a7SJ. German Rivera */ 3117b3bd9a7SJ. German Rivera unsigned long mc_get_dram_block_size(void) 3127b3bd9a7SJ. German Rivera { 3137b3bd9a7SJ. German Rivera return CONFIG_SYS_LS_MC_DRAM_BLOCK_MIN_SIZE; 3147b3bd9a7SJ. German Rivera } 315