diff mbox series

[U-Boot,RFC,04/14] dfu: allow to manage DFU on several devices

Message ID 1563541046-6432-5-git-send-email-patrick.delaunay@st.com
State Superseded
Delegated to: Patrick Delaunay
Headers show
Series dfu: update dfu stack and use them for stm32mp1 | expand

Commit Message

Patrick DELAUNAY July 19, 2019, 12:57 p.m. UTC
Add support of DFU for several interface/device
with one command.

The format for "dfu_alt_info" in this case is :
  interface with devstring'='alternate list (';' separated)
  and each interface is separated by '&'

The previous behavior is always supported.

One example for NOR (bootloaders) + NAND (rootfs in UBI):

U-Boot> env set dfu_alt_info \
"sf 0:0:10000000:0=spl part 0 1;u-boot part 0 2; \
u-boot-env part 0 3&nand 0=UBI partubi 0,3"

U-Boot> dfu 0 list

DFU alt settings list:
dev: SF alt: 0 name: spl layout: RAW_ADDR
dev: SF alt: 1 name: ssbl layout: RAW_ADDR
dev: SF alt: 2 name: u-boot-env layout: RAW_ADDR
dev: NAND alt: 3 name: UBI layout: RAW_ADDR

U-Boot> dfu 0

$> dfu-util -l

Found DFU: [0483:5720] ver=9999, devnum=96, cfg=1, intf=0, alt=3, name="UBI", serial="002700333338511934383330"
Found DFU: [0483:5720] ver=9999, devnum=96, cfg=1, intf=0, alt=2, name="u-boot-env", serial="002700333338511934383330"
Found DFU: [0483:5720] ver=9999, devnum=96, cfg=1, intf=0, alt=1, name="u-boot", serial="002700333338511934383330"
Found DFU: [0483:5720] ver=9999, devnum=96, cfg=1, intf=0, alt=0, name="spl", serial="002700333338511934383330"

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

 cmd/dfu.c         | 21 +++++++++++--------
 drivers/dfu/dfu.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 72 insertions(+), 9 deletions(-)

Comments

Lukasz Majewski July 22, 2019, 8:04 a.m. UTC | #1
Hi Patrick,

> Add support of DFU for several interface/device
> with one command.
> 
> The format for "dfu_alt_info" in this case is :
>   interface with devstring'='alternate list (';' separated)
>   and each interface is separated by '&'
> 
> The previous behavior is always supported.

Good.

> 
> One example for NOR (bootloaders) + NAND (rootfs in UBI):
> 
> U-Boot> env set dfu_alt_info \
> "sf 0:0:10000000:0=spl part 0 1;u-boot part 0 2; \
> u-boot-env part 0 3&nand 0=UBI partubi 0,3"
> 
> U-Boot> dfu 0 list
> 
> DFU alt settings list:
> dev: SF alt: 0 name: spl layout: RAW_ADDR
> dev: SF alt: 1 name: ssbl layout: RAW_ADDR
> dev: SF alt: 2 name: u-boot-env layout: RAW_ADDR
> dev: NAND alt: 3 name: UBI layout: RAW_ADDR
> 
> U-Boot> dfu 0
> 
> $> dfu-util -l  
> 
> Found DFU: [0483:5720] ver=9999, devnum=96, cfg=1, intf=0, alt=3,
> name="UBI", serial="002700333338511934383330" Found DFU: [0483:5720]
> ver=9999, devnum=96, cfg=1, intf=0, alt=2, name="u-boot-env",
> serial="002700333338511934383330" Found DFU: [0483:5720] ver=9999,
> devnum=96, cfg=1, intf=0, alt=1, name="u-boot",
> serial="002700333338511934383330" Found DFU: [0483:5720] ver=9999,
> devnum=96, cfg=1, intf=0, alt=0, name="spl",
> serial="002700333338511934383330"
> 

Please add this info (with above example usage) to ./doc/README.dfu (in
a similar way as I did it some time ago for ./doc/README.dfutftp).

I also think that it would be beneficial for the community to add a
separate entry (in this file) for the description of ST's way to
program their platform with this code.

(I mean simple howto for people who would like to start playing around
with ST & U-Boot & DFU).

> Signed-off-by: Patrick Delaunay <patrick.delaunay@st.com>
> ---
> 
>  cmd/dfu.c         | 21 +++++++++++--------
>  drivers/dfu/dfu.c | 60
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files
> changed, 72 insertions(+), 9 deletions(-)
> 
> diff --git a/cmd/dfu.c b/cmd/dfu.c
> index 91a750a..33491d0 100644
> --- a/cmd/dfu.c
> +++ b/cmd/dfu.c
> @@ -21,23 +21,28 @@
>  static int do_dfu(cmd_tbl_t *cmdtp, int flag, int argc, char * const
> argv[]) {
>  
> -	if (argc < 4)
> +	if (argc < 2)
>  		return CMD_RET_USAGE;
>  
>  #ifdef CONFIG_DFU_OVER_USB
>  	char *usb_controller = argv[1];
>  #endif
>  #if defined(CONFIG_DFU_OVER_USB) || defined(CONFIG_DFU_OVER_TFTP)
> -	char *interface = argv[2];
> -	char *devstring = argv[3];
> +	char *interface = NULL;
> +	char *devstring = NULL;
> +
> +	if (argc >= 4) {
> +		interface = argv[2];
> +		devstring = argv[3];
> +	}
>  #endif
>  
>  	int ret = 0;
>  #ifdef CONFIG_DFU_OVER_TFTP
>  	unsigned long addr = 0;
>  	if (!strcmp(argv[1], "tftp")) {
> -		if (argc == 5)
> -			addr = simple_strtoul(argv[4], NULL, 0);
> +		if (argc == 5 || argc == 3)
> +			addr = simple_strtoul(argv[argc - 1], NULL,
> 0); 
>  		return update_tftp(addr, interface, devstring);
>  	}
> @@ -48,7 +53,7 @@ static int do_dfu(cmd_tbl_t *cmdtp, int flag, int
> argc, char * const argv[]) goto done;
>  
>  	ret = CMD_RET_SUCCESS;
> -	if (argc > 4 && strcmp(argv[4], "list") == 0) {
> +	if (strcmp(argv[argc - 1], "list") == 0) {
>  		dfu_show_entities();
>  		goto done;
>  	}
> @@ -67,7 +72,7 @@ U_BOOT_CMD(dfu, CONFIG_SYS_MAXARGS, 1, do_dfu,
>  	"Device Firmware Upgrade",
>  	""
>  #ifdef CONFIG_DFU_OVER_USB
> -	"<USB_controller> <interface> <dev> [list]\n"
> +	"<USB_controller> [<interface> <dev>] [list]\n"
>  	"  - device firmware upgrade via <USB_controller>\n"
>  	"    on device <dev>, attached to interface\n"
>  	"    <interface>\n"
> @@ -77,7 +82,7 @@ U_BOOT_CMD(dfu, CONFIG_SYS_MAXARGS, 1, do_dfu,
>  #ifdef CONFIG_DFU_OVER_USB
>  	"dfu "
>  #endif
> -	"tftp <interface> <dev> [<addr>]\n"
> +	"tftp [<interface> <dev>] [<addr>]\n"
>  	"  - device firmware upgrade via TFTP\n"
>  	"    on device <dev>, attached to interface\n"
>  	"    <interface>\n"
> diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c
> index 79a652e..01ec690 100644
> --- a/drivers/dfu/dfu.c
> +++ b/drivers/dfu/dfu.c
> @@ -52,6 +52,54 @@ static int dfu_find_alt_num(const char *s)
>  	return ++i;
>  }
>  
> +/*
> + * treat dfu_alt_info with several interface information
> + * to allow DFU on several device with one command,
> + * the string format is
> + * interface devstring'='alternate list (';' separated)
> + * and each interface separated by '&'
> + */
> +int dfu_config_interfaces(char *env)
> +{
> +	struct dfu_entity *dfu;
> +	char *s, *i, *d, *a, *part;
> +	int ret = -EINVAL;
> +	int n = 1;
> +
> +	s = env;
> +	for (; *s; s++) {
> +		if (*s == ';')
> +			n++;
> +		if (*s == '&')
> +			n++;
> +	}
> +	ret = dfu_alt_init(n, &dfu);
> +	if (ret)
> +		return ret;
> +
> +	s = env;
> +	while (s) {
> +		ret = -EINVAL;
> +		i = strsep(&s, " ");
> +		if (!i)
> +			break;
> +		d = strsep(&s, "=");
> +		if (!d)
> +			break;
> +		a = strsep(&s, "&");
> +		if (!a)
> +			a = s;
> +		do {
> +			part = strsep(&a, ";");
> +			ret = dfu_alt_add(dfu, i, d, part);
> +			if (ret)
> +				return ret;
> +		} while (a);
> +	}
> +
> +	return ret;
> +}
> +
>  int dfu_init_env_entities(char *interface, char *devstr)
>  {
>  	const char *str_env;
> @@ -68,7 +116,11 @@ int dfu_init_env_entities(char *interface, char
> *devstr) }
>  
>  	env_bkp = strdup(str_env);
> -	ret = dfu_config_entities(env_bkp, interface, devstr);
> +	if (!interface && !devstr)
> +		ret = dfu_config_interfaces(env_bkp);
> +	else
> +		ret = dfu_config_entities(env_bkp, interface,
> devstr); +
>  	if (ret) {
>  		pr_err("DFU entities configuration failed!\n");
>  		pr_err("(partition table does not match
> dfu_alt_info?)\n"); @@ -82,6 +134,7 @@ done:
>  
>  static unsigned char *dfu_buf;
>  static unsigned long dfu_buf_size;
> +static enum dfu_device_type dfu_buf_device_type;
>  
>  unsigned char *dfu_free_buf(void)
>  {
> @@ -99,6 +152,10 @@ unsigned char *dfu_get_buf(struct dfu_entity *dfu)
>  {
>  	char *s;
>  
> +	/* manage several entity with several contraint */
> +	if (dfu_buf && dfu->dev_type != dfu_buf_device_type)
> +		dfu_free_buf();
> +
>  	if (dfu_buf != NULL)
>  		return dfu_buf;
>  
> @@ -117,6 +174,7 @@ unsigned char *dfu_get_buf(struct dfu_entity *dfu)
>  		printf("%s: Could not memalign 0x%lx bytes\n",
>  		       __func__, dfu_buf_size);
>  
> +	dfu_buf_device_type = dfu->dev_type;
>  	return dfu_buf;
>  }
>  




Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-59 Fax: (+49)-8142-66989-80 Email: lukma@denx.de
diff mbox series

Patch

diff --git a/cmd/dfu.c b/cmd/dfu.c
index 91a750a..33491d0 100644
--- a/cmd/dfu.c
+++ b/cmd/dfu.c
@@ -21,23 +21,28 @@ 
 static int do_dfu(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
 
-	if (argc < 4)
+	if (argc < 2)
 		return CMD_RET_USAGE;
 
 #ifdef CONFIG_DFU_OVER_USB
 	char *usb_controller = argv[1];
 #endif
 #if defined(CONFIG_DFU_OVER_USB) || defined(CONFIG_DFU_OVER_TFTP)
-	char *interface = argv[2];
-	char *devstring = argv[3];
+	char *interface = NULL;
+	char *devstring = NULL;
+
+	if (argc >= 4) {
+		interface = argv[2];
+		devstring = argv[3];
+	}
 #endif
 
 	int ret = 0;
 #ifdef CONFIG_DFU_OVER_TFTP
 	unsigned long addr = 0;
 	if (!strcmp(argv[1], "tftp")) {
-		if (argc == 5)
-			addr = simple_strtoul(argv[4], NULL, 0);
+		if (argc == 5 || argc == 3)
+			addr = simple_strtoul(argv[argc - 1], NULL, 0);
 
 		return update_tftp(addr, interface, devstring);
 	}
@@ -48,7 +53,7 @@  static int do_dfu(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 		goto done;
 
 	ret = CMD_RET_SUCCESS;
-	if (argc > 4 && strcmp(argv[4], "list") == 0) {
+	if (strcmp(argv[argc - 1], "list") == 0) {
 		dfu_show_entities();
 		goto done;
 	}
@@ -67,7 +72,7 @@  U_BOOT_CMD(dfu, CONFIG_SYS_MAXARGS, 1, do_dfu,
 	"Device Firmware Upgrade",
 	""
 #ifdef CONFIG_DFU_OVER_USB
-	"<USB_controller> <interface> <dev> [list]\n"
+	"<USB_controller> [<interface> <dev>] [list]\n"
 	"  - device firmware upgrade via <USB_controller>\n"
 	"    on device <dev>, attached to interface\n"
 	"    <interface>\n"
@@ -77,7 +82,7 @@  U_BOOT_CMD(dfu, CONFIG_SYS_MAXARGS, 1, do_dfu,
 #ifdef CONFIG_DFU_OVER_USB
 	"dfu "
 #endif
-	"tftp <interface> <dev> [<addr>]\n"
+	"tftp [<interface> <dev>] [<addr>]\n"
 	"  - device firmware upgrade via TFTP\n"
 	"    on device <dev>, attached to interface\n"
 	"    <interface>\n"
diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c
index 79a652e..01ec690 100644
--- a/drivers/dfu/dfu.c
+++ b/drivers/dfu/dfu.c
@@ -52,6 +52,54 @@  static int dfu_find_alt_num(const char *s)
 	return ++i;
 }
 
+/*
+ * treat dfu_alt_info with several interface information
+ * to allow DFU on several device with one command,
+ * the string format is
+ * interface devstring'='alternate list (';' separated)
+ * and each interface separated by '&'
+ */
+int dfu_config_interfaces(char *env)
+{
+	struct dfu_entity *dfu;
+	char *s, *i, *d, *a, *part;
+	int ret = -EINVAL;
+	int n = 1;
+
+	s = env;
+	for (; *s; s++) {
+		if (*s == ';')
+			n++;
+		if (*s == '&')
+			n++;
+	}
+	ret = dfu_alt_init(n, &dfu);
+	if (ret)
+		return ret;
+
+	s = env;
+	while (s) {
+		ret = -EINVAL;
+		i = strsep(&s, " ");
+		if (!i)
+			break;
+		d = strsep(&s, "=");
+		if (!d)
+			break;
+		a = strsep(&s, "&");
+		if (!a)
+			a = s;
+		do {
+			part = strsep(&a, ";");
+			ret = dfu_alt_add(dfu, i, d, part);
+			if (ret)
+				return ret;
+		} while (a);
+	}
+
+	return ret;
+}
+
 int dfu_init_env_entities(char *interface, char *devstr)
 {
 	const char *str_env;
@@ -68,7 +116,11 @@  int dfu_init_env_entities(char *interface, char *devstr)
 	}
 
 	env_bkp = strdup(str_env);
-	ret = dfu_config_entities(env_bkp, interface, devstr);
+	if (!interface && !devstr)
+		ret = dfu_config_interfaces(env_bkp);
+	else
+		ret = dfu_config_entities(env_bkp, interface, devstr);
+
 	if (ret) {
 		pr_err("DFU entities configuration failed!\n");
 		pr_err("(partition table does not match dfu_alt_info?)\n");
@@ -82,6 +134,7 @@  done:
 
 static unsigned char *dfu_buf;
 static unsigned long dfu_buf_size;
+static enum dfu_device_type dfu_buf_device_type;
 
 unsigned char *dfu_free_buf(void)
 {
@@ -99,6 +152,10 @@  unsigned char *dfu_get_buf(struct dfu_entity *dfu)
 {
 	char *s;
 
+	/* manage several entity with several contraint */
+	if (dfu_buf && dfu->dev_type != dfu_buf_device_type)
+		dfu_free_buf();
+
 	if (dfu_buf != NULL)
 		return dfu_buf;
 
@@ -117,6 +174,7 @@  unsigned char *dfu_get_buf(struct dfu_entity *dfu)
 		printf("%s: Could not memalign 0x%lx bytes\n",
 		       __func__, dfu_buf_size);
 
+	dfu_buf_device_type = dfu->dev_type;
 	return dfu_buf;
 }