]> git.ipfire.org Git - thirdparty/u-boot.git/blame - disk/disk-uclass.c
disk: Use a helper function to reduce duplication
[thirdparty/u-boot.git] / disk / disk-uclass.c
CommitLineData
43855fdb
AT
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Software partition device (UCLASS_PARTITION)
4 *
5 * Copyright (c) 2021 Linaro Limited
6 * Author: AKASHI Takahiro
7 */
8
9#define LOG_CATEGORY UCLASS_PARTITION
10
054de212 11#include <common.h>
43855fdb
AT
12#include <blk.h>
13#include <dm.h>
14#include <log.h>
15#include <part.h>
16#include <vsprintf.h>
17#include <dm/device-internal.h>
18#include <dm/lists.h>
19
20int part_create_block_devices(struct udevice *blk_dev)
21{
22 int part, count;
23 struct blk_desc *desc = dev_get_uclass_plat(blk_dev);
24 struct disk_partition info;
25 struct disk_part *part_data;
26 char devname[32];
27 struct udevice *dev;
28 int ret;
29
7f8967c2 30 if (!CONFIG_IS_ENABLED(PARTITIONS) || !blk_enabled())
43855fdb
AT
31 return 0;
32
33 if (device_get_uclass_id(blk_dev) != UCLASS_BLK)
34 return 0;
35
36 /* Add devices for each partition */
37 for (count = 0, part = 1; part <= MAX_SEARCH_PARTITIONS; part++) {
38 if (part_get_info(desc, part, &info))
39 continue;
40 snprintf(devname, sizeof(devname), "%s:%d", blk_dev->name,
41 part);
42
43 ret = device_bind_driver(blk_dev, "blk_partition",
44 strdup(devname), &dev);
45 if (ret)
46 return ret;
47
48 part_data = dev_get_uclass_plat(dev);
49 part_data->partnum = part;
50 part_data->gpt_part_info = info;
51 count++;
52
53 ret = device_probe(dev);
54 if (ret) {
55 debug("Can't probe\n");
56 count--;
57 device_unbind(dev);
58
59 continue;
60 }
61 }
62 debug("%s: %d partitions found in %s\n", __func__, count,
63 blk_dev->name);
64
65 return 0;
66}
67
d87bdb82
SG
68static int blk_part_setup(struct udevice *dev, lbaint_t *startp,
69 lbaint_t blkcnt)
70{
71 struct disk_part *part;
72
73 part = dev_get_uclass_plat(dev);
74 if (*startp >= part->gpt_part_info.size)
75 return -E2BIG;
76
77 if (*startp + blkcnt > part->gpt_part_info.size)
78 blkcnt = part->gpt_part_info.size - *startp;
79 *startp += part->gpt_part_info.start;
80
81 return 0;
82}
83
76c839fc 84static ulong part_blk_read(struct udevice *dev, lbaint_t start,
43855fdb
AT
85 lbaint_t blkcnt, void *buffer)
86{
87 struct udevice *parent;
43855fdb 88 const struct blk_ops *ops;
d87bdb82 89 int ret;
43855fdb
AT
90
91 parent = dev_get_parent(dev);
92 ops = blk_get_ops(parent);
93 if (!ops->read)
94 return -ENOSYS;
95
d87bdb82
SG
96 ret = blk_part_setup(dev, &start, blkcnt);
97 if (ret)
43855fdb
AT
98 return 0;
99
43855fdb
AT
100 return ops->read(parent, start, blkcnt, buffer);
101}
102
76c839fc 103static ulong part_blk_write(struct udevice *dev, lbaint_t start,
43855fdb
AT
104 lbaint_t blkcnt, const void *buffer)
105{
106 struct udevice *parent;
43855fdb 107 const struct blk_ops *ops;
d87bdb82 108 int ret;
43855fdb
AT
109
110 parent = dev_get_parent(dev);
111 ops = blk_get_ops(parent);
112 if (!ops->write)
113 return -ENOSYS;
114
d87bdb82
SG
115 ret = blk_part_setup(dev, &start, blkcnt);
116 if (ret)
43855fdb
AT
117 return 0;
118
43855fdb
AT
119 return ops->write(parent, start, blkcnt, buffer);
120}
121
76c839fc 122static ulong part_blk_erase(struct udevice *dev, lbaint_t start,
43855fdb
AT
123 lbaint_t blkcnt)
124{
125 struct udevice *parent;
43855fdb 126 const struct blk_ops *ops;
d87bdb82 127 int ret;
43855fdb
AT
128
129 parent = dev_get_parent(dev);
130 ops = blk_get_ops(parent);
131 if (!ops->erase)
132 return -ENOSYS;
133
d87bdb82
SG
134 ret = blk_part_setup(dev, &start, blkcnt);
135 if (ret)
43855fdb
AT
136 return 0;
137
43855fdb
AT
138 return ops->erase(parent, start, blkcnt);
139}
140
141static const struct blk_ops blk_part_ops = {
76c839fc
SG
142 .read = part_blk_read,
143 .write = part_blk_write,
144 .erase = part_blk_erase,
43855fdb
AT
145};
146
147U_BOOT_DRIVER(blk_partition) = {
148 .name = "blk_partition",
149 .id = UCLASS_PARTITION,
150 .ops = &blk_part_ops,
151};
152
59da9d47
AT
153/*
154 * BLOCK IO APIs
155 */
156static struct blk_desc *dev_get_blk(struct udevice *dev)
157{
b55afa0c 158 struct blk_desc *desc;
59da9d47
AT
159
160 switch (device_get_uclass_id(dev)) {
161 /*
162 * We won't support UCLASS_BLK with dev_* interfaces.
163 */
164 case UCLASS_PARTITION:
b55afa0c 165 desc = dev_get_uclass_plat(dev_get_parent(dev));
59da9d47
AT
166 break;
167 default:
b55afa0c 168 desc = NULL;
59da9d47
AT
169 break;
170 }
171
b55afa0c 172 return desc;
59da9d47
AT
173}
174
76c839fc
SG
175unsigned long disk_blk_read(struct udevice *dev, lbaint_t start,
176 lbaint_t blkcnt, void *buffer)
59da9d47 177{
b55afa0c 178 struct blk_desc *desc;
59da9d47
AT
179 const struct blk_ops *ops;
180 struct disk_part *part;
181 lbaint_t start_in_disk;
182 ulong blks_read;
183
b55afa0c
SG
184 desc = dev_get_blk(dev);
185 if (!desc)
59da9d47
AT
186 return -ENOSYS;
187
188 ops = blk_get_ops(dev);
189 if (!ops->read)
190 return -ENOSYS;
191
192 start_in_disk = start;
193 if (device_get_uclass_id(dev) == UCLASS_PARTITION) {
194 part = dev_get_uclass_plat(dev);
195 start_in_disk += part->gpt_part_info.start;
196 }
197
b55afa0c
SG
198 if (blkcache_read(desc->uclass_id, desc->devnum, start_in_disk, blkcnt,
199 desc->blksz, buffer))
59da9d47
AT
200 return blkcnt;
201 blks_read = ops->read(dev, start, blkcnt, buffer);
202 if (blks_read == blkcnt)
b55afa0c
SG
203 blkcache_fill(desc->uclass_id, desc->devnum, start_in_disk,
204 blkcnt, desc->blksz, buffer);
59da9d47
AT
205
206 return blks_read;
207}
208
76c839fc
SG
209unsigned long disk_blk_write(struct udevice *dev, lbaint_t start,
210 lbaint_t blkcnt, const void *buffer)
59da9d47 211{
b55afa0c 212 struct blk_desc *desc;
59da9d47
AT
213 const struct blk_ops *ops;
214
b55afa0c
SG
215 desc = dev_get_blk(dev);
216 if (!desc)
59da9d47
AT
217 return -ENOSYS;
218
219 ops = blk_get_ops(dev);
220 if (!ops->write)
221 return -ENOSYS;
222
b55afa0c 223 blkcache_invalidate(desc->uclass_id, desc->devnum);
59da9d47
AT
224
225 return ops->write(dev, start, blkcnt, buffer);
226}
227
76c839fc
SG
228unsigned long disk_blk_erase(struct udevice *dev, lbaint_t start,
229 lbaint_t blkcnt)
59da9d47 230{
b55afa0c 231 struct blk_desc *desc;
59da9d47
AT
232 const struct blk_ops *ops;
233
b55afa0c
SG
234 desc = dev_get_blk(dev);
235 if (!desc)
59da9d47
AT
236 return -ENOSYS;
237
238 ops = blk_get_ops(dev);
239 if (!ops->erase)
240 return -ENOSYS;
241
b55afa0c 242 blkcache_invalidate(desc->uclass_id, desc->devnum);
59da9d47
AT
243
244 return ops->erase(dev, start, blkcnt);
245}
246
43855fdb
AT
247UCLASS_DRIVER(partition) = {
248 .id = UCLASS_PARTITION,
249 .per_device_plat_auto = sizeof(struct disk_part),
250 .name = "partition",
251};