[PATCH v2 0/5] DFU: new entity types and minor improvements

Hi All,
This patchset adds support for SKIP and SCRIPT entity types to the DFU subsystem. They significantly extends the flexibility of the storage flashing commands. Together with the recently posted 'Add MBR partition table creation and verify command' patchset and proper script it allows to create the whole partition table during the board flashing. It also easies the flashing by allowing to use the same images for different board variants/types, as each board can now use only the relevant images and skip the other ones without returning a failure.
Best regards Marek Szyprowski Samsung R&D Institute Poland
Changelog: v2: - updated the "dfu: add 'SKIP' entity" patch to the latest version - added 'SCRIPT' DFU entity docs
v1: https://lists.denx.de/pipermail/u-boot/2020-December/435214.html - initial version
Patch summary:
Jaehoon Chung (1): dfu: add 'SKIP' entity
Marek Szyprowski (4): dfu: mmc: use the default MMC device if entity specifies it as -1 dfu: add 'SCRIPT' entity dfu: add support for the dfu_alt_info reintialization from the flashed script thor: add support for the dfu_alt_info reintialization from the flashed script
cmd/dfu.c | 14 ++++++++++++- cmd/thordown.c | 19 +++++++++++------- common/dfu.c | 3 +++ doc/README.dfu | 30 +++++++++++++++++++++++++++- drivers/dfu/dfu.c | 7 ++++++- drivers/dfu/dfu_mmc.c | 39 ++++++++++++++++++++++++++++++++----- drivers/usb/gadget/f_thor.c | 3 +++ include/dfu.h | 4 ++++ include/thor.h | 2 ++ 9 files changed, 106 insertions(+), 15 deletions(-)

Use the default MMC device set in the command line if entity specifies it as -1. This allows to use the same dfu_alt_info string for different MMC devices (like embedded eMMC and external SD card if data layout is the same on both devices).
Signed-off-by: Marek Szyprowski m.szyprowski@samsung.com --- drivers/dfu/dfu_mmc.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/dfu/dfu_mmc.c b/drivers/dfu/dfu_mmc.c index 691d01c7eb..784d0ec76b 100644 --- a/drivers/dfu/dfu_mmc.c +++ b/drivers/dfu/dfu_mmc.c @@ -316,7 +316,7 @@ void dfu_free_entity_mmc(struct dfu_entity *dfu) int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *devstr, char *s) { const char *entity_type; - size_t second_arg; + ssize_t second_arg; size_t third_arg;
struct mmc *mmc; @@ -339,7 +339,7 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *devstr, char *s) * Base 0 means we'll accept (prefixed with 0x or 0) base 16, 8, * with default 10. */ - second_arg = simple_strtoul(argv[1], NULL, 0); + second_arg = simple_strtol(argv[1], NULL, 0); third_arg = simple_strtoul(argv[2], NULL, 0);
mmc = find_mmc_device(dfu->data.mmc.dev_num); @@ -406,7 +406,8 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *devstr, char *s)
/* if it's NOT a raw write */ if (strcmp(entity_type, "raw")) { - dfu->data.mmc.dev = second_arg; + dfu->data.mmc.dev = (second_arg != -1) ? second_arg : + dfu->data.mmc.dev_num; dfu->data.mmc.part = third_arg; }

From: Jaehoon Chung jh80.chung@samsung.com
Define a new 'SKIP' type for the DFU entities. The flashed data for that entity is simply ignored without returning any error values.
This allows to have one flashing procedure and images for the different board types or variants, where each board uses only the images relevant to it and skips the rest. This is especially usefull for the THOR protocol, which usually transfers more than one file in a single session.
Signed-off-by: Jaehoon Chung jh80.chung@samsung.com Reviewed-by: Minkyu Kang mk7.kang@samsung.com [mszyprow: rephrased commit message and docs for easier reading, changed subject to "dfu: add 'SKIP' entity"] Signed-off-by: Marek Szyprowski m.szyprowski@samsung.com --- Original version of this patch is available here: https://patchwork.ozlabs.org/project/uboot/patch/20201109115757.24601-1-jh80... --- doc/README.dfu | 15 ++++++++++++++- drivers/dfu/dfu.c | 2 +- drivers/dfu/dfu_mmc.c | 9 +++++++++ include/dfu.h | 1 + 4 files changed, 25 insertions(+), 2 deletions(-)
diff --git a/doc/README.dfu b/doc/README.dfu index be53b5b393..6cb1cba9d7 100644 --- a/doc/README.dfu +++ b/doc/README.dfu @@ -17,7 +17,7 @@ Overview: - The access to mediums is done in DFU backends (driver/dfu)
Today the supported DFU backends are: - - MMC (RAW or FAT / EXT2 / EXT3 / EXT4 file system) + - MMC (RAW or FAT / EXT2 / EXT3 / EXT4 file system / SKIP) - NAND - RAM - SF (serial flash) @@ -91,6 +91,7 @@ Commands: <name> part <dev> <part_id> [mmcpart <num>] raw access to partition <name> fat <dev> <part_id> [mmcpart <num>] file in FAT partition <name> ext4 <dev> <part_id> [mmcpart <num>] file in EXT4 partition + <name> skip 0 0 ignore flashed data
with <partid> being the GPT or DOS partition index, with <num> being the eMMC hardware partition number. @@ -103,6 +104,18 @@ Commands:
"u-boot raw 0x80 0x800;uImage ext4 0 2"
+ If don't want to flash given image file to storage, use "skip" type + entity. + - It can be used to protect flashing wrong image for the specific board. + - Especailly, this layout will be useful when thor protocol is used, + which performs flashing in batch mode, where more than one file is + processed. + For example, if one makes a single tar file with support for the two + boards with u-boot-<board1>.bin and u-boot-<board2>.bin files, one + can use it to flash a proper u-boot image on both without a failure: + + "u-boot-<board1>.bin raw 0x80 0x800; u-boot-<board2>.bin skip 0 0" + "nand" (raw slc nand device) cmd: dfu 0 nand <dev> each element in "dfu_alt_info" = diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c index 501a60b344..fc32a53323 100644 --- a/drivers/dfu/dfu.c +++ b/drivers/dfu/dfu.c @@ -614,7 +614,7 @@ const char *dfu_get_dev_type(enum dfu_device_type t) const char *dfu_get_layout(enum dfu_layout l) { const char *const dfu_layout[] = {NULL, "RAW_ADDR", "FAT", "EXT2", - "EXT3", "EXT4", "RAM_ADDR" }; + "EXT3", "EXT4", "RAM_ADDR", "SKIP" }; return dfu_layout[l]; }
diff --git a/drivers/dfu/dfu_mmc.c b/drivers/dfu/dfu_mmc.c index 784d0ec76b..d1af11d94c 100644 --- a/drivers/dfu/dfu_mmc.c +++ b/drivers/dfu/dfu_mmc.c @@ -108,6 +108,8 @@ static int mmc_file_op(enum dfu_op op, struct dfu_entity *dfu, case DFU_FS_EXT4: fstype = FS_TYPE_EXT; break; + case DFU_SKIP: + return 0; default: printf("%s: Layout (%s) not (yet) supported!\n", __func__, dfu_get_layout(dfu->layout)); @@ -204,6 +206,9 @@ int dfu_write_medium_mmc(struct dfu_entity *dfu, case DFU_FS_EXT4: ret = mmc_file_buf_write(dfu, offset, buf, len); break; + case DFU_SKIP: + ret = 0; + break; default: printf("%s: Layout (%s) not (yet) supported!\n", __func__, dfu_get_layout(dfu->layout)); @@ -238,6 +243,8 @@ int dfu_get_medium_size_mmc(struct dfu_entity *dfu, u64 *size) if (ret < 0) return ret; return 0; + case DFU_SKIP: + return 0; default: printf("%s: Layout (%s) not (yet) supported!\n", __func__, dfu_get_layout(dfu->layout)); @@ -399,6 +406,8 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *devstr, char *s) dfu->layout = DFU_FS_FAT; } else if (!strcmp(entity_type, "ext4")) { dfu->layout = DFU_FS_EXT4; + } else if (!strcmp(entity_type, "skip")) { + dfu->layout = DFU_SKIP; } else { pr_err("Memory layout (%s) not supported!\n", entity_type); return -ENODEV; diff --git a/include/dfu.h b/include/dfu.h index a767adee41..0b1dae0b3b 100644 --- a/include/dfu.h +++ b/include/dfu.h @@ -33,6 +33,7 @@ enum dfu_layout { DFU_FS_EXT3, DFU_FS_EXT4, DFU_RAM_ADDR, + DFU_SKIP, };
enum dfu_op {

Define a new 'SCRIPT' type for DFU entities. The downloaded data are treated as simple u-boot's scripts and executed with run_command_list() function.
Flashing the 'SCRIPT' entity might result in changing the 'dfu_alt_info' environment variable from the flashed script, so add a global variable for tracking the potential need to reinitialize the dfu_alt_info related structures.
Signed-off-by: Marek Szyprowski m.szyprowski@samsung.com --- doc/README.dfu | 17 ++++++++++++++++- drivers/dfu/dfu.c | 7 ++++++- drivers/dfu/dfu_mmc.c | 23 +++++++++++++++++++++-- include/dfu.h | 3 +++ 4 files changed, 46 insertions(+), 4 deletions(-)
diff --git a/doc/README.dfu b/doc/README.dfu index 6cb1cba9d7..eacd5bbfb4 100644 --- a/doc/README.dfu +++ b/doc/README.dfu @@ -17,7 +17,7 @@ Overview: - The access to mediums is done in DFU backends (driver/dfu)
Today the supported DFU backends are: - - MMC (RAW or FAT / EXT2 / EXT3 / EXT4 file system / SKIP) + - MMC (RAW or FAT / EXT2 / EXT3 / EXT4 file system / SKIP / SCRIPT) - NAND - RAM - SF (serial flash) @@ -92,6 +92,7 @@ Commands: <name> fat <dev> <part_id> [mmcpart <num>] file in FAT partition <name> ext4 <dev> <part_id> [mmcpart <num>] file in EXT4 partition <name> skip 0 0 ignore flashed data + <name> script 0 0 execute commands in shell
with <partid> being the GPT or DOS partition index, with <num> being the eMMC hardware partition number. @@ -116,6 +117,20 @@ Commands:
"u-boot-<board1>.bin raw 0x80 0x800; u-boot-<board2>.bin skip 0 0"
+ When flashing new system image requires do some more complex things + than just writing data to the storage medium, one can use 'script' + type. Data written to such entity will be executed as a command list + in the u-boot's shell. This for example allows to re-create partition + layout and even set new dfu_alt_info for the newly created paritions. + Such script would look like: + --->8--- + setenv dfu_alt_info ... + setenv mbr_parts ... + mbr write ... + --->8--- + Please note that this means that user will be able to execute any + arbitrary commands just like in the u-boot's shell. + "nand" (raw slc nand device) cmd: dfu 0 nand <dev> each element in "dfu_alt_info" = diff --git a/drivers/dfu/dfu.c b/drivers/dfu/dfu.c index fc32a53323..213a20e7bc 100644 --- a/drivers/dfu/dfu.c +++ b/drivers/dfu/dfu.c @@ -26,6 +26,8 @@ static struct hash_algo *dfu_hash_algo; static unsigned long dfu_timeout = 0; #endif
+bool dfu_reinit_needed = false; + /* * The purpose of the dfu_flush_callback() function is to * provide callback for dfu user @@ -139,6 +141,8 @@ int dfu_init_env_entities(char *interface, char *devstr) char *env_bkp; int ret = 0;
+ dfu_reinit_needed = false; + #ifdef CONFIG_SET_DFU_ALT_INFO set_dfu_alt_info(interface, devstr); #endif @@ -614,7 +618,8 @@ const char *dfu_get_dev_type(enum dfu_device_type t) const char *dfu_get_layout(enum dfu_layout l) { const char *const dfu_layout[] = {NULL, "RAW_ADDR", "FAT", "EXT2", - "EXT3", "EXT4", "RAM_ADDR", "SKIP" }; + "EXT3", "EXT4", "RAM_ADDR", "SKIP", + "SCRIPT" }; return dfu_layout[l]; }
diff --git a/drivers/dfu/dfu_mmc.c b/drivers/dfu/dfu_mmc.c index d1af11d94c..e63fa84ce4 100644 --- a/drivers/dfu/dfu_mmc.c +++ b/drivers/dfu/dfu_mmc.c @@ -16,6 +16,7 @@ #include <fat.h> #include <mmc.h> #include <part.h> +#include <command.h>
static unsigned char *dfu_file_buf; static u64 dfu_file_buf_len; @@ -206,6 +207,9 @@ int dfu_write_medium_mmc(struct dfu_entity *dfu, case DFU_FS_EXT4: ret = mmc_file_buf_write(dfu, offset, buf, len); break; + case DFU_SCRIPT: + ret = run_command_list(buf, *len, 0); + break; case DFU_SKIP: ret = 0; break; @@ -221,9 +225,21 @@ int dfu_flush_medium_mmc(struct dfu_entity *dfu) { int ret = 0;
- if (dfu->layout != DFU_RAW_ADDR) { - /* Do stuff here. */ + switch (dfu->layout) { + case DFU_FS_FAT: + case DFU_FS_EXT4: ret = mmc_file_buf_write_finish(dfu); + break; + case DFU_SCRIPT: + /* script may have changed the dfu_alt_info */ + dfu_reinit_needed = true; + break; + case DFU_RAW_ADDR: + case DFU_SKIP: + break; + default: + printf("%s: Layout (%s) not (yet) supported!\n", __func__, + dfu_get_layout(dfu->layout)); }
return ret; @@ -243,6 +259,7 @@ int dfu_get_medium_size_mmc(struct dfu_entity *dfu, u64 *size) if (ret < 0) return ret; return 0; + case DFU_SCRIPT: case DFU_SKIP: return 0; default: @@ -408,6 +425,8 @@ int dfu_fill_entity_mmc(struct dfu_entity *dfu, char *devstr, char *s) dfu->layout = DFU_FS_EXT4; } else if (!strcmp(entity_type, "skip")) { dfu->layout = DFU_SKIP; + } else if (!strcmp(entity_type, "script")) { + dfu->layout = DFU_SCRIPT; } else { pr_err("Memory layout (%s) not supported!\n", entity_type); return -ENODEV; diff --git a/include/dfu.h b/include/dfu.h index 0b1dae0b3b..d18b701728 100644 --- a/include/dfu.h +++ b/include/dfu.h @@ -34,6 +34,7 @@ enum dfu_layout { DFU_FS_EXT4, DFU_RAM_ADDR, DFU_SKIP, + DFU_SCRIPT, };
enum dfu_op { @@ -497,6 +498,8 @@ static inline int dfu_fill_entity_virt(struct dfu_entity *dfu, char *devstr, } #endif
+extern bool dfu_reinit_needed; + #if CONFIG_IS_ENABLED(DFU_WRITE_ALT) /** * dfu_write_by_name() - write data to DFU medium

Reinitialize DFU USB gadget after flashing the 'SCRIPT' entity to ensure that the potential changes to the 'dfu_alt_info' environment variable are applied.
Signed-off-by: Marek Szyprowski m.szyprowski@samsung.com --- cmd/dfu.c | 14 +++++++++++++- common/dfu.c | 3 +++ 2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/cmd/dfu.c b/cmd/dfu.c index 7310595a02..89b1b2268e 100644 --- a/cmd/dfu.c +++ b/cmd/dfu.c @@ -34,6 +34,7 @@ static int do_dfu(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) #if defined(CONFIG_DFU_TIMEOUT) || defined(CONFIG_DFU_OVER_TFTP) unsigned long value = 0; #endif + bool retry = false;
if (argc >= 4) { interface = argv[2]; @@ -68,7 +69,18 @@ static int do_dfu(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
int controller_index = simple_strtoul(usb_controller, NULL, 0);
- run_usb_dnl_gadget(controller_index, "usb_dnl_dfu"); + do { + retry = false; + run_usb_dnl_gadget(controller_index, "usb_dnl_dfu"); + + if (dfu_reinit_needed) { + dfu_free_entities(); + ret = dfu_init_env_entities(interface, devstring); + if (ret) + goto done; + retry = true; + } + } while (retry);
done: dfu_free_entities(); diff --git a/common/dfu.c b/common/dfu.c index d23cf67f19..16bd1ba588 100644 --- a/common/dfu.c +++ b/common/dfu.c @@ -98,6 +98,9 @@ int run_usb_dnl_gadget(int usbctrl_index, char *usb_dnl_gadget) } #endif
+ if (dfu_reinit_needed) + goto exit; + WATCHDOG_RESET(); usb_gadget_handle_interrupts(usbctrl_index); }

Reinitialize dfu_env_entities after flashing the 'SCRIPT' entity to ensure that the potential changes to the 'dfu_alt_info' environment variable are applied.
Signed-off-by: Marek Szyprowski m.szyprowski@samsung.com --- cmd/thordown.c | 19 ++++++++++++------- drivers/usb/gadget/f_thor.c | 3 +++ include/thor.h | 2 ++ 3 files changed, 17 insertions(+), 7 deletions(-)
diff --git a/cmd/thordown.c b/cmd/thordown.c index ae20dddfdd..838764ccef 100644 --- a/cmd/thordown.c +++ b/cmd/thordown.c @@ -52,13 +52,18 @@ int do_thor_down(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) goto exit; }
- ret = thor_handle(); - if (ret) { - pr_err("THOR failed: %d\n", ret); - ret = CMD_RET_FAILURE; - goto exit; - } - + do { + ret = thor_handle(); + if (ret == THOR_DFU_REINIT_NEEDED) { + dfu_free_entities(); + ret = dfu_init_env_entities(interface, devstring); + } + if (ret) { + pr_err("THOR failed: %d\n", ret); + ret = CMD_RET_FAILURE; + goto exit; + } + } while (ret == 0); exit: g_dnl_unregister(); usb_gadget_release(controller_index); diff --git a/drivers/usb/gadget/f_thor.c b/drivers/usb/gadget/f_thor.c index 88fc87f2e9..3e69746ee6 100644 --- a/drivers/usb/gadget/f_thor.c +++ b/drivers/usb/gadget/f_thor.c @@ -30,6 +30,7 @@ #include <linux/usb/cdc.h> #include <g_dnl.h> #include <dfu.h> +#include <thor.h>
#include "f_thor.h"
@@ -735,6 +736,8 @@ int thor_handle(void) printf("%s: No data received!\n", __func__); break; } + if (dfu_reinit_needed) + return THOR_DFU_REINIT_NEEDED; }
return 0; diff --git a/include/thor.h b/include/thor.h index 62501bda17..ee67ab0a27 100644 --- a/include/thor.h +++ b/include/thor.h @@ -12,6 +12,8 @@
#include <linux/usb/composite.h>
+#define THOR_DFU_REINIT_NEEDED 0xFFFFFFFE + int thor_handle(void); int thor_init(void); int thor_add(struct usb_configuration *c);
participants (1)
-
Marek Szyprowski