[PATCH v6 0/6] Introduce UBI block device

Hello!
This series adds support for the UBI block device, which allows to read/write data block by block. For example, it can now be used for BCB or Android AB command:
$ bcb load ubi 0 part_name
Tested only on SPI NAND, so bind is made only for SPI NAND drivers. Can be used with mtdblock device [1].
---
Changes V1 -> V2 [2]:
- Rebased over mtdblock v2 patchset [3]. - Compile UBI partitions support only if CONFIG_BLK option is enabled.
Changes V2 -> V3 [4]:
- Fix build warnings: use LBAF printf format string for lbaint_t types.
Changes V3 -> V4 [5]:
- Rebased over u-boot/master. - Fix build errors and warnings if CONFIG_BLK isn't enabled. - Fix failed tests in cases is ubiblock device isn't binded.
Changes V4 -> V5 [6]:
- Rebased over u-boot/master. - Fix build errors when CONFIG_MTD and CONFIG_MTD_UBI isn't enabled. - Use auto blk device devnum generation when call blk_create_devicef (pass -1 parameter instead of dev_seq(dev)).
Changes V5 -> V6 [7]:
- Rebased over u-boot/master. - Introduce CONFIG_UBI_BLOCK which is disabled by default. - Fix undefined reference to `__aeabi_ldivmod' compiler error for 32-bit ARM targets.
Links:
[1] https://lore.kernel.org/all/20240227100441.1811047-1-avromanov@salutedevices... [2] https://lore.kernel.org/all/20240306134906.1179285-1-avromanov@salutedevices... [3] https://lore.kernel.org/all/20240307130726.1582487-1-avromanov@salutedevices... [4] https://lore.kernel.org/all/20240325144148.3738195-1-avromanov@salutedevices... [5] https://lore.kernel.org/all/20240524111319.3512009-1-avromanov@salutedevices... [6] https://lore.kernel.org/all/20240603155740.1840571-1-avromanov@salutedevices... [7] https://lore.kernel.org/all/20240626104527.2811828-1-avromanov@salutedevices...
Alexey Romanov (6): ubi: allow to read from volume with offset ubi: allow to write to volume with offset drivers: introduce UBI block abstraction disk: don't try search for partition type if already set disk: support UBI partitions spinand: bind UBI block
cmd/ubi.c | 78 ++++++++++++++++++++-- disk/part.c | 7 ++ drivers/block/blk-uclass.c | 1 + drivers/mtd/nand/spi/core.c | 12 +++- drivers/mtd/ubi/Kconfig | 7 ++ drivers/mtd/ubi/Makefile | 1 + drivers/mtd/ubi/block.c | 130 ++++++++++++++++++++++++++++++++++++ drivers/mtd/ubi/part.c | 99 +++++++++++++++++++++++++++ env/ubi.c | 16 ++--- include/part.h | 2 + include/ubi_uboot.h | 13 +++- 11 files changed, 348 insertions(+), 18 deletions(-) create mode 100644 drivers/mtd/ubi/block.c create mode 100644 drivers/mtd/ubi/part.c

Now user can pass an additional parameter 'offset' to ubi_volume_read() function.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com Reviewed-by: Heiko Schocher hs@denx.de Acked-by: Heiko Schocher hs@denx.de --- cmd/ubi.c | 6 +++--- env/ubi.c | 6 +++--- include/ubi_uboot.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/cmd/ubi.c b/cmd/ubi.c index 92998af2b0..4bf7c099dd 100644 --- a/cmd/ubi.c +++ b/cmd/ubi.c @@ -428,13 +428,13 @@ int ubi_volume_write(char *volume, void *buf, size_t size) return ubi_volume_begin_write(volume, buf, size, size); }
-int ubi_volume_read(char *volume, char *buf, size_t size) +int ubi_volume_read(char *volume, char *buf, loff_t offset, size_t size) { int err, lnum, off, len, tbuf_size; void *tbuf; unsigned long long tmp; struct ubi_volume *vol; - loff_t offp = 0; + loff_t offp = offset; size_t len_read;
vol = ubi_find_volume(volume); @@ -795,7 +795,7 @@ static int do_ubi(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) }
if (argc == 3) { - return ubi_volume_read(argv[3], (char *)addr, size); + return ubi_volume_read(argv[3], (char *)addr, 0, size); } }
diff --git a/env/ubi.c b/env/ubi.c index 0c3e93c2bf..22f2cafcfb 100644 --- a/env/ubi.c +++ b/env/ubi.c @@ -134,14 +134,14 @@ static int env_ubi_load(void) return -EIO; }
- read1_fail = ubi_volume_read(CONFIG_ENV_UBI_VOLUME, (void *)tmp_env1, + read1_fail = ubi_volume_read(CONFIG_ENV_UBI_VOLUME, (void *)tmp_env1, 0, CONFIG_ENV_SIZE); if (read1_fail) printf("\n** Unable to read env from %s:%s **\n", CONFIG_ENV_UBI_PART, CONFIG_ENV_UBI_VOLUME);
read2_fail = ubi_volume_read(CONFIG_ENV_UBI_VOLUME_REDUND, - (void *)tmp_env2, CONFIG_ENV_SIZE); + (void *)tmp_env2, 0, CONFIG_ENV_SIZE); if (read2_fail) printf("\n** Unable to read redundant env from %s:%s **\n", CONFIG_ENV_UBI_PART, CONFIG_ENV_UBI_VOLUME_REDUND); @@ -171,7 +171,7 @@ static int env_ubi_load(void) return -EIO; }
- if (ubi_volume_read(CONFIG_ENV_UBI_VOLUME, buf, CONFIG_ENV_SIZE)) { + if (ubi_volume_read(CONFIG_ENV_UBI_VOLUME, buf, 0, CONFIG_ENV_SIZE)) { printf("\n** Unable to read env from %s:%s **\n", CONFIG_ENV_UBI_PART, CONFIG_ENV_UBI_VOLUME); env_set_default(NULL, 0); diff --git a/include/ubi_uboot.h b/include/ubi_uboot.h index d7a8851094..a4be0feabb 100644 --- a/include/ubi_uboot.h +++ b/include/ubi_uboot.h @@ -49,7 +49,7 @@ extern int ubi_init(void); extern void ubi_exit(void); extern int ubi_part(char *part_name, const char *vid_header_offset); extern int ubi_volume_write(char *volume, void *buf, size_t size); -extern int ubi_volume_read(char *volume, char *buf, size_t size); +extern int ubi_volume_read(char *volume, char *buf, loff_t offset, size_t size);
extern struct ubi_device *ubi_devices[]; int cmd_ubifs_mount(char *vol_name);

Introduce ubi_volume_offset_write() helper, which allow to write to ubi volume with specified offset.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com Reviewed-by: Heiko Schocher hs@denx.de Acked-by: Heiko Schocher hs@denx.de --- cmd/ubi.c | 72 +++++++++++++++++++++++++++++++++++++++++++-- env/ubi.c | 10 +++---- include/ubi_uboot.h | 2 +- 3 files changed, 75 insertions(+), 9 deletions(-)
diff --git a/cmd/ubi.c b/cmd/ubi.c index 4bf7c099dd..0e62e44932 100644 --- a/cmd/ubi.c +++ b/cmd/ubi.c @@ -423,9 +423,75 @@ int ubi_volume_begin_write(char *volume, void *buf, size_t size, return ubi_volume_continue_write(volume, buf, size); }
-int ubi_volume_write(char *volume, void *buf, size_t size) +static int ubi_volume_offset_write(char *volume, void *buf, loff_t offset, + size_t size) { - return ubi_volume_begin_write(volume, buf, size, size); + int len, tbuf_size, ret; + u64 lnum; + struct ubi_volume *vol; + loff_t off = offset; + void *tbuf; + + vol = ubi_find_volume(volume); + if (!vol) + return -ENODEV; + + if (size > vol->reserved_pebs * (ubi->leb_size - vol->data_pad)) + return -EINVAL; + + tbuf_size = vol->usable_leb_size; + tbuf = malloc_cache_aligned(tbuf_size); + if (!tbuf) + return -ENOMEM; + + lnum = off; + off = do_div(lnum, vol->usable_leb_size); + + do { + struct ubi_volume_desc desc = { + .vol = vol, + .mode = UBI_READWRITE, + }; + + len = size > tbuf_size ? tbuf_size : size; + if (off + len >= vol->usable_leb_size) + len = vol->usable_leb_size - off; + + ret = ubi_read(&desc, (int)lnum, tbuf, 0, tbuf_size); + if (ret) { + pr_err("Failed to read leb %lld (%d)\n", lnum, ret); + goto exit; + } + + memcpy(tbuf + off, buf, len); + + ret = ubi_leb_change(&desc, (int)lnum, tbuf, tbuf_size); + if (ret) { + pr_err("Failed to write leb %lld (%d)\n", lnum, ret); + goto exit; + } + + off += len; + if (off >= vol->usable_leb_size) { + lnum++; + off -= vol->usable_leb_size; + } + + buf += len; + size -= len; + } while (size); + +exit: + free(tbuf); + return ret; +} + +int ubi_volume_write(char *volume, void *buf, loff_t offset, size_t size) +{ + if (!offset) + return ubi_volume_begin_write(volume, buf, size, size); + + return ubi_volume_offset_write(volume, buf, offset, size); }
int ubi_volume_read(char *volume, char *buf, loff_t offset, size_t size) @@ -769,7 +835,7 @@ static int do_ubi(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) (void *)addr, size, full_size); } } else { - ret = ubi_volume_write(argv[3], (void *)addr, size); + ret = ubi_volume_write(argv[3], (void *)addr, 0, size); } if (!ret) { printf("%lld bytes written to volume %s\n", size, diff --git a/env/ubi.c b/env/ubi.c index 22f2cafcfb..2f4ca571ed 100644 --- a/env/ubi.c +++ b/env/ubi.c @@ -53,7 +53,7 @@ static int env_ubi_save(void) if (gd->env_valid == ENV_VALID) { puts("Writing to redundant UBI... "); if (ubi_volume_write(CONFIG_ENV_UBI_VOLUME_REDUND, - (void *)env_new, CONFIG_ENV_SIZE)) { + (void *)env_new, 0, CONFIG_ENV_SIZE)) { printf("\n** Unable to write env to %s:%s **\n", CONFIG_ENV_UBI_PART, CONFIG_ENV_UBI_VOLUME_REDUND); @@ -62,7 +62,7 @@ static int env_ubi_save(void) } else { puts("Writing to UBI... "); if (ubi_volume_write(CONFIG_ENV_UBI_VOLUME, - (void *)env_new, CONFIG_ENV_SIZE)) { + (void *)env_new, 0, CONFIG_ENV_SIZE)) { printf("\n** Unable to write env to %s:%s **\n", CONFIG_ENV_UBI_PART, CONFIG_ENV_UBI_VOLUME); @@ -92,7 +92,7 @@ static int env_ubi_save(void) return 1; }
- if (ubi_volume_write(CONFIG_ENV_UBI_VOLUME, (void *)env_new, + if (ubi_volume_write(CONFIG_ENV_UBI_VOLUME, (void *)env_new, 0, CONFIG_ENV_SIZE)) { printf("\n** Unable to write env to %s:%s **\n", CONFIG_ENV_UBI_PART, CONFIG_ENV_UBI_VOLUME); @@ -196,7 +196,7 @@ static int env_ubi_erase(void) memset(env_buf, 0x0, CONFIG_ENV_SIZE);
if (ubi_volume_write(CONFIG_ENV_UBI_VOLUME, - (void *)env_buf, CONFIG_ENV_SIZE)) { + (void *)env_buf, 0, CONFIG_ENV_SIZE)) { printf("\n** Unable to erase env to %s:%s **\n", CONFIG_ENV_UBI_PART, CONFIG_ENV_UBI_VOLUME); @@ -204,7 +204,7 @@ static int env_ubi_erase(void) } if (IS_ENABLED(CONFIG_SYS_REDUNDAND_ENVIRONMENT)) { if (ubi_volume_write(ENV_UBI_VOLUME_REDUND, - (void *)env_buf, CONFIG_ENV_SIZE)) { + (void *)env_buf, 0, CONFIG_ENV_SIZE)) { printf("\n** Unable to erase env to %s:%s **\n", CONFIG_ENV_UBI_PART, ENV_UBI_VOLUME_REDUND); diff --git a/include/ubi_uboot.h b/include/ubi_uboot.h index a4be0feabb..d36bb92348 100644 --- a/include/ubi_uboot.h +++ b/include/ubi_uboot.h @@ -48,7 +48,7 @@ extern int ubi_mtd_param_parse(const char *val, struct kernel_param *kp); extern int ubi_init(void); extern void ubi_exit(void); extern int ubi_part(char *part_name, const char *vid_header_offset); -extern int ubi_volume_write(char *volume, void *buf, size_t size); +extern int ubi_volume_write(char *volume, void *buf, loff_t offset, size_t size); extern int ubi_volume_read(char *volume, char *buf, loff_t offset, size_t size);
extern struct ubi_device *ubi_devices[];

UBI block is an virtual device, that runs on top of the MTD layer. The blocks are UBI volumes. Intended to be used in combination with other MTD drivers.
Despite the fact that it, like mtdblock abstraction, it used with UCLASS_MTD, they can be used together on the system without conflicting. For example, using bcb command:
# Trying to load bcb via mtdblock: $ bcb load mtd 0 mtd_partition_name
# Trying to load bcb via UBI block: $ bcb load ubi 1 ubi_volume_name
User always must attach UBI layer (for example, using ubi_part()) before using UBI block device.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com Reviewed-by: Heiko Schocher hs@denx.de Acked-by: Heiko Schocher hs@denx.de --- drivers/block/blk-uclass.c | 1 + drivers/mtd/ubi/Kconfig | 7 ++ drivers/mtd/ubi/Makefile | 1 + drivers/mtd/ubi/block.c | 130 +++++++++++++++++++++++++++++++++++++ include/ubi_uboot.h | 9 +++ 5 files changed, 148 insertions(+) create mode 100644 drivers/mtd/ubi/block.c
diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index 9b8aa45667..312e038445 100644 --- a/drivers/block/blk-uclass.c +++ b/drivers/block/blk-uclass.c @@ -37,6 +37,7 @@ static struct { { UCLASS_BLKMAP, "blkmap" }, { UCLASS_RKMTD, "rkmtd" }, { UCLASS_MTD, "mtd" }, + { UCLASS_MTD, "ubi" }, };
static enum uclass_id uclass_name_to_iftype(const char *uclass_idname) diff --git a/drivers/mtd/ubi/Kconfig b/drivers/mtd/ubi/Kconfig index fd446d6efb..ccbeafad26 100644 --- a/drivers/mtd/ubi/Kconfig +++ b/drivers/mtd/ubi/Kconfig @@ -114,5 +114,12 @@ config MTD_UBI_FM_DEBUG help Enable UBI fastmap debug
+config UBI_BLOCK + bool "Enable UBI block device support" + depends on BLK + default n + help + Enable UBI block device support using blk_ops abstraction. + endif # MTD_UBI endmenu # "Enable UBI - Unsorted block images" diff --git a/drivers/mtd/ubi/Makefile b/drivers/mtd/ubi/Makefile index 30d00fbdfe..6e24ae95d3 100644 --- a/drivers/mtd/ubi/Makefile +++ b/drivers/mtd/ubi/Makefile @@ -7,3 +7,4 @@ obj-y += attach.o build.o vtbl.o vmt.o upd.o kapi.o eba.o io.o wl.o crc32.o obj-$(CONFIG_MTD_UBI_FASTMAP) += fastmap.o obj-y += misc.o obj-y += debug.o +obj-$(CONFIG_UBI_BLOCK) += block.o diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c new file mode 100644 index 0000000000..99d55282cd --- /dev/null +++ b/drivers/mtd/ubi/block.c @@ -0,0 +1,130 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2024 SaluteDevices, Inc. + * + * Author: Alexey Romanov avromanov@salutedevices.com + */ + +#include <blk.h> +#include <part.h> +#include <ubi_uboot.h> +#include <dm/device.h> +#include <dm/device-internal.h> + +int ubi_bind(struct udevice *dev) +{ + struct blk_desc *bdesc; + struct udevice *bdev; + int ret; + + ret = blk_create_devicef(dev, "ubi_blk", "blk", UCLASS_MTD, + -1, 512, 0, &bdev); + if (ret) { + pr_err("Cannot create block device"); + return ret; + } + + bdesc = dev_get_uclass_plat(bdev); + + bdesc->bdev = bdev; + bdesc->part_type = PART_TYPE_UBI; + + return 0; +} + +static struct ubi_device *get_ubi_device(void) +{ + return ubi_devices[0]; +} + +static char *get_volume_name(int vol_id) +{ + struct ubi_device *ubi = get_ubi_device(); + int i; + + for (i = 0; i < (ubi->vtbl_slots + 1); i++) { + struct ubi_volume *volume = ubi->volumes[i]; + + if (!volume) + continue; + + if (volume->vol_id >= UBI_INTERNAL_VOL_START) + continue; + + if (volume->vol_id == vol_id) + return volume->name; + } + + return NULL; +} + +static ulong ubi_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, + void *dst) +{ + struct blk_desc *block_dev = dev_get_uclass_plat(dev); + char *volume_name = get_volume_name(block_dev->hwpart); + unsigned int size = blkcnt * block_dev->blksz; + loff_t offset = start * block_dev->blksz; + int ret; + + if (!volume_name) { + pr_err("%s: failed to find volume name for blk=" LBAF "\n", __func__, start); + return -EINVAL; + } + + ret = ubi_volume_read(volume_name, dst, offset, size); + if (ret) { + pr_err("%s: failed to read from %s UBI volume\n", __func__, volume_name); + return ret; + } + + return blkcnt; +} + +static ulong ubi_bwrite(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, + const void *src) +{ + struct blk_desc *block_dev = dev_get_uclass_plat(dev); + char *volume_name = get_volume_name(block_dev->hwpart); + unsigned int size = blkcnt * block_dev->blksz; + loff_t offset = start * block_dev->blksz; + int ret; + + if (!volume_name) { + pr_err("%s: failed to find volume for blk=" LBAF "\n", __func__, start); + return -EINVAL; + } + + ret = ubi_volume_write(volume_name, (void *)src, offset, size); + if (ret) { + pr_err("%s: failed to write from %s UBI volume\n", __func__, volume_name); + return ret; + } + + return blkcnt; +} + +static int ubi_blk_probe(struct udevice *dev) +{ + int ret; + + ret = device_probe(dev); + if (ret) { + pr_err("Probing %s failed (err=%d)\n", dev->name, ret); + return ret; + } + + return 0; +} + +static const struct blk_ops ubi_blk_ops = { + .read = ubi_bread, + .write = ubi_bwrite, +}; + +U_BOOT_DRIVER(ubi_blk) = { + .name = "ubi_blk", + .id = UCLASS_BLK, + .ops = &ubi_blk_ops, + .probe = ubi_blk_probe, +}; diff --git a/include/ubi_uboot.h b/include/ubi_uboot.h index d36bb92348..ea0db69c72 100644 --- a/include/ubi_uboot.h +++ b/include/ubi_uboot.h @@ -55,4 +55,13 @@ extern struct ubi_device *ubi_devices[]; int cmd_ubifs_mount(char *vol_name); int cmd_ubifs_umount(void);
+#if IS_ENABLED(CONFIG_UBI_BLOCK) +int ubi_bind(struct udevice *dev); +#else +static inline int ubi_bind(struct udevice *dev) +{ + return -EOPNOTSUPP; +} +#endif + #endif

Block devices can already set partition type at initialization stage, so, in this case is no point in searching for partition type.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com Reviewed-by: Heiko Schocher hs@denx.de --- disk/part.c | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/disk/part.c b/disk/part.c index 86f669926e..706d77b319 100644 --- a/disk/part.c +++ b/disk/part.c @@ -285,6 +285,13 @@ void part_init(struct blk_desc *desc)
blkcache_invalidate(desc->uclass_id, desc->devnum);
+ if (desc->part_type != PART_TYPE_UNKNOWN) { + for (entry = drv; entry != drv + n_ents; entry++) { + if (entry->part_type == desc->part_type && !entry->test(desc)) + return; + } + } + desc->part_type = PART_TYPE_UNKNOWN; for (entry = drv; entry != drv + n_ents; entry++) { int ret;

UBI partition is abstraction over UBI volumes. Can be used by UBI block device.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com Reviewed-by: Heiko Schocher hs@denx.de --- drivers/mtd/ubi/Makefile | 2 +- drivers/mtd/ubi/part.c | 99 ++++++++++++++++++++++++++++++++++++++++ include/part.h | 2 + 3 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 drivers/mtd/ubi/part.c
diff --git a/drivers/mtd/ubi/Makefile b/drivers/mtd/ubi/Makefile index 6e24ae95d3..690ef9e901 100644 --- a/drivers/mtd/ubi/Makefile +++ b/drivers/mtd/ubi/Makefile @@ -7,4 +7,4 @@ obj-y += attach.o build.o vtbl.o vmt.o upd.o kapi.o eba.o io.o wl.o crc32.o obj-$(CONFIG_MTD_UBI_FASTMAP) += fastmap.o obj-y += misc.o obj-y += debug.o -obj-$(CONFIG_UBI_BLOCK) += block.o +obj-$(CONFIG_UBI_BLOCK) += block.o part.o diff --git a/drivers/mtd/ubi/part.c b/drivers/mtd/ubi/part.c new file mode 100644 index 0000000000..13d1f165c3 --- /dev/null +++ b/drivers/mtd/ubi/part.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * (C) Copyright 2024 SaluteDevices, Inc. + * + * Author: Alexey Romanov avromanov@salutedevices.com + */ + +#include <memalign.h> +#include <part.h> +#include <ubi_uboot.h> + +static inline struct ubi_device *get_ubi_device(void) +{ + return ubi_devices[0]; +} + +static struct ubi_volume *ubi_get_volume_by_index(int vol_id) +{ + struct ubi_device *ubi = get_ubi_device(); + int i; + + for (i = 0; i < (ubi->vtbl_slots + 1); i++) { + struct ubi_volume *volume = ubi->volumes[i]; + + if (!volume) + continue; + + if (volume->vol_id >= UBI_INTERNAL_VOL_START) + continue; + + if (volume->vol_id == vol_id) + return volume; + } + + return NULL; +} + +static int __maybe_unused part_get_info_ubi(struct blk_desc *dev_desc, int part_idx, + struct disk_partition *info) +{ + struct ubi_volume *vol; + + /* + * We must use part_idx - 1 instead of part_idx, because + * part_get_info_by_name() start indexing at 1, not 0. + * ubi volumes idexed starting at 0 + */ + vol = ubi_get_volume_by_index(part_idx - 1); + if (!vol) + return 0; + + snprintf(info->name, PART_NAME_LEN, vol->name); + + info->start = 0; + info->size = (unsigned long)vol->used_bytes / dev_desc->blksz; + info->blksz = dev_desc->blksz; + + /* Save UBI volume ID in blk device descriptor */ + dev_desc->hwpart = vol->vol_id; + + return 0; +} + +static void __maybe_unused part_print_ubi(struct blk_desc *dev_desc) +{ + struct ubi_device *ubi = get_ubi_device(); + int i; + + for (i = 0; i < (ubi->vtbl_slots + 1); i++) { + struct ubi_volume *volume = ubi->volumes[i]; + + if (!volume) + continue; + + if (volume->vol_id >= UBI_INTERNAL_VOL_START) + continue; + + printf("%d: %s\n", volume->vol_id, volume->name); + } +} + +static int part_test_ubi(struct blk_desc *dev_desc) +{ + ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, dev_desc->blksz); + + if (blk_dread(dev_desc, 0, 1, (ulong *)buffer) != 1) + return -1; + + return 0; +} + +U_BOOT_PART_TYPE(ubi) = { + .name = "ubi", + .part_type = PART_TYPE_UBI, + .max_entries = UBI_ENTRY_NUMBERS, + .get_info = part_get_info_ptr(part_get_info_ubi), + .print = part_print_ptr(part_print_ubi), + .test = part_test_ubi, +}; diff --git a/include/part.h b/include/part.h index 40419fdf2f..72b98b3512 100644 --- a/include/part.h +++ b/include/part.h @@ -31,6 +31,7 @@ struct block_drvr { #define PART_TYPE_AMIGA 0x04 #define PART_TYPE_EFI 0x05 #define PART_TYPE_MTD 0x06 +#define PART_TYPE_UBI 0x07
/* maximum number of partition entries supported by search */ #define DOS_ENTRY_NUMBERS 8 @@ -38,6 +39,7 @@ struct block_drvr { #define MAC_ENTRY_NUMBERS 64 #define AMIGA_ENTRY_NUMBERS 8 #define MTD_ENTRY_NUMBERS 64 +#define UBI_ENTRY_NUMBERS UBI_MAX_VOLUMES
/* * Type string for U-Boot bootable partitions

UBI block is virtual block device, which is an abstraction over MTD layer. Therefore it is logical to use it in combination with MTD drivers.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com Reviewed-by: Frieder Schrempf frieder.schrempf@kontron.de --- drivers/mtd/nand/spi/core.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c index 54a90ff295..f5ddfbf4b8 100644 --- a/drivers/mtd/nand/spi/core.c +++ b/drivers/mtd/nand/spi/core.c @@ -25,6 +25,7 @@ #include <watchdog.h> #include <spi.h> #include <spi-mem.h> +#include <ubi_uboot.h> #include <dm/device_compat.h> #include <dm/devres.h> #include <linux/bitops.h> @@ -1180,9 +1181,16 @@ static int spinand_bind(struct udevice *dev) { if (blk_enabled()) { struct spinand_plat *plat = dev_get_plat(dev); + int ret; + + if (CONFIG_IS_ENABLED(MTD_BLOCK)) { + ret = mtd_bind(dev, &plat->mtd); + if (ret) + return ret; + }
- if (CONFIG_IS_ENABLED(MTD_BLOCK)) - return mtd_bind(dev, &plat->mtd); + if (CONFIG_IS_ENABLED(UBI_BLOCK)) + return ubi_bind(dev); }
return 0;

Hello Alexey,
On 18.07.24 07:45, Alexey Romanov wrote:
UBI block is virtual block device, which is an abstraction over MTD layer. Therefore it is logical to use it in combination with MTD drivers.
Signed-off-by: Alexey Romanov avromanov@salutedevices.com Reviewed-by: Frieder Schrempf frieder.schrempf@kontron.de
drivers/mtd/nand/spi/core.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
Looks good from my side
Reviewed-by: Heiko Schocher hs@denx.de
Thanks!
bye, Heiko

Hi Alexey
On Thu, Jul 18, 2024 at 7:45 AM Alexey Romanov avromanov@salutedevices.com wrote:
Hello!
This series adds support for the UBI block device, which allows to read/write data block by block. For example, it can now be used for BCB or Android AB command:
$ bcb load ubi 0 part_name
Tested only on SPI NAND, so bind is made only for SPI NAND drivers. Can be used with mtdblock device [1].
Did you run the CI on it? It's important not only that review get pass but even we don't create regression on other build
Michael
Changes V1 -> V2 [2]:
- Rebased over mtdblock v2 patchset [3].
- Compile UBI partitions support only if CONFIG_BLK option is enabled.
Changes V2 -> V3 [4]:
- Fix build warnings: use LBAF printf format string for lbaint_t types.
Changes V3 -> V4 [5]:
- Rebased over u-boot/master.
- Fix build errors and warnings if CONFIG_BLK isn't enabled.
- Fix failed tests in cases is ubiblock device isn't binded.
Changes V4 -> V5 [6]:
- Rebased over u-boot/master.
- Fix build errors when CONFIG_MTD and CONFIG_MTD_UBI isn't enabled.
- Use auto blk device devnum generation when call blk_create_devicef (pass -1 parameter instead of dev_seq(dev)).
Changes V5 -> V6 [7]:
- Rebased over u-boot/master.
- Introduce CONFIG_UBI_BLOCK which is disabled by default.
- Fix undefined reference to `__aeabi_ldivmod' compiler error for 32-bit ARM targets.
Links:
[1] https://lore.kernel.org/all/20240227100441.1811047-1-avromanov@salutedevices... [2] https://lore.kernel.org/all/20240306134906.1179285-1-avromanov@salutedevices... [3] https://lore.kernel.org/all/20240307130726.1582487-1-avromanov@salutedevices... [4] https://lore.kernel.org/all/20240325144148.3738195-1-avromanov@salutedevices... [5] https://lore.kernel.org/all/20240524111319.3512009-1-avromanov@salutedevices... [6] https://lore.kernel.org/all/20240603155740.1840571-1-avromanov@salutedevices... [7] https://lore.kernel.org/all/20240626104527.2811828-1-avromanov@salutedevices...
Alexey Romanov (6): ubi: allow to read from volume with offset ubi: allow to write to volume with offset drivers: introduce UBI block abstraction disk: don't try search for partition type if already set disk: support UBI partitions spinand: bind UBI block
cmd/ubi.c | 78 ++++++++++++++++++++-- disk/part.c | 7 ++ drivers/block/blk-uclass.c | 1 + drivers/mtd/nand/spi/core.c | 12 +++- drivers/mtd/ubi/Kconfig | 7 ++ drivers/mtd/ubi/Makefile | 1 + drivers/mtd/ubi/block.c | 130 ++++++++++++++++++++++++++++++++++++ drivers/mtd/ubi/part.c | 99 +++++++++++++++++++++++++++ env/ubi.c | 16 ++--- include/part.h | 2 + include/ubi_uboot.h | 13 +++- 11 files changed, 348 insertions(+), 18 deletions(-) create mode 100644 drivers/mtd/ubi/block.c create mode 100644 drivers/mtd/ubi/part.c
-- 2.34.1
participants (3)
-
Alexey Romanov
-
Heiko Schocher
-
Michael Nazzareno Trimarchi