1 /* 2 * Copyright (C) 2014 Freescale Semiconductor 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <errno.h> 8 #include <asm/io.h> 9 #include <fsl-mc/fsl_mc.h> 10 #include <fsl-mc/fsl_mc_sys.h> 11 #include <fsl-mc/fsl_dpmng.h> 12 #include <fsl_debug_server.h> 13 14 DECLARE_GLOBAL_DATA_PTR; 15 static int mc_boot_status; 16 17 /** 18 * Copying MC firmware or DPL image to DDR 19 */ 20 static int mc_copy_image(const char *title, 21 u64 image_addr, u32 image_size, u64 mc_ram_addr) 22 { 23 debug("%s copied to address %p\n", title, (void *)mc_ram_addr); 24 memcpy((void *)mc_ram_addr, (void *)image_addr, image_size); 25 return 0; 26 } 27 28 /** 29 * MC firmware FIT image parser checks if the image is in FIT 30 * format, verifies integrity of the image and calculates 31 * raw image address and size values. 32 * Returns 0 on success and a negative errno on error. 33 * task fail. 34 **/ 35 int parse_mc_firmware_fit_image(const void **raw_image_addr, 36 size_t *raw_image_size) 37 { 38 int format; 39 void *fit_hdr; 40 int node_offset; 41 const void *data; 42 size_t size; 43 const char *uname = "firmware"; 44 45 /* Check if the image is in NOR flash */ 46 #ifdef CONFIG_SYS_LS_MC_FW_IN_NOR 47 fit_hdr = (void *)CONFIG_SYS_LS_MC_FW_ADDR; 48 #else 49 #error "No CONFIG_SYS_LS_MC_FW_IN_xxx defined" 50 #endif 51 52 /* Check if Image is in FIT format */ 53 format = genimg_get_format(fit_hdr); 54 55 if (format != IMAGE_FORMAT_FIT) { 56 printf("fsl-mc: ERROR: Bad firmware image (not a FIT image)\n"); 57 return -EINVAL; 58 } 59 60 if (!fit_check_format(fit_hdr)) { 61 printf("fsl-mc: ERROR: Bad firmware image (bad FIT header)\n"); 62 return -EINVAL; 63 } 64 65 node_offset = fit_image_get_node(fit_hdr, uname); 66 67 if (node_offset < 0) { 68 printf("fsl-mc: ERROR: Bad firmware image (missing subimage)\n"); 69 return -ENOENT; 70 } 71 72 /* Verify MC firmware image */ 73 if (!(fit_image_verify(fit_hdr, node_offset))) { 74 printf("fsl-mc: ERROR: Bad firmware image (bad CRC)\n"); 75 return -EINVAL; 76 } 77 78 /* Get address and size of raw image */ 79 fit_image_get_data(fit_hdr, node_offset, &data, &size); 80 81 *raw_image_addr = data; 82 *raw_image_size = size; 83 84 return 0; 85 } 86 87 int mc_init(bd_t *bis) 88 { 89 int error = 0; 90 int timeout = 200000; 91 struct mc_ccsr_registers __iomem *mc_ccsr_regs = MC_CCSR_BASE_ADDR; 92 u64 mc_ram_addr; 93 u64 mc_dpl_offset; 94 u32 reg_gsr; 95 u32 mc_fw_boot_status; 96 void *dpl_fdt_hdr; 97 int dpl_size; 98 const void *raw_image_addr; 99 size_t raw_image_size = 0; 100 struct fsl_mc_io mc_io; 101 int portal_id; 102 struct mc_version mc_ver_info; 103 104 /* 105 * The MC private DRAM block was already carved at the end of DRAM 106 * by board_init_f() using CONFIG_SYS_MEM_TOP_HIDE: 107 */ 108 if (gd->bd->bi_dram[1].start) { 109 mc_ram_addr = 110 gd->bd->bi_dram[1].start + gd->bd->bi_dram[1].size; 111 } else { 112 mc_ram_addr = 113 gd->bd->bi_dram[0].start + gd->bd->bi_dram[0].size; 114 } 115 116 #ifdef CONFIG_FSL_DEBUG_SERVER 117 mc_ram_addr -= debug_server_get_dram_block_size(); 118 #endif 119 /* 120 * Management Complex cores should be held at reset out of POR. 121 * U-boot should be the first software to touch MC. To be safe, 122 * we reset all cores again by setting GCR1 to 0. It doesn't do 123 * anything if they are held at reset. After we setup the firmware 124 * we kick off MC by deasserting the reset bit for core 0, and 125 * deasserting the reset bits for Command Portal Managers. 126 * The stop bits are not touched here. They are used to stop the 127 * cores when they are active. Setting stop bits doesn't stop the 128 * cores from fetching instructions when they are released from 129 * reset. 130 */ 131 out_le32(&mc_ccsr_regs->reg_gcr1, 0); 132 dmb(); 133 134 error = parse_mc_firmware_fit_image(&raw_image_addr, &raw_image_size); 135 if (error != 0) 136 goto out; 137 /* 138 * Load the MC FW at the beginning of the MC private DRAM block: 139 */ 140 mc_copy_image("MC Firmware", 141 (u64)raw_image_addr, raw_image_size, mc_ram_addr); 142 143 /* 144 * Get address and size of the DPL blob stored in flash: 145 */ 146 #ifdef CONFIG_SYS_LS_MC_DPL_IN_NOR 147 dpl_fdt_hdr = (void *)CONFIG_SYS_LS_MC_DPL_ADDR; 148 #else 149 #error "No CONFIG_SYS_LS_MC_DPL_IN_xxx defined" 150 #endif 151 152 error = fdt_check_header(dpl_fdt_hdr); 153 if (error != 0) { 154 printf("fsl-mc: ERROR: Bad DPL image (bad header)\n"); 155 goto out; 156 } 157 158 dpl_size = fdt_totalsize(dpl_fdt_hdr); 159 if (dpl_size > CONFIG_SYS_LS_MC_DPL_MAX_LENGTH) { 160 printf("fsl-mc: ERROR: Bad DPL image (too large: %d)\n", 161 dpl_size); 162 error = -EINVAL; 163 goto out; 164 } 165 166 /* 167 * Calculate offset in the MC private DRAM block at which the MC DPL 168 * blob is to be placed: 169 */ 170 #ifdef CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET 171 BUILD_BUG_ON((CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET & 0x3) != 0 || 172 CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET > 0xffffffff); 173 174 mc_dpl_offset = CONFIG_SYS_LS_MC_DRAM_DPL_OFFSET; 175 #else 176 mc_dpl_offset = mc_get_dram_block_size() - 177 roundup(CONFIG_SYS_LS_MC_DPL_MAX_LENGTH, 4096); 178 179 if ((mc_dpl_offset & 0x3) != 0 || mc_dpl_offset > 0xffffffff) { 180 printf("%s: Invalid MC DPL offset: %llu\n", 181 __func__, mc_dpl_offset); 182 error = -EINVAL; 183 goto out; 184 } 185 #endif 186 187 /* 188 * Load the MC DPL blob at the far end of the MC private DRAM block: 189 * 190 * TODO: Should we place the DPL at a different location to match 191 * assumptions of MC firmware about its memory layout? 192 */ 193 mc_copy_image("MC DPL blob", 194 (u64)dpl_fdt_hdr, dpl_size, mc_ram_addr + mc_dpl_offset); 195 196 debug("mc_ccsr_regs %p\n", mc_ccsr_regs); 197 198 /* 199 * Tell MC where the MC Firmware image was loaded in DDR: 200 */ 201 out_le32(&mc_ccsr_regs->reg_mcfbalr, (u32)mc_ram_addr); 202 out_le32(&mc_ccsr_regs->reg_mcfbahr, (u32)((u64)mc_ram_addr >> 32)); 203 out_le32(&mc_ccsr_regs->reg_mcfapr, MCFAPR_BYPASS_ICID_MASK); 204 205 /* 206 * Tell MC where the DPL blob was loaded in DDR, by indicating 207 * its offset relative to the beginning of the DDR block 208 * allocated to the MC firmware. The MC firmware is responsible 209 * for checking that there is no overlap between the DPL blob 210 * and the runtime heap and stack of the MC firmware itself. 211 * 212 * NOTE: bits [31:2] of this offset need to be stored in bits [29:0] of 213 * the GSR MC CCSR register. So, this offset is assumed to be 4-byte 214 * aligned. 215 * Care must be taken not to write 1s into bits 31 and 30 of the GSR in 216 * this case as the SoC COP or PIC will be signaled. 217 */ 218 out_le32(&mc_ccsr_regs->reg_gsr, (u32)(mc_dpl_offset >> 2)); 219 220 printf("\nfsl-mc: Booting Management Complex ...\n"); 221 222 /* 223 * Deassert reset and release MC core 0 to run 224 */ 225 out_le32(&mc_ccsr_regs->reg_gcr1, GCR1_P1_DE_RST | GCR1_M_ALL_DE_RST); 226 dmb(); 227 debug("Polling mc_ccsr_regs->reg_gsr ...\n"); 228 229 for (;;) { 230 reg_gsr = in_le32(&mc_ccsr_regs->reg_gsr); 231 mc_fw_boot_status = (reg_gsr & GSR_FS_MASK); 232 if (mc_fw_boot_status & 0x1) 233 break; 234 235 udelay(1000); /* throttle polling */ 236 if (timeout-- <= 0) 237 break; 238 } 239 240 if (timeout <= 0) { 241 printf("fsl-mc: timeout booting management complex firmware\n"); 242 243 /* TODO: Get an error status from an MC CCSR register */ 244 error = -ETIMEDOUT; 245 goto out; 246 } 247 248 if (mc_fw_boot_status != 0x1) { 249 /* 250 * TODO: Identify critical errors from the GSR register's FS 251 * field and for those errors, set error to -ENODEV or other 252 * appropriate errno, so that the status property is set to 253 * failure in the fsl,dprc device tree node. 254 */ 255 printf("fsl-mc: WARNING: Firmware booted with error (GSR: %#x)\n", 256 reg_gsr); 257 } 258 259 /* 260 * TODO: need to obtain the portal_id for the root container from the 261 * DPL 262 */ 263 portal_id = 0; 264 265 /* 266 * Check that the MC firmware is responding portal commands: 267 */ 268 mc_io.mmio_regs = SOC_MC_PORTAL_ADDR(portal_id); 269 debug("Checking access to MC portal of root DPRC container (portal_id %d, portal physical addr %p)\n", 270 portal_id, mc_io.mmio_regs); 271 272 error = mc_get_version(&mc_io, &mc_ver_info); 273 if (error != 0) { 274 printf("fsl-mc: ERROR: Firmware version check failed (error: %d)\n", 275 error); 276 goto out; 277 } 278 279 if (MC_VER_MAJOR != mc_ver_info.major) 280 printf("fsl-mc: ERROR: Firmware major version mismatch (found: %d, expected: %d)\n", 281 mc_ver_info.major, MC_VER_MAJOR); 282 283 if (MC_VER_MINOR != mc_ver_info.minor) 284 printf("fsl-mc: WARNING: Firmware minor version mismatch (found: %d, expected: %d)\n", 285 mc_ver_info.minor, MC_VER_MINOR); 286 287 printf("fsl-mc: Management Complex booted (version: %d.%d.%d, boot status: %#x)\n", 288 mc_ver_info.major, mc_ver_info.minor, mc_ver_info.revision, 289 mc_fw_boot_status); 290 out: 291 if (error != 0) 292 mc_boot_status = -error; 293 else 294 mc_boot_status = 0; 295 296 return error; 297 } 298 299 int get_mc_boot_status(void) 300 { 301 return mc_boot_status; 302 } 303 304 /** 305 * Return the actual size of the MC private DRAM block. 306 * 307 * NOTE: For now this function always returns the minimum required size, 308 * However, in the future, the actual size may be obtained from an environment 309 * variable. 310 */ 311 unsigned long mc_get_dram_block_size(void) 312 { 313 return CONFIG_SYS_LS_MC_DRAM_BLOCK_MIN_SIZE; 314 } 315