18edcde5eSStefano Babic /* 28edcde5eSStefano Babic * (C) Copyright 2009 38edcde5eSStefano Babic * Stefano Babic, DENX Software Engineering, sbabic@denx.de. 48edcde5eSStefano Babic * 58edcde5eSStefano Babic * (C) Copyright 2008 68edcde5eSStefano Babic * Marvell Semiconductor <www.marvell.com> 78edcde5eSStefano Babic * Written-by: Prafulla Wadaskar <prafulla@marvell.com> 88edcde5eSStefano Babic * 91a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 108edcde5eSStefano Babic */ 118edcde5eSStefano Babic 12f86ed6a8SGuilherme Maciel Ferreira #include "imagetool.h" 138edcde5eSStefano Babic #include <image.h> 148edcde5eSStefano Babic #include "imximage.h" 158edcde5eSStefano Babic 160187c985SStefano Babic #define UNDEFINED 0xFFFFFFFF 170187c985SStefano Babic 188edcde5eSStefano Babic /* 198edcde5eSStefano Babic * Supported commands for configuration file 208edcde5eSStefano Babic */ 218edcde5eSStefano Babic static table_entry_t imximage_cmds[] = { 22f581e3a2SStefano Babic {CMD_BOOT_FROM, "BOOT_FROM", "boot command", }, 236cb83829SMarek Vasut {CMD_BOOT_OFFSET, "BOOT_OFFSET", "Boot offset", }, 240b7f7c33SAdrian Alonso {CMD_WRITE_DATA, "DATA", "Reg Write Data", }, 250b7f7c33SAdrian Alonso {CMD_WRITE_CLR_BIT, "CLR_BIT", "Reg clear bit", }, 260b7f7c33SAdrian Alonso {CMD_CHECK_BITS_SET, "CHECK_BITS_SET", "Reg Check bits set", }, 270b7f7c33SAdrian Alonso {CMD_CHECK_BITS_CLR, "CHECK_BITS_CLR", "Reg Check bits clr", }, 280187c985SStefano Babic {CMD_CSF, "CSF", "Command Sequence File", }, 298a1edd7dSLiu Hui-R64343 {CMD_IMAGE_VERSION, "IMAGE_VERSION", "image version", }, 308edcde5eSStefano Babic {-1, "", "", }, 318edcde5eSStefano Babic }; 328edcde5eSStefano Babic 338edcde5eSStefano Babic /* 348edcde5eSStefano Babic * Supported Boot options for configuration file 358edcde5eSStefano Babic * this is needed to set the correct flash offset 368edcde5eSStefano Babic */ 37377e367aSStefano Babic static table_entry_t imximage_boot_offset[] = { 388edcde5eSStefano Babic {FLASH_OFFSET_ONENAND, "onenand", "OneNAND Flash",}, 39bd25864cSDirk Behme {FLASH_OFFSET_NAND, "nand", "NAND Flash", }, 4019b409c0SDirk Behme {FLASH_OFFSET_NOR, "nor", "NOR Flash", }, 4119b409c0SDirk Behme {FLASH_OFFSET_SATA, "sata", "SATA Disk", }, 42bd25864cSDirk Behme {FLASH_OFFSET_SD, "sd", "SD Card", }, 43bd25864cSDirk Behme {FLASH_OFFSET_SPI, "spi", "SPI Flash", }, 449598f8c3SYe.Li {FLASH_OFFSET_QSPI, "qspi", "QSPI NOR Flash",}, 458edcde5eSStefano Babic {-1, "", "Invalid", }, 468edcde5eSStefano Babic }; 478edcde5eSStefano Babic 488a1edd7dSLiu Hui-R64343 /* 49377e367aSStefano Babic * Supported Boot options for configuration file 50377e367aSStefano Babic * this is needed to determine the initial load size 51377e367aSStefano Babic */ 52377e367aSStefano Babic static table_entry_t imximage_boot_loadsize[] = { 53377e367aSStefano Babic {FLASH_LOADSIZE_ONENAND, "onenand", "OneNAND Flash",}, 54377e367aSStefano Babic {FLASH_LOADSIZE_NAND, "nand", "NAND Flash", }, 55377e367aSStefano Babic {FLASH_LOADSIZE_NOR, "nor", "NOR Flash", }, 56377e367aSStefano Babic {FLASH_LOADSIZE_SATA, "sata", "SATA Disk", }, 57377e367aSStefano Babic {FLASH_LOADSIZE_SD, "sd", "SD Card", }, 58377e367aSStefano Babic {FLASH_LOADSIZE_SPI, "spi", "SPI Flash", }, 599598f8c3SYe.Li {FLASH_LOADSIZE_QSPI, "qspi", "QSPI NOR Flash",}, 60377e367aSStefano Babic {-1, "", "Invalid", }, 61377e367aSStefano Babic }; 62377e367aSStefano Babic 63377e367aSStefano Babic /* 648a1edd7dSLiu Hui-R64343 * IMXIMAGE version definition for i.MX chips 658a1edd7dSLiu Hui-R64343 */ 668a1edd7dSLiu Hui-R64343 static table_entry_t imximage_versions[] = { 678a1edd7dSLiu Hui-R64343 {IMXIMAGE_V1, "", " (i.MX25/35/51 compatible)", }, 680b7f7c33SAdrian Alonso {IMXIMAGE_V2, "", " (i.MX53/6/7 compatible)", }, 698a1edd7dSLiu Hui-R64343 {-1, "", " (Invalid)", }, 708a1edd7dSLiu Hui-R64343 }; 718edcde5eSStefano Babic 728edcde5eSStefano Babic static struct imx_header imximage_header; 738a1edd7dSLiu Hui-R64343 static uint32_t imximage_version; 740187c985SStefano Babic /* 750187c985SStefano Babic * Image Vector Table Offset 760187c985SStefano Babic * Initialized to a wrong not 4-bytes aligned address to 770187c985SStefano Babic * check if it is was set by the cfg file. 780187c985SStefano Babic */ 790187c985SStefano Babic static uint32_t imximage_ivt_offset = UNDEFINED; 800187c985SStefano Babic static uint32_t imximage_csf_size = UNDEFINED; 81377e367aSStefano Babic /* Initial Load Region Size */ 82377e367aSStefano Babic static uint32_t imximage_init_loadsize; 838a1edd7dSLiu Hui-R64343 848a1edd7dSLiu Hui-R64343 static set_dcd_val_t set_dcd_val; 850b7f7c33SAdrian Alonso static set_dcd_param_t set_dcd_param; 868a1edd7dSLiu Hui-R64343 static set_dcd_rst_t set_dcd_rst; 878a1edd7dSLiu Hui-R64343 static set_imx_hdr_t set_imx_hdr; 884d5fa985STroy Kisky static uint32_t max_dcd_entries; 8924331982STroy Kisky static uint32_t *header_size_ptr; 900187c985SStefano Babic static uint32_t *csf_ptr; 918edcde5eSStefano Babic 928edcde5eSStefano Babic static uint32_t get_cfg_value(char *token, char *name, int linenr) 938edcde5eSStefano Babic { 948edcde5eSStefano Babic char *endptr; 958edcde5eSStefano Babic uint32_t value; 968edcde5eSStefano Babic 978edcde5eSStefano Babic errno = 0; 988edcde5eSStefano Babic value = strtoul(token, &endptr, 16); 998edcde5eSStefano Babic if (errno || (token == endptr)) { 1008edcde5eSStefano Babic fprintf(stderr, "Error: %s[%d] - Invalid hex data(%s)\n", 1018edcde5eSStefano Babic name, linenr, token); 1028edcde5eSStefano Babic exit(EXIT_FAILURE); 1038edcde5eSStefano Babic } 1048edcde5eSStefano Babic return value; 1058edcde5eSStefano Babic } 1068edcde5eSStefano Babic 1078a1edd7dSLiu Hui-R64343 static uint32_t detect_imximage_version(struct imx_header *imx_hdr) 1088edcde5eSStefano Babic { 1098a1edd7dSLiu Hui-R64343 imx_header_v1_t *hdr_v1 = &imx_hdr->header.hdr_v1; 1108a1edd7dSLiu Hui-R64343 imx_header_v2_t *hdr_v2 = &imx_hdr->header.hdr_v2; 1118a1edd7dSLiu Hui-R64343 flash_header_v1_t *fhdr_v1 = &hdr_v1->fhdr; 1128a1edd7dSLiu Hui-R64343 flash_header_v2_t *fhdr_v2 = &hdr_v2->fhdr; 1138a1edd7dSLiu Hui-R64343 1148a1edd7dSLiu Hui-R64343 /* Try to detect V1 */ 1158a1edd7dSLiu Hui-R64343 if ((fhdr_v1->app_code_barker == APP_CODE_BARKER) && 1168a1edd7dSLiu Hui-R64343 (hdr_v1->dcd_table.preamble.barker == DCD_BARKER)) 1178a1edd7dSLiu Hui-R64343 return IMXIMAGE_V1; 1188a1edd7dSLiu Hui-R64343 1198a1edd7dSLiu Hui-R64343 /* Try to detect V2 */ 1208a1edd7dSLiu Hui-R64343 if ((fhdr_v2->header.tag == IVT_HEADER_TAG) && 1218a1edd7dSLiu Hui-R64343 (hdr_v2->dcd_table.header.tag == DCD_HEADER_TAG)) 1228a1edd7dSLiu Hui-R64343 return IMXIMAGE_V2; 1238a1edd7dSLiu Hui-R64343 1248a1edd7dSLiu Hui-R64343 return IMXIMAGE_VER_INVALID; 1258edcde5eSStefano Babic } 1268edcde5eSStefano Babic 1278a1edd7dSLiu Hui-R64343 static void err_imximage_version(int version) 1288edcde5eSStefano Babic { 1298edcde5eSStefano Babic fprintf(stderr, 1308a1edd7dSLiu Hui-R64343 "Error: Unsupported imximage version:%d\n", version); 1318a1edd7dSLiu Hui-R64343 1328edcde5eSStefano Babic exit(EXIT_FAILURE); 1338edcde5eSStefano Babic } 1348edcde5eSStefano Babic 1358a1edd7dSLiu Hui-R64343 static void set_dcd_val_v1(struct imx_header *imxhdr, char *name, int lineno, 1368a1edd7dSLiu Hui-R64343 int fld, uint32_t value, uint32_t off) 1378a1edd7dSLiu Hui-R64343 { 1388a1edd7dSLiu Hui-R64343 dcd_v1_t *dcd_v1 = &imxhdr->header.hdr_v1.dcd_table; 1398edcde5eSStefano Babic 1408a1edd7dSLiu Hui-R64343 switch (fld) { 1418a1edd7dSLiu Hui-R64343 case CFG_REG_SIZE: 1428a1edd7dSLiu Hui-R64343 /* Byte, halfword, word */ 1438a1edd7dSLiu Hui-R64343 if ((value != 1) && (value != 2) && (value != 4)) { 1448a1edd7dSLiu Hui-R64343 fprintf(stderr, "Error: %s[%d] - " 1458a1edd7dSLiu Hui-R64343 "Invalid register size " "(%d)\n", 1468a1edd7dSLiu Hui-R64343 name, lineno, value); 1478a1edd7dSLiu Hui-R64343 exit(EXIT_FAILURE); 1488a1edd7dSLiu Hui-R64343 } 1498a1edd7dSLiu Hui-R64343 dcd_v1->addr_data[off].type = value; 1508a1edd7dSLiu Hui-R64343 break; 1518a1edd7dSLiu Hui-R64343 case CFG_REG_ADDRESS: 1528a1edd7dSLiu Hui-R64343 dcd_v1->addr_data[off].addr = value; 1538a1edd7dSLiu Hui-R64343 break; 1548a1edd7dSLiu Hui-R64343 case CFG_REG_VALUE: 1558a1edd7dSLiu Hui-R64343 dcd_v1->addr_data[off].value = value; 1568a1edd7dSLiu Hui-R64343 break; 1578a1edd7dSLiu Hui-R64343 default: 1588a1edd7dSLiu Hui-R64343 break; 1598a1edd7dSLiu Hui-R64343 1608a1edd7dSLiu Hui-R64343 } 1618edcde5eSStefano Babic } 1628edcde5eSStefano Babic 1630b7f7c33SAdrian Alonso static void set_dcd_param_v2(struct imx_header *imxhdr, uint32_t dcd_len, 1640b7f7c33SAdrian Alonso int32_t cmd) 1650b7f7c33SAdrian Alonso { 1660b7f7c33SAdrian Alonso dcd_v2_t *dcd_v2 = &imxhdr->header.hdr_v2.dcd_table; 1670b7f7c33SAdrian Alonso 1680b7f7c33SAdrian Alonso switch (cmd) { 1690b7f7c33SAdrian Alonso case CMD_WRITE_DATA: 1700b7f7c33SAdrian Alonso dcd_v2->write_dcd_command.tag = DCD_WRITE_DATA_COMMAND_TAG; 1710b7f7c33SAdrian Alonso dcd_v2->write_dcd_command.length = cpu_to_be16( 1720b7f7c33SAdrian Alonso dcd_len * sizeof(dcd_addr_data_t) + 4); 1730b7f7c33SAdrian Alonso dcd_v2->write_dcd_command.param = DCD_WRITE_DATA_PARAM; 1740b7f7c33SAdrian Alonso break; 1750b7f7c33SAdrian Alonso case CMD_WRITE_CLR_BIT: 1760b7f7c33SAdrian Alonso dcd_v2->write_dcd_command.tag = DCD_WRITE_DATA_COMMAND_TAG; 1770b7f7c33SAdrian Alonso dcd_v2->write_dcd_command.length = cpu_to_be16( 1780b7f7c33SAdrian Alonso dcd_len * sizeof(dcd_addr_data_t) + 4); 1790b7f7c33SAdrian Alonso dcd_v2->write_dcd_command.param = DCD_WRITE_CLR_BIT_PARAM; 1800b7f7c33SAdrian Alonso break; 1810b7f7c33SAdrian Alonso /* 1820b7f7c33SAdrian Alonso * Check data command only supports one entry, 1830b7f7c33SAdrian Alonso * so use 0xC = size(address + value + command). 1840b7f7c33SAdrian Alonso */ 1850b7f7c33SAdrian Alonso case CMD_CHECK_BITS_SET: 1860b7f7c33SAdrian Alonso dcd_v2->write_dcd_command.tag = DCD_CHECK_DATA_COMMAND_TAG; 1870b7f7c33SAdrian Alonso dcd_v2->write_dcd_command.length = cpu_to_be16(0xC); 1880b7f7c33SAdrian Alonso dcd_v2->write_dcd_command.param = DCD_CHECK_BITS_SET_PARAM; 1890b7f7c33SAdrian Alonso break; 1900b7f7c33SAdrian Alonso case CMD_CHECK_BITS_CLR: 1910b7f7c33SAdrian Alonso dcd_v2->write_dcd_command.tag = DCD_CHECK_DATA_COMMAND_TAG; 1920b7f7c33SAdrian Alonso dcd_v2->write_dcd_command.length = cpu_to_be16(0xC); 1930b7f7c33SAdrian Alonso dcd_v2->write_dcd_command.param = DCD_CHECK_BITS_SET_PARAM; 1940b7f7c33SAdrian Alonso break; 1950b7f7c33SAdrian Alonso default: 1960b7f7c33SAdrian Alonso break; 1970b7f7c33SAdrian Alonso } 1980b7f7c33SAdrian Alonso } 1990b7f7c33SAdrian Alonso 2008a1edd7dSLiu Hui-R64343 static void set_dcd_val_v2(struct imx_header *imxhdr, char *name, int lineno, 2018a1edd7dSLiu Hui-R64343 int fld, uint32_t value, uint32_t off) 2028a1edd7dSLiu Hui-R64343 { 2038a1edd7dSLiu Hui-R64343 dcd_v2_t *dcd_v2 = &imxhdr->header.hdr_v2.dcd_table; 2048a1edd7dSLiu Hui-R64343 2058a1edd7dSLiu Hui-R64343 switch (fld) { 2068a1edd7dSLiu Hui-R64343 case CFG_REG_ADDRESS: 2078a1edd7dSLiu Hui-R64343 dcd_v2->addr_data[off].addr = cpu_to_be32(value); 2088a1edd7dSLiu Hui-R64343 break; 2098a1edd7dSLiu Hui-R64343 case CFG_REG_VALUE: 2108a1edd7dSLiu Hui-R64343 dcd_v2->addr_data[off].value = cpu_to_be32(value); 2118a1edd7dSLiu Hui-R64343 break; 2128a1edd7dSLiu Hui-R64343 default: 2138a1edd7dSLiu Hui-R64343 break; 2148a1edd7dSLiu Hui-R64343 2158a1edd7dSLiu Hui-R64343 } 2168a1edd7dSLiu Hui-R64343 } 2178a1edd7dSLiu Hui-R64343 2188a1edd7dSLiu Hui-R64343 /* 2198a1edd7dSLiu Hui-R64343 * Complete setting up the rest field of DCD of V1 2208a1edd7dSLiu Hui-R64343 * such as barker code and DCD data length. 2218a1edd7dSLiu Hui-R64343 */ 2228a1edd7dSLiu Hui-R64343 static void set_dcd_rst_v1(struct imx_header *imxhdr, uint32_t dcd_len, 2238a1edd7dSLiu Hui-R64343 char *name, int lineno) 2248a1edd7dSLiu Hui-R64343 { 2258a1edd7dSLiu Hui-R64343 dcd_v1_t *dcd_v1 = &imxhdr->header.hdr_v1.dcd_table; 2268a1edd7dSLiu Hui-R64343 2278a1edd7dSLiu Hui-R64343 dcd_v1->preamble.barker = DCD_BARKER; 2288a1edd7dSLiu Hui-R64343 dcd_v1->preamble.length = dcd_len * sizeof(dcd_type_addr_data_t); 2298a1edd7dSLiu Hui-R64343 } 2308a1edd7dSLiu Hui-R64343 2318a1edd7dSLiu Hui-R64343 /* 2328a1edd7dSLiu Hui-R64343 * Complete setting up the reset field of DCD of V2 2338a1edd7dSLiu Hui-R64343 * such as DCD tag, version, length, etc. 2348a1edd7dSLiu Hui-R64343 */ 2358a1edd7dSLiu Hui-R64343 static void set_dcd_rst_v2(struct imx_header *imxhdr, uint32_t dcd_len, 2368a1edd7dSLiu Hui-R64343 char *name, int lineno) 2378a1edd7dSLiu Hui-R64343 { 2388a1edd7dSLiu Hui-R64343 dcd_v2_t *dcd_v2 = &imxhdr->header.hdr_v2.dcd_table; 2398a1edd7dSLiu Hui-R64343 2408a1edd7dSLiu Hui-R64343 dcd_v2->header.tag = DCD_HEADER_TAG; 2418a1edd7dSLiu Hui-R64343 dcd_v2->header.length = cpu_to_be16( 2428a1edd7dSLiu Hui-R64343 dcd_len * sizeof(dcd_addr_data_t) + 8); 2438a1edd7dSLiu Hui-R64343 dcd_v2->header.version = DCD_VERSION; 2440b7f7c33SAdrian Alonso set_dcd_param_v2(imxhdr, dcd_len, CMD_WRITE_DATA); 2458a1edd7dSLiu Hui-R64343 } 2468a1edd7dSLiu Hui-R64343 2478a1edd7dSLiu Hui-R64343 static void set_imx_hdr_v1(struct imx_header *imxhdr, uint32_t dcd_len, 248ad0826dcSTroy Kisky uint32_t entry_point, uint32_t flash_offset) 2498a1edd7dSLiu Hui-R64343 { 2508a1edd7dSLiu Hui-R64343 imx_header_v1_t *hdr_v1 = &imxhdr->header.hdr_v1; 2518a1edd7dSLiu Hui-R64343 flash_header_v1_t *fhdr_v1 = &hdr_v1->fhdr; 2528a1edd7dSLiu Hui-R64343 dcd_v1_t *dcd_v1 = &hdr_v1->dcd_table; 253ab857f26STroy Kisky uint32_t hdr_base; 25424331982STroy Kisky uint32_t header_length = (((char *)&dcd_v1->addr_data[dcd_len].addr) 25524331982STroy Kisky - ((char *)imxhdr)); 2568a1edd7dSLiu Hui-R64343 2578a1edd7dSLiu Hui-R64343 /* Set magic number */ 2588a1edd7dSLiu Hui-R64343 fhdr_v1->app_code_barker = APP_CODE_BARKER; 2598a1edd7dSLiu Hui-R64343 260377e367aSStefano Babic /* TODO: check i.MX image V1 handling, for now use 'old' style */ 261377e367aSStefano Babic hdr_base = entry_point - 4096; 262ab857f26STroy Kisky fhdr_v1->app_dest_ptr = hdr_base - flash_offset; 263ad0826dcSTroy Kisky fhdr_v1->app_code_jump_vector = entry_point; 2648a1edd7dSLiu Hui-R64343 265ab857f26STroy Kisky fhdr_v1->dcd_ptr_ptr = hdr_base + offsetof(flash_header_v1_t, dcd_ptr); 266ab857f26STroy Kisky fhdr_v1->dcd_ptr = hdr_base + offsetof(imx_header_v1_t, dcd_table); 2678a1edd7dSLiu Hui-R64343 2688a1edd7dSLiu Hui-R64343 /* Security feature are not supported */ 2698a1edd7dSLiu Hui-R64343 fhdr_v1->app_code_csf = 0; 2708a1edd7dSLiu Hui-R64343 fhdr_v1->super_root_key = 0; 27124331982STroy Kisky header_size_ptr = (uint32_t *)(((char *)imxhdr) + header_length - 4); 2728a1edd7dSLiu Hui-R64343 } 2738a1edd7dSLiu Hui-R64343 2748a1edd7dSLiu Hui-R64343 static void set_imx_hdr_v2(struct imx_header *imxhdr, uint32_t dcd_len, 275ad0826dcSTroy Kisky uint32_t entry_point, uint32_t flash_offset) 2768a1edd7dSLiu Hui-R64343 { 2778a1edd7dSLiu Hui-R64343 imx_header_v2_t *hdr_v2 = &imxhdr->header.hdr_v2; 2788a1edd7dSLiu Hui-R64343 flash_header_v2_t *fhdr_v2 = &hdr_v2->fhdr; 279ab857f26STroy Kisky uint32_t hdr_base; 2808a1edd7dSLiu Hui-R64343 2818a1edd7dSLiu Hui-R64343 /* Set magic number */ 2828a1edd7dSLiu Hui-R64343 fhdr_v2->header.tag = IVT_HEADER_TAG; /* 0xD1 */ 2838a1edd7dSLiu Hui-R64343 fhdr_v2->header.length = cpu_to_be16(sizeof(flash_header_v2_t)); 2848a1edd7dSLiu Hui-R64343 fhdr_v2->header.version = IVT_VERSION; /* 0x40 */ 2858a1edd7dSLiu Hui-R64343 286ad0826dcSTroy Kisky fhdr_v2->entry = entry_point; 2878a1edd7dSLiu Hui-R64343 fhdr_v2->reserved1 = fhdr_v2->reserved2 = 0; 288377e367aSStefano Babic hdr_base = entry_point - imximage_init_loadsize + 289377e367aSStefano Babic flash_offset; 290377e367aSStefano Babic fhdr_v2->self = hdr_base; 291*b893c989SBaruch Siach if (dcd_len > 0) 292*b893c989SBaruch Siach fhdr_v2->dcd_ptr = hdr_base 293*b893c989SBaruch Siach + offsetof(imx_header_v2_t, dcd_table); 294*b893c989SBaruch Siach else 295*b893c989SBaruch Siach fhdr_v2->dcd_ptr = 0; 296ab857f26STroy Kisky fhdr_v2->boot_data_ptr = hdr_base 297ab857f26STroy Kisky + offsetof(imx_header_v2_t, boot_data); 298377e367aSStefano Babic hdr_v2->boot_data.start = entry_point - imximage_init_loadsize; 2998a1edd7dSLiu Hui-R64343 3008a1edd7dSLiu Hui-R64343 fhdr_v2->csf = 0; 3010187c985SStefano Babic 30224331982STroy Kisky header_size_ptr = &hdr_v2->boot_data.size; 3030187c985SStefano Babic csf_ptr = &fhdr_v2->csf; 3048a1edd7dSLiu Hui-R64343 } 3058a1edd7dSLiu Hui-R64343 30672048bc3SYork Sun static void set_hdr_func(void) 3078a1edd7dSLiu Hui-R64343 { 3088a1edd7dSLiu Hui-R64343 switch (imximage_version) { 3098a1edd7dSLiu Hui-R64343 case IMXIMAGE_V1: 3108a1edd7dSLiu Hui-R64343 set_dcd_val = set_dcd_val_v1; 3110b7f7c33SAdrian Alonso set_dcd_param = NULL; 3128a1edd7dSLiu Hui-R64343 set_dcd_rst = set_dcd_rst_v1; 3138a1edd7dSLiu Hui-R64343 set_imx_hdr = set_imx_hdr_v1; 3144d5fa985STroy Kisky max_dcd_entries = MAX_HW_CFG_SIZE_V1; 3158a1edd7dSLiu Hui-R64343 break; 3168a1edd7dSLiu Hui-R64343 case IMXIMAGE_V2: 3178a1edd7dSLiu Hui-R64343 set_dcd_val = set_dcd_val_v2; 3180b7f7c33SAdrian Alonso set_dcd_param = set_dcd_param_v2; 3198a1edd7dSLiu Hui-R64343 set_dcd_rst = set_dcd_rst_v2; 3208a1edd7dSLiu Hui-R64343 set_imx_hdr = set_imx_hdr_v2; 3214d5fa985STroy Kisky max_dcd_entries = MAX_HW_CFG_SIZE_V2; 3228a1edd7dSLiu Hui-R64343 break; 3238a1edd7dSLiu Hui-R64343 default: 3248a1edd7dSLiu Hui-R64343 err_imximage_version(imximage_version); 3258a1edd7dSLiu Hui-R64343 break; 3268a1edd7dSLiu Hui-R64343 } 3278a1edd7dSLiu Hui-R64343 } 3288a1edd7dSLiu Hui-R64343 3298a1edd7dSLiu Hui-R64343 static void print_hdr_v1(struct imx_header *imx_hdr) 3308a1edd7dSLiu Hui-R64343 { 3318a1edd7dSLiu Hui-R64343 imx_header_v1_t *hdr_v1 = &imx_hdr->header.hdr_v1; 3328a1edd7dSLiu Hui-R64343 flash_header_v1_t *fhdr_v1 = &hdr_v1->fhdr; 3338a1edd7dSLiu Hui-R64343 dcd_v1_t *dcd_v1 = &hdr_v1->dcd_table; 3348a1edd7dSLiu Hui-R64343 uint32_t size, length, ver; 3358a1edd7dSLiu Hui-R64343 3368a1edd7dSLiu Hui-R64343 size = dcd_v1->preamble.length; 3378a1edd7dSLiu Hui-R64343 if (size > (MAX_HW_CFG_SIZE_V1 * sizeof(dcd_type_addr_data_t))) { 3388a1edd7dSLiu Hui-R64343 fprintf(stderr, 3398a1edd7dSLiu Hui-R64343 "Error: Image corrupt DCD size %d exceed maximum %d\n", 3408a1edd7dSLiu Hui-R64343 (uint32_t)(size / sizeof(dcd_type_addr_data_t)), 3418a1edd7dSLiu Hui-R64343 MAX_HW_CFG_SIZE_V1); 3428a1edd7dSLiu Hui-R64343 exit(EXIT_FAILURE); 3438a1edd7dSLiu Hui-R64343 } 3448a1edd7dSLiu Hui-R64343 3458a1edd7dSLiu Hui-R64343 length = dcd_v1->preamble.length / sizeof(dcd_type_addr_data_t); 3468a1edd7dSLiu Hui-R64343 ver = detect_imximage_version(imx_hdr); 3478a1edd7dSLiu Hui-R64343 3488a1edd7dSLiu Hui-R64343 printf("Image Type: Freescale IMX Boot Image\n"); 3498a1edd7dSLiu Hui-R64343 printf("Image Ver: %x", ver); 3508a1edd7dSLiu Hui-R64343 printf("%s\n", get_table_entry_name(imximage_versions, NULL, ver)); 3518a1edd7dSLiu Hui-R64343 printf("Data Size: "); 3528a1edd7dSLiu Hui-R64343 genimg_print_size(dcd_v1->addr_data[length].type); 3538a1edd7dSLiu Hui-R64343 printf("Load Address: %08x\n", (uint32_t)fhdr_v1->app_dest_ptr); 3548a1edd7dSLiu Hui-R64343 printf("Entry Point: %08x\n", (uint32_t)fhdr_v1->app_code_jump_vector); 3558a1edd7dSLiu Hui-R64343 } 3568a1edd7dSLiu Hui-R64343 3578a1edd7dSLiu Hui-R64343 static void print_hdr_v2(struct imx_header *imx_hdr) 3588a1edd7dSLiu Hui-R64343 { 3598a1edd7dSLiu Hui-R64343 imx_header_v2_t *hdr_v2 = &imx_hdr->header.hdr_v2; 3608a1edd7dSLiu Hui-R64343 flash_header_v2_t *fhdr_v2 = &hdr_v2->fhdr; 3618a1edd7dSLiu Hui-R64343 dcd_v2_t *dcd_v2 = &hdr_v2->dcd_table; 3628a1edd7dSLiu Hui-R64343 uint32_t size, version; 3638a1edd7dSLiu Hui-R64343 3648a1edd7dSLiu Hui-R64343 size = be16_to_cpu(dcd_v2->header.length) - 8; 3658a1edd7dSLiu Hui-R64343 if (size > (MAX_HW_CFG_SIZE_V2 * sizeof(dcd_addr_data_t))) { 3668a1edd7dSLiu Hui-R64343 fprintf(stderr, 3678a1edd7dSLiu Hui-R64343 "Error: Image corrupt DCD size %d exceed maximum %d\n", 3688a1edd7dSLiu Hui-R64343 (uint32_t)(size / sizeof(dcd_addr_data_t)), 3698a1edd7dSLiu Hui-R64343 MAX_HW_CFG_SIZE_V2); 3708a1edd7dSLiu Hui-R64343 exit(EXIT_FAILURE); 3718a1edd7dSLiu Hui-R64343 } 3728a1edd7dSLiu Hui-R64343 3738a1edd7dSLiu Hui-R64343 version = detect_imximage_version(imx_hdr); 3748a1edd7dSLiu Hui-R64343 3758a1edd7dSLiu Hui-R64343 printf("Image Type: Freescale IMX Boot Image\n"); 3768a1edd7dSLiu Hui-R64343 printf("Image Ver: %x", version); 3778a1edd7dSLiu Hui-R64343 printf("%s\n", get_table_entry_name(imximage_versions, NULL, version)); 3788a1edd7dSLiu Hui-R64343 printf("Data Size: "); 3798a1edd7dSLiu Hui-R64343 genimg_print_size(hdr_v2->boot_data.size); 3808a1edd7dSLiu Hui-R64343 printf("Load Address: %08x\n", (uint32_t)fhdr_v2->boot_data_ptr); 3818a1edd7dSLiu Hui-R64343 printf("Entry Point: %08x\n", (uint32_t)fhdr_v2->entry); 3820187c985SStefano Babic if (fhdr_v2->csf && (imximage_ivt_offset != UNDEFINED) && 3830187c985SStefano Babic (imximage_csf_size != UNDEFINED)) { 3840187c985SStefano Babic printf("HAB Blocks: %08x %08x %08x\n", 3850187c985SStefano Babic (uint32_t)fhdr_v2->self, 0, 3860187c985SStefano Babic hdr_v2->boot_data.size - imximage_ivt_offset - 3870187c985SStefano Babic imximage_csf_size); 3880187c985SStefano Babic } 3898a1edd7dSLiu Hui-R64343 } 3908a1edd7dSLiu Hui-R64343 3918a1edd7dSLiu Hui-R64343 static void parse_cfg_cmd(struct imx_header *imxhdr, int32_t cmd, char *token, 3928a1edd7dSLiu Hui-R64343 char *name, int lineno, int fld, int dcd_len) 3938a1edd7dSLiu Hui-R64343 { 3948a1edd7dSLiu Hui-R64343 int value; 3958a1edd7dSLiu Hui-R64343 static int cmd_ver_first = ~0; 3968a1edd7dSLiu Hui-R64343 3978a1edd7dSLiu Hui-R64343 switch (cmd) { 3988a1edd7dSLiu Hui-R64343 case CMD_IMAGE_VERSION: 3998a1edd7dSLiu Hui-R64343 imximage_version = get_cfg_value(token, name, lineno); 4008a1edd7dSLiu Hui-R64343 if (cmd_ver_first == 0) { 4018a1edd7dSLiu Hui-R64343 fprintf(stderr, "Error: %s[%d] - IMAGE_VERSION " 4028a1edd7dSLiu Hui-R64343 "command need be the first before other " 4038a1edd7dSLiu Hui-R64343 "valid command in the file\n", name, lineno); 4048a1edd7dSLiu Hui-R64343 exit(EXIT_FAILURE); 4058a1edd7dSLiu Hui-R64343 } 4068a1edd7dSLiu Hui-R64343 cmd_ver_first = 1; 40772048bc3SYork Sun set_hdr_func(); 4088a1edd7dSLiu Hui-R64343 break; 4098a1edd7dSLiu Hui-R64343 case CMD_BOOT_FROM: 410377e367aSStefano Babic imximage_ivt_offset = get_table_entry_id(imximage_boot_offset, 4118a1edd7dSLiu Hui-R64343 "imximage boot option", token); 4123150f92cSStefano Babic if (imximage_ivt_offset == -1) { 4138a1edd7dSLiu Hui-R64343 fprintf(stderr, "Error: %s[%d] -Invalid boot device" 4148a1edd7dSLiu Hui-R64343 "(%s)\n", name, lineno, token); 4158a1edd7dSLiu Hui-R64343 exit(EXIT_FAILURE); 4168a1edd7dSLiu Hui-R64343 } 417377e367aSStefano Babic 418377e367aSStefano Babic imximage_init_loadsize = 419377e367aSStefano Babic get_table_entry_id(imximage_boot_loadsize, 420377e367aSStefano Babic "imximage boot option", token); 421377e367aSStefano Babic 422377e367aSStefano Babic if (imximage_init_loadsize == -1) { 423377e367aSStefano Babic fprintf(stderr, 424377e367aSStefano Babic "Error: %s[%d] -Invalid boot device(%s)\n", 425377e367aSStefano Babic name, lineno, token); 426377e367aSStefano Babic exit(EXIT_FAILURE); 427377e367aSStefano Babic } 42801390affSStefano Babic 42901390affSStefano Babic /* 43001390affSStefano Babic * The SOC loads from the storage starting at address 0 43101390affSStefano Babic * then ensures that the load size contains the offset 43201390affSStefano Babic */ 43301390affSStefano Babic if (imximage_init_loadsize < imximage_ivt_offset) 43401390affSStefano Babic imximage_init_loadsize = imximage_ivt_offset; 4358a1edd7dSLiu Hui-R64343 if (unlikely(cmd_ver_first != 1)) 4368a1edd7dSLiu Hui-R64343 cmd_ver_first = 0; 4378a1edd7dSLiu Hui-R64343 break; 4386cb83829SMarek Vasut case CMD_BOOT_OFFSET: 4393150f92cSStefano Babic imximage_ivt_offset = get_cfg_value(token, name, lineno); 4406cb83829SMarek Vasut if (unlikely(cmd_ver_first != 1)) 4416cb83829SMarek Vasut cmd_ver_first = 0; 4426cb83829SMarek Vasut break; 4430b7f7c33SAdrian Alonso case CMD_WRITE_DATA: 4440b7f7c33SAdrian Alonso case CMD_WRITE_CLR_BIT: 4450b7f7c33SAdrian Alonso case CMD_CHECK_BITS_SET: 4460b7f7c33SAdrian Alonso case CMD_CHECK_BITS_CLR: 4478a1edd7dSLiu Hui-R64343 value = get_cfg_value(token, name, lineno); 4480b7f7c33SAdrian Alonso if (set_dcd_param) 4490b7f7c33SAdrian Alonso (*set_dcd_param)(imxhdr, dcd_len, cmd); 4508a1edd7dSLiu Hui-R64343 (*set_dcd_val)(imxhdr, name, lineno, fld, value, dcd_len); 4518a1edd7dSLiu Hui-R64343 if (unlikely(cmd_ver_first != 1)) 4528a1edd7dSLiu Hui-R64343 cmd_ver_first = 0; 4538a1edd7dSLiu Hui-R64343 break; 4540187c985SStefano Babic case CMD_CSF: 4550187c985SStefano Babic if (imximage_version != 2) { 4560187c985SStefano Babic fprintf(stderr, 4570187c985SStefano Babic "Error: %s[%d] - CSF only supported for VERSION 2(%s)\n", 4580187c985SStefano Babic name, lineno, token); 4590187c985SStefano Babic exit(EXIT_FAILURE); 4600187c985SStefano Babic } 4610187c985SStefano Babic imximage_csf_size = get_cfg_value(token, name, lineno); 4620187c985SStefano Babic if (unlikely(cmd_ver_first != 1)) 4630187c985SStefano Babic cmd_ver_first = 0; 4640187c985SStefano Babic break; 4658a1edd7dSLiu Hui-R64343 } 4668a1edd7dSLiu Hui-R64343 } 4678a1edd7dSLiu Hui-R64343 4688a1edd7dSLiu Hui-R64343 static void parse_cfg_fld(struct imx_header *imxhdr, int32_t *cmd, 4698a1edd7dSLiu Hui-R64343 char *token, char *name, int lineno, int fld, int *dcd_len) 4708a1edd7dSLiu Hui-R64343 { 4718a1edd7dSLiu Hui-R64343 int value; 4728a1edd7dSLiu Hui-R64343 4738a1edd7dSLiu Hui-R64343 switch (fld) { 4748a1edd7dSLiu Hui-R64343 case CFG_COMMAND: 4758a1edd7dSLiu Hui-R64343 *cmd = get_table_entry_id(imximage_cmds, 4768a1edd7dSLiu Hui-R64343 "imximage commands", token); 4778a1edd7dSLiu Hui-R64343 if (*cmd < 0) { 4788a1edd7dSLiu Hui-R64343 fprintf(stderr, "Error: %s[%d] - Invalid command" 4798a1edd7dSLiu Hui-R64343 "(%s)\n", name, lineno, token); 4808a1edd7dSLiu Hui-R64343 exit(EXIT_FAILURE); 4818a1edd7dSLiu Hui-R64343 } 4828a1edd7dSLiu Hui-R64343 break; 4838a1edd7dSLiu Hui-R64343 case CFG_REG_SIZE: 4848a1edd7dSLiu Hui-R64343 parse_cfg_cmd(imxhdr, *cmd, token, name, lineno, fld, *dcd_len); 4858a1edd7dSLiu Hui-R64343 break; 4868a1edd7dSLiu Hui-R64343 case CFG_REG_ADDRESS: 4878a1edd7dSLiu Hui-R64343 case CFG_REG_VALUE: 4880b7f7c33SAdrian Alonso switch(*cmd) { 4890b7f7c33SAdrian Alonso case CMD_WRITE_DATA: 4900b7f7c33SAdrian Alonso case CMD_WRITE_CLR_BIT: 4910b7f7c33SAdrian Alonso case CMD_CHECK_BITS_SET: 4920b7f7c33SAdrian Alonso case CMD_CHECK_BITS_CLR: 4938a1edd7dSLiu Hui-R64343 4948a1edd7dSLiu Hui-R64343 value = get_cfg_value(token, name, lineno); 4950b7f7c33SAdrian Alonso if (set_dcd_param) 4960b7f7c33SAdrian Alonso (*set_dcd_param)(imxhdr, *dcd_len, *cmd); 4970b7f7c33SAdrian Alonso (*set_dcd_val)(imxhdr, name, lineno, fld, value, 4980b7f7c33SAdrian Alonso *dcd_len); 4998a1edd7dSLiu Hui-R64343 5004d5fa985STroy Kisky if (fld == CFG_REG_VALUE) { 5018a1edd7dSLiu Hui-R64343 (*dcd_len)++; 5024d5fa985STroy Kisky if (*dcd_len > max_dcd_entries) { 5034d5fa985STroy Kisky fprintf(stderr, "Error: %s[%d] -" 5044d5fa985STroy Kisky "DCD table exceeds maximum size(%d)\n", 5054d5fa985STroy Kisky name, lineno, max_dcd_entries); 5064d5fa985STroy Kisky exit(EXIT_FAILURE); 5074d5fa985STroy Kisky } 5084d5fa985STroy Kisky } 5098a1edd7dSLiu Hui-R64343 break; 5108a1edd7dSLiu Hui-R64343 default: 5118a1edd7dSLiu Hui-R64343 break; 5128a1edd7dSLiu Hui-R64343 } 5130b7f7c33SAdrian Alonso break; 5140b7f7c33SAdrian Alonso default: 5150b7f7c33SAdrian Alonso break; 5160b7f7c33SAdrian Alonso } 5178a1edd7dSLiu Hui-R64343 } 5188a1edd7dSLiu Hui-R64343 static uint32_t parse_cfg_file(struct imx_header *imxhdr, char *name) 5198edcde5eSStefano Babic { 5208edcde5eSStefano Babic FILE *fd = NULL; 5218edcde5eSStefano Babic char *line = NULL; 5228edcde5eSStefano Babic char *token, *saveptr1, *saveptr2; 5238edcde5eSStefano Babic int lineno = 0; 5248a1edd7dSLiu Hui-R64343 int fld; 5250ad22703SKim Phillips size_t len; 5268edcde5eSStefano Babic int dcd_len = 0; 5278edcde5eSStefano Babic int32_t cmd; 5288edcde5eSStefano Babic 5298edcde5eSStefano Babic fd = fopen(name, "r"); 5308edcde5eSStefano Babic if (fd == 0) { 5318edcde5eSStefano Babic fprintf(stderr, "Error: %s - Can't open DCD file\n", name); 5328edcde5eSStefano Babic exit(EXIT_FAILURE); 5338edcde5eSStefano Babic } 5348edcde5eSStefano Babic 53501390affSStefano Babic /* 53601390affSStefano Babic * Very simple parsing, line starting with # are comments 5378edcde5eSStefano Babic * and are dropped 5388edcde5eSStefano Babic */ 5398edcde5eSStefano Babic while ((getline(&line, &len, fd)) > 0) { 5408edcde5eSStefano Babic lineno++; 5418edcde5eSStefano Babic 5428edcde5eSStefano Babic token = strtok_r(line, "\r\n", &saveptr1); 5438edcde5eSStefano Babic if (token == NULL) 5448edcde5eSStefano Babic continue; 5458edcde5eSStefano Babic 5468edcde5eSStefano Babic /* Check inside the single line */ 5478edcde5eSStefano Babic for (fld = CFG_COMMAND, cmd = CMD_INVALID, 5488edcde5eSStefano Babic line = token; ; line = NULL, fld++) { 5498edcde5eSStefano Babic token = strtok_r(line, " \t", &saveptr2); 5508edcde5eSStefano Babic if (token == NULL) 5518edcde5eSStefano Babic break; 5528edcde5eSStefano Babic 5538edcde5eSStefano Babic /* Drop all text starting with '#' as comments */ 5548edcde5eSStefano Babic if (token[0] == '#') 5558edcde5eSStefano Babic break; 5568edcde5eSStefano Babic 5578a1edd7dSLiu Hui-R64343 parse_cfg_fld(imxhdr, &cmd, token, name, 5588a1edd7dSLiu Hui-R64343 lineno, fld, &dcd_len); 5598edcde5eSStefano Babic } 5608edcde5eSStefano Babic 5618edcde5eSStefano Babic } 5628edcde5eSStefano Babic 5638a1edd7dSLiu Hui-R64343 (*set_dcd_rst)(imxhdr, dcd_len, name, lineno); 5648edcde5eSStefano Babic fclose(fd); 5658edcde5eSStefano Babic 5668d8cc828STroy Kisky /* Exit if there is no BOOT_FROM field specifying the flash_offset */ 5673150f92cSStefano Babic if (imximage_ivt_offset == FLASH_OFFSET_UNDEFINED) { 5688d8cc828STroy Kisky fprintf(stderr, "Error: No BOOT_FROM tag in %s\n", name); 5698d8cc828STroy Kisky exit(EXIT_FAILURE); 5708d8cc828STroy Kisky } 5715b28e913SStefano Babic return dcd_len; 5728edcde5eSStefano Babic } 5738edcde5eSStefano Babic 5748a1edd7dSLiu Hui-R64343 5758a1edd7dSLiu Hui-R64343 static int imximage_check_image_types(uint8_t type) 5768a1edd7dSLiu Hui-R64343 { 5778a1edd7dSLiu Hui-R64343 if (type == IH_TYPE_IMXIMAGE) 5788a1edd7dSLiu Hui-R64343 return EXIT_SUCCESS; 5798a1edd7dSLiu Hui-R64343 else 5808a1edd7dSLiu Hui-R64343 return EXIT_FAILURE; 5818a1edd7dSLiu Hui-R64343 } 5828a1edd7dSLiu Hui-R64343 5838a1edd7dSLiu Hui-R64343 static int imximage_verify_header(unsigned char *ptr, int image_size, 584f86ed6a8SGuilherme Maciel Ferreira struct image_tool_params *params) 5858a1edd7dSLiu Hui-R64343 { 5868a1edd7dSLiu Hui-R64343 struct imx_header *imx_hdr = (struct imx_header *) ptr; 5878a1edd7dSLiu Hui-R64343 5888a1edd7dSLiu Hui-R64343 if (detect_imximage_version(imx_hdr) == IMXIMAGE_VER_INVALID) 5898a1edd7dSLiu Hui-R64343 return -FDT_ERR_BADSTRUCTURE; 5908a1edd7dSLiu Hui-R64343 5918a1edd7dSLiu Hui-R64343 return 0; 5928a1edd7dSLiu Hui-R64343 } 5938a1edd7dSLiu Hui-R64343 5948a1edd7dSLiu Hui-R64343 static void imximage_print_header(const void *ptr) 5958a1edd7dSLiu Hui-R64343 { 5968a1edd7dSLiu Hui-R64343 struct imx_header *imx_hdr = (struct imx_header *) ptr; 5978a1edd7dSLiu Hui-R64343 uint32_t version = detect_imximage_version(imx_hdr); 5988a1edd7dSLiu Hui-R64343 5998a1edd7dSLiu Hui-R64343 switch (version) { 6008a1edd7dSLiu Hui-R64343 case IMXIMAGE_V1: 6018a1edd7dSLiu Hui-R64343 print_hdr_v1(imx_hdr); 6028a1edd7dSLiu Hui-R64343 break; 6038a1edd7dSLiu Hui-R64343 case IMXIMAGE_V2: 6048a1edd7dSLiu Hui-R64343 print_hdr_v2(imx_hdr); 6058a1edd7dSLiu Hui-R64343 break; 6068a1edd7dSLiu Hui-R64343 default: 6078a1edd7dSLiu Hui-R64343 err_imximage_version(version); 6088a1edd7dSLiu Hui-R64343 break; 6098a1edd7dSLiu Hui-R64343 } 6108a1edd7dSLiu Hui-R64343 } 6118a1edd7dSLiu Hui-R64343 6128edcde5eSStefano Babic static void imximage_set_header(void *ptr, struct stat *sbuf, int ifd, 613f86ed6a8SGuilherme Maciel Ferreira struct image_tool_params *params) 6148edcde5eSStefano Babic { 6158a1edd7dSLiu Hui-R64343 struct imx_header *imxhdr = (struct imx_header *)ptr; 6168a1edd7dSLiu Hui-R64343 uint32_t dcd_len; 6178edcde5eSStefano Babic 6188a1edd7dSLiu Hui-R64343 /* 6198a1edd7dSLiu Hui-R64343 * In order to not change the old imx cfg file 6208a1edd7dSLiu Hui-R64343 * by adding VERSION command into it, here need 6218a1edd7dSLiu Hui-R64343 * set up function ptr group to V1 by default. 6228a1edd7dSLiu Hui-R64343 */ 6238a1edd7dSLiu Hui-R64343 imximage_version = IMXIMAGE_V1; 62449d3e272SDirk Behme /* Be able to detect if the cfg file has no BOOT_FROM tag */ 6253150f92cSStefano Babic imximage_ivt_offset = FLASH_OFFSET_UNDEFINED; 6260187c985SStefano Babic imximage_csf_size = 0; 62772048bc3SYork Sun set_hdr_func(); 6288edcde5eSStefano Babic 6298edcde5eSStefano Babic /* Parse dcd configuration file */ 6308a1edd7dSLiu Hui-R64343 dcd_len = parse_cfg_file(imxhdr, params->imagename); 6318edcde5eSStefano Babic 63203ea24b2SYe.Li if (imximage_version == IMXIMAGE_V2) { 63303ea24b2SYe.Li if (imximage_init_loadsize < imximage_ivt_offset + 63403ea24b2SYe.Li sizeof(imx_header_v2_t)) 63503ea24b2SYe.Li imximage_init_loadsize = imximage_ivt_offset + 63603ea24b2SYe.Li sizeof(imx_header_v2_t); 63703ea24b2SYe.Li } 63803ea24b2SYe.Li 6398a1edd7dSLiu Hui-R64343 /* Set the imx header */ 6403150f92cSStefano Babic (*set_imx_hdr)(imxhdr, dcd_len, params->ep, imximage_ivt_offset); 6411411fb37SFabio Estevam 6421411fb37SFabio Estevam /* 6431411fb37SFabio Estevam * ROM bug alert 644895d9966SMarek Vasut * 645895d9966SMarek Vasut * MX53 only loads 512 byte multiples in case of SD boot. 646895d9966SMarek Vasut * MX53 only loads NAND page multiples in case of NAND boot and 647895d9966SMarek Vasut * supports up to 4096 byte large pages, thus align to 4096. 648895d9966SMarek Vasut * 649895d9966SMarek Vasut * The remaining fraction of a block bytes would not be loaded! 6501411fb37SFabio Estevam */ 651de979804SYe.Li *header_size_ptr = ROUND((sbuf->st_size + imximage_ivt_offset), 4096); 6520187c985SStefano Babic 6530187c985SStefano Babic if (csf_ptr && imximage_csf_size) { 6540187c985SStefano Babic *csf_ptr = params->ep - imximage_init_loadsize + 6550187c985SStefano Babic *header_size_ptr; 6560187c985SStefano Babic *header_size_ptr += imximage_csf_size; 6570187c985SStefano Babic } 6588edcde5eSStefano Babic } 6598edcde5eSStefano Babic 660f86ed6a8SGuilherme Maciel Ferreira int imximage_check_params(struct image_tool_params *params) 6618edcde5eSStefano Babic { 6628edcde5eSStefano Babic if (!params) 6638edcde5eSStefano Babic return CFG_INVALID; 6648edcde5eSStefano Babic if (!strlen(params->imagename)) { 6658edcde5eSStefano Babic fprintf(stderr, "Error: %s - Configuration file not specified, " 6668edcde5eSStefano Babic "it is needed for imximage generation\n", 6678edcde5eSStefano Babic params->cmdname); 6688edcde5eSStefano Babic return CFG_INVALID; 6698edcde5eSStefano Babic } 6708edcde5eSStefano Babic /* 6718edcde5eSStefano Babic * Check parameters: 6728edcde5eSStefano Babic * XIP is not allowed and verify that incompatible 6738edcde5eSStefano Babic * parameters are not sent at the same time 6748edcde5eSStefano Babic * For example, if list is required a data image must not be provided 6758edcde5eSStefano Babic */ 6768edcde5eSStefano Babic return (params->dflag && (params->fflag || params->lflag)) || 6778edcde5eSStefano Babic (params->fflag && (params->dflag || params->lflag)) || 6788edcde5eSStefano Babic (params->lflag && (params->dflag || params->fflag)) || 6798edcde5eSStefano Babic (params->xflag) || !(strlen(params->imagename)); 6808edcde5eSStefano Babic } 6818edcde5eSStefano Babic 682f86ed6a8SGuilherme Maciel Ferreira static int imximage_generate(struct image_tool_params *params, 68301390affSStefano Babic struct image_type_params *tparams) 68401390affSStefano Babic { 68501390affSStefano Babic struct imx_header *imxhdr; 68601390affSStefano Babic size_t alloc_len; 68701390affSStefano Babic struct stat sbuf; 68801390affSStefano Babic char *datafile = params->datafile; 68901390affSStefano Babic uint32_t pad_len; 69001390affSStefano Babic 69101390affSStefano Babic memset(&imximage_header, 0, sizeof(imximage_header)); 69201390affSStefano Babic 69301390affSStefano Babic /* 69401390affSStefano Babic * In order to not change the old imx cfg file 69501390affSStefano Babic * by adding VERSION command into it, here need 69601390affSStefano Babic * set up function ptr group to V1 by default. 69701390affSStefano Babic */ 69801390affSStefano Babic imximage_version = IMXIMAGE_V1; 69901390affSStefano Babic /* Be able to detect if the cfg file has no BOOT_FROM tag */ 70001390affSStefano Babic imximage_ivt_offset = FLASH_OFFSET_UNDEFINED; 70101390affSStefano Babic imximage_csf_size = 0; 70272048bc3SYork Sun set_hdr_func(); 70301390affSStefano Babic 70401390affSStefano Babic /* Parse dcd configuration file */ 70501390affSStefano Babic parse_cfg_file(&imximage_header, params->imagename); 70601390affSStefano Babic 70701390affSStefano Babic /* TODO: check i.MX image V1 handling, for now use 'old' style */ 70801390affSStefano Babic if (imximage_version == IMXIMAGE_V1) { 70901390affSStefano Babic alloc_len = 4096; 71001390affSStefano Babic } else { 71101390affSStefano Babic if (imximage_init_loadsize < imximage_ivt_offset + 71201390affSStefano Babic sizeof(imx_header_v2_t)) 71301390affSStefano Babic imximage_init_loadsize = imximage_ivt_offset + 71401390affSStefano Babic sizeof(imx_header_v2_t); 71501390affSStefano Babic alloc_len = imximage_init_loadsize - imximage_ivt_offset; 71601390affSStefano Babic } 71701390affSStefano Babic 71801390affSStefano Babic if (alloc_len < sizeof(struct imx_header)) { 71901390affSStefano Babic fprintf(stderr, "%s: header error\n", 72001390affSStefano Babic params->cmdname); 72101390affSStefano Babic exit(EXIT_FAILURE); 72201390affSStefano Babic } 72301390affSStefano Babic 72401390affSStefano Babic imxhdr = malloc(alloc_len); 72501390affSStefano Babic 72601390affSStefano Babic if (!imxhdr) { 72701390affSStefano Babic fprintf(stderr, "%s: malloc return failure: %s\n", 72801390affSStefano Babic params->cmdname, strerror(errno)); 72901390affSStefano Babic exit(EXIT_FAILURE); 73001390affSStefano Babic } 73101390affSStefano Babic 73201390affSStefano Babic memset(imxhdr, 0, alloc_len); 73301390affSStefano Babic 73401390affSStefano Babic tparams->header_size = alloc_len; 73501390affSStefano Babic tparams->hdr = imxhdr; 73601390affSStefano Babic 73701390affSStefano Babic /* determine data image file length */ 73801390affSStefano Babic 73901390affSStefano Babic if (stat(datafile, &sbuf) < 0) { 74001390affSStefano Babic fprintf(stderr, "%s: Can't stat %s: %s\n", 74101390affSStefano Babic params->cmdname, datafile, strerror(errno)); 74201390affSStefano Babic exit(EXIT_FAILURE); 74301390affSStefano Babic } 74401390affSStefano Babic 74501390affSStefano Babic pad_len = ROUND(sbuf.st_size, 4096) - sbuf.st_size; 74601390affSStefano Babic 74701390affSStefano Babic /* TODO: check i.MX image V1 handling, for now use 'old' style */ 74801390affSStefano Babic if (imximage_version == IMXIMAGE_V1) 74901390affSStefano Babic return 0; 75001390affSStefano Babic else 75101390affSStefano Babic return pad_len; 75201390affSStefano Babic } 75301390affSStefano Babic 75401390affSStefano Babic 7558edcde5eSStefano Babic /* 7568edcde5eSStefano Babic * imximage parameters 7578edcde5eSStefano Babic */ 758a93648d1SGuilherme Maciel Ferreira U_BOOT_IMAGE_TYPE( 759a93648d1SGuilherme Maciel Ferreira imximage, 760a93648d1SGuilherme Maciel Ferreira "Freescale i.MX Boot Image support", 761a93648d1SGuilherme Maciel Ferreira 0, 762a93648d1SGuilherme Maciel Ferreira NULL, 763a93648d1SGuilherme Maciel Ferreira imximage_check_params, 764a93648d1SGuilherme Maciel Ferreira imximage_verify_header, 765a93648d1SGuilherme Maciel Ferreira imximage_print_header, 766a93648d1SGuilherme Maciel Ferreira imximage_set_header, 767a93648d1SGuilherme Maciel Ferreira NULL, 768a93648d1SGuilherme Maciel Ferreira imximage_check_image_types, 769a93648d1SGuilherme Maciel Ferreira NULL, 770a93648d1SGuilherme Maciel Ferreira imximage_generate 771a93648d1SGuilherme Maciel Ferreira ); 772