diff mbox series

[11/18] stm32mp: stm32prog: add support of ssbl copy

Message ID 20200318082503.8025-12-patrick.delaunay@st.com
State Accepted
Commit b83caf9fcb6c4cf0556004480e8fbfab7c88c6eb
Headers show
Series stm32mp1: add command stm32prog | expand

Commit Message

Patrick Delaunay March 18, 2020, 8:24 a.m. UTC
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 at st.com>
---

 .../mach-stm32mp/cmd_stm32prog/stm32prog.c    | 98 ++++++++++++++++++-
 .../mach-stm32mp/cmd_stm32prog/stm32prog.h    |  1 +
 2 files changed, 94 insertions(+), 5 deletions(-)
diff mbox series

Patch

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)
diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
index 7f06627ebc..1880b163d7 100644
--- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
@@ -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 */