diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c index 9b8aa45667e..312e038445c 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 fd446d6efb3..ccbeafad260 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 30d00fbdfe9..6e24ae95d3b 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 00000000000..99d55282cd7 --- /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 d36bb923482..ea0db69c72a 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