blob: 99d55282cd720124c55c25b583091b01a500bbbe [file] [log] [blame]
Alexey Romanov4d44fa22024-07-18 08:45:25 +03001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * (C) Copyright 2024 SaluteDevices, Inc.
4 *
5 * Author: Alexey Romanov <avromanov@salutedevices.com>
6 */
7
8#include <blk.h>
9#include <part.h>
10#include <ubi_uboot.h>
11#include <dm/device.h>
12#include <dm/device-internal.h>
13
14int ubi_bind(struct udevice *dev)
15{
16 struct blk_desc *bdesc;
17 struct udevice *bdev;
18 int ret;
19
20 ret = blk_create_devicef(dev, "ubi_blk", "blk", UCLASS_MTD,
21 -1, 512, 0, &bdev);
22 if (ret) {
23 pr_err("Cannot create block device");
24 return ret;
25 }
26
27 bdesc = dev_get_uclass_plat(bdev);
28
29 bdesc->bdev = bdev;
30 bdesc->part_type = PART_TYPE_UBI;
31
32 return 0;
33}
34
35static struct ubi_device *get_ubi_device(void)
36{
37 return ubi_devices[0];
38}
39
40static char *get_volume_name(int vol_id)
41{
42 struct ubi_device *ubi = get_ubi_device();
43 int i;
44
45 for (i = 0; i < (ubi->vtbl_slots + 1); i++) {
46 struct ubi_volume *volume = ubi->volumes[i];
47
48 if (!volume)
49 continue;
50
51 if (volume->vol_id >= UBI_INTERNAL_VOL_START)
52 continue;
53
54 if (volume->vol_id == vol_id)
55 return volume->name;
56 }
57
58 return NULL;
59}
60
61static ulong ubi_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt,
62 void *dst)
63{
64 struct blk_desc *block_dev = dev_get_uclass_plat(dev);
65 char *volume_name = get_volume_name(block_dev->hwpart);
66 unsigned int size = blkcnt * block_dev->blksz;
67 loff_t offset = start * block_dev->blksz;
68 int ret;
69
70 if (!volume_name) {
71 pr_err("%s: failed to find volume name for blk=" LBAF "\n", __func__, start);
72 return -EINVAL;
73 }
74
75 ret = ubi_volume_read(volume_name, dst, offset, size);
76 if (ret) {
77 pr_err("%s: failed to read from %s UBI volume\n", __func__, volume_name);
78 return ret;
79 }
80
81 return blkcnt;
82}
83
84static ulong ubi_bwrite(struct udevice *dev, lbaint_t start, lbaint_t blkcnt,
85 const void *src)
86{
87 struct blk_desc *block_dev = dev_get_uclass_plat(dev);
88 char *volume_name = get_volume_name(block_dev->hwpart);
89 unsigned int size = blkcnt * block_dev->blksz;
90 loff_t offset = start * block_dev->blksz;
91 int ret;
92
93 if (!volume_name) {
94 pr_err("%s: failed to find volume for blk=" LBAF "\n", __func__, start);
95 return -EINVAL;
96 }
97
98 ret = ubi_volume_write(volume_name, (void *)src, offset, size);
99 if (ret) {
100 pr_err("%s: failed to write from %s UBI volume\n", __func__, volume_name);
101 return ret;
102 }
103
104 return blkcnt;
105}
106
107static int ubi_blk_probe(struct udevice *dev)
108{
109 int ret;
110
111 ret = device_probe(dev);
112 if (ret) {
113 pr_err("Probing %s failed (err=%d)\n", dev->name, ret);
114 return ret;
115 }
116
117 return 0;
118}
119
120static const struct blk_ops ubi_blk_ops = {
121 .read = ubi_bread,
122 .write = ubi_bwrite,
123};
124
125U_BOOT_DRIVER(ubi_blk) = {
126 .name = "ubi_blk",
127 .id = UCLASS_BLK,
128 .ops = &ubi_blk_ops,
129 .probe = ubi_blk_probe,
130};