All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/18] stm32mp1: add command stm32prog
@ 2020-03-18  8:24 Patrick Delaunay
  2020-03-18  8:24 ` [PATCH 01/18] usb: gadget: g_dnl: add function g_dnl_set_product Patrick Delaunay
                   ` (18 more replies)
  0 siblings, 19 replies; 40+ messages in thread
From: Patrick Delaunay @ 2020-03-18  8:24 UTC (permalink / raw)
  To: u-boot


Add a specific command stm32prog for STM32MP soc family
witch allows to update the devices on the board with the
STMicroelectronics tool STM32CubeProgrammer
(http://www.st.com/STM32CubeProg).

This command use the same UART STM32 protocol than MCU STM32
with or USB with DFU protocol v1.1 (MCU ST extension are no supported).

The executed actions are based on a tab separated value file
with a stm32 header (see
https://wiki.st.com/stm32mpu/wiki/STM32CubeProgrammer_flashlayout).

This FlashLayout file is loaded in DDR by TF-A during during a
serial boot or in a virtual device by stm32prog command
and is parsed by U-Boot (see "AN5275: USB DFU/USART protocols used
in STM32MP1 Series bootloaders" for details).

Regards
Patrick



Patrick Delaunay (18):
  usb: gadget: g_dnl: add function g_dnl_set_product
  dfu: add prototype for dfu_transaction_initiate/cleanup
  stm32mp: add function get_cpu_dev
  stm32mp: add the command stm32prog
  stm32mp: stm32prog: add flash layout parsing
  stm32mp: stm32prog: add MMC device
  stm32mp: stm32prog: add support of boot partition for eMMC device
  stm32mp: stm32prog: add upport of partial update
  stm32mp: stm32prog: add MTD devices support
  stm32mp: stm32prog: adapt the MTD partitions
  stm32mp: stm32prog: add support of ssbl copy
  stm32mp: stm32prog: add support for delete option in flashlayout
  stm32mp: stm32prog: add otp update support
  stm32mp: stm32prog: add pmic NVM update support
  stm32mp: stm32prog: add serial link support
  stm32mp: stm32prog: enable videoconsole
  stm32mp: stm32prog: support for script
  stm32mp: stm32prog: add support of RAM target

 arch/arm/mach-stm32mp/Kconfig                 |   17 +
 arch/arm/mach-stm32mp/Makefile                |    1 +
 arch/arm/mach-stm32mp/cmd_stm32prog/Makefile  |    9 +
 .../cmd_stm32prog/cmd_stm32prog.c             |  192 ++
 .../mach-stm32mp/cmd_stm32prog/stm32prog.c    | 1745 +++++++++++++++++
 .../mach-stm32mp/cmd_stm32prog/stm32prog.h    |  185 ++
 .../cmd_stm32prog/stm32prog_serial.c          |  993 ++++++++++
 .../cmd_stm32prog/stm32prog_usb.c             |  230 +++
 arch/arm/mach-stm32mp/cpu.c                   |   11 +-
 .../arm/mach-stm32mp/include/mach/stm32prog.h |   16 +
 .../arm/mach-stm32mp/include/mach/sys_proto.h |    5 +
 board/st/common/stm32mp_dfu.c                 |   20 +
 board/st/common/stm32mp_mtdparts.c            |   14 +-
 configs/stm32mp15_basic_defconfig             |    7 +-
 configs/stm32mp15_trusted_defconfig           |    7 +-
 drivers/usb/gadget/g_dnl.c                    |    8 +
 include/dfu.h                                 |    3 +
 include/g_dnl.h                               |    1 +
 18 files changed, 3445 insertions(+), 19 deletions(-)
 create mode 100644 arch/arm/mach-stm32mp/cmd_stm32prog/Makefile
 create mode 100644 arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
 create mode 100644 arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
 create mode 100644 arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
 create mode 100644 arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c
 create mode 100644 arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c
 create mode 100644 arch/arm/mach-stm32mp/include/mach/stm32prog.h

-- 
2.17.1

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 01/18] usb: gadget: g_dnl: add function g_dnl_set_product
  2020-03-18  8:24 [PATCH 00/18] stm32mp1: add command stm32prog Patrick Delaunay
@ 2020-03-18  8:24 ` Patrick Delaunay
  2020-04-14 12:57   ` [Uboot-stm32] " Patrice CHOTARD
  2020-03-18  8:24 ` [PATCH 02/18] dfu: add prototype for dfu_transaction_initiate/cleanup Patrick Delaunay
                   ` (17 subsequent siblings)
  18 siblings, 1 reply; 40+ messages in thread
From: Patrick Delaunay @ 2020-03-18  8:24 UTC (permalink / raw)
  To: u-boot

Add a function g_dnl_set_product to change the Product string used in USB
enumeration in any command based on download gadget.

If the function is called with NULL pointer, the product string is set to
the default value (product[] = "USB download gadget").

Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
---

 drivers/usb/gadget/g_dnl.c | 8 ++++++++
 include/g_dnl.h            | 1 +
 2 files changed, 9 insertions(+)

diff --git a/drivers/usb/gadget/g_dnl.c b/drivers/usb/gadget/g_dnl.c
index e9e1600a1a..7a51b53f24 100644
--- a/drivers/usb/gadget/g_dnl.c
+++ b/drivers/usb/gadget/g_dnl.c
@@ -89,6 +89,14 @@ static struct usb_gadget_strings *g_dnl_composite_strings[] = {
 	NULL,
 };
 
+void g_dnl_set_product(const char *s)
+{
+	if (s)
+		g_dnl_string_defs[1].s = s;
+	else
+		g_dnl_string_defs[1].s = product;
+}
+
 static int g_dnl_unbind(struct usb_composite_dev *cdev)
 {
 	struct usb_gadget *gadget = cdev->gadget;
diff --git a/include/g_dnl.h b/include/g_dnl.h
index 6d461c73d3..836ee602c8 100644
--- a/include/g_dnl.h
+++ b/include/g_dnl.h
@@ -38,6 +38,7 @@ int g_dnl_board_usb_cable_connected(void);
 int g_dnl_register(const char *s);
 void g_dnl_unregister(void);
 void g_dnl_set_serialnumber(char *);
+void g_dnl_set_product(const char *s);
 
 bool g_dnl_detach(void);
 void g_dnl_trigger_detach(void);
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 02/18] dfu: add prototype for dfu_transaction_initiate/cleanup
  2020-03-18  8:24 [PATCH 00/18] stm32mp1: add command stm32prog Patrick Delaunay
  2020-03-18  8:24 ` [PATCH 01/18] usb: gadget: g_dnl: add function g_dnl_set_product Patrick Delaunay
@ 2020-03-18  8:24 ` Patrick Delaunay
  2020-04-14 12:58   ` [Uboot-stm32] " Patrice CHOTARD
  2020-03-18  8:24 ` [PATCH 03/18] stm32mp: add function get_cpu_dev Patrick Delaunay
                   ` (16 subsequent siblings)
  18 siblings, 1 reply; 40+ messages in thread
From: Patrick Delaunay @ 2020-03-18  8:24 UTC (permalink / raw)
  To: u-boot

Add prototype for function dfu_transaction_initiate and
dfu_transaction_cleanup to avoid warning with W=1.

Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
---

 include/dfu.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/include/dfu.h b/include/dfu.h
index fb5260d903..2f0e335ec0 100644
--- a/include/dfu.h
+++ b/include/dfu.h
@@ -209,6 +209,9 @@ void dfu_initiated_callback(struct dfu_entity *dfu);
  */
 void dfu_flush_callback(struct dfu_entity *dfu);
 
+int dfu_transaction_initiate(struct dfu_entity *dfu, bool read);
+void dfu_transaction_cleanup(struct dfu_entity *dfu);
+
 /*
  * dfu_defer_flush - pointer to store dfu_entity for deferred flashing.
  *		     It should be NULL when not used.
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 03/18] stm32mp: add function get_cpu_dev
  2020-03-18  8:24 [PATCH 00/18] stm32mp1: add command stm32prog Patrick Delaunay
  2020-03-18  8:24 ` [PATCH 01/18] usb: gadget: g_dnl: add function g_dnl_set_product Patrick Delaunay
  2020-03-18  8:24 ` [PATCH 02/18] dfu: add prototype for dfu_transaction_initiate/cleanup Patrick Delaunay
@ 2020-03-18  8:24 ` Patrick Delaunay
  2020-04-14 12:59   ` Patrice CHOTARD
  2020-03-18  8:24 ` [PATCH 04/18] stm32mp: add the command stm32prog Patrick Delaunay
                   ` (15 subsequent siblings)
  18 siblings, 1 reply; 40+ messages in thread
From: Patrick Delaunay @ 2020-03-18  8:24 UTC (permalink / raw)
  To: u-boot

Add a function get_cpu_dev to get the DEV_ID present
in DBGMCU_IDC register.

Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
---

 arch/arm/mach-stm32mp/cpu.c                    | 11 ++++++-----
 arch/arm/mach-stm32mp/include/mach/sys_proto.h |  5 +++++
 2 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/arch/arm/mach-stm32mp/cpu.c b/arch/arm/mach-stm32mp/cpu.c
index e14e3e47f2..36a9205819 100644
--- a/arch/arm/mach-stm32mp/cpu.c
+++ b/arch/arm/mach-stm32mp/cpu.c
@@ -236,6 +236,11 @@ static u32 read_idc(void)
 	return readl(DBGMCU_IDC);
 }
 
+u32 get_cpu_dev(void)
+{
+	return (read_idc() & DBGMCU_IDC_DEV_ID_MASK) >> DBGMCU_IDC_DEV_ID_SHIFT;
+}
+
 u32 get_cpu_rev(void)
 {
 	return (read_idc() & DBGMCU_IDC_REV_ID_MASK) >> DBGMCU_IDC_REV_ID_SHIFT;
@@ -266,11 +271,7 @@ static u32 get_cpu_rpn(void)
 
 u32 get_cpu_type(void)
 {
-	u32 id;
-
-	id = (read_idc() & DBGMCU_IDC_DEV_ID_MASK) >> DBGMCU_IDC_DEV_ID_SHIFT;
-
-	return (id << 16) | get_cpu_rpn();
+	return (get_cpu_dev() << 16) | get_cpu_rpn();
 }
 
 /* Get Package options from OTP */
diff --git a/arch/arm/mach-stm32mp/include/mach/sys_proto.h b/arch/arm/mach-stm32mp/include/mach/sys_proto.h
index 1617126bea..4b6c7b8bdd 100644
--- a/arch/arm/mach-stm32mp/include/mach/sys_proto.h
+++ b/arch/arm/mach-stm32mp/include/mach/sys_proto.h
@@ -20,6 +20,11 @@
 /* return CPU_STMP32MP...Xxx constants */
 u32 get_cpu_type(void);
 
+#define CPU_DEV_STM32MP15	0x500
+
+/* return CPU_DEV constants */
+u32 get_cpu_dev(void);
+
 #define CPU_REVA	0x1000
 #define CPU_REVB	0x2000
 #define CPU_REVZ	0x2001
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 04/18] stm32mp: add the command stm32prog
  2020-03-18  8:24 [PATCH 00/18] stm32mp1: add command stm32prog Patrick Delaunay
                   ` (2 preceding siblings ...)
  2020-03-18  8:24 ` [PATCH 03/18] stm32mp: add function get_cpu_dev Patrick Delaunay
@ 2020-03-18  8:24 ` Patrick Delaunay
  2020-04-14 13:00   ` Patrice CHOTARD
  2020-04-14 13:03   ` Patrice CHOTARD
  2020-03-18  8:24 ` [PATCH 05/18] stm32mp: stm32prog: add flash layout parsing Patrick Delaunay
                   ` (14 subsequent siblings)
  18 siblings, 2 replies; 40+ messages in thread
From: Patrick Delaunay @ 2020-03-18  8:24 UTC (permalink / raw)
  To: u-boot

Add a specific command stm32prog for STM32MP soc family
witch allows to program the boot devices with the tool
STM32CubeProgrammer (http://www.st.com/STM32CubeProg).

This command uses the same UART STM32 protocol than MCU
STM32 with or USB with DFU protocol v1.1 (ithe MCU ST
extension are no supported).

The executed actions are based on a tab separated value file
with a stm32 header, the FlashLayout file
(https://wiki.st.com/stm32mpu/wiki/STM32CubeProgrammer_flashlayout).

This file is parsed by the U-Boot command to:
- initialize the devices
- create the partition table on each device
- initialize the DFU backend to access to not volatile memory
  (NOR/NAND/SD/eMMC) or to virtual device (OTP/PMIC)

Up to STM32PROG_MAX_DEV (5) devices can be updated with a FlashLayout.

The communication between U-Boot and STM32CubeProgrammer is done with
the specific alternate configuration (see "AN5275: USB DFU/USART protocols
used in STM32MP1 Series bootloaders" for details).

The command stm32prog is executed when a boot from USB is detected
(selected with bootpins) and we can program the boot devices with
a simple command (on Windows or Linux):

PC $>  STM32_Programmer_CLI -c port=usb1 -w flaslayout.tsv

1/ the ROM code loads TF-A in embedded RAM (DFU or uart)
2/ TF-A loads flashlayout file and U-Boot in DDR (DFU or uart)
3/ U-Boot executes the stm32prog command (DFU or uart)

Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
---

 arch/arm/mach-stm32mp/Kconfig                 |  12 +
 arch/arm/mach-stm32mp/Makefile                |   1 +
 arch/arm/mach-stm32mp/cmd_stm32prog/Makefile  |   8 +
 .../cmd_stm32prog/cmd_stm32prog.c             |  96 ++++
 .../mach-stm32mp/cmd_stm32prog/stm32prog.c    | 480 ++++++++++++++++++
 .../mach-stm32mp/cmd_stm32prog/stm32prog.h    | 137 +++++
 .../cmd_stm32prog/stm32prog_usb.c             | 206 ++++++++
 .../arm/mach-stm32mp/include/mach/stm32prog.h |  12 +
 board/st/common/stm32mp_dfu.c                 |  20 +
 configs/stm32mp15_basic_defconfig             |   3 +-
 configs/stm32mp15_trusted_defconfig           |   3 +-
 11 files changed, 974 insertions(+), 4 deletions(-)
 create mode 100644 arch/arm/mach-stm32mp/cmd_stm32prog/Makefile
 create mode 100644 arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
 create mode 100644 arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
 create mode 100644 arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
 create mode 100644 arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c
 create mode 100644 arch/arm/mach-stm32mp/include/mach/stm32prog.h

diff --git a/arch/arm/mach-stm32mp/Kconfig b/arch/arm/mach-stm32mp/Kconfig
index 1a5545b98d..61466f6125 100644
--- a/arch/arm/mach-stm32mp/Kconfig
+++ b/arch/arm/mach-stm32mp/Kconfig
@@ -114,6 +114,18 @@ config STM32_ETZPC
 	help
 	  Say y to enable STM32 Extended TrustZone Protection
 
+config CMD_STM32PROG
+	bool "command stm32prog for STM32CudeProgrammer"
+	select DFU
+	select DFU_RAM
+	select DFU_VIRT
+	help
+		activate a specific command stm32prog for STM32MP soc family
+		witch update the device with the tools STM32CubeProgrammer,
+		using UART with STM32 protocol or USB with DFU protocol
+		NB: access to not volatile memory (NOR/NAND/SD/eMMC) is based
+		    on U-Boot DFU framework
+
 config CMD_STM32KEY
 	bool "command stm32key to fuse public key hash"
 	default y
diff --git a/arch/arm/mach-stm32mp/Makefile b/arch/arm/mach-stm32mp/Makefile
index 19ca3b08a5..c6ab3cecf0 100644
--- a/arch/arm/mach-stm32mp/Makefile
+++ b/arch/arm/mach-stm32mp/Makefile
@@ -10,6 +10,7 @@ obj-y += syscon.o
 ifdef CONFIG_SPL_BUILD
 obj-y += spl.o
 else
+obj-$(CONFIG_CMD_STM32PROG) += cmd_stm32prog/
 obj-y += bsec.o
 obj-$(CONFIG_CMD_STM32KEY) += cmd_stm32key.o
 obj-$(CONFIG_ARMV7_PSCI) += psci.o
diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/Makefile b/arch/arm/mach-stm32mp/cmd_stm32prog/Makefile
new file mode 100644
index 0000000000..14f722759c
--- /dev/null
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2020, STMicroelectronics - All Rights Reserved
+#
+
+obj-y += cmd_stm32prog.o
+obj-y += stm32prog.o
+obj-y += stm32prog_usb.o
diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
new file mode 100644
index 0000000000..3e8b426444
--- /dev/null
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
@@ -0,0 +1,96 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2020, STMicroelectronics - All Rights Reserved
+ */
+
+#include <common.h>
+#include <command.h>
+#include <dfu.h>
+#include "stm32prog.h"
+
+struct stm32prog_data *stm32prog_data;
+
+static int do_stm32prog(cmd_tbl_t *cmdtp, int flag, int argc,
+			char * const argv[])
+{
+	ulong	addr, size;
+	int dev, ret;
+	enum stm32prog_link_t link = LINK_UNDEFINED;
+	bool reset = false;
+	struct stm32prog_data *data;
+
+	if (argc < 3 ||  argc > 5)
+		return CMD_RET_USAGE;
+
+	if (!strcmp(argv[1], "usb"))
+		link = LINK_USB;
+
+	if (link == LINK_UNDEFINED) {
+		pr_err("not supported link=%s\n", argv[1]);
+		return CMD_RET_USAGE;
+	}
+	dev = (int)simple_strtoul(argv[2], NULL, 10);
+
+	addr = STM32_DDR_BASE;
+	size = 0;
+	if (argc > 3) {
+		addr = simple_strtoul(argv[3], NULL, 16);
+		if (!addr)
+			return CMD_RET_FAILURE;
+	}
+	if (argc > 4)
+		size = simple_strtoul(argv[4], NULL, 16);
+
+	data = (struct stm32prog_data *)malloc(sizeof(*data));
+
+	if (!data) {
+		pr_err("Alloc failed.");
+		return CMD_RET_FAILURE;
+	}
+	stm32prog_data = data;
+
+	ret = stm32prog_init(data, addr, size);
+	if (ret)
+		printf("Invalid or missing layout file.");
+
+	/* prepare DFU for device read/write */
+	ret = stm32prog_dfu_init(data);
+	if (ret)
+		goto cleanup;
+
+	switch (link) {
+	case LINK_USB:
+		reset = stm32prog_usb_loop(data, dev);
+		break;
+	default:
+		goto cleanup;
+	}
+
+	stm32prog_clean(data);
+	free(stm32prog_data);
+	stm32prog_data = NULL;
+
+	puts("Download done\n");
+	if (reset) {
+		puts("Reset...\n");
+		run_command("reset", 0);
+	}
+
+	return CMD_RET_SUCCESS;
+
+cleanup:
+	stm32prog_clean(data);
+	free(stm32prog_data);
+	stm32prog_data = NULL;
+
+	return CMD_RET_FAILURE;
+}
+
+U_BOOT_CMD(stm32prog, 5, 0, do_stm32prog,
+	   "<link> <dev> [<addr>] [<size>]\n"
+	   "start communication with tools STM32Cubeprogrammer on <link> with Flashlayout at <addr>",
+	   "<link> = usb\n"
+	   "<dev>  = device instance\n"
+	   "<addr> = address of flashlayout\n"
+	   "<size> = size of flashlayout\n"
+);
diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
new file mode 100644
index 0000000000..e2c6c43d88
--- /dev/null
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
@@ -0,0 +1,480 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2020, STMicroelectronics - All Rights Reserved
+ */
+
+#include <common.h>
+#include <console.h>
+#include <dfu.h>
+#include <malloc.h>
+#include <dm/uclass.h>
+#include <linux/list.h>
+#include <linux/list_sort.h>
+#include <linux/sizes.h>
+
+#include "stm32prog.h"
+
+#define OPT_SELECT	BIT(0)
+#define OPT_EMPTY	BIT(1)
+
+#define IS_SELECT(part)	((part)->option & OPT_SELECT)
+#define IS_EMPTY(part)	((part)->option & OPT_EMPTY)
+
+#define ALT_BUF_LEN			SZ_1K
+
+DECLARE_GLOBAL_DATA_PTR;
+
+char *stm32prog_get_error(struct stm32prog_data *data)
+{
+	static const char error_msg[] = "Unspecified";
+
+	if (strlen(data->error) == 0)
+		strcpy(data->error, error_msg);
+
+	return data->error;
+}
+
+static int parse_flash_layout(struct stm32prog_data *data,
+			      ulong addr,
+			      ulong size)
+{
+	return -ENODEV;
+}
+
+static int __init part_cmp(void *priv, struct list_head *a, struct list_head *b)
+{
+	struct stm32prog_part_t *parta, *partb;
+
+	parta = container_of(a, struct stm32prog_part_t, list);
+	partb = container_of(b, struct stm32prog_part_t, list);
+
+	return parta->addr > partb->addr ? 1 : -1;
+}
+
+static int init_device(struct stm32prog_data *data,
+		       struct stm32prog_dev_t *dev)
+{
+	struct blk_desc *block_dev = NULL;
+	int part_id;
+	u64 first_addr = 0, last_addr = 0;
+	struct stm32prog_part_t *part, *next_part;
+
+	switch (dev->target) {
+	default:
+		stm32prog_err("unknown device type = %d", dev->target);
+		return -ENODEV;
+	}
+
+	/* order partition list in offset order */
+	list_sort(NULL, &dev->part_list, &part_cmp);
+	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->part_type == RAW_IMAGE) {
+			part->part_id = 0x0;
+			part->addr = 0x0;
+			if (block_dev)
+				part->size = block_dev->lba * block_dev->blksz;
+			else
+				part->size = last_addr;
+			pr_debug("-- : %1d %02x %14s %02d %02d.%02d %08llx %08llx\n",
+				 part->option, part->id, part->name,
+				 part->part_type, part->target,
+				 part->dev_id, part->addr, part->size);
+			continue;
+		}
+
+		part->part_id = part_id++;
+
+		/* last partition : size to the end of the device */
+		if (part->list.next != &dev->part_list) {
+			next_part =
+				container_of(part->list.next,
+					     struct stm32prog_part_t,
+					     list);
+			if (part->addr < next_part->addr) {
+				part->size = next_part->addr -
+					     part->addr;
+			} else {
+				stm32prog_err("%s (0x%x): same address : 0x%llx == %s (0x%x): 0x%llx",
+					      part->name, part->id,
+					      part->addr,
+					      next_part->name,
+					      next_part->id,
+					      next_part->addr);
+				return -EINVAL;
+			}
+		} else {
+			if (part->addr <= last_addr) {
+				part->size = last_addr - part->addr;
+			} else {
+				stm32prog_err("%s (0x%x): invalid address 0x%llx (max=0x%llx)",
+					      part->name, part->id,
+					      part->addr, last_addr);
+				return -EINVAL;
+			}
+		}
+		if (part->addr < first_addr) {
+			stm32prog_err("%s (0x%x): invalid address 0x%llx (min=0x%llx)",
+				      part->name, part->id,
+				      part->addr, first_addr);
+			return -EINVAL;
+		}
+
+		pr_debug("%02d : %1d %02x %14s %02d %02d.%02d %08llx %08llx",
+			 part->part_id, part->option, part->id, part->name,
+			 part->part_type, part->target,
+			 part->dev_id, part->addr, part->size);
+	}
+	return 0;
+}
+
+static int treat_partition_list(struct stm32prog_data *data)
+{
+	int i, j;
+	struct stm32prog_part_t *part;
+
+	for (j = 0; j < STM32PROG_MAX_DEV; j++) {
+		data->dev[j].target = STM32PROG_NONE;
+		INIT_LIST_HEAD(&data->dev[j].part_list);
+	}
+
+	for (i = 0; i < data->part_nb; i++) {
+		part = &data->part_array[i];
+		part->alt_id = -1;
+
+		/* skip partition with IP="none" */
+		if (part->target == STM32PROG_NONE) {
+			if (IS_SELECT(part)) {
+				stm32prog_err("Layout: selected none phase = 0x%x",
+					      part->id);
+				return -EINVAL;
+			}
+			continue;
+		}
+
+		if (part->id == PHASE_FLASHLAYOUT ||
+		    part->id > PHASE_LAST_USER) {
+			stm32prog_err("Layout: invalid phase = 0x%x",
+				      part->id);
+			return -EINVAL;
+		}
+		for (j = i + 1; j < data->part_nb; j++) {
+			if (part->id == data->part_array[j].id) {
+				stm32prog_err("Layout: duplicated phase 0x%x at line %d and %d",
+					      part->id, i, j);
+				return -EINVAL;
+			}
+		}
+		for (j = 0; j < STM32PROG_MAX_DEV; j++) {
+			if (data->dev[j].target == STM32PROG_NONE) {
+				/* new device found */
+				data->dev[j].target = part->target;
+				data->dev[j].dev_id = part->dev_id;
+				data->dev_nb++;
+				break;
+			} else if ((part->target == data->dev[j].target) &&
+				   (part->dev_id == data->dev[j].dev_id)) {
+				break;
+			}
+		}
+		if (j == STM32PROG_MAX_DEV) {
+			stm32prog_err("Layout: too many device");
+			return -EINVAL;
+		}
+		part->dev = &data->dev[j];
+		list_add_tail(&part->list, &data->dev[j].part_list);
+	}
+
+	return 0;
+}
+
+static int stm32prog_alt_add(struct stm32prog_data *data,
+			     struct dfu_entity *dfu,
+			     struct stm32prog_part_t *part)
+{
+	int ret = 0;
+	int offset = 0;
+	char devstr[10];
+	char dfustr[10];
+	char buf[ALT_BUF_LEN];
+	u32 size;
+	char multiplier,  type;
+
+	/* max 3 digit for sector size */
+	if (part->size > SZ_1M) {
+		size = (u32)(part->size / SZ_1M);
+		multiplier = 'M';
+	} else if (part->size > SZ_1K) {
+		size = (u32)(part->size / SZ_1K);
+		multiplier = 'K';
+	} else {
+		size = (u32)part->size;
+		multiplier = 'B';
+	}
+	if (IS_SELECT(part) && !IS_EMPTY(part))
+		type = 'e'; /*Readable and Writeable*/
+	else
+		type = 'a';/*Readable*/
+
+	memset(buf, 0, sizeof(buf));
+	offset = snprintf(buf, ALT_BUF_LEN - offset,
+			  "@%s/0x%02x/1*%d%c%c ",
+			  part->name, part->id,
+			  size, multiplier, type);
+
+	if (part->part_type == RAW_IMAGE) {
+		u64 dfu_size;
+
+		dfu_size = part->size;
+		offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
+				   "raw 0x0 0x%llx", dfu_size);
+	} else {
+		offset += snprintf(buf + offset,
+				   ALT_BUF_LEN - offset,
+				   "part");
+		offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
+				   " %d;", part->part_id);
+	}
+	switch (part->target) {
+	default:
+		stm32prog_err("invalid target: %d", part->target);
+		return -ENODEV;
+	}
+	pr_debug("dfu_alt_add(%s,%s,%s)\n", dfustr, devstr, buf);
+	ret = dfu_alt_add(dfu, dfustr, devstr, buf);
+	pr_debug("dfu_alt_add(%s,%s,%s) result %d\n",
+		 dfustr, devstr, buf, ret);
+
+	return ret;
+}
+
+static int stm32prog_alt_add_virt(struct dfu_entity *dfu,
+				  char *name, int phase, int size)
+{
+	int ret = 0;
+	char devstr[4];
+	char buf[ALT_BUF_LEN];
+
+	sprintf(devstr, "%d", phase);
+	sprintf(buf, "@%s/0x%02x/1*%dBe", name, phase, size);
+	ret = dfu_alt_add(dfu, "virt", devstr, buf);
+	pr_debug("dfu_alt_add(virt,%s,%s) result %d\n", devstr, buf, ret);
+
+	return ret;
+}
+
+static int dfu_init_entities(struct stm32prog_data *data)
+{
+	int ret = 0;
+	int phase, i, alt_id;
+	struct stm32prog_part_t *part;
+	struct dfu_entity *dfu;
+	int alt_nb;
+
+	alt_nb = 1; /* number of virtual = CMD */
+	if (data->part_nb == 0)
+		alt_nb++;  /* +1 for FlashLayout */
+	else
+		for (i = 0; i < data->part_nb; i++) {
+			if (data->part_array[i].target != STM32PROG_NONE)
+				alt_nb++;
+		}
+
+	if (dfu_alt_init(alt_nb, &dfu))
+		return -ENODEV;
+
+	puts("DFU alt info setting: ");
+	if (data->part_nb) {
+		alt_id = 0;
+		for (phase = 1;
+		     (phase <= PHASE_LAST_USER) &&
+		     (alt_id < alt_nb) && !ret;
+		     phase++) {
+			/* ordering alt setting by phase id */
+			part = NULL;
+			for (i = 0; i < data->part_nb; i++) {
+				if (phase == data->part_array[i].id) {
+					part = &data->part_array[i];
+					break;
+				}
+			}
+			if (!part)
+				continue;
+			if (part->target == STM32PROG_NONE)
+				continue;
+			part->alt_id = alt_id;
+			alt_id++;
+
+			ret = stm32prog_alt_add(data, dfu, part);
+		}
+	} else {
+		char buf[ALT_BUF_LEN];
+
+		sprintf(buf, "@FlashLayout/0x%02x/1*256Ke ram %x 40000",
+			PHASE_FLASHLAYOUT, STM32_DDR_BASE);
+		ret = dfu_alt_add(dfu, "ram", NULL, buf);
+		pr_debug("dfu_alt_add(ram, NULL,%s) result %d\n", buf, ret);
+	}
+
+	if (!ret)
+		ret = stm32prog_alt_add_virt(dfu, "virtual", PHASE_CMD, 512);
+
+	if (ret)
+		stm32prog_err("dfu init failed: %d", ret);
+	puts("done\n");
+
+#ifdef DEBUG
+	dfu_show_entities();
+#endif
+	return ret;
+}
+
+static void stm32prog_end_phase(struct stm32prog_data *data)
+{
+	if (data->phase == PHASE_FLASHLAYOUT) {
+		if (parse_flash_layout(data, STM32_DDR_BASE, 0))
+			stm32prog_err("Layout: invalid FlashLayout");
+		return;
+	}
+
+	if (!data->cur_part)
+		return;
+}
+
+void stm32prog_do_reset(struct stm32prog_data *data)
+{
+	if (data->phase == PHASE_RESET) {
+		data->phase = PHASE_DO_RESET;
+		puts("Reset requested\n");
+	}
+}
+
+void stm32prog_next_phase(struct stm32prog_data *data)
+{
+	int phase, i;
+	struct stm32prog_part_t *part;
+	bool found;
+
+	phase = data->phase;
+	switch (phase) {
+	case PHASE_RESET:
+	case PHASE_END:
+	case PHASE_DO_RESET:
+		return;
+	}
+
+	/* found next selected partition */
+	data->cur_part = NULL;
+	data->phase = PHASE_END;
+	found = false;
+	do {
+		phase++;
+		if (phase > PHASE_LAST_USER)
+			break;
+		for (i = 0; i < data->part_nb; i++) {
+			part = &data->part_array[i];
+			if (part->id == phase) {
+				if (IS_SELECT(part) && !IS_EMPTY(part)) {
+					data->cur_part = part;
+					data->phase = phase;
+					found = true;
+				}
+				break;
+			}
+		}
+	} while (!found);
+
+	if (data->phase == PHASE_END)
+		puts("Phase=END\n");
+}
+
+static void stm32prog_devices_init(struct stm32prog_data *data)
+{
+	int i;
+	int ret;
+
+	ret = treat_partition_list(data);
+	if (ret)
+		goto error;
+
+	/* initialize the selected device */
+	for (i = 0; i < data->dev_nb; i++) {
+		ret = init_device(data, &data->dev[i]);
+		if (ret)
+			goto error;
+	}
+
+	return;
+
+error:
+	data->part_nb = 0;
+}
+
+int stm32prog_dfu_init(struct stm32prog_data *data)
+{
+	/* init device if no error */
+	if (data->part_nb)
+		stm32prog_devices_init(data);
+
+	if (data->part_nb)
+		stm32prog_next_phase(data);
+
+	/* prepare DFU for device read/write */
+	dfu_free_entities();
+	return dfu_init_entities(data);
+}
+
+int stm32prog_init(struct stm32prog_data *data, ulong addr, ulong size)
+{
+	memset(data, 0x0, sizeof(*data));
+	data->phase = PHASE_FLASHLAYOUT;
+
+	return parse_flash_layout(data, addr, size);
+}
+
+void stm32prog_clean(struct stm32prog_data *data)
+{
+	/* clean */
+	dfu_free_entities();
+	free(data->part_array);
+	free(data->header_data);
+}
+
+/* DFU callback: used after serial and direct DFU USB access */
+void dfu_flush_callback(struct dfu_entity *dfu)
+{
+	if (!stm32prog_data)
+		return;
+
+	if (dfu->dev_type == DFU_DEV_RAM) {
+		if (dfu->alt == 0 &&
+		    stm32prog_data->phase == PHASE_FLASHLAYOUT) {
+			stm32prog_end_phase(stm32prog_data);
+			/* waiting DFU DETACH for reenumeration */
+		}
+	}
+
+	if (!stm32prog_data->cur_part)
+		return;
+
+	if (dfu->alt == stm32prog_data->cur_part->alt_id) {
+		stm32prog_end_phase(stm32prog_data);
+		stm32prog_next_phase(stm32prog_data);
+	}
+}
+
+void dfu_initiated_callback(struct dfu_entity *dfu)
+{
+	if (!stm32prog_data)
+		return;
+
+	if (!stm32prog_data->cur_part)
+		return;
+
+	/* force the saved offset for the current partition */
+	if (dfu->alt == stm32prog_data->cur_part->alt_id) {
+		dfu->offset = stm32prog_data->offset;
+		pr_debug("dfu offset = 0x%llx\n", dfu->offset);
+	}
+}
diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
new file mode 100644
index 0000000000..b44b6f89af
--- /dev/null
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
@@ -0,0 +1,137 @@
+/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
+/*
+ * Copyright (C) 2020, STMicroelectronics - All Rights Reserved
+ */
+
+#ifndef _STM32PROG_H_
+#define _STM32PROG_H_
+
+/* - phase defines ------------------------------------------------*/
+#define PHASE_FLASHLAYOUT	0x00
+#define PHASE_FIRST_USER	0x10
+#define PHASE_LAST_USER		0xF0
+#define PHASE_CMD		0xF1
+#define PHASE_END		0xFE
+#define PHASE_RESET		0xFF
+#define PHASE_DO_RESET		0x1FF
+
+#define DEFAULT_ADDRESS		0xFFFFFFFF
+
+enum stm32prog_target {
+	STM32PROG_NONE,
+};
+
+enum stm32prog_link_t {
+	LINK_USB,
+	LINK_UNDEFINED,
+};
+
+struct image_header_s {
+	bool	present;
+	u32	image_checksum;
+	u32	image_length;
+};
+
+struct raw_header_s {
+	u32 magic_number;
+	u32 image_signature[64 / 4];
+	u32 image_checksum;
+	u32 header_version;
+	u32 image_length;
+	u32 image_entry_point;
+	u32 reserved1;
+	u32 load_address;
+	u32 reserved2;
+	u32 version_number;
+	u32 option_flags;
+	u32 ecdsa_algorithm;
+	u32 ecdsa_public_key[64 / 4];
+	u32 padding[83 / 4];
+	u32 binary_type;
+};
+
+#define BL_HEADER_SIZE	sizeof(struct raw_header_s)
+
+/* partition type in flashlayout file */
+enum stm32prog_part_type {
+	PART_BINARY,
+	PART_SYSTEM,
+	PART_FILESYSTEM,
+	RAW_IMAGE
+};
+
+/* device information */
+struct stm32prog_dev_t {
+	enum stm32prog_target	target;
+	char			dev_id;
+	/* list of partition for this device / ordered in offset */
+	struct list_head	part_list;
+};
+
+/* partition information build from FlashLayout and device */
+struct stm32prog_part_t {
+	/* FlashLayout information */
+	int			option;
+	int			id;
+	enum stm32prog_part_type part_type;
+	enum stm32prog_target	target;
+	char			dev_id;
+
+	/* partition name
+	 * (16 char in gpt, + 1 for null terminated string
+	 */
+	char			name[16 + 1];
+	u64			addr;
+	u64			size;
+
+	/* information on associated device */
+	struct stm32prog_dev_t	*dev;		/* pointer to device */
+	u16			part_id;	/* partition id in device */
+	int			alt_id;		/* alt id in usb/dfu */
+
+	struct list_head	list;
+};
+
+#define STM32PROG_MAX_DEV 5
+struct stm32prog_data {
+	/* Layout information */
+	int			dev_nb;		/* device number*/
+	struct stm32prog_dev_t	dev[STM32PROG_MAX_DEV];	/* array of device */
+	int			part_nb;	/* nb of partition */
+	struct stm32prog_part_t	*part_array;	/* array of partition */
+
+	/* command internal information */
+	unsigned int		phase;
+	u32			offset;
+	char			error[255];
+	struct stm32prog_part_t	*cur_part;
+
+	/* STM32 header information */
+	struct raw_header_s	*header_data;
+	struct image_header_s	header;
+};
+
+extern struct stm32prog_data *stm32prog_data;
+
+/* generic part*/
+u8 stm32prog_header_check(struct raw_header_s *raw_header,
+			  struct image_header_s *header);
+int stm32prog_dfu_init(struct stm32prog_data *data);
+void stm32prog_next_phase(struct stm32prog_data *data);
+void stm32prog_do_reset(struct stm32prog_data *data);
+
+char *stm32prog_get_error(struct stm32prog_data *data);
+
+#define stm32prog_err(args...) {\
+	if (data->phase != PHASE_RESET) { \
+		sprintf(data->error, args); \
+		data->phase = PHASE_RESET; \
+		pr_err("Error: %s\n", data->error); } \
+	}
+
+/* Main function */
+int stm32prog_init(struct stm32prog_data *data, ulong addr, ulong size);
+bool stm32prog_usb_loop(struct stm32prog_data *data, int dev);
+void stm32prog_clean(struct stm32prog_data *data);
+
+#endif
diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c
new file mode 100644
index 0000000000..ed2cdbc66f
--- /dev/null
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2020, STMicroelectronics - All Rights Reserved
+ */
+
+#include <common.h>
+#include <dfu.h>
+#include <g_dnl.h>
+#include <usb.h>
+#include <asm/arch/stm32prog.h>
+#include <asm/arch/sys_proto.h>
+#include "stm32prog.h"
+
+static int stm32prog_set_phase(struct stm32prog_data *data, u8 phase,
+			       u32 offset)
+{
+	struct stm32prog_part_t *part;
+	int i;
+
+	if (phase == data->phase) {
+		data->offset = offset;
+		return 0;
+	}
+
+	/* found partition for phase */
+	for (i = 0; i < data->part_nb; i++) {
+		part = &data->part_array[i];
+		if (part->id == phase) {
+			data->cur_part = part;
+			data->phase = phase;
+			data->offset = offset;
+			return 0;
+		}
+	}
+
+	return  -EINVAL;
+}
+
+static int stm32prog_cmd_write(u64 offset, void *buf, long *len)
+{
+	u8 phase;
+	u32 address;
+	u8 *pt = buf;
+	void (*entry)(void);
+	int ret;
+
+	if (*len < 5) {
+		pr_err("size not allowed\n");
+		return  -EINVAL;
+	}
+	if (offset) {
+		pr_err("invalid offset\n");
+		return  -EINVAL;
+	}
+	phase = pt[0];
+	address = (pt[1] << 24) | (pt[2] << 16) | (pt[3] << 8) | pt[4];
+	if (phase == PHASE_RESET) {
+		entry = (void *)address;
+		printf("## Starting application@0x%x ...\n", address);
+		(*entry)();
+		printf("## Application terminated\n");
+		return 0;
+	}
+	/* set phase and offset */
+	ret = stm32prog_set_phase(stm32prog_data, phase, address);
+	if (ret)
+		pr_err("failed: %d\n", ret);
+	return ret;
+}
+
+#define PHASE_MIN_SIZE	9
+static int stm32prog_cmd_read(u64 offset, void *buf, long *len)
+{
+	u32 destination = DEFAULT_ADDRESS; /* destination address */
+	u32 dfu_offset;
+	u8 *pt_buf = buf;
+	int phase;
+	char *err_msg;
+	int length;
+
+	if (*len < PHASE_MIN_SIZE) {
+		pr_err("request exceeds allowed area\n");
+		return  -EINVAL;
+	}
+	if (offset) {
+		*len = 0; /* EOF for second request */
+		return 0;
+	}
+	phase = stm32prog_data->phase;
+	if (phase == PHASE_FLASHLAYOUT)
+		destination = STM32_DDR_BASE;
+	dfu_offset = stm32prog_data->offset;
+
+	/* mandatory header, size = PHASE_MIN_SIZE */
+	*pt_buf++ = (u8)(phase & 0xFF);
+	*pt_buf++ = (u8)(destination);
+	*pt_buf++ = (u8)(destination >> 8);
+	*pt_buf++ = (u8)(destination >> 16);
+	*pt_buf++ = (u8)(destination >> 24);
+	*pt_buf++ = (u8)(dfu_offset);
+	*pt_buf++ = (u8)(dfu_offset >> 8);
+	*pt_buf++ = (u8)(dfu_offset >> 16);
+	*pt_buf++ = (u8)(dfu_offset >> 24);
+
+	if (phase == PHASE_RESET || phase == PHASE_DO_RESET) {
+		err_msg = stm32prog_get_error(stm32prog_data);
+		length = strlen(err_msg);
+		if (length + PHASE_MIN_SIZE > *len)
+			length = *len - PHASE_MIN_SIZE;
+
+		memcpy(pt_buf, err_msg, length);
+		*len = PHASE_MIN_SIZE + length;
+		stm32prog_do_reset(stm32prog_data);
+	} else if (phase == PHASE_FLASHLAYOUT) {
+		*pt_buf++ = stm32prog_data->part_nb ? 1 : 0;
+		*len = PHASE_MIN_SIZE + 1;
+	} else {
+		*len = PHASE_MIN_SIZE;
+	}
+
+	return 0;
+}
+
+int stm32prog_write_medium_virt(struct dfu_entity *dfu, u64 offset,
+				void *buf, long *len)
+{
+	if (dfu->dev_type != DFU_DEV_VIRT)
+		return -EINVAL;
+
+	switch (dfu->data.virt.dev_num) {
+	case PHASE_CMD:
+		return stm32prog_cmd_write(offset, buf, len);
+	}
+	*len = 0;
+	return 0;
+}
+
+int stm32prog_read_medium_virt(struct dfu_entity *dfu, u64 offset,
+			       void *buf, long *len)
+{
+	if (dfu->dev_type != DFU_DEV_VIRT)
+		return -EINVAL;
+
+	switch (dfu->data.virt.dev_num) {
+	case PHASE_CMD:
+		return stm32prog_cmd_read(offset, buf, len);
+	}
+	*len = 0;
+	return 0;
+}
+
+int stm32prog_get_medium_size_virt(struct dfu_entity *dfu, u64 *size)
+{
+	if (dfu->dev_type != DFU_DEV_VIRT) {
+		*size = 0;
+		pr_debug("%s, invalid dev_type = %d\n",
+			 __func__, dfu->dev_type);
+		return -EINVAL;
+	}
+
+	switch (dfu->data.virt.dev_num) {
+	case PHASE_CMD:
+		*size = 512;
+		break;
+	}
+
+	return 0;
+}
+
+bool stm32prog_usb_loop(struct stm32prog_data *data, int dev)
+{
+	int ret;
+	bool result;
+	/* USB download gadget for STM32 Programmer */
+	char product[128];
+
+	snprintf(product, sizeof(product),
+		 "USB download gadget at Device ID /0x%03X, @Revision ID /0x%04X",
+		 get_cpu_dev(), get_cpu_rev());
+	g_dnl_set_product(product);
+
+	if (stm32prog_data->phase == PHASE_FLASHLAYOUT) {
+		ret = run_usb_dnl_gadget(dev, "usb_dnl_dfu");
+		if (ret || stm32prog_data->phase == PHASE_DO_RESET)
+			return ret;
+		/* prepare the second enumeration with the FlashLayout */
+		if (stm32prog_data->phase == PHASE_FLASHLAYOUT)
+			stm32prog_dfu_init(data);
+		/* found next selected partition */
+		stm32prog_next_phase(data);
+	}
+
+	ret = run_usb_dnl_gadget(dev, "usb_dnl_dfu");
+
+	result = !!(ret) || (stm32prog_data->phase == PHASE_DO_RESET);
+
+	g_dnl_set_product(NULL);
+
+	return result;
+}
+
+int g_dnl_get_board_bcd_device_number(int gcnum)
+{
+	pr_debug("%s\n", __func__);
+	return 0x200;
+}
diff --git a/arch/arm/mach-stm32mp/include/mach/stm32prog.h b/arch/arm/mach-stm32mp/include/mach/stm32prog.h
new file mode 100644
index 0000000000..c10bff09c8
--- /dev/null
+++ b/arch/arm/mach-stm32mp/include/mach/stm32prog.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
+/*
+ * Copyright (C) 2020, STMicroelectronics - All Rights Reserved
+ */
+
+#define STM32PROG_VIRT_FIRST_DEV_NUM		0xF1
+
+int stm32prog_write_medium_virt(struct dfu_entity *dfu, u64 offset,
+				void *buf, long *len);
+int stm32prog_read_medium_virt(struct dfu_entity *dfu, u64 offset,
+			       void *buf, long *len);
+int stm32prog_get_medium_size_virt(struct dfu_entity *dfu, u64 *size);
diff --git a/board/st/common/stm32mp_dfu.c b/board/st/common/stm32mp_dfu.c
index e129f8c8b5..3bd005bb04 100644
--- a/board/st/common/stm32mp_dfu.c
+++ b/board/st/common/stm32mp_dfu.c
@@ -11,6 +11,7 @@
 #include <misc.h>
 #include <mtd.h>
 #include <mtd_node.h>
+#include <asm/arch/stm32prog.h>
 
 #define DFU_ALT_BUF_LEN SZ_1K
 
@@ -211,12 +212,31 @@ int dfu_read_medium_virt(struct dfu_entity *dfu, u64 offset,
 	case 0x1:
 		return dfu_pmic_read(offset, buf, len);
 	}
+
+	if (CONFIG_IS_ENABLED(CMD_STM32PROG) &&
+	    dfu->data.virt.dev_num >= STM32PROG_VIRT_FIRST_DEV_NUM)
+		return stm32prog_read_medium_virt(dfu, offset, buf, len);
+
 	*len = 0;
 	return 0;
 }
 
+int dfu_write_medium_virt(struct dfu_entity *dfu, u64 offset,
+			  void *buf, long *len)
+{
+	if (CONFIG_IS_ENABLED(CMD_STM32PROG) &&
+	    dfu->data.virt.dev_num >= STM32PROG_VIRT_FIRST_DEV_NUM)
+		return stm32prog_write_medium_virt(dfu, offset, buf, len);
+
+	return -EOPNOTSUPP;
+}
+
 int __weak dfu_get_medium_size_virt(struct dfu_entity *dfu, u64 *size)
 {
+	if (CONFIG_IS_ENABLED(CMD_STM32PROG) &&
+	    dfu->data.virt.dev_num >= STM32PROG_VIRT_FIRST_DEV_NUM)
+		return stm32prog_get_medium_size_virt(dfu, size);
+
 	*size = SZ_1K;
 
 	return 0;
diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig
index f9bc5b6086..baed3d92f5 100644
--- a/configs/stm32mp15_basic_defconfig
+++ b/configs/stm32mp15_basic_defconfig
@@ -6,6 +6,7 @@ CONFIG_ENV_OFFSET=0x280000
 CONFIG_SPL_MMC_SUPPORT=y
 CONFIG_SPL=y
 CONFIG_TARGET_ST_STM32MP15x=y
+CONFIG_CMD_STM32PROG=y
 CONFIG_ENV_OFFSET_REDUND=0x2C0000
 CONFIG_SPL_SPI_FLASH_SUPPORT=y
 CONFIG_SPL_SPI_SUPPORT=y
@@ -68,9 +69,7 @@ CONFIG_ENV_UBI_VOLUME_REDUND="uboot_config_r"
 CONFIG_SYS_RELOC_GD_ENV_ADDR=y
 CONFIG_STM32_ADC=y
 CONFIG_DFU_MMC=y
-CONFIG_DFU_RAM=y
 CONFIG_DFU_MTD=y
-CONFIG_DFU_VIRT=y
 CONFIG_SET_DFU_ALT_INFO=y
 CONFIG_USB_FUNCTION_FASTBOOT=y
 CONFIG_FASTBOOT_BUF_ADDR=0xC0000000
diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig
index f0d524d344..adbe304902 100644
--- a/configs/stm32mp15_trusted_defconfig
+++ b/configs/stm32mp15_trusted_defconfig
@@ -4,6 +4,7 @@ CONFIG_SYS_MALLOC_F_LEN=0x3000
 CONFIG_ENV_SECT_SIZE=0x40000
 CONFIG_ENV_OFFSET=0x280000
 CONFIG_TARGET_ST_STM32MP15x=y
+CONFIG_CMD_STM32PROG=y
 CONFIG_ENV_OFFSET_REDUND=0x2C0000
 CONFIG_DISTRO_DEFAULTS=y
 CONFIG_FIT=y
@@ -54,9 +55,7 @@ CONFIG_ENV_UBI_VOLUME_REDUND="uboot_config_r"
 CONFIG_SYS_RELOC_GD_ENV_ADDR=y
 CONFIG_STM32_ADC=y
 CONFIG_DFU_MMC=y
-CONFIG_DFU_RAM=y
 CONFIG_DFU_MTD=y
-CONFIG_DFU_VIRT=y
 CONFIG_SET_DFU_ALT_INFO=y
 CONFIG_USB_FUNCTION_FASTBOOT=y
 CONFIG_FASTBOOT_BUF_ADDR=0xC0000000
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 05/18] stm32mp: stm32prog: add flash layout parsing
  2020-03-18  8:24 [PATCH 00/18] stm32mp1: add command stm32prog Patrick Delaunay
                   ` (3 preceding siblings ...)
  2020-03-18  8:24 ` [PATCH 04/18] stm32mp: add the command stm32prog Patrick Delaunay
@ 2020-03-18  8:24 ` Patrick Delaunay
  2020-04-14 13:03   ` Patrice CHOTARD
  2020-03-18  8:24 ` [PATCH 06/18] stm32mp: stm32prog: add MMC device Patrick Delaunay
                   ` (13 subsequent siblings)
  18 siblings, 1 reply; 40+ messages in thread
From: Patrick Delaunay @ 2020-03-18  8:24 UTC (permalink / raw)
  To: u-boot

Build the list of device and of partition with
a tab separated value file with a stm32 header: the FlashLayout.tsv
(https://wiki.st.com/stm32mpu/wiki/STM32CubeProgrammer_flashlayout)

Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
---

 .../mach-stm32mp/cmd_stm32prog/stm32prog.c    | 372 +++++++++++++++++-
 1 file changed, 371 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
index e2c6c43d88..11fe479072 100644
--- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
@@ -24,6 +24,17 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+/* order of column in flash layout file */
+enum stm32prog_col_t {
+	COL_OPTION,
+	COL_ID,
+	COL_NAME,
+	COL_TYPE,
+	COL_IP,
+	COL_OFFSET,
+	COL_NB_STM32
+};
+
 char *stm32prog_get_error(struct stm32prog_data *data)
 {
 	static const char error_msg[] = "Unspecified";
@@ -34,11 +45,370 @@ char *stm32prog_get_error(struct stm32prog_data *data)
 	return data->error;
 }
 
+u8 stm32prog_header_check(struct raw_header_s *raw_header,
+			  struct image_header_s *header)
+{
+	unsigned int i;
+
+	header->present = 0;
+	header->image_checksum = 0x0;
+	header->image_length = 0x0;
+
+	if (!raw_header || !header) {
+		pr_debug("%s:no header data\n", __func__);
+		return -1;
+	}
+	if (raw_header->magic_number !=
+		(('S' << 0) | ('T' << 8) | ('M' << 16) | (0x32 << 24))) {
+		pr_debug("%s:invalid magic number : 0x%x\n",
+			 __func__, raw_header->magic_number);
+		return -2;
+	}
+	/* only header v1.0 supported */
+	if (raw_header->header_version != 0x00010000) {
+		pr_debug("%s:invalid header version : 0x%x\n",
+			 __func__, raw_header->header_version);
+		return -3;
+	}
+	if (raw_header->reserved1 != 0x0 || raw_header->reserved2) {
+		pr_debug("%s:invalid reserved field\n", __func__);
+		return -4;
+	}
+	for (i = 0; i < (sizeof(raw_header->padding) / 4); i++) {
+		if (raw_header->padding[i] != 0) {
+			pr_debug("%s:invalid padding field\n", __func__);
+			return -5;
+		}
+	}
+	header->present = 1;
+	header->image_checksum = le32_to_cpu(raw_header->image_checksum);
+	header->image_length = le32_to_cpu(raw_header->image_length);
+
+	return 0;
+}
+
+static u32 stm32prog_header_checksum(u32 addr, struct image_header_s *header)
+{
+	u32 i, checksum;
+	u8 *payload;
+
+	/* compute checksum on payload */
+	payload = (u8 *)addr;
+	checksum = 0;
+	for (i = header->image_length; i > 0; i--)
+		checksum += *(payload++);
+
+	return checksum;
+}
+
+/* FLASHLAYOUT PARSING *****************************************/
+static int parse_option(struct stm32prog_data *data,
+			int i, char *p, struct stm32prog_part_t *part)
+{
+	int result = 0;
+	char *c = p;
+
+	part->option = 0;
+	if (!strcmp(p, "-"))
+		return 0;
+
+	while (*c) {
+		switch (*c) {
+		case 'P':
+			part->option |= OPT_SELECT;
+			break;
+		case 'E':
+			part->option |= OPT_EMPTY;
+			break;
+		default:
+			result = -EINVAL;
+			stm32prog_err("Layout line %d: invalid option '%c' in %s)",
+				      i, *c, p);
+			return -EINVAL;
+		}
+		c++;
+	}
+	if (!(part->option & OPT_SELECT)) {
+		stm32prog_err("Layout line %d: missing 'P' in option %s", i, p);
+		return -EINVAL;
+	}
+
+	return result;
+}
+
+static int parse_id(struct stm32prog_data *data,
+		    int i, char *p, struct stm32prog_part_t *part)
+{
+	int result = 0;
+	unsigned long value;
+
+	result = strict_strtoul(p, 0, &value);
+	part->id = value;
+	if (result || value > PHASE_LAST_USER) {
+		stm32prog_err("Layout line %d: invalid phase value = %s", i, p);
+		result = -EINVAL;
+	}
+
+	return result;
+}
+
+static int parse_name(struct stm32prog_data *data,
+		      int i, char *p, struct stm32prog_part_t *part)
+{
+	int result = 0;
+
+	if (strlen(p) < sizeof(part->name)) {
+		strcpy(part->name, p);
+	} else {
+		stm32prog_err("Layout line %d: partition name too long [%d]: %s",
+			      i, strlen(p), p);
+		result = -EINVAL;
+	}
+
+	return result;
+}
+
+static int parse_type(struct stm32prog_data *data,
+		      int i, char *p, struct stm32prog_part_t *part)
+{
+	int result = 0;
+
+	if (!strcmp(p, "Binary")) {
+		part->part_type = PART_BINARY;
+	} else if (!strcmp(p, "System")) {
+		part->part_type = PART_SYSTEM;
+	} else if (!strcmp(p, "FileSystem")) {
+		part->part_type = PART_FILESYSTEM;
+	} else if (!strcmp(p, "RawImage")) {
+		part->part_type = RAW_IMAGE;
+	} else {
+		result = -EINVAL;
+	}
+	if (result)
+		stm32prog_err("Layout line %d: type parsing error : '%s'",
+			      i, p);
+
+	return result;
+}
+
+static int parse_ip(struct stm32prog_data *data,
+		    int i, char *p, struct stm32prog_part_t *part)
+{
+	int result = 0;
+	unsigned int len = 0;
+
+	part->dev_id = 0;
+	if (!strcmp(p, "none")) {
+		part->target = STM32PROG_NONE;
+	} else {
+		result = -EINVAL;
+	}
+	if (len) {
+		/* only one digit allowed for device id */
+		if (strlen(p) != len + 1) {
+			result = -EINVAL;
+		} else {
+			part->dev_id = p[len] - '0';
+			if (part->dev_id > 9)
+				result = -EINVAL;
+		}
+	}
+	if (result)
+		stm32prog_err("Layout line %d: ip parsing error: '%s'", i, p);
+
+	return result;
+}
+
+static int parse_offset(struct stm32prog_data *data,
+			int i, char *p, struct stm32prog_part_t *part)
+{
+	int result = 0;
+	char *tail;
+
+	part->part_id = 0;
+	part->size = 0;
+	part->addr = simple_strtoull(p, &tail, 0);
+	if (tail == p || *tail != '\0') {
+		stm32prog_err("Layout line %d: invalid offset '%s'",
+			      i, p);
+		result = -EINVAL;
+	}
+
+	return result;
+}
+
+static
+int (* const parse[COL_NB_STM32])(struct stm32prog_data *data, int i, char *p,
+				  struct stm32prog_part_t *part) = {
+	[COL_OPTION] = parse_option,
+	[COL_ID] = parse_id,
+	[COL_NAME] =  parse_name,
+	[COL_TYPE] = parse_type,
+	[COL_IP] = parse_ip,
+	[COL_OFFSET] = parse_offset,
+};
+
 static int parse_flash_layout(struct stm32prog_data *data,
 			      ulong addr,
 			      ulong size)
 {
-	return -ENODEV;
+	int column = 0, part_nb = 0, ret;
+	bool end_of_line, eof;
+	char *p, *start, *last, *col;
+	struct stm32prog_part_t *part;
+	int part_list_size;
+	int i;
+
+	data->part_nb = 0;
+
+	/* check if STM32image is detected */
+	if (!stm32prog_header_check((struct raw_header_s *)addr,
+				    &data->header)) {
+		u32 checksum;
+
+		addr = addr + BL_HEADER_SIZE;
+		size = data->header.image_length;
+
+		checksum = stm32prog_header_checksum(addr, &data->header);
+		if (checksum != data->header.image_checksum) {
+			stm32prog_err("Layout: invalid checksum : 0x%x expected 0x%x",
+				      checksum, data->header.image_checksum);
+			return -EIO;
+		}
+	}
+	if (!size)
+		return -EINVAL;
+
+	start = (char *)addr;
+	last = start + size;
+
+	*last = 0x0; /* force null terminated string */
+	pr_debug("flash layout =\n%s\n", start);
+
+	/* calculate expected number of partitions */
+	part_list_size = 1;
+	p = start;
+	while (*p && (p < last)) {
+		if (*p++ == '\n') {
+			part_list_size++;
+			if (p < last && *p == '#')
+				part_list_size--;
+		}
+	}
+	if (part_list_size > PHASE_LAST_USER) {
+		stm32prog_err("Layout: too many partition (%d)",
+			      part_list_size);
+		return -1;
+	}
+	part = calloc(sizeof(struct stm32prog_part_t), part_list_size);
+	if (!part) {
+		stm32prog_err("Layout: alloc failed");
+		return -ENOMEM;
+	}
+	data->part_array = part;
+
+	/* main parsing loop */
+	i = 1;
+	eof = false;
+	p = start;
+	col = start; /* 1st column */
+	end_of_line = false;
+	while (!eof) {
+		switch (*p) {
+		/* CR is ignored and replaced by NULL character */
+		case '\r':
+			*p = '\0';
+			p++;
+			continue;
+		case '\0':
+			end_of_line = true;
+			eof = true;
+			break;
+		case '\n':
+			end_of_line = true;
+			break;
+		case '\t':
+			break;
+		case '#':
+			/* comment line is skipped */
+			if (column == 0 && p == col) {
+				while ((p < last) && *p)
+					if (*p++ == '\n')
+						break;
+				col = p;
+				i++;
+				if (p >= last || !*p) {
+					eof = true;
+					end_of_line = true;
+				}
+				continue;
+			}
+			/* fall through */
+		/* by default continue with the next character */
+		default:
+			p++;
+			continue;
+		}
+
+		/* replace by \0: allow string parsing for each column */
+		*p = '\0';
+		p++;
+		if (p >= last) {
+			eof = true;
+			end_of_line = true;
+		}
+
+		/* skip empty line and multiple TAB in tsv file */
+		if (strlen(col) == 0) {
+			col = p;
+			/* skip empty line */
+			if (column == 0 && end_of_line) {
+				end_of_line = false;
+				i++;
+			}
+			continue;
+		}
+
+		if (column < COL_NB_STM32) {
+			ret = parse[column](data, i, col, part);
+			if (ret)
+				return ret;
+		}
+
+		/* save the beginning of the next column */
+		column++;
+		col = p;
+
+		if (!end_of_line)
+			continue;
+
+		/* end of the line detected */
+		end_of_line = false;
+
+		if (column < COL_NB_STM32) {
+			stm32prog_err("Layout line %d: no enought column", i);
+			return -EINVAL;
+		}
+		column = 0;
+		part_nb++;
+		part++;
+		i++;
+		if (part_nb >= part_list_size) {
+			part = NULL;
+			if (!eof) {
+				stm32prog_err("Layout: no enought memory for %d part",
+					      part_nb);
+				return -EINVAL;
+			}
+		}
+	}
+	data->part_nb = part_nb;
+	if (data->part_nb == 0) {
+		stm32prog_err("Layout: no partition found");
+		return -ENODEV;
+	}
+
+	return 0;
 }
 
 static int __init part_cmp(void *priv, struct list_head *a, struct list_head *b)
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 06/18] stm32mp: stm32prog: add MMC device
  2020-03-18  8:24 [PATCH 00/18] stm32mp1: add command stm32prog Patrick Delaunay
                   ` (4 preceding siblings ...)
  2020-03-18  8:24 ` [PATCH 05/18] stm32mp: stm32prog: add flash layout parsing Patrick Delaunay
@ 2020-03-18  8:24 ` Patrick Delaunay
  2020-04-14 13:04   ` Patrice CHOTARD
  2020-04-14 13:04   ` Patrice CHOTARD
  2020-03-18  8:24 ` [PATCH 07/18] stm32mp: stm32prog: add support of boot partition for eMMC device Patrick Delaunay
                   ` (12 subsequent siblings)
  18 siblings, 2 replies; 40+ messages in thread
From: Patrick Delaunay @ 2020-03-18  8:24 UTC (permalink / raw)
  To: u-boot

Add support of MMC device (based on DFU_MMC backend)
for SD card and eMMC update.

Create a GPT partitioning on the device.

Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
---

 arch/arm/mach-stm32mp/Kconfig                 |   3 +
 .../mach-stm32mp/cmd_stm32prog/stm32prog.c    | 204 +++++++++++++++++-
 .../mach-stm32mp/cmd_stm32prog/stm32prog.h    |   3 +
 configs/stm32mp15_basic_defconfig             |   2 -
 configs/stm32mp15_trusted_defconfig           |   2 -
 5 files changed, 209 insertions(+), 5 deletions(-)

diff --git a/arch/arm/mach-stm32mp/Kconfig b/arch/arm/mach-stm32mp/Kconfig
index 61466f6125..39504e8540 100644
--- a/arch/arm/mach-stm32mp/Kconfig
+++ b/arch/arm/mach-stm32mp/Kconfig
@@ -119,6 +119,9 @@ config CMD_STM32PROG
 	select DFU
 	select DFU_RAM
 	select DFU_VIRT
+	select PARTITION_TYPE_GUID
+	imply CMD_GPT if MMC
+	imply DFU_MMC if MMC
 	help
 		activate a specific command stm32prog for STM32MP soc family
 		witch update the device with the tools STM32CubeProgrammer,
diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
index 11fe479072..feb83670b5 100644
--- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
@@ -7,6 +7,7 @@
 #include <console.h>
 #include <dfu.h>
 #include <malloc.h>
+#include <mmc.h>
 #include <dm/uclass.h>
 #include <linux/list.h>
 #include <linux/list_sort.h>
@@ -14,6 +15,9 @@
 
 #include "stm32prog.h"
 
+/* Primary GPT header size for 128 entries : 17kB = 34 LBA of 512B */
+#define GPT_HEADER_SZ	34
+
 #define OPT_SELECT	BIT(0)
 #define OPT_EMPTY	BIT(1)
 
@@ -22,6 +26,32 @@
 
 #define ALT_BUF_LEN			SZ_1K
 
+#define ROOTFS_MMC0_UUID \
+	EFI_GUID(0xE91C4E10, 0x16E6, 0x4C0E, \
+		 0xBD, 0x0E, 0x77, 0xBE, 0xCF, 0x4A, 0x35, 0x82)
+
+#define ROOTFS_MMC1_UUID \
+	EFI_GUID(0x491F6117, 0x415D, 0x4F53, \
+		 0x88, 0xC9, 0x6E, 0x0D, 0xE5, 0x4D, 0xEA, 0xC6)
+
+#define ROOTFS_MMC2_UUID \
+	EFI_GUID(0xFD58F1C7, 0xBE0D, 0x4338, \
+		 0x88, 0xE9, 0xAD, 0x8F, 0x05, 0x0A, 0xEB, 0x18)
+
+/* RAW parttion (binary / bootloader) used Linux - reserved UUID */
+#define LINUX_RESERVED_UUID "8DA63339-0007-60C0-C436-083AC8230908"
+
+/*
+ * unique partition guid (uuid) for partition named "rootfs"
+ * on each MMC instance = SD Card or eMMC
+ * allow fixed kernel bootcmd: "rootf=PARTUID=e91c4e10-..."
+ */
+static const efi_guid_t uuid_mmc[3] = {
+	ROOTFS_MMC0_UUID,
+	ROOTFS_MMC1_UUID,
+	ROOTFS_MMC2_UUID
+};
+
 DECLARE_GLOBAL_DATA_PTR;
 
 /* order of column in flash layout file */
@@ -200,6 +230,9 @@ static int parse_ip(struct stm32prog_data *data,
 	part->dev_id = 0;
 	if (!strcmp(p, "none")) {
 		part->target = STM32PROG_NONE;
+	} else if (!strncmp(p, "mmc", 3)) {
+		part->target = STM32PROG_MMC;
+		len = 3;
 	} else {
 		result = -EINVAL;
 	}
@@ -424,16 +457,50 @@ static int __init part_cmp(void *priv, struct list_head *a, struct list_head *b)
 static int init_device(struct stm32prog_data *data,
 		       struct stm32prog_dev_t *dev)
 {
+	struct mmc *mmc = NULL;
 	struct blk_desc *block_dev = NULL;
 	int part_id;
 	u64 first_addr = 0, last_addr = 0;
 	struct stm32prog_part_t *part, *next_part;
 
 	switch (dev->target) {
+#ifdef CONFIG_MMC
+	case STM32PROG_MMC:
+		mmc = find_mmc_device(dev->dev_id);
+		if (mmc_init(mmc)) {
+			stm32prog_err("mmc device %d not found", dev->dev_id);
+			return -ENODEV;
+		}
+		block_dev = mmc_get_blk_desc(mmc);
+		if (!block_dev) {
+			stm32prog_err("mmc device %d not probed", dev->dev_id);
+			return -ENODEV;
+		}
+		dev->erase_size = mmc->erase_grp_size * block_dev->blksz;
+		dev->mmc = mmc;
+
+		/* reserve a full erase group for each GTP headers */
+		if (mmc->erase_grp_size > GPT_HEADER_SZ) {
+			first_addr = dev->erase_size;
+			last_addr = (u64)(block_dev->lba -
+					  mmc->erase_grp_size) *
+				    block_dev->blksz;
+		} else {
+			first_addr = (u64)GPT_HEADER_SZ * block_dev->blksz;
+			last_addr = (u64)(block_dev->lba - GPT_HEADER_SZ - 1) *
+				    block_dev->blksz;
+		}
+		pr_debug("MMC %d: lba=%ld blksz=%ld\n", dev->dev_id,
+			 block_dev->lba, block_dev->blksz);
+		pr_debug(" available address = 0x%llx..0x%llx\n",
+			 first_addr, last_addr);
+		break;
+#endif
 	default:
 		stm32prog_err("unknown device type = %d", dev->target);
 		return -ENODEV;
 	}
+	pr_debug(" erase size = 0x%x\n", dev->erase_size);
 
 	/* order partition list in offset order */
 	list_sort(NULL, &dev->part_list, &part_cmp);
@@ -491,6 +558,12 @@ static int init_device(struct stm32prog_data *data,
 			return -EINVAL;
 		}
 
+		if ((part->addr & ((u64)part->dev->erase_size - 1)) != 0) {
+			stm32prog_err("%s (0x%x): not aligned address : 0x%llx on erase size 0x%x",
+				      part->name, part->id, part->addr,
+				      part->dev->erase_size);
+			return -EINVAL;
+		}
 		pr_debug("%02d : %1d %02x %14s %02d %02d.%02d %08llx %08llx",
 			 part->part_id, part->option, part->id, part->name,
 			 part->part_type, part->target,
@@ -559,6 +632,118 @@ static int treat_partition_list(struct stm32prog_data *data)
 	return 0;
 }
 
+static int create_partitions(struct stm32prog_data *data)
+{
+#ifdef CONFIG_MMC
+	int offset = 0;
+	const int buflen = SZ_8K;
+	char *buf;
+	char uuid[UUID_STR_LEN + 1];
+	unsigned char *uuid_bin;
+	unsigned int mmc_id;
+	int i;
+	bool rootfs_found;
+	struct stm32prog_part_t *part;
+
+	buf = malloc(buflen);
+	if (!buf)
+		return -ENOMEM;
+
+	puts("partitions : ");
+	/* initialize the selected device */
+	for (i = 0; i < data->dev_nb; i++) {
+		offset = 0;
+		rootfs_found = false;
+		memset(buf, 0, buflen);
+
+		list_for_each_entry(part, &data->dev[i].part_list, list) {
+			/* skip Raw Image */
+			if (part->part_type == RAW_IMAGE)
+				continue;
+
+			if (offset + 100 > buflen) {
+				pr_debug("\n%s: buffer too small, %s skippped",
+					 __func__, part->name);
+				continue;
+			}
+
+			if (!offset)
+				offset += sprintf(buf, "gpt write mmc %d \"",
+						  data->dev[i].dev_id);
+
+			offset += snprintf(buf + offset, buflen - offset,
+					   "name=%s,start=0x%llx,size=0x%llx",
+					   part->name,
+					   part->addr,
+					   part->size);
+
+			if (part->part_type == PART_BINARY)
+				offset += snprintf(buf + offset,
+						   buflen - offset,
+						   ",type="
+						   LINUX_RESERVED_UUID);
+			else
+				offset += snprintf(buf + offset,
+						   buflen - offset,
+						   ",type=linux");
+
+			if (part->part_type == PART_SYSTEM)
+				offset += snprintf(buf + offset,
+						   buflen - offset,
+						   ",bootable");
+
+			if (!rootfs_found && !strcmp(part->name, "rootfs")) {
+				mmc_id = part->dev_id;
+				rootfs_found = true;
+				if (mmc_id < ARRAY_SIZE(uuid_mmc)) {
+					uuid_bin =
+					  (unsigned char *)uuid_mmc[mmc_id].b;
+					uuid_bin_to_str(uuid_bin, uuid,
+							UUID_STR_FORMAT_GUID);
+					offset += snprintf(buf + offset,
+							   buflen - offset,
+							   ",uuid=%s", uuid);
+				}
+			}
+
+			offset += snprintf(buf + offset, buflen - offset, ";");
+		}
+
+		if (offset) {
+			offset += snprintf(buf + offset, buflen - offset, "\"");
+			pr_debug("\ncmd: %s\n", buf);
+			if (run_command(buf, 0)) {
+				stm32prog_err("GPT partitionning fail: %s",
+					      buf);
+				free(buf);
+
+				return -1;
+			}
+		}
+
+		if (data->dev[i].mmc)
+			part_init(mmc_get_blk_desc(data->dev[i].mmc));
+
+#ifdef DEBUG
+		sprintf(buf, "gpt verify mmc %d", data->dev[i].dev_id);
+		pr_debug("\ncmd: %s", buf);
+		if (run_command(buf, 0))
+			printf("fail !\n");
+		else
+			printf("OK\n");
+
+		sprintf(buf, "part list mmc %d", data->dev[i].dev_id);
+		run_command(buf, 0);
+#endif
+	}
+	puts("done\n");
+
+	free(buf);
+#endif
+
+	return 0;
+}
+
 static int stm32prog_alt_add(struct stm32prog_data *data,
 			     struct dfu_entity *dfu,
 			     struct stm32prog_part_t *part)
@@ -596,17 +781,30 @@ static int stm32prog_alt_add(struct stm32prog_data *data,
 	if (part->part_type == RAW_IMAGE) {
 		u64 dfu_size;
 
-		dfu_size = part->size;
+		if (part->dev->target == STM32PROG_MMC)
+			dfu_size = part->size / part->dev->mmc->read_bl_len;
+		else
+			dfu_size = part->size;
 		offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
 				   "raw 0x0 0x%llx", dfu_size);
 	} else {
 		offset += snprintf(buf + offset,
 				   ALT_BUF_LEN - offset,
 				   "part");
+		/* dev_id requested by DFU MMC */
+		if (part->target == STM32PROG_MMC)
+			offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
+					   " %d", part->dev_id);
 		offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
 				   " %d;", part->part_id);
 	}
 	switch (part->target) {
+#ifdef CONFIG_MMC
+	case STM32PROG_MMC:
+		sprintf(dfustr, "mmc");
+		sprintf(devstr, "%d", part->dev_id);
+		break;
+#endif
 	default:
 		stm32prog_err("invalid target: %d", part->target);
 		return -ENODEV;
@@ -775,6 +973,10 @@ static void stm32prog_devices_init(struct stm32prog_data *data)
 			goto error;
 	}
 
+	ret = create_partitions(data);
+	if (ret)
+		goto error;
+
 	return;
 
 error:
diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
index b44b6f89af..228a25d37f 100644
--- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
@@ -19,6 +19,7 @@
 
 enum stm32prog_target {
 	STM32PROG_NONE,
+	STM32PROG_MMC,
 };
 
 enum stm32prog_link_t {
@@ -64,6 +65,8 @@ enum stm32prog_part_type {
 struct stm32prog_dev_t {
 	enum stm32prog_target	target;
 	char			dev_id;
+	u32			erase_size;
+	struct mmc		*mmc;
 	/* list of partition for this device / ordered in offset */
 	struct list_head	part_list;
 };
diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig
index baed3d92f5..2e7d8bc990 100644
--- a/configs/stm32mp15_basic_defconfig
+++ b/configs/stm32mp15_basic_defconfig
@@ -35,7 +35,6 @@ CONFIG_CMD_CLK=y
 CONFIG_CMD_DFU=y
 CONFIG_CMD_FUSE=y
 CONFIG_CMD_GPIO=y
-CONFIG_CMD_GPT=y
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y
 CONFIG_CMD_MTD=y
@@ -68,7 +67,6 @@ CONFIG_ENV_UBI_VOLUME="uboot_config"
 CONFIG_ENV_UBI_VOLUME_REDUND="uboot_config_r"
 CONFIG_SYS_RELOC_GD_ENV_ADDR=y
 CONFIG_STM32_ADC=y
-CONFIG_DFU_MMC=y
 CONFIG_DFU_MTD=y
 CONFIG_SET_DFU_ALT_INFO=y
 CONFIG_USB_FUNCTION_FASTBOOT=y
diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig
index adbe304902..6f6c909da0 100644
--- a/configs/stm32mp15_trusted_defconfig
+++ b/configs/stm32mp15_trusted_defconfig
@@ -23,7 +23,6 @@ CONFIG_CMD_CLK=y
 CONFIG_CMD_DFU=y
 CONFIG_CMD_FUSE=y
 CONFIG_CMD_GPIO=y
-CONFIG_CMD_GPT=y
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y
 CONFIG_CMD_MTD=y
@@ -54,7 +53,6 @@ CONFIG_ENV_UBI_VOLUME="uboot_config"
 CONFIG_ENV_UBI_VOLUME_REDUND="uboot_config_r"
 CONFIG_SYS_RELOC_GD_ENV_ADDR=y
 CONFIG_STM32_ADC=y
-CONFIG_DFU_MMC=y
 CONFIG_DFU_MTD=y
 CONFIG_SET_DFU_ALT_INFO=y
 CONFIG_USB_FUNCTION_FASTBOOT=y
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 07/18] stm32mp: stm32prog: add support of boot partition for eMMC device
  2020-03-18  8:24 [PATCH 00/18] stm32mp1: add command stm32prog Patrick Delaunay
                   ` (5 preceding siblings ...)
  2020-03-18  8:24 ` [PATCH 06/18] stm32mp: stm32prog: add MMC device Patrick Delaunay
@ 2020-03-18  8:24 ` Patrick Delaunay
  2020-04-14 13:05   ` Patrice CHOTARD
  2020-03-18  8:24 ` [PATCH 08/18] stm32mp: stm32prog: add upport of partial update Patrick Delaunay
                   ` (11 subsequent siblings)
  18 siblings, 1 reply; 40+ messages in thread
From: Patrick Delaunay @ 2020-03-18  8:24 UTC (permalink / raw)
  To: u-boot

Add support of eMMC device boot partition with
part_id = -1 for offset="boot1"
     or = -2 for offset="boot2"

The stm32prog command configures the MMC DFU backend with "mmcpart"
and configure the eMMC (command "mmc bootbus" and "mmc partconf")
when the update is done.

Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
---

 .../mach-stm32mp/cmd_stm32prog/stm32prog.c    | 124 +++++++++++++-----
 .../mach-stm32mp/cmd_stm32prog/stm32prog.h    |   2 +-
 2 files changed, 90 insertions(+), 36 deletions(-)

diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
index feb83670b5..f63036606e 100644
--- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
@@ -259,12 +259,30 @@ static int parse_offset(struct stm32prog_data *data,
 	char *tail;
 
 	part->part_id = 0;
+	part->addr = 0;
 	part->size = 0;
-	part->addr = simple_strtoull(p, &tail, 0);
-	if (tail == p || *tail != '\0') {
-		stm32prog_err("Layout line %d: invalid offset '%s'",
-			      i, p);
-		result = -EINVAL;
+	/* eMMC boot parttion */
+	if (!strncmp(p, "boot", 4)) {
+		if (strlen(p) != 5) {
+			result = -EINVAL;
+		} else {
+			if (p[4] == '1')
+				part->part_id = -1;
+			else if (p[4] == '2')
+				part->part_id = -2;
+			else
+				result = -EINVAL;
+		}
+		if (result)
+			stm32prog_err("Layout line %d: invalid part '%s'",
+				      i, p);
+	} else {
+		part->addr = simple_strtoull(p, &tail, 0);
+		if (tail == p || *tail != '\0') {
+			stm32prog_err("Layout line %d: invalid offset '%s'",
+				      i, p);
+			result = -EINVAL;
+		}
 	}
 
 	return result;
@@ -451,7 +469,10 @@ static int __init part_cmp(void *priv, struct list_head *a, struct list_head *b)
 	parta = container_of(a, struct stm32prog_part_t, list);
 	partb = container_of(b, struct stm32prog_part_t, list);
 
-	return parta->addr > partb->addr ? 1 : -1;
+	if (parta->part_id != partb->part_id)
+		return parta->part_id - partb->part_id;
+	else
+		return parta->addr > partb->addr ? 1 : -1;
 }
 
 static int init_device(struct stm32prog_data *data,
@@ -520,44 +541,53 @@ static int init_device(struct stm32prog_data *data,
 				 part->dev_id, part->addr, part->size);
 			continue;
 		}
-
-		part->part_id = part_id++;
-
-		/* last partition : size to the end of the device */
-		if (part->list.next != &dev->part_list) {
-			next_part =
-				container_of(part->list.next,
-					     struct stm32prog_part_t,
-					     list);
-			if (part->addr < next_part->addr) {
-				part->size = next_part->addr -
-					     part->addr;
+		if (part->part_id < 0) { /* boot hw partition for eMMC */
+			if (mmc) {
+				part->size = mmc->capacity_boot;
 			} else {
-				stm32prog_err("%s (0x%x): same address : 0x%llx == %s (0x%x): 0x%llx",
+				stm32prog_err("%s (0x%x): hw partition not expected : %d",
 					      part->name, part->id,
-					      part->addr,
-					      next_part->name,
-					      next_part->id,
-					      next_part->addr);
-				return -EINVAL;
+					      part->part_id);
+				return -ENODEV;
 			}
 		} else {
-			if (part->addr <= last_addr) {
-				part->size = last_addr - part->addr;
+			part->part_id = part_id++;
+
+			/* last partition : size to the end of the device */
+			if (part->list.next != &dev->part_list) {
+				next_part =
+					container_of(part->list.next,
+						     struct stm32prog_part_t,
+						     list);
+				if (part->addr < next_part->addr) {
+					part->size = next_part->addr -
+						     part->addr;
+				} else {
+					stm32prog_err("%s (0x%x): same address : 0x%llx == %s (0x%x): 0x%llx",
+						      part->name, part->id,
+						      part->addr,
+						      next_part->name,
+						      next_part->id,
+						      next_part->addr);
+					return -EINVAL;
+				}
 			} else {
-				stm32prog_err("%s (0x%x): invalid address 0x%llx (max=0x%llx)",
+				if (part->addr <= last_addr) {
+					part->size = last_addr - part->addr;
+				} else {
+					stm32prog_err("%s (0x%x): invalid address 0x%llx (max=0x%llx)",
+						      part->name, part->id,
+						      part->addr, last_addr);
+					return -EINVAL;
+				}
+			}
+			if (part->addr < first_addr) {
+				stm32prog_err("%s (0x%x): invalid address 0x%llx (min=0x%llx)",
 					      part->name, part->id,
-					      part->addr, last_addr);
+					      part->addr, first_addr);
 				return -EINVAL;
 			}
 		}
-		if (part->addr < first_addr) {
-			stm32prog_err("%s (0x%x): invalid address 0x%llx (min=0x%llx)",
-				      part->name, part->id,
-				      part->addr, first_addr);
-			return -EINVAL;
-		}
-
 		if ((part->addr & ((u64)part->dev->erase_size - 1)) != 0) {
 			stm32prog_err("%s (0x%x): not aligned address : 0x%llx on erase size 0x%x",
 				      part->name, part->id, part->addr,
@@ -657,6 +687,9 @@ static int create_partitions(struct stm32prog_data *data)
 		memset(buf, 0, buflen);
 
 		list_for_each_entry(part, &data->dev[i].part_list, list) {
+			/* skip eMMC boot partitions */
+			if (part->part_id < 0)
+				continue;
 			/* skip Raw Image */
 			if (part->part_type == RAW_IMAGE)
 				continue;
@@ -787,6 +820,14 @@ static int stm32prog_alt_add(struct stm32prog_data *data,
 			dfu_size = part->size;
 		offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
 				   "raw 0x0 0x%llx", dfu_size);
+	} else if (part->part_id < 0) {
+		u64 nb_blk = part->size / part->dev->mmc->read_bl_len;
+
+		offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
+				   "raw 0x%llx 0x%llx",
+				   part->addr, nb_blk);
+		offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
+				   " mmcpart %d;", -(part->part_id));
 	} else {
 		offset += snprintf(buf + offset,
 				   ALT_BUF_LEN - offset,
@@ -908,6 +949,19 @@ static void stm32prog_end_phase(struct stm32prog_data *data)
 
 	if (!data->cur_part)
 		return;
+
+	if (CONFIG_IS_ENABLED(MMC) &&
+	    data->cur_part->part_id < 0) {
+		char cmdbuf[60];
+
+		sprintf(cmdbuf, "mmc bootbus %d 0 0 0; mmc partconf %d 1 %d 0",
+			data->cur_part->dev_id, data->cur_part->dev_id,
+			-(data->cur_part->part_id));
+		if (run_command(cmdbuf, 0)) {
+			stm32prog_err("commands '%s' failed", cmdbuf);
+			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 228a25d37f..6c3ad56a38 100644
--- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
@@ -89,7 +89,7 @@ struct stm32prog_part_t {
 
 	/* information on associated device */
 	struct stm32prog_dev_t	*dev;		/* pointer to device */
-	u16			part_id;	/* partition id in device */
+	s16			part_id;	/* partition id in device */
 	int			alt_id;		/* alt id in usb/dfu */
 
 	struct list_head	list;
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 08/18] stm32mp: stm32prog: add upport of partial update
  2020-03-18  8:24 [PATCH 00/18] stm32mp1: add command stm32prog Patrick Delaunay
                   ` (6 preceding siblings ...)
  2020-03-18  8:24 ` [PATCH 07/18] stm32mp: stm32prog: add support of boot partition for eMMC device Patrick Delaunay
@ 2020-03-18  8:24 ` Patrick Delaunay
  2020-04-14 13:05   ` Patrice CHOTARD
  2020-03-18  8:24 ` [PATCH 09/18] stm32mp: stm32prog: add MTD devices support Patrick Delaunay
                   ` (10 subsequent siblings)
  18 siblings, 1 reply; 40+ messages in thread
From: Patrick Delaunay @ 2020-03-18  8:24 UTC (permalink / raw)
  To: u-boot

Add support of partial update, update only some partitions,
and check the coherence of the layout with the existing GPT
partitions (offset and size).

Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
---

 .../mach-stm32mp/cmd_stm32prog/stm32prog.c    | 69 +++++++++++++++++++
 .../mach-stm32mp/cmd_stm32prog/stm32prog.h    |  1 +
 2 files changed, 70 insertions(+)

diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
index f63036606e..787bcdef7d 100644
--- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
@@ -481,8 +481,12 @@ static int init_device(struct stm32prog_data *data,
 	struct mmc *mmc = NULL;
 	struct blk_desc *block_dev = NULL;
 	int part_id;
+	int ret;
 	u64 first_addr = 0, last_addr = 0;
 	struct stm32prog_part_t *part, *next_part;
+	u64 part_addr, part_size;
+	bool part_found;
+	const char *part_name;
 
 	switch (dev->target) {
 #ifdef CONFIG_MMC
@@ -515,6 +519,7 @@ static int init_device(struct stm32prog_data *data,
 			 block_dev->lba, block_dev->blksz);
 		pr_debug(" available address = 0x%llx..0x%llx\n",
 			 first_addr, last_addr);
+		pr_debug(" full_update = %d\n", dev->full_update);
 		break;
 #endif
 	default:
@@ -522,6 +527,7 @@ static int init_device(struct stm32prog_data *data,
 		return -ENODEV;
 	}
 	pr_debug(" erase size = 0x%x\n", dev->erase_size);
+	pr_debug(" full_update = %d\n", dev->full_update);
 
 	/* order partition list in offset order */
 	list_sort(NULL, &dev->part_list, &part_cmp);
@@ -598,6 +604,61 @@ static int init_device(struct stm32prog_data *data,
 			 part->part_id, part->option, part->id, part->name,
 			 part->part_type, part->target,
 			 part->dev_id, part->addr, part->size);
+
+		part_addr = 0;
+		part_size = 0;
+		part_found = false;
+
+		/* check coherency with existing partition */
+		if (block_dev) {
+			/*
+			 * block devices with GPT: check user partition size
+			 * only for partial update, the GPT partions are be
+			 * created for full update
+			 */
+			if (dev->full_update || part->part_id < 0) {
+				pr_debug("\n");
+				continue;
+			}
+			disk_partition_t partinfo;
+
+			ret = part_get_info(block_dev, part->part_id,
+					    &partinfo);
+
+			if (ret) {
+				stm32prog_err("%s (0x%x):Couldn't find part %d on device mmc %d",
+					      part->name, part->id,
+					      part_id, part->dev_id);
+				return -ENODEV;
+			}
+			part_addr = (u64)partinfo.start * partinfo.blksz;
+			part_size = (u64)partinfo.size * partinfo.blksz;
+			part_name = (char *)partinfo.name;
+			part_found = true;
+		}
+
+		if (!part_found) {
+			stm32prog_err("%s (0x%x): Invalid partition",
+				      part->name, part->id);
+			pr_debug("\n");
+			continue;
+		}
+
+		pr_debug(" %08llx %08llx\n", part_addr, part_size);
+
+		if (part->addr != part_addr) {
+			stm32prog_err("%s (0x%x): Bad address for partition %d (%s) = 0x%llx <> 0x%llx expected",
+				      part->name, part->id, part->part_id,
+				      part_name, part->addr, part_addr);
+			return -ENODEV;
+		}
+		if (part->size != part_size) {
+			stm32prog_err("%s (0x%x): Bad size for partition %d (%s) at 0x%llx = 0x%llx <> 0x%llx expected",
+				      part->name, part->id, part->part_id,
+				      part_name, part->addr, part->size,
+				      part_size);
+			return -ENODEV;
+		}
 	}
 	return 0;
 }
@@ -644,6 +705,7 @@ static int treat_partition_list(struct stm32prog_data *data)
 				/* new device found */
 				data->dev[j].target = part->target;
 				data->dev[j].dev_id = part->dev_id;
+				data->dev[j].full_update = true;
 				data->dev_nb++;
 				break;
 			} else if ((part->target == data->dev[j].target) &&
@@ -656,6 +718,8 @@ static int treat_partition_list(struct stm32prog_data *data)
 			return -EINVAL;
 		}
 		part->dev = &data->dev[j];
+		if (!IS_SELECT(part))
+			part->dev->full_update = false;
 		list_add_tail(&part->list, &data->dev[j].part_list);
 	}
 
@@ -682,6 +746,11 @@ static int create_partitions(struct stm32prog_data *data)
 	puts("partitions : ");
 	/* initialize the selected device */
 	for (i = 0; i < data->dev_nb; i++) {
+		/* create gpt partition support only for full update on MMC */
+		if (data->dev[i].target != STM32PROG_MMC ||
+		    !data->dev[i].full_update)
+			continue;
+
 		offset = 0;
 		rootfs_found = false;
 		memset(buf, 0, buflen);
diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
index 6c3ad56a38..ea88459896 100644
--- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
@@ -69,6 +69,7 @@ struct stm32prog_dev_t {
 	struct mmc		*mmc;
 	/* list of partition for this device / ordered in offset */
 	struct list_head	part_list;
+	bool			full_update;
 };
 
 /* partition information build from FlashLayout and device */
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 09/18] stm32mp: stm32prog: add MTD devices support
  2020-03-18  8:24 [PATCH 00/18] stm32mp1: add command stm32prog Patrick Delaunay
                   ` (7 preceding siblings ...)
  2020-03-18  8:24 ` [PATCH 08/18] stm32mp: stm32prog: add upport of partial update Patrick Delaunay
@ 2020-03-18  8:24 ` Patrick Delaunay
  2020-04-14 13:06   ` Patrice CHOTARD
  2020-03-18  8:24 ` [PATCH 10/18] stm32mp: stm32prog: adapt the MTD partitions Patrick Delaunay
                   ` (9 subsequent siblings)
  18 siblings, 1 reply; 40+ messages in thread
From: Patrick Delaunay @ 2020-03-18  8:24 UTC (permalink / raw)
  To: u-boot

Add support of MTD device (DFU_MTD backend) for
NOR, NAND or SPI-NAND target.

Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
---

 arch/arm/mach-stm32mp/Kconfig                 |   2 +
 .../mach-stm32mp/cmd_stm32prog/stm32prog.c    | 114 +++++++++++++++++-
 .../mach-stm32mp/cmd_stm32prog/stm32prog.h    |   4 +
 configs/stm32mp15_basic_defconfig             |   2 -
 configs/stm32mp15_trusted_defconfig           |   2 -
 5 files changed, 117 insertions(+), 7 deletions(-)

diff --git a/arch/arm/mach-stm32mp/Kconfig b/arch/arm/mach-stm32mp/Kconfig
index 39504e8540..af16393152 100644
--- a/arch/arm/mach-stm32mp/Kconfig
+++ b/arch/arm/mach-stm32mp/Kconfig
@@ -121,7 +121,9 @@ config CMD_STM32PROG
 	select DFU_VIRT
 	select PARTITION_TYPE_GUID
 	imply CMD_GPT if MMC
+	imply CMD_MTD if MTD
 	imply DFU_MMC if MMC
+	imply DFU_MTD if MTD
 	help
 		activate a specific command stm32prog for STM32MP soc family
 		witch update the device with the tools STM32CubeProgrammer,
diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
index 787bcdef7d..93ee6a55a1 100644
--- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
@@ -8,9 +8,12 @@
 #include <dfu.h>
 #include <malloc.h>
 #include <mmc.h>
+#include <part.h>
 #include <dm/uclass.h>
+#include <jffs2/load_kernel.h>
 #include <linux/list.h>
 #include <linux/list_sort.h>
+#include <linux/mtd/mtd.h>
 #include <linux/sizes.h>
 
 #include "stm32prog.h"
@@ -65,6 +68,11 @@ enum stm32prog_col_t {
 	COL_NB_STM32
 };
 
+/* partition handling routines : CONFIG_CMD_MTDPARTS */
+int mtdparts_init(void);
+int find_dev_and_part(const char *id, struct mtd_device **dev,
+		      u8 *part_num, struct part_info **part);
+
 char *stm32prog_get_error(struct stm32prog_data *data)
 {
 	static const char error_msg[] = "Unspecified";
@@ -233,6 +241,15 @@ static int parse_ip(struct stm32prog_data *data,
 	} else if (!strncmp(p, "mmc", 3)) {
 		part->target = STM32PROG_MMC;
 		len = 3;
+	} else if (!strncmp(p, "nor", 3)) {
+		part->target = STM32PROG_NOR;
+		len = 3;
+	} else if (!strncmp(p, "nand", 4)) {
+		part->target = STM32PROG_NAND;
+		len = 4;
+	} else if (!strncmp(p, "spi-nand", 8)) {
+		part->target = STM32PROG_SPI_NAND;
+		len = 8;
 	} else {
 		result = -EINVAL;
 	}
@@ -475,11 +492,37 @@ static int __init part_cmp(void *priv, struct list_head *a, struct list_head *b)
 		return parta->addr > partb->addr ? 1 : -1;
 }
 
+static void get_mtd_by_target(char *string, enum stm32prog_target target,
+			      int dev_id)
+{
+	const char *dev_str;
+
+	switch (target) {
+	case STM32PROG_NOR:
+		dev_str = "nor";
+		break;
+	case STM32PROG_NAND:
+		dev_str = "nand";
+		break;
+	case STM32PROG_SPI_NAND:
+		dev_str = "spi-nand";
+		break;
+	default:
+		dev_str = "invalid";
+		break;
+	}
+	sprintf(string, "%s%d", dev_str, dev_id);
+}
+
 static int init_device(struct stm32prog_data *data,
 		       struct stm32prog_dev_t *dev)
 {
 	struct mmc *mmc = NULL;
 	struct blk_desc *block_dev = NULL;
+#ifdef CONFIG_MTD
+	struct mtd_info *mtd = NULL;
+	char mtd_id[16];
+#endif
 	int part_id;
 	int ret;
 	u64 first_addr = 0, last_addr = 0;
@@ -521,6 +564,29 @@ static int init_device(struct stm32prog_data *data,
 			 first_addr, last_addr);
 		pr_debug(" full_update = %d\n", dev->full_update);
 		break;
+#endif
+#ifdef CONFIG_MTD
+	case STM32PROG_NOR:
+	case STM32PROG_NAND:
+	case STM32PROG_SPI_NAND:
+		get_mtd_by_target(mtd_id, dev->target, dev->dev_id);
+		pr_debug("%s\n", mtd_id);
+
+		mtdparts_init();
+		mtd = get_mtd_device_nm(mtd_id);
+		if (IS_ERR(mtd)) {
+			stm32prog_err("MTD device %s not found", mtd_id);
+			return -ENODEV;
+		}
+		first_addr = 0;
+		last_addr = mtd->size;
+		dev->erase_size = mtd->erasesize;
+		pr_debug("MTD device %s: size=%lld erasesize=%d\n",
+			 mtd_id, mtd->size, mtd->erasesize);
+		pr_debug(" available address = 0x%llx..0x%llx\n",
+			 first_addr, last_addr);
+		dev->mtd = mtd;
+		break;
 #endif
 	default:
 		stm32prog_err("unknown device type = %d", dev->target);
@@ -637,6 +703,29 @@ static int init_device(struct stm32prog_data *data,
 			part_found = true;
 		}
 
+#ifdef CONFIG_MTD
+		if (mtd) {
+			char mtd_part_id[32];
+			struct part_info *mtd_part;
+			struct mtd_device *mtd_dev;
+			u8 part_num;
+
+			sprintf(mtd_part_id, "%s,%d", mtd_id,
+				part->part_id - 1);
+			ret = find_dev_and_part(mtd_part_id, &mtd_dev,
+						&part_num, &mtd_part);
+			if (ret != 0) {
+				stm32prog_err("%s (0x%x): Invalid MTD partition %s",
+					      part->name, part->id,
+					      mtd_part_id);
+				return -ENODEV;
+			}
+			part_addr = mtd_part->offset;
+			part_size = mtd_part->size;
+			part_name = mtd_part->name;
+			part_found = true;
+		}
+#endif
 		if (!part_found) {
 			stm32prog_err("%s (0x%x): Invalid partition",
 				      part->name, part->id);
@@ -840,6 +929,9 @@ static int create_partitions(struct stm32prog_data *data)
 	}
 	puts("done\n");
 
+#ifdef DEBUG
+	run_command("mtd list", 0);
+#endif
 	free(buf);
 #endif
 
@@ -898,9 +990,17 @@ static int stm32prog_alt_add(struct stm32prog_data *data,
 		offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
 				   " mmcpart %d;", -(part->part_id));
 	} else {
-		offset += snprintf(buf + offset,
-				   ALT_BUF_LEN - offset,
-				   "part");
+		if (part->part_type == PART_SYSTEM &&
+		    (part->target == STM32PROG_NAND ||
+		     part->target == STM32PROG_NOR ||
+		     part->target == STM32PROG_SPI_NAND))
+			offset += snprintf(buf + offset,
+					   ALT_BUF_LEN - offset,
+					   "partubi");
+		else
+			offset += snprintf(buf + offset,
+					   ALT_BUF_LEN - offset,
+					   "part");
 		/* dev_id requested by DFU MMC */
 		if (part->target == STM32PROG_MMC)
 			offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
@@ -914,6 +1014,14 @@ static int stm32prog_alt_add(struct stm32prog_data *data,
 		sprintf(dfustr, "mmc");
 		sprintf(devstr, "%d", part->dev_id);
 		break;
+#endif
+#ifdef CONFIG_MTD
+	case STM32PROG_NAND:
+	case STM32PROG_NOR:
+	case STM32PROG_SPI_NAND:
+		sprintf(dfustr, "mtd");
+		get_mtd_by_target(devstr, part->target, part->dev_id);
+		break;
 #endif
 	default:
 		stm32prog_err("invalid target: %d", part->target);
diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
index ea88459896..8e635da3a4 100644
--- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
@@ -20,6 +20,9 @@
 enum stm32prog_target {
 	STM32PROG_NONE,
 	STM32PROG_MMC,
+	STM32PROG_NAND,
+	STM32PROG_NOR,
+	STM32PROG_SPI_NAND
 };
 
 enum stm32prog_link_t {
@@ -67,6 +70,7 @@ struct stm32prog_dev_t {
 	char			dev_id;
 	u32			erase_size;
 	struct mmc		*mmc;
+	struct mtd_info		*mtd;
 	/* list of partition for this device / ordered in offset */
 	struct list_head	part_list;
 	bool			full_update;
diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig
index 2e7d8bc990..7837cbe9c7 100644
--- a/configs/stm32mp15_basic_defconfig
+++ b/configs/stm32mp15_basic_defconfig
@@ -37,7 +37,6 @@ CONFIG_CMD_FUSE=y
 CONFIG_CMD_GPIO=y
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y
-CONFIG_CMD_MTD=y
 CONFIG_CMD_REMOTEPROC=y
 CONFIG_CMD_SPI=y
 CONFIG_CMD_USB=y
@@ -67,7 +66,6 @@ CONFIG_ENV_UBI_VOLUME="uboot_config"
 CONFIG_ENV_UBI_VOLUME_REDUND="uboot_config_r"
 CONFIG_SYS_RELOC_GD_ENV_ADDR=y
 CONFIG_STM32_ADC=y
-CONFIG_DFU_MTD=y
 CONFIG_SET_DFU_ALT_INFO=y
 CONFIG_USB_FUNCTION_FASTBOOT=y
 CONFIG_FASTBOOT_BUF_ADDR=0xC0000000
diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig
index 6f6c909da0..e5b1ab5d04 100644
--- a/configs/stm32mp15_trusted_defconfig
+++ b/configs/stm32mp15_trusted_defconfig
@@ -25,7 +25,6 @@ CONFIG_CMD_FUSE=y
 CONFIG_CMD_GPIO=y
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y
-CONFIG_CMD_MTD=y
 CONFIG_CMD_REMOTEPROC=y
 CONFIG_CMD_SPI=y
 CONFIG_CMD_USB=y
@@ -53,7 +52,6 @@ CONFIG_ENV_UBI_VOLUME="uboot_config"
 CONFIG_ENV_UBI_VOLUME_REDUND="uboot_config_r"
 CONFIG_SYS_RELOC_GD_ENV_ADDR=y
 CONFIG_STM32_ADC=y
-CONFIG_DFU_MTD=y
 CONFIG_SET_DFU_ALT_INFO=y
 CONFIG_USB_FUNCTION_FASTBOOT=y
 CONFIG_FASTBOOT_BUF_ADDR=0xC0000000
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 10/18] stm32mp: stm32prog: adapt the MTD partitions
  2020-03-18  8:24 [PATCH 00/18] stm32mp1: add command stm32prog Patrick Delaunay
                   ` (8 preceding siblings ...)
  2020-03-18  8:24 ` [PATCH 09/18] stm32mp: stm32prog: add MTD devices support Patrick Delaunay
@ 2020-03-18  8:24 ` Patrick Delaunay
  2020-04-14 13:07   ` Patrice CHOTARD
  2020-03-18  8:24 ` [PATCH 11/18] stm32mp: stm32prog: add support of ssbl copy Patrick Delaunay
                   ` (8 subsequent siblings)
  18 siblings, 1 reply; 40+ messages in thread
From: Patrick Delaunay @ 2020-03-18  8:24 UTC (permalink / raw)
  To: u-boot

Dynamically adapt the MTD partitions in NOR/NAND/SPI-NAND when stm32prog
command detects in the parsed flash layout files:
- a fsbl partition in NOR.
- a tee partition in NOR/NAND/SPI-NAND

Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
---

 .../mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c  | 17 +++++++++++++++++
 arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c | 17 +++++++++++++++++
 arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h |  2 ++
 arch/arm/mach-stm32mp/include/mach/stm32prog.h  |  4 ++++
 board/st/common/stm32mp_mtdparts.c              | 14 ++++++++++++--
 5 files changed, 52 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
index 3e8b426444..581f97e0b5 100644
--- a/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
@@ -6,6 +6,7 @@
 #include <common.h>
 #include <command.h>
 #include <dfu.h>
+#include <asm/arch/stm32prog.h>
 #include "stm32prog.h"
 
 struct stm32prog_data *stm32prog_data;
@@ -94,3 +95,19 @@ U_BOOT_CMD(stm32prog, 5, 0, do_stm32prog,
 	   "<addr> = address of flashlayout\n"
 	   "<size> = size of flashlayout\n"
 );
+
+bool stm32prog_get_tee_partitions(void)
+{
+	if (stm32prog_data)
+		return stm32prog_data->tee_detected;
+
+	return false;
+}
+
+bool stm32prog_get_fsbl_nor(void)
+{
+	if (stm32prog_data)
+		return stm32prog_data->fsbl_nor_detected;
+
+	return false;
+}
diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
index 93ee6a55a1..0140fd479d 100644
--- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
@@ -762,6 +762,8 @@ static int treat_partition_list(struct stm32prog_data *data)
 		INIT_LIST_HEAD(&data->dev[j].part_list);
 	}
 
+	data->tee_detected = false;
+	data->fsbl_nor_detected = false;
 	for (i = 0; i < data->part_nb; i++) {
 		part = &data->part_array[i];
 		part->alt_id = -1;
@@ -806,6 +808,21 @@ static int treat_partition_list(struct stm32prog_data *data)
 			stm32prog_err("Layout: too many device");
 			return -EINVAL;
 		}
+		switch (part->target)  {
+		case STM32PROG_NOR:
+			if (!data->fsbl_nor_detected &&
+			    !strncmp(part->name, "fsbl", 4))
+				data->fsbl_nor_detected = true;
+			/* fallthrough */
+		case STM32PROG_NAND:
+		case STM32PROG_SPI_NAND:
+			if (!data->tee_detected &&
+			    !strncmp(part->name, "tee", 3))
+				data->tee_detected = true;
+			break;
+		default:
+			break;
+		}
 		part->dev = &data->dev[j];
 		if (!IS_SELECT(part))
 			part->dev->full_update = false;
diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
index 8e635da3a4..7f06627ebc 100644
--- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
@@ -107,6 +107,8 @@ struct stm32prog_data {
 	struct stm32prog_dev_t	dev[STM32PROG_MAX_DEV];	/* array of device */
 	int			part_nb;	/* nb of partition */
 	struct stm32prog_part_t	*part_array;	/* array of partition */
+	bool			tee_detected;
+	bool			fsbl_nor_detected;
 
 	/* command internal information */
 	unsigned int		phase;
diff --git a/arch/arm/mach-stm32mp/include/mach/stm32prog.h b/arch/arm/mach-stm32mp/include/mach/stm32prog.h
index c10bff09c8..c080b9cc42 100644
--- a/arch/arm/mach-stm32mp/include/mach/stm32prog.h
+++ b/arch/arm/mach-stm32mp/include/mach/stm32prog.h
@@ -10,3 +10,7 @@ int stm32prog_write_medium_virt(struct dfu_entity *dfu, u64 offset,
 int stm32prog_read_medium_virt(struct dfu_entity *dfu, u64 offset,
 			       void *buf, long *len);
 int stm32prog_get_medium_size_virt(struct dfu_entity *dfu, u64 *size);
+
+bool stm32prog_get_tee_partitions(void);
+
+bool stm32prog_get_fsbl_nor(void);
diff --git a/board/st/common/stm32mp_mtdparts.c b/board/st/common/stm32mp_mtdparts.c
index 5028511077..9f5897f8c8 100644
--- a/board/st/common/stm32mp_mtdparts.c
+++ b/board/st/common/stm32mp_mtdparts.c
@@ -4,12 +4,14 @@
  */
 
 #include <common.h>
+#include <dfu.h>
 #include <dm.h>
 #include <env.h>
 #include <env_internal.h>
 #include <mtd.h>
 #include <mtd_node.h>
 #include <tee.h>
+#include <asm/arch/stm32prog.h>
 #include <asm/arch/sys_proto.h>
 
 #define MTDPARTS_LEN		256
@@ -66,7 +68,7 @@ void board_mtdparts_default(const char **mtdids, const char **mtdparts)
 	static char parts[3 * MTDPARTS_LEN + 1];
 	static char ids[MTDIDS_LEN + 1];
 	static bool mtd_initialized;
-	bool tee, nor, nand, spinand;
+	bool tee, nor, nand, spinand, serial;
 
 	if (mtd_initialized) {
 		*mtdids = ids;
@@ -78,10 +80,18 @@ void board_mtdparts_default(const char **mtdids, const char **mtdparts)
 	nor = false;
 	nand = false;
 	spinand = false;
+	serial = false;
 
 	switch (get_bootmode() & TAMP_BOOT_DEVICE_MASK) {
 	case BOOT_SERIAL_UART:
 	case BOOT_SERIAL_USB:
+		serial = true;
+		if (CONFIG_IS_ENABLED(CMD_STM32PROG)) {
+			tee = stm32prog_get_tee_partitions();
+			nor = stm32prog_get_fsbl_nor();
+		}
+		nand = true;
+		spinand = true;
 		break;
 	case BOOT_FLASH_NAND:
 		nand = true;
@@ -96,7 +106,7 @@ void board_mtdparts_default(const char **mtdids, const char **mtdparts)
 		break;
 	}
 
-	if (CONFIG_IS_ENABLED(OPTEE) &&
+	if (!serial && CONFIG_IS_ENABLED(OPTEE) &&
 	    tee_find_device(NULL, NULL, NULL, NULL))
 		tee = true;
 
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 11/18] stm32mp: stm32prog: add support of ssbl copy
  2020-03-18  8:24 [PATCH 00/18] stm32mp1: add command stm32prog Patrick Delaunay
                   ` (9 preceding siblings ...)
  2020-03-18  8:24 ` [PATCH 10/18] stm32mp: stm32prog: adapt the MTD partitions Patrick Delaunay
@ 2020-03-18  8:24 ` Patrick Delaunay
  2020-04-14 13:07   ` Patrice CHOTARD
  2020-03-18  8:24 ` [PATCH 12/18] stm32mp: stm32prog: add support for delete option in flashlayout Patrick Delaunay
                   ` (7 subsequent siblings)
  18 siblings, 1 reply; 40+ messages in thread
From: Patrick Delaunay @ 2020-03-18  8:24 UTC (permalink / raw)
  To: u-boot

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>
---

 .../mach-stm32mp/cmd_stm32prog/stm32prog.c    | 98 ++++++++++++++++++-
 .../mach-stm32mp/cmd_stm32prog/stm32prog.h    |  1 +
 2 files changed, 94 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)
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 */
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 12/18] stm32mp: stm32prog: add support for delete option in flashlayout
  2020-03-18  8:24 [PATCH 00/18] stm32mp1: add command stm32prog Patrick Delaunay
                   ` (10 preceding siblings ...)
  2020-03-18  8:24 ` [PATCH 11/18] stm32mp: stm32prog: add support of ssbl copy Patrick Delaunay
@ 2020-03-18  8:24 ` Patrick Delaunay
  2020-04-14 13:08   ` Patrice CHOTARD
  2020-03-18  8:24 ` [PATCH 13/18] stm32mp: stm32prog: add otp update support Patrick Delaunay
                   ` (6 subsequent siblings)
  18 siblings, 1 reply; 40+ messages in thread
From: Patrick Delaunay @ 2020-03-18  8:24 UTC (permalink / raw)
  To: u-boot

Add support for delete option 'D' in flashlayout for
full device or for partitions

Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
---

 .../mach-stm32mp/cmd_stm32prog/stm32prog.c    | 105 ++++++++++++++++++
 1 file changed, 105 insertions(+)

diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
index 3e521d42f2..3573c04d16 100644
--- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
@@ -23,9 +23,11 @@
 
 #define OPT_SELECT	BIT(0)
 #define OPT_EMPTY	BIT(1)
+#define OPT_DELETE	BIT(2)
 
 #define IS_SELECT(part)	((part)->option & OPT_SELECT)
 #define IS_EMPTY(part)	((part)->option & OPT_EMPTY)
+#define IS_DELETE(part)	((part)->option & OPT_DELETE)
 
 #define ALT_BUF_LEN			SZ_1K
 
@@ -158,6 +160,9 @@ static int parse_option(struct stm32prog_data *data,
 		case 'E':
 			part->option |= OPT_EMPTY;
 			break;
+		case 'D':
+			part->option |= OPT_DELETE;
+			break;
 		default:
 			result = -EINVAL;
 			stm32prog_err("Layout line %d: invalid option '%c' in %s)",
@@ -1293,10 +1298,80 @@ void stm32prog_next_phase(struct stm32prog_data *data)
 		puts("Phase=END\n");
 }
 
+static int part_delete(struct stm32prog_data *data,
+		       struct stm32prog_part_t *part)
+{
+	int ret = 0;
+#ifdef CONFIG_MMC
+	unsigned long blks, blks_offset, blks_size;
+	struct blk_desc *block_dev = NULL;
+ #endif
+#ifdef CONFIG_MTD
+	char cmdbuf[40];
+	char devstr[10];
+#endif
+
+	printf("Erasing %s ", part->name);
+	switch (part->target) {
+#ifdef CONFIG_MMC
+	case STM32PROG_MMC:
+		printf("on mmc %d: ", part->dev->dev_id);
+		block_dev = mmc_get_blk_desc(part->dev->mmc);
+		blks_offset = lldiv(part->addr, part->dev->mmc->read_bl_len);
+		blks_size = lldiv(part->size, part->dev->mmc->read_bl_len);
+		/* -1 or -2 : delete boot partition of MMC
+		 * need to switch to associated hwpart 1 or 2
+		 */
+		if (part->part_id < 0)
+			if (blk_select_hwpart_devnum(IF_TYPE_MMC,
+						     part->dev->dev_id,
+						     -part->part_id))
+				return -1;
+
+		blks = blk_derase(block_dev, blks_offset, blks_size);
+
+		/* return to user partition */
+		if (part->part_id < 0)
+			blk_select_hwpart_devnum(IF_TYPE_MMC,
+						 part->dev->dev_id, 0);
+		if (blks != blks_size) {
+			ret = -1;
+			stm32prog_err("%s (0x%x): MMC erase failed",
+				      part->name, part->id);
+		}
+		break;
+#endif
+#ifdef CONFIG_MTD
+	case STM32PROG_NOR:
+	case STM32PROG_NAND:
+	case STM32PROG_SPI_NAND:
+		get_mtd_by_target(devstr, part->target, part->dev->dev_id);
+		printf("on %s: ", devstr);
+		sprintf(cmdbuf, "mtd erase %s 0x%llx 0x%llx",
+			devstr, part->addr, part->size);
+		if (run_command(cmdbuf, 0)) {
+			ret = -1;
+			stm32prog_err("%s (0x%x): MTD erase commands failed (%s)",
+				      part->name, part->id, cmdbuf);
+		}
+		break;
+#endif
+	default:
+		ret = -1;
+		stm32prog_err("%s (0x%x): erase invalid", part->name, part->id);
+		break;
+	}
+	if (!ret)
+		printf("done\n");
+
+	return ret;
+}
+
 static void stm32prog_devices_init(struct stm32prog_data *data)
 {
 	int i;
 	int ret;
+	struct stm32prog_part_t *part;
 
 	ret = treat_partition_list(data);
 	if (ret)
@@ -1309,10 +1384,40 @@ static void stm32prog_devices_init(struct stm32prog_data *data)
 			goto error;
 	}
 
+	/* delete RAW partition before create partition */
+	for (i = 0; i < data->part_nb; i++) {
+		part = &data->part_array[i];
+
+		if (part->part_type != RAW_IMAGE)
+			continue;
+
+		if (!IS_SELECT(part) || !IS_DELETE(part))
+			continue;
+
+		ret = part_delete(data, part);
+		if (ret)
+			goto error;
+	}
+
 	ret = create_partitions(data);
 	if (ret)
 		goto error;
 
+	/* delete partition GPT or MTD */
+	for (i = 0; i < data->part_nb; i++) {
+		part = &data->part_array[i];
+
+		if (part->part_type == RAW_IMAGE)
+			continue;
+
+		if (!IS_SELECT(part) || !IS_DELETE(part))
+			continue;
+
+		ret = part_delete(data, part);
+		if (ret)
+			goto error;
+	}
+
 	return;
 
 error:
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 13/18] stm32mp: stm32prog: add otp update support
  2020-03-18  8:24 [PATCH 00/18] stm32mp1: add command stm32prog Patrick Delaunay
                   ` (11 preceding siblings ...)
  2020-03-18  8:24 ` [PATCH 12/18] stm32mp: stm32prog: add support for delete option in flashlayout Patrick Delaunay
@ 2020-03-18  8:24 ` Patrick Delaunay
  2020-04-14 13:09   ` Patrice CHOTARD
  2020-03-18  8:24 ` [PATCH 14/18] stm32mp: stm32prog: add pmic NVM " Patrick Delaunay
                   ` (5 subsequent siblings)
  18 siblings, 1 reply; 40+ messages in thread
From: Patrick Delaunay @ 2020-03-18  8:24 UTC (permalink / raw)
  To: u-boot

Add a virtual partition to update the STM32MP15x OTP based
on SMC service provided by TF-A.

Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
---

 .../mach-stm32mp/cmd_stm32prog/stm32prog.c    | 130 +++++++++++++++++-
 .../mach-stm32mp/cmd_stm32prog/stm32prog.h    |  11 ++
 .../cmd_stm32prog/stm32prog_usb.c             |  11 ++
 3 files changed, 151 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
index 3573c04d16..cd826dbb9c 100644
--- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
@@ -9,6 +9,7 @@
 #include <malloc.h>
 #include <mmc.h>
 #include <part.h>
+#include <asm/arch/stm32mp1_smc.h>
 #include <dm/uclass.h>
 #include <jffs2/load_kernel.h>
 #include <linux/list.h>
@@ -1106,7 +1107,7 @@ static int dfu_init_entities(struct stm32prog_data *data)
 	struct dfu_entity *dfu;
 	int alt_nb;
 
-	alt_nb = 1; /* number of virtual = CMD */
+	alt_nb = 2; /* number of virtual = CMD, OTP*/
 	if (data->part_nb == 0)
 		alt_nb++;  /* +1 for FlashLayout */
 	else
@@ -1154,6 +1155,9 @@ static int dfu_init_entities(struct stm32prog_data *data)
 	if (!ret)
 		ret = stm32prog_alt_add_virt(dfu, "virtual", PHASE_CMD, 512);
 
+	if (!ret)
+		ret = stm32prog_alt_add_virt(dfu, "OTP", PHASE_OTP, 512);
+
 	if (ret)
 		stm32prog_err("dfu init failed: %d", ret);
 	puts("done\n");
@@ -1164,6 +1168,123 @@ static int dfu_init_entities(struct stm32prog_data *data)
 	return ret;
 }
 
+int stm32prog_otp_write(struct stm32prog_data *data, u32 offset, u8 *buffer,
+			long *size)
+{
+	pr_debug("%s: %x %lx\n", __func__, offset, *size);
+
+	if (!data->otp_part) {
+		data->otp_part = memalign(CONFIG_SYS_CACHELINE_SIZE, OTP_SIZE);
+		if (!data->otp_part)
+			return -ENOMEM;
+	}
+
+	if (!offset)
+		memset(data->otp_part, 0, OTP_SIZE);
+
+	if (offset + *size > OTP_SIZE)
+		*size = OTP_SIZE - offset;
+
+	memcpy((void *)((u32)data->otp_part + offset), buffer, *size);
+
+	return 0;
+}
+
+int stm32prog_otp_read(struct stm32prog_data *data, u32 offset, u8 *buffer,
+		       long *size)
+{
+#ifndef CONFIG_ARM_SMCCC
+	stm32prog_err("OTP update not supported");
+
+	return -1;
+#else
+	int result = 0;
+
+	pr_debug("%s: %x %lx\n", __func__, offset, *size);
+	/* alway read for first packet */
+	if (!offset) {
+		if (!data->otp_part)
+			data->otp_part =
+				memalign(CONFIG_SYS_CACHELINE_SIZE, OTP_SIZE);
+
+		if (!data->otp_part) {
+			result = -ENOMEM;
+			goto end_otp_read;
+		}
+
+		/* init struct with 0 */
+		memset(data->otp_part, 0, OTP_SIZE);
+
+		/* call the service */
+		result = stm32_smc_exec(STM32_SMC_BSEC, STM32_SMC_READ_ALL,
+					(u32)data->otp_part, 0);
+		if (result)
+			goto end_otp_read;
+	}
+
+	if (!data->otp_part) {
+		result = -ENOMEM;
+		goto end_otp_read;
+	}
+
+	if (offset + *size > OTP_SIZE)
+		*size = OTP_SIZE - offset;
+	memcpy(buffer, (void *)((u32)data->otp_part + offset), *size);
+
+end_otp_read:
+	pr_debug("%s: result %i\n", __func__, result);
+
+	return result;
+#endif
+}
+
+int stm32prog_otp_start(struct stm32prog_data *data)
+{
+#ifndef CONFIG_ARM_SMCCC
+	stm32prog_err("OTP update not supported");
+
+	return -1;
+#else
+	int result = 0;
+	struct arm_smccc_res res;
+
+	if (!data->otp_part) {
+		stm32prog_err("start OTP without data");
+		return -1;
+	}
+
+	arm_smccc_smc(STM32_SMC_BSEC, STM32_SMC_WRITE_ALL,
+		      (u32)data->otp_part, 0, 0, 0, 0, 0, &res);
+
+	if (!res.a0) {
+		switch (res.a1) {
+		case 0:
+			result = 0;
+			break;
+		case 1:
+			stm32prog_err("Provisioning");
+			result = 0;
+			break;
+		default:
+			pr_err("%s: OTP incorrect value (err = %ld)\n",
+			       __func__, res.a1);
+			result = -EINVAL;
+			break;
+		}
+	} else {
+		pr_err("%s: Failed to exec svc=%x op=%x in secure mode (err = %ld)\n",
+		       __func__, STM32_SMC_BSEC, STM32_SMC_WRITE_ALL, res.a0);
+		result = -EINVAL;
+	}
+
+	free(data->otp_part);
+	data->otp_part = NULL;
+	pr_debug("%s: result %i\n", __func__, result);
+
+	return result;
+#endif
+}
+
 /* copy FSBL on NAND to improve reliability on NAND */
 static int stm32prog_copy_fsbl(struct stm32prog_part_t *part)
 {
@@ -1451,6 +1572,7 @@ void stm32prog_clean(struct stm32prog_data *data)
 	/* clean */
 	dfu_free_entities();
 	free(data->part_array);
+	free(data->otp_part);
 	free(data->header_data);
 }
 
@@ -1460,6 +1582,12 @@ void dfu_flush_callback(struct dfu_entity *dfu)
 	if (!stm32prog_data)
 		return;
 
+	if (dfu->dev_type == DFU_DEV_VIRT) {
+		if (dfu->data.virt.dev_num == PHASE_OTP)
+			stm32prog_otp_start(stm32prog_data);
+		return;
+	}
+
 	if (dfu->dev_type == DFU_DEV_RAM) {
 		if (dfu->alt == 0 &&
 		    stm32prog_data->phase == PHASE_FLASHLAYOUT) {
diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
index 1880b163d7..6024657433 100644
--- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
@@ -11,12 +11,15 @@
 #define PHASE_FIRST_USER	0x10
 #define PHASE_LAST_USER		0xF0
 #define PHASE_CMD		0xF1
+#define PHASE_OTP		0xF2
 #define PHASE_END		0xFE
 #define PHASE_RESET		0xFF
 #define PHASE_DO_RESET		0x1FF
 
 #define DEFAULT_ADDRESS		0xFFFFFFFF
 
+#define OTP_SIZE		1024
+
 enum stm32prog_target {
 	STM32PROG_NONE,
 	STM32PROG_MMC,
@@ -116,6 +119,7 @@ struct stm32prog_data {
 	u32			offset;
 	char			error[255];
 	struct stm32prog_part_t	*cur_part;
+	u32			*otp_part;
 
 	/* STM32 header information */
 	struct raw_header_s	*header_data;
@@ -124,6 +128,13 @@ struct stm32prog_data {
 
 extern struct stm32prog_data *stm32prog_data;
 
+/* OTP access */
+int stm32prog_otp_write(struct stm32prog_data *data, u32 offset,
+			u8 *buffer, long *size);
+int stm32prog_otp_read(struct stm32prog_data *data, u32 offset,
+		       u8 *buffer, long *size);
+int stm32prog_otp_start(struct stm32prog_data *data);
+
 /* generic part*/
 u8 stm32prog_header_check(struct raw_header_s *raw_header,
 			  struct image_header_s *header);
diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c
index ed2cdbc66f..4a4b4d326b 100644
--- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c
@@ -130,6 +130,10 @@ int stm32prog_write_medium_virt(struct dfu_entity *dfu, u64 offset,
 	switch (dfu->data.virt.dev_num) {
 	case PHASE_CMD:
 		return stm32prog_cmd_write(offset, buf, len);
+
+	case PHASE_OTP:
+		return stm32prog_otp_write(stm32prog_data, (u32)offset,
+					   buf, len);
 	}
 	*len = 0;
 	return 0;
@@ -144,6 +148,10 @@ int stm32prog_read_medium_virt(struct dfu_entity *dfu, u64 offset,
 	switch (dfu->data.virt.dev_num) {
 	case PHASE_CMD:
 		return stm32prog_cmd_read(offset, buf, len);
+
+	case PHASE_OTP:
+		return stm32prog_otp_read(stm32prog_data, (u32)offset,
+					  buf, len);
 	}
 	*len = 0;
 	return 0;
@@ -162,6 +170,9 @@ int stm32prog_get_medium_size_virt(struct dfu_entity *dfu, u64 *size)
 	case PHASE_CMD:
 		*size = 512;
 		break;
+	case PHASE_OTP:
+		*size = OTP_SIZE;
+		break;
 	}
 
 	return 0;
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 14/18] stm32mp: stm32prog: add pmic NVM update support
  2020-03-18  8:24 [PATCH 00/18] stm32mp1: add command stm32prog Patrick Delaunay
                   ` (12 preceding siblings ...)
  2020-03-18  8:24 ` [PATCH 13/18] stm32mp: stm32prog: add otp update support Patrick Delaunay
@ 2020-03-18  8:24 ` Patrick Delaunay
  2020-04-14 13:09   ` Patrice CHOTARD
  2020-03-18  8:25 ` [PATCH 15/18] stm32mp: stm32prog: add serial link support Patrick Delaunay
                   ` (4 subsequent siblings)
  18 siblings, 1 reply; 40+ messages in thread
From: Patrick Delaunay @ 2020-03-18  8:24 UTC (permalink / raw)
  To: u-boot

Add a virtual partition to update the pmic non volatile memory.
(on ST board, STPMIC1).

Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
---

 .../mach-stm32mp/cmd_stm32prog/stm32prog.c    | 95 ++++++++++++++++++-
 .../mach-stm32mp/cmd_stm32prog/stm32prog.h    | 10 ++
 .../cmd_stm32prog/stm32prog_usb.c             | 11 +++
 3 files changed, 115 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
index cd826dbb9c..d127afefaa 100644
--- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
@@ -7,6 +7,7 @@
 #include <console.h>
 #include <dfu.h>
 #include <malloc.h>
+#include <misc.h>
 #include <mmc.h>
 #include <part.h>
 #include <asm/arch/stm32mp1_smc.h>
@@ -1107,7 +1108,7 @@ static int dfu_init_entities(struct stm32prog_data *data)
 	struct dfu_entity *dfu;
 	int alt_nb;
 
-	alt_nb = 2; /* number of virtual = CMD, OTP*/
+	alt_nb = 3; /* number of virtual = CMD, OTP, PMIC*/
 	if (data->part_nb == 0)
 		alt_nb++;  /* +1 for FlashLayout */
 	else
@@ -1158,6 +1159,9 @@ static int dfu_init_entities(struct stm32prog_data *data)
 	if (!ret)
 		ret = stm32prog_alt_add_virt(dfu, "OTP", PHASE_OTP, 512);
 
+	if (!ret && CONFIG_IS_ENABLED(DM_PMIC))
+		ret = stm32prog_alt_add_virt(dfu, "PMIC", PHASE_PMIC, 8);
+
 	if (ret)
 		stm32prog_err("dfu init failed: %d", ret);
 	puts("done\n");
@@ -1285,6 +1289,93 @@ int stm32prog_otp_start(struct stm32prog_data *data)
 #endif
 }
 
+int stm32prog_pmic_write(struct stm32prog_data *data, u32 offset, u8 *buffer,
+			 long *size)
+{
+	pr_debug("%s: %x %lx\n", __func__, offset, *size);
+
+	if (!offset)
+		memset(data->pmic_part, 0, PMIC_SIZE);
+
+	if (offset + *size > PMIC_SIZE)
+		*size = PMIC_SIZE - offset;
+
+	memcpy(&data->pmic_part[offset], buffer, *size);
+
+	return 0;
+}
+
+int stm32prog_pmic_read(struct stm32prog_data *data, u32 offset, u8 *buffer,
+			long *size)
+{
+	int result = 0, ret;
+	struct udevice *dev;
+
+	if (!CONFIG_IS_ENABLED(PMIC_STPMIC1)) {
+		stm32prog_err("PMIC update not supported");
+
+		return -EOPNOTSUPP;
+	}
+
+	pr_debug("%s: %x %lx\n", __func__, offset, *size);
+	ret = uclass_get_device_by_driver(UCLASS_MISC,
+					  DM_GET_DRIVER(stpmic1_nvm),
+					  &dev);
+	if (ret)
+		return ret;
+
+	/* alway request PMIC for first packet */
+	if (!offset) {
+		/* init struct with 0 */
+		memset(data->pmic_part, 0, PMIC_SIZE);
+
+		ret = uclass_get_device_by_driver(UCLASS_MISC,
+						  DM_GET_DRIVER(stpmic1_nvm),
+						  &dev);
+		if (ret)
+			return ret;
+
+		ret = misc_read(dev, 0xF8, data->pmic_part, PMIC_SIZE);
+		if (ret < 0) {
+			result = ret;
+			goto end_pmic_read;
+		}
+		if (ret != PMIC_SIZE) {
+			result = -EACCES;
+			goto end_pmic_read;
+		}
+	}
+
+	if (offset + *size > PMIC_SIZE)
+		*size = PMIC_SIZE - offset;
+
+	memcpy(buffer, &data->pmic_part[offset], *size);
+
+end_pmic_read:
+	pr_debug("%s: result %i\n", __func__, result);
+	return result;
+}
+
+int stm32prog_pmic_start(struct stm32prog_data *data)
+{
+	int ret;
+	struct udevice *dev;
+
+	if (!CONFIG_IS_ENABLED(PMIC_STPMIC1)) {
+		stm32prog_err("PMIC update not supported");
+
+		return -EOPNOTSUPP;
+	}
+
+	ret = uclass_get_device_by_driver(UCLASS_MISC,
+					  DM_GET_DRIVER(stpmic1_nvm),
+					  &dev);
+	if (ret)
+		return ret;
+
+	return misc_write(dev, 0xF8, data->pmic_part, PMIC_SIZE);
+}
+
 /* copy FSBL on NAND to improve reliability on NAND */
 static int stm32prog_copy_fsbl(struct stm32prog_part_t *part)
 {
@@ -1585,6 +1676,8 @@ void dfu_flush_callback(struct dfu_entity *dfu)
 	if (dfu->dev_type == DFU_DEV_VIRT) {
 		if (dfu->data.virt.dev_num == PHASE_OTP)
 			stm32prog_otp_start(stm32prog_data);
+		else if (dfu->data.virt.dev_num == PHASE_PMIC)
+			stm32prog_pmic_start(stm32prog_data);
 		return;
 	}
 
diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
index 6024657433..83b27980f5 100644
--- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
@@ -12,6 +12,7 @@
 #define PHASE_LAST_USER		0xF0
 #define PHASE_CMD		0xF1
 #define PHASE_OTP		0xF2
+#define PHASE_PMIC		0xF4
 #define PHASE_END		0xFE
 #define PHASE_RESET		0xFF
 #define PHASE_DO_RESET		0x1FF
@@ -19,6 +20,7 @@
 #define DEFAULT_ADDRESS		0xFFFFFFFF
 
 #define OTP_SIZE		1024
+#define PMIC_SIZE		8
 
 enum stm32prog_target {
 	STM32PROG_NONE,
@@ -120,6 +122,7 @@ struct stm32prog_data {
 	char			error[255];
 	struct stm32prog_part_t	*cur_part;
 	u32			*otp_part;
+	u8			pmic_part[PMIC_SIZE];
 
 	/* STM32 header information */
 	struct raw_header_s	*header_data;
@@ -135,6 +138,13 @@ int stm32prog_otp_read(struct stm32prog_data *data, u32 offset,
 		       u8 *buffer, long *size);
 int stm32prog_otp_start(struct stm32prog_data *data);
 
+/* PMIC access */
+int stm32prog_pmic_write(struct stm32prog_data *data, u32 offset,
+			 u8 *buffer, long *size);
+int stm32prog_pmic_read(struct stm32prog_data *data, u32 offset,
+			u8 *buffer, long *size);
+int stm32prog_pmic_start(struct stm32prog_data *data);
+
 /* generic part*/
 u8 stm32prog_header_check(struct raw_header_s *raw_header,
 			  struct image_header_s *header);
diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c
index 4a4b4d326b..34f27c074f 100644
--- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c
@@ -134,6 +134,10 @@ int stm32prog_write_medium_virt(struct dfu_entity *dfu, u64 offset,
 	case PHASE_OTP:
 		return stm32prog_otp_write(stm32prog_data, (u32)offset,
 					   buf, len);
+
+	case PHASE_PMIC:
+		return stm32prog_pmic_write(stm32prog_data, (u32)offset,
+					    buf, len);
 	}
 	*len = 0;
 	return 0;
@@ -152,6 +156,10 @@ int stm32prog_read_medium_virt(struct dfu_entity *dfu, u64 offset,
 	case PHASE_OTP:
 		return stm32prog_otp_read(stm32prog_data, (u32)offset,
 					  buf, len);
+
+	case PHASE_PMIC:
+		return stm32prog_pmic_read(stm32prog_data, (u32)offset,
+					   buf, len);
 	}
 	*len = 0;
 	return 0;
@@ -173,6 +181,9 @@ int stm32prog_get_medium_size_virt(struct dfu_entity *dfu, u64 *size)
 	case PHASE_OTP:
 		*size = OTP_SIZE;
 		break;
+	case PHASE_PMIC:
+		*size = PMIC_SIZE;
+		break;
 	}
 
 	return 0;
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 15/18] stm32mp: stm32prog: add serial link support
  2020-03-18  8:24 [PATCH 00/18] stm32mp1: add command stm32prog Patrick Delaunay
                   ` (13 preceding siblings ...)
  2020-03-18  8:24 ` [PATCH 14/18] stm32mp: stm32prog: add pmic NVM " Patrick Delaunay
@ 2020-03-18  8:25 ` Patrick Delaunay
  2020-04-14 13:10   ` Patrice CHOTARD
  2020-03-18  8:25 ` [PATCH 16/18] stm32mp: stm32prog: enable videoconsole Patrick Delaunay
                   ` (3 subsequent siblings)
  18 siblings, 1 reply; 40+ messages in thread
From: Patrick Delaunay @ 2020-03-18  8:25 UTC (permalink / raw)
  To: u-boot

Add a support of UART, using the same protocol than MCU STM32.

See "AN5275: USB DFU/USART protocols used in STM32MP1 Series
bootloaders" for details.

Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
---

 arch/arm/mach-stm32mp/cmd_stm32prog/Makefile  |   1 +
 .../cmd_stm32prog/cmd_stm32prog.c             |  11 +-
 .../mach-stm32mp/cmd_stm32prog/stm32prog.c    |   4 +
 .../mach-stm32mp/cmd_stm32prog/stm32prog.h    |  11 +
 .../cmd_stm32prog/stm32prog_serial.c          | 993 ++++++++++++++++++
 .../cmd_stm32prog/stm32prog_usb.c             |   2 +
 6 files changed, 1021 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c

diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/Makefile b/arch/arm/mach-stm32mp/cmd_stm32prog/Makefile
index 14f722759c..548a378921 100644
--- a/arch/arm/mach-stm32mp/cmd_stm32prog/Makefile
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/Makefile
@@ -5,4 +5,5 @@
 
 obj-y += cmd_stm32prog.o
 obj-y += stm32prog.o
+obj-y += stm32prog_serial.o
 obj-y += stm32prog_usb.o
diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
index 581f97e0b5..1769ba05f2 100644
--- a/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
@@ -25,11 +25,14 @@ static int do_stm32prog(cmd_tbl_t *cmdtp, int flag, int argc,
 
 	if (!strcmp(argv[1], "usb"))
 		link = LINK_USB;
+	else if (!strcmp(argv[1], "serial"))
+		link = LINK_SERIAL;
 
 	if (link == LINK_UNDEFINED) {
 		pr_err("not supported link=%s\n", argv[1]);
 		return CMD_RET_USAGE;
 	}
+
 	dev = (int)simple_strtoul(argv[2], NULL, 10);
 
 	addr = STM32_DDR_BASE;
@@ -60,6 +63,12 @@ static int do_stm32prog(cmd_tbl_t *cmdtp, int flag, int argc,
 		goto cleanup;
 
 	switch (link) {
+	case LINK_SERIAL:
+		ret = stm32prog_serial_init(data, dev);
+		if (ret)
+			goto cleanup;
+		reset = stm32prog_serial_loop(data);
+		break;
 	case LINK_USB:
 		reset = stm32prog_usb_loop(data, dev);
 		break;
@@ -90,7 +99,7 @@ cleanup:
 U_BOOT_CMD(stm32prog, 5, 0, do_stm32prog,
 	   "<link> <dev> [<addr>] [<size>]\n"
 	   "start communication with tools STM32Cubeprogrammer on <link> with Flashlayout at <addr>",
-	   "<link> = usb\n"
+	   "<link> = serial|usb\n"
 	   "<dev>  = device instance\n"
 	   "<addr> = address of flashlayout\n"
 	   "<size> = size of flashlayout\n"
diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
index d127afefaa..0967bbc11a 100644
--- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
@@ -1486,6 +1486,7 @@ void stm32prog_next_phase(struct stm32prog_data *data)
 	}
 
 	/* found next selected partition */
+	data->dfu_seq = 0;
 	data->cur_part = NULL;
 	data->phase = PHASE_END;
 	found = false;
@@ -1653,6 +1654,7 @@ int stm32prog_dfu_init(struct stm32prog_data *data)
 int stm32prog_init(struct stm32prog_data *data, ulong addr, ulong size)
 {
 	memset(data, 0x0, sizeof(*data));
+	data->read_phase = PHASE_RESET;
 	data->phase = PHASE_FLASHLAYOUT;
 
 	return parse_flash_layout(data, addr, size);
@@ -1664,6 +1666,7 @@ void stm32prog_clean(struct stm32prog_data *data)
 	dfu_free_entities();
 	free(data->part_array);
 	free(data->otp_part);
+	free(data->buffer);
 	free(data->header_data);
 }
 
@@ -1709,6 +1712,7 @@ void dfu_initiated_callback(struct dfu_entity *dfu)
 	/* force the saved offset for the current partition */
 	if (dfu->alt == stm32prog_data->cur_part->alt_id) {
 		dfu->offset = stm32prog_data->offset;
+		stm32prog_data->dfu_seq = 0;
 		pr_debug("dfu offset = 0x%llx\n", dfu->offset);
 	}
 }
diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
index 83b27980f5..c4fdb5b8c3 100644
--- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
@@ -31,6 +31,7 @@ enum stm32prog_target {
 };
 
 enum stm32prog_link_t {
+	LINK_SERIAL,
 	LINK_USB,
 	LINK_UNDEFINED,
 };
@@ -127,6 +128,14 @@ struct stm32prog_data {
 	/* STM32 header information */
 	struct raw_header_s	*header_data;
 	struct image_header_s	header;
+
+	/* SERIAL information */
+	u32	cursor;
+	u32	packet_number;
+	u32	checksum;
+	u8	*buffer; /* size = USART_RAM_BUFFER_SIZE*/
+	int	dfu_seq;
+	u8	read_phase;
 };
 
 extern struct stm32prog_data *stm32prog_data;
@@ -163,6 +172,8 @@ char *stm32prog_get_error(struct stm32prog_data *data);
 
 /* Main function */
 int stm32prog_init(struct stm32prog_data *data, ulong addr, ulong size);
+int stm32prog_serial_init(struct stm32prog_data *data, int link_dev);
+bool stm32prog_serial_loop(struct stm32prog_data *data);
 bool stm32prog_usb_loop(struct stm32prog_data *data, int dev);
 void stm32prog_clean(struct stm32prog_data *data);
 
diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c
new file mode 100644
index 0000000000..5a16979adc
--- /dev/null
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c
@@ -0,0 +1,993 @@
+// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
+/*
+ * Copyright (C) 2020, STMicroelectronics - All Rights Reserved
+ */
+
+#include <common.h>
+#include <console.h>
+#include <dfu.h>
+#include <malloc.h>
+#include <serial.h>
+#include <watchdog.h>
+#include <dm/lists.h>
+#include <dm/device-internal.h>
+#include "stm32prog.h"
+
+/* - configuration part -----------------------------*/
+#define USART_BL_VERSION	0x40	/* USART bootloader version V4.0*/
+#define UBOOT_BL_VERSION	0x03	/* bootloader version V0.3*/
+#define DEVICE_ID_BYTE1		0x05	/* MSB byte of device ID*/
+#define DEVICE_ID_BYTE2		0x00	/* LSB byte of device ID*/
+#define USART_RAM_BUFFER_SIZE	256	/* Size of USART_RAM_Buf buffer*/
+
+/* - Commands -----------------------------*/
+#define GET_CMD_COMMAND		0x00	/* Get CMD command*/
+#define GET_VER_COMMAND		0x01	/* Get Version command*/
+#define GET_ID_COMMAND		0x02	/* Get ID command*/
+#define GET_PHASE_COMMAND	0x03	/* Get Phase command*/
+#define RM_COMMAND		0x11	/* Read Memory command*/
+#define READ_PART_COMMAND	0x12	/* Read Partition command*/
+#define START_COMMAND		0x21	/* START command (Go)*/
+#define DOWNLOAD_COMMAND	0x31	/* Download command*/
+/* existing command for other STM32 but not used */
+/* ERASE			0x43 */
+/* EXTENDED_ERASE		0x44 */
+/* WRITE_UNPROTECTED		0x73 */
+/* READOUT_PROTECT		0x82 */
+/* READOUT_UNPROTECT		0x92 */
+
+/* - miscellaneous defines ----------------------------------------*/
+#define INIT_BYTE		0x7F	/*Init Byte ID*/
+#define ACK_BYTE		0x79	/*Acknowlede Byte ID*/
+#define NACK_BYTE		0x1F	/*No Acknowlede Byte ID*/
+#define ABORT_BYTE		0x5F	/*ABORT*/
+
+struct udevice *down_serial_dev;
+
+const u8 cmd_id[] = {
+	GET_CMD_COMMAND,
+	GET_VER_COMMAND,
+	GET_ID_COMMAND,
+	GET_PHASE_COMMAND,
+	RM_COMMAND,
+	READ_PART_COMMAND,
+	START_COMMAND,
+	DOWNLOAD_COMMAND
+};
+
+#define NB_CMD sizeof(cmd_id)
+
+/* DFU support for serial *********************************************/
+static struct dfu_entity *stm32prog_get_entity(struct stm32prog_data *data)
+{
+	int alt_id;
+
+	if (!data->cur_part)
+		if (data->phase == PHASE_FLASHLAYOUT)
+			alt_id = 0;
+		else
+			return NULL;
+	else
+		alt_id = data->cur_part->alt_id;
+
+	return dfu_get_entity(alt_id);
+}
+
+static int stm32prog_write(struct stm32prog_data *data, u8 *buffer,
+			   u32 buffer_size)
+{
+	struct dfu_entity *dfu_entity;
+	u8 ret = 0;
+
+	dfu_entity = stm32prog_get_entity(data);
+	if (!dfu_entity)
+		return -ENODEV;
+
+	ret = dfu_write(dfu_entity,
+			buffer,
+			buffer_size,
+			data->dfu_seq);
+
+	if (ret) {
+		stm32prog_err("DFU write failed [%d] cnt: %d",
+			      ret, data->dfu_seq);
+	}
+	data->dfu_seq++;
+	/* handle rollover as in driver/dfu/dfu.c */
+	data->dfu_seq &= 0xffff;
+	if (buffer_size == 0)
+		data->dfu_seq = 0; /* flush done */
+
+	return ret;
+}
+
+static int stm32prog_read(struct stm32prog_data *data, u8 phase, u32 offset,
+			  u8 *buffer, u32 buffer_size)
+{
+	struct dfu_entity *dfu_entity;
+	struct stm32prog_part_t *part;
+	u32 size;
+	int ret, i;
+
+	if (data->dfu_seq) {
+		stm32prog_err("DFU write pending for phase %d, seq %d",
+			      data->phase, data->dfu_seq);
+		return -EINVAL;
+	}
+	if (phase == PHASE_FLASHLAYOUT || phase > PHASE_LAST_USER) {
+		stm32prog_err("read failed : phase %d is invalid", phase);
+		return -EINVAL;
+	}
+	if (data->read_phase <= PHASE_LAST_USER &&
+	    phase != data->read_phase) {
+		/* clear previous read session */
+		dfu_entity = dfu_get_entity(data->read_phase - 1);
+		if (dfu_entity)
+			dfu_transaction_cleanup(dfu_entity);
+	}
+
+	dfu_entity = NULL;
+	/* found partition for the expected phase */
+	for (i = 0; i < data->part_nb; i++) {
+		part = &data->part_array[i];
+		if (part->id == phase)
+			dfu_entity = dfu_get_entity(part->alt_id);
+	}
+	if (!dfu_entity) {
+		stm32prog_err("read failed : phase %d is unknown", phase);
+		return -ENODEV;
+	}
+
+	/* clear pending read before to force offset */
+	if (dfu_entity->inited &&
+	    (data->read_phase != phase || data->offset != offset))
+		dfu_transaction_cleanup(dfu_entity);
+
+	/* initiate before to force offset */
+	if (!dfu_entity->inited) {
+		ret = dfu_transaction_initiate(dfu_entity, true);
+			if (ret < 0) {
+				stm32prog_err("DFU read init failed [%d] phase = %d offset = 0x%08x",
+					      ret, phase, offset);
+			return ret;
+		}
+	}
+	/* force new offset */
+	if (dfu_entity->offset != offset)
+		dfu_entity->offset = offset;
+	data->offset = offset;
+	data->read_phase = phase;
+	pr_debug("\nSTM32 download read %s offset=0x%x\n",
+		 dfu_entity->name, offset);
+	ret = dfu_read(dfu_entity, buffer, buffer_size,
+		       dfu_entity->i_blk_seq_num);
+	if (ret < 0) {
+		stm32prog_err("DFU read failed [%d] phase = %d offset = 0x%08x",
+			      ret, phase, offset);
+		return ret;
+	}
+
+	size = ret;
+
+	if (size < buffer_size) {
+		data->offset = 0;
+		data->read_phase = PHASE_END;
+		memset(buffer + size, 0, buffer_size - size);
+	} else {
+		data->offset += size;
+	}
+
+	return ret;
+}
+
+/* UART access ***************************************************/
+int stm32prog_serial_init(struct stm32prog_data *data, int link_dev)
+{
+	struct udevice *dev = NULL;
+	int node;
+	char alias[10];
+	const char *path;
+	struct dm_serial_ops *ops;
+	/* no parity, 8 bits, 1 stop */
+	u32 serial_config = SERIAL_DEFAULT_CONFIG;
+
+	down_serial_dev = NULL;
+
+	sprintf(alias, "serial%d", link_dev);
+	path = fdt_get_alias(gd->fdt_blob, alias);
+	if (!path) {
+		pr_err("%s alias not found", alias);
+		return -ENODEV;
+	}
+	node = fdt_path_offset(gd->fdt_blob, path);
+	if (!uclass_get_device_by_of_offset(UCLASS_SERIAL, node,
+					    &dev)) {
+		down_serial_dev = dev;
+	} else if (node > 0 &&
+		   !lists_bind_fdt(gd->dm_root, offset_to_ofnode(node),
+				   &dev, false)) {
+		if (!device_probe(dev))
+			down_serial_dev = dev;
+	}
+	if (!down_serial_dev) {
+		pr_err("%s = %s device not found", alias, path);
+		return -ENODEV;
+	}
+
+	/* force silent console on uart only when used */
+	if (gd->cur_serial_dev == down_serial_dev)
+		gd->flags |= GD_FLG_DISABLE_CONSOLE | GD_FLG_SILENT;
+	else
+		gd->flags &= ~(GD_FLG_DISABLE_CONSOLE | GD_FLG_SILENT);
+
+	ops = serial_get_ops(down_serial_dev);
+
+	if (!ops) {
+		pr_err("%s = %s missing ops", alias, path);
+		return -ENODEV;
+	}
+	if (!ops->setconfig) {
+		pr_err("%s = %s missing setconfig", alias, path);
+		return -ENODEV;
+	}
+
+	clrsetbits_le32(&serial_config, SERIAL_PAR_MASK, SERIAL_PAR_EVEN);
+
+	data->buffer = memalign(CONFIG_SYS_CACHELINE_SIZE,
+				USART_RAM_BUFFER_SIZE);
+
+	return ops->setconfig(down_serial_dev, serial_config);
+}
+
+static void stm32prog_serial_flush(void)
+{
+	struct dm_serial_ops *ops = serial_get_ops(down_serial_dev);
+	int err;
+
+	do {
+		err = ops->getc(down_serial_dev);
+	} while (err != -EAGAIN);
+}
+
+static int stm32prog_serial_getc_err(void)
+{
+	struct dm_serial_ops *ops = serial_get_ops(down_serial_dev);
+	int err;
+
+	do {
+		err = ops->getc(down_serial_dev);
+		if (err == -EAGAIN) {
+			ctrlc();
+			WATCHDOG_RESET();
+		}
+	} while ((err == -EAGAIN) && (!had_ctrlc()));
+
+	return err;
+}
+
+static u8 stm32prog_serial_getc(void)
+{
+	int err;
+
+	err = stm32prog_serial_getc_err();
+
+	return err >= 0 ? err : 0;
+}
+
+static bool stm32prog_serial_get_buffer(u8 *buffer, u32 *count)
+{
+	struct dm_serial_ops *ops = serial_get_ops(down_serial_dev);
+	int err;
+
+	do {
+		err = ops->getc(down_serial_dev);
+		if (err >= 0) {
+			*buffer++ = err;
+			*count -= 1;
+		} else if (err == -EAGAIN) {
+			ctrlc();
+			WATCHDOG_RESET();
+		} else {
+			break;
+		}
+	} while (*count && !had_ctrlc());
+
+	return !!(err < 0);
+}
+
+static void stm32prog_serial_putc(u8 w_byte)
+{
+	struct dm_serial_ops *ops = serial_get_ops(down_serial_dev);
+	int err;
+
+	do {
+		err = ops->putc(down_serial_dev, w_byte);
+	} while (err == -EAGAIN);
+}
+
+/* Helper function ************************************************/
+
+static u8 stm32prog_header(struct stm32prog_data *data)
+{
+	u8 ret;
+	u8 boot = 0;
+	struct dfu_entity *dfu_entity;
+	u64 size = 0;
+
+	dfu_entity = stm32prog_get_entity(data);
+	if (!dfu_entity)
+		return -ENODEV;
+
+	printf("\nSTM32 download write %s\n", dfu_entity->name);
+
+	/* force cleanup to avoid issue with previous read */
+	dfu_transaction_cleanup(dfu_entity);
+
+	ret = stm32prog_header_check(data->header_data,
+				     &data->header);
+
+	/* no header : max size is partition size */
+	if (ret) {
+		dfu_entity->get_medium_size(dfu_entity, &size);
+		data->header.image_length = size;
+	}
+
+	/**** Flash the header if necessary for boot partition */
+	if (data->phase < PHASE_FIRST_USER)
+		boot = 1;
+
+	/* write header if boot partition */
+	if (boot) {
+		if (ret) {
+			stm32prog_err("invalid header (error %d)", ret);
+		} else {
+			ret = stm32prog_write(data,
+					      (u8 *)data->header_data,
+					      BL_HEADER_SIZE);
+		}
+	} else {
+		if (ret)
+			printf("  partition without checksum\n");
+		ret = 0;
+	}
+
+	free(data->header_data);
+	data->header_data = NULL;
+
+	return ret;
+}
+
+static u8 stm32prog_start(struct stm32prog_data *data, u32 address)
+{
+	u8 ret = 0;
+	struct dfu_entity *dfu_entity;
+
+	if (address < 0x100) {
+		if (address == PHASE_OTP)
+			return stm32prog_otp_start(data);
+
+		if (address == PHASE_PMIC)
+			return stm32prog_pmic_start(data);
+
+		if (address == PHASE_RESET || address == PHASE_END) {
+			data->cur_part = NULL;
+			data->dfu_seq = 0;
+			data->phase = address;
+			return 0;
+		}
+		if (address != data->phase) {
+			stm32prog_err("invalid received phase id %d, current phase is %d",
+				      (u8)address, (u8)data->phase);
+			return -EINVAL;
+		}
+	}
+	/* check the last loaded partition */
+	if (address == DEFAULT_ADDRESS || address == data->phase) {
+		switch (data->phase) {
+		case PHASE_END:
+		case PHASE_RESET:
+		case PHASE_DO_RESET:
+			data->cur_part = NULL;
+			data->phase = PHASE_DO_RESET;
+			return 0;
+		}
+		dfu_entity = stm32prog_get_entity(data);
+		if (!dfu_entity)
+			return -ENODEV;
+
+		if (data->dfu_seq) {
+			ret = dfu_flush(dfu_entity, NULL, 0, data->dfu_seq);
+			data->dfu_seq = 0;
+			if (ret) {
+				stm32prog_err("DFU flush failed [%d]", ret);
+				return ret;
+			}
+		}
+		printf("\n  received length = 0x%x\n", data->cursor);
+		if (data->header.present) {
+			if (data->cursor !=
+			    (data->header.image_length + BL_HEADER_SIZE)) {
+				stm32prog_err("transmission interrupted (length=0x%x expected=0x%x)",
+					      data->cursor,
+					      data->header.image_length +
+					      BL_HEADER_SIZE);
+				return -EIO;
+			}
+			if (data->header.image_checksum != data->checksum) {
+				stm32prog_err("invalid checksum received (0x%x expected 0x%x)",
+					      data->checksum,
+					      data->header.image_checksum);
+				return -EIO;
+			}
+			printf("\n  checksum OK (0x%x)\n", data->checksum);
+		}
+
+		/* update DFU with received flashlayout */
+		if (data->phase == PHASE_FLASHLAYOUT)
+			stm32prog_dfu_init(data);
+	} else {
+		void (*entry)(void) = (void *)address;
+
+		printf("## Starting application at 0x%x ...\n", address);
+		(*entry)();
+		printf("## Application terminated\n");
+		ret = -ENOEXEC;
+	}
+
+	return ret;
+}
+
+/**
+ * get_address() - Get address if it is valid
+ *
+ * @tmp_xor:		Current xor value to update
+ * @return The address area
+ */
+static u32 get_address(u8 *tmp_xor)
+{
+	u32 address = 0x0;
+	u8 data;
+
+	data = stm32prog_serial_getc();
+	*tmp_xor ^= data;
+	address |= ((u32)data) << 24;
+
+	data = stm32prog_serial_getc();
+	address |= ((u32)data) << 16;
+	*tmp_xor ^= data;
+
+	data = stm32prog_serial_getc();
+	address |= ((u32)data) << 8;
+	*tmp_xor ^= data;
+
+	data = stm32prog_serial_getc();
+	address |= ((u32)data);
+	*tmp_xor ^= data;
+
+	return address;
+}
+
+static void stm32prog_serial_result(u8 result)
+{
+	/* always flush fifo before to send result */
+	stm32prog_serial_flush();
+	stm32prog_serial_putc(result);
+}
+
+/* Command -----------------------------------------------*/
+/**
+ * get_cmd_command() - Respond to Get command
+ *
+ * @data:		Current command context
+ */
+static void get_cmd_command(struct stm32prog_data *data)
+{
+	u32 counter = 0x0;
+
+	stm32prog_serial_putc(NB_CMD);
+	stm32prog_serial_putc(USART_BL_VERSION);
+
+	for (counter = 0; counter < NB_CMD; counter++)
+		stm32prog_serial_putc(cmd_id[counter]);
+
+	stm32prog_serial_result(ACK_BYTE);
+}
+
+/**
+ * get_version_command() - Respond to Get Version command
+ *
+ * @data:		Current command context
+ */
+static void get_version_command(struct stm32prog_data *data)
+{
+	stm32prog_serial_putc(UBOOT_BL_VERSION);
+	stm32prog_serial_result(ACK_BYTE);
+}
+
+/**
+ * get_id_command() - Respond to Get ID command
+ *
+ * @data:		Current command context
+ */
+static void get_id_command(struct stm32prog_data *data)
+{
+	/* Send Device IDCode */
+	stm32prog_serial_putc(0x1);
+	stm32prog_serial_putc(DEVICE_ID_BYTE1);
+	stm32prog_serial_putc(DEVICE_ID_BYTE2);
+	stm32prog_serial_result(ACK_BYTE);
+}
+
+/**
+ * get_phase_command() - Respond to Get phase
+ *
+ * @data:		Current command context
+ */
+static void get_phase_command(struct stm32prog_data *data)
+{
+	char *err_msg = NULL;
+	u8 i, length = 0;
+	u32 destination = DEFAULT_ADDRESS; /* destination address */
+	int phase = data->phase;
+
+	if (phase == PHASE_RESET || phase == PHASE_DO_RESET) {
+		err_msg = stm32prog_get_error(data);
+		length = strlen(err_msg);
+	}
+	if (phase == PHASE_FLASHLAYOUT)
+		destination = STM32_DDR_BASE;
+
+	stm32prog_serial_putc(length + 5);           /* Total length */
+	stm32prog_serial_putc(phase & 0xFF);         /* partition ID */
+	stm32prog_serial_putc(destination);          /* byte 1 of address */
+	stm32prog_serial_putc(destination >> 8);     /* byte 2 of address */
+	stm32prog_serial_putc(destination >> 16);    /* byte 3 of address */
+	stm32prog_serial_putc(destination >> 24);    /* byte 4 of address */
+
+	stm32prog_serial_putc(length);               /* Information length */
+	for (i = 0; i < length; i++)
+		stm32prog_serial_putc(err_msg[i]);
+	stm32prog_serial_result(ACK_BYTE);
+
+	if (phase == PHASE_RESET)
+		stm32prog_do_reset(data);
+}
+
+/**
+ * read_memory_command() - Read data from memory
+ *
+ * @data:		Current command context
+ */
+static void read_memory_command(struct stm32prog_data *data)
+{
+	u32 address = 0x0;
+	u8 rcv_data = 0x0, tmp_xor = 0x0;
+	u32 counter = 0x0;
+
+	/* Read memory address */
+	address = get_address(&tmp_xor);
+
+	/* If address memory is not received correctly */
+	rcv_data = stm32prog_serial_getc();
+	if (rcv_data != tmp_xor) {
+		stm32prog_serial_result(NACK_BYTE);
+		return;
+	}
+
+	stm32prog_serial_result(ACK_BYTE);
+
+	/* Read the number of bytes to be received:
+	 * Max NbrOfData = Data + 1 = 256
+	 */
+	rcv_data = stm32prog_serial_getc();
+	tmp_xor = ~rcv_data;
+	if (stm32prog_serial_getc() != tmp_xor) {
+		stm32prog_serial_result(NACK_BYTE);
+		return;
+	}
+
+	/* If checksum is correct send ACK */
+	stm32prog_serial_result(ACK_BYTE);
+
+	/* Send data to the host:
+	 * Number of data to read = data + 1
+	 */
+	for (counter = (rcv_data + 1); counter != 0; counter--)
+		stm32prog_serial_putc(*(u8 *)(address++));
+}
+
+/**
+ * start_command() - Respond to start command
+ *
+ * Jump to user application in RAM or partition check
+ *
+ * @data:		Current command context
+ */
+static void start_command(struct stm32prog_data *data)
+{
+	u32 address = 0;
+	u8 tmp_xor = 0x0;
+	u8 ret, rcv_data;
+
+	/* Read memory address */
+	address = get_address(&tmp_xor);
+
+	/* If address memory is not received correctly */
+	rcv_data = stm32prog_serial_getc();
+	if (rcv_data != tmp_xor) {
+		stm32prog_serial_result(NACK_BYTE);
+		return;
+	}
+	/* validate partition */
+	ret = stm32prog_start(data,
+			      address);
+
+	if (ret)
+		stm32prog_serial_result(ABORT_BYTE);
+	else
+		stm32prog_serial_result(ACK_BYTE);
+}
+
+/**
+ * download_command() - Respond to download command
+ *
+ * Write data to not volatile memory, Flash
+ *
+ * @data:		Current command context
+ */
+static void download_command(struct stm32prog_data *data)
+{
+	u32 address = 0x0;
+	u8 my_xor = 0x0;
+	u8 rcv_xor;
+	u32 counter = 0x0, codesize = 0x0;
+	u8 *ramaddress = 0;
+	u8 rcv_data = 0x0;
+	struct image_header_s *image_header = &data->header;
+	u32 cursor = data->cursor;
+	long size = 0;
+	u8 operation;
+	u32 packet_number;
+	u32 result = ACK_BYTE;
+	u8 ret;
+	unsigned int i;
+	bool error;
+	int rcv;
+
+	address = get_address(&my_xor);
+
+	/* If address memory is not received correctly */
+	rcv_xor = stm32prog_serial_getc();
+	if (rcv_xor != my_xor) {
+		result = NACK_BYTE;
+		goto end;
+	}
+
+	/* If address valid send ACK */
+	stm32prog_serial_result(ACK_BYTE);
+
+	/* get packet number and operation type */
+	operation = (u8)((u32)address >> 24);
+	packet_number = ((u32)(((u32)address << 8))) >> 8;
+
+	switch (operation) {
+	/* supported operation */
+	case PHASE_FLASHLAYOUT:
+	case PHASE_OTP:
+	case PHASE_PMIC:
+		break;
+	default:
+		result = NACK_BYTE;
+		goto end;
+	}
+	/* check the packet number */
+	if (packet_number == 0) {
+		/* erase: re-initialize the image_header struct */
+		data->packet_number = 0;
+		if (data->header_data)
+			memset(data->header_data, 0, BL_HEADER_SIZE);
+		else
+			data->header_data = calloc(1, BL_HEADER_SIZE);
+		cursor = 0;
+		data->cursor = 0;
+		data->checksum = 0;
+		/*idx = cursor;*/
+	} else {
+		data->packet_number++;
+	}
+
+	/* Check with the number of current packet if the device receive
+	 * the true packet
+	 */
+	if (packet_number != data->packet_number) {
+		data->packet_number--;
+		result = NACK_BYTE;
+		goto end;
+	}
+
+	/*-- Read number of bytes to be written and data -----------*/
+
+	/* Read the number of bytes to be written:
+	 * Max NbrOfData = data + 1 <= 256
+	 */
+	rcv_data = stm32prog_serial_getc();
+
+	/* NbrOfData to write = data + 1 */
+	codesize = rcv_data + 0x01;
+
+	if (codesize > USART_RAM_BUFFER_SIZE) {
+		result = NACK_BYTE;
+		goto end;
+	}
+
+	/* Checksum Initialization */
+	my_xor = rcv_data;
+
+	/* UART receive data and send to Buffer */
+	counter = codesize;
+	error = stm32prog_serial_get_buffer(data->buffer, &counter);
+
+	/* read checksum */
+	if (!error) {
+		rcv = stm32prog_serial_getc_err();
+		error = !!(rcv < 0);
+		rcv_xor = rcv;
+	}
+
+	if (error) {
+		printf("transmission error on packet %d, byte %d\n",
+		       packet_number, codesize - counter);
+		/* waiting end of packet before flush & NACK */
+		mdelay(30);
+		data->packet_number--;
+		result = NACK_BYTE;
+		goto end;
+	}
+
+	/* Compute Checksum */
+	ramaddress = data->buffer;
+	for (counter = codesize; counter != 0; counter--)
+		my_xor ^= *(ramaddress++);
+
+	/* If Checksum is incorrect */
+	if (rcv_xor != my_xor) {
+		printf("checksum error on packet %d\n",
+		       packet_number);
+		/* wait to be sure that all data are received
+		 * in the FIFO before flush
+		 */
+		mdelay(30);
+		data->packet_number--;
+		result = NACK_BYTE;
+		goto end;
+	}
+
+	/* Update current position in buffer */
+	data->cursor += codesize;
+
+	if (operation == PHASE_OTP) {
+		size = data->cursor - cursor;
+		/* no header for OTP */
+		if (stm32prog_otp_write(data, cursor,
+					data->buffer, &size))
+			result = ABORT_BYTE;
+		goto end;
+	}
+
+	if (operation == PHASE_PMIC) {
+		size = data->cursor - cursor;
+		/* no header for PMIC */
+		if (stm32prog_pmic_write(data, cursor,
+					 data->buffer, &size))
+			result = ABORT_BYTE;
+		goto end;
+	}
+
+	if (cursor < BL_HEADER_SIZE) {
+		/* size = portion of header in this chunck */
+		if (data->cursor >= BL_HEADER_SIZE)
+			size = BL_HEADER_SIZE - cursor;
+		else
+			size = data->cursor - cursor;
+		memcpy((void *)((u32)(data->header_data) + cursor),
+		       data->buffer, size);
+		cursor += size;
+
+		if (cursor == BL_HEADER_SIZE) {
+			/* Check and Write the header */
+			if (stm32prog_header(data)) {
+				result = ABORT_BYTE;
+				goto end;
+			}
+		} else {
+			goto end;
+		}
+	}
+
+	if (image_header->present) {
+		if (data->cursor <= BL_HEADER_SIZE)
+			goto end;
+		/* compute checksum on payload */
+		for (i = (unsigned long)size; i < codesize; i++)
+			data->checksum += data->buffer[i];
+
+		if (data->cursor >
+		    image_header->image_length + BL_HEADER_SIZE) {
+			pr_err("expected size exceeded\n");
+			result = ABORT_BYTE;
+			goto end;
+		}
+
+		/* write data (payload) */
+		ret = stm32prog_write(data,
+				      &data->buffer[size],
+				      codesize - size);
+	} else {
+		/* write all */
+		ret = stm32prog_write(data,
+				      data->buffer,
+				      codesize);
+	}
+	if (ret)
+		result = ABORT_BYTE;
+
+end:
+	stm32prog_serial_result(result);
+}
+
+/**
+ * read_partition() - Respond to read command
+ *
+ * Read data from not volatile memory, Flash
+ *
+ * @data:		Current command context
+ */
+static void read_partition_command(struct stm32prog_data *data)
+{
+	u32 i, part_id, codesize, offset = 0, rcv_data;
+	long size;
+	u8 tmp_xor;
+	int res;
+	u8 buffer[256];
+
+	part_id = stm32prog_serial_getc();
+	tmp_xor = part_id;
+
+	offset = get_address(&tmp_xor);
+
+	rcv_data = stm32prog_serial_getc();
+	if (rcv_data != tmp_xor) {
+		pr_debug("1st checksum received = %x, computed %x\n",
+			 rcv_data, tmp_xor);
+		goto error;
+	}
+	stm32prog_serial_putc(ACK_BYTE);
+
+	/* NbrOfData to read = data + 1 */
+	rcv_data = stm32prog_serial_getc();
+	codesize = rcv_data + 0x01;
+	tmp_xor = rcv_data;
+
+	rcv_data = stm32prog_serial_getc();
+	if ((rcv_data ^ tmp_xor) != 0xFF) {
+		pr_debug("2nd checksum received = %x, computed %x\n",
+			 rcv_data, tmp_xor);
+		goto error;
+	}
+
+	pr_debug("%s : %x\n", __func__, part_id);
+	rcv_data = 0;
+	switch (part_id) {
+	case PHASE_OTP:
+		size = codesize;
+		if (!stm32prog_otp_read(data, offset, buffer, &size))
+			rcv_data = size;
+		break;
+	case PHASE_PMIC:
+		size = codesize;
+		if (!stm32prog_pmic_read(data, offset, buffer, &size))
+			rcv_data = size;
+		break;
+	default:
+		res = stm32prog_read(data, part_id, offset,
+				     buffer, codesize);
+		if (res > 0)
+			rcv_data = res;
+		break;
+	}
+	if (rcv_data > 0) {
+		stm32prog_serial_putc(ACK_BYTE);
+		/*----------- Send data to the host -----------*/
+		for (i = 0; i < rcv_data; i++)
+			stm32prog_serial_putc(buffer[i]);
+		/*----------- Send filler to the host -----------*/
+		for (; i < codesize; i++)
+			stm32prog_serial_putc(0x0);
+		return;
+	}
+	stm32prog_serial_result(ABORT_BYTE);
+	return;
+
+error:
+	stm32prog_serial_result(NACK_BYTE);
+}
+
+/* MAIN function = SERIAL LOOP ***********************************************/
+
+/**
+ * stm32prog_serial_loop() - USART bootloader Loop routine
+ *
+ * @data:		Current command context
+ * @return true if reset is needed after loop
+ */
+bool stm32prog_serial_loop(struct stm32prog_data *data)
+{
+	u32 counter = 0x0;
+	u8 command = 0x0;
+	u8 found;
+	int phase = data->phase;
+
+	/* element of cmd_func need to aligned with cmd_id[]*/
+	void (*cmd_func[NB_CMD])(struct stm32prog_data *) = {
+		/* GET_CMD_COMMAND */	get_cmd_command,
+		/* GET_VER_COMMAND */	get_version_command,
+		/* GET_ID_COMMAND */	get_id_command,
+		/* GET_PHASE_COMMAND */	get_phase_command,
+		/* RM_COMMAND */	read_memory_command,
+		/* READ_PART_COMMAND */	read_partition_command,
+		/* START_COMMAND */	start_command,
+		/* DOWNLOAD_COMMAND */	download_command
+	};
+
+	/* flush and NACK pending command received during u-boot init
+	 * request command reemit
+	 */
+	stm32prog_serial_result(NACK_BYTE);
+
+	clear_ctrlc(); /* forget any previous Control C */
+	while (!had_ctrlc()) {
+		phase = data->phase;
+
+		if (phase == PHASE_DO_RESET)
+			return true;
+
+		/* Get the user command: read first byte */
+		command = stm32prog_serial_getc();
+
+		if (command == INIT_BYTE) {
+			puts("\nConnected\n");
+			stm32prog_serial_result(ACK_BYTE);
+			continue;
+		}
+
+		found = 0;
+		for (counter = 0; counter < NB_CMD; counter++)
+			if (cmd_id[counter] == command) {
+				found = 1;
+				break;
+			}
+		if (found)
+			if ((command ^ stm32prog_serial_getc()) != 0xFF)
+				found = 0;
+		if (!found) {
+			/* wait to be sure that all data are received
+			 * in the FIFO before flush (CMD and XOR)
+			 */
+			mdelay(3);
+			stm32prog_serial_result(NACK_BYTE);
+		} else {
+			stm32prog_serial_result(ACK_BYTE);
+			cmd_func[counter](data);
+		}
+		WATCHDOG_RESET();
+	}
+
+	/* clean device */
+	if (gd->cur_serial_dev == down_serial_dev) {
+		/* restore console on uart */
+		gd->flags &= ~(GD_FLG_DISABLE_CONSOLE | GD_FLG_SILENT);
+	}
+	down_serial_dev = NULL;
+
+	return false; /* no reset after ctrlc */
+}
diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c
index 34f27c074f..969245e199 100644
--- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c
@@ -19,6 +19,7 @@ static int stm32prog_set_phase(struct stm32prog_data *data, u8 phase,
 
 	if (phase == data->phase) {
 		data->offset = offset;
+		data->dfu_seq = 0;
 		return 0;
 	}
 
@@ -29,6 +30,7 @@ static int stm32prog_set_phase(struct stm32prog_data *data, u8 phase,
 			data->cur_part = part;
 			data->phase = phase;
 			data->offset = offset;
+			data->dfu_seq = 0;
 			return 0;
 		}
 	}
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 16/18] stm32mp: stm32prog: enable videoconsole
  2020-03-18  8:24 [PATCH 00/18] stm32mp1: add command stm32prog Patrick Delaunay
                   ` (14 preceding siblings ...)
  2020-03-18  8:25 ` [PATCH 15/18] stm32mp: stm32prog: add serial link support Patrick Delaunay
@ 2020-03-18  8:25 ` Patrick Delaunay
  2020-04-14 13:11   ` Patrice CHOTARD
  2020-03-18  8:25 ` [PATCH 17/18] stm32mp: stm32prog: support for script Patrick Delaunay
                   ` (2 subsequent siblings)
  18 siblings, 1 reply; 40+ messages in thread
From: Patrick Delaunay @ 2020-03-18  8:25 UTC (permalink / raw)
  To: u-boot

Enable the videoconsole during the stm32prog command execution
to have information without UART.

Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
---

 .../cmd_stm32prog/cmd_stm32prog.c             | 28 +++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
index 1769ba05f2..15bbdc2cb6 100644
--- a/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
@@ -11,6 +11,32 @@
 
 struct stm32prog_data *stm32prog_data;
 
+static void enable_vidconsole(void)
+{
+#ifdef CONFIG_DM_VIDEO
+	char *stdname;
+	char buf[64];
+
+	stdname = env_get("stdout");
+	if (!stdname || !strstr(stdname, "vidconsole")) {
+		if (!stdname)
+			snprintf(buf, sizeof(buf), "serial,vidconsole");
+		else
+			snprintf(buf, sizeof(buf), "%s,vidconsole", stdname);
+		env_set("stdout", buf);
+	}
+
+	stdname = env_get("stderr");
+	if (!stdname || !strstr(stdname, "vidconsole")) {
+		if (!stdname)
+			snprintf(buf, sizeof(buf), "serial,vidconsole");
+		else
+			snprintf(buf, sizeof(buf), "%s,vidconsole", stdname);
+		env_set("stderr", buf);
+	}
+#endif
+}
+
 static int do_stm32prog(cmd_tbl_t *cmdtp, int flag, int argc,
 			char * const argv[])
 {
@@ -45,6 +71,8 @@ static int do_stm32prog(cmd_tbl_t *cmdtp, int flag, int argc,
 	if (argc > 4)
 		size = simple_strtoul(argv[4], NULL, 16);
 
+	enable_vidconsole();
+
 	data = (struct stm32prog_data *)malloc(sizeof(*data));
 
 	if (!data) {
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 17/18] stm32mp: stm32prog: support for script
  2020-03-18  8:24 [PATCH 00/18] stm32mp1: add command stm32prog Patrick Delaunay
                   ` (15 preceding siblings ...)
  2020-03-18  8:25 ` [PATCH 16/18] stm32mp: stm32prog: enable videoconsole Patrick Delaunay
@ 2020-03-18  8:25 ` Patrick Delaunay
  2020-04-14 13:11   ` Patrice CHOTARD
  2020-03-18  8:25 ` [PATCH 18/18] stm32mp: stm32prog: add support of RAM target Patrick Delaunay
  2020-05-14  9:28 ` [PATCH 00/18] stm32mp1: add command stm32prog Patrick DELAUNAY
  18 siblings, 1 reply; 40+ messages in thread
From: Patrick Delaunay @ 2020-03-18  8:25 UTC (permalink / raw)
  To: u-boot

Support an U-Boot script included in uimage instead of flashlayout file
(text file in tsv format).

This feature is used to execute this script directly when U-Boot is
loaded in DDR (for update without STM32CubeProgrammer for example).

A simple example with dfu-util only is:

$> echo "dfu 0" > script.cmd
$> mkimage -C none -A arm -T script -d script.cmd script.uimg
$> mkimage -T stm32image -a 0xC0000000 -e 0xC0000000 -d script.uimg \
  script.stm32

$> dfu-util -d 0483:df11 -a 1 -D tf-a.stm32
$> dfu-util -d 0483:df11 -a 0 -D script.stm32
$> dfu-util -d 0483:df11 -a 0 -D u-boot.stm32
$> dfu-util -d 0483:df11 -a 0 -e

Then you can used dfu-utils to update your device

To increase speed, you can also switch to fastboot protocol with:
  echo "fastboot 0" > script.cmd

Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
---

 .../arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
index 15bbdc2cb6..baf9b6bd1e 100644
--- a/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
@@ -6,6 +6,7 @@
 #include <common.h>
 #include <command.h>
 #include <dfu.h>
+#include <image.h>
 #include <asm/arch/stm32prog.h>
 #include "stm32prog.h"
 
@@ -44,6 +45,7 @@ static int do_stm32prog(cmd_tbl_t *cmdtp, int flag, int argc,
 	int dev, ret;
 	enum stm32prog_link_t link = LINK_UNDEFINED;
 	bool reset = false;
+	struct image_header_s header;
 	struct stm32prog_data *data;
 
 	if (argc < 3 ||  argc > 5)
@@ -71,6 +73,18 @@ static int do_stm32prog(cmd_tbl_t *cmdtp, int flag, int argc,
 	if (argc > 4)
 		size = simple_strtoul(argv[4], NULL, 16);
 
+	/* check STM32IMAGE presence */
+	if (size == 0 &&
+	    !stm32prog_header_check((struct raw_header_s *)addr, &header)) {
+		size = header.image_length + BL_HEADER_SIZE;
+
+		/* uImage detected in STM32IMAGE, execute the script */
+		if (IMAGE_FORMAT_LEGACY ==
+		    genimg_get_format((void *)(addr + BL_HEADER_SIZE)))
+			return image_source_script(addr + BL_HEADER_SIZE,
+						   "script at 1");
+	}
+
 	enable_vidconsole();
 
 	data = (struct stm32prog_data *)malloc(sizeof(*data));
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH 18/18] stm32mp: stm32prog: add support of RAM target
  2020-03-18  8:24 [PATCH 00/18] stm32mp1: add command stm32prog Patrick Delaunay
                   ` (16 preceding siblings ...)
  2020-03-18  8:25 ` [PATCH 17/18] stm32mp: stm32prog: support for script Patrick Delaunay
@ 2020-03-18  8:25 ` Patrick Delaunay
  2020-04-14 13:11   ` Patrice CHOTARD
  2020-05-14  9:28 ` [PATCH 00/18] stm32mp1: add command stm32prog Patrick DELAUNAY
  18 siblings, 1 reply; 40+ messages in thread
From: Patrick Delaunay @ 2020-03-18  8:25 UTC (permalink / raw)
  To: u-boot

Add support of RAM target in flashlayout to load kernel image
("system") and device tree ("filesystem") in DDR with DFU and
start these images.

The flashlayout.tsv is:

-	0x01	fsbl		Binary		none	0x00000000	tf-a.stm32
-	0x03	ssbl		Binary		none	0x00000000	u-boot.stm32
P	0x10	kernel		System		ram0	0xC2000000	uImage.bin
P	0x11	dtb		FileSystem	ram0	0xC4000000	dtb.bin

Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
---

 .../cmd_stm32prog/cmd_stm32prog.c             | 28 ++++++++++++++++++
 .../mach-stm32mp/cmd_stm32prog/stm32prog.c    | 29 ++++++++++++++++++-
 .../mach-stm32mp/cmd_stm32prog/stm32prog.h    |  7 ++++-
 3 files changed, 62 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
index baf9b6bd1e..6bebea7ad5 100644
--- a/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
@@ -47,6 +47,7 @@ static int do_stm32prog(cmd_tbl_t *cmdtp, int flag, int argc,
 	bool reset = false;
 	struct image_header_s header;
 	struct stm32prog_data *data;
+	u32 uimage, dtb;
 
 	if (argc < 3 ||  argc > 5)
 		return CMD_RET_USAGE;
@@ -118,11 +119,38 @@ static int do_stm32prog(cmd_tbl_t *cmdtp, int flag, int argc,
 		goto cleanup;
 	}
 
+	uimage = data->uimage;
+	dtb = data->dtb;
+
 	stm32prog_clean(data);
 	free(stm32prog_data);
 	stm32prog_data = NULL;
 
 	puts("Download done\n");
+
+	if (uimage) {
+		char boot_addr_start[20];
+		char dtb_addr[20];
+		char *bootm_argv[5] = {
+			"bootm", boot_addr_start, "-", dtb_addr, NULL
+		};
+		if (!dtb)
+			bootm_argv[3] = env_get("fdtcontroladdr");
+		else
+			snprintf(dtb_addr, sizeof(dtb_addr) - 1,
+				 "0x%x", dtb);
+
+		snprintf(boot_addr_start, sizeof(boot_addr_start) - 1,
+			 "0x%x", uimage);
+		printf("Booting kernel at %s - %s...\n\n\n",
+		       boot_addr_start, bootm_argv[3]);
+		/* Try bootm for legacy and FIT format image */
+		if (genimg_get_format((void *)uimage) != IMAGE_FORMAT_INVALID)
+			do_bootm(cmdtp, 0, 4, bootm_argv);
+		else if CONFIG_IS_ENABLED(CMD_BOOTZ)
+			do_bootz(cmdtp, 0, 4, bootm_argv);
+	}
+
 	if (reset) {
 		puts("Reset...\n");
 		run_command("reset", 0);
diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
index 0967bbc11a..cc303214cf 100644
--- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
@@ -272,6 +272,9 @@ static int parse_ip(struct stm32prog_data *data,
 	} else if (!strncmp(p, "spi-nand", 8)) {
 		part->target = STM32PROG_SPI_NAND;
 		len = 8;
+	} else if (!strncmp(p, "ram", 3)) {
+		part->target = STM32PROG_RAM;
+		len = 0;
 	} else {
 		result = -EINVAL;
 	}
@@ -610,6 +613,11 @@ static int init_device(struct stm32prog_data *data,
 		dev->mtd = mtd;
 		break;
 #endif
+	case STM32PROG_RAM:
+		first_addr = gd->bd->bi_dram[0].start;
+		last_addr = first_addr + gd->bd->bi_dram[0].size;
+		dev->erase_size = 1;
+		break;
 	default:
 		stm32prog_err("unknown device type = %d", dev->target);
 		return -ENODEV;
@@ -1022,7 +1030,11 @@ static int stm32prog_alt_add(struct stm32prog_data *data,
 			  part->name, part->id,
 			  size, multiplier, type);
 
-	if (part->part_type == RAW_IMAGE) {
+	if (part->target == STM32PROG_RAM) {
+		offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
+				   "ram 0x%llx 0x%llx",
+				   part->addr, part->size);
+	} else if (part->part_type == RAW_IMAGE) {
 		u64 dfu_size;
 
 		if (part->dev->target == STM32PROG_MMC)
@@ -1073,6 +1085,10 @@ static int stm32prog_alt_add(struct stm32prog_data *data,
 		get_mtd_by_target(devstr, part->target, part->dev_id);
 		break;
 #endif
+	case STM32PROG_RAM:
+		sprintf(dfustr, "ram");
+		sprintf(devstr, "0");
+		break;
 	default:
 		stm32prog_err("invalid target: %d", part->target);
 		return -ENODEV;
@@ -1440,6 +1456,13 @@ static void stm32prog_end_phase(struct stm32prog_data *data)
 	if (!data->cur_part)
 		return;
 
+	if (data->cur_part->target == STM32PROG_RAM) {
+		if (data->cur_part->part_type == PART_SYSTEM)
+			data->uimage = data->cur_part->addr;
+		if (data->cur_part->part_type == PART_FILESYSTEM)
+			data->dtb = data->cur_part->addr;
+	}
+
 	if (CONFIG_IS_ENABLED(MMC) &&
 	    data->cur_part->part_id < 0) {
 		char cmdbuf[60];
@@ -1569,6 +1592,10 @@ static int part_delete(struct stm32prog_data *data,
 		}
 		break;
 #endif
+	case STM32PROG_RAM:
+		printf("on ram: ");
+		memset((void *)(uintptr_t)part->addr, 0, (size_t)part->size);
+		break;
 	default:
 		ret = -1;
 		stm32prog_err("%s (0x%x): erase invalid", part->name, part->id);
diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
index c4fdb5b8c3..bae4e91c01 100644
--- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
+++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
@@ -27,7 +27,8 @@ enum stm32prog_target {
 	STM32PROG_MMC,
 	STM32PROG_NAND,
 	STM32PROG_NOR,
-	STM32PROG_SPI_NAND
+	STM32PROG_SPI_NAND,
+	STM32PROG_RAM
 };
 
 enum stm32prog_link_t {
@@ -136,6 +137,10 @@ struct stm32prog_data {
 	u8	*buffer; /* size = USART_RAM_BUFFER_SIZE*/
 	int	dfu_seq;
 	u8	read_phase;
+
+	/* bootm information */
+	u32	uimage;
+	u32	dtb;
 };
 
 extern struct stm32prog_data *stm32prog_data;
-- 
2.17.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [Uboot-stm32] [PATCH 01/18] usb: gadget: g_dnl: add function g_dnl_set_product
  2020-03-18  8:24 ` [PATCH 01/18] usb: gadget: g_dnl: add function g_dnl_set_product Patrick Delaunay
@ 2020-04-14 12:57   ` Patrice CHOTARD
  0 siblings, 0 replies; 40+ messages in thread
From: Patrice CHOTARD @ 2020-04-14 12:57 UTC (permalink / raw)
  To: u-boot

Hi

On 3/18/20 9:24 AM, Patrick Delaunay wrote:
> Add a function g_dnl_set_product to change the Product string used in USB
> enumeration in any command based on download gadget.
>
> If the function is called with NULL pointer, the product string is set to
> the default value (product[] = "USB download gadget").
>
> Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
> ---
>
>  drivers/usb/gadget/g_dnl.c | 8 ++++++++
>  include/g_dnl.h            | 1 +
>  2 files changed, 9 insertions(+)
>
> diff --git a/drivers/usb/gadget/g_dnl.c b/drivers/usb/gadget/g_dnl.c
> index e9e1600a1a..7a51b53f24 100644
> --- a/drivers/usb/gadget/g_dnl.c
> +++ b/drivers/usb/gadget/g_dnl.c
> @@ -89,6 +89,14 @@ static struct usb_gadget_strings *g_dnl_composite_strings[] = {
>  	NULL,
>  };
>  
> +void g_dnl_set_product(const char *s)
> +{
> +	if (s)
> +		g_dnl_string_defs[1].s = s;
> +	else
> +		g_dnl_string_defs[1].s = product;
> +}
> +
>  static int g_dnl_unbind(struct usb_composite_dev *cdev)
>  {
>  	struct usb_gadget *gadget = cdev->gadget;
> diff --git a/include/g_dnl.h b/include/g_dnl.h
> index 6d461c73d3..836ee602c8 100644
> --- a/include/g_dnl.h
> +++ b/include/g_dnl.h
> @@ -38,6 +38,7 @@ int g_dnl_board_usb_cable_connected(void);
>  int g_dnl_register(const char *s);
>  void g_dnl_unregister(void);
>  void g_dnl_set_serialnumber(char *);
> +void g_dnl_set_product(const char *s);
>  
>  bool g_dnl_detach(void);
>  void g_dnl_trigger_detach(void);

Reviewed-by: Patrice Chotard <patrice.chotard@st.com>

Thanks

Patrice

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [Uboot-stm32] [PATCH 02/18] dfu: add prototype for dfu_transaction_initiate/cleanup
  2020-03-18  8:24 ` [PATCH 02/18] dfu: add prototype for dfu_transaction_initiate/cleanup Patrick Delaunay
@ 2020-04-14 12:58   ` Patrice CHOTARD
  0 siblings, 0 replies; 40+ messages in thread
From: Patrice CHOTARD @ 2020-04-14 12:58 UTC (permalink / raw)
  To: u-boot

Hi

On 3/18/20 9:24 AM, Patrick Delaunay wrote:
> Add prototype for function dfu_transaction_initiate and
> dfu_transaction_cleanup to avoid warning with W=1.
>
> Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
> ---
>
>  include/dfu.h | 3 +++
>  1 file changed, 3 insertions(+)
>
> diff --git a/include/dfu.h b/include/dfu.h
> index fb5260d903..2f0e335ec0 100644
> --- a/include/dfu.h
> +++ b/include/dfu.h
> @@ -209,6 +209,9 @@ void dfu_initiated_callback(struct dfu_entity *dfu);
>   */
>  void dfu_flush_callback(struct dfu_entity *dfu);
>  
> +int dfu_transaction_initiate(struct dfu_entity *dfu, bool read);
> +void dfu_transaction_cleanup(struct dfu_entity *dfu);
> +
>  /*
>   * dfu_defer_flush - pointer to store dfu_entity for deferred flashing.
>   *		     It should be NULL when not used.

Reviewed-by: Patrice Chotard <patrice.chotard@st.com>

Thanks

Patrice

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 03/18] stm32mp: add function get_cpu_dev
  2020-03-18  8:24 ` [PATCH 03/18] stm32mp: add function get_cpu_dev Patrick Delaunay
@ 2020-04-14 12:59   ` Patrice CHOTARD
  0 siblings, 0 replies; 40+ messages in thread
From: Patrice CHOTARD @ 2020-04-14 12:59 UTC (permalink / raw)
  To: u-boot

Hi

On 3/18/20 9:24 AM, Patrick Delaunay wrote:
> Add a function get_cpu_dev to get the DEV_ID present
> in DBGMCU_IDC register.
>
> Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
> ---
>
>  arch/arm/mach-stm32mp/cpu.c                    | 11 ++++++-----
>  arch/arm/mach-stm32mp/include/mach/sys_proto.h |  5 +++++
>  2 files changed, 11 insertions(+), 5 deletions(-)
>
> diff --git a/arch/arm/mach-stm32mp/cpu.c b/arch/arm/mach-stm32mp/cpu.c
> index e14e3e47f2..36a9205819 100644
> --- a/arch/arm/mach-stm32mp/cpu.c
> +++ b/arch/arm/mach-stm32mp/cpu.c
> @@ -236,6 +236,11 @@ static u32 read_idc(void)
>  	return readl(DBGMCU_IDC);
>  }
>  
> +u32 get_cpu_dev(void)
> +{
> +	return (read_idc() & DBGMCU_IDC_DEV_ID_MASK) >> DBGMCU_IDC_DEV_ID_SHIFT;
> +}
> +
>  u32 get_cpu_rev(void)
>  {
>  	return (read_idc() & DBGMCU_IDC_REV_ID_MASK) >> DBGMCU_IDC_REV_ID_SHIFT;
> @@ -266,11 +271,7 @@ static u32 get_cpu_rpn(void)
>  
>  u32 get_cpu_type(void)
>  {
> -	u32 id;
> -
> -	id = (read_idc() & DBGMCU_IDC_DEV_ID_MASK) >> DBGMCU_IDC_DEV_ID_SHIFT;
> -
> -	return (id << 16) | get_cpu_rpn();
> +	return (get_cpu_dev() << 16) | get_cpu_rpn();
>  }
>  
>  /* Get Package options from OTP */
> diff --git a/arch/arm/mach-stm32mp/include/mach/sys_proto.h b/arch/arm/mach-stm32mp/include/mach/sys_proto.h
> index 1617126bea..4b6c7b8bdd 100644
> --- a/arch/arm/mach-stm32mp/include/mach/sys_proto.h
> +++ b/arch/arm/mach-stm32mp/include/mach/sys_proto.h
> @@ -20,6 +20,11 @@
>  /* return CPU_STMP32MP...Xxx constants */
>  u32 get_cpu_type(void);
>  
> +#define CPU_DEV_STM32MP15	0x500
> +
> +/* return CPU_DEV constants */
> +u32 get_cpu_dev(void);
> +
>  #define CPU_REVA	0x1000
>  #define CPU_REVB	0x2000
>  #define CPU_REVZ	0x2001

Reviewed-by: Patrice Chotard <patrice.chotard@st.com>

Thanks

Patrice

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 04/18] stm32mp: add the command stm32prog
  2020-03-18  8:24 ` [PATCH 04/18] stm32mp: add the command stm32prog Patrick Delaunay
@ 2020-04-14 13:00   ` Patrice CHOTARD
  2020-04-14 13:03   ` Patrice CHOTARD
  1 sibling, 0 replies; 40+ messages in thread
From: Patrice CHOTARD @ 2020-04-14 13:00 UTC (permalink / raw)
  To: u-boot

Hi

On 3/18/20 9:24 AM, Patrick Delaunay wrote:
> Add a specific command stm32prog for STM32MP soc family
> witch allows to program the boot devices with the tool
> STM32CubeProgrammer (http://www.st.com/STM32CubeProg).
>
> This command uses the same UART STM32 protocol than MCU
> STM32 with or USB with DFU protocol v1.1 (ithe MCU ST
> extension are no supported).
>
> The executed actions are based on a tab separated value file
> with a stm32 header, the FlashLayout file
> (https://wiki.st.com/stm32mpu/wiki/STM32CubeProgrammer_flashlayout).
>
> This file is parsed by the U-Boot command to:
> - initialize the devices
> - create the partition table on each device
> - initialize the DFU backend to access to not volatile memory
>   (NOR/NAND/SD/eMMC) or to virtual device (OTP/PMIC)
>
> Up to STM32PROG_MAX_DEV (5) devices can be updated with a FlashLayout.
>
> The communication between U-Boot and STM32CubeProgrammer is done with
> the specific alternate configuration (see "AN5275: USB DFU/USART protocols
> used in STM32MP1 Series bootloaders" for details).
>
> The command stm32prog is executed when a boot from USB is detected
> (selected with bootpins) and we can program the boot devices with
> a simple command (on Windows or Linux):
>
> PC $>  STM32_Programmer_CLI -c port=usb1 -w flaslayout.tsv
>
> 1/ the ROM code loads TF-A in embedded RAM (DFU or uart)
> 2/ TF-A loads flashlayout file and U-Boot in DDR (DFU or uart)
> 3/ U-Boot executes the stm32prog command (DFU or uart)
>
> Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
> ---
>
>  arch/arm/mach-stm32mp/Kconfig                 |  12 +
>  arch/arm/mach-stm32mp/Makefile                |   1 +
>  arch/arm/mach-stm32mp/cmd_stm32prog/Makefile  |   8 +
>  .../cmd_stm32prog/cmd_stm32prog.c             |  96 ++++
>  .../mach-stm32mp/cmd_stm32prog/stm32prog.c    | 480 ++++++++++++++++++
>  .../mach-stm32mp/cmd_stm32prog/stm32prog.h    | 137 +++++
>  .../cmd_stm32prog/stm32prog_usb.c             | 206 ++++++++
>  .../arm/mach-stm32mp/include/mach/stm32prog.h |  12 +
>  board/st/common/stm32mp_dfu.c                 |  20 +
>  configs/stm32mp15_basic_defconfig             |   3 +-
>  configs/stm32mp15_trusted_defconfig           |   3 +-
>  11 files changed, 974 insertions(+), 4 deletions(-)
>  create mode 100644 arch/arm/mach-stm32mp/cmd_stm32prog/Makefile
>  create mode 100644 arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
>  create mode 100644 arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
>  create mode 100644 arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
>  create mode 100644 arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c
>  create mode 100644 arch/arm/mach-stm32mp/include/mach/stm32prog.h
>
> diff --git a/arch/arm/mach-stm32mp/Kconfig b/arch/arm/mach-stm32mp/Kconfig
> index 1a5545b98d..61466f6125 100644
> --- a/arch/arm/mach-stm32mp/Kconfig
> +++ b/arch/arm/mach-stm32mp/Kconfig
> @@ -114,6 +114,18 @@ config STM32_ETZPC
>  	help
>  	  Say y to enable STM32 Extended TrustZone Protection
>  
> +config CMD_STM32PROG
> +	bool "command stm32prog for STM32CudeProgrammer"
> +	select DFU
> +	select DFU_RAM
> +	select DFU_VIRT
> +	help
> +		activate a specific command stm32prog for STM32MP soc family
> +		witch update the device with the tools STM32CubeProgrammer,
> +		using UART with STM32 protocol or USB with DFU protocol
> +		NB: access to not volatile memory (NOR/NAND/SD/eMMC) is based
> +		    on U-Boot DFU framework
> +
>  config CMD_STM32KEY
>  	bool "command stm32key to fuse public key hash"
>  	default y
> diff --git a/arch/arm/mach-stm32mp/Makefile b/arch/arm/mach-stm32mp/Makefile
> index 19ca3b08a5..c6ab3cecf0 100644
> --- a/arch/arm/mach-stm32mp/Makefile
> +++ b/arch/arm/mach-stm32mp/Makefile
> @@ -10,6 +10,7 @@ obj-y += syscon.o
>  ifdef CONFIG_SPL_BUILD
>  obj-y += spl.o
>  else
> +obj-$(CONFIG_CMD_STM32PROG) += cmd_stm32prog/
>  obj-y += bsec.o
>  obj-$(CONFIG_CMD_STM32KEY) += cmd_stm32key.o
>  obj-$(CONFIG_ARMV7_PSCI) += psci.o
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/Makefile b/arch/arm/mach-stm32mp/cmd_stm32prog/Makefile
> new file mode 100644
> index 0000000000..14f722759c
> --- /dev/null
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/Makefile
> @@ -0,0 +1,8 @@
> +# SPDX-License-Identifier: GPL-2.0+
> +#
> +# Copyright (C) 2020, STMicroelectronics - All Rights Reserved
> +#
> +
> +obj-y += cmd_stm32prog.o
> +obj-y += stm32prog.o
> +obj-y += stm32prog_usb.o
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
> new file mode 100644
> index 0000000000..3e8b426444
> --- /dev/null
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
> @@ -0,0 +1,96 @@
> +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
> +/*
> + * Copyright (C) 2020, STMicroelectronics - All Rights Reserved
> + */
> +
> +#include <common.h>
> +#include <command.h>
> +#include <dfu.h>
> +#include "stm32prog.h"
> +
> +struct stm32prog_data *stm32prog_data;
> +
> +static int do_stm32prog(cmd_tbl_t *cmdtp, int flag, int argc,
> +			char * const argv[])
> +{
> +	ulong	addr, size;
> +	int dev, ret;
> +	enum stm32prog_link_t link = LINK_UNDEFINED;
> +	bool reset = false;
> +	struct stm32prog_data *data;
> +
> +	if (argc < 3 ||  argc > 5)
> +		return CMD_RET_USAGE;
> +
> +	if (!strcmp(argv[1], "usb"))
> +		link = LINK_USB;
> +
> +	if (link == LINK_UNDEFINED) {
> +		pr_err("not supported link=%s\n", argv[1]);
> +		return CMD_RET_USAGE;
> +	}
> +	dev = (int)simple_strtoul(argv[2], NULL, 10);
> +
> +	addr = STM32_DDR_BASE;
> +	size = 0;
> +	if (argc > 3) {
> +		addr = simple_strtoul(argv[3], NULL, 16);
> +		if (!addr)
> +			return CMD_RET_FAILURE;
> +	}
> +	if (argc > 4)
> +		size = simple_strtoul(argv[4], NULL, 16);
> +
> +	data = (struct stm32prog_data *)malloc(sizeof(*data));
> +
> +	if (!data) {
> +		pr_err("Alloc failed.");
> +		return CMD_RET_FAILURE;
> +	}
> +	stm32prog_data = data;
> +
> +	ret = stm32prog_init(data, addr, size);
> +	if (ret)
> +		printf("Invalid or missing layout file.");
> +
> +	/* prepare DFU for device read/write */
> +	ret = stm32prog_dfu_init(data);
> +	if (ret)
> +		goto cleanup;
> +
> +	switch (link) {
> +	case LINK_USB:
> +		reset = stm32prog_usb_loop(data, dev);
> +		break;
> +	default:
> +		goto cleanup;
> +	}
> +
> +	stm32prog_clean(data);
> +	free(stm32prog_data);
> +	stm32prog_data = NULL;
> +
> +	puts("Download done\n");
> +	if (reset) {
> +		puts("Reset...\n");
> +		run_command("reset", 0);
> +	}
> +
> +	return CMD_RET_SUCCESS;
> +
> +cleanup:
> +	stm32prog_clean(data);
> +	free(stm32prog_data);
> +	stm32prog_data = NULL;
> +
> +	return CMD_RET_FAILURE;
> +}
> +
> +U_BOOT_CMD(stm32prog, 5, 0, do_stm32prog,
> +	   "<link> <dev> [<addr>] [<size>]\n"
> +	   "start communication with tools STM32Cubeprogrammer on <link> with Flashlayout at <addr>",
> +	   "<link> = usb\n"
> +	   "<dev>  = device instance\n"
> +	   "<addr> = address of flashlayout\n"
> +	   "<size> = size of flashlayout\n"
> +);
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> new file mode 100644
> index 0000000000..e2c6c43d88
> --- /dev/null
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> @@ -0,0 +1,480 @@
> +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
> +/*
> + * Copyright (C) 2020, STMicroelectronics - All Rights Reserved
> + */
> +
> +#include <common.h>
> +#include <console.h>
> +#include <dfu.h>
> +#include <malloc.h>
> +#include <dm/uclass.h>
> +#include <linux/list.h>
> +#include <linux/list_sort.h>
> +#include <linux/sizes.h>
> +
> +#include "stm32prog.h"
> +
> +#define OPT_SELECT	BIT(0)
> +#define OPT_EMPTY	BIT(1)
> +
> +#define IS_SELECT(part)	((part)->option & OPT_SELECT)
> +#define IS_EMPTY(part)	((part)->option & OPT_EMPTY)
> +
> +#define ALT_BUF_LEN			SZ_1K
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +char *stm32prog_get_error(struct stm32prog_data *data)
> +{
> +	static const char error_msg[] = "Unspecified";
> +
> +	if (strlen(data->error) == 0)
> +		strcpy(data->error, error_msg);
> +
> +	return data->error;
> +}
> +
> +static int parse_flash_layout(struct stm32prog_data *data,
> +			      ulong addr,
> +			      ulong size)
> +{
> +	return -ENODEV;
> +}
> +
> +static int __init part_cmp(void *priv, struct list_head *a, struct list_head *b)
> +{
> +	struct stm32prog_part_t *parta, *partb;
> +
> +	parta = container_of(a, struct stm32prog_part_t, list);
> +	partb = container_of(b, struct stm32prog_part_t, list);
> +
> +	return parta->addr > partb->addr ? 1 : -1;
> +}
> +
> +static int init_device(struct stm32prog_data *data,
> +		       struct stm32prog_dev_t *dev)
> +{
> +	struct blk_desc *block_dev = NULL;
> +	int part_id;
> +	u64 first_addr = 0, last_addr = 0;
> +	struct stm32prog_part_t *part, *next_part;
> +
> +	switch (dev->target) {
> +	default:
> +		stm32prog_err("unknown device type = %d", dev->target);
> +		return -ENODEV;
> +	}
> +
> +	/* order partition list in offset order */
> +	list_sort(NULL, &dev->part_list, &part_cmp);
> +	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->part_type == RAW_IMAGE) {
> +			part->part_id = 0x0;
> +			part->addr = 0x0;
> +			if (block_dev)
> +				part->size = block_dev->lba * block_dev->blksz;
> +			else
> +				part->size = last_addr;
> +			pr_debug("-- : %1d %02x %14s %02d %02d.%02d %08llx %08llx\n",
> +				 part->option, part->id, part->name,
> +				 part->part_type, part->target,
> +				 part->dev_id, part->addr, part->size);
> +			continue;
> +		}
> +
> +		part->part_id = part_id++;
> +
> +		/* last partition : size to the end of the device */
> +		if (part->list.next != &dev->part_list) {
> +			next_part =
> +				container_of(part->list.next,
> +					     struct stm32prog_part_t,
> +					     list);
> +			if (part->addr < next_part->addr) {
> +				part->size = next_part->addr -
> +					     part->addr;
> +			} else {
> +				stm32prog_err("%s (0x%x): same address : 0x%llx == %s (0x%x): 0x%llx",
> +					      part->name, part->id,
> +					      part->addr,
> +					      next_part->name,
> +					      next_part->id,
> +					      next_part->addr);
> +				return -EINVAL;
> +			}
> +		} else {
> +			if (part->addr <= last_addr) {
> +				part->size = last_addr - part->addr;
> +			} else {
> +				stm32prog_err("%s (0x%x): invalid address 0x%llx (max=0x%llx)",
> +					      part->name, part->id,
> +					      part->addr, last_addr);
> +				return -EINVAL;
> +			}
> +		}
> +		if (part->addr < first_addr) {
> +			stm32prog_err("%s (0x%x): invalid address 0x%llx (min=0x%llx)",
> +				      part->name, part->id,
> +				      part->addr, first_addr);
> +			return -EINVAL;
> +		}
> +
> +		pr_debug("%02d : %1d %02x %14s %02d %02d.%02d %08llx %08llx",
> +			 part->part_id, part->option, part->id, part->name,
> +			 part->part_type, part->target,
> +			 part->dev_id, part->addr, part->size);
> +	}
> +	return 0;
> +}
> +
> +static int treat_partition_list(struct stm32prog_data *data)
> +{
> +	int i, j;
> +	struct stm32prog_part_t *part;
> +
> +	for (j = 0; j < STM32PROG_MAX_DEV; j++) {
> +		data->dev[j].target = STM32PROG_NONE;
> +		INIT_LIST_HEAD(&data->dev[j].part_list);
> +	}
> +
> +	for (i = 0; i < data->part_nb; i++) {
> +		part = &data->part_array[i];
> +		part->alt_id = -1;
> +
> +		/* skip partition with IP="none" */
> +		if (part->target == STM32PROG_NONE) {
> +			if (IS_SELECT(part)) {
> +				stm32prog_err("Layout: selected none phase = 0x%x",
> +					      part->id);
> +				return -EINVAL;
> +			}
> +			continue;
> +		}
> +
> +		if (part->id == PHASE_FLASHLAYOUT ||
> +		    part->id > PHASE_LAST_USER) {
> +			stm32prog_err("Layout: invalid phase = 0x%x",
> +				      part->id);
> +			return -EINVAL;
> +		}
> +		for (j = i + 1; j < data->part_nb; j++) {
> +			if (part->id == data->part_array[j].id) {
> +				stm32prog_err("Layout: duplicated phase 0x%x at line %d and %d",
> +					      part->id, i, j);
> +				return -EINVAL;
> +			}
> +		}
> +		for (j = 0; j < STM32PROG_MAX_DEV; j++) {
> +			if (data->dev[j].target == STM32PROG_NONE) {
> +				/* new device found */
> +				data->dev[j].target = part->target;
> +				data->dev[j].dev_id = part->dev_id;
> +				data->dev_nb++;
> +				break;
> +			} else if ((part->target == data->dev[j].target) &&
> +				   (part->dev_id == data->dev[j].dev_id)) {
> +				break;
> +			}
> +		}
> +		if (j == STM32PROG_MAX_DEV) {
> +			stm32prog_err("Layout: too many device");
> +			return -EINVAL;
> +		}
> +		part->dev = &data->dev[j];
> +		list_add_tail(&part->list, &data->dev[j].part_list);
> +	}
> +
> +	return 0;
> +}
> +
> +static int stm32prog_alt_add(struct stm32prog_data *data,
> +			     struct dfu_entity *dfu,
> +			     struct stm32prog_part_t *part)
> +{
> +	int ret = 0;
> +	int offset = 0;
> +	char devstr[10];
> +	char dfustr[10];
> +	char buf[ALT_BUF_LEN];
> +	u32 size;
> +	char multiplier,  type;
> +
> +	/* max 3 digit for sector size */
> +	if (part->size > SZ_1M) {
> +		size = (u32)(part->size / SZ_1M);
> +		multiplier = 'M';
> +	} else if (part->size > SZ_1K) {
> +		size = (u32)(part->size / SZ_1K);
> +		multiplier = 'K';
> +	} else {
> +		size = (u32)part->size;
> +		multiplier = 'B';
> +	}
> +	if (IS_SELECT(part) && !IS_EMPTY(part))
> +		type = 'e'; /*Readable and Writeable*/
> +	else
> +		type = 'a';/*Readable*/
> +
> +	memset(buf, 0, sizeof(buf));
> +	offset = snprintf(buf, ALT_BUF_LEN - offset,
> +			  "@%s/0x%02x/1*%d%c%c ",
> +			  part->name, part->id,
> +			  size, multiplier, type);
> +
> +	if (part->part_type == RAW_IMAGE) {
> +		u64 dfu_size;
> +
> +		dfu_size = part->size;
> +		offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
> +				   "raw 0x0 0x%llx", dfu_size);
> +	} else {
> +		offset += snprintf(buf + offset,
> +				   ALT_BUF_LEN - offset,
> +				   "part");
> +		offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
> +				   " %d;", part->part_id);
> +	}
> +	switch (part->target) {
> +	default:
> +		stm32prog_err("invalid target: %d", part->target);
> +		return -ENODEV;
> +	}
> +	pr_debug("dfu_alt_add(%s,%s,%s)\n", dfustr, devstr, buf);
> +	ret = dfu_alt_add(dfu, dfustr, devstr, buf);
> +	pr_debug("dfu_alt_add(%s,%s,%s) result %d\n",
> +		 dfustr, devstr, buf, ret);
> +
> +	return ret;
> +}
> +
> +static int stm32prog_alt_add_virt(struct dfu_entity *dfu,
> +				  char *name, int phase, int size)
> +{
> +	int ret = 0;
> +	char devstr[4];
> +	char buf[ALT_BUF_LEN];
> +
> +	sprintf(devstr, "%d", phase);
> +	sprintf(buf, "@%s/0x%02x/1*%dBe", name, phase, size);
> +	ret = dfu_alt_add(dfu, "virt", devstr, buf);
> +	pr_debug("dfu_alt_add(virt,%s,%s) result %d\n", devstr, buf, ret);
> +
> +	return ret;
> +}
> +
> +static int dfu_init_entities(struct stm32prog_data *data)
> +{
> +	int ret = 0;
> +	int phase, i, alt_id;
> +	struct stm32prog_part_t *part;
> +	struct dfu_entity *dfu;
> +	int alt_nb;
> +
> +	alt_nb = 1; /* number of virtual = CMD */
> +	if (data->part_nb == 0)
> +		alt_nb++;  /* +1 for FlashLayout */
> +	else
> +		for (i = 0; i < data->part_nb; i++) {
> +			if (data->part_array[i].target != STM32PROG_NONE)
> +				alt_nb++;
> +		}
> +
> +	if (dfu_alt_init(alt_nb, &dfu))
> +		return -ENODEV;
> +
> +	puts("DFU alt info setting: ");
> +	if (data->part_nb) {
> +		alt_id = 0;
> +		for (phase = 1;
> +		     (phase <= PHASE_LAST_USER) &&
> +		     (alt_id < alt_nb) && !ret;
> +		     phase++) {
> +			/* ordering alt setting by phase id */
> +			part = NULL;
> +			for (i = 0; i < data->part_nb; i++) {
> +				if (phase == data->part_array[i].id) {
> +					part = &data->part_array[i];
> +					break;
> +				}
> +			}
> +			if (!part)
> +				continue;
> +			if (part->target == STM32PROG_NONE)
> +				continue;
> +			part->alt_id = alt_id;
> +			alt_id++;
> +
> +			ret = stm32prog_alt_add(data, dfu, part);
> +		}
> +	} else {
> +		char buf[ALT_BUF_LEN];
> +
> +		sprintf(buf, "@FlashLayout/0x%02x/1*256Ke ram %x 40000",
> +			PHASE_FLASHLAYOUT, STM32_DDR_BASE);
> +		ret = dfu_alt_add(dfu, "ram", NULL, buf);
> +		pr_debug("dfu_alt_add(ram, NULL,%s) result %d\n", buf, ret);
> +	}
> +
> +	if (!ret)
> +		ret = stm32prog_alt_add_virt(dfu, "virtual", PHASE_CMD, 512);
> +
> +	if (ret)
> +		stm32prog_err("dfu init failed: %d", ret);
> +	puts("done\n");
> +
> +#ifdef DEBUG
> +	dfu_show_entities();
> +#endif
> +	return ret;
> +}
> +
> +static void stm32prog_end_phase(struct stm32prog_data *data)
> +{
> +	if (data->phase == PHASE_FLASHLAYOUT) {
> +		if (parse_flash_layout(data, STM32_DDR_BASE, 0))
> +			stm32prog_err("Layout: invalid FlashLayout");
> +		return;
> +	}
> +
> +	if (!data->cur_part)
> +		return;
> +}
> +
> +void stm32prog_do_reset(struct stm32prog_data *data)
> +{
> +	if (data->phase == PHASE_RESET) {
> +		data->phase = PHASE_DO_RESET;
> +		puts("Reset requested\n");
> +	}
> +}
> +
> +void stm32prog_next_phase(struct stm32prog_data *data)
> +{
> +	int phase, i;
> +	struct stm32prog_part_t *part;
> +	bool found;
> +
> +	phase = data->phase;
> +	switch (phase) {
> +	case PHASE_RESET:
> +	case PHASE_END:
> +	case PHASE_DO_RESET:
> +		return;
> +	}
> +
> +	/* found next selected partition */
> +	data->cur_part = NULL;
> +	data->phase = PHASE_END;
> +	found = false;
> +	do {
> +		phase++;
> +		if (phase > PHASE_LAST_USER)
> +			break;
> +		for (i = 0; i < data->part_nb; i++) {
> +			part = &data->part_array[i];
> +			if (part->id == phase) {
> +				if (IS_SELECT(part) && !IS_EMPTY(part)) {
> +					data->cur_part = part;
> +					data->phase = phase;
> +					found = true;
> +				}
> +				break;
> +			}
> +		}
> +	} while (!found);
> +
> +	if (data->phase == PHASE_END)
> +		puts("Phase=END\n");
> +}
> +
> +static void stm32prog_devices_init(struct stm32prog_data *data)
> +{
> +	int i;
> +	int ret;
> +
> +	ret = treat_partition_list(data);
> +	if (ret)
> +		goto error;
> +
> +	/* initialize the selected device */
> +	for (i = 0; i < data->dev_nb; i++) {
> +		ret = init_device(data, &data->dev[i]);
> +		if (ret)
> +			goto error;
> +	}
> +
> +	return;
> +
> +error:
> +	data->part_nb = 0;
> +}
> +
> +int stm32prog_dfu_init(struct stm32prog_data *data)
> +{
> +	/* init device if no error */
> +	if (data->part_nb)
> +		stm32prog_devices_init(data);
> +
> +	if (data->part_nb)
> +		stm32prog_next_phase(data);
> +
> +	/* prepare DFU for device read/write */
> +	dfu_free_entities();
> +	return dfu_init_entities(data);
> +}
> +
> +int stm32prog_init(struct stm32prog_data *data, ulong addr, ulong size)
> +{
> +	memset(data, 0x0, sizeof(*data));
> +	data->phase = PHASE_FLASHLAYOUT;
> +
> +	return parse_flash_layout(data, addr, size);
> +}
> +
> +void stm32prog_clean(struct stm32prog_data *data)
> +{
> +	/* clean */
> +	dfu_free_entities();
> +	free(data->part_array);
> +	free(data->header_data);
> +}
> +
> +/* DFU callback: used after serial and direct DFU USB access */
> +void dfu_flush_callback(struct dfu_entity *dfu)
> +{
> +	if (!stm32prog_data)
> +		return;
> +
> +	if (dfu->dev_type == DFU_DEV_RAM) {
> +		if (dfu->alt == 0 &&
> +		    stm32prog_data->phase == PHASE_FLASHLAYOUT) {
> +			stm32prog_end_phase(stm32prog_data);
> +			/* waiting DFU DETACH for reenumeration */
> +		}
> +	}
> +
> +	if (!stm32prog_data->cur_part)
> +		return;
> +
> +	if (dfu->alt == stm32prog_data->cur_part->alt_id) {
> +		stm32prog_end_phase(stm32prog_data);
> +		stm32prog_next_phase(stm32prog_data);
> +	}
> +}
> +
> +void dfu_initiated_callback(struct dfu_entity *dfu)
> +{
> +	if (!stm32prog_data)
> +		return;
> +
> +	if (!stm32prog_data->cur_part)
> +		return;
> +
> +	/* force the saved offset for the current partition */
> +	if (dfu->alt == stm32prog_data->cur_part->alt_id) {
> +		dfu->offset = stm32prog_data->offset;
> +		pr_debug("dfu offset = 0x%llx\n", dfu->offset);
> +	}
> +}
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
> new file mode 100644
> index 0000000000..b44b6f89af
> --- /dev/null
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
> @@ -0,0 +1,137 @@
> +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
> +/*
> + * Copyright (C) 2020, STMicroelectronics - All Rights Reserved
> + */
> +
> +#ifndef _STM32PROG_H_
> +#define _STM32PROG_H_
> +
> +/* - phase defines ------------------------------------------------*/
> +#define PHASE_FLASHLAYOUT	0x00
> +#define PHASE_FIRST_USER	0x10
> +#define PHASE_LAST_USER		0xF0
> +#define PHASE_CMD		0xF1
> +#define PHASE_END		0xFE
> +#define PHASE_RESET		0xFF
> +#define PHASE_DO_RESET		0x1FF
> +
> +#define DEFAULT_ADDRESS		0xFFFFFFFF
> +
> +enum stm32prog_target {
> +	STM32PROG_NONE,
> +};
> +
> +enum stm32prog_link_t {
> +	LINK_USB,
> +	LINK_UNDEFINED,
> +};
> +
> +struct image_header_s {
> +	bool	present;
> +	u32	image_checksum;
> +	u32	image_length;
> +};
> +
> +struct raw_header_s {
> +	u32 magic_number;
> +	u32 image_signature[64 / 4];
> +	u32 image_checksum;
> +	u32 header_version;
> +	u32 image_length;
> +	u32 image_entry_point;
> +	u32 reserved1;
> +	u32 load_address;
> +	u32 reserved2;
> +	u32 version_number;
> +	u32 option_flags;
> +	u32 ecdsa_algorithm;
> +	u32 ecdsa_public_key[64 / 4];
> +	u32 padding[83 / 4];
> +	u32 binary_type;
> +};
> +
> +#define BL_HEADER_SIZE	sizeof(struct raw_header_s)
> +
> +/* partition type in flashlayout file */
> +enum stm32prog_part_type {
> +	PART_BINARY,
> +	PART_SYSTEM,
> +	PART_FILESYSTEM,
> +	RAW_IMAGE
> +};
> +
> +/* device information */
> +struct stm32prog_dev_t {
> +	enum stm32prog_target	target;
> +	char			dev_id;
> +	/* list of partition for this device / ordered in offset */
> +	struct list_head	part_list;
> +};
> +
> +/* partition information build from FlashLayout and device */
> +struct stm32prog_part_t {
> +	/* FlashLayout information */
> +	int			option;
> +	int			id;
> +	enum stm32prog_part_type part_type;
> +	enum stm32prog_target	target;
> +	char			dev_id;
> +
> +	/* partition name
> +	 * (16 char in gpt, + 1 for null terminated string
> +	 */
> +	char			name[16 + 1];
> +	u64			addr;
> +	u64			size;
> +
> +	/* information on associated device */
> +	struct stm32prog_dev_t	*dev;		/* pointer to device */
> +	u16			part_id;	/* partition id in device */
> +	int			alt_id;		/* alt id in usb/dfu */
> +
> +	struct list_head	list;
> +};
> +
> +#define STM32PROG_MAX_DEV 5
> +struct stm32prog_data {
> +	/* Layout information */
> +	int			dev_nb;		/* device number*/
> +	struct stm32prog_dev_t	dev[STM32PROG_MAX_DEV];	/* array of device */
> +	int			part_nb;	/* nb of partition */
> +	struct stm32prog_part_t	*part_array;	/* array of partition */
> +
> +	/* command internal information */
> +	unsigned int		phase;
> +	u32			offset;
> +	char			error[255];
> +	struct stm32prog_part_t	*cur_part;
> +
> +	/* STM32 header information */
> +	struct raw_header_s	*header_data;
> +	struct image_header_s	header;
> +};
> +
> +extern struct stm32prog_data *stm32prog_data;
> +
> +/* generic part*/
> +u8 stm32prog_header_check(struct raw_header_s *raw_header,
> +			  struct image_header_s *header);
> +int stm32prog_dfu_init(struct stm32prog_data *data);
> +void stm32prog_next_phase(struct stm32prog_data *data);
> +void stm32prog_do_reset(struct stm32prog_data *data);
> +
> +char *stm32prog_get_error(struct stm32prog_data *data);
> +
> +#define stm32prog_err(args...) {\
> +	if (data->phase != PHASE_RESET) { \
> +		sprintf(data->error, args); \
> +		data->phase = PHASE_RESET; \
> +		pr_err("Error: %s\n", data->error); } \
> +	}
> +
> +/* Main function */
> +int stm32prog_init(struct stm32prog_data *data, ulong addr, ulong size);
> +bool stm32prog_usb_loop(struct stm32prog_data *data, int dev);
> +void stm32prog_clean(struct stm32prog_data *data);
> +
> +#endif
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c
> new file mode 100644
> index 0000000000..ed2cdbc66f
> --- /dev/null
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c
> @@ -0,0 +1,206 @@
> +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
> +/*
> + * Copyright (C) 2020, STMicroelectronics - All Rights Reserved
> + */
> +
> +#include <common.h>
> +#include <dfu.h>
> +#include <g_dnl.h>
> +#include <usb.h>
> +#include <asm/arch/stm32prog.h>
> +#include <asm/arch/sys_proto.h>
> +#include "stm32prog.h"
> +
> +static int stm32prog_set_phase(struct stm32prog_data *data, u8 phase,
> +			       u32 offset)
> +{
> +	struct stm32prog_part_t *part;
> +	int i;
> +
> +	if (phase == data->phase) {
> +		data->offset = offset;
> +		return 0;
> +	}
> +
> +	/* found partition for phase */
> +	for (i = 0; i < data->part_nb; i++) {
> +		part = &data->part_array[i];
> +		if (part->id == phase) {
> +			data->cur_part = part;
> +			data->phase = phase;
> +			data->offset = offset;
> +			return 0;
> +		}
> +	}
> +
> +	return  -EINVAL;
> +}
> +
> +static int stm32prog_cmd_write(u64 offset, void *buf, long *len)
> +{
> +	u8 phase;
> +	u32 address;
> +	u8 *pt = buf;
> +	void (*entry)(void);
> +	int ret;
> +
> +	if (*len < 5) {
> +		pr_err("size not allowed\n");
> +		return  -EINVAL;
> +	}
> +	if (offset) {
> +		pr_err("invalid offset\n");
> +		return  -EINVAL;
> +	}
> +	phase = pt[0];
> +	address = (pt[1] << 24) | (pt[2] << 16) | (pt[3] << 8) | pt[4];
> +	if (phase == PHASE_RESET) {
> +		entry = (void *)address;
> +		printf("## Starting application at 0x%x ...\n", address);
> +		(*entry)();
> +		printf("## Application terminated\n");
> +		return 0;
> +	}
> +	/* set phase and offset */
> +	ret = stm32prog_set_phase(stm32prog_data, phase, address);
> +	if (ret)
> +		pr_err("failed: %d\n", ret);
> +	return ret;
> +}
> +
> +#define PHASE_MIN_SIZE	9
> +static int stm32prog_cmd_read(u64 offset, void *buf, long *len)
> +{
> +	u32 destination = DEFAULT_ADDRESS; /* destination address */
> +	u32 dfu_offset;
> +	u8 *pt_buf = buf;
> +	int phase;
> +	char *err_msg;
> +	int length;
> +
> +	if (*len < PHASE_MIN_SIZE) {
> +		pr_err("request exceeds allowed area\n");
> +		return  -EINVAL;
> +	}
> +	if (offset) {
> +		*len = 0; /* EOF for second request */
> +		return 0;
> +	}
> +	phase = stm32prog_data->phase;
> +	if (phase == PHASE_FLASHLAYOUT)
> +		destination = STM32_DDR_BASE;
> +	dfu_offset = stm32prog_data->offset;
> +
> +	/* mandatory header, size = PHASE_MIN_SIZE */
> +	*pt_buf++ = (u8)(phase & 0xFF);
> +	*pt_buf++ = (u8)(destination);
> +	*pt_buf++ = (u8)(destination >> 8);
> +	*pt_buf++ = (u8)(destination >> 16);
> +	*pt_buf++ = (u8)(destination >> 24);
> +	*pt_buf++ = (u8)(dfu_offset);
> +	*pt_buf++ = (u8)(dfu_offset >> 8);
> +	*pt_buf++ = (u8)(dfu_offset >> 16);
> +	*pt_buf++ = (u8)(dfu_offset >> 24);
> +
> +	if (phase == PHASE_RESET || phase == PHASE_DO_RESET) {
> +		err_msg = stm32prog_get_error(stm32prog_data);
> +		length = strlen(err_msg);
> +		if (length + PHASE_MIN_SIZE > *len)
> +			length = *len - PHASE_MIN_SIZE;
> +
> +		memcpy(pt_buf, err_msg, length);
> +		*len = PHASE_MIN_SIZE + length;
> +		stm32prog_do_reset(stm32prog_data);
> +	} else if (phase == PHASE_FLASHLAYOUT) {
> +		*pt_buf++ = stm32prog_data->part_nb ? 1 : 0;
> +		*len = PHASE_MIN_SIZE + 1;
> +	} else {
> +		*len = PHASE_MIN_SIZE;
> +	}
> +
> +	return 0;
> +}
> +
> +int stm32prog_write_medium_virt(struct dfu_entity *dfu, u64 offset,
> +				void *buf, long *len)
> +{
> +	if (dfu->dev_type != DFU_DEV_VIRT)
> +		return -EINVAL;
> +
> +	switch (dfu->data.virt.dev_num) {
> +	case PHASE_CMD:
> +		return stm32prog_cmd_write(offset, buf, len);
> +	}
> +	*len = 0;
> +	return 0;
> +}
> +
> +int stm32prog_read_medium_virt(struct dfu_entity *dfu, u64 offset,
> +			       void *buf, long *len)
> +{
> +	if (dfu->dev_type != DFU_DEV_VIRT)
> +		return -EINVAL;
> +
> +	switch (dfu->data.virt.dev_num) {
> +	case PHASE_CMD:
> +		return stm32prog_cmd_read(offset, buf, len);
> +	}
> +	*len = 0;
> +	return 0;
> +}
> +
> +int stm32prog_get_medium_size_virt(struct dfu_entity *dfu, u64 *size)
> +{
> +	if (dfu->dev_type != DFU_DEV_VIRT) {
> +		*size = 0;
> +		pr_debug("%s, invalid dev_type = %d\n",
> +			 __func__, dfu->dev_type);
> +		return -EINVAL;
> +	}
> +
> +	switch (dfu->data.virt.dev_num) {
> +	case PHASE_CMD:
> +		*size = 512;
> +		break;
> +	}
> +
> +	return 0;
> +}
> +
> +bool stm32prog_usb_loop(struct stm32prog_data *data, int dev)
> +{
> +	int ret;
> +	bool result;
> +	/* USB download gadget for STM32 Programmer */
> +	char product[128];
> +
> +	snprintf(product, sizeof(product),
> +		 "USB download gadget at Device ID /0x%03X, @Revision ID /0x%04X",
> +		 get_cpu_dev(), get_cpu_rev());
> +	g_dnl_set_product(product);
> +
> +	if (stm32prog_data->phase == PHASE_FLASHLAYOUT) {
> +		ret = run_usb_dnl_gadget(dev, "usb_dnl_dfu");
> +		if (ret || stm32prog_data->phase == PHASE_DO_RESET)
> +			return ret;
> +		/* prepare the second enumeration with the FlashLayout */
> +		if (stm32prog_data->phase == PHASE_FLASHLAYOUT)
> +			stm32prog_dfu_init(data);
> +		/* found next selected partition */
> +		stm32prog_next_phase(data);
> +	}
> +
> +	ret = run_usb_dnl_gadget(dev, "usb_dnl_dfu");
> +
> +	result = !!(ret) || (stm32prog_data->phase == PHASE_DO_RESET);
> +
> +	g_dnl_set_product(NULL);
> +
> +	return result;
> +}
> +
> +int g_dnl_get_board_bcd_device_number(int gcnum)
> +{
> +	pr_debug("%s\n", __func__);
> +	return 0x200;
> +}
> diff --git a/arch/arm/mach-stm32mp/include/mach/stm32prog.h b/arch/arm/mach-stm32mp/include/mach/stm32prog.h
> new file mode 100644
> index 0000000000..c10bff09c8
> --- /dev/null
> +++ b/arch/arm/mach-stm32mp/include/mach/stm32prog.h
> @@ -0,0 +1,12 @@
> +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
> +/*
> + * Copyright (C) 2020, STMicroelectronics - All Rights Reserved
> + */
> +
> +#define STM32PROG_VIRT_FIRST_DEV_NUM		0xF1
> +
> +int stm32prog_write_medium_virt(struct dfu_entity *dfu, u64 offset,
> +				void *buf, long *len);
> +int stm32prog_read_medium_virt(struct dfu_entity *dfu, u64 offset,
> +			       void *buf, long *len);
> +int stm32prog_get_medium_size_virt(struct dfu_entity *dfu, u64 *size);
> diff --git a/board/st/common/stm32mp_dfu.c b/board/st/common/stm32mp_dfu.c
> index e129f8c8b5..3bd005bb04 100644
> --- a/board/st/common/stm32mp_dfu.c
> +++ b/board/st/common/stm32mp_dfu.c
> @@ -11,6 +11,7 @@
>  #include <misc.h>
>  #include <mtd.h>
>  #include <mtd_node.h>
> +#include <asm/arch/stm32prog.h>
>  
>  #define DFU_ALT_BUF_LEN SZ_1K
>  
> @@ -211,12 +212,31 @@ int dfu_read_medium_virt(struct dfu_entity *dfu, u64 offset,
>  	case 0x1:
>  		return dfu_pmic_read(offset, buf, len);
>  	}
> +
> +	if (CONFIG_IS_ENABLED(CMD_STM32PROG) &&
> +	    dfu->data.virt.dev_num >= STM32PROG_VIRT_FIRST_DEV_NUM)
> +		return stm32prog_read_medium_virt(dfu, offset, buf, len);
> +
>  	*len = 0;
>  	return 0;
>  }
>  
> +int dfu_write_medium_virt(struct dfu_entity *dfu, u64 offset,
> +			  void *buf, long *len)
> +{
> +	if (CONFIG_IS_ENABLED(CMD_STM32PROG) &&
> +	    dfu->data.virt.dev_num >= STM32PROG_VIRT_FIRST_DEV_NUM)
> +		return stm32prog_write_medium_virt(dfu, offset, buf, len);
> +
> +	return -EOPNOTSUPP;
> +}
> +
>  int __weak dfu_get_medium_size_virt(struct dfu_entity *dfu, u64 *size)
>  {
> +	if (CONFIG_IS_ENABLED(CMD_STM32PROG) &&
> +	    dfu->data.virt.dev_num >= STM32PROG_VIRT_FIRST_DEV_NUM)
> +		return stm32prog_get_medium_size_virt(dfu, size);
> +
>  	*size = SZ_1K;
>  
>  	return 0;
> diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig
> index f9bc5b6086..baed3d92f5 100644
> --- a/configs/stm32mp15_basic_defconfig
> +++ b/configs/stm32mp15_basic_defconfig
> @@ -6,6 +6,7 @@ CONFIG_ENV_OFFSET=0x280000
>  CONFIG_SPL_MMC_SUPPORT=y
>  CONFIG_SPL=y
>  CONFIG_TARGET_ST_STM32MP15x=y
> +CONFIG_CMD_STM32PROG=y
>  CONFIG_ENV_OFFSET_REDUND=0x2C0000
>  CONFIG_SPL_SPI_FLASH_SUPPORT=y
>  CONFIG_SPL_SPI_SUPPORT=y
> @@ -68,9 +69,7 @@ CONFIG_ENV_UBI_VOLUME_REDUND="uboot_config_r"
>  CONFIG_SYS_RELOC_GD_ENV_ADDR=y
>  CONFIG_STM32_ADC=y
>  CONFIG_DFU_MMC=y
> -CONFIG_DFU_RAM=y
>  CONFIG_DFU_MTD=y
> -CONFIG_DFU_VIRT=y
>  CONFIG_SET_DFU_ALT_INFO=y
>  CONFIG_USB_FUNCTION_FASTBOOT=y
>  CONFIG_FASTBOOT_BUF_ADDR=0xC0000000
> diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig
> index f0d524d344..adbe304902 100644
> --- a/configs/stm32mp15_trusted_defconfig
> +++ b/configs/stm32mp15_trusted_defconfig
> @@ -4,6 +4,7 @@ CONFIG_SYS_MALLOC_F_LEN=0x3000
>  CONFIG_ENV_SECT_SIZE=0x40000
>  CONFIG_ENV_OFFSET=0x280000
>  CONFIG_TARGET_ST_STM32MP15x=y
> +CONFIG_CMD_STM32PROG=y
>  CONFIG_ENV_OFFSET_REDUND=0x2C0000
>  CONFIG_DISTRO_DEFAULTS=y
>  CONFIG_FIT=y
> @@ -54,9 +55,7 @@ CONFIG_ENV_UBI_VOLUME_REDUND="uboot_config_r"
>  CONFIG_SYS_RELOC_GD_ENV_ADDR=y
>  CONFIG_STM32_ADC=y
>  CONFIG_DFU_MMC=y
> -CONFIG_DFU_RAM=y
>  CONFIG_DFU_MTD=y
> -CONFIG_DFU_VIRT=y
>  CONFIG_SET_DFU_ALT_INFO=y
>  CONFIG_USB_FUNCTION_FASTBOOT=y
>  CONFIG_FASTBOOT_BUF_ADDR=0xC0000000


Reviewed-by: Patrice Chotard <patrice.chotard@st.com>

Thanks

Patrice

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 04/18] stm32mp: add the command stm32prog
  2020-03-18  8:24 ` [PATCH 04/18] stm32mp: add the command stm32prog Patrick Delaunay
  2020-04-14 13:00   ` Patrice CHOTARD
@ 2020-04-14 13:03   ` Patrice CHOTARD
  1 sibling, 0 replies; 40+ messages in thread
From: Patrice CHOTARD @ 2020-04-14 13:03 UTC (permalink / raw)
  To: u-boot

Hi

On 3/18/20 9:24 AM, Patrick Delaunay wrote:
> Add a specific command stm32prog for STM32MP soc family
> witch allows to program the boot devices with the tool
> STM32CubeProgrammer (http://www.st.com/STM32CubeProg).
>
> This command uses the same UART STM32 protocol than MCU
> STM32 with or USB with DFU protocol v1.1 (ithe MCU ST
> extension are no supported).
>
> The executed actions are based on a tab separated value file
> with a stm32 header, the FlashLayout file
> (https://wiki.st.com/stm32mpu/wiki/STM32CubeProgrammer_flashlayout).
>
> This file is parsed by the U-Boot command to:
> - initialize the devices
> - create the partition table on each device
> - initialize the DFU backend to access to not volatile memory
>   (NOR/NAND/SD/eMMC) or to virtual device (OTP/PMIC)
>
> Up to STM32PROG_MAX_DEV (5) devices can be updated with a FlashLayout.
>
> The communication between U-Boot and STM32CubeProgrammer is done with
> the specific alternate configuration (see "AN5275: USB DFU/USART protocols
> used in STM32MP1 Series bootloaders" for details).
>
> The command stm32prog is executed when a boot from USB is detected
> (selected with bootpins) and we can program the boot devices with
> a simple command (on Windows or Linux):
>
> PC $>  STM32_Programmer_CLI -c port=usb1 -w flaslayout.tsv
>
> 1/ the ROM code loads TF-A in embedded RAM (DFU or uart)
> 2/ TF-A loads flashlayout file and U-Boot in DDR (DFU or uart)
> 3/ U-Boot executes the stm32prog command (DFU or uart)
>
> Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
> ---
>
>  arch/arm/mach-stm32mp/Kconfig                 |  12 +
>  arch/arm/mach-stm32mp/Makefile                |   1 +
>  arch/arm/mach-stm32mp/cmd_stm32prog/Makefile  |   8 +
>  .../cmd_stm32prog/cmd_stm32prog.c             |  96 ++++
>  .../mach-stm32mp/cmd_stm32prog/stm32prog.c    | 480 ++++++++++++++++++
>  .../mach-stm32mp/cmd_stm32prog/stm32prog.h    | 137 +++++
>  .../cmd_stm32prog/stm32prog_usb.c             | 206 ++++++++
>  .../arm/mach-stm32mp/include/mach/stm32prog.h |  12 +
>  board/st/common/stm32mp_dfu.c                 |  20 +
>  configs/stm32mp15_basic_defconfig             |   3 +-
>  configs/stm32mp15_trusted_defconfig           |   3 +-
>  11 files changed, 974 insertions(+), 4 deletions(-)
>  create mode 100644 arch/arm/mach-stm32mp/cmd_stm32prog/Makefile
>  create mode 100644 arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
>  create mode 100644 arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
>  create mode 100644 arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
>  create mode 100644 arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c
>  create mode 100644 arch/arm/mach-stm32mp/include/mach/stm32prog.h
>
> diff --git a/arch/arm/mach-stm32mp/Kconfig b/arch/arm/mach-stm32mp/Kconfig
> index 1a5545b98d..61466f6125 100644
> --- a/arch/arm/mach-stm32mp/Kconfig
> +++ b/arch/arm/mach-stm32mp/Kconfig
> @@ -114,6 +114,18 @@ config STM32_ETZPC
>  	help
>  	  Say y to enable STM32 Extended TrustZone Protection
>  
> +config CMD_STM32PROG
> +	bool "command stm32prog for STM32CudeProgrammer"
> +	select DFU
> +	select DFU_RAM
> +	select DFU_VIRT
> +	help
> +		activate a specific command stm32prog for STM32MP soc family
> +		witch update the device with the tools STM32CubeProgrammer,
> +		using UART with STM32 protocol or USB with DFU protocol
> +		NB: access to not volatile memory (NOR/NAND/SD/eMMC) is based
> +		    on U-Boot DFU framework
> +
>  config CMD_STM32KEY
>  	bool "command stm32key to fuse public key hash"
>  	default y
> diff --git a/arch/arm/mach-stm32mp/Makefile b/arch/arm/mach-stm32mp/Makefile
> index 19ca3b08a5..c6ab3cecf0 100644
> --- a/arch/arm/mach-stm32mp/Makefile
> +++ b/arch/arm/mach-stm32mp/Makefile
> @@ -10,6 +10,7 @@ obj-y += syscon.o
>  ifdef CONFIG_SPL_BUILD
>  obj-y += spl.o
>  else
> +obj-$(CONFIG_CMD_STM32PROG) += cmd_stm32prog/
>  obj-y += bsec.o
>  obj-$(CONFIG_CMD_STM32KEY) += cmd_stm32key.o
>  obj-$(CONFIG_ARMV7_PSCI) += psci.o
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/Makefile b/arch/arm/mach-stm32mp/cmd_stm32prog/Makefile
> new file mode 100644
> index 0000000000..14f722759c
> --- /dev/null
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/Makefile
> @@ -0,0 +1,8 @@
> +# SPDX-License-Identifier: GPL-2.0+
> +#
> +# Copyright (C) 2020, STMicroelectronics - All Rights Reserved
> +#
> +
> +obj-y += cmd_stm32prog.o
> +obj-y += stm32prog.o
> +obj-y += stm32prog_usb.o
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
> new file mode 100644
> index 0000000000..3e8b426444
> --- /dev/null
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
> @@ -0,0 +1,96 @@
> +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
> +/*
> + * Copyright (C) 2020, STMicroelectronics - All Rights Reserved
> + */
> +
> +#include <common.h>
> +#include <command.h>
> +#include <dfu.h>
> +#include "stm32prog.h"
> +
> +struct stm32prog_data *stm32prog_data;
> +
> +static int do_stm32prog(cmd_tbl_t *cmdtp, int flag, int argc,
> +			char * const argv[])
> +{
> +	ulong	addr, size;
> +	int dev, ret;
> +	enum stm32prog_link_t link = LINK_UNDEFINED;
> +	bool reset = false;
> +	struct stm32prog_data *data;
> +
> +	if (argc < 3 ||  argc > 5)
> +		return CMD_RET_USAGE;
> +
> +	if (!strcmp(argv[1], "usb"))
> +		link = LINK_USB;
> +
> +	if (link == LINK_UNDEFINED) {
> +		pr_err("not supported link=%s\n", argv[1]);
> +		return CMD_RET_USAGE;
> +	}
> +	dev = (int)simple_strtoul(argv[2], NULL, 10);
> +
> +	addr = STM32_DDR_BASE;
> +	size = 0;
> +	if (argc > 3) {
> +		addr = simple_strtoul(argv[3], NULL, 16);
> +		if (!addr)
> +			return CMD_RET_FAILURE;
> +	}
> +	if (argc > 4)
> +		size = simple_strtoul(argv[4], NULL, 16);
> +
> +	data = (struct stm32prog_data *)malloc(sizeof(*data));
> +
> +	if (!data) {
> +		pr_err("Alloc failed.");
> +		return CMD_RET_FAILURE;
> +	}
> +	stm32prog_data = data;
> +
> +	ret = stm32prog_init(data, addr, size);
> +	if (ret)
> +		printf("Invalid or missing layout file.");
> +
> +	/* prepare DFU for device read/write */
> +	ret = stm32prog_dfu_init(data);
> +	if (ret)
> +		goto cleanup;
> +
> +	switch (link) {
> +	case LINK_USB:
> +		reset = stm32prog_usb_loop(data, dev);
> +		break;
> +	default:
> +		goto cleanup;
> +	}
> +
> +	stm32prog_clean(data);
> +	free(stm32prog_data);
> +	stm32prog_data = NULL;
> +
> +	puts("Download done\n");
> +	if (reset) {
> +		puts("Reset...\n");
> +		run_command("reset", 0);
> +	}
> +
> +	return CMD_RET_SUCCESS;
> +
> +cleanup:
> +	stm32prog_clean(data);
> +	free(stm32prog_data);
> +	stm32prog_data = NULL;
> +
> +	return CMD_RET_FAILURE;
> +}
> +
> +U_BOOT_CMD(stm32prog, 5, 0, do_stm32prog,
> +	   "<link> <dev> [<addr>] [<size>]\n"
> +	   "start communication with tools STM32Cubeprogrammer on <link> with Flashlayout at <addr>",
> +	   "<link> = usb\n"
> +	   "<dev>  = device instance\n"
> +	   "<addr> = address of flashlayout\n"
> +	   "<size> = size of flashlayout\n"
> +);
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> new file mode 100644
> index 0000000000..e2c6c43d88
> --- /dev/null
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> @@ -0,0 +1,480 @@
> +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
> +/*
> + * Copyright (C) 2020, STMicroelectronics - All Rights Reserved
> + */
> +
> +#include <common.h>
> +#include <console.h>
> +#include <dfu.h>
> +#include <malloc.h>
> +#include <dm/uclass.h>
> +#include <linux/list.h>
> +#include <linux/list_sort.h>
> +#include <linux/sizes.h>
> +
> +#include "stm32prog.h"
> +
> +#define OPT_SELECT	BIT(0)
> +#define OPT_EMPTY	BIT(1)
> +
> +#define IS_SELECT(part)	((part)->option & OPT_SELECT)
> +#define IS_EMPTY(part)	((part)->option & OPT_EMPTY)
> +
> +#define ALT_BUF_LEN			SZ_1K
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +char *stm32prog_get_error(struct stm32prog_data *data)
> +{
> +	static const char error_msg[] = "Unspecified";
> +
> +	if (strlen(data->error) == 0)
> +		strcpy(data->error, error_msg);
> +
> +	return data->error;
> +}
> +
> +static int parse_flash_layout(struct stm32prog_data *data,
> +			      ulong addr,
> +			      ulong size)
> +{
> +	return -ENODEV;
> +}
> +
> +static int __init part_cmp(void *priv, struct list_head *a, struct list_head *b)
> +{
> +	struct stm32prog_part_t *parta, *partb;
> +
> +	parta = container_of(a, struct stm32prog_part_t, list);
> +	partb = container_of(b, struct stm32prog_part_t, list);
> +
> +	return parta->addr > partb->addr ? 1 : -1;
> +}
> +
> +static int init_device(struct stm32prog_data *data,
> +		       struct stm32prog_dev_t *dev)
> +{
> +	struct blk_desc *block_dev = NULL;
> +	int part_id;
> +	u64 first_addr = 0, last_addr = 0;
> +	struct stm32prog_part_t *part, *next_part;
> +
> +	switch (dev->target) {
> +	default:
> +		stm32prog_err("unknown device type = %d", dev->target);
> +		return -ENODEV;
> +	}
> +
> +	/* order partition list in offset order */
> +	list_sort(NULL, &dev->part_list, &part_cmp);
> +	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->part_type == RAW_IMAGE) {
> +			part->part_id = 0x0;
> +			part->addr = 0x0;
> +			if (block_dev)
> +				part->size = block_dev->lba * block_dev->blksz;
> +			else
> +				part->size = last_addr;
> +			pr_debug("-- : %1d %02x %14s %02d %02d.%02d %08llx %08llx\n",
> +				 part->option, part->id, part->name,
> +				 part->part_type, part->target,
> +				 part->dev_id, part->addr, part->size);
> +			continue;
> +		}
> +
> +		part->part_id = part_id++;
> +
> +		/* last partition : size to the end of the device */
> +		if (part->list.next != &dev->part_list) {
> +			next_part =
> +				container_of(part->list.next,
> +					     struct stm32prog_part_t,
> +					     list);
> +			if (part->addr < next_part->addr) {
> +				part->size = next_part->addr -
> +					     part->addr;
> +			} else {
> +				stm32prog_err("%s (0x%x): same address : 0x%llx == %s (0x%x): 0x%llx",
> +					      part->name, part->id,
> +					      part->addr,
> +					      next_part->name,
> +					      next_part->id,
> +					      next_part->addr);
> +				return -EINVAL;
> +			}
> +		} else {
> +			if (part->addr <= last_addr) {
> +				part->size = last_addr - part->addr;
> +			} else {
> +				stm32prog_err("%s (0x%x): invalid address 0x%llx (max=0x%llx)",
> +					      part->name, part->id,
> +					      part->addr, last_addr);
> +				return -EINVAL;
> +			}
> +		}
> +		if (part->addr < first_addr) {
> +			stm32prog_err("%s (0x%x): invalid address 0x%llx (min=0x%llx)",
> +				      part->name, part->id,
> +				      part->addr, first_addr);
> +			return -EINVAL;
> +		}
> +
> +		pr_debug("%02d : %1d %02x %14s %02d %02d.%02d %08llx %08llx",
> +			 part->part_id, part->option, part->id, part->name,
> +			 part->part_type, part->target,
> +			 part->dev_id, part->addr, part->size);
> +	}
> +	return 0;
> +}
> +
> +static int treat_partition_list(struct stm32prog_data *data)
> +{
> +	int i, j;
> +	struct stm32prog_part_t *part;
> +
> +	for (j = 0; j < STM32PROG_MAX_DEV; j++) {
> +		data->dev[j].target = STM32PROG_NONE;
> +		INIT_LIST_HEAD(&data->dev[j].part_list);
> +	}
> +
> +	for (i = 0; i < data->part_nb; i++) {
> +		part = &data->part_array[i];
> +		part->alt_id = -1;
> +
> +		/* skip partition with IP="none" */
> +		if (part->target == STM32PROG_NONE) {
> +			if (IS_SELECT(part)) {
> +				stm32prog_err("Layout: selected none phase = 0x%x",
> +					      part->id);
> +				return -EINVAL;
> +			}
> +			continue;
> +		}
> +
> +		if (part->id == PHASE_FLASHLAYOUT ||
> +		    part->id > PHASE_LAST_USER) {
> +			stm32prog_err("Layout: invalid phase = 0x%x",
> +				      part->id);
> +			return -EINVAL;
> +		}
> +		for (j = i + 1; j < data->part_nb; j++) {
> +			if (part->id == data->part_array[j].id) {
> +				stm32prog_err("Layout: duplicated phase 0x%x at line %d and %d",
> +					      part->id, i, j);
> +				return -EINVAL;
> +			}
> +		}
> +		for (j = 0; j < STM32PROG_MAX_DEV; j++) {
> +			if (data->dev[j].target == STM32PROG_NONE) {
> +				/* new device found */
> +				data->dev[j].target = part->target;
> +				data->dev[j].dev_id = part->dev_id;
> +				data->dev_nb++;
> +				break;
> +			} else if ((part->target == data->dev[j].target) &&
> +				   (part->dev_id == data->dev[j].dev_id)) {
> +				break;
> +			}
> +		}
> +		if (j == STM32PROG_MAX_DEV) {
> +			stm32prog_err("Layout: too many device");
> +			return -EINVAL;
> +		}
> +		part->dev = &data->dev[j];
> +		list_add_tail(&part->list, &data->dev[j].part_list);
> +	}
> +
> +	return 0;
> +}
> +
> +static int stm32prog_alt_add(struct stm32prog_data *data,
> +			     struct dfu_entity *dfu,
> +			     struct stm32prog_part_t *part)
> +{
> +	int ret = 0;
> +	int offset = 0;
> +	char devstr[10];
> +	char dfustr[10];
> +	char buf[ALT_BUF_LEN];
> +	u32 size;
> +	char multiplier,  type;
> +
> +	/* max 3 digit for sector size */
> +	if (part->size > SZ_1M) {
> +		size = (u32)(part->size / SZ_1M);
> +		multiplier = 'M';
> +	} else if (part->size > SZ_1K) {
> +		size = (u32)(part->size / SZ_1K);
> +		multiplier = 'K';
> +	} else {
> +		size = (u32)part->size;
> +		multiplier = 'B';
> +	}
> +	if (IS_SELECT(part) && !IS_EMPTY(part))
> +		type = 'e'; /*Readable and Writeable*/
> +	else
> +		type = 'a';/*Readable*/
> +
> +	memset(buf, 0, sizeof(buf));
> +	offset = snprintf(buf, ALT_BUF_LEN - offset,
> +			  "@%s/0x%02x/1*%d%c%c ",
> +			  part->name, part->id,
> +			  size, multiplier, type);
> +
> +	if (part->part_type == RAW_IMAGE) {
> +		u64 dfu_size;
> +
> +		dfu_size = part->size;
> +		offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
> +				   "raw 0x0 0x%llx", dfu_size);
> +	} else {
> +		offset += snprintf(buf + offset,
> +				   ALT_BUF_LEN - offset,
> +				   "part");
> +		offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
> +				   " %d;", part->part_id);
> +	}
> +	switch (part->target) {
> +	default:
> +		stm32prog_err("invalid target: %d", part->target);
> +		return -ENODEV;
> +	}
> +	pr_debug("dfu_alt_add(%s,%s,%s)\n", dfustr, devstr, buf);
> +	ret = dfu_alt_add(dfu, dfustr, devstr, buf);
> +	pr_debug("dfu_alt_add(%s,%s,%s) result %d\n",
> +		 dfustr, devstr, buf, ret);
> +
> +	return ret;
> +}
> +
> +static int stm32prog_alt_add_virt(struct dfu_entity *dfu,
> +				  char *name, int phase, int size)
> +{
> +	int ret = 0;
> +	char devstr[4];
> +	char buf[ALT_BUF_LEN];
> +
> +	sprintf(devstr, "%d", phase);
> +	sprintf(buf, "@%s/0x%02x/1*%dBe", name, phase, size);
> +	ret = dfu_alt_add(dfu, "virt", devstr, buf);
> +	pr_debug("dfu_alt_add(virt,%s,%s) result %d\n", devstr, buf, ret);
> +
> +	return ret;
> +}
> +
> +static int dfu_init_entities(struct stm32prog_data *data)
> +{
> +	int ret = 0;
> +	int phase, i, alt_id;
> +	struct stm32prog_part_t *part;
> +	struct dfu_entity *dfu;
> +	int alt_nb;
> +
> +	alt_nb = 1; /* number of virtual = CMD */
> +	if (data->part_nb == 0)
> +		alt_nb++;  /* +1 for FlashLayout */
> +	else
> +		for (i = 0; i < data->part_nb; i++) {
> +			if (data->part_array[i].target != STM32PROG_NONE)
> +				alt_nb++;
> +		}
> +
> +	if (dfu_alt_init(alt_nb, &dfu))
> +		return -ENODEV;
> +
> +	puts("DFU alt info setting: ");
> +	if (data->part_nb) {
> +		alt_id = 0;
> +		for (phase = 1;
> +		     (phase <= PHASE_LAST_USER) &&
> +		     (alt_id < alt_nb) && !ret;
> +		     phase++) {
> +			/* ordering alt setting by phase id */
> +			part = NULL;
> +			for (i = 0; i < data->part_nb; i++) {
> +				if (phase == data->part_array[i].id) {
> +					part = &data->part_array[i];
> +					break;
> +				}
> +			}
> +			if (!part)
> +				continue;
> +			if (part->target == STM32PROG_NONE)
> +				continue;
> +			part->alt_id = alt_id;
> +			alt_id++;
> +
> +			ret = stm32prog_alt_add(data, dfu, part);
> +		}
> +	} else {
> +		char buf[ALT_BUF_LEN];
> +
> +		sprintf(buf, "@FlashLayout/0x%02x/1*256Ke ram %x 40000",
> +			PHASE_FLASHLAYOUT, STM32_DDR_BASE);
> +		ret = dfu_alt_add(dfu, "ram", NULL, buf);
> +		pr_debug("dfu_alt_add(ram, NULL,%s) result %d\n", buf, ret);
> +	}
> +
> +	if (!ret)
> +		ret = stm32prog_alt_add_virt(dfu, "virtual", PHASE_CMD, 512);
> +
> +	if (ret)
> +		stm32prog_err("dfu init failed: %d", ret);
> +	puts("done\n");
> +
> +#ifdef DEBUG
> +	dfu_show_entities();
> +#endif
> +	return ret;
> +}
> +
> +static void stm32prog_end_phase(struct stm32prog_data *data)
> +{
> +	if (data->phase == PHASE_FLASHLAYOUT) {
> +		if (parse_flash_layout(data, STM32_DDR_BASE, 0))
> +			stm32prog_err("Layout: invalid FlashLayout");
> +		return;
> +	}
> +
> +	if (!data->cur_part)
> +		return;
> +}
> +
> +void stm32prog_do_reset(struct stm32prog_data *data)
> +{
> +	if (data->phase == PHASE_RESET) {
> +		data->phase = PHASE_DO_RESET;
> +		puts("Reset requested\n");
> +	}
> +}
> +
> +void stm32prog_next_phase(struct stm32prog_data *data)
> +{
> +	int phase, i;
> +	struct stm32prog_part_t *part;
> +	bool found;
> +
> +	phase = data->phase;
> +	switch (phase) {
> +	case PHASE_RESET:
> +	case PHASE_END:
> +	case PHASE_DO_RESET:
> +		return;
> +	}
> +
> +	/* found next selected partition */
> +	data->cur_part = NULL;
> +	data->phase = PHASE_END;
> +	found = false;
> +	do {
> +		phase++;
> +		if (phase > PHASE_LAST_USER)
> +			break;
> +		for (i = 0; i < data->part_nb; i++) {
> +			part = &data->part_array[i];
> +			if (part->id == phase) {
> +				if (IS_SELECT(part) && !IS_EMPTY(part)) {
> +					data->cur_part = part;
> +					data->phase = phase;
> +					found = true;
> +				}
> +				break;
> +			}
> +		}
> +	} while (!found);
> +
> +	if (data->phase == PHASE_END)
> +		puts("Phase=END\n");
> +}
> +
> +static void stm32prog_devices_init(struct stm32prog_data *data)
> +{
> +	int i;
> +	int ret;
> +
> +	ret = treat_partition_list(data);
> +	if (ret)
> +		goto error;
> +
> +	/* initialize the selected device */
> +	for (i = 0; i < data->dev_nb; i++) {
> +		ret = init_device(data, &data->dev[i]);
> +		if (ret)
> +			goto error;
> +	}
> +
> +	return;
> +
> +error:
> +	data->part_nb = 0;
> +}
> +
> +int stm32prog_dfu_init(struct stm32prog_data *data)
> +{
> +	/* init device if no error */
> +	if (data->part_nb)
> +		stm32prog_devices_init(data);
> +
> +	if (data->part_nb)
> +		stm32prog_next_phase(data);
> +
> +	/* prepare DFU for device read/write */
> +	dfu_free_entities();
> +	return dfu_init_entities(data);
> +}
> +
> +int stm32prog_init(struct stm32prog_data *data, ulong addr, ulong size)
> +{
> +	memset(data, 0x0, sizeof(*data));
> +	data->phase = PHASE_FLASHLAYOUT;
> +
> +	return parse_flash_layout(data, addr, size);
> +}
> +
> +void stm32prog_clean(struct stm32prog_data *data)
> +{
> +	/* clean */
> +	dfu_free_entities();
> +	free(data->part_array);
> +	free(data->header_data);
> +}
> +
> +/* DFU callback: used after serial and direct DFU USB access */
> +void dfu_flush_callback(struct dfu_entity *dfu)
> +{
> +	if (!stm32prog_data)
> +		return;
> +
> +	if (dfu->dev_type == DFU_DEV_RAM) {
> +		if (dfu->alt == 0 &&
> +		    stm32prog_data->phase == PHASE_FLASHLAYOUT) {
> +			stm32prog_end_phase(stm32prog_data);
> +			/* waiting DFU DETACH for reenumeration */
> +		}
> +	}
> +
> +	if (!stm32prog_data->cur_part)
> +		return;
> +
> +	if (dfu->alt == stm32prog_data->cur_part->alt_id) {
> +		stm32prog_end_phase(stm32prog_data);
> +		stm32prog_next_phase(stm32prog_data);
> +	}
> +}
> +
> +void dfu_initiated_callback(struct dfu_entity *dfu)
> +{
> +	if (!stm32prog_data)
> +		return;
> +
> +	if (!stm32prog_data->cur_part)
> +		return;
> +
> +	/* force the saved offset for the current partition */
> +	if (dfu->alt == stm32prog_data->cur_part->alt_id) {
> +		dfu->offset = stm32prog_data->offset;
> +		pr_debug("dfu offset = 0x%llx\n", dfu->offset);
> +	}
> +}
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
> new file mode 100644
> index 0000000000..b44b6f89af
> --- /dev/null
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
> @@ -0,0 +1,137 @@
> +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
> +/*
> + * Copyright (C) 2020, STMicroelectronics - All Rights Reserved
> + */
> +
> +#ifndef _STM32PROG_H_
> +#define _STM32PROG_H_
> +
> +/* - phase defines ------------------------------------------------*/
> +#define PHASE_FLASHLAYOUT	0x00
> +#define PHASE_FIRST_USER	0x10
> +#define PHASE_LAST_USER		0xF0
> +#define PHASE_CMD		0xF1
> +#define PHASE_END		0xFE
> +#define PHASE_RESET		0xFF
> +#define PHASE_DO_RESET		0x1FF
> +
> +#define DEFAULT_ADDRESS		0xFFFFFFFF
> +
> +enum stm32prog_target {
> +	STM32PROG_NONE,
> +};
> +
> +enum stm32prog_link_t {
> +	LINK_USB,
> +	LINK_UNDEFINED,
> +};
> +
> +struct image_header_s {
> +	bool	present;
> +	u32	image_checksum;
> +	u32	image_length;
> +};
> +
> +struct raw_header_s {
> +	u32 magic_number;
> +	u32 image_signature[64 / 4];
> +	u32 image_checksum;
> +	u32 header_version;
> +	u32 image_length;
> +	u32 image_entry_point;
> +	u32 reserved1;
> +	u32 load_address;
> +	u32 reserved2;
> +	u32 version_number;
> +	u32 option_flags;
> +	u32 ecdsa_algorithm;
> +	u32 ecdsa_public_key[64 / 4];
> +	u32 padding[83 / 4];
> +	u32 binary_type;
> +};
> +
> +#define BL_HEADER_SIZE	sizeof(struct raw_header_s)
> +
> +/* partition type in flashlayout file */
> +enum stm32prog_part_type {
> +	PART_BINARY,
> +	PART_SYSTEM,
> +	PART_FILESYSTEM,
> +	RAW_IMAGE
> +};
> +
> +/* device information */
> +struct stm32prog_dev_t {
> +	enum stm32prog_target	target;
> +	char			dev_id;
> +	/* list of partition for this device / ordered in offset */
> +	struct list_head	part_list;
> +};
> +
> +/* partition information build from FlashLayout and device */
> +struct stm32prog_part_t {
> +	/* FlashLayout information */
> +	int			option;
> +	int			id;
> +	enum stm32prog_part_type part_type;
> +	enum stm32prog_target	target;
> +	char			dev_id;
> +
> +	/* partition name
> +	 * (16 char in gpt, + 1 for null terminated string
> +	 */
> +	char			name[16 + 1];
> +	u64			addr;
> +	u64			size;
> +
> +	/* information on associated device */
> +	struct stm32prog_dev_t	*dev;		/* pointer to device */
> +	u16			part_id;	/* partition id in device */
> +	int			alt_id;		/* alt id in usb/dfu */
> +
> +	struct list_head	list;
> +};
> +
> +#define STM32PROG_MAX_DEV 5
> +struct stm32prog_data {
> +	/* Layout information */
> +	int			dev_nb;		/* device number*/
> +	struct stm32prog_dev_t	dev[STM32PROG_MAX_DEV];	/* array of device */
> +	int			part_nb;	/* nb of partition */
> +	struct stm32prog_part_t	*part_array;	/* array of partition */
> +
> +	/* command internal information */
> +	unsigned int		phase;
> +	u32			offset;
> +	char			error[255];
> +	struct stm32prog_part_t	*cur_part;
> +
> +	/* STM32 header information */
> +	struct raw_header_s	*header_data;
> +	struct image_header_s	header;
> +};
> +
> +extern struct stm32prog_data *stm32prog_data;
> +
> +/* generic part*/
> +u8 stm32prog_header_check(struct raw_header_s *raw_header,
> +			  struct image_header_s *header);
> +int stm32prog_dfu_init(struct stm32prog_data *data);
> +void stm32prog_next_phase(struct stm32prog_data *data);
> +void stm32prog_do_reset(struct stm32prog_data *data);
> +
> +char *stm32prog_get_error(struct stm32prog_data *data);
> +
> +#define stm32prog_err(args...) {\
> +	if (data->phase != PHASE_RESET) { \
> +		sprintf(data->error, args); \
> +		data->phase = PHASE_RESET; \
> +		pr_err("Error: %s\n", data->error); } \
> +	}
> +
> +/* Main function */
> +int stm32prog_init(struct stm32prog_data *data, ulong addr, ulong size);
> +bool stm32prog_usb_loop(struct stm32prog_data *data, int dev);
> +void stm32prog_clean(struct stm32prog_data *data);
> +
> +#endif
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c
> new file mode 100644
> index 0000000000..ed2cdbc66f
> --- /dev/null
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c
> @@ -0,0 +1,206 @@
> +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
> +/*
> + * Copyright (C) 2020, STMicroelectronics - All Rights Reserved
> + */
> +
> +#include <common.h>
> +#include <dfu.h>
> +#include <g_dnl.h>
> +#include <usb.h>
> +#include <asm/arch/stm32prog.h>
> +#include <asm/arch/sys_proto.h>
> +#include "stm32prog.h"
> +
> +static int stm32prog_set_phase(struct stm32prog_data *data, u8 phase,
> +			       u32 offset)
> +{
> +	struct stm32prog_part_t *part;
> +	int i;
> +
> +	if (phase == data->phase) {
> +		data->offset = offset;
> +		return 0;
> +	}
> +
> +	/* found partition for phase */
> +	for (i = 0; i < data->part_nb; i++) {
> +		part = &data->part_array[i];
> +		if (part->id == phase) {
> +			data->cur_part = part;
> +			data->phase = phase;
> +			data->offset = offset;
> +			return 0;
> +		}
> +	}
> +
> +	return  -EINVAL;
> +}
> +
> +static int stm32prog_cmd_write(u64 offset, void *buf, long *len)
> +{
> +	u8 phase;
> +	u32 address;
> +	u8 *pt = buf;
> +	void (*entry)(void);
> +	int ret;
> +
> +	if (*len < 5) {
> +		pr_err("size not allowed\n");
> +		return  -EINVAL;
> +	}
> +	if (offset) {
> +		pr_err("invalid offset\n");
> +		return  -EINVAL;
> +	}
> +	phase = pt[0];
> +	address = (pt[1] << 24) | (pt[2] << 16) | (pt[3] << 8) | pt[4];
> +	if (phase == PHASE_RESET) {
> +		entry = (void *)address;
> +		printf("## Starting application at 0x%x ...\n", address);
> +		(*entry)();
> +		printf("## Application terminated\n");
> +		return 0;
> +	}
> +	/* set phase and offset */
> +	ret = stm32prog_set_phase(stm32prog_data, phase, address);
> +	if (ret)
> +		pr_err("failed: %d\n", ret);
> +	return ret;
> +}
> +
> +#define PHASE_MIN_SIZE	9
> +static int stm32prog_cmd_read(u64 offset, void *buf, long *len)
> +{
> +	u32 destination = DEFAULT_ADDRESS; /* destination address */
> +	u32 dfu_offset;
> +	u8 *pt_buf = buf;
> +	int phase;
> +	char *err_msg;
> +	int length;
> +
> +	if (*len < PHASE_MIN_SIZE) {
> +		pr_err("request exceeds allowed area\n");
> +		return  -EINVAL;
> +	}
> +	if (offset) {
> +		*len = 0; /* EOF for second request */
> +		return 0;
> +	}
> +	phase = stm32prog_data->phase;
> +	if (phase == PHASE_FLASHLAYOUT)
> +		destination = STM32_DDR_BASE;
> +	dfu_offset = stm32prog_data->offset;
> +
> +	/* mandatory header, size = PHASE_MIN_SIZE */
> +	*pt_buf++ = (u8)(phase & 0xFF);
> +	*pt_buf++ = (u8)(destination);
> +	*pt_buf++ = (u8)(destination >> 8);
> +	*pt_buf++ = (u8)(destination >> 16);
> +	*pt_buf++ = (u8)(destination >> 24);
> +	*pt_buf++ = (u8)(dfu_offset);
> +	*pt_buf++ = (u8)(dfu_offset >> 8);
> +	*pt_buf++ = (u8)(dfu_offset >> 16);
> +	*pt_buf++ = (u8)(dfu_offset >> 24);
> +
> +	if (phase == PHASE_RESET || phase == PHASE_DO_RESET) {
> +		err_msg = stm32prog_get_error(stm32prog_data);
> +		length = strlen(err_msg);
> +		if (length + PHASE_MIN_SIZE > *len)
> +			length = *len - PHASE_MIN_SIZE;
> +
> +		memcpy(pt_buf, err_msg, length);
> +		*len = PHASE_MIN_SIZE + length;
> +		stm32prog_do_reset(stm32prog_data);
> +	} else if (phase == PHASE_FLASHLAYOUT) {
> +		*pt_buf++ = stm32prog_data->part_nb ? 1 : 0;
> +		*len = PHASE_MIN_SIZE + 1;
> +	} else {
> +		*len = PHASE_MIN_SIZE;
> +	}
> +
> +	return 0;
> +}
> +
> +int stm32prog_write_medium_virt(struct dfu_entity *dfu, u64 offset,
> +				void *buf, long *len)
> +{
> +	if (dfu->dev_type != DFU_DEV_VIRT)
> +		return -EINVAL;
> +
> +	switch (dfu->data.virt.dev_num) {
> +	case PHASE_CMD:
> +		return stm32prog_cmd_write(offset, buf, len);
> +	}
> +	*len = 0;
> +	return 0;
> +}
> +
> +int stm32prog_read_medium_virt(struct dfu_entity *dfu, u64 offset,
> +			       void *buf, long *len)
> +{
> +	if (dfu->dev_type != DFU_DEV_VIRT)
> +		return -EINVAL;
> +
> +	switch (dfu->data.virt.dev_num) {
> +	case PHASE_CMD:
> +		return stm32prog_cmd_read(offset, buf, len);
> +	}
> +	*len = 0;
> +	return 0;
> +}
> +
> +int stm32prog_get_medium_size_virt(struct dfu_entity *dfu, u64 *size)
> +{
> +	if (dfu->dev_type != DFU_DEV_VIRT) {
> +		*size = 0;
> +		pr_debug("%s, invalid dev_type = %d\n",
> +			 __func__, dfu->dev_type);
> +		return -EINVAL;
> +	}
> +
> +	switch (dfu->data.virt.dev_num) {
> +	case PHASE_CMD:
> +		*size = 512;
> +		break;
> +	}
> +
> +	return 0;
> +}
> +
> +bool stm32prog_usb_loop(struct stm32prog_data *data, int dev)
> +{
> +	int ret;
> +	bool result;
> +	/* USB download gadget for STM32 Programmer */
> +	char product[128];
> +
> +	snprintf(product, sizeof(product),
> +		 "USB download gadget at Device ID /0x%03X, @Revision ID /0x%04X",
> +		 get_cpu_dev(), get_cpu_rev());
> +	g_dnl_set_product(product);
> +
> +	if (stm32prog_data->phase == PHASE_FLASHLAYOUT) {
> +		ret = run_usb_dnl_gadget(dev, "usb_dnl_dfu");
> +		if (ret || stm32prog_data->phase == PHASE_DO_RESET)
> +			return ret;
> +		/* prepare the second enumeration with the FlashLayout */
> +		if (stm32prog_data->phase == PHASE_FLASHLAYOUT)
> +			stm32prog_dfu_init(data);
> +		/* found next selected partition */
> +		stm32prog_next_phase(data);
> +	}
> +
> +	ret = run_usb_dnl_gadget(dev, "usb_dnl_dfu");
> +
> +	result = !!(ret) || (stm32prog_data->phase == PHASE_DO_RESET);
> +
> +	g_dnl_set_product(NULL);
> +
> +	return result;
> +}
> +
> +int g_dnl_get_board_bcd_device_number(int gcnum)
> +{
> +	pr_debug("%s\n", __func__);
> +	return 0x200;
> +}
> diff --git a/arch/arm/mach-stm32mp/include/mach/stm32prog.h b/arch/arm/mach-stm32mp/include/mach/stm32prog.h
> new file mode 100644
> index 0000000000..c10bff09c8
> --- /dev/null
> +++ b/arch/arm/mach-stm32mp/include/mach/stm32prog.h
> @@ -0,0 +1,12 @@
> +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */
> +/*
> + * Copyright (C) 2020, STMicroelectronics - All Rights Reserved
> + */
> +
> +#define STM32PROG_VIRT_FIRST_DEV_NUM		0xF1
> +
> +int stm32prog_write_medium_virt(struct dfu_entity *dfu, u64 offset,
> +				void *buf, long *len);
> +int stm32prog_read_medium_virt(struct dfu_entity *dfu, u64 offset,
> +			       void *buf, long *len);
> +int stm32prog_get_medium_size_virt(struct dfu_entity *dfu, u64 *size);
> diff --git a/board/st/common/stm32mp_dfu.c b/board/st/common/stm32mp_dfu.c
> index e129f8c8b5..3bd005bb04 100644
> --- a/board/st/common/stm32mp_dfu.c
> +++ b/board/st/common/stm32mp_dfu.c
> @@ -11,6 +11,7 @@
>  #include <misc.h>
>  #include <mtd.h>
>  #include <mtd_node.h>
> +#include <asm/arch/stm32prog.h>
>  
>  #define DFU_ALT_BUF_LEN SZ_1K
>  
> @@ -211,12 +212,31 @@ int dfu_read_medium_virt(struct dfu_entity *dfu, u64 offset,
>  	case 0x1:
>  		return dfu_pmic_read(offset, buf, len);
>  	}
> +
> +	if (CONFIG_IS_ENABLED(CMD_STM32PROG) &&
> +	    dfu->data.virt.dev_num >= STM32PROG_VIRT_FIRST_DEV_NUM)
> +		return stm32prog_read_medium_virt(dfu, offset, buf, len);
> +
>  	*len = 0;
>  	return 0;
>  }
>  
> +int dfu_write_medium_virt(struct dfu_entity *dfu, u64 offset,
> +			  void *buf, long *len)
> +{
> +	if (CONFIG_IS_ENABLED(CMD_STM32PROG) &&
> +	    dfu->data.virt.dev_num >= STM32PROG_VIRT_FIRST_DEV_NUM)
> +		return stm32prog_write_medium_virt(dfu, offset, buf, len);
> +
> +	return -EOPNOTSUPP;
> +}
> +
>  int __weak dfu_get_medium_size_virt(struct dfu_entity *dfu, u64 *size)
>  {
> +	if (CONFIG_IS_ENABLED(CMD_STM32PROG) &&
> +	    dfu->data.virt.dev_num >= STM32PROG_VIRT_FIRST_DEV_NUM)
> +		return stm32prog_get_medium_size_virt(dfu, size);
> +
>  	*size = SZ_1K;
>  
>  	return 0;
> diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig
> index f9bc5b6086..baed3d92f5 100644
> --- a/configs/stm32mp15_basic_defconfig
> +++ b/configs/stm32mp15_basic_defconfig
> @@ -6,6 +6,7 @@ CONFIG_ENV_OFFSET=0x280000
>  CONFIG_SPL_MMC_SUPPORT=y
>  CONFIG_SPL=y
>  CONFIG_TARGET_ST_STM32MP15x=y
> +CONFIG_CMD_STM32PROG=y
>  CONFIG_ENV_OFFSET_REDUND=0x2C0000
>  CONFIG_SPL_SPI_FLASH_SUPPORT=y
>  CONFIG_SPL_SPI_SUPPORT=y
> @@ -68,9 +69,7 @@ CONFIG_ENV_UBI_VOLUME_REDUND="uboot_config_r"
>  CONFIG_SYS_RELOC_GD_ENV_ADDR=y
>  CONFIG_STM32_ADC=y
>  CONFIG_DFU_MMC=y
> -CONFIG_DFU_RAM=y
>  CONFIG_DFU_MTD=y
> -CONFIG_DFU_VIRT=y
>  CONFIG_SET_DFU_ALT_INFO=y
>  CONFIG_USB_FUNCTION_FASTBOOT=y
>  CONFIG_FASTBOOT_BUF_ADDR=0xC0000000
> diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig
> index f0d524d344..adbe304902 100644
> --- a/configs/stm32mp15_trusted_defconfig
> +++ b/configs/stm32mp15_trusted_defconfig
> @@ -4,6 +4,7 @@ CONFIG_SYS_MALLOC_F_LEN=0x3000
>  CONFIG_ENV_SECT_SIZE=0x40000
>  CONFIG_ENV_OFFSET=0x280000
>  CONFIG_TARGET_ST_STM32MP15x=y
> +CONFIG_CMD_STM32PROG=y
>  CONFIG_ENV_OFFSET_REDUND=0x2C0000
>  CONFIG_DISTRO_DEFAULTS=y
>  CONFIG_FIT=y
> @@ -54,9 +55,7 @@ CONFIG_ENV_UBI_VOLUME_REDUND="uboot_config_r"
>  CONFIG_SYS_RELOC_GD_ENV_ADDR=y
>  CONFIG_STM32_ADC=y
>  CONFIG_DFU_MMC=y
> -CONFIG_DFU_RAM=y
>  CONFIG_DFU_MTD=y
> -CONFIG_DFU_VIRT=y
>  CONFIG_SET_DFU_ALT_INFO=y
>  CONFIG_USB_FUNCTION_FASTBOOT=y
>  CONFIG_FASTBOOT_BUF_ADDR=0xC0000000

Reviewed-by: Patrice Chotard <patrice.chotard@st.com>

Thanks

Patrice

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 05/18] stm32mp: stm32prog: add flash layout parsing
  2020-03-18  8:24 ` [PATCH 05/18] stm32mp: stm32prog: add flash layout parsing Patrick Delaunay
@ 2020-04-14 13:03   ` Patrice CHOTARD
  0 siblings, 0 replies; 40+ messages in thread
From: Patrice CHOTARD @ 2020-04-14 13:03 UTC (permalink / raw)
  To: u-boot

Hi

On 3/18/20 9:24 AM, Patrick Delaunay wrote:
> Build the list of device and of partition with
> a tab separated value file with a stm32 header: the FlashLayout.tsv
> (https://wiki.st.com/stm32mpu/wiki/STM32CubeProgrammer_flashlayout)
>
> Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
> ---
>
>  .../mach-stm32mp/cmd_stm32prog/stm32prog.c    | 372 +++++++++++++++++-
>  1 file changed, 371 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> index e2c6c43d88..11fe479072 100644
> --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> @@ -24,6 +24,17 @@
>  
>  DECLARE_GLOBAL_DATA_PTR;
>  
> +/* order of column in flash layout file */
> +enum stm32prog_col_t {
> +	COL_OPTION,
> +	COL_ID,
> +	COL_NAME,
> +	COL_TYPE,
> +	COL_IP,
> +	COL_OFFSET,
> +	COL_NB_STM32
> +};
> +
>  char *stm32prog_get_error(struct stm32prog_data *data)
>  {
>  	static const char error_msg[] = "Unspecified";
> @@ -34,11 +45,370 @@ char *stm32prog_get_error(struct stm32prog_data *data)
>  	return data->error;
>  }
>  
> +u8 stm32prog_header_check(struct raw_header_s *raw_header,
> +			  struct image_header_s *header)
> +{
> +	unsigned int i;
> +
> +	header->present = 0;
> +	header->image_checksum = 0x0;
> +	header->image_length = 0x0;
> +
> +	if (!raw_header || !header) {
> +		pr_debug("%s:no header data\n", __func__);
> +		return -1;
> +	}
> +	if (raw_header->magic_number !=
> +		(('S' << 0) | ('T' << 8) | ('M' << 16) | (0x32 << 24))) {
> +		pr_debug("%s:invalid magic number : 0x%x\n",
> +			 __func__, raw_header->magic_number);
> +		return -2;
> +	}
> +	/* only header v1.0 supported */
> +	if (raw_header->header_version != 0x00010000) {
> +		pr_debug("%s:invalid header version : 0x%x\n",
> +			 __func__, raw_header->header_version);
> +		return -3;
> +	}
> +	if (raw_header->reserved1 != 0x0 || raw_header->reserved2) {
> +		pr_debug("%s:invalid reserved field\n", __func__);
> +		return -4;
> +	}
> +	for (i = 0; i < (sizeof(raw_header->padding) / 4); i++) {
> +		if (raw_header->padding[i] != 0) {
> +			pr_debug("%s:invalid padding field\n", __func__);
> +			return -5;
> +		}
> +	}
> +	header->present = 1;
> +	header->image_checksum = le32_to_cpu(raw_header->image_checksum);
> +	header->image_length = le32_to_cpu(raw_header->image_length);
> +
> +	return 0;
> +}
> +
> +static u32 stm32prog_header_checksum(u32 addr, struct image_header_s *header)
> +{
> +	u32 i, checksum;
> +	u8 *payload;
> +
> +	/* compute checksum on payload */
> +	payload = (u8 *)addr;
> +	checksum = 0;
> +	for (i = header->image_length; i > 0; i--)
> +		checksum += *(payload++);
> +
> +	return checksum;
> +}
> +
> +/* FLASHLAYOUT PARSING *****************************************/
> +static int parse_option(struct stm32prog_data *data,
> +			int i, char *p, struct stm32prog_part_t *part)
> +{
> +	int result = 0;
> +	char *c = p;
> +
> +	part->option = 0;
> +	if (!strcmp(p, "-"))
> +		return 0;
> +
> +	while (*c) {
> +		switch (*c) {
> +		case 'P':
> +			part->option |= OPT_SELECT;
> +			break;
> +		case 'E':
> +			part->option |= OPT_EMPTY;
> +			break;
> +		default:
> +			result = -EINVAL;
> +			stm32prog_err("Layout line %d: invalid option '%c' in %s)",
> +				      i, *c, p);
> +			return -EINVAL;
> +		}
> +		c++;
> +	}
> +	if (!(part->option & OPT_SELECT)) {
> +		stm32prog_err("Layout line %d: missing 'P' in option %s", i, p);
> +		return -EINVAL;
> +	}
> +
> +	return result;
> +}
> +
> +static int parse_id(struct stm32prog_data *data,
> +		    int i, char *p, struct stm32prog_part_t *part)
> +{
> +	int result = 0;
> +	unsigned long value;
> +
> +	result = strict_strtoul(p, 0, &value);
> +	part->id = value;
> +	if (result || value > PHASE_LAST_USER) {
> +		stm32prog_err("Layout line %d: invalid phase value = %s", i, p);
> +		result = -EINVAL;
> +	}
> +
> +	return result;
> +}
> +
> +static int parse_name(struct stm32prog_data *data,
> +		      int i, char *p, struct stm32prog_part_t *part)
> +{
> +	int result = 0;
> +
> +	if (strlen(p) < sizeof(part->name)) {
> +		strcpy(part->name, p);
> +	} else {
> +		stm32prog_err("Layout line %d: partition name too long [%d]: %s",
> +			      i, strlen(p), p);
> +		result = -EINVAL;
> +	}
> +
> +	return result;
> +}
> +
> +static int parse_type(struct stm32prog_data *data,
> +		      int i, char *p, struct stm32prog_part_t *part)
> +{
> +	int result = 0;
> +
> +	if (!strcmp(p, "Binary")) {
> +		part->part_type = PART_BINARY;
> +	} else if (!strcmp(p, "System")) {
> +		part->part_type = PART_SYSTEM;
> +	} else if (!strcmp(p, "FileSystem")) {
> +		part->part_type = PART_FILESYSTEM;
> +	} else if (!strcmp(p, "RawImage")) {
> +		part->part_type = RAW_IMAGE;
> +	} else {
> +		result = -EINVAL;
> +	}
> +	if (result)
> +		stm32prog_err("Layout line %d: type parsing error : '%s'",
> +			      i, p);
> +
> +	return result;
> +}
> +
> +static int parse_ip(struct stm32prog_data *data,
> +		    int i, char *p, struct stm32prog_part_t *part)
> +{
> +	int result = 0;
> +	unsigned int len = 0;
> +
> +	part->dev_id = 0;
> +	if (!strcmp(p, "none")) {
> +		part->target = STM32PROG_NONE;
> +	} else {
> +		result = -EINVAL;
> +	}
> +	if (len) {
> +		/* only one digit allowed for device id */
> +		if (strlen(p) != len + 1) {
> +			result = -EINVAL;
> +		} else {
> +			part->dev_id = p[len] - '0';
> +			if (part->dev_id > 9)
> +				result = -EINVAL;
> +		}
> +	}
> +	if (result)
> +		stm32prog_err("Layout line %d: ip parsing error: '%s'", i, p);
> +
> +	return result;
> +}
> +
> +static int parse_offset(struct stm32prog_data *data,
> +			int i, char *p, struct stm32prog_part_t *part)
> +{
> +	int result = 0;
> +	char *tail;
> +
> +	part->part_id = 0;
> +	part->size = 0;
> +	part->addr = simple_strtoull(p, &tail, 0);
> +	if (tail == p || *tail != '\0') {
> +		stm32prog_err("Layout line %d: invalid offset '%s'",
> +			      i, p);
> +		result = -EINVAL;
> +	}
> +
> +	return result;
> +}
> +
> +static
> +int (* const parse[COL_NB_STM32])(struct stm32prog_data *data, int i, char *p,
> +				  struct stm32prog_part_t *part) = {
> +	[COL_OPTION] = parse_option,
> +	[COL_ID] = parse_id,
> +	[COL_NAME] =  parse_name,
> +	[COL_TYPE] = parse_type,
> +	[COL_IP] = parse_ip,
> +	[COL_OFFSET] = parse_offset,
> +};
> +
>  static int parse_flash_layout(struct stm32prog_data *data,
>  			      ulong addr,
>  			      ulong size)
>  {
> -	return -ENODEV;
> +	int column = 0, part_nb = 0, ret;
> +	bool end_of_line, eof;
> +	char *p, *start, *last, *col;
> +	struct stm32prog_part_t *part;
> +	int part_list_size;
> +	int i;
> +
> +	data->part_nb = 0;
> +
> +	/* check if STM32image is detected */
> +	if (!stm32prog_header_check((struct raw_header_s *)addr,
> +				    &data->header)) {
> +		u32 checksum;
> +
> +		addr = addr + BL_HEADER_SIZE;
> +		size = data->header.image_length;
> +
> +		checksum = stm32prog_header_checksum(addr, &data->header);
> +		if (checksum != data->header.image_checksum) {
> +			stm32prog_err("Layout: invalid checksum : 0x%x expected 0x%x",
> +				      checksum, data->header.image_checksum);
> +			return -EIO;
> +		}
> +	}
> +	if (!size)
> +		return -EINVAL;
> +
> +	start = (char *)addr;
> +	last = start + size;
> +
> +	*last = 0x0; /* force null terminated string */
> +	pr_debug("flash layout =\n%s\n", start);
> +
> +	/* calculate expected number of partitions */
> +	part_list_size = 1;
> +	p = start;
> +	while (*p && (p < last)) {
> +		if (*p++ == '\n') {
> +			part_list_size++;
> +			if (p < last && *p == '#')
> +				part_list_size--;
> +		}
> +	}
> +	if (part_list_size > PHASE_LAST_USER) {
> +		stm32prog_err("Layout: too many partition (%d)",
> +			      part_list_size);
> +		return -1;
> +	}
> +	part = calloc(sizeof(struct stm32prog_part_t), part_list_size);
> +	if (!part) {
> +		stm32prog_err("Layout: alloc failed");
> +		return -ENOMEM;
> +	}
> +	data->part_array = part;
> +
> +	/* main parsing loop */
> +	i = 1;
> +	eof = false;
> +	p = start;
> +	col = start; /* 1st column */
> +	end_of_line = false;
> +	while (!eof) {
> +		switch (*p) {
> +		/* CR is ignored and replaced by NULL character */
> +		case '\r':
> +			*p = '\0';
> +			p++;
> +			continue;
> +		case '\0':
> +			end_of_line = true;
> +			eof = true;
> +			break;
> +		case '\n':
> +			end_of_line = true;
> +			break;
> +		case '\t':
> +			break;
> +		case '#':
> +			/* comment line is skipped */
> +			if (column == 0 && p == col) {
> +				while ((p < last) && *p)
> +					if (*p++ == '\n')
> +						break;
> +				col = p;
> +				i++;
> +				if (p >= last || !*p) {
> +					eof = true;
> +					end_of_line = true;
> +				}
> +				continue;
> +			}
> +			/* fall through */
> +		/* by default continue with the next character */
> +		default:
> +			p++;
> +			continue;
> +		}
> +
> +		/* replace by \0: allow string parsing for each column */
> +		*p = '\0';
> +		p++;
> +		if (p >= last) {
> +			eof = true;
> +			end_of_line = true;
> +		}
> +
> +		/* skip empty line and multiple TAB in tsv file */
> +		if (strlen(col) == 0) {
> +			col = p;
> +			/* skip empty line */
> +			if (column == 0 && end_of_line) {
> +				end_of_line = false;
> +				i++;
> +			}
> +			continue;
> +		}
> +
> +		if (column < COL_NB_STM32) {
> +			ret = parse[column](data, i, col, part);
> +			if (ret)
> +				return ret;
> +		}
> +
> +		/* save the beginning of the next column */
> +		column++;
> +		col = p;
> +
> +		if (!end_of_line)
> +			continue;
> +
> +		/* end of the line detected */
> +		end_of_line = false;
> +
> +		if (column < COL_NB_STM32) {
> +			stm32prog_err("Layout line %d: no enought column", i);
> +			return -EINVAL;
> +		}
> +		column = 0;
> +		part_nb++;
> +		part++;
> +		i++;
> +		if (part_nb >= part_list_size) {
> +			part = NULL;
> +			if (!eof) {
> +				stm32prog_err("Layout: no enought memory for %d part",
> +					      part_nb);
> +				return -EINVAL;
> +			}
> +		}
> +	}
> +	data->part_nb = part_nb;
> +	if (data->part_nb == 0) {
> +		stm32prog_err("Layout: no partition found");
> +		return -ENODEV;
> +	}
> +
> +	return 0;
>  }
>  
>  static int __init part_cmp(void *priv, struct list_head *a, struct list_head *b)

Reviewed-by: Patrice Chotard <patrice.chotard@st.com>

Thanks

Patrice

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 06/18] stm32mp: stm32prog: add MMC device
  2020-03-18  8:24 ` [PATCH 06/18] stm32mp: stm32prog: add MMC device Patrick Delaunay
@ 2020-04-14 13:04   ` Patrice CHOTARD
  2020-04-14 13:04   ` Patrice CHOTARD
  1 sibling, 0 replies; 40+ messages in thread
From: Patrice CHOTARD @ 2020-04-14 13:04 UTC (permalink / raw)
  To: u-boot

Hi

On 3/18/20 9:24 AM, Patrick Delaunay wrote:
> Add support of MMC device (based on DFU_MMC backend)
> for SD card and eMMC update.
>
> Create a GPT partitioning on the device.
>
> Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
> ---
>
>  arch/arm/mach-stm32mp/Kconfig                 |   3 +
>  .../mach-stm32mp/cmd_stm32prog/stm32prog.c    | 204 +++++++++++++++++-
>  .../mach-stm32mp/cmd_stm32prog/stm32prog.h    |   3 +
>  configs/stm32mp15_basic_defconfig             |   2 -
>  configs/stm32mp15_trusted_defconfig           |   2 -
>  5 files changed, 209 insertions(+), 5 deletions(-)
>
> diff --git a/arch/arm/mach-stm32mp/Kconfig b/arch/arm/mach-stm32mp/Kconfig
> index 61466f6125..39504e8540 100644
> --- a/arch/arm/mach-stm32mp/Kconfig
> +++ b/arch/arm/mach-stm32mp/Kconfig
> @@ -119,6 +119,9 @@ config CMD_STM32PROG
>  	select DFU
>  	select DFU_RAM
>  	select DFU_VIRT
> +	select PARTITION_TYPE_GUID
> +	imply CMD_GPT if MMC
> +	imply DFU_MMC if MMC
>  	help
>  		activate a specific command stm32prog for STM32MP soc family
>  		witch update the device with the tools STM32CubeProgrammer,
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> index 11fe479072..feb83670b5 100644
> --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> @@ -7,6 +7,7 @@
>  #include <console.h>
>  #include <dfu.h>
>  #include <malloc.h>
> +#include <mmc.h>
>  #include <dm/uclass.h>
>  #include <linux/list.h>
>  #include <linux/list_sort.h>
> @@ -14,6 +15,9 @@
>  
>  #include "stm32prog.h"
>  
> +/* Primary GPT header size for 128 entries : 17kB = 34 LBA of 512B */
> +#define GPT_HEADER_SZ	34
> +
>  #define OPT_SELECT	BIT(0)
>  #define OPT_EMPTY	BIT(1)
>  
> @@ -22,6 +26,32 @@
>  
>  #define ALT_BUF_LEN			SZ_1K
>  
> +#define ROOTFS_MMC0_UUID \
> +	EFI_GUID(0xE91C4E10, 0x16E6, 0x4C0E, \
> +		 0xBD, 0x0E, 0x77, 0xBE, 0xCF, 0x4A, 0x35, 0x82)
> +
> +#define ROOTFS_MMC1_UUID \
> +	EFI_GUID(0x491F6117, 0x415D, 0x4F53, \
> +		 0x88, 0xC9, 0x6E, 0x0D, 0xE5, 0x4D, 0xEA, 0xC6)
> +
> +#define ROOTFS_MMC2_UUID \
> +	EFI_GUID(0xFD58F1C7, 0xBE0D, 0x4338, \
> +		 0x88, 0xE9, 0xAD, 0x8F, 0x05, 0x0A, 0xEB, 0x18)
> +
> +/* RAW parttion (binary / bootloader) used Linux - reserved UUID */
> +#define LINUX_RESERVED_UUID "8DA63339-0007-60C0-C436-083AC8230908"
> +
> +/*
> + * unique partition guid (uuid) for partition named "rootfs"
> + * on each MMC instance = SD Card or eMMC
> + * allow fixed kernel bootcmd: "rootf=PARTUID=e91c4e10-..."
> + */
> +static const efi_guid_t uuid_mmc[3] = {
> +	ROOTFS_MMC0_UUID,
> +	ROOTFS_MMC1_UUID,
> +	ROOTFS_MMC2_UUID
> +};
> +
>  DECLARE_GLOBAL_DATA_PTR;
>  
>  /* order of column in flash layout file */
> @@ -200,6 +230,9 @@ static int parse_ip(struct stm32prog_data *data,
>  	part->dev_id = 0;
>  	if (!strcmp(p, "none")) {
>  		part->target = STM32PROG_NONE;
> +	} else if (!strncmp(p, "mmc", 3)) {
> +		part->target = STM32PROG_MMC;
> +		len = 3;
>  	} else {
>  		result = -EINVAL;
>  	}
> @@ -424,16 +457,50 @@ static int __init part_cmp(void *priv, struct list_head *a, struct list_head *b)
>  static int init_device(struct stm32prog_data *data,
>  		       struct stm32prog_dev_t *dev)
>  {
> +	struct mmc *mmc = NULL;
>  	struct blk_desc *block_dev = NULL;
>  	int part_id;
>  	u64 first_addr = 0, last_addr = 0;
>  	struct stm32prog_part_t *part, *next_part;
>  
>  	switch (dev->target) {
> +#ifdef CONFIG_MMC
> +	case STM32PROG_MMC:
> +		mmc = find_mmc_device(dev->dev_id);
> +		if (mmc_init(mmc)) {
> +			stm32prog_err("mmc device %d not found", dev->dev_id);
> +			return -ENODEV;
> +		}
> +		block_dev = mmc_get_blk_desc(mmc);
> +		if (!block_dev) {
> +			stm32prog_err("mmc device %d not probed", dev->dev_id);
> +			return -ENODEV;
> +		}
> +		dev->erase_size = mmc->erase_grp_size * block_dev->blksz;
> +		dev->mmc = mmc;
> +
> +		/* reserve a full erase group for each GTP headers */
> +		if (mmc->erase_grp_size > GPT_HEADER_SZ) {
> +			first_addr = dev->erase_size;
> +			last_addr = (u64)(block_dev->lba -
> +					  mmc->erase_grp_size) *
> +				    block_dev->blksz;
> +		} else {
> +			first_addr = (u64)GPT_HEADER_SZ * block_dev->blksz;
> +			last_addr = (u64)(block_dev->lba - GPT_HEADER_SZ - 1) *
> +				    block_dev->blksz;
> +		}
> +		pr_debug("MMC %d: lba=%ld blksz=%ld\n", dev->dev_id,
> +			 block_dev->lba, block_dev->blksz);
> +		pr_debug(" available address = 0x%llx..0x%llx\n",
> +			 first_addr, last_addr);
> +		break;
> +#endif
>  	default:
>  		stm32prog_err("unknown device type = %d", dev->target);
>  		return -ENODEV;
>  	}
> +	pr_debug(" erase size = 0x%x\n", dev->erase_size);
>  
>  	/* order partition list in offset order */
>  	list_sort(NULL, &dev->part_list, &part_cmp);
> @@ -491,6 +558,12 @@ static int init_device(struct stm32prog_data *data,
>  			return -EINVAL;
>  		}
>  
> +		if ((part->addr & ((u64)part->dev->erase_size - 1)) != 0) {
> +			stm32prog_err("%s (0x%x): not aligned address : 0x%llx on erase size 0x%x",
> +				      part->name, part->id, part->addr,
> +				      part->dev->erase_size);
> +			return -EINVAL;
> +		}
>  		pr_debug("%02d : %1d %02x %14s %02d %02d.%02d %08llx %08llx",
>  			 part->part_id, part->option, part->id, part->name,
>  			 part->part_type, part->target,
> @@ -559,6 +632,118 @@ static int treat_partition_list(struct stm32prog_data *data)
>  	return 0;
>  }
>  
> +static int create_partitions(struct stm32prog_data *data)
> +{
> +#ifdef CONFIG_MMC
> +	int offset = 0;
> +	const int buflen = SZ_8K;
> +	char *buf;
> +	char uuid[UUID_STR_LEN + 1];
> +	unsigned char *uuid_bin;
> +	unsigned int mmc_id;
> +	int i;
> +	bool rootfs_found;
> +	struct stm32prog_part_t *part;
> +
> +	buf = malloc(buflen);
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	puts("partitions : ");
> +	/* initialize the selected device */
> +	for (i = 0; i < data->dev_nb; i++) {
> +		offset = 0;
> +		rootfs_found = false;
> +		memset(buf, 0, buflen);
> +
> +		list_for_each_entry(part, &data->dev[i].part_list, list) {
> +			/* skip Raw Image */
> +			if (part->part_type == RAW_IMAGE)
> +				continue;
> +
> +			if (offset + 100 > buflen) {
> +				pr_debug("\n%s: buffer too small, %s skippped",
> +					 __func__, part->name);
> +				continue;
> +			}
> +
> +			if (!offset)
> +				offset += sprintf(buf, "gpt write mmc %d \"",
> +						  data->dev[i].dev_id);
> +
> +			offset += snprintf(buf + offset, buflen - offset,
> +					   "name=%s,start=0x%llx,size=0x%llx",
> +					   part->name,
> +					   part->addr,
> +					   part->size);
> +
> +			if (part->part_type == PART_BINARY)
> +				offset += snprintf(buf + offset,
> +						   buflen - offset,
> +						   ",type="
> +						   LINUX_RESERVED_UUID);
> +			else
> +				offset += snprintf(buf + offset,
> +						   buflen - offset,
> +						   ",type=linux");
> +
> +			if (part->part_type == PART_SYSTEM)
> +				offset += snprintf(buf + offset,
> +						   buflen - offset,
> +						   ",bootable");
> +
> +			if (!rootfs_found && !strcmp(part->name, "rootfs")) {
> +				mmc_id = part->dev_id;
> +				rootfs_found = true;
> +				if (mmc_id < ARRAY_SIZE(uuid_mmc)) {
> +					uuid_bin =
> +					  (unsigned char *)uuid_mmc[mmc_id].b;
> +					uuid_bin_to_str(uuid_bin, uuid,
> +							UUID_STR_FORMAT_GUID);
> +					offset += snprintf(buf + offset,
> +							   buflen - offset,
> +							   ",uuid=%s", uuid);
> +				}
> +			}
> +
> +			offset += snprintf(buf + offset, buflen - offset, ";");
> +		}
> +
> +		if (offset) {
> +			offset += snprintf(buf + offset, buflen - offset, "\"");
> +			pr_debug("\ncmd: %s\n", buf);
> +			if (run_command(buf, 0)) {
> +				stm32prog_err("GPT partitionning fail: %s",
> +					      buf);
> +				free(buf);
> +
> +				return -1;
> +			}
> +		}
> +
> +		if (data->dev[i].mmc)
> +			part_init(mmc_get_blk_desc(data->dev[i].mmc));
> +
> +#ifdef DEBUG
> +		sprintf(buf, "gpt verify mmc %d", data->dev[i].dev_id);
> +		pr_debug("\ncmd: %s", buf);
> +		if (run_command(buf, 0))
> +			printf("fail !\n");
> +		else
> +			printf("OK\n");
> +
> +		sprintf(buf, "part list mmc %d", data->dev[i].dev_id);
> +		run_command(buf, 0);
> +#endif
> +	}
> +	puts("done\n");
> +
> +	free(buf);
> +#endif
> +
> +	return 0;
> +}
> +
>  static int stm32prog_alt_add(struct stm32prog_data *data,
>  			     struct dfu_entity *dfu,
>  			     struct stm32prog_part_t *part)
> @@ -596,17 +781,30 @@ static int stm32prog_alt_add(struct stm32prog_data *data,
>  	if (part->part_type == RAW_IMAGE) {
>  		u64 dfu_size;
>  
> -		dfu_size = part->size;
> +		if (part->dev->target == STM32PROG_MMC)
> +			dfu_size = part->size / part->dev->mmc->read_bl_len;
> +		else
> +			dfu_size = part->size;
>  		offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
>  				   "raw 0x0 0x%llx", dfu_size);
>  	} else {
>  		offset += snprintf(buf + offset,
>  				   ALT_BUF_LEN - offset,
>  				   "part");
> +		/* dev_id requested by DFU MMC */
> +		if (part->target == STM32PROG_MMC)
> +			offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
> +					   " %d", part->dev_id);
>  		offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
>  				   " %d;", part->part_id);
>  	}
>  	switch (part->target) {
> +#ifdef CONFIG_MMC
> +	case STM32PROG_MMC:
> +		sprintf(dfustr, "mmc");
> +		sprintf(devstr, "%d", part->dev_id);
> +		break;
> +#endif
>  	default:
>  		stm32prog_err("invalid target: %d", part->target);
>  		return -ENODEV;
> @@ -775,6 +973,10 @@ static void stm32prog_devices_init(struct stm32prog_data *data)
>  			goto error;
>  	}
>  
> +	ret = create_partitions(data);
> +	if (ret)
> +		goto error;
> +
>  	return;
>  
>  error:
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
> index b44b6f89af..228a25d37f 100644
> --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
> @@ -19,6 +19,7 @@
>  
>  enum stm32prog_target {
>  	STM32PROG_NONE,
> +	STM32PROG_MMC,
>  };
>  
>  enum stm32prog_link_t {
> @@ -64,6 +65,8 @@ enum stm32prog_part_type {
>  struct stm32prog_dev_t {
>  	enum stm32prog_target	target;
>  	char			dev_id;
> +	u32			erase_size;
> +	struct mmc		*mmc;
>  	/* list of partition for this device / ordered in offset */
>  	struct list_head	part_list;
>  };
> diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig
> index baed3d92f5..2e7d8bc990 100644
> --- a/configs/stm32mp15_basic_defconfig
> +++ b/configs/stm32mp15_basic_defconfig
> @@ -35,7 +35,6 @@ CONFIG_CMD_CLK=y
>  CONFIG_CMD_DFU=y
>  CONFIG_CMD_FUSE=y
>  CONFIG_CMD_GPIO=y
> -CONFIG_CMD_GPT=y
>  CONFIG_CMD_I2C=y
>  CONFIG_CMD_MMC=y
>  CONFIG_CMD_MTD=y
> @@ -68,7 +67,6 @@ CONFIG_ENV_UBI_VOLUME="uboot_config"
>  CONFIG_ENV_UBI_VOLUME_REDUND="uboot_config_r"
>  CONFIG_SYS_RELOC_GD_ENV_ADDR=y
>  CONFIG_STM32_ADC=y
> -CONFIG_DFU_MMC=y
>  CONFIG_DFU_MTD=y
>  CONFIG_SET_DFU_ALT_INFO=y
>  CONFIG_USB_FUNCTION_FASTBOOT=y
> diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig
> index adbe304902..6f6c909da0 100644
> --- a/configs/stm32mp15_trusted_defconfig
> +++ b/configs/stm32mp15_trusted_defconfig
> @@ -23,7 +23,6 @@ CONFIG_CMD_CLK=y
>  CONFIG_CMD_DFU=y
>  CONFIG_CMD_FUSE=y
>  CONFIG_CMD_GPIO=y
> -CONFIG_CMD_GPT=y
>  CONFIG_CMD_I2C=y
>  CONFIG_CMD_MMC=y
>  CONFIG_CMD_MTD=y
> @@ -54,7 +53,6 @@ CONFIG_ENV_UBI_VOLUME="uboot_config"
>  CONFIG_ENV_UBI_VOLUME_REDUND="uboot_config_r"
>  CONFIG_SYS_RELOC_GD_ENV_ADDR=y
>  CONFIG_STM32_ADC=y
> -CONFIG_DFU_MMC=y
>  CONFIG_DFU_MTD=y
>  CONFIG_SET_DFU_ALT_INFO=y
>  CONFIG_USB_FUNCTION_FASTBOOT=y

Reviewed-by: Patrice Chotard <patrice.chotard@st.com>

Thanks

Patrice

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 06/18] stm32mp: stm32prog: add MMC device
  2020-03-18  8:24 ` [PATCH 06/18] stm32mp: stm32prog: add MMC device Patrick Delaunay
  2020-04-14 13:04   ` Patrice CHOTARD
@ 2020-04-14 13:04   ` Patrice CHOTARD
  1 sibling, 0 replies; 40+ messages in thread
From: Patrice CHOTARD @ 2020-04-14 13:04 UTC (permalink / raw)
  To: u-boot

Hi

On 3/18/20 9:24 AM, Patrick Delaunay wrote:
> Add support of MMC device (based on DFU_MMC backend)
> for SD card and eMMC update.
>
> Create a GPT partitioning on the device.
>
> Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
> ---
>
>  arch/arm/mach-stm32mp/Kconfig                 |   3 +
>  .../mach-stm32mp/cmd_stm32prog/stm32prog.c    | 204 +++++++++++++++++-
>  .../mach-stm32mp/cmd_stm32prog/stm32prog.h    |   3 +
>  configs/stm32mp15_basic_defconfig             |   2 -
>  configs/stm32mp15_trusted_defconfig           |   2 -
>  5 files changed, 209 insertions(+), 5 deletions(-)
>
> diff --git a/arch/arm/mach-stm32mp/Kconfig b/arch/arm/mach-stm32mp/Kconfig
> index 61466f6125..39504e8540 100644
> --- a/arch/arm/mach-stm32mp/Kconfig
> +++ b/arch/arm/mach-stm32mp/Kconfig
> @@ -119,6 +119,9 @@ config CMD_STM32PROG
>  	select DFU
>  	select DFU_RAM
>  	select DFU_VIRT
> +	select PARTITION_TYPE_GUID
> +	imply CMD_GPT if MMC
> +	imply DFU_MMC if MMC
>  	help
>  		activate a specific command stm32prog for STM32MP soc family
>  		witch update the device with the tools STM32CubeProgrammer,
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> index 11fe479072..feb83670b5 100644
> --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> @@ -7,6 +7,7 @@
>  #include <console.h>
>  #include <dfu.h>
>  #include <malloc.h>
> +#include <mmc.h>
>  #include <dm/uclass.h>
>  #include <linux/list.h>
>  #include <linux/list_sort.h>
> @@ -14,6 +15,9 @@
>  
>  #include "stm32prog.h"
>  
> +/* Primary GPT header size for 128 entries : 17kB = 34 LBA of 512B */
> +#define GPT_HEADER_SZ	34
> +
>  #define OPT_SELECT	BIT(0)
>  #define OPT_EMPTY	BIT(1)
>  
> @@ -22,6 +26,32 @@
>  
>  #define ALT_BUF_LEN			SZ_1K
>  
> +#define ROOTFS_MMC0_UUID \
> +	EFI_GUID(0xE91C4E10, 0x16E6, 0x4C0E, \
> +		 0xBD, 0x0E, 0x77, 0xBE, 0xCF, 0x4A, 0x35, 0x82)
> +
> +#define ROOTFS_MMC1_UUID \
> +	EFI_GUID(0x491F6117, 0x415D, 0x4F53, \
> +		 0x88, 0xC9, 0x6E, 0x0D, 0xE5, 0x4D, 0xEA, 0xC6)
> +
> +#define ROOTFS_MMC2_UUID \
> +	EFI_GUID(0xFD58F1C7, 0xBE0D, 0x4338, \
> +		 0x88, 0xE9, 0xAD, 0x8F, 0x05, 0x0A, 0xEB, 0x18)
> +
> +/* RAW parttion (binary / bootloader) used Linux - reserved UUID */
> +#define LINUX_RESERVED_UUID "8DA63339-0007-60C0-C436-083AC8230908"
> +
> +/*
> + * unique partition guid (uuid) for partition named "rootfs"
> + * on each MMC instance = SD Card or eMMC
> + * allow fixed kernel bootcmd: "rootf=PARTUID=e91c4e10-..."
> + */
> +static const efi_guid_t uuid_mmc[3] = {
> +	ROOTFS_MMC0_UUID,
> +	ROOTFS_MMC1_UUID,
> +	ROOTFS_MMC2_UUID
> +};
> +
>  DECLARE_GLOBAL_DATA_PTR;
>  
>  /* order of column in flash layout file */
> @@ -200,6 +230,9 @@ static int parse_ip(struct stm32prog_data *data,
>  	part->dev_id = 0;
>  	if (!strcmp(p, "none")) {
>  		part->target = STM32PROG_NONE;
> +	} else if (!strncmp(p, "mmc", 3)) {
> +		part->target = STM32PROG_MMC;
> +		len = 3;
>  	} else {
>  		result = -EINVAL;
>  	}
> @@ -424,16 +457,50 @@ static int __init part_cmp(void *priv, struct list_head *a, struct list_head *b)
>  static int init_device(struct stm32prog_data *data,
>  		       struct stm32prog_dev_t *dev)
>  {
> +	struct mmc *mmc = NULL;
>  	struct blk_desc *block_dev = NULL;
>  	int part_id;
>  	u64 first_addr = 0, last_addr = 0;
>  	struct stm32prog_part_t *part, *next_part;
>  
>  	switch (dev->target) {
> +#ifdef CONFIG_MMC
> +	case STM32PROG_MMC:
> +		mmc = find_mmc_device(dev->dev_id);
> +		if (mmc_init(mmc)) {
> +			stm32prog_err("mmc device %d not found", dev->dev_id);
> +			return -ENODEV;
> +		}
> +		block_dev = mmc_get_blk_desc(mmc);
> +		if (!block_dev) {
> +			stm32prog_err("mmc device %d not probed", dev->dev_id);
> +			return -ENODEV;
> +		}
> +		dev->erase_size = mmc->erase_grp_size * block_dev->blksz;
> +		dev->mmc = mmc;
> +
> +		/* reserve a full erase group for each GTP headers */
> +		if (mmc->erase_grp_size > GPT_HEADER_SZ) {
> +			first_addr = dev->erase_size;
> +			last_addr = (u64)(block_dev->lba -
> +					  mmc->erase_grp_size) *
> +				    block_dev->blksz;
> +		} else {
> +			first_addr = (u64)GPT_HEADER_SZ * block_dev->blksz;
> +			last_addr = (u64)(block_dev->lba - GPT_HEADER_SZ - 1) *
> +				    block_dev->blksz;
> +		}
> +		pr_debug("MMC %d: lba=%ld blksz=%ld\n", dev->dev_id,
> +			 block_dev->lba, block_dev->blksz);
> +		pr_debug(" available address = 0x%llx..0x%llx\n",
> +			 first_addr, last_addr);
> +		break;
> +#endif
>  	default:
>  		stm32prog_err("unknown device type = %d", dev->target);
>  		return -ENODEV;
>  	}
> +	pr_debug(" erase size = 0x%x\n", dev->erase_size);
>  
>  	/* order partition list in offset order */
>  	list_sort(NULL, &dev->part_list, &part_cmp);
> @@ -491,6 +558,12 @@ static int init_device(struct stm32prog_data *data,
>  			return -EINVAL;
>  		}
>  
> +		if ((part->addr & ((u64)part->dev->erase_size - 1)) != 0) {
> +			stm32prog_err("%s (0x%x): not aligned address : 0x%llx on erase size 0x%x",
> +				      part->name, part->id, part->addr,
> +				      part->dev->erase_size);
> +			return -EINVAL;
> +		}
>  		pr_debug("%02d : %1d %02x %14s %02d %02d.%02d %08llx %08llx",
>  			 part->part_id, part->option, part->id, part->name,
>  			 part->part_type, part->target,
> @@ -559,6 +632,118 @@ static int treat_partition_list(struct stm32prog_data *data)
>  	return 0;
>  }
>  
> +static int create_partitions(struct stm32prog_data *data)
> +{
> +#ifdef CONFIG_MMC
> +	int offset = 0;
> +	const int buflen = SZ_8K;
> +	char *buf;
> +	char uuid[UUID_STR_LEN + 1];
> +	unsigned char *uuid_bin;
> +	unsigned int mmc_id;
> +	int i;
> +	bool rootfs_found;
> +	struct stm32prog_part_t *part;
> +
> +	buf = malloc(buflen);
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	puts("partitions : ");
> +	/* initialize the selected device */
> +	for (i = 0; i < data->dev_nb; i++) {
> +		offset = 0;
> +		rootfs_found = false;
> +		memset(buf, 0, buflen);
> +
> +		list_for_each_entry(part, &data->dev[i].part_list, list) {
> +			/* skip Raw Image */
> +			if (part->part_type == RAW_IMAGE)
> +				continue;
> +
> +			if (offset + 100 > buflen) {
> +				pr_debug("\n%s: buffer too small, %s skippped",
> +					 __func__, part->name);
> +				continue;
> +			}
> +
> +			if (!offset)
> +				offset += sprintf(buf, "gpt write mmc %d \"",
> +						  data->dev[i].dev_id);
> +
> +			offset += snprintf(buf + offset, buflen - offset,
> +					   "name=%s,start=0x%llx,size=0x%llx",
> +					   part->name,
> +					   part->addr,
> +					   part->size);
> +
> +			if (part->part_type == PART_BINARY)
> +				offset += snprintf(buf + offset,
> +						   buflen - offset,
> +						   ",type="
> +						   LINUX_RESERVED_UUID);
> +			else
> +				offset += snprintf(buf + offset,
> +						   buflen - offset,
> +						   ",type=linux");
> +
> +			if (part->part_type == PART_SYSTEM)
> +				offset += snprintf(buf + offset,
> +						   buflen - offset,
> +						   ",bootable");
> +
> +			if (!rootfs_found && !strcmp(part->name, "rootfs")) {
> +				mmc_id = part->dev_id;
> +				rootfs_found = true;
> +				if (mmc_id < ARRAY_SIZE(uuid_mmc)) {
> +					uuid_bin =
> +					  (unsigned char *)uuid_mmc[mmc_id].b;
> +					uuid_bin_to_str(uuid_bin, uuid,
> +							UUID_STR_FORMAT_GUID);
> +					offset += snprintf(buf + offset,
> +							   buflen - offset,
> +							   ",uuid=%s", uuid);
> +				}
> +			}
> +
> +			offset += snprintf(buf + offset, buflen - offset, ";");
> +		}
> +
> +		if (offset) {
> +			offset += snprintf(buf + offset, buflen - offset, "\"");
> +			pr_debug("\ncmd: %s\n", buf);
> +			if (run_command(buf, 0)) {
> +				stm32prog_err("GPT partitionning fail: %s",
> +					      buf);
> +				free(buf);
> +
> +				return -1;
> +			}
> +		}
> +
> +		if (data->dev[i].mmc)
> +			part_init(mmc_get_blk_desc(data->dev[i].mmc));
> +
> +#ifdef DEBUG
> +		sprintf(buf, "gpt verify mmc %d", data->dev[i].dev_id);
> +		pr_debug("\ncmd: %s", buf);
> +		if (run_command(buf, 0))
> +			printf("fail !\n");
> +		else
> +			printf("OK\n");
> +
> +		sprintf(buf, "part list mmc %d", data->dev[i].dev_id);
> +		run_command(buf, 0);
> +#endif
> +	}
> +	puts("done\n");
> +
> +	free(buf);
> +#endif
> +
> +	return 0;
> +}
> +
>  static int stm32prog_alt_add(struct stm32prog_data *data,
>  			     struct dfu_entity *dfu,
>  			     struct stm32prog_part_t *part)
> @@ -596,17 +781,30 @@ static int stm32prog_alt_add(struct stm32prog_data *data,
>  	if (part->part_type == RAW_IMAGE) {
>  		u64 dfu_size;
>  
> -		dfu_size = part->size;
> +		if (part->dev->target == STM32PROG_MMC)
> +			dfu_size = part->size / part->dev->mmc->read_bl_len;
> +		else
> +			dfu_size = part->size;
>  		offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
>  				   "raw 0x0 0x%llx", dfu_size);
>  	} else {
>  		offset += snprintf(buf + offset,
>  				   ALT_BUF_LEN - offset,
>  				   "part");
> +		/* dev_id requested by DFU MMC */
> +		if (part->target == STM32PROG_MMC)
> +			offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
> +					   " %d", part->dev_id);
>  		offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
>  				   " %d;", part->part_id);
>  	}
>  	switch (part->target) {
> +#ifdef CONFIG_MMC
> +	case STM32PROG_MMC:
> +		sprintf(dfustr, "mmc");
> +		sprintf(devstr, "%d", part->dev_id);
> +		break;
> +#endif
>  	default:
>  		stm32prog_err("invalid target: %d", part->target);
>  		return -ENODEV;
> @@ -775,6 +973,10 @@ static void stm32prog_devices_init(struct stm32prog_data *data)
>  			goto error;
>  	}
>  
> +	ret = create_partitions(data);
> +	if (ret)
> +		goto error;
> +
>  	return;
>  
>  error:
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
> index b44b6f89af..228a25d37f 100644
> --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
> @@ -19,6 +19,7 @@
>  
>  enum stm32prog_target {
>  	STM32PROG_NONE,
> +	STM32PROG_MMC,
>  };
>  
>  enum stm32prog_link_t {
> @@ -64,6 +65,8 @@ enum stm32prog_part_type {
>  struct stm32prog_dev_t {
>  	enum stm32prog_target	target;
>  	char			dev_id;
> +	u32			erase_size;
> +	struct mmc		*mmc;
>  	/* list of partition for this device / ordered in offset */
>  	struct list_head	part_list;
>  };
> diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig
> index baed3d92f5..2e7d8bc990 100644
> --- a/configs/stm32mp15_basic_defconfig
> +++ b/configs/stm32mp15_basic_defconfig
> @@ -35,7 +35,6 @@ CONFIG_CMD_CLK=y
>  CONFIG_CMD_DFU=y
>  CONFIG_CMD_FUSE=y
>  CONFIG_CMD_GPIO=y
> -CONFIG_CMD_GPT=y
>  CONFIG_CMD_I2C=y
>  CONFIG_CMD_MMC=y
>  CONFIG_CMD_MTD=y
> @@ -68,7 +67,6 @@ CONFIG_ENV_UBI_VOLUME="uboot_config"
>  CONFIG_ENV_UBI_VOLUME_REDUND="uboot_config_r"
>  CONFIG_SYS_RELOC_GD_ENV_ADDR=y
>  CONFIG_STM32_ADC=y
> -CONFIG_DFU_MMC=y
>  CONFIG_DFU_MTD=y
>  CONFIG_SET_DFU_ALT_INFO=y
>  CONFIG_USB_FUNCTION_FASTBOOT=y
> diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig
> index adbe304902..6f6c909da0 100644
> --- a/configs/stm32mp15_trusted_defconfig
> +++ b/configs/stm32mp15_trusted_defconfig
> @@ -23,7 +23,6 @@ CONFIG_CMD_CLK=y
>  CONFIG_CMD_DFU=y
>  CONFIG_CMD_FUSE=y
>  CONFIG_CMD_GPIO=y
> -CONFIG_CMD_GPT=y
>  CONFIG_CMD_I2C=y
>  CONFIG_CMD_MMC=y
>  CONFIG_CMD_MTD=y
> @@ -54,7 +53,6 @@ CONFIG_ENV_UBI_VOLUME="uboot_config"
>  CONFIG_ENV_UBI_VOLUME_REDUND="uboot_config_r"
>  CONFIG_SYS_RELOC_GD_ENV_ADDR=y
>  CONFIG_STM32_ADC=y
> -CONFIG_DFU_MMC=y
>  CONFIG_DFU_MTD=y
>  CONFIG_SET_DFU_ALT_INFO=y
>  CONFIG_USB_FUNCTION_FASTBOOT=y

Reviewed-by: Patrice Chotard <patrice.chotard@st.com>

Thanks

Patrice

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 07/18] stm32mp: stm32prog: add support of boot partition for eMMC device
  2020-03-18  8:24 ` [PATCH 07/18] stm32mp: stm32prog: add support of boot partition for eMMC device Patrick Delaunay
@ 2020-04-14 13:05   ` Patrice CHOTARD
  0 siblings, 0 replies; 40+ messages in thread
From: Patrice CHOTARD @ 2020-04-14 13:05 UTC (permalink / raw)
  To: u-boot

Hi

On 3/18/20 9:24 AM, Patrick Delaunay wrote:
> Add support of eMMC device boot partition with
> part_id = -1 for offset="boot1"
>      or = -2 for offset="boot2"
>
> The stm32prog command configures the MMC DFU backend with "mmcpart"
> and configure the eMMC (command "mmc bootbus" and "mmc partconf")
> when the update is done.
>
> Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
> ---
>
>  .../mach-stm32mp/cmd_stm32prog/stm32prog.c    | 124 +++++++++++++-----
>  .../mach-stm32mp/cmd_stm32prog/stm32prog.h    |   2 +-
>  2 files changed, 90 insertions(+), 36 deletions(-)
>
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> index feb83670b5..f63036606e 100644
> --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> @@ -259,12 +259,30 @@ static int parse_offset(struct stm32prog_data *data,
>  	char *tail;
>  
>  	part->part_id = 0;
> +	part->addr = 0;
>  	part->size = 0;
> -	part->addr = simple_strtoull(p, &tail, 0);
> -	if (tail == p || *tail != '\0') {
> -		stm32prog_err("Layout line %d: invalid offset '%s'",
> -			      i, p);
> -		result = -EINVAL;
> +	/* eMMC boot parttion */
> +	if (!strncmp(p, "boot", 4)) {
> +		if (strlen(p) != 5) {
> +			result = -EINVAL;
> +		} else {
> +			if (p[4] == '1')
> +				part->part_id = -1;
> +			else if (p[4] == '2')
> +				part->part_id = -2;
> +			else
> +				result = -EINVAL;
> +		}
> +		if (result)
> +			stm32prog_err("Layout line %d: invalid part '%s'",
> +				      i, p);
> +	} else {
> +		part->addr = simple_strtoull(p, &tail, 0);
> +		if (tail == p || *tail != '\0') {
> +			stm32prog_err("Layout line %d: invalid offset '%s'",
> +				      i, p);
> +			result = -EINVAL;
> +		}
>  	}
>  
>  	return result;
> @@ -451,7 +469,10 @@ static int __init part_cmp(void *priv, struct list_head *a, struct list_head *b)
>  	parta = container_of(a, struct stm32prog_part_t, list);
>  	partb = container_of(b, struct stm32prog_part_t, list);
>  
> -	return parta->addr > partb->addr ? 1 : -1;
> +	if (parta->part_id != partb->part_id)
> +		return parta->part_id - partb->part_id;
> +	else
> +		return parta->addr > partb->addr ? 1 : -1;
>  }
>  
>  static int init_device(struct stm32prog_data *data,
> @@ -520,44 +541,53 @@ static int init_device(struct stm32prog_data *data,
>  				 part->dev_id, part->addr, part->size);
>  			continue;
>  		}
> -
> -		part->part_id = part_id++;
> -
> -		/* last partition : size to the end of the device */
> -		if (part->list.next != &dev->part_list) {
> -			next_part =
> -				container_of(part->list.next,
> -					     struct stm32prog_part_t,
> -					     list);
> -			if (part->addr < next_part->addr) {
> -				part->size = next_part->addr -
> -					     part->addr;
> +		if (part->part_id < 0) { /* boot hw partition for eMMC */
> +			if (mmc) {
> +				part->size = mmc->capacity_boot;
>  			} else {
> -				stm32prog_err("%s (0x%x): same address : 0x%llx == %s (0x%x): 0x%llx",
> +				stm32prog_err("%s (0x%x): hw partition not expected : %d",
>  					      part->name, part->id,
> -					      part->addr,
> -					      next_part->name,
> -					      next_part->id,
> -					      next_part->addr);
> -				return -EINVAL;
> +					      part->part_id);
> +				return -ENODEV;
>  			}
>  		} else {
> -			if (part->addr <= last_addr) {
> -				part->size = last_addr - part->addr;
> +			part->part_id = part_id++;
> +
> +			/* last partition : size to the end of the device */
> +			if (part->list.next != &dev->part_list) {
> +				next_part =
> +					container_of(part->list.next,
> +						     struct stm32prog_part_t,
> +						     list);
> +				if (part->addr < next_part->addr) {
> +					part->size = next_part->addr -
> +						     part->addr;
> +				} else {
> +					stm32prog_err("%s (0x%x): same address : 0x%llx == %s (0x%x): 0x%llx",
> +						      part->name, part->id,
> +						      part->addr,
> +						      next_part->name,
> +						      next_part->id,
> +						      next_part->addr);
> +					return -EINVAL;
> +				}
>  			} else {
> -				stm32prog_err("%s (0x%x): invalid address 0x%llx (max=0x%llx)",
> +				if (part->addr <= last_addr) {
> +					part->size = last_addr - part->addr;
> +				} else {
> +					stm32prog_err("%s (0x%x): invalid address 0x%llx (max=0x%llx)",
> +						      part->name, part->id,
> +						      part->addr, last_addr);
> +					return -EINVAL;
> +				}
> +			}
> +			if (part->addr < first_addr) {
> +				stm32prog_err("%s (0x%x): invalid address 0x%llx (min=0x%llx)",
>  					      part->name, part->id,
> -					      part->addr, last_addr);
> +					      part->addr, first_addr);
>  				return -EINVAL;
>  			}
>  		}
> -		if (part->addr < first_addr) {
> -			stm32prog_err("%s (0x%x): invalid address 0x%llx (min=0x%llx)",
> -				      part->name, part->id,
> -				      part->addr, first_addr);
> -			return -EINVAL;
> -		}
> -
>  		if ((part->addr & ((u64)part->dev->erase_size - 1)) != 0) {
>  			stm32prog_err("%s (0x%x): not aligned address : 0x%llx on erase size 0x%x",
>  				      part->name, part->id, part->addr,
> @@ -657,6 +687,9 @@ static int create_partitions(struct stm32prog_data *data)
>  		memset(buf, 0, buflen);
>  
>  		list_for_each_entry(part, &data->dev[i].part_list, list) {
> +			/* skip eMMC boot partitions */
> +			if (part->part_id < 0)
> +				continue;
>  			/* skip Raw Image */
>  			if (part->part_type == RAW_IMAGE)
>  				continue;
> @@ -787,6 +820,14 @@ static int stm32prog_alt_add(struct stm32prog_data *data,
>  			dfu_size = part->size;
>  		offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
>  				   "raw 0x0 0x%llx", dfu_size);
> +	} else if (part->part_id < 0) {
> +		u64 nb_blk = part->size / part->dev->mmc->read_bl_len;
> +
> +		offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
> +				   "raw 0x%llx 0x%llx",
> +				   part->addr, nb_blk);
> +		offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
> +				   " mmcpart %d;", -(part->part_id));
>  	} else {
>  		offset += snprintf(buf + offset,
>  				   ALT_BUF_LEN - offset,
> @@ -908,6 +949,19 @@ static void stm32prog_end_phase(struct stm32prog_data *data)
>  
>  	if (!data->cur_part)
>  		return;
> +
> +	if (CONFIG_IS_ENABLED(MMC) &&
> +	    data->cur_part->part_id < 0) {
> +		char cmdbuf[60];
> +
> +		sprintf(cmdbuf, "mmc bootbus %d 0 0 0; mmc partconf %d 1 %d 0",
> +			data->cur_part->dev_id, data->cur_part->dev_id,
> +			-(data->cur_part->part_id));
> +		if (run_command(cmdbuf, 0)) {
> +			stm32prog_err("commands '%s' failed", cmdbuf);
> +			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 228a25d37f..6c3ad56a38 100644
> --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
> @@ -89,7 +89,7 @@ struct stm32prog_part_t {
>  
>  	/* information on associated device */
>  	struct stm32prog_dev_t	*dev;		/* pointer to device */
> -	u16			part_id;	/* partition id in device */
> +	s16			part_id;	/* partition id in device */
>  	int			alt_id;		/* alt id in usb/dfu */
>  
>  	struct list_head	list;

Reviewed-by: Patrice Chotard <patrice.chotard@st.com>

Thanks

Patrice

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 08/18] stm32mp: stm32prog: add upport of partial update
  2020-03-18  8:24 ` [PATCH 08/18] stm32mp: stm32prog: add upport of partial update Patrick Delaunay
@ 2020-04-14 13:05   ` Patrice CHOTARD
  0 siblings, 0 replies; 40+ messages in thread
From: Patrice CHOTARD @ 2020-04-14 13:05 UTC (permalink / raw)
  To: u-boot

Hi

On 3/18/20 9:24 AM, Patrick Delaunay wrote:
> Add support of partial update, update only some partitions,
> and check the coherence of the layout with the existing GPT
> partitions (offset and size).
>
> Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
> ---
>
>  .../mach-stm32mp/cmd_stm32prog/stm32prog.c    | 69 +++++++++++++++++++
>  .../mach-stm32mp/cmd_stm32prog/stm32prog.h    |  1 +
>  2 files changed, 70 insertions(+)
>
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> index f63036606e..787bcdef7d 100644
> --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> @@ -481,8 +481,12 @@ static int init_device(struct stm32prog_data *data,
>  	struct mmc *mmc = NULL;
>  	struct blk_desc *block_dev = NULL;
>  	int part_id;
> +	int ret;
>  	u64 first_addr = 0, last_addr = 0;
>  	struct stm32prog_part_t *part, *next_part;
> +	u64 part_addr, part_size;
> +	bool part_found;
> +	const char *part_name;
>  
>  	switch (dev->target) {
>  #ifdef CONFIG_MMC
> @@ -515,6 +519,7 @@ static int init_device(struct stm32prog_data *data,
>  			 block_dev->lba, block_dev->blksz);
>  		pr_debug(" available address = 0x%llx..0x%llx\n",
>  			 first_addr, last_addr);
> +		pr_debug(" full_update = %d\n", dev->full_update);
>  		break;
>  #endif
>  	default:
> @@ -522,6 +527,7 @@ static int init_device(struct stm32prog_data *data,
>  		return -ENODEV;
>  	}
>  	pr_debug(" erase size = 0x%x\n", dev->erase_size);
> +	pr_debug(" full_update = %d\n", dev->full_update);
>  
>  	/* order partition list in offset order */
>  	list_sort(NULL, &dev->part_list, &part_cmp);
> @@ -598,6 +604,61 @@ static int init_device(struct stm32prog_data *data,
>  			 part->part_id, part->option, part->id, part->name,
>  			 part->part_type, part->target,
>  			 part->dev_id, part->addr, part->size);
> +
> +		part_addr = 0;
> +		part_size = 0;
> +		part_found = false;
> +
> +		/* check coherency with existing partition */
> +		if (block_dev) {
> +			/*
> +			 * block devices with GPT: check user partition size
> +			 * only for partial update, the GPT partions are be
> +			 * created for full update
> +			 */
> +			if (dev->full_update || part->part_id < 0) {
> +				pr_debug("\n");
> +				continue;
> +			}
> +			disk_partition_t partinfo;
> +
> +			ret = part_get_info(block_dev, part->part_id,
> +					    &partinfo);
> +
> +			if (ret) {
> +				stm32prog_err("%s (0x%x):Couldn't find part %d on device mmc %d",
> +					      part->name, part->id,
> +					      part_id, part->dev_id);
> +				return -ENODEV;
> +			}
> +			part_addr = (u64)partinfo.start * partinfo.blksz;
> +			part_size = (u64)partinfo.size * partinfo.blksz;
> +			part_name = (char *)partinfo.name;
> +			part_found = true;
> +		}
> +
> +		if (!part_found) {
> +			stm32prog_err("%s (0x%x): Invalid partition",
> +				      part->name, part->id);
> +			pr_debug("\n");
> +			continue;
> +		}
> +
> +		pr_debug(" %08llx %08llx\n", part_addr, part_size);
> +
> +		if (part->addr != part_addr) {
> +			stm32prog_err("%s (0x%x): Bad address for partition %d (%s) = 0x%llx <> 0x%llx expected",
> +				      part->name, part->id, part->part_id,
> +				      part_name, part->addr, part_addr);
> +			return -ENODEV;
> +		}
> +		if (part->size != part_size) {
> +			stm32prog_err("%s (0x%x): Bad size for partition %d (%s) at 0x%llx = 0x%llx <> 0x%llx expected",
> +				      part->name, part->id, part->part_id,
> +				      part_name, part->addr, part->size,
> +				      part_size);
> +			return -ENODEV;
> +		}
>  	}
>  	return 0;
>  }
> @@ -644,6 +705,7 @@ static int treat_partition_list(struct stm32prog_data *data)
>  				/* new device found */
>  				data->dev[j].target = part->target;
>  				data->dev[j].dev_id = part->dev_id;
> +				data->dev[j].full_update = true;
>  				data->dev_nb++;
>  				break;
>  			} else if ((part->target == data->dev[j].target) &&
> @@ -656,6 +718,8 @@ static int treat_partition_list(struct stm32prog_data *data)
>  			return -EINVAL;
>  		}
>  		part->dev = &data->dev[j];
> +		if (!IS_SELECT(part))
> +			part->dev->full_update = false;
>  		list_add_tail(&part->list, &data->dev[j].part_list);
>  	}
>  
> @@ -682,6 +746,11 @@ static int create_partitions(struct stm32prog_data *data)
>  	puts("partitions : ");
>  	/* initialize the selected device */
>  	for (i = 0; i < data->dev_nb; i++) {
> +		/* create gpt partition support only for full update on MMC */
> +		if (data->dev[i].target != STM32PROG_MMC ||
> +		    !data->dev[i].full_update)
> +			continue;
> +
>  		offset = 0;
>  		rootfs_found = false;
>  		memset(buf, 0, buflen);
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
> index 6c3ad56a38..ea88459896 100644
> --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
> @@ -69,6 +69,7 @@ struct stm32prog_dev_t {
>  	struct mmc		*mmc;
>  	/* list of partition for this device / ordered in offset */
>  	struct list_head	part_list;
> +	bool			full_update;
>  };
>  
>  /* partition information build from FlashLayout and device */

Reviewed-by: Patrice Chotard <patrice.chotard@st.com>

Thanks

Patrice

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 09/18] stm32mp: stm32prog: add MTD devices support
  2020-03-18  8:24 ` [PATCH 09/18] stm32mp: stm32prog: add MTD devices support Patrick Delaunay
@ 2020-04-14 13:06   ` Patrice CHOTARD
  0 siblings, 0 replies; 40+ messages in thread
From: Patrice CHOTARD @ 2020-04-14 13:06 UTC (permalink / raw)
  To: u-boot

Hi

On 3/18/20 9:24 AM, Patrick Delaunay wrote:
> Add support of MTD device (DFU_MTD backend) for
> NOR, NAND or SPI-NAND target.
>
> Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
> ---
>
>  arch/arm/mach-stm32mp/Kconfig                 |   2 +
>  .../mach-stm32mp/cmd_stm32prog/stm32prog.c    | 114 +++++++++++++++++-
>  .../mach-stm32mp/cmd_stm32prog/stm32prog.h    |   4 +
>  configs/stm32mp15_basic_defconfig             |   2 -
>  configs/stm32mp15_trusted_defconfig           |   2 -
>  5 files changed, 117 insertions(+), 7 deletions(-)
>
> diff --git a/arch/arm/mach-stm32mp/Kconfig b/arch/arm/mach-stm32mp/Kconfig
> index 39504e8540..af16393152 100644
> --- a/arch/arm/mach-stm32mp/Kconfig
> +++ b/arch/arm/mach-stm32mp/Kconfig
> @@ -121,7 +121,9 @@ config CMD_STM32PROG
>  	select DFU_VIRT
>  	select PARTITION_TYPE_GUID
>  	imply CMD_GPT if MMC
> +	imply CMD_MTD if MTD
>  	imply DFU_MMC if MMC
> +	imply DFU_MTD if MTD
>  	help
>  		activate a specific command stm32prog for STM32MP soc family
>  		witch update the device with the tools STM32CubeProgrammer,
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> index 787bcdef7d..93ee6a55a1 100644
> --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> @@ -8,9 +8,12 @@
>  #include <dfu.h>
>  #include <malloc.h>
>  #include <mmc.h>
> +#include <part.h>
>  #include <dm/uclass.h>
> +#include <jffs2/load_kernel.h>
>  #include <linux/list.h>
>  #include <linux/list_sort.h>
> +#include <linux/mtd/mtd.h>
>  #include <linux/sizes.h>
>  
>  #include "stm32prog.h"
> @@ -65,6 +68,11 @@ enum stm32prog_col_t {
>  	COL_NB_STM32
>  };
>  
> +/* partition handling routines : CONFIG_CMD_MTDPARTS */
> +int mtdparts_init(void);
> +int find_dev_and_part(const char *id, struct mtd_device **dev,
> +		      u8 *part_num, struct part_info **part);
> +
>  char *stm32prog_get_error(struct stm32prog_data *data)
>  {
>  	static const char error_msg[] = "Unspecified";
> @@ -233,6 +241,15 @@ static int parse_ip(struct stm32prog_data *data,
>  	} else if (!strncmp(p, "mmc", 3)) {
>  		part->target = STM32PROG_MMC;
>  		len = 3;
> +	} else if (!strncmp(p, "nor", 3)) {
> +		part->target = STM32PROG_NOR;
> +		len = 3;
> +	} else if (!strncmp(p, "nand", 4)) {
> +		part->target = STM32PROG_NAND;
> +		len = 4;
> +	} else if (!strncmp(p, "spi-nand", 8)) {
> +		part->target = STM32PROG_SPI_NAND;
> +		len = 8;
>  	} else {
>  		result = -EINVAL;
>  	}
> @@ -475,11 +492,37 @@ static int __init part_cmp(void *priv, struct list_head *a, struct list_head *b)
>  		return parta->addr > partb->addr ? 1 : -1;
>  }
>  
> +static void get_mtd_by_target(char *string, enum stm32prog_target target,
> +			      int dev_id)
> +{
> +	const char *dev_str;
> +
> +	switch (target) {
> +	case STM32PROG_NOR:
> +		dev_str = "nor";
> +		break;
> +	case STM32PROG_NAND:
> +		dev_str = "nand";
> +		break;
> +	case STM32PROG_SPI_NAND:
> +		dev_str = "spi-nand";
> +		break;
> +	default:
> +		dev_str = "invalid";
> +		break;
> +	}
> +	sprintf(string, "%s%d", dev_str, dev_id);
> +}
> +
>  static int init_device(struct stm32prog_data *data,
>  		       struct stm32prog_dev_t *dev)
>  {
>  	struct mmc *mmc = NULL;
>  	struct blk_desc *block_dev = NULL;
> +#ifdef CONFIG_MTD
> +	struct mtd_info *mtd = NULL;
> +	char mtd_id[16];
> +#endif
>  	int part_id;
>  	int ret;
>  	u64 first_addr = 0, last_addr = 0;
> @@ -521,6 +564,29 @@ static int init_device(struct stm32prog_data *data,
>  			 first_addr, last_addr);
>  		pr_debug(" full_update = %d\n", dev->full_update);
>  		break;
> +#endif
> +#ifdef CONFIG_MTD
> +	case STM32PROG_NOR:
> +	case STM32PROG_NAND:
> +	case STM32PROG_SPI_NAND:
> +		get_mtd_by_target(mtd_id, dev->target, dev->dev_id);
> +		pr_debug("%s\n", mtd_id);
> +
> +		mtdparts_init();
> +		mtd = get_mtd_device_nm(mtd_id);
> +		if (IS_ERR(mtd)) {
> +			stm32prog_err("MTD device %s not found", mtd_id);
> +			return -ENODEV;
> +		}
> +		first_addr = 0;
> +		last_addr = mtd->size;
> +		dev->erase_size = mtd->erasesize;
> +		pr_debug("MTD device %s: size=%lld erasesize=%d\n",
> +			 mtd_id, mtd->size, mtd->erasesize);
> +		pr_debug(" available address = 0x%llx..0x%llx\n",
> +			 first_addr, last_addr);
> +		dev->mtd = mtd;
> +		break;
>  #endif
>  	default:
>  		stm32prog_err("unknown device type = %d", dev->target);
> @@ -637,6 +703,29 @@ static int init_device(struct stm32prog_data *data,
>  			part_found = true;
>  		}
>  
> +#ifdef CONFIG_MTD
> +		if (mtd) {
> +			char mtd_part_id[32];
> +			struct part_info *mtd_part;
> +			struct mtd_device *mtd_dev;
> +			u8 part_num;
> +
> +			sprintf(mtd_part_id, "%s,%d", mtd_id,
> +				part->part_id - 1);
> +			ret = find_dev_and_part(mtd_part_id, &mtd_dev,
> +						&part_num, &mtd_part);
> +			if (ret != 0) {
> +				stm32prog_err("%s (0x%x): Invalid MTD partition %s",
> +					      part->name, part->id,
> +					      mtd_part_id);
> +				return -ENODEV;
> +			}
> +			part_addr = mtd_part->offset;
> +			part_size = mtd_part->size;
> +			part_name = mtd_part->name;
> +			part_found = true;
> +		}
> +#endif
>  		if (!part_found) {
>  			stm32prog_err("%s (0x%x): Invalid partition",
>  				      part->name, part->id);
> @@ -840,6 +929,9 @@ static int create_partitions(struct stm32prog_data *data)
>  	}
>  	puts("done\n");
>  
> +#ifdef DEBUG
> +	run_command("mtd list", 0);
> +#endif
>  	free(buf);
>  #endif
>  
> @@ -898,9 +990,17 @@ static int stm32prog_alt_add(struct stm32prog_data *data,
>  		offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
>  				   " mmcpart %d;", -(part->part_id));
>  	} else {
> -		offset += snprintf(buf + offset,
> -				   ALT_BUF_LEN - offset,
> -				   "part");
> +		if (part->part_type == PART_SYSTEM &&
> +		    (part->target == STM32PROG_NAND ||
> +		     part->target == STM32PROG_NOR ||
> +		     part->target == STM32PROG_SPI_NAND))
> +			offset += snprintf(buf + offset,
> +					   ALT_BUF_LEN - offset,
> +					   "partubi");
> +		else
> +			offset += snprintf(buf + offset,
> +					   ALT_BUF_LEN - offset,
> +					   "part");
>  		/* dev_id requested by DFU MMC */
>  		if (part->target == STM32PROG_MMC)
>  			offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
> @@ -914,6 +1014,14 @@ static int stm32prog_alt_add(struct stm32prog_data *data,
>  		sprintf(dfustr, "mmc");
>  		sprintf(devstr, "%d", part->dev_id);
>  		break;
> +#endif
> +#ifdef CONFIG_MTD
> +	case STM32PROG_NAND:
> +	case STM32PROG_NOR:
> +	case STM32PROG_SPI_NAND:
> +		sprintf(dfustr, "mtd");
> +		get_mtd_by_target(devstr, part->target, part->dev_id);
> +		break;
>  #endif
>  	default:
>  		stm32prog_err("invalid target: %d", part->target);
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
> index ea88459896..8e635da3a4 100644
> --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
> @@ -20,6 +20,9 @@
>  enum stm32prog_target {
>  	STM32PROG_NONE,
>  	STM32PROG_MMC,
> +	STM32PROG_NAND,
> +	STM32PROG_NOR,
> +	STM32PROG_SPI_NAND
>  };
>  
>  enum stm32prog_link_t {
> @@ -67,6 +70,7 @@ struct stm32prog_dev_t {
>  	char			dev_id;
>  	u32			erase_size;
>  	struct mmc		*mmc;
> +	struct mtd_info		*mtd;
>  	/* list of partition for this device / ordered in offset */
>  	struct list_head	part_list;
>  	bool			full_update;
> diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig
> index 2e7d8bc990..7837cbe9c7 100644
> --- a/configs/stm32mp15_basic_defconfig
> +++ b/configs/stm32mp15_basic_defconfig
> @@ -37,7 +37,6 @@ CONFIG_CMD_FUSE=y
>  CONFIG_CMD_GPIO=y
>  CONFIG_CMD_I2C=y
>  CONFIG_CMD_MMC=y
> -CONFIG_CMD_MTD=y
>  CONFIG_CMD_REMOTEPROC=y
>  CONFIG_CMD_SPI=y
>  CONFIG_CMD_USB=y
> @@ -67,7 +66,6 @@ CONFIG_ENV_UBI_VOLUME="uboot_config"
>  CONFIG_ENV_UBI_VOLUME_REDUND="uboot_config_r"
>  CONFIG_SYS_RELOC_GD_ENV_ADDR=y
>  CONFIG_STM32_ADC=y
> -CONFIG_DFU_MTD=y
>  CONFIG_SET_DFU_ALT_INFO=y
>  CONFIG_USB_FUNCTION_FASTBOOT=y
>  CONFIG_FASTBOOT_BUF_ADDR=0xC0000000
> diff --git a/configs/stm32mp15_trusted_defconfig b/configs/stm32mp15_trusted_defconfig
> index 6f6c909da0..e5b1ab5d04 100644
> --- a/configs/stm32mp15_trusted_defconfig
> +++ b/configs/stm32mp15_trusted_defconfig
> @@ -25,7 +25,6 @@ CONFIG_CMD_FUSE=y
>  CONFIG_CMD_GPIO=y
>  CONFIG_CMD_I2C=y
>  CONFIG_CMD_MMC=y
> -CONFIG_CMD_MTD=y
>  CONFIG_CMD_REMOTEPROC=y
>  CONFIG_CMD_SPI=y
>  CONFIG_CMD_USB=y
> @@ -53,7 +52,6 @@ CONFIG_ENV_UBI_VOLUME="uboot_config"
>  CONFIG_ENV_UBI_VOLUME_REDUND="uboot_config_r"
>  CONFIG_SYS_RELOC_GD_ENV_ADDR=y
>  CONFIG_STM32_ADC=y
> -CONFIG_DFU_MTD=y
>  CONFIG_SET_DFU_ALT_INFO=y
>  CONFIG_USB_FUNCTION_FASTBOOT=y
>  CONFIG_FASTBOOT_BUF_ADDR=0xC0000000

Reviewed-by: Patrice Chotard <patrice.chotard@st.com>

Thanks

Patrice

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 10/18] stm32mp: stm32prog: adapt the MTD partitions
  2020-03-18  8:24 ` [PATCH 10/18] stm32mp: stm32prog: adapt the MTD partitions Patrick Delaunay
@ 2020-04-14 13:07   ` Patrice CHOTARD
  0 siblings, 0 replies; 40+ messages in thread
From: Patrice CHOTARD @ 2020-04-14 13:07 UTC (permalink / raw)
  To: u-boot

Hi

On 3/18/20 9:24 AM, Patrick Delaunay wrote:
> Dynamically adapt the MTD partitions in NOR/NAND/SPI-NAND when stm32prog
> command detects in the parsed flash layout files:
> - a fsbl partition in NOR.
> - a tee partition in NOR/NAND/SPI-NAND
>
> Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
> ---
>
>  .../mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c  | 17 +++++++++++++++++
>  arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c | 17 +++++++++++++++++
>  arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h |  2 ++
>  arch/arm/mach-stm32mp/include/mach/stm32prog.h  |  4 ++++
>  board/st/common/stm32mp_mtdparts.c              | 14 ++++++++++++--
>  5 files changed, 52 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
> index 3e8b426444..581f97e0b5 100644
> --- a/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
> @@ -6,6 +6,7 @@
>  #include <common.h>
>  #include <command.h>
>  #include <dfu.h>
> +#include <asm/arch/stm32prog.h>
>  #include "stm32prog.h"
>  
>  struct stm32prog_data *stm32prog_data;
> @@ -94,3 +95,19 @@ U_BOOT_CMD(stm32prog, 5, 0, do_stm32prog,
>  	   "<addr> = address of flashlayout\n"
>  	   "<size> = size of flashlayout\n"
>  );
> +
> +bool stm32prog_get_tee_partitions(void)
> +{
> +	if (stm32prog_data)
> +		return stm32prog_data->tee_detected;
> +
> +	return false;
> +}
> +
> +bool stm32prog_get_fsbl_nor(void)
> +{
> +	if (stm32prog_data)
> +		return stm32prog_data->fsbl_nor_detected;
> +
> +	return false;
> +}
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> index 93ee6a55a1..0140fd479d 100644
> --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> @@ -762,6 +762,8 @@ static int treat_partition_list(struct stm32prog_data *data)
>  		INIT_LIST_HEAD(&data->dev[j].part_list);
>  	}
>  
> +	data->tee_detected = false;
> +	data->fsbl_nor_detected = false;
>  	for (i = 0; i < data->part_nb; i++) {
>  		part = &data->part_array[i];
>  		part->alt_id = -1;
> @@ -806,6 +808,21 @@ static int treat_partition_list(struct stm32prog_data *data)
>  			stm32prog_err("Layout: too many device");
>  			return -EINVAL;
>  		}
> +		switch (part->target)  {
> +		case STM32PROG_NOR:
> +			if (!data->fsbl_nor_detected &&
> +			    !strncmp(part->name, "fsbl", 4))
> +				data->fsbl_nor_detected = true;
> +			/* fallthrough */
> +		case STM32PROG_NAND:
> +		case STM32PROG_SPI_NAND:
> +			if (!data->tee_detected &&
> +			    !strncmp(part->name, "tee", 3))
> +				data->tee_detected = true;
> +			break;
> +		default:
> +			break;
> +		}
>  		part->dev = &data->dev[j];
>  		if (!IS_SELECT(part))
>  			part->dev->full_update = false;
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
> index 8e635da3a4..7f06627ebc 100644
> --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
> @@ -107,6 +107,8 @@ struct stm32prog_data {
>  	struct stm32prog_dev_t	dev[STM32PROG_MAX_DEV];	/* array of device */
>  	int			part_nb;	/* nb of partition */
>  	struct stm32prog_part_t	*part_array;	/* array of partition */
> +	bool			tee_detected;
> +	bool			fsbl_nor_detected;
>  
>  	/* command internal information */
>  	unsigned int		phase;
> diff --git a/arch/arm/mach-stm32mp/include/mach/stm32prog.h b/arch/arm/mach-stm32mp/include/mach/stm32prog.h
> index c10bff09c8..c080b9cc42 100644
> --- a/arch/arm/mach-stm32mp/include/mach/stm32prog.h
> +++ b/arch/arm/mach-stm32mp/include/mach/stm32prog.h
> @@ -10,3 +10,7 @@ int stm32prog_write_medium_virt(struct dfu_entity *dfu, u64 offset,
>  int stm32prog_read_medium_virt(struct dfu_entity *dfu, u64 offset,
>  			       void *buf, long *len);
>  int stm32prog_get_medium_size_virt(struct dfu_entity *dfu, u64 *size);
> +
> +bool stm32prog_get_tee_partitions(void);
> +
> +bool stm32prog_get_fsbl_nor(void);
> diff --git a/board/st/common/stm32mp_mtdparts.c b/board/st/common/stm32mp_mtdparts.c
> index 5028511077..9f5897f8c8 100644
> --- a/board/st/common/stm32mp_mtdparts.c
> +++ b/board/st/common/stm32mp_mtdparts.c
> @@ -4,12 +4,14 @@
>   */
>  
>  #include <common.h>
> +#include <dfu.h>
>  #include <dm.h>
>  #include <env.h>
>  #include <env_internal.h>
>  #include <mtd.h>
>  #include <mtd_node.h>
>  #include <tee.h>
> +#include <asm/arch/stm32prog.h>
>  #include <asm/arch/sys_proto.h>
>  
>  #define MTDPARTS_LEN		256
> @@ -66,7 +68,7 @@ void board_mtdparts_default(const char **mtdids, const char **mtdparts)
>  	static char parts[3 * MTDPARTS_LEN + 1];
>  	static char ids[MTDIDS_LEN + 1];
>  	static bool mtd_initialized;
> -	bool tee, nor, nand, spinand;
> +	bool tee, nor, nand, spinand, serial;
>  
>  	if (mtd_initialized) {
>  		*mtdids = ids;
> @@ -78,10 +80,18 @@ void board_mtdparts_default(const char **mtdids, const char **mtdparts)
>  	nor = false;
>  	nand = false;
>  	spinand = false;
> +	serial = false;
>  
>  	switch (get_bootmode() & TAMP_BOOT_DEVICE_MASK) {
>  	case BOOT_SERIAL_UART:
>  	case BOOT_SERIAL_USB:
> +		serial = true;
> +		if (CONFIG_IS_ENABLED(CMD_STM32PROG)) {
> +			tee = stm32prog_get_tee_partitions();
> +			nor = stm32prog_get_fsbl_nor();
> +		}
> +		nand = true;
> +		spinand = true;
>  		break;
>  	case BOOT_FLASH_NAND:
>  		nand = true;
> @@ -96,7 +106,7 @@ void board_mtdparts_default(const char **mtdids, const char **mtdparts)
>  		break;
>  	}
>  
> -	if (CONFIG_IS_ENABLED(OPTEE) &&
> +	if (!serial && CONFIG_IS_ENABLED(OPTEE) &&
>  	    tee_find_device(NULL, NULL, NULL, NULL))
>  		tee = true;
>  

Reviewed-by: Patrice Chotard <patrice.chotard@st.com>

Thanks

Patrice

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 11/18] stm32mp: stm32prog: add support of ssbl copy
  2020-03-18  8:24 ` [PATCH 11/18] stm32mp: stm32prog: add support of ssbl copy Patrick Delaunay
@ 2020-04-14 13:07   ` Patrice CHOTARD
  0 siblings, 0 replies; 40+ messages in thread
From: Patrice CHOTARD @ 2020-04-14 13:07 UTC (permalink / raw)
  To: u-boot

Hi

On 3/18/20 9:24 AM, Patrick Delaunay wrote:
> 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>
> ---
>
>  .../mach-stm32mp/cmd_stm32prog/stm32prog.c    | 98 ++++++++++++++++++-
>  .../mach-stm32mp/cmd_stm32prog/stm32prog.h    |  1 +
>  2 files changed, 94 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)
> 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 */

Reviewed-by: Patrice Chotard <patrice.chotard@st.com>

Thanks

Patrice

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 12/18] stm32mp: stm32prog: add support for delete option in flashlayout
  2020-03-18  8:24 ` [PATCH 12/18] stm32mp: stm32prog: add support for delete option in flashlayout Patrick Delaunay
@ 2020-04-14 13:08   ` Patrice CHOTARD
  0 siblings, 0 replies; 40+ messages in thread
From: Patrice CHOTARD @ 2020-04-14 13:08 UTC (permalink / raw)
  To: u-boot

Hi

On 3/18/20 9:24 AM, Patrick Delaunay wrote:
> Add support for delete option 'D' in flashlayout for
> full device or for partitions
>
> Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
> ---
>
>  .../mach-stm32mp/cmd_stm32prog/stm32prog.c    | 105 ++++++++++++++++++
>  1 file changed, 105 insertions(+)
>
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> index 3e521d42f2..3573c04d16 100644
> --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> @@ -23,9 +23,11 @@
>  
>  #define OPT_SELECT	BIT(0)
>  #define OPT_EMPTY	BIT(1)
> +#define OPT_DELETE	BIT(2)
>  
>  #define IS_SELECT(part)	((part)->option & OPT_SELECT)
>  #define IS_EMPTY(part)	((part)->option & OPT_EMPTY)
> +#define IS_DELETE(part)	((part)->option & OPT_DELETE)
>  
>  #define ALT_BUF_LEN			SZ_1K
>  
> @@ -158,6 +160,9 @@ static int parse_option(struct stm32prog_data *data,
>  		case 'E':
>  			part->option |= OPT_EMPTY;
>  			break;
> +		case 'D':
> +			part->option |= OPT_DELETE;
> +			break;
>  		default:
>  			result = -EINVAL;
>  			stm32prog_err("Layout line %d: invalid option '%c' in %s)",
> @@ -1293,10 +1298,80 @@ void stm32prog_next_phase(struct stm32prog_data *data)
>  		puts("Phase=END\n");
>  }
>  
> +static int part_delete(struct stm32prog_data *data,
> +		       struct stm32prog_part_t *part)
> +{
> +	int ret = 0;
> +#ifdef CONFIG_MMC
> +	unsigned long blks, blks_offset, blks_size;
> +	struct blk_desc *block_dev = NULL;
> + #endif
> +#ifdef CONFIG_MTD
> +	char cmdbuf[40];
> +	char devstr[10];
> +#endif
> +
> +	printf("Erasing %s ", part->name);
> +	switch (part->target) {
> +#ifdef CONFIG_MMC
> +	case STM32PROG_MMC:
> +		printf("on mmc %d: ", part->dev->dev_id);
> +		block_dev = mmc_get_blk_desc(part->dev->mmc);
> +		blks_offset = lldiv(part->addr, part->dev->mmc->read_bl_len);
> +		blks_size = lldiv(part->size, part->dev->mmc->read_bl_len);
> +		/* -1 or -2 : delete boot partition of MMC
> +		 * need to switch to associated hwpart 1 or 2
> +		 */
> +		if (part->part_id < 0)
> +			if (blk_select_hwpart_devnum(IF_TYPE_MMC,
> +						     part->dev->dev_id,
> +						     -part->part_id))
> +				return -1;
> +
> +		blks = blk_derase(block_dev, blks_offset, blks_size);
> +
> +		/* return to user partition */
> +		if (part->part_id < 0)
> +			blk_select_hwpart_devnum(IF_TYPE_MMC,
> +						 part->dev->dev_id, 0);
> +		if (blks != blks_size) {
> +			ret = -1;
> +			stm32prog_err("%s (0x%x): MMC erase failed",
> +				      part->name, part->id);
> +		}
> +		break;
> +#endif
> +#ifdef CONFIG_MTD
> +	case STM32PROG_NOR:
> +	case STM32PROG_NAND:
> +	case STM32PROG_SPI_NAND:
> +		get_mtd_by_target(devstr, part->target, part->dev->dev_id);
> +		printf("on %s: ", devstr);
> +		sprintf(cmdbuf, "mtd erase %s 0x%llx 0x%llx",
> +			devstr, part->addr, part->size);
> +		if (run_command(cmdbuf, 0)) {
> +			ret = -1;
> +			stm32prog_err("%s (0x%x): MTD erase commands failed (%s)",
> +				      part->name, part->id, cmdbuf);
> +		}
> +		break;
> +#endif
> +	default:
> +		ret = -1;
> +		stm32prog_err("%s (0x%x): erase invalid", part->name, part->id);
> +		break;
> +	}
> +	if (!ret)
> +		printf("done\n");
> +
> +	return ret;
> +}
> +
>  static void stm32prog_devices_init(struct stm32prog_data *data)
>  {
>  	int i;
>  	int ret;
> +	struct stm32prog_part_t *part;
>  
>  	ret = treat_partition_list(data);
>  	if (ret)
> @@ -1309,10 +1384,40 @@ static void stm32prog_devices_init(struct stm32prog_data *data)
>  			goto error;
>  	}
>  
> +	/* delete RAW partition before create partition */
> +	for (i = 0; i < data->part_nb; i++) {
> +		part = &data->part_array[i];
> +
> +		if (part->part_type != RAW_IMAGE)
> +			continue;
> +
> +		if (!IS_SELECT(part) || !IS_DELETE(part))
> +			continue;
> +
> +		ret = part_delete(data, part);
> +		if (ret)
> +			goto error;
> +	}
> +
>  	ret = create_partitions(data);
>  	if (ret)
>  		goto error;
>  
> +	/* delete partition GPT or MTD */
> +	for (i = 0; i < data->part_nb; i++) {
> +		part = &data->part_array[i];
> +
> +		if (part->part_type == RAW_IMAGE)
> +			continue;
> +
> +		if (!IS_SELECT(part) || !IS_DELETE(part))
> +			continue;
> +
> +		ret = part_delete(data, part);
> +		if (ret)
> +			goto error;
> +	}
> +
>  	return;
>  
>  error:

Reviewed-by: Patrice Chotard <patrice.chotard@st.com>

Thanks

Patrice

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 13/18] stm32mp: stm32prog: add otp update support
  2020-03-18  8:24 ` [PATCH 13/18] stm32mp: stm32prog: add otp update support Patrick Delaunay
@ 2020-04-14 13:09   ` Patrice CHOTARD
  0 siblings, 0 replies; 40+ messages in thread
From: Patrice CHOTARD @ 2020-04-14 13:09 UTC (permalink / raw)
  To: u-boot

Hi

On 3/18/20 9:24 AM, Patrick Delaunay wrote:
> Add a virtual partition to update the STM32MP15x OTP based
> on SMC service provided by TF-A.
>
> Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
> ---
>
>  .../mach-stm32mp/cmd_stm32prog/stm32prog.c    | 130 +++++++++++++++++-
>  .../mach-stm32mp/cmd_stm32prog/stm32prog.h    |  11 ++
>  .../cmd_stm32prog/stm32prog_usb.c             |  11 ++
>  3 files changed, 151 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> index 3573c04d16..cd826dbb9c 100644
> --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> @@ -9,6 +9,7 @@
>  #include <malloc.h>
>  #include <mmc.h>
>  #include <part.h>
> +#include <asm/arch/stm32mp1_smc.h>
>  #include <dm/uclass.h>
>  #include <jffs2/load_kernel.h>
>  #include <linux/list.h>
> @@ -1106,7 +1107,7 @@ static int dfu_init_entities(struct stm32prog_data *data)
>  	struct dfu_entity *dfu;
>  	int alt_nb;
>  
> -	alt_nb = 1; /* number of virtual = CMD */
> +	alt_nb = 2; /* number of virtual = CMD, OTP*/
>  	if (data->part_nb == 0)
>  		alt_nb++;  /* +1 for FlashLayout */
>  	else
> @@ -1154,6 +1155,9 @@ static int dfu_init_entities(struct stm32prog_data *data)
>  	if (!ret)
>  		ret = stm32prog_alt_add_virt(dfu, "virtual", PHASE_CMD, 512);
>  
> +	if (!ret)
> +		ret = stm32prog_alt_add_virt(dfu, "OTP", PHASE_OTP, 512);
> +
>  	if (ret)
>  		stm32prog_err("dfu init failed: %d", ret);
>  	puts("done\n");
> @@ -1164,6 +1168,123 @@ static int dfu_init_entities(struct stm32prog_data *data)
>  	return ret;
>  }
>  
> +int stm32prog_otp_write(struct stm32prog_data *data, u32 offset, u8 *buffer,
> +			long *size)
> +{
> +	pr_debug("%s: %x %lx\n", __func__, offset, *size);
> +
> +	if (!data->otp_part) {
> +		data->otp_part = memalign(CONFIG_SYS_CACHELINE_SIZE, OTP_SIZE);
> +		if (!data->otp_part)
> +			return -ENOMEM;
> +	}
> +
> +	if (!offset)
> +		memset(data->otp_part, 0, OTP_SIZE);
> +
> +	if (offset + *size > OTP_SIZE)
> +		*size = OTP_SIZE - offset;
> +
> +	memcpy((void *)((u32)data->otp_part + offset), buffer, *size);
> +
> +	return 0;
> +}
> +
> +int stm32prog_otp_read(struct stm32prog_data *data, u32 offset, u8 *buffer,
> +		       long *size)
> +{
> +#ifndef CONFIG_ARM_SMCCC
> +	stm32prog_err("OTP update not supported");
> +
> +	return -1;
> +#else
> +	int result = 0;
> +
> +	pr_debug("%s: %x %lx\n", __func__, offset, *size);
> +	/* alway read for first packet */
> +	if (!offset) {
> +		if (!data->otp_part)
> +			data->otp_part =
> +				memalign(CONFIG_SYS_CACHELINE_SIZE, OTP_SIZE);
> +
> +		if (!data->otp_part) {
> +			result = -ENOMEM;
> +			goto end_otp_read;
> +		}
> +
> +		/* init struct with 0 */
> +		memset(data->otp_part, 0, OTP_SIZE);
> +
> +		/* call the service */
> +		result = stm32_smc_exec(STM32_SMC_BSEC, STM32_SMC_READ_ALL,
> +					(u32)data->otp_part, 0);
> +		if (result)
> +			goto end_otp_read;
> +	}
> +
> +	if (!data->otp_part) {
> +		result = -ENOMEM;
> +		goto end_otp_read;
> +	}
> +
> +	if (offset + *size > OTP_SIZE)
> +		*size = OTP_SIZE - offset;
> +	memcpy(buffer, (void *)((u32)data->otp_part + offset), *size);
> +
> +end_otp_read:
> +	pr_debug("%s: result %i\n", __func__, result);
> +
> +	return result;
> +#endif
> +}
> +
> +int stm32prog_otp_start(struct stm32prog_data *data)
> +{
> +#ifndef CONFIG_ARM_SMCCC
> +	stm32prog_err("OTP update not supported");
> +
> +	return -1;
> +#else
> +	int result = 0;
> +	struct arm_smccc_res res;
> +
> +	if (!data->otp_part) {
> +		stm32prog_err("start OTP without data");
> +		return -1;
> +	}
> +
> +	arm_smccc_smc(STM32_SMC_BSEC, STM32_SMC_WRITE_ALL,
> +		      (u32)data->otp_part, 0, 0, 0, 0, 0, &res);
> +
> +	if (!res.a0) {
> +		switch (res.a1) {
> +		case 0:
> +			result = 0;
> +			break;
> +		case 1:
> +			stm32prog_err("Provisioning");
> +			result = 0;
> +			break;
> +		default:
> +			pr_err("%s: OTP incorrect value (err = %ld)\n",
> +			       __func__, res.a1);
> +			result = -EINVAL;
> +			break;
> +		}
> +	} else {
> +		pr_err("%s: Failed to exec svc=%x op=%x in secure mode (err = %ld)\n",
> +		       __func__, STM32_SMC_BSEC, STM32_SMC_WRITE_ALL, res.a0);
> +		result = -EINVAL;
> +	}
> +
> +	free(data->otp_part);
> +	data->otp_part = NULL;
> +	pr_debug("%s: result %i\n", __func__, result);
> +
> +	return result;
> +#endif
> +}
> +
>  /* copy FSBL on NAND to improve reliability on NAND */
>  static int stm32prog_copy_fsbl(struct stm32prog_part_t *part)
>  {
> @@ -1451,6 +1572,7 @@ void stm32prog_clean(struct stm32prog_data *data)
>  	/* clean */
>  	dfu_free_entities();
>  	free(data->part_array);
> +	free(data->otp_part);
>  	free(data->header_data);
>  }
>  
> @@ -1460,6 +1582,12 @@ void dfu_flush_callback(struct dfu_entity *dfu)
>  	if (!stm32prog_data)
>  		return;
>  
> +	if (dfu->dev_type == DFU_DEV_VIRT) {
> +		if (dfu->data.virt.dev_num == PHASE_OTP)
> +			stm32prog_otp_start(stm32prog_data);
> +		return;
> +	}
> +
>  	if (dfu->dev_type == DFU_DEV_RAM) {
>  		if (dfu->alt == 0 &&
>  		    stm32prog_data->phase == PHASE_FLASHLAYOUT) {
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
> index 1880b163d7..6024657433 100644
> --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
> @@ -11,12 +11,15 @@
>  #define PHASE_FIRST_USER	0x10
>  #define PHASE_LAST_USER		0xF0
>  #define PHASE_CMD		0xF1
> +#define PHASE_OTP		0xF2
>  #define PHASE_END		0xFE
>  #define PHASE_RESET		0xFF
>  #define PHASE_DO_RESET		0x1FF
>  
>  #define DEFAULT_ADDRESS		0xFFFFFFFF
>  
> +#define OTP_SIZE		1024
> +
>  enum stm32prog_target {
>  	STM32PROG_NONE,
>  	STM32PROG_MMC,
> @@ -116,6 +119,7 @@ struct stm32prog_data {
>  	u32			offset;
>  	char			error[255];
>  	struct stm32prog_part_t	*cur_part;
> +	u32			*otp_part;
>  
>  	/* STM32 header information */
>  	struct raw_header_s	*header_data;
> @@ -124,6 +128,13 @@ struct stm32prog_data {
>  
>  extern struct stm32prog_data *stm32prog_data;
>  
> +/* OTP access */
> +int stm32prog_otp_write(struct stm32prog_data *data, u32 offset,
> +			u8 *buffer, long *size);
> +int stm32prog_otp_read(struct stm32prog_data *data, u32 offset,
> +		       u8 *buffer, long *size);
> +int stm32prog_otp_start(struct stm32prog_data *data);
> +
>  /* generic part*/
>  u8 stm32prog_header_check(struct raw_header_s *raw_header,
>  			  struct image_header_s *header);
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c
> index ed2cdbc66f..4a4b4d326b 100644
> --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c
> @@ -130,6 +130,10 @@ int stm32prog_write_medium_virt(struct dfu_entity *dfu, u64 offset,
>  	switch (dfu->data.virt.dev_num) {
>  	case PHASE_CMD:
>  		return stm32prog_cmd_write(offset, buf, len);
> +
> +	case PHASE_OTP:
> +		return stm32prog_otp_write(stm32prog_data, (u32)offset,
> +					   buf, len);
>  	}
>  	*len = 0;
>  	return 0;
> @@ -144,6 +148,10 @@ int stm32prog_read_medium_virt(struct dfu_entity *dfu, u64 offset,
>  	switch (dfu->data.virt.dev_num) {
>  	case PHASE_CMD:
>  		return stm32prog_cmd_read(offset, buf, len);
> +
> +	case PHASE_OTP:
> +		return stm32prog_otp_read(stm32prog_data, (u32)offset,
> +					  buf, len);
>  	}
>  	*len = 0;
>  	return 0;
> @@ -162,6 +170,9 @@ int stm32prog_get_medium_size_virt(struct dfu_entity *dfu, u64 *size)
>  	case PHASE_CMD:
>  		*size = 512;
>  		break;
> +	case PHASE_OTP:
> +		*size = OTP_SIZE;
> +		break;
>  	}
>  
>  	return 0;

Reviewed-by: Patrice Chotard <patrice.chotard@st.com>

Thanks

Patrice

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 14/18] stm32mp: stm32prog: add pmic NVM update support
  2020-03-18  8:24 ` [PATCH 14/18] stm32mp: stm32prog: add pmic NVM " Patrick Delaunay
@ 2020-04-14 13:09   ` Patrice CHOTARD
  0 siblings, 0 replies; 40+ messages in thread
From: Patrice CHOTARD @ 2020-04-14 13:09 UTC (permalink / raw)
  To: u-boot

Hi

On 3/18/20 9:24 AM, Patrick Delaunay wrote:
> Add a virtual partition to update the pmic non volatile memory.
> (on ST board, STPMIC1).
>
> Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
> ---
>
>  .../mach-stm32mp/cmd_stm32prog/stm32prog.c    | 95 ++++++++++++++++++-
>  .../mach-stm32mp/cmd_stm32prog/stm32prog.h    | 10 ++
>  .../cmd_stm32prog/stm32prog_usb.c             | 11 +++
>  3 files changed, 115 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> index cd826dbb9c..d127afefaa 100644
> --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> @@ -7,6 +7,7 @@
>  #include <console.h>
>  #include <dfu.h>
>  #include <malloc.h>
> +#include <misc.h>
>  #include <mmc.h>
>  #include <part.h>
>  #include <asm/arch/stm32mp1_smc.h>
> @@ -1107,7 +1108,7 @@ static int dfu_init_entities(struct stm32prog_data *data)
>  	struct dfu_entity *dfu;
>  	int alt_nb;
>  
> -	alt_nb = 2; /* number of virtual = CMD, OTP*/
> +	alt_nb = 3; /* number of virtual = CMD, OTP, PMIC*/
>  	if (data->part_nb == 0)
>  		alt_nb++;  /* +1 for FlashLayout */
>  	else
> @@ -1158,6 +1159,9 @@ static int dfu_init_entities(struct stm32prog_data *data)
>  	if (!ret)
>  		ret = stm32prog_alt_add_virt(dfu, "OTP", PHASE_OTP, 512);
>  
> +	if (!ret && CONFIG_IS_ENABLED(DM_PMIC))
> +		ret = stm32prog_alt_add_virt(dfu, "PMIC", PHASE_PMIC, 8);
> +
>  	if (ret)
>  		stm32prog_err("dfu init failed: %d", ret);
>  	puts("done\n");
> @@ -1285,6 +1289,93 @@ int stm32prog_otp_start(struct stm32prog_data *data)
>  #endif
>  }
>  
> +int stm32prog_pmic_write(struct stm32prog_data *data, u32 offset, u8 *buffer,
> +			 long *size)
> +{
> +	pr_debug("%s: %x %lx\n", __func__, offset, *size);
> +
> +	if (!offset)
> +		memset(data->pmic_part, 0, PMIC_SIZE);
> +
> +	if (offset + *size > PMIC_SIZE)
> +		*size = PMIC_SIZE - offset;
> +
> +	memcpy(&data->pmic_part[offset], buffer, *size);
> +
> +	return 0;
> +}
> +
> +int stm32prog_pmic_read(struct stm32prog_data *data, u32 offset, u8 *buffer,
> +			long *size)
> +{
> +	int result = 0, ret;
> +	struct udevice *dev;
> +
> +	if (!CONFIG_IS_ENABLED(PMIC_STPMIC1)) {
> +		stm32prog_err("PMIC update not supported");
> +
> +		return -EOPNOTSUPP;
> +	}
> +
> +	pr_debug("%s: %x %lx\n", __func__, offset, *size);
> +	ret = uclass_get_device_by_driver(UCLASS_MISC,
> +					  DM_GET_DRIVER(stpmic1_nvm),
> +					  &dev);
> +	if (ret)
> +		return ret;
> +
> +	/* alway request PMIC for first packet */
> +	if (!offset) {
> +		/* init struct with 0 */
> +		memset(data->pmic_part, 0, PMIC_SIZE);
> +
> +		ret = uclass_get_device_by_driver(UCLASS_MISC,
> +						  DM_GET_DRIVER(stpmic1_nvm),
> +						  &dev);
> +		if (ret)
> +			return ret;
> +
> +		ret = misc_read(dev, 0xF8, data->pmic_part, PMIC_SIZE);
> +		if (ret < 0) {
> +			result = ret;
> +			goto end_pmic_read;
> +		}
> +		if (ret != PMIC_SIZE) {
> +			result = -EACCES;
> +			goto end_pmic_read;
> +		}
> +	}
> +
> +	if (offset + *size > PMIC_SIZE)
> +		*size = PMIC_SIZE - offset;
> +
> +	memcpy(buffer, &data->pmic_part[offset], *size);
> +
> +end_pmic_read:
> +	pr_debug("%s: result %i\n", __func__, result);
> +	return result;
> +}
> +
> +int stm32prog_pmic_start(struct stm32prog_data *data)
> +{
> +	int ret;
> +	struct udevice *dev;
> +
> +	if (!CONFIG_IS_ENABLED(PMIC_STPMIC1)) {
> +		stm32prog_err("PMIC update not supported");
> +
> +		return -EOPNOTSUPP;
> +	}
> +
> +	ret = uclass_get_device_by_driver(UCLASS_MISC,
> +					  DM_GET_DRIVER(stpmic1_nvm),
> +					  &dev);
> +	if (ret)
> +		return ret;
> +
> +	return misc_write(dev, 0xF8, data->pmic_part, PMIC_SIZE);
> +}
> +
>  /* copy FSBL on NAND to improve reliability on NAND */
>  static int stm32prog_copy_fsbl(struct stm32prog_part_t *part)
>  {
> @@ -1585,6 +1676,8 @@ void dfu_flush_callback(struct dfu_entity *dfu)
>  	if (dfu->dev_type == DFU_DEV_VIRT) {
>  		if (dfu->data.virt.dev_num == PHASE_OTP)
>  			stm32prog_otp_start(stm32prog_data);
> +		else if (dfu->data.virt.dev_num == PHASE_PMIC)
> +			stm32prog_pmic_start(stm32prog_data);
>  		return;
>  	}
>  
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
> index 6024657433..83b27980f5 100644
> --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
> @@ -12,6 +12,7 @@
>  #define PHASE_LAST_USER		0xF0
>  #define PHASE_CMD		0xF1
>  #define PHASE_OTP		0xF2
> +#define PHASE_PMIC		0xF4
>  #define PHASE_END		0xFE
>  #define PHASE_RESET		0xFF
>  #define PHASE_DO_RESET		0x1FF
> @@ -19,6 +20,7 @@
>  #define DEFAULT_ADDRESS		0xFFFFFFFF
>  
>  #define OTP_SIZE		1024
> +#define PMIC_SIZE		8
>  
>  enum stm32prog_target {
>  	STM32PROG_NONE,
> @@ -120,6 +122,7 @@ struct stm32prog_data {
>  	char			error[255];
>  	struct stm32prog_part_t	*cur_part;
>  	u32			*otp_part;
> +	u8			pmic_part[PMIC_SIZE];
>  
>  	/* STM32 header information */
>  	struct raw_header_s	*header_data;
> @@ -135,6 +138,13 @@ int stm32prog_otp_read(struct stm32prog_data *data, u32 offset,
>  		       u8 *buffer, long *size);
>  int stm32prog_otp_start(struct stm32prog_data *data);
>  
> +/* PMIC access */
> +int stm32prog_pmic_write(struct stm32prog_data *data, u32 offset,
> +			 u8 *buffer, long *size);
> +int stm32prog_pmic_read(struct stm32prog_data *data, u32 offset,
> +			u8 *buffer, long *size);
> +int stm32prog_pmic_start(struct stm32prog_data *data);
> +
>  /* generic part*/
>  u8 stm32prog_header_check(struct raw_header_s *raw_header,
>  			  struct image_header_s *header);
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c
> index 4a4b4d326b..34f27c074f 100644
> --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c
> @@ -134,6 +134,10 @@ int stm32prog_write_medium_virt(struct dfu_entity *dfu, u64 offset,
>  	case PHASE_OTP:
>  		return stm32prog_otp_write(stm32prog_data, (u32)offset,
>  					   buf, len);
> +
> +	case PHASE_PMIC:
> +		return stm32prog_pmic_write(stm32prog_data, (u32)offset,
> +					    buf, len);
>  	}
>  	*len = 0;
>  	return 0;
> @@ -152,6 +156,10 @@ int stm32prog_read_medium_virt(struct dfu_entity *dfu, u64 offset,
>  	case PHASE_OTP:
>  		return stm32prog_otp_read(stm32prog_data, (u32)offset,
>  					  buf, len);
> +
> +	case PHASE_PMIC:
> +		return stm32prog_pmic_read(stm32prog_data, (u32)offset,
> +					   buf, len);
>  	}
>  	*len = 0;
>  	return 0;
> @@ -173,6 +181,9 @@ int stm32prog_get_medium_size_virt(struct dfu_entity *dfu, u64 *size)
>  	case PHASE_OTP:
>  		*size = OTP_SIZE;
>  		break;
> +	case PHASE_PMIC:
> +		*size = PMIC_SIZE;
> +		break;
>  	}
>  
>  	return 0;

Reviewed-by: Patrice Chotard <patrice.chotard@st.com>

Thanks

Patrice

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 15/18] stm32mp: stm32prog: add serial link support
  2020-03-18  8:25 ` [PATCH 15/18] stm32mp: stm32prog: add serial link support Patrick Delaunay
@ 2020-04-14 13:10   ` Patrice CHOTARD
  0 siblings, 0 replies; 40+ messages in thread
From: Patrice CHOTARD @ 2020-04-14 13:10 UTC (permalink / raw)
  To: u-boot

Hi

On 3/18/20 9:25 AM, Patrick Delaunay wrote:
> Add a support of UART, using the same protocol than MCU STM32.
>
> See "AN5275: USB DFU/USART protocols used in STM32MP1 Series
> bootloaders" for details.
>
> Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
> ---
>
>  arch/arm/mach-stm32mp/cmd_stm32prog/Makefile  |   1 +
>  .../cmd_stm32prog/cmd_stm32prog.c             |  11 +-
>  .../mach-stm32mp/cmd_stm32prog/stm32prog.c    |   4 +
>  .../mach-stm32mp/cmd_stm32prog/stm32prog.h    |  11 +
>  .../cmd_stm32prog/stm32prog_serial.c          | 993 ++++++++++++++++++
>  .../cmd_stm32prog/stm32prog_usb.c             |   2 +
>  6 files changed, 1021 insertions(+), 1 deletion(-)
>  create mode 100644 arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c
>
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/Makefile b/arch/arm/mach-stm32mp/cmd_stm32prog/Makefile
> index 14f722759c..548a378921 100644
> --- a/arch/arm/mach-stm32mp/cmd_stm32prog/Makefile
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/Makefile
> @@ -5,4 +5,5 @@
>  
>  obj-y += cmd_stm32prog.o
>  obj-y += stm32prog.o
> +obj-y += stm32prog_serial.o
>  obj-y += stm32prog_usb.o
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
> index 581f97e0b5..1769ba05f2 100644
> --- a/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
> @@ -25,11 +25,14 @@ static int do_stm32prog(cmd_tbl_t *cmdtp, int flag, int argc,
>  
>  	if (!strcmp(argv[1], "usb"))
>  		link = LINK_USB;
> +	else if (!strcmp(argv[1], "serial"))
> +		link = LINK_SERIAL;
>  
>  	if (link == LINK_UNDEFINED) {
>  		pr_err("not supported link=%s\n", argv[1]);
>  		return CMD_RET_USAGE;
>  	}
> +
>  	dev = (int)simple_strtoul(argv[2], NULL, 10);
>  
>  	addr = STM32_DDR_BASE;
> @@ -60,6 +63,12 @@ static int do_stm32prog(cmd_tbl_t *cmdtp, int flag, int argc,
>  		goto cleanup;
>  
>  	switch (link) {
> +	case LINK_SERIAL:
> +		ret = stm32prog_serial_init(data, dev);
> +		if (ret)
> +			goto cleanup;
> +		reset = stm32prog_serial_loop(data);
> +		break;
>  	case LINK_USB:
>  		reset = stm32prog_usb_loop(data, dev);
>  		break;
> @@ -90,7 +99,7 @@ cleanup:
>  U_BOOT_CMD(stm32prog, 5, 0, do_stm32prog,
>  	   "<link> <dev> [<addr>] [<size>]\n"
>  	   "start communication with tools STM32Cubeprogrammer on <link> with Flashlayout at <addr>",
> -	   "<link> = usb\n"
> +	   "<link> = serial|usb\n"
>  	   "<dev>  = device instance\n"
>  	   "<addr> = address of flashlayout\n"
>  	   "<size> = size of flashlayout\n"
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> index d127afefaa..0967bbc11a 100644
> --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> @@ -1486,6 +1486,7 @@ void stm32prog_next_phase(struct stm32prog_data *data)
>  	}
>  
>  	/* found next selected partition */
> +	data->dfu_seq = 0;
>  	data->cur_part = NULL;
>  	data->phase = PHASE_END;
>  	found = false;
> @@ -1653,6 +1654,7 @@ int stm32prog_dfu_init(struct stm32prog_data *data)
>  int stm32prog_init(struct stm32prog_data *data, ulong addr, ulong size)
>  {
>  	memset(data, 0x0, sizeof(*data));
> +	data->read_phase = PHASE_RESET;
>  	data->phase = PHASE_FLASHLAYOUT;
>  
>  	return parse_flash_layout(data, addr, size);
> @@ -1664,6 +1666,7 @@ void stm32prog_clean(struct stm32prog_data *data)
>  	dfu_free_entities();
>  	free(data->part_array);
>  	free(data->otp_part);
> +	free(data->buffer);
>  	free(data->header_data);
>  }
>  
> @@ -1709,6 +1712,7 @@ void dfu_initiated_callback(struct dfu_entity *dfu)
>  	/* force the saved offset for the current partition */
>  	if (dfu->alt == stm32prog_data->cur_part->alt_id) {
>  		dfu->offset = stm32prog_data->offset;
> +		stm32prog_data->dfu_seq = 0;
>  		pr_debug("dfu offset = 0x%llx\n", dfu->offset);
>  	}
>  }
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
> index 83b27980f5..c4fdb5b8c3 100644
> --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
> @@ -31,6 +31,7 @@ enum stm32prog_target {
>  };
>  
>  enum stm32prog_link_t {
> +	LINK_SERIAL,
>  	LINK_USB,
>  	LINK_UNDEFINED,
>  };
> @@ -127,6 +128,14 @@ struct stm32prog_data {
>  	/* STM32 header information */
>  	struct raw_header_s	*header_data;
>  	struct image_header_s	header;
> +
> +	/* SERIAL information */
> +	u32	cursor;
> +	u32	packet_number;
> +	u32	checksum;
> +	u8	*buffer; /* size = USART_RAM_BUFFER_SIZE*/
> +	int	dfu_seq;
> +	u8	read_phase;
>  };
>  
>  extern struct stm32prog_data *stm32prog_data;
> @@ -163,6 +172,8 @@ char *stm32prog_get_error(struct stm32prog_data *data);
>  
>  /* Main function */
>  int stm32prog_init(struct stm32prog_data *data, ulong addr, ulong size);
> +int stm32prog_serial_init(struct stm32prog_data *data, int link_dev);
> +bool stm32prog_serial_loop(struct stm32prog_data *data);
>  bool stm32prog_usb_loop(struct stm32prog_data *data, int dev);
>  void stm32prog_clean(struct stm32prog_data *data);
>  
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c
> new file mode 100644
> index 0000000000..5a16979adc
> --- /dev/null
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_serial.c
> @@ -0,0 +1,993 @@
> +// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
> +/*
> + * Copyright (C) 2020, STMicroelectronics - All Rights Reserved
> + */
> +
> +#include <common.h>
> +#include <console.h>
> +#include <dfu.h>
> +#include <malloc.h>
> +#include <serial.h>
> +#include <watchdog.h>
> +#include <dm/lists.h>
> +#include <dm/device-internal.h>
> +#include "stm32prog.h"
> +
> +/* - configuration part -----------------------------*/
> +#define USART_BL_VERSION	0x40	/* USART bootloader version V4.0*/
> +#define UBOOT_BL_VERSION	0x03	/* bootloader version V0.3*/
> +#define DEVICE_ID_BYTE1		0x05	/* MSB byte of device ID*/
> +#define DEVICE_ID_BYTE2		0x00	/* LSB byte of device ID*/
> +#define USART_RAM_BUFFER_SIZE	256	/* Size of USART_RAM_Buf buffer*/
> +
> +/* - Commands -----------------------------*/
> +#define GET_CMD_COMMAND		0x00	/* Get CMD command*/
> +#define GET_VER_COMMAND		0x01	/* Get Version command*/
> +#define GET_ID_COMMAND		0x02	/* Get ID command*/
> +#define GET_PHASE_COMMAND	0x03	/* Get Phase command*/
> +#define RM_COMMAND		0x11	/* Read Memory command*/
> +#define READ_PART_COMMAND	0x12	/* Read Partition command*/
> +#define START_COMMAND		0x21	/* START command (Go)*/
> +#define DOWNLOAD_COMMAND	0x31	/* Download command*/
> +/* existing command for other STM32 but not used */
> +/* ERASE			0x43 */
> +/* EXTENDED_ERASE		0x44 */
> +/* WRITE_UNPROTECTED		0x73 */
> +/* READOUT_PROTECT		0x82 */
> +/* READOUT_UNPROTECT		0x92 */
> +
> +/* - miscellaneous defines ----------------------------------------*/
> +#define INIT_BYTE		0x7F	/*Init Byte ID*/
> +#define ACK_BYTE		0x79	/*Acknowlede Byte ID*/
> +#define NACK_BYTE		0x1F	/*No Acknowlede Byte ID*/
> +#define ABORT_BYTE		0x5F	/*ABORT*/
> +
> +struct udevice *down_serial_dev;
> +
> +const u8 cmd_id[] = {
> +	GET_CMD_COMMAND,
> +	GET_VER_COMMAND,
> +	GET_ID_COMMAND,
> +	GET_PHASE_COMMAND,
> +	RM_COMMAND,
> +	READ_PART_COMMAND,
> +	START_COMMAND,
> +	DOWNLOAD_COMMAND
> +};
> +
> +#define NB_CMD sizeof(cmd_id)
> +
> +/* DFU support for serial *********************************************/
> +static struct dfu_entity *stm32prog_get_entity(struct stm32prog_data *data)
> +{
> +	int alt_id;
> +
> +	if (!data->cur_part)
> +		if (data->phase == PHASE_FLASHLAYOUT)
> +			alt_id = 0;
> +		else
> +			return NULL;
> +	else
> +		alt_id = data->cur_part->alt_id;
> +
> +	return dfu_get_entity(alt_id);
> +}
> +
> +static int stm32prog_write(struct stm32prog_data *data, u8 *buffer,
> +			   u32 buffer_size)
> +{
> +	struct dfu_entity *dfu_entity;
> +	u8 ret = 0;
> +
> +	dfu_entity = stm32prog_get_entity(data);
> +	if (!dfu_entity)
> +		return -ENODEV;
> +
> +	ret = dfu_write(dfu_entity,
> +			buffer,
> +			buffer_size,
> +			data->dfu_seq);
> +
> +	if (ret) {
> +		stm32prog_err("DFU write failed [%d] cnt: %d",
> +			      ret, data->dfu_seq);
> +	}
> +	data->dfu_seq++;
> +	/* handle rollover as in driver/dfu/dfu.c */
> +	data->dfu_seq &= 0xffff;
> +	if (buffer_size == 0)
> +		data->dfu_seq = 0; /* flush done */
> +
> +	return ret;
> +}
> +
> +static int stm32prog_read(struct stm32prog_data *data, u8 phase, u32 offset,
> +			  u8 *buffer, u32 buffer_size)
> +{
> +	struct dfu_entity *dfu_entity;
> +	struct stm32prog_part_t *part;
> +	u32 size;
> +	int ret, i;
> +
> +	if (data->dfu_seq) {
> +		stm32prog_err("DFU write pending for phase %d, seq %d",
> +			      data->phase, data->dfu_seq);
> +		return -EINVAL;
> +	}
> +	if (phase == PHASE_FLASHLAYOUT || phase > PHASE_LAST_USER) {
> +		stm32prog_err("read failed : phase %d is invalid", phase);
> +		return -EINVAL;
> +	}
> +	if (data->read_phase <= PHASE_LAST_USER &&
> +	    phase != data->read_phase) {
> +		/* clear previous read session */
> +		dfu_entity = dfu_get_entity(data->read_phase - 1);
> +		if (dfu_entity)
> +			dfu_transaction_cleanup(dfu_entity);
> +	}
> +
> +	dfu_entity = NULL;
> +	/* found partition for the expected phase */
> +	for (i = 0; i < data->part_nb; i++) {
> +		part = &data->part_array[i];
> +		if (part->id == phase)
> +			dfu_entity = dfu_get_entity(part->alt_id);
> +	}
> +	if (!dfu_entity) {
> +		stm32prog_err("read failed : phase %d is unknown", phase);
> +		return -ENODEV;
> +	}
> +
> +	/* clear pending read before to force offset */
> +	if (dfu_entity->inited &&
> +	    (data->read_phase != phase || data->offset != offset))
> +		dfu_transaction_cleanup(dfu_entity);
> +
> +	/* initiate before to force offset */
> +	if (!dfu_entity->inited) {
> +		ret = dfu_transaction_initiate(dfu_entity, true);
> +			if (ret < 0) {
> +				stm32prog_err("DFU read init failed [%d] phase = %d offset = 0x%08x",
> +					      ret, phase, offset);
> +			return ret;
> +		}
> +	}
> +	/* force new offset */
> +	if (dfu_entity->offset != offset)
> +		dfu_entity->offset = offset;
> +	data->offset = offset;
> +	data->read_phase = phase;
> +	pr_debug("\nSTM32 download read %s offset=0x%x\n",
> +		 dfu_entity->name, offset);
> +	ret = dfu_read(dfu_entity, buffer, buffer_size,
> +		       dfu_entity->i_blk_seq_num);
> +	if (ret < 0) {
> +		stm32prog_err("DFU read failed [%d] phase = %d offset = 0x%08x",
> +			      ret, phase, offset);
> +		return ret;
> +	}
> +
> +	size = ret;
> +
> +	if (size < buffer_size) {
> +		data->offset = 0;
> +		data->read_phase = PHASE_END;
> +		memset(buffer + size, 0, buffer_size - size);
> +	} else {
> +		data->offset += size;
> +	}
> +
> +	return ret;
> +}
> +
> +/* UART access ***************************************************/
> +int stm32prog_serial_init(struct stm32prog_data *data, int link_dev)
> +{
> +	struct udevice *dev = NULL;
> +	int node;
> +	char alias[10];
> +	const char *path;
> +	struct dm_serial_ops *ops;
> +	/* no parity, 8 bits, 1 stop */
> +	u32 serial_config = SERIAL_DEFAULT_CONFIG;
> +
> +	down_serial_dev = NULL;
> +
> +	sprintf(alias, "serial%d", link_dev);
> +	path = fdt_get_alias(gd->fdt_blob, alias);
> +	if (!path) {
> +		pr_err("%s alias not found", alias);
> +		return -ENODEV;
> +	}
> +	node = fdt_path_offset(gd->fdt_blob, path);
> +	if (!uclass_get_device_by_of_offset(UCLASS_SERIAL, node,
> +					    &dev)) {
> +		down_serial_dev = dev;
> +	} else if (node > 0 &&
> +		   !lists_bind_fdt(gd->dm_root, offset_to_ofnode(node),
> +				   &dev, false)) {
> +		if (!device_probe(dev))
> +			down_serial_dev = dev;
> +	}
> +	if (!down_serial_dev) {
> +		pr_err("%s = %s device not found", alias, path);
> +		return -ENODEV;
> +	}
> +
> +	/* force silent console on uart only when used */
> +	if (gd->cur_serial_dev == down_serial_dev)
> +		gd->flags |= GD_FLG_DISABLE_CONSOLE | GD_FLG_SILENT;
> +	else
> +		gd->flags &= ~(GD_FLG_DISABLE_CONSOLE | GD_FLG_SILENT);
> +
> +	ops = serial_get_ops(down_serial_dev);
> +
> +	if (!ops) {
> +		pr_err("%s = %s missing ops", alias, path);
> +		return -ENODEV;
> +	}
> +	if (!ops->setconfig) {
> +		pr_err("%s = %s missing setconfig", alias, path);
> +		return -ENODEV;
> +	}
> +
> +	clrsetbits_le32(&serial_config, SERIAL_PAR_MASK, SERIAL_PAR_EVEN);
> +
> +	data->buffer = memalign(CONFIG_SYS_CACHELINE_SIZE,
> +				USART_RAM_BUFFER_SIZE);
> +
> +	return ops->setconfig(down_serial_dev, serial_config);
> +}
> +
> +static void stm32prog_serial_flush(void)
> +{
> +	struct dm_serial_ops *ops = serial_get_ops(down_serial_dev);
> +	int err;
> +
> +	do {
> +		err = ops->getc(down_serial_dev);
> +	} while (err != -EAGAIN);
> +}
> +
> +static int stm32prog_serial_getc_err(void)
> +{
> +	struct dm_serial_ops *ops = serial_get_ops(down_serial_dev);
> +	int err;
> +
> +	do {
> +		err = ops->getc(down_serial_dev);
> +		if (err == -EAGAIN) {
> +			ctrlc();
> +			WATCHDOG_RESET();
> +		}
> +	} while ((err == -EAGAIN) && (!had_ctrlc()));
> +
> +	return err;
> +}
> +
> +static u8 stm32prog_serial_getc(void)
> +{
> +	int err;
> +
> +	err = stm32prog_serial_getc_err();
> +
> +	return err >= 0 ? err : 0;
> +}
> +
> +static bool stm32prog_serial_get_buffer(u8 *buffer, u32 *count)
> +{
> +	struct dm_serial_ops *ops = serial_get_ops(down_serial_dev);
> +	int err;
> +
> +	do {
> +		err = ops->getc(down_serial_dev);
> +		if (err >= 0) {
> +			*buffer++ = err;
> +			*count -= 1;
> +		} else if (err == -EAGAIN) {
> +			ctrlc();
> +			WATCHDOG_RESET();
> +		} else {
> +			break;
> +		}
> +	} while (*count && !had_ctrlc());
> +
> +	return !!(err < 0);
> +}
> +
> +static void stm32prog_serial_putc(u8 w_byte)
> +{
> +	struct dm_serial_ops *ops = serial_get_ops(down_serial_dev);
> +	int err;
> +
> +	do {
> +		err = ops->putc(down_serial_dev, w_byte);
> +	} while (err == -EAGAIN);
> +}
> +
> +/* Helper function ************************************************/
> +
> +static u8 stm32prog_header(struct stm32prog_data *data)
> +{
> +	u8 ret;
> +	u8 boot = 0;
> +	struct dfu_entity *dfu_entity;
> +	u64 size = 0;
> +
> +	dfu_entity = stm32prog_get_entity(data);
> +	if (!dfu_entity)
> +		return -ENODEV;
> +
> +	printf("\nSTM32 download write %s\n", dfu_entity->name);
> +
> +	/* force cleanup to avoid issue with previous read */
> +	dfu_transaction_cleanup(dfu_entity);
> +
> +	ret = stm32prog_header_check(data->header_data,
> +				     &data->header);
> +
> +	/* no header : max size is partition size */
> +	if (ret) {
> +		dfu_entity->get_medium_size(dfu_entity, &size);
> +		data->header.image_length = size;
> +	}
> +
> +	/**** Flash the header if necessary for boot partition */
> +	if (data->phase < PHASE_FIRST_USER)
> +		boot = 1;
> +
> +	/* write header if boot partition */
> +	if (boot) {
> +		if (ret) {
> +			stm32prog_err("invalid header (error %d)", ret);
> +		} else {
> +			ret = stm32prog_write(data,
> +					      (u8 *)data->header_data,
> +					      BL_HEADER_SIZE);
> +		}
> +	} else {
> +		if (ret)
> +			printf("  partition without checksum\n");
> +		ret = 0;
> +	}
> +
> +	free(data->header_data);
> +	data->header_data = NULL;
> +
> +	return ret;
> +}
> +
> +static u8 stm32prog_start(struct stm32prog_data *data, u32 address)
> +{
> +	u8 ret = 0;
> +	struct dfu_entity *dfu_entity;
> +
> +	if (address < 0x100) {
> +		if (address == PHASE_OTP)
> +			return stm32prog_otp_start(data);
> +
> +		if (address == PHASE_PMIC)
> +			return stm32prog_pmic_start(data);
> +
> +		if (address == PHASE_RESET || address == PHASE_END) {
> +			data->cur_part = NULL;
> +			data->dfu_seq = 0;
> +			data->phase = address;
> +			return 0;
> +		}
> +		if (address != data->phase) {
> +			stm32prog_err("invalid received phase id %d, current phase is %d",
> +				      (u8)address, (u8)data->phase);
> +			return -EINVAL;
> +		}
> +	}
> +	/* check the last loaded partition */
> +	if (address == DEFAULT_ADDRESS || address == data->phase) {
> +		switch (data->phase) {
> +		case PHASE_END:
> +		case PHASE_RESET:
> +		case PHASE_DO_RESET:
> +			data->cur_part = NULL;
> +			data->phase = PHASE_DO_RESET;
> +			return 0;
> +		}
> +		dfu_entity = stm32prog_get_entity(data);
> +		if (!dfu_entity)
> +			return -ENODEV;
> +
> +		if (data->dfu_seq) {
> +			ret = dfu_flush(dfu_entity, NULL, 0, data->dfu_seq);
> +			data->dfu_seq = 0;
> +			if (ret) {
> +				stm32prog_err("DFU flush failed [%d]", ret);
> +				return ret;
> +			}
> +		}
> +		printf("\n  received length = 0x%x\n", data->cursor);
> +		if (data->header.present) {
> +			if (data->cursor !=
> +			    (data->header.image_length + BL_HEADER_SIZE)) {
> +				stm32prog_err("transmission interrupted (length=0x%x expected=0x%x)",
> +					      data->cursor,
> +					      data->header.image_length +
> +					      BL_HEADER_SIZE);
> +				return -EIO;
> +			}
> +			if (data->header.image_checksum != data->checksum) {
> +				stm32prog_err("invalid checksum received (0x%x expected 0x%x)",
> +					      data->checksum,
> +					      data->header.image_checksum);
> +				return -EIO;
> +			}
> +			printf("\n  checksum OK (0x%x)\n", data->checksum);
> +		}
> +
> +		/* update DFU with received flashlayout */
> +		if (data->phase == PHASE_FLASHLAYOUT)
> +			stm32prog_dfu_init(data);
> +	} else {
> +		void (*entry)(void) = (void *)address;
> +
> +		printf("## Starting application at 0x%x ...\n", address);
> +		(*entry)();
> +		printf("## Application terminated\n");
> +		ret = -ENOEXEC;
> +	}
> +
> +	return ret;
> +}
> +
> +/**
> + * get_address() - Get address if it is valid
> + *
> + * @tmp_xor:		Current xor value to update
> + * @return The address area
> + */
> +static u32 get_address(u8 *tmp_xor)
> +{
> +	u32 address = 0x0;
> +	u8 data;
> +
> +	data = stm32prog_serial_getc();
> +	*tmp_xor ^= data;
> +	address |= ((u32)data) << 24;
> +
> +	data = stm32prog_serial_getc();
> +	address |= ((u32)data) << 16;
> +	*tmp_xor ^= data;
> +
> +	data = stm32prog_serial_getc();
> +	address |= ((u32)data) << 8;
> +	*tmp_xor ^= data;
> +
> +	data = stm32prog_serial_getc();
> +	address |= ((u32)data);
> +	*tmp_xor ^= data;
> +
> +	return address;
> +}
> +
> +static void stm32prog_serial_result(u8 result)
> +{
> +	/* always flush fifo before to send result */
> +	stm32prog_serial_flush();
> +	stm32prog_serial_putc(result);
> +}
> +
> +/* Command -----------------------------------------------*/
> +/**
> + * get_cmd_command() - Respond to Get command
> + *
> + * @data:		Current command context
> + */
> +static void get_cmd_command(struct stm32prog_data *data)
> +{
> +	u32 counter = 0x0;
> +
> +	stm32prog_serial_putc(NB_CMD);
> +	stm32prog_serial_putc(USART_BL_VERSION);
> +
> +	for (counter = 0; counter < NB_CMD; counter++)
> +		stm32prog_serial_putc(cmd_id[counter]);
> +
> +	stm32prog_serial_result(ACK_BYTE);
> +}
> +
> +/**
> + * get_version_command() - Respond to Get Version command
> + *
> + * @data:		Current command context
> + */
> +static void get_version_command(struct stm32prog_data *data)
> +{
> +	stm32prog_serial_putc(UBOOT_BL_VERSION);
> +	stm32prog_serial_result(ACK_BYTE);
> +}
> +
> +/**
> + * get_id_command() - Respond to Get ID command
> + *
> + * @data:		Current command context
> + */
> +static void get_id_command(struct stm32prog_data *data)
> +{
> +	/* Send Device IDCode */
> +	stm32prog_serial_putc(0x1);
> +	stm32prog_serial_putc(DEVICE_ID_BYTE1);
> +	stm32prog_serial_putc(DEVICE_ID_BYTE2);
> +	stm32prog_serial_result(ACK_BYTE);
> +}
> +
> +/**
> + * get_phase_command() - Respond to Get phase
> + *
> + * @data:		Current command context
> + */
> +static void get_phase_command(struct stm32prog_data *data)
> +{
> +	char *err_msg = NULL;
> +	u8 i, length = 0;
> +	u32 destination = DEFAULT_ADDRESS; /* destination address */
> +	int phase = data->phase;
> +
> +	if (phase == PHASE_RESET || phase == PHASE_DO_RESET) {
> +		err_msg = stm32prog_get_error(data);
> +		length = strlen(err_msg);
> +	}
> +	if (phase == PHASE_FLASHLAYOUT)
> +		destination = STM32_DDR_BASE;
> +
> +	stm32prog_serial_putc(length + 5);           /* Total length */
> +	stm32prog_serial_putc(phase & 0xFF);         /* partition ID */
> +	stm32prog_serial_putc(destination);          /* byte 1 of address */
> +	stm32prog_serial_putc(destination >> 8);     /* byte 2 of address */
> +	stm32prog_serial_putc(destination >> 16);    /* byte 3 of address */
> +	stm32prog_serial_putc(destination >> 24);    /* byte 4 of address */
> +
> +	stm32prog_serial_putc(length);               /* Information length */
> +	for (i = 0; i < length; i++)
> +		stm32prog_serial_putc(err_msg[i]);
> +	stm32prog_serial_result(ACK_BYTE);
> +
> +	if (phase == PHASE_RESET)
> +		stm32prog_do_reset(data);
> +}
> +
> +/**
> + * read_memory_command() - Read data from memory
> + *
> + * @data:		Current command context
> + */
> +static void read_memory_command(struct stm32prog_data *data)
> +{
> +	u32 address = 0x0;
> +	u8 rcv_data = 0x0, tmp_xor = 0x0;
> +	u32 counter = 0x0;
> +
> +	/* Read memory address */
> +	address = get_address(&tmp_xor);
> +
> +	/* If address memory is not received correctly */
> +	rcv_data = stm32prog_serial_getc();
> +	if (rcv_data != tmp_xor) {
> +		stm32prog_serial_result(NACK_BYTE);
> +		return;
> +	}
> +
> +	stm32prog_serial_result(ACK_BYTE);
> +
> +	/* Read the number of bytes to be received:
> +	 * Max NbrOfData = Data + 1 = 256
> +	 */
> +	rcv_data = stm32prog_serial_getc();
> +	tmp_xor = ~rcv_data;
> +	if (stm32prog_serial_getc() != tmp_xor) {
> +		stm32prog_serial_result(NACK_BYTE);
> +		return;
> +	}
> +
> +	/* If checksum is correct send ACK */
> +	stm32prog_serial_result(ACK_BYTE);
> +
> +	/* Send data to the host:
> +	 * Number of data to read = data + 1
> +	 */
> +	for (counter = (rcv_data + 1); counter != 0; counter--)
> +		stm32prog_serial_putc(*(u8 *)(address++));
> +}
> +
> +/**
> + * start_command() - Respond to start command
> + *
> + * Jump to user application in RAM or partition check
> + *
> + * @data:		Current command context
> + */
> +static void start_command(struct stm32prog_data *data)
> +{
> +	u32 address = 0;
> +	u8 tmp_xor = 0x0;
> +	u8 ret, rcv_data;
> +
> +	/* Read memory address */
> +	address = get_address(&tmp_xor);
> +
> +	/* If address memory is not received correctly */
> +	rcv_data = stm32prog_serial_getc();
> +	if (rcv_data != tmp_xor) {
> +		stm32prog_serial_result(NACK_BYTE);
> +		return;
> +	}
> +	/* validate partition */
> +	ret = stm32prog_start(data,
> +			      address);
> +
> +	if (ret)
> +		stm32prog_serial_result(ABORT_BYTE);
> +	else
> +		stm32prog_serial_result(ACK_BYTE);
> +}
> +
> +/**
> + * download_command() - Respond to download command
> + *
> + * Write data to not volatile memory, Flash
> + *
> + * @data:		Current command context
> + */
> +static void download_command(struct stm32prog_data *data)
> +{
> +	u32 address = 0x0;
> +	u8 my_xor = 0x0;
> +	u8 rcv_xor;
> +	u32 counter = 0x0, codesize = 0x0;
> +	u8 *ramaddress = 0;
> +	u8 rcv_data = 0x0;
> +	struct image_header_s *image_header = &data->header;
> +	u32 cursor = data->cursor;
> +	long size = 0;
> +	u8 operation;
> +	u32 packet_number;
> +	u32 result = ACK_BYTE;
> +	u8 ret;
> +	unsigned int i;
> +	bool error;
> +	int rcv;
> +
> +	address = get_address(&my_xor);
> +
> +	/* If address memory is not received correctly */
> +	rcv_xor = stm32prog_serial_getc();
> +	if (rcv_xor != my_xor) {
> +		result = NACK_BYTE;
> +		goto end;
> +	}
> +
> +	/* If address valid send ACK */
> +	stm32prog_serial_result(ACK_BYTE);
> +
> +	/* get packet number and operation type */
> +	operation = (u8)((u32)address >> 24);
> +	packet_number = ((u32)(((u32)address << 8))) >> 8;
> +
> +	switch (operation) {
> +	/* supported operation */
> +	case PHASE_FLASHLAYOUT:
> +	case PHASE_OTP:
> +	case PHASE_PMIC:
> +		break;
> +	default:
> +		result = NACK_BYTE;
> +		goto end;
> +	}
> +	/* check the packet number */
> +	if (packet_number == 0) {
> +		/* erase: re-initialize the image_header struct */
> +		data->packet_number = 0;
> +		if (data->header_data)
> +			memset(data->header_data, 0, BL_HEADER_SIZE);
> +		else
> +			data->header_data = calloc(1, BL_HEADER_SIZE);
> +		cursor = 0;
> +		data->cursor = 0;
> +		data->checksum = 0;
> +		/*idx = cursor;*/
> +	} else {
> +		data->packet_number++;
> +	}
> +
> +	/* Check with the number of current packet if the device receive
> +	 * the true packet
> +	 */
> +	if (packet_number != data->packet_number) {
> +		data->packet_number--;
> +		result = NACK_BYTE;
> +		goto end;
> +	}
> +
> +	/*-- Read number of bytes to be written and data -----------*/
> +
> +	/* Read the number of bytes to be written:
> +	 * Max NbrOfData = data + 1 <= 256
> +	 */
> +	rcv_data = stm32prog_serial_getc();
> +
> +	/* NbrOfData to write = data + 1 */
> +	codesize = rcv_data + 0x01;
> +
> +	if (codesize > USART_RAM_BUFFER_SIZE) {
> +		result = NACK_BYTE;
> +		goto end;
> +	}
> +
> +	/* Checksum Initialization */
> +	my_xor = rcv_data;
> +
> +	/* UART receive data and send to Buffer */
> +	counter = codesize;
> +	error = stm32prog_serial_get_buffer(data->buffer, &counter);
> +
> +	/* read checksum */
> +	if (!error) {
> +		rcv = stm32prog_serial_getc_err();
> +		error = !!(rcv < 0);
> +		rcv_xor = rcv;
> +	}
> +
> +	if (error) {
> +		printf("transmission error on packet %d, byte %d\n",
> +		       packet_number, codesize - counter);
> +		/* waiting end of packet before flush & NACK */
> +		mdelay(30);
> +		data->packet_number--;
> +		result = NACK_BYTE;
> +		goto end;
> +	}
> +
> +	/* Compute Checksum */
> +	ramaddress = data->buffer;
> +	for (counter = codesize; counter != 0; counter--)
> +		my_xor ^= *(ramaddress++);
> +
> +	/* If Checksum is incorrect */
> +	if (rcv_xor != my_xor) {
> +		printf("checksum error on packet %d\n",
> +		       packet_number);
> +		/* wait to be sure that all data are received
> +		 * in the FIFO before flush
> +		 */
> +		mdelay(30);
> +		data->packet_number--;
> +		result = NACK_BYTE;
> +		goto end;
> +	}
> +
> +	/* Update current position in buffer */
> +	data->cursor += codesize;
> +
> +	if (operation == PHASE_OTP) {
> +		size = data->cursor - cursor;
> +		/* no header for OTP */
> +		if (stm32prog_otp_write(data, cursor,
> +					data->buffer, &size))
> +			result = ABORT_BYTE;
> +		goto end;
> +	}
> +
> +	if (operation == PHASE_PMIC) {
> +		size = data->cursor - cursor;
> +		/* no header for PMIC */
> +		if (stm32prog_pmic_write(data, cursor,
> +					 data->buffer, &size))
> +			result = ABORT_BYTE;
> +		goto end;
> +	}
> +
> +	if (cursor < BL_HEADER_SIZE) {
> +		/* size = portion of header in this chunck */
> +		if (data->cursor >= BL_HEADER_SIZE)
> +			size = BL_HEADER_SIZE - cursor;
> +		else
> +			size = data->cursor - cursor;
> +		memcpy((void *)((u32)(data->header_data) + cursor),
> +		       data->buffer, size);
> +		cursor += size;
> +
> +		if (cursor == BL_HEADER_SIZE) {
> +			/* Check and Write the header */
> +			if (stm32prog_header(data)) {
> +				result = ABORT_BYTE;
> +				goto end;
> +			}
> +		} else {
> +			goto end;
> +		}
> +	}
> +
> +	if (image_header->present) {
> +		if (data->cursor <= BL_HEADER_SIZE)
> +			goto end;
> +		/* compute checksum on payload */
> +		for (i = (unsigned long)size; i < codesize; i++)
> +			data->checksum += data->buffer[i];
> +
> +		if (data->cursor >
> +		    image_header->image_length + BL_HEADER_SIZE) {
> +			pr_err("expected size exceeded\n");
> +			result = ABORT_BYTE;
> +			goto end;
> +		}
> +
> +		/* write data (payload) */
> +		ret = stm32prog_write(data,
> +				      &data->buffer[size],
> +				      codesize - size);
> +	} else {
> +		/* write all */
> +		ret = stm32prog_write(data,
> +				      data->buffer,
> +				      codesize);
> +	}
> +	if (ret)
> +		result = ABORT_BYTE;
> +
> +end:
> +	stm32prog_serial_result(result);
> +}
> +
> +/**
> + * read_partition() - Respond to read command
> + *
> + * Read data from not volatile memory, Flash
> + *
> + * @data:		Current command context
> + */
> +static void read_partition_command(struct stm32prog_data *data)
> +{
> +	u32 i, part_id, codesize, offset = 0, rcv_data;
> +	long size;
> +	u8 tmp_xor;
> +	int res;
> +	u8 buffer[256];
> +
> +	part_id = stm32prog_serial_getc();
> +	tmp_xor = part_id;
> +
> +	offset = get_address(&tmp_xor);
> +
> +	rcv_data = stm32prog_serial_getc();
> +	if (rcv_data != tmp_xor) {
> +		pr_debug("1st checksum received = %x, computed %x\n",
> +			 rcv_data, tmp_xor);
> +		goto error;
> +	}
> +	stm32prog_serial_putc(ACK_BYTE);
> +
> +	/* NbrOfData to read = data + 1 */
> +	rcv_data = stm32prog_serial_getc();
> +	codesize = rcv_data + 0x01;
> +	tmp_xor = rcv_data;
> +
> +	rcv_data = stm32prog_serial_getc();
> +	if ((rcv_data ^ tmp_xor) != 0xFF) {
> +		pr_debug("2nd checksum received = %x, computed %x\n",
> +			 rcv_data, tmp_xor);
> +		goto error;
> +	}
> +
> +	pr_debug("%s : %x\n", __func__, part_id);
> +	rcv_data = 0;
> +	switch (part_id) {
> +	case PHASE_OTP:
> +		size = codesize;
> +		if (!stm32prog_otp_read(data, offset, buffer, &size))
> +			rcv_data = size;
> +		break;
> +	case PHASE_PMIC:
> +		size = codesize;
> +		if (!stm32prog_pmic_read(data, offset, buffer, &size))
> +			rcv_data = size;
> +		break;
> +	default:
> +		res = stm32prog_read(data, part_id, offset,
> +				     buffer, codesize);
> +		if (res > 0)
> +			rcv_data = res;
> +		break;
> +	}
> +	if (rcv_data > 0) {
> +		stm32prog_serial_putc(ACK_BYTE);
> +		/*----------- Send data to the host -----------*/
> +		for (i = 0; i < rcv_data; i++)
> +			stm32prog_serial_putc(buffer[i]);
> +		/*----------- Send filler to the host -----------*/
> +		for (; i < codesize; i++)
> +			stm32prog_serial_putc(0x0);
> +		return;
> +	}
> +	stm32prog_serial_result(ABORT_BYTE);
> +	return;
> +
> +error:
> +	stm32prog_serial_result(NACK_BYTE);
> +}
> +
> +/* MAIN function = SERIAL LOOP ***********************************************/
> +
> +/**
> + * stm32prog_serial_loop() - USART bootloader Loop routine
> + *
> + * @data:		Current command context
> + * @return true if reset is needed after loop
> + */
> +bool stm32prog_serial_loop(struct stm32prog_data *data)
> +{
> +	u32 counter = 0x0;
> +	u8 command = 0x0;
> +	u8 found;
> +	int phase = data->phase;
> +
> +	/* element of cmd_func need to aligned with cmd_id[]*/
> +	void (*cmd_func[NB_CMD])(struct stm32prog_data *) = {
> +		/* GET_CMD_COMMAND */	get_cmd_command,
> +		/* GET_VER_COMMAND */	get_version_command,
> +		/* GET_ID_COMMAND */	get_id_command,
> +		/* GET_PHASE_COMMAND */	get_phase_command,
> +		/* RM_COMMAND */	read_memory_command,
> +		/* READ_PART_COMMAND */	read_partition_command,
> +		/* START_COMMAND */	start_command,
> +		/* DOWNLOAD_COMMAND */	download_command
> +	};
> +
> +	/* flush and NACK pending command received during u-boot init
> +	 * request command reemit
> +	 */
> +	stm32prog_serial_result(NACK_BYTE);
> +
> +	clear_ctrlc(); /* forget any previous Control C */
> +	while (!had_ctrlc()) {
> +		phase = data->phase;
> +
> +		if (phase == PHASE_DO_RESET)
> +			return true;
> +
> +		/* Get the user command: read first byte */
> +		command = stm32prog_serial_getc();
> +
> +		if (command == INIT_BYTE) {
> +			puts("\nConnected\n");
> +			stm32prog_serial_result(ACK_BYTE);
> +			continue;
> +		}
> +
> +		found = 0;
> +		for (counter = 0; counter < NB_CMD; counter++)
> +			if (cmd_id[counter] == command) {
> +				found = 1;
> +				break;
> +			}
> +		if (found)
> +			if ((command ^ stm32prog_serial_getc()) != 0xFF)
> +				found = 0;
> +		if (!found) {
> +			/* wait to be sure that all data are received
> +			 * in the FIFO before flush (CMD and XOR)
> +			 */
> +			mdelay(3);
> +			stm32prog_serial_result(NACK_BYTE);
> +		} else {
> +			stm32prog_serial_result(ACK_BYTE);
> +			cmd_func[counter](data);
> +		}
> +		WATCHDOG_RESET();
> +	}
> +
> +	/* clean device */
> +	if (gd->cur_serial_dev == down_serial_dev) {
> +		/* restore console on uart */
> +		gd->flags &= ~(GD_FLG_DISABLE_CONSOLE | GD_FLG_SILENT);
> +	}
> +	down_serial_dev = NULL;
> +
> +	return false; /* no reset after ctrlc */
> +}
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c
> index 34f27c074f..969245e199 100644
> --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c
> @@ -19,6 +19,7 @@ static int stm32prog_set_phase(struct stm32prog_data *data, u8 phase,
>  
>  	if (phase == data->phase) {
>  		data->offset = offset;
> +		data->dfu_seq = 0;
>  		return 0;
>  	}
>  
> @@ -29,6 +30,7 @@ static int stm32prog_set_phase(struct stm32prog_data *data, u8 phase,
>  			data->cur_part = part;
>  			data->phase = phase;
>  			data->offset = offset;
> +			data->dfu_seq = 0;
>  			return 0;
>  		}
>  	}

Reviewed-by: Patrice Chotard <patrice.chotard@st.com>

Thanks

Patrice

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 16/18] stm32mp: stm32prog: enable videoconsole
  2020-03-18  8:25 ` [PATCH 16/18] stm32mp: stm32prog: enable videoconsole Patrick Delaunay
@ 2020-04-14 13:11   ` Patrice CHOTARD
  0 siblings, 0 replies; 40+ messages in thread
From: Patrice CHOTARD @ 2020-04-14 13:11 UTC (permalink / raw)
  To: u-boot

Hi

On 3/18/20 9:25 AM, Patrick Delaunay wrote:
> Enable the videoconsole during the stm32prog command execution
> to have information without UART.
>
> Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
> ---
>
>  .../cmd_stm32prog/cmd_stm32prog.c             | 28 +++++++++++++++++++
>  1 file changed, 28 insertions(+)
>
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
> index 1769ba05f2..15bbdc2cb6 100644
> --- a/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
> @@ -11,6 +11,32 @@
>  
>  struct stm32prog_data *stm32prog_data;
>  
> +static void enable_vidconsole(void)
> +{
> +#ifdef CONFIG_DM_VIDEO
> +	char *stdname;
> +	char buf[64];
> +
> +	stdname = env_get("stdout");
> +	if (!stdname || !strstr(stdname, "vidconsole")) {
> +		if (!stdname)
> +			snprintf(buf, sizeof(buf), "serial,vidconsole");
> +		else
> +			snprintf(buf, sizeof(buf), "%s,vidconsole", stdname);
> +		env_set("stdout", buf);
> +	}
> +
> +	stdname = env_get("stderr");
> +	if (!stdname || !strstr(stdname, "vidconsole")) {
> +		if (!stdname)
> +			snprintf(buf, sizeof(buf), "serial,vidconsole");
> +		else
> +			snprintf(buf, sizeof(buf), "%s,vidconsole", stdname);
> +		env_set("stderr", buf);
> +	}
> +#endif
> +}
> +
>  static int do_stm32prog(cmd_tbl_t *cmdtp, int flag, int argc,
>  			char * const argv[])
>  {
> @@ -45,6 +71,8 @@ static int do_stm32prog(cmd_tbl_t *cmdtp, int flag, int argc,
>  	if (argc > 4)
>  		size = simple_strtoul(argv[4], NULL, 16);
>  
> +	enable_vidconsole();
> +
>  	data = (struct stm32prog_data *)malloc(sizeof(*data));
>  
>  	if (!data) {

Reviewed-by: Patrice Chotard <patrice.chotard@st.com>

Thanks

Patrice

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 17/18] stm32mp: stm32prog: support for script
  2020-03-18  8:25 ` [PATCH 17/18] stm32mp: stm32prog: support for script Patrick Delaunay
@ 2020-04-14 13:11   ` Patrice CHOTARD
  0 siblings, 0 replies; 40+ messages in thread
From: Patrice CHOTARD @ 2020-04-14 13:11 UTC (permalink / raw)
  To: u-boot

Hi

On 3/18/20 9:25 AM, Patrick Delaunay wrote:
> Support an U-Boot script included in uimage instead of flashlayout file
> (text file in tsv format).
>
> This feature is used to execute this script directly when U-Boot is
> loaded in DDR (for update without STM32CubeProgrammer for example).
>
> A simple example with dfu-util only is:
>
> $> echo "dfu 0" > script.cmd
> $> mkimage -C none -A arm -T script -d script.cmd script.uimg
> $> mkimage -T stm32image -a 0xC0000000 -e 0xC0000000 -d script.uimg \
>   script.stm32
>
> $> dfu-util -d 0483:df11 -a 1 -D tf-a.stm32
> $> dfu-util -d 0483:df11 -a 0 -D script.stm32
> $> dfu-util -d 0483:df11 -a 0 -D u-boot.stm32
> $> dfu-util -d 0483:df11 -a 0 -e
>
> Then you can used dfu-utils to update your device
>
> To increase speed, you can also switch to fastboot protocol with:
>   echo "fastboot 0" > script.cmd
>
> Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
> ---
>
>  .../arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c | 14 ++++++++++++++
>  1 file changed, 14 insertions(+)
>
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
> index 15bbdc2cb6..baf9b6bd1e 100644
> --- a/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
> @@ -6,6 +6,7 @@
>  #include <common.h>
>  #include <command.h>
>  #include <dfu.h>
> +#include <image.h>
>  #include <asm/arch/stm32prog.h>
>  #include "stm32prog.h"
>  
> @@ -44,6 +45,7 @@ static int do_stm32prog(cmd_tbl_t *cmdtp, int flag, int argc,
>  	int dev, ret;
>  	enum stm32prog_link_t link = LINK_UNDEFINED;
>  	bool reset = false;
> +	struct image_header_s header;
>  	struct stm32prog_data *data;
>  
>  	if (argc < 3 ||  argc > 5)
> @@ -71,6 +73,18 @@ static int do_stm32prog(cmd_tbl_t *cmdtp, int flag, int argc,
>  	if (argc > 4)
>  		size = simple_strtoul(argv[4], NULL, 16);
>  
> +	/* check STM32IMAGE presence */
> +	if (size == 0 &&
> +	    !stm32prog_header_check((struct raw_header_s *)addr, &header)) {
> +		size = header.image_length + BL_HEADER_SIZE;
> +
> +		/* uImage detected in STM32IMAGE, execute the script */
> +		if (IMAGE_FORMAT_LEGACY ==
> +		    genimg_get_format((void *)(addr + BL_HEADER_SIZE)))
> +			return image_source_script(addr + BL_HEADER_SIZE,
> +						   "script at 1");
> +	}
> +
>  	enable_vidconsole();
>  
>  	data = (struct stm32prog_data *)malloc(sizeof(*data));

Reviewed-by: Patrice Chotard <patrice.chotard@st.com>

Thanks

Patrice

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 18/18] stm32mp: stm32prog: add support of RAM target
  2020-03-18  8:25 ` [PATCH 18/18] stm32mp: stm32prog: add support of RAM target Patrick Delaunay
@ 2020-04-14 13:11   ` Patrice CHOTARD
  0 siblings, 0 replies; 40+ messages in thread
From: Patrice CHOTARD @ 2020-04-14 13:11 UTC (permalink / raw)
  To: u-boot

Hi

On 3/18/20 9:25 AM, Patrick Delaunay wrote:
> Add support of RAM target in flashlayout to load kernel image
> ("system") and device tree ("filesystem") in DDR with DFU and
> start these images.
>
> The flashlayout.tsv is:
>
> -	0x01	fsbl		Binary		none	0x00000000	tf-a.stm32
> -	0x03	ssbl		Binary		none	0x00000000	u-boot.stm32
> P	0x10	kernel		System		ram0	0xC2000000	uImage.bin
> P	0x11	dtb		FileSystem	ram0	0xC4000000	dtb.bin
>
> Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
> ---
>
>  .../cmd_stm32prog/cmd_stm32prog.c             | 28 ++++++++++++++++++
>  .../mach-stm32mp/cmd_stm32prog/stm32prog.c    | 29 ++++++++++++++++++-
>  .../mach-stm32mp/cmd_stm32prog/stm32prog.h    |  7 ++++-
>  3 files changed, 62 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
> index baf9b6bd1e..6bebea7ad5 100644
> --- a/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
> @@ -47,6 +47,7 @@ static int do_stm32prog(cmd_tbl_t *cmdtp, int flag, int argc,
>  	bool reset = false;
>  	struct image_header_s header;
>  	struct stm32prog_data *data;
> +	u32 uimage, dtb;
>  
>  	if (argc < 3 ||  argc > 5)
>  		return CMD_RET_USAGE;
> @@ -118,11 +119,38 @@ static int do_stm32prog(cmd_tbl_t *cmdtp, int flag, int argc,
>  		goto cleanup;
>  	}
>  
> +	uimage = data->uimage;
> +	dtb = data->dtb;
> +
>  	stm32prog_clean(data);
>  	free(stm32prog_data);
>  	stm32prog_data = NULL;
>  
>  	puts("Download done\n");
> +
> +	if (uimage) {
> +		char boot_addr_start[20];
> +		char dtb_addr[20];
> +		char *bootm_argv[5] = {
> +			"bootm", boot_addr_start, "-", dtb_addr, NULL
> +		};
> +		if (!dtb)
> +			bootm_argv[3] = env_get("fdtcontroladdr");
> +		else
> +			snprintf(dtb_addr, sizeof(dtb_addr) - 1,
> +				 "0x%x", dtb);
> +
> +		snprintf(boot_addr_start, sizeof(boot_addr_start) - 1,
> +			 "0x%x", uimage);
> +		printf("Booting kernel at %s - %s...\n\n\n",
> +		       boot_addr_start, bootm_argv[3]);
> +		/* Try bootm for legacy and FIT format image */
> +		if (genimg_get_format((void *)uimage) != IMAGE_FORMAT_INVALID)
> +			do_bootm(cmdtp, 0, 4, bootm_argv);
> +		else if CONFIG_IS_ENABLED(CMD_BOOTZ)
> +			do_bootz(cmdtp, 0, 4, bootm_argv);
> +	}
> +
>  	if (reset) {
>  		puts("Reset...\n");
>  		run_command("reset", 0);
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> index 0967bbc11a..cc303214cf 100644
> --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
> @@ -272,6 +272,9 @@ static int parse_ip(struct stm32prog_data *data,
>  	} else if (!strncmp(p, "spi-nand", 8)) {
>  		part->target = STM32PROG_SPI_NAND;
>  		len = 8;
> +	} else if (!strncmp(p, "ram", 3)) {
> +		part->target = STM32PROG_RAM;
> +		len = 0;
>  	} else {
>  		result = -EINVAL;
>  	}
> @@ -610,6 +613,11 @@ static int init_device(struct stm32prog_data *data,
>  		dev->mtd = mtd;
>  		break;
>  #endif
> +	case STM32PROG_RAM:
> +		first_addr = gd->bd->bi_dram[0].start;
> +		last_addr = first_addr + gd->bd->bi_dram[0].size;
> +		dev->erase_size = 1;
> +		break;
>  	default:
>  		stm32prog_err("unknown device type = %d", dev->target);
>  		return -ENODEV;
> @@ -1022,7 +1030,11 @@ static int stm32prog_alt_add(struct stm32prog_data *data,
>  			  part->name, part->id,
>  			  size, multiplier, type);
>  
> -	if (part->part_type == RAW_IMAGE) {
> +	if (part->target == STM32PROG_RAM) {
> +		offset += snprintf(buf + offset, ALT_BUF_LEN - offset,
> +				   "ram 0x%llx 0x%llx",
> +				   part->addr, part->size);
> +	} else if (part->part_type == RAW_IMAGE) {
>  		u64 dfu_size;
>  
>  		if (part->dev->target == STM32PROG_MMC)
> @@ -1073,6 +1085,10 @@ static int stm32prog_alt_add(struct stm32prog_data *data,
>  		get_mtd_by_target(devstr, part->target, part->dev_id);
>  		break;
>  #endif
> +	case STM32PROG_RAM:
> +		sprintf(dfustr, "ram");
> +		sprintf(devstr, "0");
> +		break;
>  	default:
>  		stm32prog_err("invalid target: %d", part->target);
>  		return -ENODEV;
> @@ -1440,6 +1456,13 @@ static void stm32prog_end_phase(struct stm32prog_data *data)
>  	if (!data->cur_part)
>  		return;
>  
> +	if (data->cur_part->target == STM32PROG_RAM) {
> +		if (data->cur_part->part_type == PART_SYSTEM)
> +			data->uimage = data->cur_part->addr;
> +		if (data->cur_part->part_type == PART_FILESYSTEM)
> +			data->dtb = data->cur_part->addr;
> +	}
> +
>  	if (CONFIG_IS_ENABLED(MMC) &&
>  	    data->cur_part->part_id < 0) {
>  		char cmdbuf[60];
> @@ -1569,6 +1592,10 @@ static int part_delete(struct stm32prog_data *data,
>  		}
>  		break;
>  #endif
> +	case STM32PROG_RAM:
> +		printf("on ram: ");
> +		memset((void *)(uintptr_t)part->addr, 0, (size_t)part->size);
> +		break;
>  	default:
>  		ret = -1;
>  		stm32prog_err("%s (0x%x): erase invalid", part->name, part->id);
> diff --git a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
> index c4fdb5b8c3..bae4e91c01 100644
> --- a/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
> +++ b/arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
> @@ -27,7 +27,8 @@ enum stm32prog_target {
>  	STM32PROG_MMC,
>  	STM32PROG_NAND,
>  	STM32PROG_NOR,
> -	STM32PROG_SPI_NAND
> +	STM32PROG_SPI_NAND,
> +	STM32PROG_RAM
>  };
>  
>  enum stm32prog_link_t {
> @@ -136,6 +137,10 @@ struct stm32prog_data {
>  	u8	*buffer; /* size = USART_RAM_BUFFER_SIZE*/
>  	int	dfu_seq;
>  	u8	read_phase;
> +
> +	/* bootm information */
> +	u32	uimage;
> +	u32	dtb;
>  };
>  
>  extern struct stm32prog_data *stm32prog_data;

Reviewed-by: Patrice Chotard <patrice.chotard@st.com>

Thanks

Patrice

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH 00/18] stm32mp1: add command stm32prog
  2020-03-18  8:24 [PATCH 00/18] stm32mp1: add command stm32prog Patrick Delaunay
                   ` (17 preceding siblings ...)
  2020-03-18  8:25 ` [PATCH 18/18] stm32mp: stm32prog: add support of RAM target Patrick Delaunay
@ 2020-05-14  9:28 ` Patrick DELAUNAY
  18 siblings, 0 replies; 40+ messages in thread
From: Patrick DELAUNAY @ 2020-05-14  9:28 UTC (permalink / raw)
  To: u-boot

Hi,

> From: Patrick DELAUNAY <patrick.delaunay@st.com>
> Sent: mercredi 18 mars 2020 09:25
> 
> 
> Add a specific command stm32prog for STM32MP soc family witch allows to
> update the devices on the board with the STMicroelectronics tool
> STM32CubeProgrammer (http://www.st.com/STM32CubeProg).
> 
> This command use the same UART STM32 protocol than MCU STM32 with or
> USB with DFU protocol v1.1 (MCU ST extension are no supported).
> 
> The executed actions are based on a tab separated value file with a stm32 header
> (see https://wiki.st.com/stm32mpu/wiki/STM32CubeProgrammer_flashlayout).
> 
> This FlashLayout file is loaded in DDR by TF-A during during a serial boot or in a
> virtual device by stm32prog command and is parsed by U-Boot (see "AN5275:
> USB DFU/USART protocols used in STM32MP1 Series bootloaders" for details).
> 
> Regards
> Patrick
> 
> 
> 
> Patrick Delaunay (18):
>   usb: gadget: g_dnl: add function g_dnl_set_product
>   dfu: add prototype for dfu_transaction_initiate/cleanup
>   stm32mp: add function get_cpu_dev
>   stm32mp: add the command stm32prog
>   stm32mp: stm32prog: add flash layout parsing
>   stm32mp: stm32prog: add MMC device
>   stm32mp: stm32prog: add support of boot partition for eMMC device
>   stm32mp: stm32prog: add upport of partial update
>   stm32mp: stm32prog: add MTD devices support
>   stm32mp: stm32prog: adapt the MTD partitions
>   stm32mp: stm32prog: add support of ssbl copy
>   stm32mp: stm32prog: add support for delete option in flashlayout
>   stm32mp: stm32prog: add otp update support
>   stm32mp: stm32prog: add pmic NVM update support
>   stm32mp: stm32prog: add serial link support
>   stm32mp: stm32prog: enable videoconsole
>   stm32mp: stm32prog: support for script
>   stm32mp: stm32prog: add support of RAM target
> 
>  arch/arm/mach-stm32mp/Kconfig                 |   17 +
>  arch/arm/mach-stm32mp/Makefile                |    1 +
>  arch/arm/mach-stm32mp/cmd_stm32prog/Makefile  |    9 +
>  .../cmd_stm32prog/cmd_stm32prog.c             |  192 ++
>  .../mach-stm32mp/cmd_stm32prog/stm32prog.c    | 1745 +++++++++++++++++
>  .../mach-stm32mp/cmd_stm32prog/stm32prog.h    |  185 ++
>  .../cmd_stm32prog/stm32prog_serial.c          |  993 ++++++++++
>  .../cmd_stm32prog/stm32prog_usb.c             |  230 +++
>  arch/arm/mach-stm32mp/cpu.c                   |   11 +-
>  .../arm/mach-stm32mp/include/mach/stm32prog.h |   16 +
>  .../arm/mach-stm32mp/include/mach/sys_proto.h |    5 +
>  board/st/common/stm32mp_dfu.c                 |   20 +
>  board/st/common/stm32mp_mtdparts.c            |   14 +-
>  configs/stm32mp15_basic_defconfig             |    7 +-
>  configs/stm32mp15_trusted_defconfig           |    7 +-
>  drivers/usb/gadget/g_dnl.c                    |    8 +
>  include/dfu.h                                 |    3 +
>  include/g_dnl.h                               |    1 +
>  18 files changed, 3445 insertions(+), 19 deletions(-)  create mode 100644
> arch/arm/mach-stm32mp/cmd_stm32prog/Makefile
>  create mode 100644 arch/arm/mach-stm32mp/cmd_stm32prog/cmd_stm32prog.c
>  create mode 100644 arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.c
>  create mode 100644 arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog.h
>  create mode 100644 arch/arm/mach-
> stm32mp/cmd_stm32prog/stm32prog_serial.c
>  create mode 100644 arch/arm/mach-stm32mp/cmd_stm32prog/stm32prog_usb.c
>  create mode 100644 arch/arm/mach-stm32mp/include/mach/stm32prog.h
> 
> --
> 2.17.1

For the serie: applied to u-boot-stm/master, thanks!

Regards

Patrick

^ permalink raw reply	[flat|nested] 40+ messages in thread

end of thread, other threads:[~2020-05-14  9:28 UTC | newest]

Thread overview: 40+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-03-18  8:24 [PATCH 00/18] stm32mp1: add command stm32prog Patrick Delaunay
2020-03-18  8:24 ` [PATCH 01/18] usb: gadget: g_dnl: add function g_dnl_set_product Patrick Delaunay
2020-04-14 12:57   ` [Uboot-stm32] " Patrice CHOTARD
2020-03-18  8:24 ` [PATCH 02/18] dfu: add prototype for dfu_transaction_initiate/cleanup Patrick Delaunay
2020-04-14 12:58   ` [Uboot-stm32] " Patrice CHOTARD
2020-03-18  8:24 ` [PATCH 03/18] stm32mp: add function get_cpu_dev Patrick Delaunay
2020-04-14 12:59   ` Patrice CHOTARD
2020-03-18  8:24 ` [PATCH 04/18] stm32mp: add the command stm32prog Patrick Delaunay
2020-04-14 13:00   ` Patrice CHOTARD
2020-04-14 13:03   ` Patrice CHOTARD
2020-03-18  8:24 ` [PATCH 05/18] stm32mp: stm32prog: add flash layout parsing Patrick Delaunay
2020-04-14 13:03   ` Patrice CHOTARD
2020-03-18  8:24 ` [PATCH 06/18] stm32mp: stm32prog: add MMC device Patrick Delaunay
2020-04-14 13:04   ` Patrice CHOTARD
2020-04-14 13:04   ` Patrice CHOTARD
2020-03-18  8:24 ` [PATCH 07/18] stm32mp: stm32prog: add support of boot partition for eMMC device Patrick Delaunay
2020-04-14 13:05   ` Patrice CHOTARD
2020-03-18  8:24 ` [PATCH 08/18] stm32mp: stm32prog: add upport of partial update Patrick Delaunay
2020-04-14 13:05   ` Patrice CHOTARD
2020-03-18  8:24 ` [PATCH 09/18] stm32mp: stm32prog: add MTD devices support Patrick Delaunay
2020-04-14 13:06   ` Patrice CHOTARD
2020-03-18  8:24 ` [PATCH 10/18] stm32mp: stm32prog: adapt the MTD partitions Patrick Delaunay
2020-04-14 13:07   ` Patrice CHOTARD
2020-03-18  8:24 ` [PATCH 11/18] stm32mp: stm32prog: add support of ssbl copy Patrick Delaunay
2020-04-14 13:07   ` Patrice CHOTARD
2020-03-18  8:24 ` [PATCH 12/18] stm32mp: stm32prog: add support for delete option in flashlayout Patrick Delaunay
2020-04-14 13:08   ` Patrice CHOTARD
2020-03-18  8:24 ` [PATCH 13/18] stm32mp: stm32prog: add otp update support Patrick Delaunay
2020-04-14 13:09   ` Patrice CHOTARD
2020-03-18  8:24 ` [PATCH 14/18] stm32mp: stm32prog: add pmic NVM " Patrick Delaunay
2020-04-14 13:09   ` Patrice CHOTARD
2020-03-18  8:25 ` [PATCH 15/18] stm32mp: stm32prog: add serial link support Patrick Delaunay
2020-04-14 13:10   ` Patrice CHOTARD
2020-03-18  8:25 ` [PATCH 16/18] stm32mp: stm32prog: enable videoconsole Patrick Delaunay
2020-04-14 13:11   ` Patrice CHOTARD
2020-03-18  8:25 ` [PATCH 17/18] stm32mp: stm32prog: support for script Patrick Delaunay
2020-04-14 13:11   ` Patrice CHOTARD
2020-03-18  8:25 ` [PATCH 18/18] stm32mp: stm32prog: add support of RAM target Patrick Delaunay
2020-04-14 13:11   ` Patrice CHOTARD
2020-05-14  9:28 ` [PATCH 00/18] stm32mp1: add command stm32prog Patrick DELAUNAY

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.