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", }, 408edcde5eSStefano Babic {CMD_DATA, "DATA", "Reg Write Data", }, 418a1edd7dSLiu Hui-R64343 {CMD_IMAGE_VERSION, "IMAGE_VERSION", "image version", }, 428edcde5eSStefano Babic {-1, "", "", }, 438edcde5eSStefano Babic }; 448edcde5eSStefano Babic 458edcde5eSStefano Babic /* 468edcde5eSStefano Babic * Supported Boot options for configuration file 478edcde5eSStefano Babic * this is needed to set the correct flash offset 488edcde5eSStefano Babic */ 498edcde5eSStefano Babic static table_entry_t imximage_bootops[] = { 508edcde5eSStefano Babic {FLASH_OFFSET_SPI, "spi", "SPI Flash", }, 518edcde5eSStefano Babic {FLASH_OFFSET_NAND, "nand", "NAND Flash", }, 528edcde5eSStefano Babic {FLASH_OFFSET_SD, "sd", "SD Card", }, 538edcde5eSStefano Babic {FLASH_OFFSET_ONENAND, "onenand", "OneNAND Flash",}, 54*19b409c0SDirk Behme {FLASH_OFFSET_NOR, "nor", "NOR Flash", }, 55*19b409c0SDirk Behme {FLASH_OFFSET_SATA, "sata", "SATA Disk", }, 568edcde5eSStefano Babic {-1, "", "Invalid", }, 578edcde5eSStefano Babic }; 588edcde5eSStefano Babic 598a1edd7dSLiu Hui-R64343 /* 608a1edd7dSLiu Hui-R64343 * IMXIMAGE version definition for i.MX chips 618a1edd7dSLiu Hui-R64343 */ 628a1edd7dSLiu Hui-R64343 static table_entry_t imximage_versions[] = { 638a1edd7dSLiu Hui-R64343 {IMXIMAGE_V1, "", " (i.MX25/35/51 compatible)", }, 64*19b409c0SDirk Behme {IMXIMAGE_V2, "", " (i.MX53/6 compatible)", }, 658a1edd7dSLiu Hui-R64343 {-1, "", " (Invalid)", }, 668a1edd7dSLiu Hui-R64343 }; 678edcde5eSStefano Babic 688edcde5eSStefano Babic static struct imx_header imximage_header; 698a1edd7dSLiu Hui-R64343 static uint32_t imximage_version; 708a1edd7dSLiu Hui-R64343 718a1edd7dSLiu Hui-R64343 static set_dcd_val_t set_dcd_val; 728a1edd7dSLiu Hui-R64343 static set_dcd_rst_t set_dcd_rst; 738a1edd7dSLiu Hui-R64343 static set_imx_hdr_t set_imx_hdr; 748edcde5eSStefano Babic 758edcde5eSStefano Babic static uint32_t get_cfg_value(char *token, char *name, int linenr) 768edcde5eSStefano Babic { 778edcde5eSStefano Babic char *endptr; 788edcde5eSStefano Babic uint32_t value; 798edcde5eSStefano Babic 808edcde5eSStefano Babic errno = 0; 818edcde5eSStefano Babic value = strtoul(token, &endptr, 16); 828edcde5eSStefano Babic if (errno || (token == endptr)) { 838edcde5eSStefano Babic fprintf(stderr, "Error: %s[%d] - Invalid hex data(%s)\n", 848edcde5eSStefano Babic name, linenr, token); 858edcde5eSStefano Babic exit(EXIT_FAILURE); 868edcde5eSStefano Babic } 878edcde5eSStefano Babic return value; 888edcde5eSStefano Babic } 898edcde5eSStefano Babic 908a1edd7dSLiu Hui-R64343 static uint32_t detect_imximage_version(struct imx_header *imx_hdr) 918edcde5eSStefano Babic { 928a1edd7dSLiu Hui-R64343 imx_header_v1_t *hdr_v1 = &imx_hdr->header.hdr_v1; 938a1edd7dSLiu Hui-R64343 imx_header_v2_t *hdr_v2 = &imx_hdr->header.hdr_v2; 948a1edd7dSLiu Hui-R64343 flash_header_v1_t *fhdr_v1 = &hdr_v1->fhdr; 958a1edd7dSLiu Hui-R64343 flash_header_v2_t *fhdr_v2 = &hdr_v2->fhdr; 968a1edd7dSLiu Hui-R64343 978a1edd7dSLiu Hui-R64343 /* Try to detect V1 */ 988a1edd7dSLiu Hui-R64343 if ((fhdr_v1->app_code_barker == APP_CODE_BARKER) && 998a1edd7dSLiu Hui-R64343 (hdr_v1->dcd_table.preamble.barker == DCD_BARKER)) 1008a1edd7dSLiu Hui-R64343 return IMXIMAGE_V1; 1018a1edd7dSLiu Hui-R64343 1028a1edd7dSLiu Hui-R64343 /* Try to detect V2 */ 1038a1edd7dSLiu Hui-R64343 if ((fhdr_v2->header.tag == IVT_HEADER_TAG) && 1048a1edd7dSLiu Hui-R64343 (hdr_v2->dcd_table.header.tag == DCD_HEADER_TAG)) 1058a1edd7dSLiu Hui-R64343 return IMXIMAGE_V2; 1068a1edd7dSLiu Hui-R64343 1078a1edd7dSLiu Hui-R64343 return IMXIMAGE_VER_INVALID; 1088edcde5eSStefano Babic } 1098edcde5eSStefano Babic 1108a1edd7dSLiu Hui-R64343 static void err_imximage_version(int version) 1118edcde5eSStefano Babic { 1128edcde5eSStefano Babic fprintf(stderr, 1138a1edd7dSLiu Hui-R64343 "Error: Unsupported imximage version:%d\n", version); 1148a1edd7dSLiu Hui-R64343 1158edcde5eSStefano Babic exit(EXIT_FAILURE); 1168edcde5eSStefano Babic } 1178edcde5eSStefano Babic 1188a1edd7dSLiu Hui-R64343 static void set_dcd_val_v1(struct imx_header *imxhdr, char *name, int lineno, 1198a1edd7dSLiu Hui-R64343 int fld, uint32_t value, uint32_t off) 1208a1edd7dSLiu Hui-R64343 { 1218a1edd7dSLiu Hui-R64343 dcd_v1_t *dcd_v1 = &imxhdr->header.hdr_v1.dcd_table; 1228edcde5eSStefano Babic 1238a1edd7dSLiu Hui-R64343 switch (fld) { 1248a1edd7dSLiu Hui-R64343 case CFG_REG_SIZE: 1258a1edd7dSLiu Hui-R64343 /* Byte, halfword, word */ 1268a1edd7dSLiu Hui-R64343 if ((value != 1) && (value != 2) && (value != 4)) { 1278a1edd7dSLiu Hui-R64343 fprintf(stderr, "Error: %s[%d] - " 1288a1edd7dSLiu Hui-R64343 "Invalid register size " "(%d)\n", 1298a1edd7dSLiu Hui-R64343 name, lineno, value); 1308a1edd7dSLiu Hui-R64343 exit(EXIT_FAILURE); 1318a1edd7dSLiu Hui-R64343 } 1328a1edd7dSLiu Hui-R64343 dcd_v1->addr_data[off].type = value; 1338a1edd7dSLiu Hui-R64343 break; 1348a1edd7dSLiu Hui-R64343 case CFG_REG_ADDRESS: 1358a1edd7dSLiu Hui-R64343 dcd_v1->addr_data[off].addr = value; 1368a1edd7dSLiu Hui-R64343 break; 1378a1edd7dSLiu Hui-R64343 case CFG_REG_VALUE: 1388a1edd7dSLiu Hui-R64343 dcd_v1->addr_data[off].value = value; 1398a1edd7dSLiu Hui-R64343 break; 1408a1edd7dSLiu Hui-R64343 default: 1418a1edd7dSLiu Hui-R64343 break; 1428a1edd7dSLiu Hui-R64343 1438a1edd7dSLiu Hui-R64343 } 1448edcde5eSStefano Babic } 1458edcde5eSStefano Babic 1468a1edd7dSLiu Hui-R64343 static void set_dcd_val_v2(struct imx_header *imxhdr, char *name, int lineno, 1478a1edd7dSLiu Hui-R64343 int fld, uint32_t value, uint32_t off) 1488a1edd7dSLiu Hui-R64343 { 1498a1edd7dSLiu Hui-R64343 dcd_v2_t *dcd_v2 = &imxhdr->header.hdr_v2.dcd_table; 1508a1edd7dSLiu Hui-R64343 1518a1edd7dSLiu Hui-R64343 switch (fld) { 1528a1edd7dSLiu Hui-R64343 case CFG_REG_ADDRESS: 1538a1edd7dSLiu Hui-R64343 dcd_v2->addr_data[off].addr = cpu_to_be32(value); 1548a1edd7dSLiu Hui-R64343 break; 1558a1edd7dSLiu Hui-R64343 case CFG_REG_VALUE: 1568a1edd7dSLiu Hui-R64343 dcd_v2->addr_data[off].value = cpu_to_be32(value); 1578a1edd7dSLiu Hui-R64343 break; 1588a1edd7dSLiu Hui-R64343 default: 1598a1edd7dSLiu Hui-R64343 break; 1608a1edd7dSLiu Hui-R64343 1618a1edd7dSLiu Hui-R64343 } 1628a1edd7dSLiu Hui-R64343 } 1638a1edd7dSLiu Hui-R64343 1648a1edd7dSLiu Hui-R64343 /* 1658a1edd7dSLiu Hui-R64343 * Complete setting up the rest field of DCD of V1 1668a1edd7dSLiu Hui-R64343 * such as barker code and DCD data length. 1678a1edd7dSLiu Hui-R64343 */ 1688a1edd7dSLiu Hui-R64343 static void set_dcd_rst_v1(struct imx_header *imxhdr, uint32_t dcd_len, 1698a1edd7dSLiu Hui-R64343 char *name, int lineno) 1708a1edd7dSLiu Hui-R64343 { 1718a1edd7dSLiu Hui-R64343 dcd_v1_t *dcd_v1 = &imxhdr->header.hdr_v1.dcd_table; 1728a1edd7dSLiu Hui-R64343 1738a1edd7dSLiu Hui-R64343 if (dcd_len > MAX_HW_CFG_SIZE_V1) { 1748a1edd7dSLiu Hui-R64343 fprintf(stderr, "Error: %s[%d] -" 1758a1edd7dSLiu Hui-R64343 "DCD table exceeds maximum size(%d)\n", 1768a1edd7dSLiu Hui-R64343 name, lineno, MAX_HW_CFG_SIZE_V1); 1778a1edd7dSLiu Hui-R64343 exit(EXIT_FAILURE); 1788a1edd7dSLiu Hui-R64343 } 1798a1edd7dSLiu Hui-R64343 1808a1edd7dSLiu Hui-R64343 dcd_v1->preamble.barker = DCD_BARKER; 1818a1edd7dSLiu Hui-R64343 dcd_v1->preamble.length = dcd_len * sizeof(dcd_type_addr_data_t); 1828a1edd7dSLiu Hui-R64343 } 1838a1edd7dSLiu Hui-R64343 1848a1edd7dSLiu Hui-R64343 /* 1858a1edd7dSLiu Hui-R64343 * Complete setting up the reset field of DCD of V2 1868a1edd7dSLiu Hui-R64343 * such as DCD tag, version, length, etc. 1878a1edd7dSLiu Hui-R64343 */ 1888a1edd7dSLiu Hui-R64343 static void set_dcd_rst_v2(struct imx_header *imxhdr, uint32_t dcd_len, 1898a1edd7dSLiu Hui-R64343 char *name, int lineno) 1908a1edd7dSLiu Hui-R64343 { 1918a1edd7dSLiu Hui-R64343 dcd_v2_t *dcd_v2 = &imxhdr->header.hdr_v2.dcd_table; 1928a1edd7dSLiu Hui-R64343 1938a1edd7dSLiu Hui-R64343 if (dcd_len > MAX_HW_CFG_SIZE_V2) { 1948a1edd7dSLiu Hui-R64343 fprintf(stderr, "Error: %s[%d] -" 1958a1edd7dSLiu Hui-R64343 "DCD table exceeds maximum size(%d)\n", 1968a1edd7dSLiu Hui-R64343 name, lineno, MAX_HW_CFG_SIZE_V2); 1978a1edd7dSLiu Hui-R64343 exit(EXIT_FAILURE); 1988a1edd7dSLiu Hui-R64343 } 1998a1edd7dSLiu Hui-R64343 2008a1edd7dSLiu Hui-R64343 dcd_v2->header.tag = DCD_HEADER_TAG; 2018a1edd7dSLiu Hui-R64343 dcd_v2->header.length = cpu_to_be16( 2028a1edd7dSLiu Hui-R64343 dcd_len * sizeof(dcd_addr_data_t) + 8); 2038a1edd7dSLiu Hui-R64343 dcd_v2->header.version = DCD_VERSION; 2048a1edd7dSLiu Hui-R64343 dcd_v2->write_dcd_command.tag = DCD_COMMAND_TAG; 2058a1edd7dSLiu Hui-R64343 dcd_v2->write_dcd_command.length = cpu_to_be16( 2068a1edd7dSLiu Hui-R64343 dcd_len * sizeof(dcd_addr_data_t) + 4); 2078a1edd7dSLiu Hui-R64343 dcd_v2->write_dcd_command.param = DCD_COMMAND_PARAM; 2088a1edd7dSLiu Hui-R64343 } 2098a1edd7dSLiu Hui-R64343 2108a1edd7dSLiu Hui-R64343 static void set_imx_hdr_v1(struct imx_header *imxhdr, uint32_t dcd_len, 2118a1edd7dSLiu Hui-R64343 struct stat *sbuf, 2128a1edd7dSLiu Hui-R64343 struct mkimage_params *params) 2138a1edd7dSLiu Hui-R64343 { 2148a1edd7dSLiu Hui-R64343 imx_header_v1_t *hdr_v1 = &imxhdr->header.hdr_v1; 2158a1edd7dSLiu Hui-R64343 flash_header_v1_t *fhdr_v1 = &hdr_v1->fhdr; 2168a1edd7dSLiu Hui-R64343 dcd_v1_t *dcd_v1 = &hdr_v1->dcd_table; 2178a1edd7dSLiu Hui-R64343 uint32_t base_offset; 2188a1edd7dSLiu Hui-R64343 2198a1edd7dSLiu Hui-R64343 /* Set default offset */ 2208a1edd7dSLiu Hui-R64343 imxhdr->flash_offset = FLASH_OFFSET_STANDARD; 2218a1edd7dSLiu Hui-R64343 2228a1edd7dSLiu Hui-R64343 /* Set magic number */ 2238a1edd7dSLiu Hui-R64343 fhdr_v1->app_code_barker = APP_CODE_BARKER; 2248a1edd7dSLiu Hui-R64343 2258a1edd7dSLiu Hui-R64343 fhdr_v1->app_dest_ptr = params->addr; 2268a1edd7dSLiu Hui-R64343 fhdr_v1->app_dest_ptr = params->ep - imxhdr->flash_offset - 2278a1edd7dSLiu Hui-R64343 sizeof(struct imx_header); 2288a1edd7dSLiu Hui-R64343 fhdr_v1->app_code_jump_vector = params->ep; 2298a1edd7dSLiu Hui-R64343 2308a1edd7dSLiu Hui-R64343 base_offset = fhdr_v1->app_dest_ptr + imxhdr->flash_offset ; 2318a1edd7dSLiu Hui-R64343 fhdr_v1->dcd_ptr_ptr = 2328a1edd7dSLiu Hui-R64343 (uint32_t) (offsetof(flash_header_v1_t, dcd_ptr) - 2338a1edd7dSLiu Hui-R64343 offsetof(flash_header_v1_t, app_code_jump_vector) + 2348a1edd7dSLiu Hui-R64343 base_offset); 2358a1edd7dSLiu Hui-R64343 2368a1edd7dSLiu Hui-R64343 fhdr_v1->dcd_ptr = base_offset + 2378a1edd7dSLiu Hui-R64343 offsetof(imx_header_v1_t, dcd_table); 2388a1edd7dSLiu Hui-R64343 2398a1edd7dSLiu Hui-R64343 /* The external flash header must be at the end of the DCD table */ 2408a1edd7dSLiu Hui-R64343 dcd_v1->addr_data[dcd_len].type = sbuf->st_size + 2418a1edd7dSLiu Hui-R64343 imxhdr->flash_offset + 2428a1edd7dSLiu Hui-R64343 sizeof(struct imx_header); 2438a1edd7dSLiu Hui-R64343 2448a1edd7dSLiu Hui-R64343 /* Security feature are not supported */ 2458a1edd7dSLiu Hui-R64343 fhdr_v1->app_code_csf = 0; 2468a1edd7dSLiu Hui-R64343 fhdr_v1->super_root_key = 0; 2478a1edd7dSLiu Hui-R64343 } 2488a1edd7dSLiu Hui-R64343 2498a1edd7dSLiu Hui-R64343 static void set_imx_hdr_v2(struct imx_header *imxhdr, uint32_t dcd_len, 2508a1edd7dSLiu Hui-R64343 struct stat *sbuf, 2518a1edd7dSLiu Hui-R64343 struct mkimage_params *params) 2528a1edd7dSLiu Hui-R64343 { 2538a1edd7dSLiu Hui-R64343 imx_header_v2_t *hdr_v2 = &imxhdr->header.hdr_v2; 2548a1edd7dSLiu Hui-R64343 flash_header_v2_t *fhdr_v2 = &hdr_v2->fhdr; 2558a1edd7dSLiu Hui-R64343 2568a1edd7dSLiu Hui-R64343 /* Set default offset */ 2578a1edd7dSLiu Hui-R64343 imxhdr->flash_offset = FLASH_OFFSET_STANDARD; 2588a1edd7dSLiu Hui-R64343 2598a1edd7dSLiu Hui-R64343 /* Set magic number */ 2608a1edd7dSLiu Hui-R64343 fhdr_v2->header.tag = IVT_HEADER_TAG; /* 0xD1 */ 2618a1edd7dSLiu Hui-R64343 fhdr_v2->header.length = cpu_to_be16(sizeof(flash_header_v2_t)); 2628a1edd7dSLiu Hui-R64343 fhdr_v2->header.version = IVT_VERSION; /* 0x40 */ 2638a1edd7dSLiu Hui-R64343 2648a1edd7dSLiu Hui-R64343 fhdr_v2->entry = params->ep; 2658a1edd7dSLiu Hui-R64343 fhdr_v2->reserved1 = fhdr_v2->reserved2 = 0; 2668a1edd7dSLiu Hui-R64343 fhdr_v2->self = params->ep - sizeof(struct imx_header); 2678a1edd7dSLiu Hui-R64343 2688a1edd7dSLiu Hui-R64343 fhdr_v2->dcd_ptr = fhdr_v2->self + 2698a1edd7dSLiu Hui-R64343 offsetof(imx_header_v2_t, dcd_table); 2708a1edd7dSLiu Hui-R64343 2718a1edd7dSLiu Hui-R64343 fhdr_v2->boot_data_ptr = fhdr_v2->self + 2728a1edd7dSLiu Hui-R64343 offsetof(imx_header_v2_t, boot_data); 2738a1edd7dSLiu Hui-R64343 2748a1edd7dSLiu Hui-R64343 hdr_v2->boot_data.start = fhdr_v2->self - imxhdr->flash_offset; 2758a1edd7dSLiu Hui-R64343 hdr_v2->boot_data.size = sbuf->st_size + 2768a1edd7dSLiu Hui-R64343 imxhdr->flash_offset + 2778a1edd7dSLiu Hui-R64343 sizeof(struct imx_header); 2788a1edd7dSLiu Hui-R64343 2798a1edd7dSLiu Hui-R64343 /* Security feature are not supported */ 2808a1edd7dSLiu Hui-R64343 fhdr_v2->csf = 0; 2818a1edd7dSLiu Hui-R64343 } 2828a1edd7dSLiu Hui-R64343 2838a1edd7dSLiu Hui-R64343 static void set_hdr_func(struct imx_header *imxhdr) 2848a1edd7dSLiu Hui-R64343 { 2858a1edd7dSLiu Hui-R64343 switch (imximage_version) { 2868a1edd7dSLiu Hui-R64343 case IMXIMAGE_V1: 2878a1edd7dSLiu Hui-R64343 set_dcd_val = set_dcd_val_v1; 2888a1edd7dSLiu Hui-R64343 set_dcd_rst = set_dcd_rst_v1; 2898a1edd7dSLiu Hui-R64343 set_imx_hdr = set_imx_hdr_v1; 2908a1edd7dSLiu Hui-R64343 break; 2918a1edd7dSLiu Hui-R64343 case IMXIMAGE_V2: 2928a1edd7dSLiu Hui-R64343 set_dcd_val = set_dcd_val_v2; 2938a1edd7dSLiu Hui-R64343 set_dcd_rst = set_dcd_rst_v2; 2948a1edd7dSLiu Hui-R64343 set_imx_hdr = set_imx_hdr_v2; 2958a1edd7dSLiu Hui-R64343 break; 2968a1edd7dSLiu Hui-R64343 default: 2978a1edd7dSLiu Hui-R64343 err_imximage_version(imximage_version); 2988a1edd7dSLiu Hui-R64343 break; 2998a1edd7dSLiu Hui-R64343 } 3008a1edd7dSLiu Hui-R64343 } 3018a1edd7dSLiu Hui-R64343 3028a1edd7dSLiu Hui-R64343 static void print_hdr_v1(struct imx_header *imx_hdr) 3038a1edd7dSLiu Hui-R64343 { 3048a1edd7dSLiu Hui-R64343 imx_header_v1_t *hdr_v1 = &imx_hdr->header.hdr_v1; 3058a1edd7dSLiu Hui-R64343 flash_header_v1_t *fhdr_v1 = &hdr_v1->fhdr; 3068a1edd7dSLiu Hui-R64343 dcd_v1_t *dcd_v1 = &hdr_v1->dcd_table; 3078a1edd7dSLiu Hui-R64343 uint32_t size, length, ver; 3088a1edd7dSLiu Hui-R64343 3098a1edd7dSLiu Hui-R64343 size = dcd_v1->preamble.length; 3108a1edd7dSLiu Hui-R64343 if (size > (MAX_HW_CFG_SIZE_V1 * sizeof(dcd_type_addr_data_t))) { 3118a1edd7dSLiu Hui-R64343 fprintf(stderr, 3128a1edd7dSLiu Hui-R64343 "Error: Image corrupt DCD size %d exceed maximum %d\n", 3138a1edd7dSLiu Hui-R64343 (uint32_t)(size / sizeof(dcd_type_addr_data_t)), 3148a1edd7dSLiu Hui-R64343 MAX_HW_CFG_SIZE_V1); 3158a1edd7dSLiu Hui-R64343 exit(EXIT_FAILURE); 3168a1edd7dSLiu Hui-R64343 } 3178a1edd7dSLiu Hui-R64343 3188a1edd7dSLiu Hui-R64343 length = dcd_v1->preamble.length / sizeof(dcd_type_addr_data_t); 3198a1edd7dSLiu Hui-R64343 ver = detect_imximage_version(imx_hdr); 3208a1edd7dSLiu Hui-R64343 3218a1edd7dSLiu Hui-R64343 printf("Image Type: Freescale IMX Boot Image\n"); 3228a1edd7dSLiu Hui-R64343 printf("Image Ver: %x", ver); 3238a1edd7dSLiu Hui-R64343 printf("%s\n", get_table_entry_name(imximage_versions, NULL, ver)); 3248a1edd7dSLiu Hui-R64343 printf("Data Size: "); 3258a1edd7dSLiu Hui-R64343 genimg_print_size(dcd_v1->addr_data[length].type); 3268a1edd7dSLiu Hui-R64343 printf("Load Address: %08x\n", (uint32_t)fhdr_v1->app_dest_ptr); 3278a1edd7dSLiu Hui-R64343 printf("Entry Point: %08x\n", (uint32_t)fhdr_v1->app_code_jump_vector); 3288a1edd7dSLiu Hui-R64343 } 3298a1edd7dSLiu Hui-R64343 3308a1edd7dSLiu Hui-R64343 static void print_hdr_v2(struct imx_header *imx_hdr) 3318a1edd7dSLiu Hui-R64343 { 3328a1edd7dSLiu Hui-R64343 imx_header_v2_t *hdr_v2 = &imx_hdr->header.hdr_v2; 3338a1edd7dSLiu Hui-R64343 flash_header_v2_t *fhdr_v2 = &hdr_v2->fhdr; 3348a1edd7dSLiu Hui-R64343 dcd_v2_t *dcd_v2 = &hdr_v2->dcd_table; 3358a1edd7dSLiu Hui-R64343 uint32_t size, version; 3368a1edd7dSLiu Hui-R64343 3378a1edd7dSLiu Hui-R64343 size = be16_to_cpu(dcd_v2->header.length) - 8; 3388a1edd7dSLiu Hui-R64343 if (size > (MAX_HW_CFG_SIZE_V2 * sizeof(dcd_addr_data_t))) { 3398a1edd7dSLiu Hui-R64343 fprintf(stderr, 3408a1edd7dSLiu Hui-R64343 "Error: Image corrupt DCD size %d exceed maximum %d\n", 3418a1edd7dSLiu Hui-R64343 (uint32_t)(size / sizeof(dcd_addr_data_t)), 3428a1edd7dSLiu Hui-R64343 MAX_HW_CFG_SIZE_V2); 3438a1edd7dSLiu Hui-R64343 exit(EXIT_FAILURE); 3448a1edd7dSLiu Hui-R64343 } 3458a1edd7dSLiu Hui-R64343 3468a1edd7dSLiu Hui-R64343 version = 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", version); 3508a1edd7dSLiu Hui-R64343 printf("%s\n", get_table_entry_name(imximage_versions, NULL, version)); 3518a1edd7dSLiu Hui-R64343 printf("Data Size: "); 3528a1edd7dSLiu Hui-R64343 genimg_print_size(hdr_v2->boot_data.size); 3538a1edd7dSLiu Hui-R64343 printf("Load Address: %08x\n", (uint32_t)fhdr_v2->boot_data_ptr); 3548a1edd7dSLiu Hui-R64343 printf("Entry Point: %08x\n", (uint32_t)fhdr_v2->entry); 3558a1edd7dSLiu Hui-R64343 } 3568a1edd7dSLiu Hui-R64343 3578a1edd7dSLiu Hui-R64343 static void parse_cfg_cmd(struct imx_header *imxhdr, int32_t cmd, char *token, 3588a1edd7dSLiu Hui-R64343 char *name, int lineno, int fld, int dcd_len) 3598a1edd7dSLiu Hui-R64343 { 3608a1edd7dSLiu Hui-R64343 int value; 3618a1edd7dSLiu Hui-R64343 static int cmd_ver_first = ~0; 3628a1edd7dSLiu Hui-R64343 3638a1edd7dSLiu Hui-R64343 switch (cmd) { 3648a1edd7dSLiu Hui-R64343 case CMD_IMAGE_VERSION: 3658a1edd7dSLiu Hui-R64343 imximage_version = get_cfg_value(token, name, lineno); 3668a1edd7dSLiu Hui-R64343 if (cmd_ver_first == 0) { 3678a1edd7dSLiu Hui-R64343 fprintf(stderr, "Error: %s[%d] - IMAGE_VERSION " 3688a1edd7dSLiu Hui-R64343 "command need be the first before other " 3698a1edd7dSLiu Hui-R64343 "valid command in the file\n", name, lineno); 3708a1edd7dSLiu Hui-R64343 exit(EXIT_FAILURE); 3718a1edd7dSLiu Hui-R64343 } 3728a1edd7dSLiu Hui-R64343 cmd_ver_first = 1; 3738a1edd7dSLiu Hui-R64343 set_hdr_func(imxhdr); 3748a1edd7dSLiu Hui-R64343 break; 3758a1edd7dSLiu Hui-R64343 case CMD_BOOT_FROM: 3768a1edd7dSLiu Hui-R64343 imxhdr->flash_offset = get_table_entry_id(imximage_bootops, 3778a1edd7dSLiu Hui-R64343 "imximage boot option", token); 3788a1edd7dSLiu Hui-R64343 if (imxhdr->flash_offset == -1) { 3798a1edd7dSLiu Hui-R64343 fprintf(stderr, "Error: %s[%d] -Invalid boot device" 3808a1edd7dSLiu Hui-R64343 "(%s)\n", name, lineno, token); 3818a1edd7dSLiu Hui-R64343 exit(EXIT_FAILURE); 3828a1edd7dSLiu Hui-R64343 } 3838a1edd7dSLiu Hui-R64343 if (unlikely(cmd_ver_first != 1)) 3848a1edd7dSLiu Hui-R64343 cmd_ver_first = 0; 3858a1edd7dSLiu Hui-R64343 break; 3868a1edd7dSLiu Hui-R64343 case CMD_DATA: 3878a1edd7dSLiu Hui-R64343 value = get_cfg_value(token, name, lineno); 3888a1edd7dSLiu Hui-R64343 (*set_dcd_val)(imxhdr, name, lineno, fld, value, dcd_len); 3898a1edd7dSLiu Hui-R64343 if (unlikely(cmd_ver_first != 1)) 3908a1edd7dSLiu Hui-R64343 cmd_ver_first = 0; 3918a1edd7dSLiu Hui-R64343 break; 3928a1edd7dSLiu Hui-R64343 } 3938a1edd7dSLiu Hui-R64343 } 3948a1edd7dSLiu Hui-R64343 3958a1edd7dSLiu Hui-R64343 static void parse_cfg_fld(struct imx_header *imxhdr, int32_t *cmd, 3968a1edd7dSLiu Hui-R64343 char *token, char *name, int lineno, int fld, int *dcd_len) 3978a1edd7dSLiu Hui-R64343 { 3988a1edd7dSLiu Hui-R64343 int value; 3998a1edd7dSLiu Hui-R64343 4008a1edd7dSLiu Hui-R64343 switch (fld) { 4018a1edd7dSLiu Hui-R64343 case CFG_COMMAND: 4028a1edd7dSLiu Hui-R64343 *cmd = get_table_entry_id(imximage_cmds, 4038a1edd7dSLiu Hui-R64343 "imximage commands", token); 4048a1edd7dSLiu Hui-R64343 if (*cmd < 0) { 4058a1edd7dSLiu Hui-R64343 fprintf(stderr, "Error: %s[%d] - Invalid command" 4068a1edd7dSLiu Hui-R64343 "(%s)\n", name, lineno, token); 4078a1edd7dSLiu Hui-R64343 exit(EXIT_FAILURE); 4088a1edd7dSLiu Hui-R64343 } 4098a1edd7dSLiu Hui-R64343 break; 4108a1edd7dSLiu Hui-R64343 case CFG_REG_SIZE: 4118a1edd7dSLiu Hui-R64343 parse_cfg_cmd(imxhdr, *cmd, token, name, lineno, fld, *dcd_len); 4128a1edd7dSLiu Hui-R64343 break; 4138a1edd7dSLiu Hui-R64343 case CFG_REG_ADDRESS: 4148a1edd7dSLiu Hui-R64343 case CFG_REG_VALUE: 4158a1edd7dSLiu Hui-R64343 if (*cmd != CMD_DATA) 4168a1edd7dSLiu Hui-R64343 return; 4178a1edd7dSLiu Hui-R64343 4188a1edd7dSLiu Hui-R64343 value = get_cfg_value(token, name, lineno); 4198a1edd7dSLiu Hui-R64343 (*set_dcd_val)(imxhdr, name, lineno, fld, value, *dcd_len); 4208a1edd7dSLiu Hui-R64343 4218a1edd7dSLiu Hui-R64343 if (fld == CFG_REG_VALUE) 4228a1edd7dSLiu Hui-R64343 (*dcd_len)++; 4238a1edd7dSLiu Hui-R64343 break; 4248a1edd7dSLiu Hui-R64343 default: 4258a1edd7dSLiu Hui-R64343 break; 4268a1edd7dSLiu Hui-R64343 } 4278a1edd7dSLiu Hui-R64343 } 4288a1edd7dSLiu Hui-R64343 static uint32_t parse_cfg_file(struct imx_header *imxhdr, char *name) 4298edcde5eSStefano Babic { 4308edcde5eSStefano Babic FILE *fd = NULL; 4318edcde5eSStefano Babic char *line = NULL; 4328edcde5eSStefano Babic char *token, *saveptr1, *saveptr2; 4338edcde5eSStefano Babic int lineno = 0; 4348a1edd7dSLiu Hui-R64343 int fld; 4350ad22703SKim Phillips size_t len; 4368edcde5eSStefano Babic int dcd_len = 0; 4378edcde5eSStefano Babic int32_t cmd; 4388edcde5eSStefano Babic 4398edcde5eSStefano Babic fd = fopen(name, "r"); 4408edcde5eSStefano Babic if (fd == 0) { 4418edcde5eSStefano Babic fprintf(stderr, "Error: %s - Can't open DCD file\n", name); 4428edcde5eSStefano Babic exit(EXIT_FAILURE); 4438edcde5eSStefano Babic } 4448edcde5eSStefano Babic 4458edcde5eSStefano Babic /* Very simple parsing, line starting with # are comments 4468edcde5eSStefano Babic * and are dropped 4478edcde5eSStefano Babic */ 4488edcde5eSStefano Babic while ((getline(&line, &len, fd)) > 0) { 4498edcde5eSStefano Babic lineno++; 4508edcde5eSStefano Babic 4518edcde5eSStefano Babic token = strtok_r(line, "\r\n", &saveptr1); 4528edcde5eSStefano Babic if (token == NULL) 4538edcde5eSStefano Babic continue; 4548edcde5eSStefano Babic 4558edcde5eSStefano Babic /* Check inside the single line */ 4568edcde5eSStefano Babic for (fld = CFG_COMMAND, cmd = CMD_INVALID, 4578edcde5eSStefano Babic line = token; ; line = NULL, fld++) { 4588edcde5eSStefano Babic token = strtok_r(line, " \t", &saveptr2); 4598edcde5eSStefano Babic if (token == NULL) 4608edcde5eSStefano Babic break; 4618edcde5eSStefano Babic 4628edcde5eSStefano Babic /* Drop all text starting with '#' as comments */ 4638edcde5eSStefano Babic if (token[0] == '#') 4648edcde5eSStefano Babic break; 4658edcde5eSStefano Babic 4668a1edd7dSLiu Hui-R64343 parse_cfg_fld(imxhdr, &cmd, token, name, 4678a1edd7dSLiu Hui-R64343 lineno, fld, &dcd_len); 4688edcde5eSStefano Babic } 4698edcde5eSStefano Babic 4708edcde5eSStefano Babic } 4718edcde5eSStefano Babic 4728a1edd7dSLiu Hui-R64343 (*set_dcd_rst)(imxhdr, dcd_len, name, lineno); 4738edcde5eSStefano Babic fclose(fd); 4748edcde5eSStefano Babic 4755b28e913SStefano Babic return dcd_len; 4768edcde5eSStefano Babic } 4778edcde5eSStefano Babic 4788a1edd7dSLiu Hui-R64343 4798a1edd7dSLiu Hui-R64343 static int imximage_check_image_types(uint8_t type) 4808a1edd7dSLiu Hui-R64343 { 4818a1edd7dSLiu Hui-R64343 if (type == IH_TYPE_IMXIMAGE) 4828a1edd7dSLiu Hui-R64343 return EXIT_SUCCESS; 4838a1edd7dSLiu Hui-R64343 else 4848a1edd7dSLiu Hui-R64343 return EXIT_FAILURE; 4858a1edd7dSLiu Hui-R64343 } 4868a1edd7dSLiu Hui-R64343 4878a1edd7dSLiu Hui-R64343 static int imximage_verify_header(unsigned char *ptr, int image_size, 4888a1edd7dSLiu Hui-R64343 struct mkimage_params *params) 4898a1edd7dSLiu Hui-R64343 { 4908a1edd7dSLiu Hui-R64343 struct imx_header *imx_hdr = (struct imx_header *) ptr; 4918a1edd7dSLiu Hui-R64343 4928a1edd7dSLiu Hui-R64343 if (detect_imximage_version(imx_hdr) == IMXIMAGE_VER_INVALID) 4938a1edd7dSLiu Hui-R64343 return -FDT_ERR_BADSTRUCTURE; 4948a1edd7dSLiu Hui-R64343 4958a1edd7dSLiu Hui-R64343 return 0; 4968a1edd7dSLiu Hui-R64343 } 4978a1edd7dSLiu Hui-R64343 4988a1edd7dSLiu Hui-R64343 static void imximage_print_header(const void *ptr) 4998a1edd7dSLiu Hui-R64343 { 5008a1edd7dSLiu Hui-R64343 struct imx_header *imx_hdr = (struct imx_header *) ptr; 5018a1edd7dSLiu Hui-R64343 uint32_t version = detect_imximage_version(imx_hdr); 5028a1edd7dSLiu Hui-R64343 5038a1edd7dSLiu Hui-R64343 switch (version) { 5048a1edd7dSLiu Hui-R64343 case IMXIMAGE_V1: 5058a1edd7dSLiu Hui-R64343 print_hdr_v1(imx_hdr); 5068a1edd7dSLiu Hui-R64343 break; 5078a1edd7dSLiu Hui-R64343 case IMXIMAGE_V2: 5088a1edd7dSLiu Hui-R64343 print_hdr_v2(imx_hdr); 5098a1edd7dSLiu Hui-R64343 break; 5108a1edd7dSLiu Hui-R64343 default: 5118a1edd7dSLiu Hui-R64343 err_imximage_version(version); 5128a1edd7dSLiu Hui-R64343 break; 5138a1edd7dSLiu Hui-R64343 } 5148a1edd7dSLiu Hui-R64343 } 5158a1edd7dSLiu Hui-R64343 5168edcde5eSStefano Babic static void imximage_set_header(void *ptr, struct stat *sbuf, int ifd, 5178edcde5eSStefano Babic struct mkimage_params *params) 5188edcde5eSStefano Babic { 5198a1edd7dSLiu Hui-R64343 struct imx_header *imxhdr = (struct imx_header *)ptr; 5208a1edd7dSLiu Hui-R64343 uint32_t dcd_len; 5218edcde5eSStefano Babic 5228a1edd7dSLiu Hui-R64343 /* 5238a1edd7dSLiu Hui-R64343 * In order to not change the old imx cfg file 5248a1edd7dSLiu Hui-R64343 * by adding VERSION command into it, here need 5258a1edd7dSLiu Hui-R64343 * set up function ptr group to V1 by default. 5268a1edd7dSLiu Hui-R64343 */ 5278a1edd7dSLiu Hui-R64343 imximage_version = IMXIMAGE_V1; 5288a1edd7dSLiu Hui-R64343 set_hdr_func(imxhdr); 5298edcde5eSStefano Babic 5308edcde5eSStefano Babic /* Parse dcd configuration file */ 5318a1edd7dSLiu Hui-R64343 dcd_len = parse_cfg_file(imxhdr, params->imagename); 5328edcde5eSStefano Babic 5338a1edd7dSLiu Hui-R64343 /* Set the imx header */ 5348a1edd7dSLiu Hui-R64343 (*set_imx_hdr)(imxhdr, dcd_len, sbuf, params); 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 = { 5638a1edd7dSLiu Hui-R64343 .name = "Freescale i.MX 5x 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