summaryrefslogtreecommitdiffstats
path: root/scripts/imx/imx-image.c
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/imx/imx-image.c')
-rw-r--r--scripts/imx/imx-image.c248
1 files changed, 185 insertions, 63 deletions
diff --git a/scripts/imx/imx-image.c b/scripts/imx/imx-image.c
index b97f561897..9ba60dbc5b 100644
--- a/scripts/imx/imx-image.c
+++ b/scripts/imx/imx-image.c
@@ -15,14 +15,18 @@
#include <linux/kernel.h>
#include <sys/file.h>
#include "../compiler.h"
+#include "../common.h"
#include "imx.h"
#include <include/filetype.h>
+#include <include/linux/sizes.h>
#define FLASH_HEADER_OFFSET 0x400
#define ARM_HEAD_SIZE_INDEX (ARM_HEAD_SIZE_OFFSET / sizeof(uint32_t))
+#include "../common.c"
+
/*
* Conservative DCD element limit set to restriction v2 header size to
* HEADER_SIZE
@@ -31,7 +35,7 @@
static uint32_t dcdtable[MAX_DCD];
static int curdcd;
-static int create_usb_image;
+static bool create_usb_image;
static char *prgname;
/*
@@ -292,11 +296,12 @@ static int write_mem_v1(uint32_t addr, uint32_t val, int width, int set_bits, in
* ============================================================================
*/
-static size_t add_header_v2(const struct config_data *data, void *buf)
+static size_t
+add_header_v2(const struct config_data *data, void *buf, uint32_t offset,
+ size_t header_len, unsigned int csf_slot)
{
struct imx_flash_header_v2 *hdr;
int dcdsize = curdcd * sizeof(uint32_t);
- int offset = data->image_ivt_offset;
uint32_t loadaddr = data->image_load_addr;
uint32_t imagesize = data->load_size;
@@ -305,7 +310,7 @@ static size_t add_header_v2(const struct config_data *data, void *buf)
* Restrict the imagesize to the PBL if given.
* Also take the alignment for CSF into account.
*/
- imagesize = roundup(data->pbl_code_size + HEADER_LEN, 0x4);
+ imagesize = roundup(data->pbl_code_size + header_len, 0x4);
if (data->csf)
imagesize = roundup(imagesize, 0x1000);
}
@@ -317,7 +322,11 @@ static size_t add_header_v2(const struct config_data *data, void *buf)
hdr->header.length = htobe16(32);
hdr->header.version = IVT_VERSION;
- hdr->entry = loadaddr + HEADER_LEN;
+ /* IMX_CPU_IMX8MQ is a special case with fixed offset */
+ if (data->cpu_type == IMX_CPU_IMX8MQ)
+ hdr->entry = loadaddr + HEADER_LEN;
+ else
+ hdr->entry = loadaddr + header_len;
if (dcdsize)
hdr->dcd_ptr = loadaddr + offset + offsetof(struct imx_flash_header_v2, dcd_header);
if (create_usb_image) {
@@ -336,8 +345,10 @@ static size_t add_header_v2(const struct config_data *data, void *buf)
hdr->boot_data.size = imagesize;
if (data->sign_image) {
- hdr->csf = loadaddr + imagesize;
+ hdr->csf = loadaddr + imagesize + (csf_slot * CSF_LEN);
hdr->boot_data.size += CSF_LEN;
+ if (data->flexspi_csf)
+ hdr->boot_data.size += CSF_LEN;
} else if (data->pbl_code_size && data->csf) {
/*
* For i.MX8 the CSF space is added via the linker script, so
@@ -345,6 +356,8 @@ static size_t add_header_v2(const struct config_data *data, void *buf)
* signing is not.
*/
hdr->boot_data.size += CSF_LEN;
+ if (data->flexspi_csf)
+ hdr->boot_data.size += CSF_LEN;
}
buf += sizeof(*hdr);
@@ -359,6 +372,112 @@ static size_t add_header_v2(const struct config_data *data, void *buf)
return imagesize;
}
+#define LUT_PAD_1 0
+#define LUT_PAD_2 1
+#define LUT_PAD_4 2
+#define LUT_PAD_8 3
+
+static size_t add_flexspi_fcfb_header(const struct config_data *data, void *buf)
+{
+ uint32_t fcfb_offset = data->image_flexspi_fcfb_offset;
+ const struct imx_fcfb_nor nor_conf = {
+ .memcfg = {
+ .tag = htobe32(FCFB_HEAD_TAG),
+ .version = htole32(FCFB_VERSION),
+ .read_sample = FCFB_SAMLPE_CLK_SRC_INTERNAL,
+ /* flash CS hold time, recommended by RM */
+ .datahold = 0x03,
+ /* flash CS setup time, recommended by RM */
+ .datasetup = 0x03,
+ /* 3 - Hyperflash, 12/13 serial NAND, 0 - other */
+ .coladdrwidth = 0,
+ .devcfgenable = 0,
+ .cmd_enable = 0,
+ .controllermisc = 0,
+ .dev_type = FCFB_DEVTYPE_SERIAL_NOR,
+ .sflash_pad = FCFB_SFLASH_PADS_SINGLE,
+ .serial_clk = FCFB_SERIAL_CLK_FREQ_50MHZ,
+ .sflashA1 = htole32(SZ_256M),
+ .lut.seq[0] = {
+ .instr = {
+ htole16(LUT_DEF(LUT_CMD, LUT_PAD_1, 0x0b)),
+ htole16(LUT_DEF(LUT_ADDR, LUT_PAD_1, 24)),
+ htole16(LUT_DEF(LUT_DUMMY, LUT_PAD_1, 8)),
+ htole16(LUT_DEF(LUT_NXP_READ, LUT_PAD_1, 4)),
+ htole16(LUT_DEF(LUT_STOP, LUT_PAD_1, 0)),
+ },
+ },
+ },
+ };
+
+ buf += fcfb_offset;
+ memcpy(buf, &nor_conf, sizeof(nor_conf));
+
+ return sizeof(nor_conf);
+}
+
+static size_t
+add_flexspi_header(const struct config_data *data, void **_buf, size_t *header_len)
+{
+ uint32_t ivt_offset = data->image_flexspi_ivt_offset;
+ size_t size;
+ size_t len;
+ void *buf;
+
+ if (!flexspi_image(data))
+ return 0;
+
+ if (data->signed_hdmi_firmware_file) {
+ free(*_buf);
+ fprintf(stderr, "Signed HDMI firmware and FlexSPI compatible image is not supported!\n");
+ exit(1);
+ }
+
+ /*
+ * Extend the header to be able to build build one image which can be
+ * used for: USB/SD/eMMC/eMMC-Boot/QSPI/barebox-chainload.
+ */
+ buf = realloc(*_buf, *header_len + FLEXSPI_HEADER_LEN);
+ if (!buf)
+ exit(1);
+
+ *_buf = buf;
+
+ size = add_flexspi_fcfb_header(data, buf);
+
+ /*
+ * The following table list the offsets we need to ensure for
+ * the one image approach.
+ *
+ * | i.MX8MM | i.MX8MN/P |
+ * -----------------------------+---------+-----------+
+ * SD/eMMC primary image offset | 0 | 0/32K |
+ * FlexSPI primary image offset | 0 | 4K |
+ * SD/eMMC-IVT offset | 1K | 0 |
+ * SD/eMMC-IVT image entry | 8K | 8K |
+ * FlexSPI-IVT offset | 4K | 0 |
+ * FlexSPI-IVT image entry | 8K | 4K |
+ *
+ * According the above table the rom-loader for i.MX8MM will
+ * search for the image on the same place (8K). On the other
+ * hand the rom-loader for the i.MX8MN/P will look for it at
+ * 8K for SD/eMMC case or at 4K for FlexSPI case.
+ */
+ len = *header_len;
+ if (data->cpu_type == IMX_CPU_IMX8MM)
+ len += FLEXSPI_HEADER_LEN;
+
+ if (data->cpu_type == IMX_CPU_IMX8MP ||
+ data->cpu_type == IMX_CPU_IMX8MN)
+ buf += SZ_4K;
+
+ size += add_header_v2(data, buf, ivt_offset, len, 1);
+
+ *header_len += FLEXSPI_HEADER_LEN;
+
+ return size;
+}
+
static void usage(const char *prgname)
{
fprintf(stderr, "usage: %s [OPTIONS]\n\n"
@@ -549,12 +668,13 @@ static int nop(const struct config_data *data)
* The cst is expected to be executable as 'cst' or if exists, the content
* of the environment variable 'CST' is used.
*/
-static int hab_sign(struct config_data *data)
+static int hab_sign(struct config_data *data, const char *csfcmds,
+ unsigned int csf_slot)
{
int fd, outfd, ret, lockfd;
char *csffile, *command;
struct stat s;
- char *cst;
+ char *cst, *cstopts;
void *buf;
size_t csf_space = CSF_LEN;
unsigned int offset = 0;
@@ -563,7 +683,11 @@ static int hab_sign(struct config_data *data)
if (!cst)
cst = "cst";
- ret = asprintf(&csffile, "%s.csfbin", data->outfile);
+ cstopts = getenv("CST_EXTRA_CMDLINE_OPTIONS");
+ if (!cstopts)
+ cstopts = "";
+
+ ret = asprintf(&csffile, "%s.slot%u.csfbin", data->outfile, csf_slot);
if (ret < 0)
exit(1);
@@ -600,11 +724,11 @@ static int hab_sign(struct config_data *data)
if (ret == -1)
return -EINVAL;
else if (ret == 0)
- ret = asprintf(&command, "%s -o %s -i /dev/stdin",
- cst, csffile);
+ ret = asprintf(&command, "%s -o %s -i /dev/stdin %s",
+ cst, csffile, cstopts);
else
- ret = asprintf(&command, "%s -o %s;",
- cst, csffile);
+ ret = asprintf(&command, "%s -o %s %s;",
+ cst, csffile, cstopts);
if (ret < 0)
return -ENOMEM;
@@ -632,7 +756,7 @@ static int hab_sign(struct config_data *data)
return -errno;
}
- fwrite(data->csf, 1, strlen(data->csf) + 1, f);
+ fwrite(csfcmds, 1, strlen(csfcmds) + 1, f);
pclose(f);
@@ -680,6 +804,8 @@ static int hab_sign(struct config_data *data)
xread(fd, buf, s.st_size);
+ close(fd);
+
/*
* For i.MX8M, write into the reserved CSF section
*/
@@ -699,8 +825,13 @@ static int hab_sign(struct config_data *data)
* For i.MX8 insert the CSF data into the reserved CSF area
* right behind the PBL
*/
- offset = roundup(data->header_gap + data->pbl_code_size +
- HEADER_LEN, 0x1000);
+ offset = data->header_gap + data->pbl_code_size + HEADER_LEN;
+ if (flexspi_image(data))
+ offset += FLEXSPI_HEADER_LEN;
+
+ offset += csf_slot * CSF_LEN;
+
+ offset = roundup(offset, 0x1000);
if (data->signed_hdmi_firmware_file)
offset += PLUGIN_HDMI_SIZE;
@@ -721,38 +852,6 @@ static int hab_sign(struct config_data *data)
return 0;
}
-static void *xread_file(const char *filename, size_t *size)
-{
- int fd, ret;
- void *buf;
- struct stat s;
-
- fd = open(filename, O_RDONLY);
- if (fd < 0) {
- fprintf(stderr, "Cannot open %s: %s\n", filename, strerror(errno));
- exit(1);
- }
-
- ret = fstat(fd, &s);
- if (ret) {
- fprintf(stderr, "Cannot stat %s: %s\n", filename, strerror(errno));
- exit(1);
- }
-
- *size = s.st_size;
- buf = malloc(*size);
- if (!buf) {
- perror("malloc");
- exit(1);
- }
-
- xread(fd, buf, *size);
-
- close(fd);
-
- return buf;
-}
-
static bool cpu_is_aarch64(const struct config_data *data)
{
return cpu_is_mx8m(data);
@@ -768,9 +867,9 @@ int main(int argc, char *argv[])
void *infile;
struct stat s;
int outfd;
- int dcd_only = 0;
+ bool dcd_only = false;
int now = 0;
- int add_barebox_header = 0;
+ bool add_barebox_header = false;
uint32_t barebox_image_size = 0;
struct config_data data = {
.image_ivt_offset = 0xffffffff,
@@ -800,16 +899,16 @@ int main(int argc, char *argv[])
data.pbl_code_size = strtoul(optarg, NULL, 0);
break;
case 'b':
- add_barebox_header = 1;
+ add_barebox_header = true;
break;
case 'd':
- dcd_only = 1;
+ dcd_only = true;
break;
case 's':
data.sign_image = 1;
break;
case 'u':
- create_usb_image = 1;
+ create_usb_image = true;
break;
case 'e':
data.encrypt_image = 1;
@@ -914,14 +1013,17 @@ int main(int argc, char *argv[])
if (data.signed_hdmi_firmware_file) {
free(buf);
- buf = xread_file(data.signed_hdmi_firmware_file,
+ buf = read_file(data.signed_hdmi_firmware_file,
&signed_hdmi_firmware_size);
+ if (!buf)
+ exit(1);
signed_hdmi_firmware_size =
roundup(signed_hdmi_firmware_size,
PLUGIN_HDMI_SIZE);
header_len += signed_hdmi_firmware_size;
+
barebox_image_size += signed_hdmi_firmware_size;
buf = realloc(buf, header_len);
@@ -931,8 +1033,10 @@ int main(int argc, char *argv[])
}
}
+ barebox_image_size += add_flexspi_header(&data, &buf, &header_len);
barebox_image_size += add_header_v2(&data, buf +
- signed_hdmi_firmware_size);
+ signed_hdmi_firmware_size,
+ data.image_ivt_offset, header_len, 0);
break;
default:
fprintf(stderr, "Congratulations! You're welcome to implement header version %d\n",
@@ -957,7 +1061,9 @@ int main(int argc, char *argv[])
bb_header[0] = data.first_opcode;
bb_header[ARM_HEAD_SIZE_INDEX] = barebox_image_size;
- infile = xread_file(imagename, &insize);
+ infile = read_file(imagename, &insize);
+ if (!infile)
+ exit(1);
outfd = open(data.outfile, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (outfd < 0) {
@@ -1001,12 +1107,21 @@ int main(int argc, char *argv[])
xwrite(outfd, infile, insize);
- /* pad until next 4k boundary */
- now = 4096 - (insize % 4096);
- if (data.csf && now) {
- memset(buf, 0x5a, now);
+ /*
+ * The alignment may be required on ARMv7 SoCs like i.MX6/7 for HAB
+ * boot. On newer SoCs like i.MX8MP/N this cause libusb communication
+ * errors while uploading images because these machines request the
+ * exact amount of required bytes and move on afterwards while the host
+ * tool still try to send the whole (padded) file size.
+ */
+ if (!cpu_is_mx8m(&data)) {
+ /* pad until next 4k boundary */
+ now = 4096 - (insize % 4096);
+ if (data.csf && now) {
+ memset(buf, 0x5a, now);
- xwrite(outfd, buf, now);
+ xwrite(outfd, buf, now);
+ }
}
ret = close(outfd);
@@ -1016,15 +1131,22 @@ int main(int argc, char *argv[])
}
if (data.csf && data.sign_image) {
- ret = hab_sign(&data);
+ ret = hab_sign(&data, data.csf, 0);
if (ret)
exit(1);
+ if (data.flexspi_csf) {
+ ret = hab_sign(&data, data.flexspi_csf, 1);
+ if (ret)
+ exit(1);
+ }
}
if (create_usb_image) {
uint32_t *dcd;
- infile = xread_file(data.outfile, &insize);
+ infile = read_file(data.outfile, &insize);
+ if (!infile)
+ exit(1);
dcd = infile + dcd_ptr_offset;
*dcd = dcd_ptr_content;