tools: add i.MX8M image support
i.MX8M bootable image type is like i.MX6/7, but there is signed HDMI firmware image in front of A53 bootable image, which is also has an IVT header. Here we also include fit image to generate a bootable image. Signed-off-by: Peng Fan <peng.fan@nxp.com> Signed-off-by: Stefano Babic <sbabic@denx.de>
This commit is contained in:
		
							parent
							
								
									ea91031b22
								
							
						
					
					
						commit
						6609c2663c
					
				|  | @ -140,6 +140,7 @@ static const table_entry_t uimage_type[] = { | ||||||
| 	{	IH_TYPE_KWBIMAGE,   "kwbimage",   "Kirkwood Boot Image",}, | 	{	IH_TYPE_KWBIMAGE,   "kwbimage",   "Kirkwood Boot Image",}, | ||||||
| 	{	IH_TYPE_IMXIMAGE,   "imximage",   "Freescale i.MX Boot Image",}, | 	{	IH_TYPE_IMXIMAGE,   "imximage",   "Freescale i.MX Boot Image",}, | ||||||
| 	{	IH_TYPE_IMX8IMAGE,  "imx8image",  "NXP i.MX8 Boot Image",}, | 	{	IH_TYPE_IMX8IMAGE,  "imx8image",  "NXP i.MX8 Boot Image",}, | ||||||
|  | 	{	IH_TYPE_IMX8MIMAGE, "imx8mimage", "NXP i.MX8M Boot Image",}, | ||||||
| 	{	IH_TYPE_INVALID,    "invalid",	  "Invalid Image",	}, | 	{	IH_TYPE_INVALID,    "invalid",	  "Invalid Image",	}, | ||||||
| 	{	IH_TYPE_MULTI,	    "multi",	  "Multi-File Image",	}, | 	{	IH_TYPE_MULTI,	    "multi",	  "Multi-File Image",	}, | ||||||
| 	{	IH_TYPE_OMAPIMAGE,  "omapimage",  "TI OMAP SPL With GP CH",}, | 	{	IH_TYPE_OMAPIMAGE,  "omapimage",  "TI OMAP SPL With GP CH",}, | ||||||
|  |  | ||||||
|  | @ -279,6 +279,7 @@ enum { | ||||||
| 	IH_TYPE_PMMC,            /* TI Power Management Micro-Controller Firmware */ | 	IH_TYPE_PMMC,            /* TI Power Management Micro-Controller Firmware */ | ||||||
| 	IH_TYPE_STM32IMAGE,		/* STMicroelectronics STM32 Image */ | 	IH_TYPE_STM32IMAGE,		/* STMicroelectronics STM32 Image */ | ||||||
| 	IH_TYPE_SOCFPGAIMAGE_V1,	/* Altera SOCFPGA A10 Preloader	*/ | 	IH_TYPE_SOCFPGAIMAGE_V1,	/* Altera SOCFPGA A10 Preloader	*/ | ||||||
|  | 	IH_TYPE_IMX8MIMAGE,		/* Freescale IMX8MBoot Image	*/ | ||||||
| 	IH_TYPE_MTKIMAGE,		/* MediaTek BootROM loadable Image */ | 	IH_TYPE_MTKIMAGE,		/* MediaTek BootROM loadable Image */ | ||||||
| 
 | 
 | ||||||
| 	IH_TYPE_COUNT,			/* Number of image types */ | 	IH_TYPE_COUNT,			/* Number of image types */ | ||||||
|  |  | ||||||
|  | @ -33,6 +33,7 @@ | ||||||
| #define FLASH_OFFSET_NOR	0x1000 | #define FLASH_OFFSET_NOR	0x1000 | ||||||
| #define FLASH_OFFSET_SATA	FLASH_OFFSET_STANDARD | #define FLASH_OFFSET_SATA	FLASH_OFFSET_STANDARD | ||||||
| #define FLASH_OFFSET_QSPI	0x1000 | #define FLASH_OFFSET_QSPI	0x1000 | ||||||
|  | #define FLASH_OFFSET_FLEXSPI	0x1000 | ||||||
| 
 | 
 | ||||||
| /* Initial Load Region Size */ | /* Initial Load Region Size */ | ||||||
| #define FLASH_LOADSIZE_UNDEFINED	0xFFFFFFFF | #define FLASH_LOADSIZE_UNDEFINED	0xFFFFFFFF | ||||||
|  | @ -48,6 +49,7 @@ | ||||||
| /* Command tags and parameters */ | /* Command tags and parameters */ | ||||||
| #define IVT_HEADER_TAG			0xD1 | #define IVT_HEADER_TAG			0xD1 | ||||||
| #define IVT_VERSION			0x40 | #define IVT_VERSION			0x40 | ||||||
|  | #define IVT_VERSION_V3			0x41 | ||||||
| #define DCD_HEADER_TAG			0xD2 | #define DCD_HEADER_TAG			0xD2 | ||||||
| #define DCD_VERSION			0x40 | #define DCD_VERSION			0x40 | ||||||
| #define DCD_WRITE_DATA_COMMAND_TAG	0xCC | #define DCD_WRITE_DATA_COMMAND_TAG	0xCC | ||||||
|  | @ -71,6 +73,12 @@ enum imximage_cmd { | ||||||
| 	CMD_CHECK_BITS_CLR, | 	CMD_CHECK_BITS_CLR, | ||||||
| 	CMD_CSF, | 	CMD_CSF, | ||||||
| 	CMD_PLUGIN, | 	CMD_PLUGIN, | ||||||
|  | 	/* Follwoing on i.MX8MQ/MM */ | ||||||
|  | 	CMD_FIT, | ||||||
|  | 	CMD_SIGNED_HDMI, | ||||||
|  | 	CMD_LOADER, | ||||||
|  | 	CMD_SECOND_LOADER, | ||||||
|  | 	CMD_DDR_FW, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| enum imximage_fld_types { | enum imximage_fld_types { | ||||||
|  | @ -84,7 +92,8 @@ enum imximage_fld_types { | ||||||
| enum imximage_version { | enum imximage_version { | ||||||
| 	IMXIMAGE_VER_INVALID = -1, | 	IMXIMAGE_VER_INVALID = -1, | ||||||
| 	IMXIMAGE_V1 = 1, | 	IMXIMAGE_V1 = 1, | ||||||
| 	IMXIMAGE_V2 | 	IMXIMAGE_V2, | ||||||
|  | 	IMXIMAGE_V3 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|  | @ -177,6 +186,12 @@ typedef struct { | ||||||
| 	} data; | 	} data; | ||||||
| } imx_header_v2_t; | } imx_header_v2_t; | ||||||
| 
 | 
 | ||||||
|  | typedef struct { | ||||||
|  | 	flash_header_v2_t fhdr; | ||||||
|  | 	boot_data_t boot_data; | ||||||
|  | 	uint32_t padding[5]; | ||||||
|  | } imx_header_v3_t; | ||||||
|  | 
 | ||||||
| /* The header must be aligned to 4k on MX53 for NAND boot */ | /* The header must be aligned to 4k on MX53 for NAND boot */ | ||||||
| struct imx_header { | struct imx_header { | ||||||
| 	union { | 	union { | ||||||
|  |  | ||||||
|  | @ -94,6 +94,7 @@ dumpimage-mkimage-objs := aisimage.o \ | ||||||
| 			imagetool.o \
 | 			imagetool.o \
 | ||||||
| 			imximage.o \
 | 			imximage.o \
 | ||||||
| 			imx8image.o \
 | 			imx8image.o \
 | ||||||
|  | 			imx8mimage.o \
 | ||||||
| 			kwbimage.o \
 | 			kwbimage.o \
 | ||||||
| 			lib/md5.o \
 | 			lib/md5.o \
 | ||||||
| 			lpc32xximage.o \
 | 			lpc32xximage.o \
 | ||||||
|  |  | ||||||
|  | @ -233,6 +233,7 @@ time_t imagetool_get_source_date( | ||||||
| void pbl_load_uboot(int fd, struct image_tool_params *mparams); | void pbl_load_uboot(int fd, struct image_tool_params *mparams); | ||||||
| int zynqmpbif_copy_image(int fd, struct image_tool_params *mparams); | int zynqmpbif_copy_image(int fd, struct image_tool_params *mparams); | ||||||
| int imx8image_copy_image(int fd, struct image_tool_params *mparams); | int imx8image_copy_image(int fd, struct image_tool_params *mparams); | ||||||
|  | int imx8mimage_copy_image(int fd, struct image_tool_params *mparams); | ||||||
| 
 | 
 | ||||||
| #define ___cat(a, b) a ## b | #define ___cat(a, b) a ## b | ||||||
| #define __cat(a, b) ___cat(a, b) | #define __cat(a, b) ___cat(a, b) | ||||||
|  |  | ||||||
|  | @ -0,0 +1,623 @@ | ||||||
|  | // SPDX-License-Identifier: GPL-2.0+
 | ||||||
|  | /*
 | ||||||
|  |  * Copyright 2018 NXP | ||||||
|  |  * | ||||||
|  |  * Peng Fan <peng.fan@nxp.com> | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | #include "imagetool.h" | ||||||
|  | #include <image.h> | ||||||
|  | #include "imximage.h" | ||||||
|  | #include "compiler.h" | ||||||
|  | 
 | ||||||
|  | static uint32_t ap_start_addr, sld_start_addr, sld_src_off; | ||||||
|  | static char *ap_img, *sld_img, *signed_hdmi; | ||||||
|  | static imx_header_v3_t imx_header[2]; /* At most there are 3 IVT headers */ | ||||||
|  | static uint32_t rom_image_offset; | ||||||
|  | static uint32_t sector_size = 0x200; | ||||||
|  | static uint32_t image_off; | ||||||
|  | static uint32_t sld_header_off; | ||||||
|  | static uint32_t ivt_offset; | ||||||
|  | static uint32_t using_fit; | ||||||
|  | 
 | ||||||
|  | #define CSF_SIZE 0x2000 | ||||||
|  | #define HDMI_IVT_ID 0 | ||||||
|  | #define IMAGE_IVT_ID 1 | ||||||
|  | 
 | ||||||
|  | #define HDMI_FW_SIZE		0x17000 /* Use Last 0x1000 for IVT and CSF */ | ||||||
|  | #define ALIGN_SIZE		0x1000 | ||||||
|  | #define ALIGN(x,a)	__ALIGN_MASK((x), (__typeof__(x))(a) - 1, a) | ||||||
|  | #define __ALIGN_MASK(x,mask,mask2) (((x) + (mask)) / (mask2) * (mask2)) | ||||||
|  | 
 | ||||||
|  | static uint32_t get_cfg_value(char *token, char *name,  int linenr) | ||||||
|  | { | ||||||
|  | 	char *endptr; | ||||||
|  | 	uint32_t value; | ||||||
|  | 
 | ||||||
|  | 	errno = 0; | ||||||
|  | 	value = strtoul(token, &endptr, 16); | ||||||
|  | 	if (errno || token == endptr) { | ||||||
|  | 		fprintf(stderr, "Error: %s[%d] - Invalid hex data(%s)\n", | ||||||
|  | 			name,  linenr, token); | ||||||
|  | 		exit(EXIT_FAILURE); | ||||||
|  | 	} | ||||||
|  | 	return value; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int imx8mimage_check_params(struct image_tool_params *params) | ||||||
|  | { | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void imx8mimage_set_header(void *ptr, struct stat *sbuf, int ifd, | ||||||
|  | 				  struct image_tool_params *params) | ||||||
|  | { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void imx8mimage_print_header(const void *ptr) | ||||||
|  | { | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int imx8mimage_check_image_types(uint8_t type) | ||||||
|  | { | ||||||
|  | 	return (type == IH_TYPE_IMX8MIMAGE) ? EXIT_SUCCESS : EXIT_FAILURE; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static table_entry_t imx8mimage_cmds[] = { | ||||||
|  | 	{CMD_BOOT_FROM,         "BOOT_FROM",            "boot command",	      }, | ||||||
|  | 	{CMD_FIT,               "FIT",                  "fit image",	      }, | ||||||
|  | 	{CMD_SIGNED_HDMI,       "SIGNED_HDMI",          "signed hdmi image",  }, | ||||||
|  | 	{CMD_LOADER,            "LOADER",               "loader image",       }, | ||||||
|  | 	{CMD_SECOND_LOADER,     "SECOND_LOADER",        "2nd loader image",   }, | ||||||
|  | 	{CMD_DDR_FW,            "DDR_FW",               "ddr firmware",       }, | ||||||
|  | 	{-1,                    "",                     "",	              }, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static table_entry_t imx8mimage_ivt_offset[] = { | ||||||
|  | 	{0x400,		"sd",			"sd/emmc",}, | ||||||
|  | 	{0x400,		"emmc_fastboot",	"emmc fastboot",}, | ||||||
|  | 	{0x1000,	"fspi",			"flexspi",	}, | ||||||
|  | 	{-1,		"",			"Invalid",	}, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static void parse_cfg_cmd(int32_t cmd, char *token, char *name, int lineno) | ||||||
|  | { | ||||||
|  | 	switch (cmd) { | ||||||
|  | 	case CMD_BOOT_FROM: | ||||||
|  | 		ivt_offset = get_table_entry_id(imx8mimage_ivt_offset, | ||||||
|  | 						"imx8mimage ivt offset", | ||||||
|  | 						token); | ||||||
|  | 		if (!strncmp(token, "sd", 2)) | ||||||
|  | 			rom_image_offset = 0x8000; | ||||||
|  | 		break; | ||||||
|  | 	case CMD_LOADER: | ||||||
|  | 		ap_img = token; | ||||||
|  | 		break; | ||||||
|  | 	case CMD_SECOND_LOADER: | ||||||
|  | 		sld_img = token; | ||||||
|  | 		break; | ||||||
|  | 	case CMD_SIGNED_HDMI: | ||||||
|  | 		signed_hdmi = token; | ||||||
|  | 	case CMD_FIT: | ||||||
|  | 		using_fit = 1; | ||||||
|  | 		break; | ||||||
|  | 	case CMD_DDR_FW: | ||||||
|  | 		/* Do nothing */ | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void parse_cfg_fld(int32_t *cmd, char *token, | ||||||
|  | 			  char *name, int lineno, int fld) | ||||||
|  | { | ||||||
|  | 	switch (fld) { | ||||||
|  | 	case CFG_COMMAND: | ||||||
|  | 		*cmd = get_table_entry_id(imx8mimage_cmds, | ||||||
|  | 					  "imx8mimage commands", token); | ||||||
|  | 		if (*cmd < 0) { | ||||||
|  | 			fprintf(stderr, "Error: %s[%d] - Invalid command" "(%s)\n", | ||||||
|  | 				name, lineno, token); | ||||||
|  | 			exit(EXIT_FAILURE); | ||||||
|  | 		} | ||||||
|  | 		break; | ||||||
|  | 	case CFG_REG_SIZE: | ||||||
|  | 		parse_cfg_cmd(*cmd, token, name, lineno); | ||||||
|  | 		break; | ||||||
|  | 	case CFG_REG_ADDRESS: | ||||||
|  | 		switch (*cmd) { | ||||||
|  | 		case CMD_LOADER: | ||||||
|  | 			ap_start_addr = get_cfg_value(token, name, lineno); | ||||||
|  | 			break; | ||||||
|  | 		case CMD_SECOND_LOADER: | ||||||
|  | 			sld_start_addr = get_cfg_value(token, name, lineno); | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 		break; | ||||||
|  | 	case CFG_REG_VALUE: | ||||||
|  | 		switch (*cmd) { | ||||||
|  | 		case CMD_SECOND_LOADER: | ||||||
|  | 			sld_src_off = get_cfg_value(token, name, lineno); | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 	default: | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static uint32_t parse_cfg_file(char *name) | ||||||
|  | { | ||||||
|  | 	FILE *fd = NULL; | ||||||
|  | 	char *line = NULL; | ||||||
|  | 	char *token, *saveptr1, *saveptr2; | ||||||
|  | 	int lineno = 0; | ||||||
|  | 	int fld; | ||||||
|  | 	size_t len; | ||||||
|  | 	int32_t cmd; | ||||||
|  | 
 | ||||||
|  | 	fd = fopen(name, "r"); | ||||||
|  | 	if (fd == 0) { | ||||||
|  | 		fprintf(stderr, "Error: %s - Can't open cfg file\n", name); | ||||||
|  | 		exit(EXIT_FAILURE); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Very simple parsing, line starting with # are comments | ||||||
|  | 	 * and are dropped | ||||||
|  | 	 */ | ||||||
|  | 	while ((getline(&line, &len, fd)) > 0) { | ||||||
|  | 		lineno++; | ||||||
|  | 
 | ||||||
|  | 		token = strtok_r(line, "\r\n", &saveptr1); | ||||||
|  | 		if (!token) | ||||||
|  | 			continue; | ||||||
|  | 
 | ||||||
|  | 		/* Check inside the single line */ | ||||||
|  | 		for (fld = CFG_COMMAND, cmd = CFG_INVALID, | ||||||
|  | 		     line = token; ; line = NULL, fld++) { | ||||||
|  | 			token = strtok_r(line, " \t", &saveptr2); | ||||||
|  | 			if (!token) | ||||||
|  | 				break; | ||||||
|  | 
 | ||||||
|  | 			/* Drop all text starting with '#' as comments */ | ||||||
|  | 			if (token[0] == '#') | ||||||
|  | 				break; | ||||||
|  | 
 | ||||||
|  | 			parse_cfg_fld(&cmd, token, name, lineno, fld); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void fill_zero(int ifd, int size, int offset) | ||||||
|  | { | ||||||
|  | 	int fill_size; | ||||||
|  | 	uint8_t zeros[4096]; | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	memset(zeros, 0, sizeof(zeros)); | ||||||
|  | 
 | ||||||
|  | 	ret = lseek(ifd, offset, SEEK_SET); | ||||||
|  | 	if (ret < 0) { | ||||||
|  | 		fprintf(stderr, "%s seek: %s\n", __func__, strerror(errno)); | ||||||
|  | 		exit(EXIT_FAILURE); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	while (size) { | ||||||
|  | 		if (size > 4096) | ||||||
|  | 			fill_size = 4096; | ||||||
|  | 		else | ||||||
|  | 			fill_size = size; | ||||||
|  | 
 | ||||||
|  | 		if (write(ifd, (char *)&zeros, fill_size) != fill_size) { | ||||||
|  | 			fprintf(stderr, "Write error: %s\n", | ||||||
|  | 				strerror(errno)); | ||||||
|  | 			exit(EXIT_FAILURE); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		size -= fill_size; | ||||||
|  | 	}; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void copy_file(int ifd, const char *datafile, int pad, int offset, | ||||||
|  | 		      int datafile_offset) | ||||||
|  | { | ||||||
|  | 	int dfd; | ||||||
|  | 	struct stat sbuf; | ||||||
|  | 	unsigned char *ptr; | ||||||
|  | 	int tail; | ||||||
|  | 	int zero = 0; | ||||||
|  | 	uint8_t zeros[4096]; | ||||||
|  | 	int size, ret; | ||||||
|  | 
 | ||||||
|  | 	memset(zeros, 0, sizeof(zeros)); | ||||||
|  | 
 | ||||||
|  | 	dfd = open(datafile, O_RDONLY | O_BINARY); | ||||||
|  | 	if (dfd < 0) { | ||||||
|  | 		fprintf(stderr, "Can't open %s: %s\n", | ||||||
|  | 			datafile, strerror(errno)); | ||||||
|  | 		exit(EXIT_FAILURE); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (fstat(dfd, &sbuf) < 0) { | ||||||
|  | 		fprintf(stderr, "Can't stat %s: %s\n", | ||||||
|  | 			datafile, strerror(errno)); | ||||||
|  | 		exit(EXIT_FAILURE); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, dfd, 0); | ||||||
|  | 	if (ptr == MAP_FAILED) { | ||||||
|  | 		fprintf(stderr, "Can't read %s: %s\n", | ||||||
|  | 			datafile, strerror(errno)); | ||||||
|  | 		exit(EXIT_FAILURE); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	size = sbuf.st_size - datafile_offset; | ||||||
|  | 	ret = lseek(ifd, offset, SEEK_SET); | ||||||
|  | 	if (ret < 0) { | ||||||
|  | 		fprintf(stderr, "lseek ifd fail\n"); | ||||||
|  | 		exit(EXIT_FAILURE); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (write(ifd, ptr + datafile_offset, size) != size) { | ||||||
|  | 		fprintf(stderr, "Write error %s\n", | ||||||
|  | 			strerror(errno)); | ||||||
|  | 		exit(EXIT_FAILURE); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	tail = size % 4; | ||||||
|  | 	pad = pad - size; | ||||||
|  | 	if (pad == 1 && tail != 0) { | ||||||
|  | 		if (write(ifd, (char *)&zero, 4 - tail) != 4 - tail) { | ||||||
|  | 			fprintf(stderr, "Write error on %s\n", | ||||||
|  | 				strerror(errno)); | ||||||
|  | 			exit(EXIT_FAILURE); | ||||||
|  | 		} | ||||||
|  | 	} else if (pad > 1) { | ||||||
|  | 		while (pad > 0) { | ||||||
|  | 			int todo = sizeof(zeros); | ||||||
|  | 
 | ||||||
|  | 			if (todo > pad) | ||||||
|  | 				todo = pad; | ||||||
|  | 			if (write(ifd, (char *)&zeros, todo) != todo) { | ||||||
|  | 				fprintf(stderr, "Write error: %s\n", | ||||||
|  | 					strerror(errno)); | ||||||
|  | 				exit(EXIT_FAILURE); | ||||||
|  | 			} | ||||||
|  | 			pad -= todo; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	munmap((void *)ptr, sbuf.st_size); | ||||||
|  | 	close(dfd); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* Return this IVT offset in the final output file */ | ||||||
|  | static int generate_ivt_for_fit(int fd, int fit_offset, uint32_t ep, | ||||||
|  | 				uint32_t *fit_load_addr) | ||||||
|  | { | ||||||
|  | 	image_header_t image_header; | ||||||
|  | 	int ret; | ||||||
|  | 
 | ||||||
|  | 	uint32_t fit_size, load_addr; | ||||||
|  | 	int align_len = 64 - 1; /* 64 is cacheline size */ | ||||||
|  | 
 | ||||||
|  | 	ret = lseek(fd, fit_offset, SEEK_SET); | ||||||
|  | 	if (ret < 0) { | ||||||
|  | 		fprintf(stderr, "lseek fd fail for fit\n"); | ||||||
|  | 		exit(EXIT_FAILURE); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (read(fd, (char *)&image_header, sizeof(image_header_t)) != | ||||||
|  | 	    sizeof(image_header_t)) { | ||||||
|  | 		fprintf(stderr, "generate_ivt_for_fit read failed: %s\n", | ||||||
|  | 			strerror(errno)); | ||||||
|  | 		exit(EXIT_FAILURE); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (be32_to_cpu(image_header.ih_magic) != FDT_MAGIC) { | ||||||
|  | 		fprintf(stderr, "%s error: not a FIT file\n", __func__); | ||||||
|  | 		exit(EXIT_FAILURE); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	fit_size = fdt_totalsize(&image_header); | ||||||
|  | 	fit_size = (fit_size + 3) & ~3; | ||||||
|  | 
 | ||||||
|  | 	fit_size = ALIGN(fit_size, ALIGN_SIZE); | ||||||
|  | 
 | ||||||
|  | 	ret = lseek(fd, fit_offset + fit_size, SEEK_SET); | ||||||
|  | 	if (ret < 0) { | ||||||
|  | 		fprintf(stderr, "lseek fd fail for fit\n"); | ||||||
|  | 		exit(EXIT_FAILURE); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * ep is the u-boot entry. SPL loads the FIT before the u-boot | ||||||
|  | 	 * address. 0x2000 is for CSF_SIZE | ||||||
|  | 	 */ | ||||||
|  | 	load_addr = (ep - (fit_size + CSF_SIZE) - 512 - align_len) & | ||||||
|  | 		~align_len; | ||||||
|  | 
 | ||||||
|  | 	flash_header_v2_t ivt_header = { { 0xd1, 0x2000, 0x40 }, | ||||||
|  | 		load_addr, 0, 0, 0, | ||||||
|  | 		(load_addr + fit_size), | ||||||
|  | 		(load_addr + fit_size + 0x20), | ||||||
|  | 		0 }; | ||||||
|  | 
 | ||||||
|  | 	if (write(fd, &ivt_header, sizeof(flash_header_v2_t)) != | ||||||
|  | 	    sizeof(flash_header_v2_t)) { | ||||||
|  | 		fprintf(stderr, "IVT writing error on fit image\n"); | ||||||
|  | 		exit(EXIT_FAILURE); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	*fit_load_addr = load_addr; | ||||||
|  | 
 | ||||||
|  | 	return fit_offset + fit_size; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void dump_header_v2(imx_header_v3_t *imx_header, int index) | ||||||
|  | { | ||||||
|  | 	const char *ivt_name[2] = {"HDMI FW", "LOADER IMAGE"}; | ||||||
|  | 
 | ||||||
|  | 	fprintf(stdout, "========= IVT HEADER [%s] =========\n", | ||||||
|  | 		ivt_name[index]); | ||||||
|  | 	fprintf(stdout, "header.tag: \t\t0x%x\n", | ||||||
|  | 		imx_header[index].fhdr.header.tag); | ||||||
|  | 	fprintf(stdout, "header.length: \t\t0x%x\n", | ||||||
|  | 		imx_header[index].fhdr.header.length); | ||||||
|  | 	fprintf(stdout, "header.version: \t0x%x\n", | ||||||
|  | 		imx_header[index].fhdr.header.version); | ||||||
|  | 	fprintf(stdout, "entry: \t\t\t0x%x\n", | ||||||
|  | 		imx_header[index].fhdr.entry); | ||||||
|  | 	fprintf(stdout, "reserved1: \t\t0x%x\n", | ||||||
|  | 		imx_header[index].fhdr.reserved1); | ||||||
|  | 	fprintf(stdout, "dcd_ptr: \t\t0x%x\n", | ||||||
|  | 		imx_header[index].fhdr.dcd_ptr); | ||||||
|  | 	fprintf(stdout, "boot_data_ptr: \t\t0x%x\n", | ||||||
|  | 		imx_header[index].fhdr.boot_data_ptr); | ||||||
|  | 	fprintf(stdout, "self: \t\t\t0x%x\n", | ||||||
|  | 		imx_header[index].fhdr.self); | ||||||
|  | 	fprintf(stdout, "csf: \t\t\t0x%x\n", | ||||||
|  | 		imx_header[index].fhdr.csf); | ||||||
|  | 	fprintf(stdout, "reserved2: \t\t0x%x\n", | ||||||
|  | 		imx_header[index].fhdr.reserved2); | ||||||
|  | 
 | ||||||
|  | 	fprintf(stdout, "boot_data.start: \t0x%x\n", | ||||||
|  | 		imx_header[index].boot_data.start); | ||||||
|  | 	fprintf(stdout, "boot_data.size: \t0x%x\n", | ||||||
|  | 		imx_header[index].boot_data.size); | ||||||
|  | 	fprintf(stdout, "boot_data.plugin: \t0x%x\n", | ||||||
|  | 		imx_header[index].boot_data.plugin); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void build_image(int ofd) | ||||||
|  | { | ||||||
|  | 	int file_off, header_hdmi_off = 0, header_image_off; | ||||||
|  | 	int hdmi_fd, ap_fd, sld_fd; | ||||||
|  | 	uint32_t sld_load_addr = 0; | ||||||
|  | 	uint32_t csf_off, sld_csf_off = 0; | ||||||
|  | 	int ret; | ||||||
|  | 	struct stat sbuf; | ||||||
|  | 
 | ||||||
|  | 	if (!ap_img) { | ||||||
|  | 		fprintf(stderr, "No LOADER image specificed\n"); | ||||||
|  | 		exit(EXIT_FAILURE); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	file_off = 0; | ||||||
|  | 
 | ||||||
|  | 	if (signed_hdmi) { | ||||||
|  | 		header_hdmi_off = file_off + ivt_offset; | ||||||
|  | 
 | ||||||
|  | 		hdmi_fd = open(signed_hdmi, O_RDONLY | O_BINARY); | ||||||
|  | 		if (hdmi_fd < 0) { | ||||||
|  | 			fprintf(stderr, "%s: Can't open: %s\n", | ||||||
|  | 				signed_hdmi, strerror(errno)); | ||||||
|  | 			exit(EXIT_FAILURE); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (fstat(hdmi_fd, &sbuf) < 0) { | ||||||
|  | 			fprintf(stderr, "%s: Can't stat: %s\n", | ||||||
|  | 				signed_hdmi, strerror(errno)); | ||||||
|  | 			exit(EXIT_FAILURE); | ||||||
|  | 		} | ||||||
|  | 		close(hdmi_fd); | ||||||
|  | 
 | ||||||
|  | 		/*
 | ||||||
|  | 		 * Aligned to 104KB = 92KB FW image + 0x8000 | ||||||
|  | 		 * (IVT and alignment) + 0x4000 (second IVT + CSF) | ||||||
|  | 		 */ | ||||||
|  | 		file_off += ALIGN(sbuf.st_size, | ||||||
|  | 				  HDMI_FW_SIZE + 0x2000 + 0x1000); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	header_image_off = file_off + ivt_offset; | ||||||
|  | 
 | ||||||
|  | 	ap_fd = open(ap_img, O_RDONLY | O_BINARY); | ||||||
|  | 	if (ap_fd < 0) { | ||||||
|  | 		fprintf(stderr, "%s: Can't open: %s\n", | ||||||
|  | 			ap_img, strerror(errno)); | ||||||
|  | 		exit(EXIT_FAILURE); | ||||||
|  | 	} | ||||||
|  | 	if (fstat(ap_fd, &sbuf) < 0) { | ||||||
|  | 		fprintf(stderr, "%s: Can't stat: %s\n", | ||||||
|  | 			ap_img, strerror(errno)); | ||||||
|  | 		exit(EXIT_FAILURE); | ||||||
|  | 	} | ||||||
|  | 	close(ap_fd); | ||||||
|  | 
 | ||||||
|  | 	imx_header[IMAGE_IVT_ID].fhdr.header.tag = IVT_HEADER_TAG; /* 0xD1 */ | ||||||
|  | 	imx_header[IMAGE_IVT_ID].fhdr.header.length = | ||||||
|  | 		cpu_to_be16(sizeof(flash_header_v2_t)); | ||||||
|  | 	imx_header[IMAGE_IVT_ID].fhdr.header.version = IVT_VERSION_V3; /* 0x41 */ | ||||||
|  | 	imx_header[IMAGE_IVT_ID].fhdr.entry = ap_start_addr; | ||||||
|  | 	imx_header[IMAGE_IVT_ID].fhdr.self = ap_start_addr - | ||||||
|  | 		sizeof(imx_header_v3_t); | ||||||
|  | 	imx_header[IMAGE_IVT_ID].fhdr.dcd_ptr = 0; | ||||||
|  | 	imx_header[IMAGE_IVT_ID].fhdr.boot_data_ptr = | ||||||
|  | 		imx_header[IMAGE_IVT_ID].fhdr.self + | ||||||
|  | 		offsetof(imx_header_v3_t, boot_data); | ||||||
|  | 	imx_header[IMAGE_IVT_ID].boot_data.start = | ||||||
|  | 		imx_header[IMAGE_IVT_ID].fhdr.self - ivt_offset; | ||||||
|  | 	imx_header[IMAGE_IVT_ID].boot_data.size = | ||||||
|  | 		ALIGN(sbuf.st_size + sizeof(imx_header_v3_t) + ivt_offset, | ||||||
|  | 		      sector_size); | ||||||
|  | 
 | ||||||
|  | 	image_off = header_image_off + sizeof(imx_header_v3_t); | ||||||
|  | 	file_off +=  imx_header[IMAGE_IVT_ID].boot_data.size; | ||||||
|  | 
 | ||||||
|  | 	imx_header[IMAGE_IVT_ID].boot_data.plugin = 0; | ||||||
|  | 	imx_header[IMAGE_IVT_ID].fhdr.csf = | ||||||
|  | 		imx_header[IMAGE_IVT_ID].boot_data.start + | ||||||
|  | 		imx_header[IMAGE_IVT_ID].boot_data.size; | ||||||
|  | 
 | ||||||
|  | 	imx_header[IMAGE_IVT_ID].boot_data.size += CSF_SIZE; /* 8K region dummy CSF */ | ||||||
|  | 
 | ||||||
|  | 	csf_off = file_off; | ||||||
|  | 	file_off += CSF_SIZE; | ||||||
|  | 
 | ||||||
|  | 	/* Second boot loader image */ | ||||||
|  | 	if (sld_img) { | ||||||
|  | 		if (!using_fit) { | ||||||
|  | 			fprintf(stderr, "Not support no fit\n"); | ||||||
|  | 			exit(EXIT_FAILURE); | ||||||
|  | 		} else { | ||||||
|  | 			sld_header_off = sld_src_off - rom_image_offset; | ||||||
|  | 			/*
 | ||||||
|  | 			 * Record the second bootloader relative offset in | ||||||
|  | 			 * image's IVT reserved1 | ||||||
|  | 			 */ | ||||||
|  | 			imx_header[IMAGE_IVT_ID].fhdr.reserved1 = | ||||||
|  | 				sld_header_off - header_image_off; | ||||||
|  | 			sld_fd = open(sld_img, O_RDONLY | O_BINARY); | ||||||
|  | 			if (sld_fd < 0) { | ||||||
|  | 				fprintf(stderr, "%s: Can't open: %s\n", | ||||||
|  | 					sld_img, strerror(errno)); | ||||||
|  | 				exit(EXIT_FAILURE); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if (fstat(sld_fd, &sbuf) < 0) { | ||||||
|  | 				fprintf(stderr, "%s: Can't stat: %s\n", | ||||||
|  | 					sld_img, strerror(errno)); | ||||||
|  | 				exit(EXIT_FAILURE); | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			close(sld_fd); | ||||||
|  | 
 | ||||||
|  | 			file_off = sld_header_off; | ||||||
|  | 			file_off += sbuf.st_size + sizeof(image_header_t); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (signed_hdmi) { | ||||||
|  | 		header_hdmi_off -= ivt_offset; | ||||||
|  | 		ret = lseek(ofd, header_hdmi_off, SEEK_SET); | ||||||
|  | 		if (ret < 0) { | ||||||
|  | 			fprintf(stderr, "lseek ofd fail for hdmi\n"); | ||||||
|  | 			exit(EXIT_FAILURE); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		/* The signed HDMI FW has 0x400 IVT offset, need remove it */ | ||||||
|  | 		copy_file(ofd, signed_hdmi, 0, header_hdmi_off, 0x400); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* Main Image */ | ||||||
|  | 	header_image_off -= ivt_offset; | ||||||
|  | 	image_off -= ivt_offset; | ||||||
|  | 	ret = lseek(ofd, header_image_off, SEEK_SET); | ||||||
|  | 	if (ret < 0) { | ||||||
|  | 		fprintf(stderr, "lseek ofd fail\n"); | ||||||
|  | 		exit(EXIT_FAILURE); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* Write image header */ | ||||||
|  | 	if (write(ofd, &imx_header[IMAGE_IVT_ID], sizeof(imx_header_v3_t)) != | ||||||
|  | 	    sizeof(imx_header_v3_t)) { | ||||||
|  | 		fprintf(stderr, "error writing image hdr\n"); | ||||||
|  | 		exit(1); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	copy_file(ofd, ap_img, 0, image_off, 0); | ||||||
|  | 
 | ||||||
|  | 	csf_off -= ivt_offset; | ||||||
|  | 	fill_zero(ofd, CSF_SIZE, csf_off); | ||||||
|  | 
 | ||||||
|  | 	if (sld_img) { | ||||||
|  | 		sld_header_off -= ivt_offset; | ||||||
|  | 		ret = lseek(ofd, sld_header_off, SEEK_SET); | ||||||
|  | 		if (ret < 0) { | ||||||
|  | 			fprintf(stderr, "lseek ofd fail for sld_img\n"); | ||||||
|  | 			exit(EXIT_FAILURE); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		/* Write image header */ | ||||||
|  | 		if (!using_fit) { | ||||||
|  | 			/* TODO */ | ||||||
|  | 		} else { | ||||||
|  | 			copy_file(ofd, sld_img, 0, sld_header_off, 0); | ||||||
|  | 			sld_csf_off = | ||||||
|  | 				generate_ivt_for_fit(ofd, sld_header_off, | ||||||
|  | 						     sld_start_addr, | ||||||
|  | 						     &sld_load_addr) + 0x20; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (!signed_hdmi) | ||||||
|  | 		dump_header_v2(imx_header, 0); | ||||||
|  | 	dump_header_v2(imx_header, 1); | ||||||
|  | 
 | ||||||
|  | 	fprintf(stdout, "========= OFFSET dump ========="); | ||||||
|  | 	if (signed_hdmi) { | ||||||
|  | 		fprintf(stdout, "\nSIGNED HDMI FW:\n"); | ||||||
|  | 		fprintf(stdout, " header_hdmi_off \t0x%x\n", | ||||||
|  | 			header_hdmi_off); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	fprintf(stdout, "\nLoader IMAGE:\n"); | ||||||
|  | 	fprintf(stdout, " header_image_off \t0x%x\n image_off \t\t0x%x\n csf_off \t\t0x%x\n", | ||||||
|  | 		header_image_off, image_off, csf_off); | ||||||
|  | 	fprintf(stdout, " spl hab block: \t0x%x 0x%x 0x%x\n", | ||||||
|  | 		imx_header[IMAGE_IVT_ID].fhdr.self, header_image_off, | ||||||
|  | 		csf_off - header_image_off); | ||||||
|  | 
 | ||||||
|  | 	fprintf(stdout, "\nSecond Loader IMAGE:\n"); | ||||||
|  | 	fprintf(stdout, " sld_header_off \t0x%x\n", | ||||||
|  | 		sld_header_off); | ||||||
|  | 	fprintf(stdout, " sld_csf_off \t\t0x%x\n", | ||||||
|  | 		sld_csf_off); | ||||||
|  | 	fprintf(stdout, " sld hab block: \t0x%x 0x%x 0x%x\n", | ||||||
|  | 		sld_load_addr, sld_header_off, sld_csf_off - sld_header_off); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int imx8mimage_copy_image(int outfd, struct image_tool_params *mparams) | ||||||
|  | { | ||||||
|  | 	/*
 | ||||||
|  | 	 * SECO FW is a container image, this is to calculate the | ||||||
|  | 	 * 2nd container offset. | ||||||
|  | 	 */ | ||||||
|  | 	fprintf(stdout, "parsing %s\n", mparams->imagename); | ||||||
|  | 	parse_cfg_file(mparams->imagename); | ||||||
|  | 
 | ||||||
|  | 	build_image(outfd); | ||||||
|  | 
 | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * imx8mimage parameters | ||||||
|  |  */ | ||||||
|  | U_BOOT_IMAGE_TYPE( | ||||||
|  | 	imx8mimage, | ||||||
|  | 	"NXP i.MX8M Boot Image support", | ||||||
|  | 	0, | ||||||
|  | 	NULL, | ||||||
|  | 	imx8mimage_check_params, | ||||||
|  | 	NULL, | ||||||
|  | 	imx8mimage_print_header, | ||||||
|  | 	imx8mimage_set_header, | ||||||
|  | 	NULL, | ||||||
|  | 	imx8mimage_check_image_types, | ||||||
|  | 	NULL, | ||||||
|  | 	NULL | ||||||
|  | ); | ||||||
|  | @ -530,6 +530,13 @@ int main(int argc, char **argv) | ||||||
| 			ret = imx8image_copy_image(ifd, ¶ms); | 			ret = imx8image_copy_image(ifd, ¶ms); | ||||||
| 			if (ret) | 			if (ret) | ||||||
| 				return ret; | 				return ret; | ||||||
|  | 		} else if (params.type == IH_TYPE_IMX8MIMAGE) { | ||||||
|  | 			/* i.MX8M has special Image format */ | ||||||
|  | 			int ret; | ||||||
|  | 
 | ||||||
|  | 			ret = imx8mimage_copy_image(ifd, ¶ms); | ||||||
|  | 			if (ret) | ||||||
|  | 				return ret; | ||||||
| 		} else { | 		} else { | ||||||
| 			copy_file(ifd, params.datafile, pad_len); | 			copy_file(ifd, params.datafile, pad_len); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue