stm32mp: stm32prog: add support of ssbl copy
authorPatrick Delaunay <patrick.delaunay@st.com>
Wed, 18 Mar 2020 08:24:56 +0000 (09:24 +0100)
committerPatrick Delaunay <patrick.delaunay@st.com>
Thu, 14 May 2020 07:02:12 +0000 (09:02 +0200)
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>
arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h

index 0140fd479dd3a64f6ddc79c6a8662e0fb2866abe..3e521d42f22c095223148d3efbf93f84d9feb471 100644 (file)
@@ -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)
index 7f06627ebc8068fdb5d4970a2fcbc478b7732c91..1880b163d7f322bd8311481230e69505e8e7ae8d 100644 (file)
@@ -91,6 +91,7 @@ struct stm32prog_part_t {
        char                    name[16 + 1];
        u64                     addr;
        u64                     size;
+       enum stm32prog_part_type bin_nb;        /* SSBL repeatition */
 
        /* information on associated device */
        struct stm32prog_dev_t  *dev;           /* pointer to device */