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 * 98edcde5eSStefano Babic * See file CREDITS for list of people who contributed to this 108edcde5eSStefano Babic * project. 118edcde5eSStefano Babic * 128edcde5eSStefano Babic * This program is free software; you can redistribute it and/or 138edcde5eSStefano Babic * modify it under the terms of the GNU General Public License as 148edcde5eSStefano Babic * published by the Free Software Foundation; either version 2 of 158edcde5eSStefano Babic * the License, or (at your option) any later version. 168edcde5eSStefano Babic * 178edcde5eSStefano Babic * This program is distributed in the hope that it will be useful, 188edcde5eSStefano Babic * but WITHOUT ANY WARRANTY; without even the implied warranty of 198edcde5eSStefano Babic * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 208edcde5eSStefano Babic * GNU General Public License for more details. 218edcde5eSStefano Babic * 228edcde5eSStefano Babic * You should have received a copy of the GNU General Public License 238edcde5eSStefano Babic * along with this program; if not, write to the Free Software 248edcde5eSStefano Babic * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 258edcde5eSStefano Babic * MA 02111-1307 USA 268edcde5eSStefano Babic */ 278edcde5eSStefano Babic 28249d4decSKumar Gala /* Required to obtain the getline prototype from stdio.h */ 29249d4decSKumar Gala #define _GNU_SOURCE 30249d4decSKumar Gala 318edcde5eSStefano Babic #include "mkimage.h" 328edcde5eSStefano Babic #include <image.h> 338edcde5eSStefano Babic #include "imximage.h" 348edcde5eSStefano Babic 358edcde5eSStefano Babic /* 368edcde5eSStefano Babic * Supported commands for configuration file 378edcde5eSStefano Babic */ 388edcde5eSStefano Babic static table_entry_t imximage_cmds[] = { 39f581e3a2SStefano Babic {CMD_BOOT_FROM, "BOOT_FROM", "boot command", }, 406cb83829SMarek Vasut {CMD_BOOT_OFFSET, "BOOT_OFFSET", "Boot offset", }, 418edcde5eSStefano Babic {CMD_DATA, "DATA", "Reg Write Data", }, 428a1edd7dSLiu Hui-R64343 {CMD_IMAGE_VERSION, "IMAGE_VERSION", "image version", }, 438edcde5eSStefano Babic {-1, "", "", }, 448edcde5eSStefano Babic }; 458edcde5eSStefano Babic 468edcde5eSStefano Babic /* 478edcde5eSStefano Babic * Supported Boot options for configuration file 488edcde5eSStefano Babic * this is needed to set the correct flash offset 498edcde5eSStefano Babic */ 508edcde5eSStefano Babic static table_entry_t imximage_bootops[] = { 518edcde5eSStefano Babic {FLASH_OFFSET_ONENAND, "onenand", "OneNAND Flash",}, 52bd25864cSDirk Behme {FLASH_OFFSET_NAND, "nand", "NAND Flash", }, 5319b409c0SDirk Behme {FLASH_OFFSET_NOR, "nor", "NOR Flash", }, 5419b409c0SDirk Behme {FLASH_OFFSET_SATA, "sata", "SATA Disk", }, 55bd25864cSDirk Behme {FLASH_OFFSET_SD, "sd", "SD Card", }, 56bd25864cSDirk Behme {FLASH_OFFSET_SPI, "spi", "SPI Flash", }, 578edcde5eSStefano Babic {-1, "", "Invalid", }, 588edcde5eSStefano Babic }; 598edcde5eSStefano Babic 608a1edd7dSLiu Hui-R64343 /* 618a1edd7dSLiu Hui-R64343 * IMXIMAGE version definition for i.MX chips 628a1edd7dSLiu Hui-R64343 */ 638a1edd7dSLiu Hui-R64343 static table_entry_t imximage_versions[] = { 648a1edd7dSLiu Hui-R64343 {IMXIMAGE_V1, "", " (i.MX25/35/51 compatible)", }, 6519b409c0SDirk Behme {IMXIMAGE_V2, "", " (i.MX53/6 compatible)", }, 668a1edd7dSLiu Hui-R64343 {-1, "", " (Invalid)", }, 678a1edd7dSLiu Hui-R64343 }; 688edcde5eSStefano Babic 698edcde5eSStefano Babic static struct imx_header imximage_header; 708a1edd7dSLiu Hui-R64343 static uint32_t imximage_version; 718a1edd7dSLiu Hui-R64343 728a1edd7dSLiu Hui-R64343 static set_dcd_val_t set_dcd_val; 738a1edd7dSLiu Hui-R64343 static set_dcd_rst_t set_dcd_rst; 748a1edd7dSLiu Hui-R64343 static set_imx_hdr_t set_imx_hdr; 754d5fa985STroy Kisky static uint32_t max_dcd_entries; 7624331982STroy Kisky static uint32_t *header_size_ptr; 778edcde5eSStefano Babic 788edcde5eSStefano Babic static uint32_t get_cfg_value(char *token, char *name, int linenr) 798edcde5eSStefano Babic { 808edcde5eSStefano Babic char *endptr; 818edcde5eSStefano Babic uint32_t value; 828edcde5eSStefano Babic 838edcde5eSStefano Babic errno = 0; 848edcde5eSStefano Babic value = strtoul(token, &endptr, 16); 858edcde5eSStefano Babic if (errno || (token == endptr)) { 868edcde5eSStefano Babic fprintf(stderr, "Error: %s[%d] - Invalid hex data(%s)\n", 878edcde5eSStefano Babic name, linenr, token); 888edcde5eSStefano Babic exit(EXIT_FAILURE); 898edcde5eSStefano Babic } 908edcde5eSStefano Babic return value; 918edcde5eSStefano Babic } 928edcde5eSStefano Babic 938a1edd7dSLiu Hui-R64343 static uint32_t detect_imximage_version(struct imx_header *imx_hdr) 948edcde5eSStefano Babic { 958a1edd7dSLiu Hui-R64343 imx_header_v1_t *hdr_v1 = &imx_hdr->header.hdr_v1; 968a1edd7dSLiu Hui-R64343 imx_header_v2_t *hdr_v2 = &imx_hdr->header.hdr_v2; 978a1edd7dSLiu Hui-R64343 flash_header_v1_t *fhdr_v1 = &hdr_v1->fhdr; 988a1edd7dSLiu Hui-R64343 flash_header_v2_t *fhdr_v2 = &hdr_v2->fhdr; 998a1edd7dSLiu Hui-R64343 1008a1edd7dSLiu Hui-R64343 /* Try to detect V1 */ 1018a1edd7dSLiu Hui-R64343 if ((fhdr_v1->app_code_barker == APP_CODE_BARKER) && 1028a1edd7dSLiu Hui-R64343 (hdr_v1->dcd_table.preamble.barker == DCD_BARKER)) 1038a1edd7dSLiu Hui-R64343 return IMXIMAGE_V1; 1048a1edd7dSLiu Hui-R64343 1058a1edd7dSLiu Hui-R64343 /* Try to detect V2 */ 1068a1edd7dSLiu Hui-R64343 if ((fhdr_v2->header.tag == IVT_HEADER_TAG) && 1078a1edd7dSLiu Hui-R64343 (hdr_v2->dcd_table.header.tag == DCD_HEADER_TAG)) 1088a1edd7dSLiu Hui-R64343 return IMXIMAGE_V2; 1098a1edd7dSLiu Hui-R64343 1108a1edd7dSLiu Hui-R64343 return IMXIMAGE_VER_INVALID; 1118edcde5eSStefano Babic } 1128edcde5eSStefano Babic 1138a1edd7dSLiu Hui-R64343 static void err_imximage_version(int version) 1148edcde5eSStefano Babic { 1158edcde5eSStefano Babic fprintf(stderr, 1168a1edd7dSLiu Hui-R64343 "Error: Unsupported imximage version:%d\n", version); 1178a1edd7dSLiu Hui-R64343 1188edcde5eSStefano Babic exit(EXIT_FAILURE); 1198edcde5eSStefano Babic } 1208edcde5eSStefano Babic 1218a1edd7dSLiu Hui-R64343 static void set_dcd_val_v1(struct imx_header *imxhdr, char *name, int lineno, 1228a1edd7dSLiu Hui-R64343 int fld, uint32_t value, uint32_t off) 1238a1edd7dSLiu Hui-R64343 { 1248a1edd7dSLiu Hui-R64343 dcd_v1_t *dcd_v1 = &imxhdr->header.hdr_v1.dcd_table; 1258edcde5eSStefano Babic 1268a1edd7dSLiu Hui-R64343 switch (fld) { 1278a1edd7dSLiu Hui-R64343 case CFG_REG_SIZE: 1288a1edd7dSLiu Hui-R64343 /* Byte, halfword, word */ 1298a1edd7dSLiu Hui-R64343 if ((value != 1) && (value != 2) && (value != 4)) { 1308a1edd7dSLiu Hui-R64343 fprintf(stderr, "Error: %s[%d] - " 1318a1edd7dSLiu Hui-R64343 "Invalid register size " "(%d)\n", 1328a1edd7dSLiu Hui-R64343 name, lineno, value); 1338a1edd7dSLiu Hui-R64343 exit(EXIT_FAILURE); 1348a1edd7dSLiu Hui-R64343 } 1358a1edd7dSLiu Hui-R64343 dcd_v1->addr_data[off].type = value; 1368a1edd7dSLiu Hui-R64343 break; 1378a1edd7dSLiu Hui-R64343 case CFG_REG_ADDRESS: 1388a1edd7dSLiu Hui-R64343 dcd_v1->addr_data[off].addr = value; 1398a1edd7dSLiu Hui-R64343 break; 1408a1edd7dSLiu Hui-R64343 case CFG_REG_VALUE: 1418a1edd7dSLiu Hui-R64343 dcd_v1->addr_data[off].value = value; 1428a1edd7dSLiu Hui-R64343 break; 1438a1edd7dSLiu Hui-R64343 default: 1448a1edd7dSLiu Hui-R64343 break; 1458a1edd7dSLiu Hui-R64343 1468a1edd7dSLiu Hui-R64343 } 1478edcde5eSStefano Babic } 1488edcde5eSStefano Babic 1498a1edd7dSLiu Hui-R64343 static void set_dcd_val_v2(struct imx_header *imxhdr, char *name, int lineno, 1508a1edd7dSLiu Hui-R64343 int fld, uint32_t value, uint32_t off) 1518a1edd7dSLiu Hui-R64343 { 1528a1edd7dSLiu Hui-R64343 dcd_v2_t *dcd_v2 = &imxhdr->header.hdr_v2.dcd_table; 1538a1edd7dSLiu Hui-R64343 1548a1edd7dSLiu Hui-R64343 switch (fld) { 1558a1edd7dSLiu Hui-R64343 case CFG_REG_ADDRESS: 1568a1edd7dSLiu Hui-R64343 dcd_v2->addr_data[off].addr = cpu_to_be32(value); 1578a1edd7dSLiu Hui-R64343 break; 1588a1edd7dSLiu Hui-R64343 case CFG_REG_VALUE: 1598a1edd7dSLiu Hui-R64343 dcd_v2->addr_data[off].value = cpu_to_be32(value); 1608a1edd7dSLiu Hui-R64343 break; 1618a1edd7dSLiu Hui-R64343 default: 1628a1edd7dSLiu Hui-R64343 break; 1638a1edd7dSLiu Hui-R64343 1648a1edd7dSLiu Hui-R64343 } 1658a1edd7dSLiu Hui-R64343 } 1668a1edd7dSLiu Hui-R64343 1678a1edd7dSLiu Hui-R64343 /* 1688a1edd7dSLiu Hui-R64343 * Complete setting up the rest field of DCD of V1 1698a1edd7dSLiu Hui-R64343 * such as barker code and DCD data length. 1708a1edd7dSLiu Hui-R64343 */ 1718a1edd7dSLiu Hui-R64343 static void set_dcd_rst_v1(struct imx_header *imxhdr, uint32_t dcd_len, 1728a1edd7dSLiu Hui-R64343 char *name, int lineno) 1738a1edd7dSLiu Hui-R64343 { 1748a1edd7dSLiu Hui-R64343 dcd_v1_t *dcd_v1 = &imxhdr->header.hdr_v1.dcd_table; 1758a1edd7dSLiu Hui-R64343 1768a1edd7dSLiu Hui-R64343 dcd_v1->preamble.barker = DCD_BARKER; 1778a1edd7dSLiu Hui-R64343 dcd_v1->preamble.length = dcd_len * sizeof(dcd_type_addr_data_t); 1788a1edd7dSLiu Hui-R64343 } 1798a1edd7dSLiu Hui-R64343 1808a1edd7dSLiu Hui-R64343 /* 1818a1edd7dSLiu Hui-R64343 * Complete setting up the reset field of DCD of V2 1828a1edd7dSLiu Hui-R64343 * such as DCD tag, version, length, etc. 1838a1edd7dSLiu Hui-R64343 */ 1848a1edd7dSLiu Hui-R64343 static void set_dcd_rst_v2(struct imx_header *imxhdr, uint32_t dcd_len, 1858a1edd7dSLiu Hui-R64343 char *name, int lineno) 1868a1edd7dSLiu Hui-R64343 { 1878a1edd7dSLiu Hui-R64343 dcd_v2_t *dcd_v2 = &imxhdr->header.hdr_v2.dcd_table; 1888a1edd7dSLiu Hui-R64343 1898a1edd7dSLiu Hui-R64343 dcd_v2->header.tag = DCD_HEADER_TAG; 1908a1edd7dSLiu Hui-R64343 dcd_v2->header.length = cpu_to_be16( 1918a1edd7dSLiu Hui-R64343 dcd_len * sizeof(dcd_addr_data_t) + 8); 1928a1edd7dSLiu Hui-R64343 dcd_v2->header.version = DCD_VERSION; 1938a1edd7dSLiu Hui-R64343 dcd_v2->write_dcd_command.tag = DCD_COMMAND_TAG; 1948a1edd7dSLiu Hui-R64343 dcd_v2->write_dcd_command.length = cpu_to_be16( 1958a1edd7dSLiu Hui-R64343 dcd_len * sizeof(dcd_addr_data_t) + 4); 1968a1edd7dSLiu Hui-R64343 dcd_v2->write_dcd_command.param = DCD_COMMAND_PARAM; 1978a1edd7dSLiu Hui-R64343 } 1988a1edd7dSLiu Hui-R64343 1998a1edd7dSLiu Hui-R64343 static void set_imx_hdr_v1(struct imx_header *imxhdr, uint32_t dcd_len, 200ad0826dcSTroy Kisky uint32_t entry_point, uint32_t flash_offset) 2018a1edd7dSLiu Hui-R64343 { 2028a1edd7dSLiu Hui-R64343 imx_header_v1_t *hdr_v1 = &imxhdr->header.hdr_v1; 2038a1edd7dSLiu Hui-R64343 flash_header_v1_t *fhdr_v1 = &hdr_v1->fhdr; 2048a1edd7dSLiu Hui-R64343 dcd_v1_t *dcd_v1 = &hdr_v1->dcd_table; 205ab857f26STroy Kisky uint32_t hdr_base; 20624331982STroy Kisky uint32_t header_length = (((char *)&dcd_v1->addr_data[dcd_len].addr) 20724331982STroy Kisky - ((char *)imxhdr)); 2088a1edd7dSLiu Hui-R64343 2098a1edd7dSLiu Hui-R64343 /* Set magic number */ 2108a1edd7dSLiu Hui-R64343 fhdr_v1->app_code_barker = APP_CODE_BARKER; 2118a1edd7dSLiu Hui-R64343 212ab857f26STroy Kisky hdr_base = entry_point - sizeof(struct imx_header); 213ab857f26STroy Kisky fhdr_v1->app_dest_ptr = hdr_base - flash_offset; 214ad0826dcSTroy Kisky fhdr_v1->app_code_jump_vector = entry_point; 2158a1edd7dSLiu Hui-R64343 216ab857f26STroy Kisky fhdr_v1->dcd_ptr_ptr = hdr_base + offsetof(flash_header_v1_t, dcd_ptr); 217ab857f26STroy Kisky fhdr_v1->dcd_ptr = hdr_base + offsetof(imx_header_v1_t, dcd_table); 2188a1edd7dSLiu Hui-R64343 2198a1edd7dSLiu Hui-R64343 /* Security feature are not supported */ 2208a1edd7dSLiu Hui-R64343 fhdr_v1->app_code_csf = 0; 2218a1edd7dSLiu Hui-R64343 fhdr_v1->super_root_key = 0; 22224331982STroy Kisky header_size_ptr = (uint32_t *)(((char *)imxhdr) + header_length - 4); 2238a1edd7dSLiu Hui-R64343 } 2248a1edd7dSLiu Hui-R64343 2258a1edd7dSLiu Hui-R64343 static void set_imx_hdr_v2(struct imx_header *imxhdr, uint32_t dcd_len, 226ad0826dcSTroy Kisky uint32_t entry_point, uint32_t flash_offset) 2278a1edd7dSLiu Hui-R64343 { 2288a1edd7dSLiu Hui-R64343 imx_header_v2_t *hdr_v2 = &imxhdr->header.hdr_v2; 2298a1edd7dSLiu Hui-R64343 flash_header_v2_t *fhdr_v2 = &hdr_v2->fhdr; 230ab857f26STroy Kisky uint32_t hdr_base; 2318a1edd7dSLiu Hui-R64343 2328a1edd7dSLiu Hui-R64343 /* Set magic number */ 2338a1edd7dSLiu Hui-R64343 fhdr_v2->header.tag = IVT_HEADER_TAG; /* 0xD1 */ 2348a1edd7dSLiu Hui-R64343 fhdr_v2->header.length = cpu_to_be16(sizeof(flash_header_v2_t)); 2358a1edd7dSLiu Hui-R64343 fhdr_v2->header.version = IVT_VERSION; /* 0x40 */ 2368a1edd7dSLiu Hui-R64343 237ad0826dcSTroy Kisky fhdr_v2->entry = entry_point; 2388a1edd7dSLiu Hui-R64343 fhdr_v2->reserved1 = fhdr_v2->reserved2 = 0; 239ab857f26STroy Kisky fhdr_v2->self = hdr_base = entry_point - sizeof(struct imx_header); 2408a1edd7dSLiu Hui-R64343 241ab857f26STroy Kisky fhdr_v2->dcd_ptr = hdr_base + offsetof(imx_header_v2_t, dcd_table); 242ab857f26STroy Kisky fhdr_v2->boot_data_ptr = hdr_base 243ab857f26STroy Kisky + offsetof(imx_header_v2_t, boot_data); 244ab857f26STroy Kisky hdr_v2->boot_data.start = hdr_base - flash_offset; 2458a1edd7dSLiu Hui-R64343 2468a1edd7dSLiu Hui-R64343 /* Security feature are not supported */ 2478a1edd7dSLiu Hui-R64343 fhdr_v2->csf = 0; 24824331982STroy Kisky header_size_ptr = &hdr_v2->boot_data.size; 2498a1edd7dSLiu Hui-R64343 } 2508a1edd7dSLiu Hui-R64343 2518a1edd7dSLiu Hui-R64343 static void set_hdr_func(struct imx_header *imxhdr) 2528a1edd7dSLiu Hui-R64343 { 2538a1edd7dSLiu Hui-R64343 switch (imximage_version) { 2548a1edd7dSLiu Hui-R64343 case IMXIMAGE_V1: 2558a1edd7dSLiu Hui-R64343 set_dcd_val = set_dcd_val_v1; 2568a1edd7dSLiu Hui-R64343 set_dcd_rst = set_dcd_rst_v1; 2578a1edd7dSLiu Hui-R64343 set_imx_hdr = set_imx_hdr_v1; 2584d5fa985STroy Kisky max_dcd_entries = MAX_HW_CFG_SIZE_V1; 2598a1edd7dSLiu Hui-R64343 break; 2608a1edd7dSLiu Hui-R64343 case IMXIMAGE_V2: 2618a1edd7dSLiu Hui-R64343 set_dcd_val = set_dcd_val_v2; 2628a1edd7dSLiu Hui-R64343 set_dcd_rst = set_dcd_rst_v2; 2638a1edd7dSLiu Hui-R64343 set_imx_hdr = set_imx_hdr_v2; 2644d5fa985STroy Kisky max_dcd_entries = MAX_HW_CFG_SIZE_V2; 2658a1edd7dSLiu Hui-R64343 break; 2668a1edd7dSLiu Hui-R64343 default: 2678a1edd7dSLiu Hui-R64343 err_imximage_version(imximage_version); 2688a1edd7dSLiu Hui-R64343 break; 2698a1edd7dSLiu Hui-R64343 } 2708a1edd7dSLiu Hui-R64343 } 2718a1edd7dSLiu Hui-R64343 2728a1edd7dSLiu Hui-R64343 static void print_hdr_v1(struct imx_header *imx_hdr) 2738a1edd7dSLiu Hui-R64343 { 2748a1edd7dSLiu Hui-R64343 imx_header_v1_t *hdr_v1 = &imx_hdr->header.hdr_v1; 2758a1edd7dSLiu Hui-R64343 flash_header_v1_t *fhdr_v1 = &hdr_v1->fhdr; 2768a1edd7dSLiu Hui-R64343 dcd_v1_t *dcd_v1 = &hdr_v1->dcd_table; 2778a1edd7dSLiu Hui-R64343 uint32_t size, length, ver; 2788a1edd7dSLiu Hui-R64343 2798a1edd7dSLiu Hui-R64343 size = dcd_v1->preamble.length; 2808a1edd7dSLiu Hui-R64343 if (size > (MAX_HW_CFG_SIZE_V1 * sizeof(dcd_type_addr_data_t))) { 2818a1edd7dSLiu Hui-R64343 fprintf(stderr, 2828a1edd7dSLiu Hui-R64343 "Error: Image corrupt DCD size %d exceed maximum %d\n", 2838a1edd7dSLiu Hui-R64343 (uint32_t)(size / sizeof(dcd_type_addr_data_t)), 2848a1edd7dSLiu Hui-R64343 MAX_HW_CFG_SIZE_V1); 2858a1edd7dSLiu Hui-R64343 exit(EXIT_FAILURE); 2868a1edd7dSLiu Hui-R64343 } 2878a1edd7dSLiu Hui-R64343 2888a1edd7dSLiu Hui-R64343 length = dcd_v1->preamble.length / sizeof(dcd_type_addr_data_t); 2898a1edd7dSLiu Hui-R64343 ver = detect_imximage_version(imx_hdr); 2908a1edd7dSLiu Hui-R64343 2918a1edd7dSLiu Hui-R64343 printf("Image Type: Freescale IMX Boot Image\n"); 2928a1edd7dSLiu Hui-R64343 printf("Image Ver: %x", ver); 2938a1edd7dSLiu Hui-R64343 printf("%s\n", get_table_entry_name(imximage_versions, NULL, ver)); 2948a1edd7dSLiu Hui-R64343 printf("Data Size: "); 2958a1edd7dSLiu Hui-R64343 genimg_print_size(dcd_v1->addr_data[length].type); 2968a1edd7dSLiu Hui-R64343 printf("Load Address: %08x\n", (uint32_t)fhdr_v1->app_dest_ptr); 2978a1edd7dSLiu Hui-R64343 printf("Entry Point: %08x\n", (uint32_t)fhdr_v1->app_code_jump_vector); 2988a1edd7dSLiu Hui-R64343 } 2998a1edd7dSLiu Hui-R64343 3008a1edd7dSLiu Hui-R64343 static void print_hdr_v2(struct imx_header *imx_hdr) 3018a1edd7dSLiu Hui-R64343 { 3028a1edd7dSLiu Hui-R64343 imx_header_v2_t *hdr_v2 = &imx_hdr->header.hdr_v2; 3038a1edd7dSLiu Hui-R64343 flash_header_v2_t *fhdr_v2 = &hdr_v2->fhdr; 3048a1edd7dSLiu Hui-R64343 dcd_v2_t *dcd_v2 = &hdr_v2->dcd_table; 3058a1edd7dSLiu Hui-R64343 uint32_t size, version; 3068a1edd7dSLiu Hui-R64343 3078a1edd7dSLiu Hui-R64343 size = be16_to_cpu(dcd_v2->header.length) - 8; 3088a1edd7dSLiu Hui-R64343 if (size > (MAX_HW_CFG_SIZE_V2 * sizeof(dcd_addr_data_t))) { 3098a1edd7dSLiu Hui-R64343 fprintf(stderr, 3108a1edd7dSLiu Hui-R64343 "Error: Image corrupt DCD size %d exceed maximum %d\n", 3118a1edd7dSLiu Hui-R64343 (uint32_t)(size / sizeof(dcd_addr_data_t)), 3128a1edd7dSLiu Hui-R64343 MAX_HW_CFG_SIZE_V2); 3138a1edd7dSLiu Hui-R64343 exit(EXIT_FAILURE); 3148a1edd7dSLiu Hui-R64343 } 3158a1edd7dSLiu Hui-R64343 3168a1edd7dSLiu Hui-R64343 version = detect_imximage_version(imx_hdr); 3178a1edd7dSLiu Hui-R64343 3188a1edd7dSLiu Hui-R64343 printf("Image Type: Freescale IMX Boot Image\n"); 3198a1edd7dSLiu Hui-R64343 printf("Image Ver: %x", version); 3208a1edd7dSLiu Hui-R64343 printf("%s\n", get_table_entry_name(imximage_versions, NULL, version)); 3218a1edd7dSLiu Hui-R64343 printf("Data Size: "); 3228a1edd7dSLiu Hui-R64343 genimg_print_size(hdr_v2->boot_data.size); 3238a1edd7dSLiu Hui-R64343 printf("Load Address: %08x\n", (uint32_t)fhdr_v2->boot_data_ptr); 3248a1edd7dSLiu Hui-R64343 printf("Entry Point: %08x\n", (uint32_t)fhdr_v2->entry); 3258a1edd7dSLiu Hui-R64343 } 3268a1edd7dSLiu Hui-R64343 3278a1edd7dSLiu Hui-R64343 static void parse_cfg_cmd(struct imx_header *imxhdr, int32_t cmd, char *token, 3288a1edd7dSLiu Hui-R64343 char *name, int lineno, int fld, int dcd_len) 3298a1edd7dSLiu Hui-R64343 { 3308a1edd7dSLiu Hui-R64343 int value; 3318a1edd7dSLiu Hui-R64343 static int cmd_ver_first = ~0; 3328a1edd7dSLiu Hui-R64343 3338a1edd7dSLiu Hui-R64343 switch (cmd) { 3348a1edd7dSLiu Hui-R64343 case CMD_IMAGE_VERSION: 3358a1edd7dSLiu Hui-R64343 imximage_version = get_cfg_value(token, name, lineno); 3368a1edd7dSLiu Hui-R64343 if (cmd_ver_first == 0) { 3378a1edd7dSLiu Hui-R64343 fprintf(stderr, "Error: %s[%d] - IMAGE_VERSION " 3388a1edd7dSLiu Hui-R64343 "command need be the first before other " 3398a1edd7dSLiu Hui-R64343 "valid command in the file\n", name, lineno); 3408a1edd7dSLiu Hui-R64343 exit(EXIT_FAILURE); 3418a1edd7dSLiu Hui-R64343 } 3428a1edd7dSLiu Hui-R64343 cmd_ver_first = 1; 3438a1edd7dSLiu Hui-R64343 set_hdr_func(imxhdr); 3448a1edd7dSLiu Hui-R64343 break; 3458a1edd7dSLiu Hui-R64343 case CMD_BOOT_FROM: 3468a1edd7dSLiu Hui-R64343 imxhdr->flash_offset = get_table_entry_id(imximage_bootops, 3478a1edd7dSLiu Hui-R64343 "imximage boot option", token); 3488a1edd7dSLiu Hui-R64343 if (imxhdr->flash_offset == -1) { 3498a1edd7dSLiu Hui-R64343 fprintf(stderr, "Error: %s[%d] -Invalid boot device" 3508a1edd7dSLiu Hui-R64343 "(%s)\n", name, lineno, token); 3518a1edd7dSLiu Hui-R64343 exit(EXIT_FAILURE); 3528a1edd7dSLiu Hui-R64343 } 3538a1edd7dSLiu Hui-R64343 if (unlikely(cmd_ver_first != 1)) 3548a1edd7dSLiu Hui-R64343 cmd_ver_first = 0; 3558a1edd7dSLiu Hui-R64343 break; 3566cb83829SMarek Vasut case CMD_BOOT_OFFSET: 3576cb83829SMarek Vasut imxhdr->flash_offset = get_cfg_value(token, name, lineno); 3586cb83829SMarek Vasut if (unlikely(cmd_ver_first != 1)) 3596cb83829SMarek Vasut cmd_ver_first = 0; 3606cb83829SMarek Vasut break; 3618a1edd7dSLiu Hui-R64343 case CMD_DATA: 3628a1edd7dSLiu Hui-R64343 value = get_cfg_value(token, name, lineno); 3638a1edd7dSLiu Hui-R64343 (*set_dcd_val)(imxhdr, name, lineno, fld, value, dcd_len); 3648a1edd7dSLiu Hui-R64343 if (unlikely(cmd_ver_first != 1)) 3658a1edd7dSLiu Hui-R64343 cmd_ver_first = 0; 3668a1edd7dSLiu Hui-R64343 break; 3678a1edd7dSLiu Hui-R64343 } 3688a1edd7dSLiu Hui-R64343 } 3698a1edd7dSLiu Hui-R64343 3708a1edd7dSLiu Hui-R64343 static void parse_cfg_fld(struct imx_header *imxhdr, int32_t *cmd, 3718a1edd7dSLiu Hui-R64343 char *token, char *name, int lineno, int fld, int *dcd_len) 3728a1edd7dSLiu Hui-R64343 { 3738a1edd7dSLiu Hui-R64343 int value; 3748a1edd7dSLiu Hui-R64343 3758a1edd7dSLiu Hui-R64343 switch (fld) { 3768a1edd7dSLiu Hui-R64343 case CFG_COMMAND: 3778a1edd7dSLiu Hui-R64343 *cmd = get_table_entry_id(imximage_cmds, 3788a1edd7dSLiu Hui-R64343 "imximage commands", token); 3798a1edd7dSLiu Hui-R64343 if (*cmd < 0) { 3808a1edd7dSLiu Hui-R64343 fprintf(stderr, "Error: %s[%d] - Invalid command" 3818a1edd7dSLiu Hui-R64343 "(%s)\n", name, lineno, token); 3828a1edd7dSLiu Hui-R64343 exit(EXIT_FAILURE); 3838a1edd7dSLiu Hui-R64343 } 3848a1edd7dSLiu Hui-R64343 break; 3858a1edd7dSLiu Hui-R64343 case CFG_REG_SIZE: 3868a1edd7dSLiu Hui-R64343 parse_cfg_cmd(imxhdr, *cmd, token, name, lineno, fld, *dcd_len); 3878a1edd7dSLiu Hui-R64343 break; 3888a1edd7dSLiu Hui-R64343 case CFG_REG_ADDRESS: 3898a1edd7dSLiu Hui-R64343 case CFG_REG_VALUE: 3908a1edd7dSLiu Hui-R64343 if (*cmd != CMD_DATA) 3918a1edd7dSLiu Hui-R64343 return; 3928a1edd7dSLiu Hui-R64343 3938a1edd7dSLiu Hui-R64343 value = get_cfg_value(token, name, lineno); 3948a1edd7dSLiu Hui-R64343 (*set_dcd_val)(imxhdr, name, lineno, fld, value, *dcd_len); 3958a1edd7dSLiu Hui-R64343 3964d5fa985STroy Kisky if (fld == CFG_REG_VALUE) { 3978a1edd7dSLiu Hui-R64343 (*dcd_len)++; 3984d5fa985STroy Kisky if (*dcd_len > max_dcd_entries) { 3994d5fa985STroy Kisky fprintf(stderr, "Error: %s[%d] -" 4004d5fa985STroy Kisky "DCD table exceeds maximum size(%d)\n", 4014d5fa985STroy Kisky name, lineno, max_dcd_entries); 4024d5fa985STroy Kisky exit(EXIT_FAILURE); 4034d5fa985STroy Kisky } 4044d5fa985STroy Kisky } 4058a1edd7dSLiu Hui-R64343 break; 4068a1edd7dSLiu Hui-R64343 default: 4078a1edd7dSLiu Hui-R64343 break; 4088a1edd7dSLiu Hui-R64343 } 4098a1edd7dSLiu Hui-R64343 } 4108a1edd7dSLiu Hui-R64343 static uint32_t parse_cfg_file(struct imx_header *imxhdr, char *name) 4118edcde5eSStefano Babic { 4128edcde5eSStefano Babic FILE *fd = NULL; 4138edcde5eSStefano Babic char *line = NULL; 4148edcde5eSStefano Babic char *token, *saveptr1, *saveptr2; 4158edcde5eSStefano Babic int lineno = 0; 4168a1edd7dSLiu Hui-R64343 int fld; 4170ad22703SKim Phillips size_t len; 4188edcde5eSStefano Babic int dcd_len = 0; 4198edcde5eSStefano Babic int32_t cmd; 4208edcde5eSStefano Babic 4218edcde5eSStefano Babic fd = fopen(name, "r"); 4228edcde5eSStefano Babic if (fd == 0) { 4238edcde5eSStefano Babic fprintf(stderr, "Error: %s - Can't open DCD file\n", name); 4248edcde5eSStefano Babic exit(EXIT_FAILURE); 4258edcde5eSStefano Babic } 4268edcde5eSStefano Babic 4278edcde5eSStefano Babic /* Very simple parsing, line starting with # are comments 4288edcde5eSStefano Babic * and are dropped 4298edcde5eSStefano Babic */ 4308edcde5eSStefano Babic while ((getline(&line, &len, fd)) > 0) { 4318edcde5eSStefano Babic lineno++; 4328edcde5eSStefano Babic 4338edcde5eSStefano Babic token = strtok_r(line, "\r\n", &saveptr1); 4348edcde5eSStefano Babic if (token == NULL) 4358edcde5eSStefano Babic continue; 4368edcde5eSStefano Babic 4378edcde5eSStefano Babic /* Check inside the single line */ 4388edcde5eSStefano Babic for (fld = CFG_COMMAND, cmd = CMD_INVALID, 4398edcde5eSStefano Babic line = token; ; line = NULL, fld++) { 4408edcde5eSStefano Babic token = strtok_r(line, " \t", &saveptr2); 4418edcde5eSStefano Babic if (token == NULL) 4428edcde5eSStefano Babic break; 4438edcde5eSStefano Babic 4448edcde5eSStefano Babic /* Drop all text starting with '#' as comments */ 4458edcde5eSStefano Babic if (token[0] == '#') 4468edcde5eSStefano Babic break; 4478edcde5eSStefano Babic 4488a1edd7dSLiu Hui-R64343 parse_cfg_fld(imxhdr, &cmd, token, name, 4498a1edd7dSLiu Hui-R64343 lineno, fld, &dcd_len); 4508edcde5eSStefano Babic } 4518edcde5eSStefano Babic 4528edcde5eSStefano Babic } 4538edcde5eSStefano Babic 4548a1edd7dSLiu Hui-R64343 (*set_dcd_rst)(imxhdr, dcd_len, name, lineno); 4558edcde5eSStefano Babic fclose(fd); 4568edcde5eSStefano Babic 4578d8cc828STroy Kisky /* Exit if there is no BOOT_FROM field specifying the flash_offset */ 4588d8cc828STroy Kisky if (imxhdr->flash_offset == FLASH_OFFSET_UNDEFINED) { 4598d8cc828STroy Kisky fprintf(stderr, "Error: No BOOT_FROM tag in %s\n", name); 4608d8cc828STroy Kisky exit(EXIT_FAILURE); 4618d8cc828STroy Kisky } 4625b28e913SStefano Babic return dcd_len; 4638edcde5eSStefano Babic } 4648edcde5eSStefano Babic 4658a1edd7dSLiu Hui-R64343 4668a1edd7dSLiu Hui-R64343 static int imximage_check_image_types(uint8_t type) 4678a1edd7dSLiu Hui-R64343 { 4688a1edd7dSLiu Hui-R64343 if (type == IH_TYPE_IMXIMAGE) 4698a1edd7dSLiu Hui-R64343 return EXIT_SUCCESS; 4708a1edd7dSLiu Hui-R64343 else 4718a1edd7dSLiu Hui-R64343 return EXIT_FAILURE; 4728a1edd7dSLiu Hui-R64343 } 4738a1edd7dSLiu Hui-R64343 4748a1edd7dSLiu Hui-R64343 static int imximage_verify_header(unsigned char *ptr, int image_size, 4758a1edd7dSLiu Hui-R64343 struct mkimage_params *params) 4768a1edd7dSLiu Hui-R64343 { 4778a1edd7dSLiu Hui-R64343 struct imx_header *imx_hdr = (struct imx_header *) ptr; 4788a1edd7dSLiu Hui-R64343 4798a1edd7dSLiu Hui-R64343 if (detect_imximage_version(imx_hdr) == IMXIMAGE_VER_INVALID) 4808a1edd7dSLiu Hui-R64343 return -FDT_ERR_BADSTRUCTURE; 4818a1edd7dSLiu Hui-R64343 4828a1edd7dSLiu Hui-R64343 return 0; 4838a1edd7dSLiu Hui-R64343 } 4848a1edd7dSLiu Hui-R64343 4858a1edd7dSLiu Hui-R64343 static void imximage_print_header(const void *ptr) 4868a1edd7dSLiu Hui-R64343 { 4878a1edd7dSLiu Hui-R64343 struct imx_header *imx_hdr = (struct imx_header *) ptr; 4888a1edd7dSLiu Hui-R64343 uint32_t version = detect_imximage_version(imx_hdr); 4898a1edd7dSLiu Hui-R64343 4908a1edd7dSLiu Hui-R64343 switch (version) { 4918a1edd7dSLiu Hui-R64343 case IMXIMAGE_V1: 4928a1edd7dSLiu Hui-R64343 print_hdr_v1(imx_hdr); 4938a1edd7dSLiu Hui-R64343 break; 4948a1edd7dSLiu Hui-R64343 case IMXIMAGE_V2: 4958a1edd7dSLiu Hui-R64343 print_hdr_v2(imx_hdr); 4968a1edd7dSLiu Hui-R64343 break; 4978a1edd7dSLiu Hui-R64343 default: 4988a1edd7dSLiu Hui-R64343 err_imximage_version(version); 4998a1edd7dSLiu Hui-R64343 break; 5008a1edd7dSLiu Hui-R64343 } 5018a1edd7dSLiu Hui-R64343 } 5028a1edd7dSLiu Hui-R64343 5038edcde5eSStefano Babic static void imximage_set_header(void *ptr, struct stat *sbuf, int ifd, 5048edcde5eSStefano Babic struct mkimage_params *params) 5058edcde5eSStefano Babic { 5068a1edd7dSLiu Hui-R64343 struct imx_header *imxhdr = (struct imx_header *)ptr; 5078a1edd7dSLiu Hui-R64343 uint32_t dcd_len; 5088edcde5eSStefano Babic 5098a1edd7dSLiu Hui-R64343 /* 5108a1edd7dSLiu Hui-R64343 * In order to not change the old imx cfg file 5118a1edd7dSLiu Hui-R64343 * by adding VERSION command into it, here need 5128a1edd7dSLiu Hui-R64343 * set up function ptr group to V1 by default. 5138a1edd7dSLiu Hui-R64343 */ 5148a1edd7dSLiu Hui-R64343 imximage_version = IMXIMAGE_V1; 51549d3e272SDirk Behme /* Be able to detect if the cfg file has no BOOT_FROM tag */ 51649d3e272SDirk Behme imxhdr->flash_offset = FLASH_OFFSET_UNDEFINED; 5178a1edd7dSLiu Hui-R64343 set_hdr_func(imxhdr); 5188edcde5eSStefano Babic 5198edcde5eSStefano Babic /* Parse dcd configuration file */ 5208a1edd7dSLiu Hui-R64343 dcd_len = parse_cfg_file(imxhdr, params->imagename); 5218edcde5eSStefano Babic 5228a1edd7dSLiu Hui-R64343 /* Set the imx header */ 523ad0826dcSTroy Kisky (*set_imx_hdr)(imxhdr, dcd_len, params->ep, imxhdr->flash_offset); 5241411fb37SFabio Estevam 5251411fb37SFabio Estevam /* 5261411fb37SFabio Estevam * ROM bug alert 527*895d9966SMarek Vasut * 528*895d9966SMarek Vasut * MX53 only loads 512 byte multiples in case of SD boot. 529*895d9966SMarek Vasut * MX53 only loads NAND page multiples in case of NAND boot and 530*895d9966SMarek Vasut * supports up to 4096 byte large pages, thus align to 4096. 531*895d9966SMarek Vasut * 532*895d9966SMarek Vasut * The remaining fraction of a block bytes would not be loaded! 5331411fb37SFabio Estevam */ 534*895d9966SMarek Vasut *header_size_ptr = ROUND(sbuf->st_size + imxhdr->flash_offset, 4096); 5358edcde5eSStefano Babic } 5368edcde5eSStefano Babic 5378edcde5eSStefano Babic int imximage_check_params(struct mkimage_params *params) 5388edcde5eSStefano Babic { 5398edcde5eSStefano Babic if (!params) 5408edcde5eSStefano Babic return CFG_INVALID; 5418edcde5eSStefano Babic if (!strlen(params->imagename)) { 5428edcde5eSStefano Babic fprintf(stderr, "Error: %s - Configuration file not specified, " 5438edcde5eSStefano Babic "it is needed for imximage generation\n", 5448edcde5eSStefano Babic params->cmdname); 5458edcde5eSStefano Babic return CFG_INVALID; 5468edcde5eSStefano Babic } 5478edcde5eSStefano Babic /* 5488edcde5eSStefano Babic * Check parameters: 5498edcde5eSStefano Babic * XIP is not allowed and verify that incompatible 5508edcde5eSStefano Babic * parameters are not sent at the same time 5518edcde5eSStefano Babic * For example, if list is required a data image must not be provided 5528edcde5eSStefano Babic */ 5538edcde5eSStefano Babic return (params->dflag && (params->fflag || params->lflag)) || 5548edcde5eSStefano Babic (params->fflag && (params->dflag || params->lflag)) || 5558edcde5eSStefano Babic (params->lflag && (params->dflag || params->fflag)) || 5568edcde5eSStefano Babic (params->xflag) || !(strlen(params->imagename)); 5578edcde5eSStefano Babic } 5588edcde5eSStefano Babic 5598edcde5eSStefano Babic /* 5608edcde5eSStefano Babic * imximage parameters 5618edcde5eSStefano Babic */ 5628edcde5eSStefano Babic static struct image_type_params imximage_params = { 5636e083857SFabio Estevam .name = "Freescale i.MX Boot Image support", 5648edcde5eSStefano Babic .header_size = sizeof(struct imx_header), 5658edcde5eSStefano Babic .hdr = (void *)&imximage_header, 5668edcde5eSStefano Babic .check_image_type = imximage_check_image_types, 5678edcde5eSStefano Babic .verify_header = imximage_verify_header, 5688edcde5eSStefano Babic .print_header = imximage_print_header, 5698edcde5eSStefano Babic .set_header = imximage_set_header, 5708edcde5eSStefano Babic .check_params = imximage_check_params, 5718edcde5eSStefano Babic }; 5728edcde5eSStefano Babic 5738edcde5eSStefano Babic void init_imx_image_type(void) 5748edcde5eSStefano Babic { 5758edcde5eSStefano Babic mkimage_register(&imximage_params); 5768edcde5eSStefano Babic } 577