diff --git a/doc/README.dfu b/doc/README.dfu index 96bced39d8..92a7695be2 100644 --- a/doc/README.dfu +++ b/doc/README.dfu @@ -112,6 +112,10 @@ Commands: (nand0, nor0, spi-nand0,...) each element in "dfu_alt_info" = raw raw access to mtd device + part raw acces to partition + partubi raw acces to ubi partition + + with is the MTD partition index and are absent: the dfu command to use multiple devices @@ -209,3 +213,20 @@ Usage: 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" + + Same example with MTD backend + + U-Boot> env set dfu_alt_info \ + "mtd nor0=spl part 1;u-boot part 2;u-boot-env part 3&"\ + "mtd nand0=UBI partubi 1" + + U-Boot> dfu 0 list + using id 'nor0,0' + using id 'nor0,1' + using id 'nor0,2' + using id 'nand0,0' + DFU alt settings list: + dev: MTD alt: 0 name: spl layout: RAW_ADDR + dev: MTD alt: 1 name: u-boot layout: RAW_ADDR + dev: MTD alt: 2 name: u-boot-env layout: RAW_ADDR + dev: MTD alt: 3 name: UBI layout: RAW_ADDR diff --git a/drivers/dfu/dfu_mtd.c b/drivers/dfu/dfu_mtd.c index 13fc837c69..9528a7b4ee 100644 --- a/drivers/dfu/dfu_mtd.c +++ b/drivers/dfu/dfu_mtd.c @@ -10,6 +10,7 @@ #include #include #include +#include static bool mtd_is_aligned_with_block_size(struct mtd_info *mtd, u64 size) { @@ -183,11 +184,52 @@ static int dfu_write_medium_mtd(struct dfu_entity *dfu, static int dfu_flush_medium_mtd(struct dfu_entity *dfu) { + struct mtd_info *mtd = dfu->data.mtd.info; + u64 remaining; + int ret; + + /* in case of ubi partition, erase rest of the partition */ + if (dfu->data.nand.ubi) { + struct erase_info erase_op = {}; + + erase_op.mtd = dfu->data.mtd.info; + erase_op.addr = round_up(dfu->data.mtd.start + dfu->offset + + dfu->bad_skip, mtd->erasesize); + erase_op.len = mtd->erasesize; + erase_op.scrub = 0; + + remaining = dfu->data.mtd.start + dfu->data.mtd.size - + erase_op.addr; + + while (remaining) { + ret = mtd_erase(mtd, &erase_op); + + if (ret) { + /* Abort if its not a bad block error */ + if (ret != -EIO) + break; + printf("Skipping bad block at 0x%08llx\n", + erase_op.addr); + } + + /* Skip bad block and continue behind it */ + erase_op.addr += mtd->erasesize; + remaining -= mtd->erasesize; + } + } return 0; } static unsigned int dfu_polltimeout_mtd(struct dfu_entity *dfu) { + /* + * Currently, Poll Timeout != 0 is only needed on nand + * ubi partition, as sectors which are not used need + * to be erased + */ + if (dfu->data.nand.ubi) + return DFU_MANIFEST_POLL_TIMEOUT; + return DFU_DEFAULT_POLL_TIMEOUT; } @@ -196,6 +238,7 @@ int dfu_fill_entity_mtd(struct dfu_entity *dfu, char *devstr, char *s) char *st; struct mtd_info *mtd; bool has_pages; + int ret, part; mtd = get_mtd_device_nm(devstr); if (IS_ERR_OR_NULL(mtd)) @@ -214,11 +257,47 @@ int dfu_fill_entity_mtd(struct dfu_entity *dfu, char *devstr, char *s) dfu->data.mtd.start = simple_strtoul(s, &s, 16); s++; dfu->data.mtd.size = simple_strtoul(s, &s, 16); + } else if ((!strcmp(st, "part")) || (!strcmp(st, "partubi"))) { + char mtd_id[32]; + struct mtd_device *mtd_dev; + u8 part_num; + struct part_info *pi; + + dfu->layout = DFU_RAW_ADDR; + + part = simple_strtoul(s, &s, 10); + + sprintf(mtd_id, "%s,%d", devstr, part - 1); + printf("using id '%s'\n", mtd_id); + + mtdparts_init(); + + ret = find_dev_and_part(mtd_id, &mtd_dev, &part_num, &pi); + if (ret != 0) { + printf("Could not locate '%s'\n", mtd_id); + return -1; + } + + dfu->data.mtd.start = pi->offset; + dfu->data.mtd.size = pi->size; + if (!strcmp(st, "partubi")) + dfu->data.mtd.ubi = 1; } else { - printf("%s: (%s) not supported!\n", __func__, st); + printf("%s: Memory layout (%s) not supported!\n", __func__, st); return -1; } + if (!mtd_is_aligned_with_block_size(mtd, dfu->data.mtd.start)) { + printf("Offset not aligned with a block (0x%x)\n", + mtd->erasesize); + return -EINVAL; + } + if (!mtd_is_aligned_with_block_size(mtd, dfu->data.mtd.size)) { + printf("Size not aligned with a block (0x%x)\n", + mtd->erasesize); + return -EINVAL; + } + dfu->get_medium_size = dfu_get_medium_size_mtd; dfu->read_medium = dfu_read_medium_mtd; dfu->write_medium = dfu_write_medium_mtd; diff --git a/include/dfu.h b/include/dfu.h index 924952f805..a90732cc43 100644 --- a/include/dfu.h +++ b/include/dfu.h @@ -62,6 +62,8 @@ struct mtd_internal_data { /* RAW programming */ u64 start; u64 size; + /* for ubi partition */ + unsigned int ubi; }; struct nand_internal_data {