// SPDX-License-Identifier: GPL-2.0+ /* * (C) Copyright 2024 SaluteDevices, Inc. * * Author: Alexey Romanov */ #include #include #include #include #include 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, };