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[] = { 39*f581e3a2SStefano Babic {CMD_BOOT_FROM, "BOOT_FROM", "boot command", }, 408edcde5eSStefano Babic {CMD_DATA, "DATA", "Reg Write Data", }, 418edcde5eSStefano Babic {-1, "", "", }, 428edcde5eSStefano Babic }; 438edcde5eSStefano Babic 448edcde5eSStefano Babic /* 458edcde5eSStefano Babic * Supported Boot options for configuration file 468edcde5eSStefano Babic * this is needed to set the correct flash offset 478edcde5eSStefano Babic */ 488edcde5eSStefano Babic static table_entry_t imximage_bootops[] = { 498edcde5eSStefano Babic {FLASH_OFFSET_SPI, "spi", "SPI Flash", }, 508edcde5eSStefano Babic {FLASH_OFFSET_NAND, "nand", "NAND Flash", }, 518edcde5eSStefano Babic {FLASH_OFFSET_SD, "sd", "SD Card", }, 528edcde5eSStefano Babic {FLASH_OFFSET_ONENAND, "onenand", "OneNAND Flash",}, 538edcde5eSStefano Babic {-1, "", "Invalid", }, 548edcde5eSStefano Babic }; 558edcde5eSStefano Babic 568edcde5eSStefano Babic 578edcde5eSStefano Babic static struct imx_header imximage_header; 588edcde5eSStefano Babic 598edcde5eSStefano Babic static uint32_t get_cfg_value(char *token, char *name, int linenr) 608edcde5eSStefano Babic { 618edcde5eSStefano Babic char *endptr; 628edcde5eSStefano Babic uint32_t value; 638edcde5eSStefano Babic 648edcde5eSStefano Babic errno = 0; 658edcde5eSStefano Babic value = strtoul(token, &endptr, 16); 668edcde5eSStefano Babic if (errno || (token == endptr)) { 678edcde5eSStefano Babic fprintf(stderr, "Error: %s[%d] - Invalid hex data(%s)\n", 688edcde5eSStefano Babic name, linenr, token); 698edcde5eSStefano Babic exit(EXIT_FAILURE); 708edcde5eSStefano Babic } 718edcde5eSStefano Babic return value; 728edcde5eSStefano Babic } 738edcde5eSStefano Babic 748edcde5eSStefano Babic static int imximage_check_image_types(uint8_t type) 758edcde5eSStefano Babic { 768edcde5eSStefano Babic if (type == IH_TYPE_IMXIMAGE) 778edcde5eSStefano Babic return EXIT_SUCCESS; 788edcde5eSStefano Babic else 798edcde5eSStefano Babic return EXIT_FAILURE; 808edcde5eSStefano Babic } 818edcde5eSStefano Babic 828edcde5eSStefano Babic static int imximage_verify_header(unsigned char *ptr, int image_size, 838edcde5eSStefano Babic struct mkimage_params *params) 848edcde5eSStefano Babic { 858edcde5eSStefano Babic 868edcde5eSStefano Babic struct imx_header *imx_hdr = (struct imx_header *) ptr; 878edcde5eSStefano Babic flash_header_t *hdr = &imx_hdr->fhdr; 888edcde5eSStefano Babic 898edcde5eSStefano Babic /* Only a few checks can be done: search for magic numbers */ 908edcde5eSStefano Babic if (hdr->app_code_barker != APP_CODE_BARKER) 918edcde5eSStefano Babic return -FDT_ERR_BADSTRUCTURE; 928edcde5eSStefano Babic 938edcde5eSStefano Babic if (imx_hdr->dcd_table.preamble.barker != DCD_BARKER) 948edcde5eSStefano Babic return -FDT_ERR_BADSTRUCTURE; 958edcde5eSStefano Babic 968edcde5eSStefano Babic return 0; 978edcde5eSStefano Babic } 988edcde5eSStefano Babic 998edcde5eSStefano Babic static void imximage_print_header(const void *ptr) 1008edcde5eSStefano Babic { 1018edcde5eSStefano Babic struct imx_header *imx_hdr = (struct imx_header *) ptr; 1028edcde5eSStefano Babic flash_header_t *hdr = &imx_hdr->fhdr; 1038edcde5eSStefano Babic uint32_t size; 1045b28e913SStefano Babic uint32_t length; 1055b28e913SStefano Babic dcd_t *dcd = &imx_hdr->dcd_table; 1068edcde5eSStefano Babic 1078edcde5eSStefano Babic size = imx_hdr->dcd_table.preamble.length; 1088edcde5eSStefano Babic if (size > (MAX_HW_CFG_SIZE * sizeof(dcd_type_addr_data_t))) { 1098edcde5eSStefano Babic fprintf(stderr, 1108edcde5eSStefano Babic "Error: Image corrupt DCD size %d exceed maximum %d\n", 1115b28e913SStefano Babic (uint32_t)(size / sizeof(dcd_type_addr_data_t)), 1125b28e913SStefano Babic MAX_HW_CFG_SIZE); 1138edcde5eSStefano Babic exit(EXIT_FAILURE); 1148edcde5eSStefano Babic } 1158edcde5eSStefano Babic 1165b28e913SStefano Babic length = dcd->preamble.length / sizeof(dcd_type_addr_data_t); 1178edcde5eSStefano Babic 1188edcde5eSStefano Babic printf("Image Type: Freescale IMX Boot Image\n"); 1198edcde5eSStefano Babic printf("Data Size: "); 1205b28e913SStefano Babic genimg_print_size(dcd->addr_data[length].type); 1218edcde5eSStefano Babic printf("Load Address: %08x\n", (unsigned int)hdr->app_dest_ptr); 1228edcde5eSStefano Babic printf("Entry Point: %08x\n", (unsigned int)hdr->app_code_jump_vector); 1238edcde5eSStefano Babic } 1248edcde5eSStefano Babic 1258edcde5eSStefano Babic static uint32_t imximage_parse_cfg_file(struct imx_header *imxhdr, char *name) 1268edcde5eSStefano Babic { 1278edcde5eSStefano Babic FILE *fd = NULL; 1288edcde5eSStefano Babic char *line = NULL; 1298edcde5eSStefano Babic char *token, *saveptr1, *saveptr2; 1308edcde5eSStefano Babic int lineno = 0; 1318edcde5eSStefano Babic int fld, value; 1320ad22703SKim Phillips size_t len; 1338edcde5eSStefano Babic int dcd_len = 0; 1348edcde5eSStefano Babic dcd_t *dcd = &imxhdr->dcd_table; 1358edcde5eSStefano Babic int32_t cmd; 1368edcde5eSStefano Babic 1378edcde5eSStefano Babic fd = fopen(name, "r"); 1388edcde5eSStefano Babic if (fd == 0) { 1398edcde5eSStefano Babic fprintf(stderr, "Error: %s - Can't open DCD file\n", name); 1408edcde5eSStefano Babic exit(EXIT_FAILURE); 1418edcde5eSStefano Babic } 1428edcde5eSStefano Babic 1438edcde5eSStefano Babic /* Very simple parsing, line starting with # are comments 1448edcde5eSStefano Babic * and are dropped 1458edcde5eSStefano Babic */ 1468edcde5eSStefano Babic while ((getline(&line, &len, fd)) > 0) { 1478edcde5eSStefano Babic lineno++; 1488edcde5eSStefano Babic 1498edcde5eSStefano Babic token = strtok_r(line, "\r\n", &saveptr1); 1508edcde5eSStefano Babic if (token == NULL) 1518edcde5eSStefano Babic continue; 1528edcde5eSStefano Babic 1538edcde5eSStefano Babic /* Check inside the single line */ 1548edcde5eSStefano Babic for (fld = CFG_COMMAND, cmd = CMD_INVALID, 1558edcde5eSStefano Babic line = token; ; line = NULL, fld++) { 1568edcde5eSStefano Babic token = strtok_r(line, " \t", &saveptr2); 1578edcde5eSStefano Babic if (token == NULL) 1588edcde5eSStefano Babic break; 1598edcde5eSStefano Babic 1608edcde5eSStefano Babic /* Drop all text starting with '#' as comments */ 1618edcde5eSStefano Babic if (token[0] == '#') 1628edcde5eSStefano Babic break; 1638edcde5eSStefano Babic 1648edcde5eSStefano Babic /* parse all fields in a single line */ 1658edcde5eSStefano Babic switch (fld) { 1668edcde5eSStefano Babic case CFG_COMMAND: 1678edcde5eSStefano Babic cmd = get_table_entry_id(imximage_cmds, 1688edcde5eSStefano Babic "imximage commands", token); 1698edcde5eSStefano Babic if (cmd < 0) { 1708edcde5eSStefano Babic fprintf(stderr, 1718edcde5eSStefano Babic "Error: %s[%d] - " 1728edcde5eSStefano Babic "Invalid command (%s)\n", 1738edcde5eSStefano Babic name, lineno, token); 1748edcde5eSStefano Babic exit(EXIT_FAILURE); 1758edcde5eSStefano Babic } 1768edcde5eSStefano Babic break; 1778edcde5eSStefano Babic case CFG_REG_SIZE: 1788edcde5eSStefano Babic switch (cmd) { 1798edcde5eSStefano Babic case CMD_BOOT_FROM: 1808edcde5eSStefano Babic /* Get flash header offset */ 1818edcde5eSStefano Babic imxhdr->flash_offset = 1828edcde5eSStefano Babic get_table_entry_id( 1838edcde5eSStefano Babic imximage_bootops, 1848edcde5eSStefano Babic "imximage boot option", 1858edcde5eSStefano Babic token); 1868edcde5eSStefano Babic if (imxhdr->flash_offset == -1) { 1878edcde5eSStefano Babic fprintf(stderr, 1888edcde5eSStefano Babic "Error: %s[%d] -" 1898edcde5eSStefano Babic "Invalid boot device" 1908edcde5eSStefano Babic "(%s)\n", 1918edcde5eSStefano Babic name, lineno, token); 1928edcde5eSStefano Babic exit(EXIT_FAILURE); 1938edcde5eSStefano Babic } 1948edcde5eSStefano Babic break; 1958edcde5eSStefano Babic case CMD_DATA: 1968edcde5eSStefano Babic value = get_cfg_value(token, 1978edcde5eSStefano Babic name, lineno); 1988edcde5eSStefano Babic 1998edcde5eSStefano Babic /* Byte, halfword, word */ 2008edcde5eSStefano Babic if ((value != 1) && 2018edcde5eSStefano Babic (value != 2) && (value != 4)) { 2028edcde5eSStefano Babic fprintf(stderr, 2038edcde5eSStefano Babic "Error: %s[%d] - " 2048edcde5eSStefano Babic "Invalid register size " 2058edcde5eSStefano Babic "(%d)\n", 2068edcde5eSStefano Babic name, lineno, value); 2078edcde5eSStefano Babic exit(EXIT_FAILURE); 2088edcde5eSStefano Babic } 2098edcde5eSStefano Babic dcd->addr_data[dcd_len].type = value; 2108edcde5eSStefano Babic break; 2118edcde5eSStefano Babic } 2128edcde5eSStefano Babic 2138edcde5eSStefano Babic case CFG_REG_ADDRESS: 2148edcde5eSStefano Babic if (cmd == CMD_DATA) 2158edcde5eSStefano Babic dcd->addr_data[dcd_len].addr = 2168edcde5eSStefano Babic get_cfg_value(token, 2178edcde5eSStefano Babic name, lineno); 2188edcde5eSStefano Babic break; 2198edcde5eSStefano Babic case CFG_REG_VALUE: 2208edcde5eSStefano Babic if (cmd == CMD_DATA) { 2218edcde5eSStefano Babic dcd->addr_data[dcd_len].value = 2228edcde5eSStefano Babic get_cfg_value(token, 2238edcde5eSStefano Babic name, lineno); 2248edcde5eSStefano Babic dcd_len++; 2258edcde5eSStefano Babic } 2268edcde5eSStefano Babic break; 2278edcde5eSStefano Babic } 2288edcde5eSStefano Babic } 2298edcde5eSStefano Babic 2308edcde5eSStefano Babic if (dcd_len > MAX_HW_CFG_SIZE) { 2318edcde5eSStefano Babic fprintf(stderr, 2328edcde5eSStefano Babic "Error: %s[%d] -" 2338edcde5eSStefano Babic "DCD table exceeds maximum size(%d)\n", 2348edcde5eSStefano Babic name, lineno, MAX_HW_CFG_SIZE); 2358edcde5eSStefano Babic } 2368edcde5eSStefano Babic } 2378edcde5eSStefano Babic dcd->preamble.barker = DCD_BARKER; 2388edcde5eSStefano Babic dcd->preamble.length = dcd_len * sizeof(dcd_type_addr_data_t); 2398edcde5eSStefano Babic fclose(fd); 2408edcde5eSStefano Babic 2415b28e913SStefano Babic return dcd_len; 2428edcde5eSStefano Babic } 2438edcde5eSStefano Babic 2448edcde5eSStefano Babic static void imximage_set_header(void *ptr, struct stat *sbuf, int ifd, 2458edcde5eSStefano Babic struct mkimage_params *params) 2468edcde5eSStefano Babic { 2478edcde5eSStefano Babic struct imx_header *hdr = (struct imx_header *)ptr; 2488edcde5eSStefano Babic flash_header_t *fhdr = &hdr->fhdr; 2498edcde5eSStefano Babic int dcd_len; 2505b28e913SStefano Babic dcd_t *dcd = &hdr->dcd_table; 2518edcde5eSStefano Babic uint32_t base_offset; 2528edcde5eSStefano Babic 2538edcde5eSStefano Babic /* Set default offset */ 2548edcde5eSStefano Babic hdr->flash_offset = FLASH_OFFSET_STANDARD; 2558edcde5eSStefano Babic 2568edcde5eSStefano Babic /* Set magic number */ 2578edcde5eSStefano Babic fhdr->app_code_barker = APP_CODE_BARKER; 2588edcde5eSStefano Babic 2598edcde5eSStefano Babic /* Parse dcd configuration file */ 2608edcde5eSStefano Babic dcd_len = imximage_parse_cfg_file(hdr, params->imagename); 2618edcde5eSStefano Babic 2628edcde5eSStefano Babic fhdr->app_dest_ptr = params->addr; 2638edcde5eSStefano Babic fhdr->app_dest_ptr = params->ep - hdr->flash_offset - 2648edcde5eSStefano Babic sizeof(struct imx_header); 2658edcde5eSStefano Babic fhdr->app_code_jump_vector = params->ep; 2668edcde5eSStefano Babic 2678edcde5eSStefano Babic base_offset = fhdr->app_dest_ptr + hdr->flash_offset ; 2685b28e913SStefano Babic fhdr->dcd_ptr_ptr = (uint32_t) (offsetof(flash_header_t, dcd_ptr) - 2695b28e913SStefano Babic offsetof(flash_header_t, app_code_jump_vector) + 2705b28e913SStefano Babic base_offset); 2718edcde5eSStefano Babic 2728edcde5eSStefano Babic fhdr->dcd_ptr = base_offset + 2735b28e913SStefano Babic offsetof(struct imx_header, dcd_table); 2748edcde5eSStefano Babic 2758edcde5eSStefano Babic /* The external flash header must be at the end of the DCD table */ 2765b28e913SStefano Babic dcd->addr_data[dcd_len].type = sbuf->st_size + 2778edcde5eSStefano Babic hdr->flash_offset + 2788edcde5eSStefano Babic sizeof(struct imx_header); 2798edcde5eSStefano Babic 2808edcde5eSStefano Babic /* Security feature are not supported */ 2818edcde5eSStefano Babic fhdr->app_code_csf = 0; 2825b28e913SStefano Babic fhdr->super_root_key = 0; 2838edcde5eSStefano Babic 2848edcde5eSStefano Babic } 2858edcde5eSStefano Babic 2868edcde5eSStefano Babic int imximage_check_params(struct mkimage_params *params) 2878edcde5eSStefano Babic { 2888edcde5eSStefano Babic if (!params) 2898edcde5eSStefano Babic return CFG_INVALID; 2908edcde5eSStefano Babic if (!strlen(params->imagename)) { 2918edcde5eSStefano Babic fprintf(stderr, "Error: %s - Configuration file not specified, " 2928edcde5eSStefano Babic "it is needed for imximage generation\n", 2938edcde5eSStefano Babic params->cmdname); 2948edcde5eSStefano Babic return CFG_INVALID; 2958edcde5eSStefano Babic } 2968edcde5eSStefano Babic /* 2978edcde5eSStefano Babic * Check parameters: 2988edcde5eSStefano Babic * XIP is not allowed and verify that incompatible 2998edcde5eSStefano Babic * parameters are not sent at the same time 3008edcde5eSStefano Babic * For example, if list is required a data image must not be provided 3018edcde5eSStefano Babic */ 3028edcde5eSStefano Babic return (params->dflag && (params->fflag || params->lflag)) || 3038edcde5eSStefano Babic (params->fflag && (params->dflag || params->lflag)) || 3048edcde5eSStefano Babic (params->lflag && (params->dflag || params->fflag)) || 3058edcde5eSStefano Babic (params->xflag) || !(strlen(params->imagename)); 3068edcde5eSStefano Babic } 3078edcde5eSStefano Babic 3088edcde5eSStefano Babic /* 3098edcde5eSStefano Babic * imximage parameters 3108edcde5eSStefano Babic */ 3118edcde5eSStefano Babic static struct image_type_params imximage_params = { 3128edcde5eSStefano Babic .name = "Freescale i.MX 51 Boot Image support", 3138edcde5eSStefano Babic .header_size = sizeof(struct imx_header), 3148edcde5eSStefano Babic .hdr = (void *)&imximage_header, 3158edcde5eSStefano Babic .check_image_type = imximage_check_image_types, 3168edcde5eSStefano Babic .verify_header = imximage_verify_header, 3178edcde5eSStefano Babic .print_header = imximage_print_header, 3188edcde5eSStefano Babic .set_header = imximage_set_header, 3198edcde5eSStefano Babic .check_params = imximage_check_params, 3208edcde5eSStefano Babic }; 3218edcde5eSStefano Babic 3228edcde5eSStefano Babic void init_imx_image_type(void) 3238edcde5eSStefano Babic { 3248edcde5eSStefano Babic mkimage_register(&imximage_params); 3258edcde5eSStefano Babic } 326