summaryrefslogtreecommitdiff
path: root/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
diff options
context:
space:
mode:
authorPatrick Delaunay <patrick.delaunay@st.com>2020-03-18 09:24:56 +0100
committerPatrick Delaunay <patrick.delaunay@st.com>2020-05-14 09:02:12 +0200
commitb83caf9fcb6c4cf0556004480e8fbfab7c88c6eb (patch)
tree9e9bf9451eaad7a62f6e0e8d8d0b02715e4cbfb5 /arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
parent8f035f7b48f79460d296824b37b69dd5cc0b9567 (diff)
stm32mp: stm32prog: add support of ssbl copy
For reliability of boot from NAND/SPI-NAND (with read-disturb issue) the SSBL can be present several time, when it is indicated in the flashlayout with "Binary(X)". The received binary is copied X times by U-Boot on the target. Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com> Reviewed-by: Patrice Chotard <patrice.chotard@st.com>
Diffstat (limited to 'arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c')
-rw-r--r--arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c98
1 files changed, 93 insertions, 5 deletions
diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
index 0140fd479d..3e521d42f2 100644
--- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
@@ -210,9 +210,24 @@ static int parse_type(struct stm32prog_data *data,
int i, char *p, struct stm32prog_part_t *part)
{
int result = 0;
+ int len = 0;
- if (!strcmp(p, "Binary")) {
+ part->bin_nb = 0;
+ if (!strncmp(p, "Binary", 6)) {
part->part_type = PART_BINARY;
+
+ /* search for Binary(X) case */
+ len = strlen(p);
+ part->bin_nb = 1;
+ if (len > 6) {
+ if (len < 8 ||
+ (p[6] != '(') ||
+ (p[len - 1] != ')'))
+ result = -EINVAL;
+ else
+ part->bin_nb =
+ simple_strtoul(&p[7], NULL, 10);
+ }
} else if (!strcmp(p, "System")) {
part->part_type = PART_SYSTEM;
} else if (!strcmp(p, "FileSystem")) {
@@ -600,6 +615,17 @@ static int init_device(struct stm32prog_data *data,
part_id = 1;
pr_debug("id : Opt Phase Name target.n dev.n addr size part_off part_size\n");
list_for_each_entry(part, &dev->part_list, list) {
+ if (part->bin_nb > 1) {
+ if ((dev->target != STM32PROG_NAND &&
+ dev->target != STM32PROG_SPI_NAND) ||
+ part->id >= PHASE_FIRST_USER ||
+ strncmp(part->name, "fsbl", 4)) {
+ stm32prog_err("%s (0x%x): multiple binary %d not supported",
+ part->name, part->id,
+ part->bin_nb);
+ return -EINVAL;
+ }
+ }
if (part->part_type == RAW_IMAGE) {
part->part_id = 0x0;
part->addr = 0x0;
@@ -607,9 +633,9 @@ static int init_device(struct stm32prog_data *data,
part->size = block_dev->lba * block_dev->blksz;
else
part->size = last_addr;
- pr_debug("-- : %1d %02x %14s %02d %02d.%02d %08llx %08llx\n",
+ pr_debug("-- : %1d %02x %14s %02d.%d %02d.%02d %08llx %08llx\n",
part->option, part->id, part->name,
- part->part_type, part->target,
+ part->part_type, part->bin_nb, part->target,
part->dev_id, part->addr, part->size);
continue;
}
@@ -666,9 +692,9 @@ static int init_device(struct stm32prog_data *data,
part->dev->erase_size);
return -EINVAL;
}
- pr_debug("%02d : %1d %02x %14s %02d %02d.%02d %08llx %08llx",
+ pr_debug("%02d : %1d %02x %14s %02d.%d %02d.%02d %08llx %08llx",
part->part_id, part->option, part->id, part->name,
- part->part_type, part->target,
+ part->part_type, part->bin_nb, part->target,
part->dev_id, part->addr, part->size);
part_addr = 0;
@@ -1133,6 +1159,59 @@ static int dfu_init_entities(struct stm32prog_data *data)
return ret;
}
+/* copy FSBL on NAND to improve reliability on NAND */
+static int stm32prog_copy_fsbl(struct stm32prog_part_t *part)
+{
+ int ret, i;
+ void *fsbl;
+ struct image_header_s header;
+ struct raw_header_s raw_header;
+ struct dfu_entity *dfu;
+ long size, offset;
+
+ if (part->target != STM32PROG_NAND &&
+ part->target != STM32PROG_SPI_NAND)
+ return -1;
+
+ dfu = dfu_get_entity(part->alt_id);
+
+ /* read header */
+ dfu_transaction_cleanup(dfu);
+ size = BL_HEADER_SIZE;
+ ret = dfu->read_medium(dfu, 0, (void *)&raw_header, &size);
+ if (ret)
+ return ret;
+ if (stm32prog_header_check(&raw_header, &header))
+ return -1;
+
+ /* read header + payload */
+ size = header.image_length + BL_HEADER_SIZE;
+ size = round_up(size, part->dev->mtd->erasesize);
+ fsbl = calloc(1, size);
+ if (!fsbl)
+ return -ENOMEM;
+ ret = dfu->read_medium(dfu, 0, fsbl, &size);
+ pr_debug("%s read size=%lx ret=%d\n", __func__, size, ret);
+ if (ret)
+ goto error;
+
+ dfu_transaction_cleanup(dfu);
+ offset = 0;
+ for (i = part->bin_nb - 1; i > 0; i--) {
+ offset += size;
+ /* write to the next erase block */
+ ret = dfu->write_medium(dfu, offset, fsbl, &size);
+ pr_debug("%s copy at ofset=%lx size=%lx ret=%d",
+ __func__, offset, size, ret);
+ if (ret)
+ goto error;
+ }
+
+error:
+ free(fsbl);
+ return ret;
+}
+
static void stm32prog_end_phase(struct stm32prog_data *data)
{
if (data->phase == PHASE_FLASHLAYOUT) {
@@ -1156,6 +1235,15 @@ static void stm32prog_end_phase(struct stm32prog_data *data)
return;
}
}
+
+ if (CONFIG_IS_ENABLED(MTD) &&
+ data->cur_part->bin_nb > 1) {
+ if (stm32prog_copy_fsbl(data->cur_part)) {
+ stm32prog_err("%s (0x%x): copy of fsbl failed",
+ data->cur_part->name, data->cur_part->id);
+ return;
+ }
+ }
}
void stm32prog_do_reset(struct stm32prog_data *data)