blob: 99d55282cd720124c55c25b583091b01a500bbbe [file] [log] [blame]
// 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,
};