blob: ae26f88a21559f5738f4971accd1579d95591c88 [file] [log] [blame]
/*
* Copyright (C) 2016 Freescale Semiconductor, Inc.
*
* SPDX-License-Identifier: GPL-2.0+
* derived from u-boot's mkimage utility
*
*/
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <stddef.h>
#include <sys/stat.h>
#include <getopt.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#ifndef O_BINARY
#define O_BINARY 0
#endif
typedef struct {
uint32_t addr;
uint32_t value;
} dcd_addr_data_t;
typedef struct {
uint8_t tag;
uint16_t length;
uint8_t version;
} __attribute__((packed)) ivt_header_t;
typedef struct {
uint8_t tag;
uint16_t length;
uint8_t param;
} __attribute__((packed)) write_dcd_command_t;
#define MAX_NUM_IMGS 3
#define MAX_HW_CFG_SIZE_V2 359
struct dcd_v2_cmd {
write_dcd_command_t write_dcd_command; /*4*/
dcd_addr_data_t addr_data[MAX_HW_CFG_SIZE_V2]; /*2872*/
} __attribute__((packed));
typedef struct {
ivt_header_t header; /*4*/
struct dcd_v2_cmd dcd_cmd; /*2876*/
} __attribute__((packed)) dcd_v2_t; /*2880*/
typedef struct {
uint64_t src; /*8*/
uint64_t dst; /*8*/
uint64_t entry; /*8*/
uint32_t size; /*4*/
uint32_t flags; /*4*/
} __attribute__((packed)) boot_img_t;; /*32*/
#define CORE_SC 1
#define CORE_CM4_0 2
#define CORE_CM4_1 3
#define CORE_CA53 4
#define CORE_CA72 5
#define BOOT_IMG_FLAGS_CORE_MASK 0xF
#define BOOT_IMG_FLAGS_CPU_RID_MASK 0x3FF0
#define BOOT_IMG_FLAGS_CPU_RID_SHIFT 4
#define BOOT_IMG_FLAGS_MU_RID_MASK 0xFFC000
#define BOOT_IMG_FLAGS_MU_RID_SHIFT 14
#define BOOT_IMG_FLAGS_PARTITION_ID_MASK 0x1F000000
#define BOOT_IMG_FLAGS_PARTITION_ID_SHIFT 24
#define SC_R_A53_0 1
#define SC_R_A72_0 6
#define SC_R_MU_0A 213
#define SC_R_M4_0_PID0 278
#define SC_R_M4_0_MU_1A 297
#define SC_R_M4_1_PID0 298
#define SC_R_M4_1_MU_1A 317
#define PARTITION_ID_M4 0
#define PARTITION_ID_AP 1
typedef struct {
uint32_t num_images; /*4*/
uint32_t bd_size; /*4*/
uint32_t bd_flags; /*4*/
uint32_t reserved; /*4*/
boot_img_t img[MAX_NUM_IMGS]; /*96*/
uint32_t padding[4]; /* end up on an 8-byte boundary */
} __attribute__((packed)) boot_data_v3_t; /*128*/
typedef struct {
ivt_header_t header; /*4*/
uint32_t reserved1; /*4*/
uint64_t dcd_ptr; /*8*/
uint64_t boot_data_ptr; /*8*/
uint64_t self; /*8*/
uint64_t csf; /*8*/
uint64_t scd; /*8*/
uint64_t reserved2; /*8*/
uint64_t reserved3; /*8*/
} __attribute__((packed)) flash_header_v3_t; /*64*/
typedef struct {
flash_header_v3_t fhdr; /*64*/
boot_data_v3_t boot_data; /*128*/
dcd_v2_t dcd_table; /*2880*/
} __attribute__((packed)) imx_header_v3_t; /*3072*/
/* Command tags and parameters */
#define IVT_HEADER_TAG 0xD1
#define IVT_VERSION 0x43
#define DCD_HEADER_TAG 0xD2
#define DCD_VERSION 0x43
#define DCD_WRITE_DATA_COMMAND_TAG 0xCC
#define DCD_WRITE_DATA_PARAM 0x4
#define DCD_WRITE_CLR_BIT_PARAM 0xC
#define DCD_CHECK_DATA_COMMAND_TAG 0xCF
#define DCD_CHECK_BITS_SET_PARAM 0x14
#define DCD_CHECK_BITS_CLR_PARAM 0x04
#define ALIGN(x,a) __ALIGN_MASK((x),(__typeof__(x))(a)-1)
#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))
#define uswap_16(x) \
((((x) & 0xff00) >> 8) | \
(((x) & 0x00ff) << 8))
#define uswap_32(x) \
((((x) & 0xff000000) >> 24) | \
(((x) & 0x00ff0000) >> 8) | \
(((x) & 0x0000ff00) << 8) | \
(((x) & 0x000000ff) << 24))
#define _uswap_64(x, sfx) \
((((x) & 0xff00000000000000##sfx) >> 56) | \
(((x) & 0x00ff000000000000##sfx) >> 40) | \
(((x) & 0x0000ff0000000000##sfx) >> 24) | \
(((x) & 0x000000ff00000000##sfx) >> 8) | \
(((x) & 0x00000000ff000000##sfx) << 8) | \
(((x) & 0x0000000000ff0000##sfx) << 24) | \
(((x) & 0x000000000000ff00##sfx) << 40) | \
(((x) & 0x00000000000000ff##sfx) << 56))
#if defined(__GNUC__)
# define uswap_64(x) _uswap_64(x, ull)
#else
#error
# define uswap_64(x) _uswap_64(x, )
#endif
#if __BYTE_ORDER == __LITTLE_ENDIAN
# define cpu_to_le16(x) (x)
# define cpu_to_le32(x) (x)
# define cpu_to_le64(x) (x)
# define le16_to_cpu(x) (x)
# define le32_to_cpu(x) (x)
# define le64_to_cpu(x) (x)
# define cpu_to_be16(x) uswap_16(x)
# define cpu_to_be32(x) uswap_32(x)
# define cpu_to_be64(x) uswap_64(x)
# define be16_to_cpu(x) uswap_16(x)
# define be32_to_cpu(x) uswap_32(x)
# define be64_to_cpu(x) uswap_64(x)
#else
#error
# define cpu_to_le16(x) uswap_16(x)
# define cpu_to_le32(x) uswap_32(x)
# define cpu_to_le64(x) uswap_64(x)
# define le16_to_cpu(x) uswap_16(x)
# define le32_to_cpu(x) uswap_32(x)
# define le64_to_cpu(x) uswap_64(x)
# define cpu_to_be16(x) (x)
# define cpu_to_be32(x) (x)
# define cpu_to_be64(x) (x)
# define be16_to_cpu(x) (x)
# define be32_to_cpu(x) (x)
# define be64_to_cpu(x) (x)
#endif
#define UNDEFINED 0xFFFFFFFF
static void
copy_file (int ifd, const char *datafile, int pad, int offset)
{
int dfd;
struct stat sbuf;
unsigned char *ptr;
int tail;
int zero = 0;
uint8_t zeros[4096];
int size;
memset(zeros, 0, sizeof(zeros));
if ((dfd = open(datafile, O_RDONLY|O_BINARY)) < 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;
lseek(ifd, offset, SEEK_SET);
if (write(ifd, ptr, 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;
}
}
(void) munmap((void *)ptr, sbuf.st_size);
(void) close (dfd);
}
enum imximage_fld_types {
CFG_INVALID = -1,
CFG_COMMAND,
CFG_REG_SIZE,
CFG_REG_ADDRESS,
CFG_REG_VALUE
};
enum imximage_cmd {
CMD_INVALID,
CMD_IMAGE_VERSION,
CMD_BOOT_FROM,
CMD_BOOT_OFFSET,
CMD_WRITE_DATA,
CMD_WRITE_CLR_BIT,
CMD_CHECK_BITS_SET,
CMD_CHECK_BITS_CLR,
CMD_CSF,
CMD_PLUGIN,
};
typedef struct table_entry {
int id;
char *sname; /* short (input) name to find table entry */
char *lname; /* long (output) name to print for messages */
} table_entry_t;
/*
* Supported commands for configuration file
*/
static table_entry_t imximage_cmds[] = {
{CMD_BOOT_FROM, "BOOT_FROM", "boot command", },
{CMD_BOOT_OFFSET, "BOOT_OFFSET", "Boot offset", },
{CMD_WRITE_DATA, "DATA", "Reg Write Data", },
{CMD_WRITE_CLR_BIT, "CLR_BIT", "Reg clear bit", },
{CMD_CHECK_BITS_SET, "CHECK_BITS_SET", "Reg Check bits set", },
{CMD_CHECK_BITS_CLR, "CHECK_BITS_CLR", "Reg Check bits clr", },
{CMD_CSF, "CSF", "Command Sequence File", },
{CMD_IMAGE_VERSION, "IMAGE_VERSION", "image version", },
{-1, "", "", },
};
static uint32_t imximage_version;
static struct dcd_v2_cmd *gd_last_cmd;
static uint32_t imximage_ivt_offset = UNDEFINED;
static uint32_t imximage_csf_size = UNDEFINED;
int get_table_entry_id(const table_entry_t *table,
const char *table_name, const char *name)
{
const table_entry_t *t;
for (t = table; t->id >= 0; ++t) {
if (t->sname && strcasecmp(t->sname, name) == 0)
return (t->id);
}
return -1;
}
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;
}
static void set_imx_hdr_v3(imx_header_v3_t *imxhdr, uint32_t dcd_len,
uint32_t flash_offset)
{
flash_header_v3_t *fhdr_v3 = &imxhdr->fhdr;
uint32_t hdr_base = 0;
/* Set magic number */
fhdr_v3->header.tag = IVT_HEADER_TAG; /* 0xD1 */
fhdr_v3->header.length = cpu_to_be16(sizeof(flash_header_v3_t));
fhdr_v3->header.version = IVT_VERSION; /* 0x40 */
fhdr_v3->reserved1 = fhdr_v3->reserved2 = fhdr_v3->reserved3 = 0;
fhdr_v3->self = hdr_base;
if (dcd_len > 0)
fhdr_v3->dcd_ptr = hdr_base +
offsetof(imx_header_v3_t, dcd_table);
else
fhdr_v3->dcd_ptr = 0;
fhdr_v3->boot_data_ptr = hdr_base
+ offsetof(imx_header_v3_t, boot_data);
fhdr_v3->csf = 0;
}
static void set_dcd_param_v2(imx_header_v3_t *imxhdr, uint32_t dcd_len,
int32_t cmd)
{
dcd_v2_t *dcd_v2 = &imxhdr->dcd_table;
struct dcd_v2_cmd *d = gd_last_cmd;
struct dcd_v2_cmd *d2;
int len;
if (!d)
d = &dcd_v2->dcd_cmd;
d2 = d;
len = be16_to_cpu(d->write_dcd_command.length);
if (len > 4)
d2 = (struct dcd_v2_cmd *)(((char *)d) + len);
switch (cmd) {
case CMD_WRITE_DATA:
if ((d->write_dcd_command.tag == DCD_WRITE_DATA_COMMAND_TAG) &&
(d->write_dcd_command.param == DCD_WRITE_DATA_PARAM))
break;
d = d2;
d->write_dcd_command.tag = DCD_WRITE_DATA_COMMAND_TAG;
d->write_dcd_command.length = cpu_to_be16(4);
d->write_dcd_command.param = DCD_WRITE_DATA_PARAM;
break;
case CMD_WRITE_CLR_BIT:
if ((d->write_dcd_command.tag == DCD_WRITE_DATA_COMMAND_TAG) &&
(d->write_dcd_command.param == DCD_WRITE_CLR_BIT_PARAM))
break;
d = d2;
d->write_dcd_command.tag = DCD_WRITE_DATA_COMMAND_TAG;
d->write_dcd_command.length = cpu_to_be16(4);
d->write_dcd_command.param = DCD_WRITE_CLR_BIT_PARAM;
break;
/*
* Check data command only supports one entry,
*/
case CMD_CHECK_BITS_SET:
d = d2;
d->write_dcd_command.tag = DCD_CHECK_DATA_COMMAND_TAG;
d->write_dcd_command.length = cpu_to_be16(4);
d->write_dcd_command.param = DCD_CHECK_BITS_SET_PARAM;
break;
case CMD_CHECK_BITS_CLR:
d = d2;
d->write_dcd_command.tag = DCD_CHECK_DATA_COMMAND_TAG;
d->write_dcd_command.length = cpu_to_be16(4);
d->write_dcd_command.param = DCD_CHECK_BITS_CLR_PARAM;
break;
default:
break;
}
gd_last_cmd = d;
}
static void set_dcd_val_v2(imx_header_v3_t *imxhdr, char *name, int lineno,
int fld, uint32_t value, uint32_t off)
{
struct dcd_v2_cmd *d = gd_last_cmd;
int len;
len = be16_to_cpu(d->write_dcd_command.length);
off = (len - 4) >> 3;
switch (fld) {
case CFG_REG_ADDRESS:
d->addr_data[off].addr = cpu_to_be32(value);
break;
case CFG_REG_VALUE:
d->addr_data[off].value = cpu_to_be32(value);
off++;
d->write_dcd_command.length = cpu_to_be16((off << 3) + 4);
break;
default:
break;
}
}
static void set_dcd_rst_v2(imx_header_v3_t *imxhdr, uint32_t dcd_len,
char *name, int lineno)
{
dcd_v2_t *dcd_v2 = &imxhdr->dcd_table;
struct dcd_v2_cmd *d = gd_last_cmd;
int len;
if (!d)
d = &dcd_v2->dcd_cmd;
len = be16_to_cpu(d->write_dcd_command.length);
if (len > 4)
d = (struct dcd_v2_cmd *)(((char *)d) + len);
len = (char *)d - (char *)&dcd_v2->header;
dcd_v2->header.tag = DCD_HEADER_TAG;
dcd_v2->header.length = cpu_to_be16(len);
dcd_v2->header.version = DCD_VERSION;
}
static void parse_cfg_cmd(imx_header_v3_t *imxhdr, int32_t cmd, char *token,
char *name, int lineno, int fld, int dcd_len)
{
int value;
static int cmd_ver_first = ~0;
switch (cmd) {
case CMD_IMAGE_VERSION:
imximage_version = get_cfg_value(token, name, lineno);
if (cmd_ver_first == 0) {
fprintf(stderr, "Error: %s[%d] - IMAGE_VERSION "
"command need be the first before other "
"valid command in the file\n", name, lineno);
exit(EXIT_FAILURE);
}
cmd_ver_first = 1;
break;
case CMD_BOOT_OFFSET:
imximage_ivt_offset = get_cfg_value(token, name, lineno);
if (cmd_ver_first != 1)
cmd_ver_first = 0;
break;
case CMD_WRITE_DATA:
case CMD_WRITE_CLR_BIT:
case CMD_CHECK_BITS_SET:
case CMD_CHECK_BITS_CLR:
value = get_cfg_value(token, name, lineno);
set_dcd_param_v2(imxhdr, dcd_len, cmd);
set_dcd_val_v2(imxhdr, name, lineno, fld, value, dcd_len);
if (cmd_ver_first != 1)
cmd_ver_first = 0;
break;
case CMD_CSF:
if (imximage_version != 2) {
fprintf(stderr,
"Error: %s[%d] - CSF only supported for VERSION 2(%s)\n",
name, lineno, token);
exit(EXIT_FAILURE);
}
imximage_csf_size = get_cfg_value(token, name, lineno);
if (cmd_ver_first != 1)
cmd_ver_first = 0;
break;
}
}
static void parse_cfg_fld(imx_header_v3_t *imxhdr, int32_t *cmd,
char *token, char *name, int lineno, int fld, int *dcd_len)
{
int value;
switch (fld) {
case CFG_COMMAND:
*cmd = get_table_entry_id(imximage_cmds,
"imximage 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(imxhdr, *cmd, token, name, lineno, fld, *dcd_len);
break;
case CFG_REG_ADDRESS:
case CFG_REG_VALUE:
switch(*cmd) {
case CMD_WRITE_DATA:
case CMD_WRITE_CLR_BIT:
case CMD_CHECK_BITS_SET:
case CMD_CHECK_BITS_CLR:
value = get_cfg_value(token, name, lineno);
set_dcd_param_v2(imxhdr, *dcd_len, *cmd);
set_dcd_val_v2(imxhdr, name, lineno, fld, value,
*dcd_len);
if (fld == CFG_REG_VALUE) {
(*dcd_len)++;
if (*dcd_len > MAX_HW_CFG_SIZE_V2) {
fprintf(stderr, "Error: %s[%d] -"
"DCD table exceeds maximum size(%d)\n",
name, lineno, MAX_HW_CFG_SIZE_V2);
exit(EXIT_FAILURE);
}
}
break;
default:
break;
}
break;
default:
break;
}
}
static uint32_t parse_cfg_file(imx_header_v3_t *imxhdr, char *name)
{
FILE *fd = NULL;
char *line = NULL;
char *token, *saveptr1, *saveptr2;
int lineno = 0;
int fld;
size_t len;
int dcd_len = 0;
int32_t cmd;
fd = fopen(name, "r");
if (fd == 0) {
fprintf(stderr, "Error: %s - Can't open DCD 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 == NULL)
continue;
/* Check inside the single line */
for (fld = CFG_COMMAND, cmd = CMD_INVALID,
line = token; ; line = NULL, fld++) {
token = strtok_r(line, " \t", &saveptr2);
if (token == NULL)
break;
/* Drop all text starting with '#' as comments */
if (token[0] == '#')
break;
parse_cfg_fld(imxhdr, &cmd, token, name,
lineno, fld, &dcd_len);
}
}
set_dcd_rst_v2(imxhdr, dcd_len, name, lineno);
fclose(fd);
/* Exit if there is no BOOT_FROM field specifying the flash_offset */
if (imximage_ivt_offset == UNDEFINED) {
fprintf(stderr, "Error: No BOOT_FROM tag in %s\n", name);
exit(EXIT_FAILURE);
}
return dcd_len;
}
int main(int argc, char **argv)
{
int c, scfw_file_size, cm4_file_size = 0, scfw_fd = -1, cm4_fd = -1, ap_fd = -1, ofd = -1;
unsigned int dcd_len = 0, cm4_core = 0, cm4_start_addr = 0, ap_start_addr = 0, ap_core = 0;
char *ofname=NULL, *scfw_img = NULL, *dcd_img = NULL, *cm4_img = NULL, *ap_img = NULL;
uint32_t flags = 0;
static imx_header_v3_t imx_header;
struct stat sbuf;
static struct option long_options[] =
{
{"scfw", required_argument, NULL, 's'},
{"m4", required_argument, NULL, 'm'},
{"ap", required_argument, NULL, 'a'},
{"dcd", required_argument, NULL, 'd'},
{"out", required_argument, NULL, 'o'},
{"flags", required_argument, NULL, 'f'},
{NULL, 0, NULL, 0}
};
//fprintf(stderr, "imx_header_v3_t size %lu boot_data_v3_t = %lu flash_header_v3_t = %lu\n",
// sizeof(imx_header_v3_t), sizeof(boot_data_v3_t), sizeof(flash_header_v3_t));
while(1)
{
/* getopt_long stores the option index here. */
int option_index = 0;
c = getopt_long_only (argc, argv, ":s:d:m:a:o:f:",
long_options, &option_index);
/* Detect the end of the options. */
if (c == -1)
break;
switch (c)
{
case 0:
fprintf(stderr, "option %s", long_options[option_index].name);
if (optarg)
fprintf(stderr, " with arg %s", optarg);
fprintf(stderr, "\n");
break;
case 's':
fprintf(stderr, "SCFW:\t%s\n", optarg);
scfw_img = optarg;
break;
case 'd':
fprintf(stderr, "DCD:\t%s\n", optarg);
dcd_img = optarg;
break;
case 'm':
fprintf(stderr, "CM4:\t%s", optarg);
cm4_img = optarg;
if ((optind < argc && *argv[optind] != '-') && (optind+1 < argc &&*argv[optind+1] != '-' )) {
cm4_core = strtol(argv[optind++], NULL, 0);
cm4_start_addr = (uint32_t) strtoll(argv[optind++], NULL, 0);
fprintf(stderr, "\tcore: %d", cm4_core);
fprintf(stderr, " addr: 0x%08x\n", cm4_start_addr);
} else {
fprintf(stderr, "\n-m4 option require THREE arguments: filename, core: 0/1, start address in hex\n\n");
exit(1);
}
break;
case 'a':
fprintf(stderr, "AP:\t%s", optarg);
ap_img = optarg;
if ((optind < argc && *argv[optind] != '-') && (optind+1 < argc &&*argv[optind+1] != '-' )) {
if(!strncmp(argv[optind++], "a53", 3))
ap_core = CORE_CA53;
else
ap_core = CORE_CA72;
ap_start_addr = (uint32_t) strtoll(argv[optind++], NULL, 0);
fprintf(stderr, "\tcore: %s", (ap_core == CORE_CA53)? "a53":"a72");
fprintf(stderr, " addr: 0x%08x\n", ap_start_addr);
} else {
fprintf(stderr, "\n-ap option require THREE arguments: filename, a53/a72, start address in hex\n\n");
exit(1);
}
break;
case 'f':
fprintf(stderr, "FLAG:\t%s\n", optarg);
flags = (uint32_t) strtoll(optarg, NULL, 0);
break;
case 'o':
fprintf(stderr, "Output:\t%s\n", optarg);
ofname = optarg;
break;
case ':':
fprintf(stderr, "option %c missing arguments\n", optopt);
break;
case '?':
default:
/* invalid option */
fprintf(stderr, "option '%c' is invalid: ignored\n",
optopt);
exit(1);
}
}
if((scfw_img == NULL) || (ofname == NULL))
{
fprintf(stderr, "mandatory args scfw and output file name missing! abort\n");
exit(1);
}
scfw_fd = open(scfw_img, O_RDONLY | O_BINARY);
if (scfw_fd < 0) {
fprintf(stderr, "%s: Can't open: %s\n",
scfw_img, strerror(errno));
exit(EXIT_FAILURE);
}
if (fstat(scfw_fd, &sbuf) < 0) {
fprintf(stderr, "%s: Can't stat: %s\n",
scfw_img, strerror(errno));
exit(EXIT_FAILURE);
}
close(scfw_fd);
if(dcd_img) {
dcd_len = parse_cfg_file(&imx_header, dcd_img);
fprintf(stderr, "dcd len = %d\n", dcd_len);
}
set_imx_hdr_v3(&imx_header, dcd_len, 0);
scfw_file_size = sbuf.st_size;
fprintf(stderr, "scfw size = %d\n", scfw_file_size);
imx_header.boot_data.img[0].src = ALIGN(sizeof(imx_header_v3_t), 512);
imx_header.boot_data.img[0].dst = 0x30fe0000;
imx_header.boot_data.img[0].entry = 0x1ffe0000;
imx_header.boot_data.img[0].size = scfw_file_size;
imx_header.boot_data.img[0].flags = 0;
imx_header.boot_data.img[0].flags = (CORE_SC & BOOT_IMG_FLAGS_CORE_MASK);
imx_header.boot_data.num_images++;
imx_header.boot_data.bd_size = sizeof(boot_data_v3_t);
imx_header.boot_data.bd_flags = flags;
if(cm4_img) {
cm4_fd = open(cm4_img, O_RDONLY | O_BINARY);
if (cm4_fd < 0) {
fprintf(stderr, "%s: Can't open: %s\n",
cm4_img, strerror(errno));
exit(EXIT_FAILURE);
}
if (fstat(cm4_fd, &sbuf) < 0) {
fprintf(stderr, "%s: Can't stat: %s\n",
cm4_img, strerror(errno));
exit(EXIT_FAILURE);
}
close(cm4_fd);
cm4_file_size = sbuf.st_size;
//fprintf(stderr, "cm4 size = %d\n", (int)sbuf.st_size);
imx_header.boot_data.img[1].src = imx_header.boot_data.img[0].src + ALIGN(scfw_file_size, 512);
imx_header.boot_data.img[1].dst = cm4_start_addr;
imx_header.boot_data.img[1].entry = cm4_start_addr;
imx_header.boot_data.img[1].size = sbuf.st_size;
imx_header.boot_data.num_images++;
if(cm4_core == 0) {
if(cm4_start_addr == 0x38fe0000) {
fprintf(stderr, "! Invalid CM4_0 start address\n");
exit(EXIT_FAILURE);
}
imx_header.boot_data.img[1].flags = (CORE_CM4_0 & BOOT_IMG_FLAGS_CORE_MASK);
imx_header.boot_data.img[1].flags |= (SC_R_M4_0_PID0 << BOOT_IMG_FLAGS_CPU_RID_SHIFT);
imx_header.boot_data.img[1].flags |= (SC_R_M4_0_MU_1A << BOOT_IMG_FLAGS_MU_RID_SHIFT);
imx_header.boot_data.img[1].flags |= (PARTITION_ID_M4 << BOOT_IMG_FLAGS_PARTITION_ID_SHIFT);
}
else {
if(cm4_start_addr == 0x34fe0000) {
fprintf(stderr, "! Invalid CM4_1 start address\n");
exit(EXIT_FAILURE);
}
imx_header.boot_data.img[1].flags = (CORE_CM4_1 & BOOT_IMG_FLAGS_CORE_MASK);
imx_header.boot_data.img[1].flags |= (SC_R_M4_1_PID0 << BOOT_IMG_FLAGS_CPU_RID_SHIFT);
imx_header.boot_data.img[1].flags |= (SC_R_M4_1_MU_1A << BOOT_IMG_FLAGS_MU_RID_SHIFT);
imx_header.boot_data.img[1].flags |= (PARTITION_ID_M4 << BOOT_IMG_FLAGS_PARTITION_ID_SHIFT);
}
}
if((ap_core == CORE_CA72) || (ap_core == CORE_CA53))
{
//printf("Note: Ignoring CM4_0 and CA53 images\n");
//printf("Special case for DDR stress test tool\n");
if(strncmp(ap_img, "null", 4)) {
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.boot_data.img[2].src = imx_header.boot_data.img[0].src + ALIGN(scfw_file_size, 512) + ALIGN(cm4_file_size, 512);
imx_header.boot_data.img[2].dst = ap_start_addr;
imx_header.boot_data.img[2].size = sbuf.st_size;
imx_header.boot_data.img[2].entry = ap_start_addr;
imx_header.boot_data.num_images++;
//fprintf(stderr, "ap img size = %d\n", (int)sbuf.st_size);
}
else {
imx_header.boot_data.img[2].src = 0;
imx_header.boot_data.img[2].dst = 0;
imx_header.boot_data.img[2].size = 0;
imx_header.boot_data.img[2].entry = 0;
}
imx_header.boot_data.img[2].flags = (ap_core & BOOT_IMG_FLAGS_CORE_MASK);
if (ap_core == CORE_CA53)
imx_header.boot_data.img[2].flags |= (SC_R_A53_0 << BOOT_IMG_FLAGS_CPU_RID_SHIFT);
else
imx_header.boot_data.img[2].flags |= (SC_R_A72_0 << BOOT_IMG_FLAGS_CPU_RID_SHIFT);
imx_header.boot_data.img[2].flags |= (SC_R_MU_0A << BOOT_IMG_FLAGS_MU_RID_SHIFT);
imx_header.boot_data.img[2].flags |= (PARTITION_ID_AP << BOOT_IMG_FLAGS_PARTITION_ID_SHIFT);
}
/* Open output file */
ofd = open (ofname, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0666);
if (ofd < 0) {
fprintf(stderr, "%s: Can't open: %s\n",
ofname, strerror(errno));
exit(EXIT_FAILURE);
}
/* Write image header */
if (write(ofd, &imx_header, sizeof(imx_header_v3_t)) != sizeof(imx_header_v3_t)) {
fprintf(stderr, "error writing image hdr\n");
exit(1);
}
/* Write SCFW after header */
copy_file(ofd, scfw_img, 0, imx_header.boot_data.img[0].src);
/* Write CM4 image after SCFW */
if(cm4_img) {
copy_file(ofd, cm4_img, 0, imx_header.boot_data.img[1].src);
}
/* Write AP image (if present) after CM4 */
if(ap_img && strncmp(ap_img, "null", 4)) {
copy_file(ofd, ap_img, 0, imx_header.boot_data.img[2].src);
}
/* Close output file */
close(ofd);
fprintf(stderr, "done.\n");
return 0;
}