blob: 312e038445c0253c58c12e0fb6d356efb3b00ef8 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glasscceee552016-02-29 15:25:55 -07002/*
3 * Copyright (C) 2016 Google, Inc
4 * Written by Simon Glass <sjg@chromium.org>
Simon Glasscceee552016-02-29 15:25:55 -07005 */
6
Patrick Delaunay81313352021-04-27 11:02:19 +02007#define LOG_CATEGORY UCLASS_BLK
8
Simon Glasscceee552016-02-29 15:25:55 -07009#include <blk.h>
10#include <dm.h>
Simon Glass0f2af882020-05-10 11:40:05 -060011#include <log.h>
Simon Glass9bc15642020-02-03 07:36:16 -070012#include <malloc.h>
Simon Glass655306c2020-05-10 11:39:58 -060013#include <part.h>
Simon Glasscceee552016-02-29 15:25:55 -070014#include <dm/device-internal.h>
15#include <dm/lists.h>
Stefan Roeseef58a902017-11-29 16:46:42 +010016#include <dm/uclass-internal.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070017#include <linux/err.h>
Simon Glasscceee552016-02-29 15:25:55 -070018
Marek Vasutddfa0882023-08-14 01:46:48 +020019#define blk_get_ops(dev) ((struct blk_ops *)(dev)->driver->ops)
20
Simon Glass95e6e032022-08-11 19:34:57 -060021static struct {
22 enum uclass_id id;
23 const char *name;
Simon Glassfada3f92022-09-17 09:00:09 -060024} uclass_idname_str[] = {
Simon Glassdbfa32c2022-08-11 19:34:59 -060025 { UCLASS_IDE, "ide" },
26 { UCLASS_SCSI, "scsi" },
27 { UCLASS_USB, "usb" },
28 { UCLASS_MMC, "mmc" },
29 { UCLASS_AHCI, "sata" },
Simon Glasse57f8d42022-10-29 19:47:17 -060030 { UCLASS_HOST, "host" },
Simon Glassdbfa32c2022-08-11 19:34:59 -060031 { UCLASS_NVME, "nvme" },
Abdellatif El Khlifi857360c2023-04-17 10:11:52 +010032 { UCLASS_NVMXIP, "nvmxip" },
Simon Glassdbfa32c2022-08-11 19:34:59 -060033 { UCLASS_EFI_MEDIA, "efi" },
34 { UCLASS_EFI_LOADER, "efiloader" },
35 { UCLASS_VIRTIO, "virtio" },
36 { UCLASS_PVBLOCK, "pvblock" },
Tobias Waldekranz4f76dd32023-02-16 16:33:49 +010037 { UCLASS_BLKMAP, "blkmap" },
Johan Jonker7a657e02023-10-18 16:00:40 +020038 { UCLASS_RKMTD, "rkmtd" },
Alexey Romanov8e1fd2e2024-07-18 08:46:05 +030039 { UCLASS_MTD, "mtd" },
Alexey Romanov4d44fa22024-07-18 08:45:25 +030040 { UCLASS_MTD, "ubi" },
Simon Glass4131ad52016-05-01 11:36:08 -060041};
42
Simon Glassfada3f92022-09-17 09:00:09 -060043static enum uclass_id uclass_name_to_iftype(const char *uclass_idname)
Simon Glass4131ad52016-05-01 11:36:08 -060044{
45 int i;
46
Simon Glassfada3f92022-09-17 09:00:09 -060047 for (i = 0; i < ARRAY_SIZE(uclass_idname_str); i++) {
48 if (!strcmp(uclass_idname, uclass_idname_str[i].name))
49 return uclass_idname_str[i].id;
Simon Glass4131ad52016-05-01 11:36:08 -060050 }
51
Simon Glassdbfa32c2022-08-11 19:34:59 -060052 return UCLASS_INVALID;
Simon Glass4131ad52016-05-01 11:36:08 -060053}
54
Simon Glassfada3f92022-09-17 09:00:09 -060055static enum uclass_id conv_uclass_id(enum uclass_id uclass_id)
Simon Glass4131ad52016-05-01 11:36:08 -060056{
Simon Glassdbfa32c2022-08-11 19:34:59 -060057 /*
58 * This strange adjustment is used because we use UCLASS_MASS_STORAGE
59 * for USB storage devices, so need to return this as the uclass to
60 * use for USB. In fact USB_UCLASS is for USB controllers, not
61 * peripherals.
62 *
63 * The name of the UCLASS_MASS_STORAGE uclass driver is
64 * "usb_mass_storage", but we want to use "usb" in things like the
65 * 'part list' command and when showing interfaces.
66 *
67 * So for now we have this one-way conversion.
68 *
69 * The fix for this is possibly to:
70 * - rename UCLASS_MASS_STORAGE name to "usb"
71 * - rename UCLASS_USB name to "usb_ctlr"
72 * - use UCLASS_MASS_STORAGE instead of UCLASS_USB in if_typename_str
73 */
Simon Glassfada3f92022-09-17 09:00:09 -060074 if (uclass_id == UCLASS_USB)
Simon Glassdbfa32c2022-08-11 19:34:59 -060075 return UCLASS_MASS_STORAGE;
Simon Glassfada3f92022-09-17 09:00:09 -060076 return uclass_id;
Simon Glass4131ad52016-05-01 11:36:08 -060077}
78
Simon Glassfada3f92022-09-17 09:00:09 -060079const char *blk_get_uclass_name(enum uclass_id uclass_id)
Simon Glass85af5a42017-07-29 11:34:53 -060080{
Simon Glass95e6e032022-08-11 19:34:57 -060081 int i;
82
Simon Glassfada3f92022-09-17 09:00:09 -060083 for (i = 0; i < ARRAY_SIZE(uclass_idname_str); i++) {
84 if (uclass_idname_str[i].id == uclass_id)
85 return uclass_idname_str[i].name;
Simon Glass95e6e032022-08-11 19:34:57 -060086 }
87
88 return "(none)";
Simon Glass85af5a42017-07-29 11:34:53 -060089}
90
Simon Glassfada3f92022-09-17 09:00:09 -060091struct blk_desc *blk_get_devnum_by_uclass_id(enum uclass_id uclass_id, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -060092{
93 struct blk_desc *desc;
94 struct udevice *dev;
95 int ret;
96
Simon Glassfada3f92022-09-17 09:00:09 -060097 ret = blk_get_device(uclass_id, devnum, &dev);
Simon Glass4131ad52016-05-01 11:36:08 -060098 if (ret)
99 return NULL;
Simon Glass71fa5b42020-12-03 16:55:18 -0700100 desc = dev_get_uclass_plat(dev);
Simon Glass4131ad52016-05-01 11:36:08 -0600101
102 return desc;
103}
104
105/*
106 * This function is complicated with driver model. We look up the interface
107 * name in a local table. This gives us an interface type which we can match
108 * against the uclass of the block device's parent.
109 */
Simon Glassfada3f92022-09-17 09:00:09 -0600110struct blk_desc *blk_get_devnum_by_uclass_idname(const char *uclass_idname, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -0600111{
112 enum uclass_id uclass_id;
Simon Glass57b3d2e2022-08-11 19:35:01 -0600113 enum uclass_id type;
Simon Glass4131ad52016-05-01 11:36:08 -0600114 struct udevice *dev;
115 struct uclass *uc;
116 int ret;
117
Simon Glassfada3f92022-09-17 09:00:09 -0600118 type = uclass_name_to_iftype(uclass_idname);
Simon Glassdbfa32c2022-08-11 19:34:59 -0600119 if (type == UCLASS_INVALID) {
Simon Glass4131ad52016-05-01 11:36:08 -0600120 debug("%s: Unknown interface type '%s'\n", __func__,
Simon Glassfada3f92022-09-17 09:00:09 -0600121 uclass_idname);
Simon Glass4131ad52016-05-01 11:36:08 -0600122 return NULL;
123 }
Simon Glassfada3f92022-09-17 09:00:09 -0600124 uclass_id = conv_uclass_id(type);
Simon Glass4131ad52016-05-01 11:36:08 -0600125 if (uclass_id == UCLASS_INVALID) {
126 debug("%s: Unknown uclass for interface type'\n",
Simon Glassfada3f92022-09-17 09:00:09 -0600127 blk_get_uclass_name(type));
Simon Glass4131ad52016-05-01 11:36:08 -0600128 return NULL;
129 }
130
131 ret = uclass_get(UCLASS_BLK, &uc);
132 if (ret)
133 return NULL;
134 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700135 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glass4131ad52016-05-01 11:36:08 -0600136
Simon Glassfada3f92022-09-17 09:00:09 -0600137 debug("%s: uclass_id=%d, devnum=%d: %s, %d, %d\n", __func__,
138 type, devnum, dev->name, desc->uclass_id, desc->devnum);
Simon Glass4131ad52016-05-01 11:36:08 -0600139 if (desc->devnum != devnum)
140 continue;
141
142 /* Find out the parent device uclass */
143 if (device_get_uclass_id(dev->parent) != uclass_id) {
144 debug("%s: parent uclass %d, this dev %d\n", __func__,
145 device_get_uclass_id(dev->parent), uclass_id);
146 continue;
147 }
148
149 if (device_probe(dev))
150 return NULL;
151
152 debug("%s: Device desc %p\n", __func__, desc);
153 return desc;
154 }
155 debug("%s: No device found\n", __func__);
156
157 return NULL;
158}
159
160/**
Tien Fong Chee10378522018-07-06 16:26:36 +0800161 * blk_get_by_device() - Get the block device descriptor for the given device
162 * @dev: Instance of a storage device
163 *
164 * Return: With block device descriptor on success , NULL if there is no such
165 * block device.
166 */
167struct blk_desc *blk_get_by_device(struct udevice *dev)
168{
Simon Glasscfd72932019-09-25 08:55:56 -0600169 struct udevice *child_dev;
Tien Fong Chee10378522018-07-06 16:26:36 +0800170
Simon Glasscfd72932019-09-25 08:55:56 -0600171 device_foreach_child(child_dev, dev) {
Tien Fong Chee10378522018-07-06 16:26:36 +0800172 if (device_get_uclass_id(child_dev) != UCLASS_BLK)
173 continue;
174
Simon Glass71fa5b42020-12-03 16:55:18 -0700175 return dev_get_uclass_plat(child_dev);
Tien Fong Chee10378522018-07-06 16:26:36 +0800176 }
177
178 debug("%s: No block device found\n", __func__);
179
180 return NULL;
181}
182
Bin Meng9efc2452023-09-26 16:43:41 +0800183int blk_get_desc(enum uclass_id uclass_id, int devnum, struct blk_desc **descp)
Simon Glass4131ad52016-05-01 11:36:08 -0600184{
185 bool found_more = false;
186 struct udevice *dev;
187 struct uclass *uc;
188 int ret;
189
190 *descp = NULL;
191 ret = uclass_get(UCLASS_BLK, &uc);
192 if (ret)
193 return ret;
194 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700195 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glass4131ad52016-05-01 11:36:08 -0600196
Simon Glassfada3f92022-09-17 09:00:09 -0600197 debug("%s: uclass_id=%d, devnum=%d: %s, %d, %d\n", __func__,
198 uclass_id, devnum, dev->name, desc->uclass_id, desc->devnum);
199 if (desc->uclass_id == uclass_id) {
Simon Glass4131ad52016-05-01 11:36:08 -0600200 if (desc->devnum == devnum) {
201 ret = device_probe(dev);
202 if (ret)
203 return ret;
204
Michal Simekf438b6b2016-11-16 17:37:42 +0100205 *descp = desc;
206 return 0;
Simon Glass4131ad52016-05-01 11:36:08 -0600207 } else if (desc->devnum > devnum) {
208 found_more = true;
209 }
210 }
211 }
212
213 return found_more ? -ENOENT : -ENODEV;
214}
215
Simon Glassfada3f92022-09-17 09:00:09 -0600216int blk_select_hwpart_devnum(enum uclass_id uclass_id, int devnum, int hwpart)
Simon Glass13c2c292016-05-01 13:52:30 -0600217{
218 struct udevice *dev;
219 int ret;
220
Simon Glassfada3f92022-09-17 09:00:09 -0600221 ret = blk_get_device(uclass_id, devnum, &dev);
Simon Glass13c2c292016-05-01 13:52:30 -0600222 if (ret)
223 return ret;
224
developerf50d8d12019-08-27 15:32:18 +0800225 return blk_select_hwpart(dev, hwpart);
Simon Glass13c2c292016-05-01 13:52:30 -0600226}
227
Simon Glassfada3f92022-09-17 09:00:09 -0600228int blk_list_part(enum uclass_id uclass_id)
Simon Glass4131ad52016-05-01 11:36:08 -0600229{
230 struct blk_desc *desc;
231 int devnum, ok;
232 int ret;
233
234 for (ok = 0, devnum = 0;; ++devnum) {
Bin Meng9efc2452023-09-26 16:43:41 +0800235 ret = blk_get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600236 if (ret == -ENODEV)
237 break;
238 else if (ret)
239 continue;
240 if (desc->part_type != PART_TYPE_UNKNOWN) {
241 ++ok;
242 if (devnum)
243 putc('\n');
244 part_print(desc);
245 }
246 }
247 if (!ok)
248 return -ENODEV;
249
250 return 0;
251}
252
Simon Glassfada3f92022-09-17 09:00:09 -0600253int blk_print_part_devnum(enum uclass_id uclass_id, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -0600254{
255 struct blk_desc *desc;
256 int ret;
257
Bin Meng9efc2452023-09-26 16:43:41 +0800258 ret = blk_get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600259 if (ret)
260 return ret;
261 if (desc->type == DEV_TYPE_UNKNOWN)
262 return -ENOENT;
263 part_print(desc);
264
265 return 0;
266}
267
Simon Glassfada3f92022-09-17 09:00:09 -0600268void blk_list_devices(enum uclass_id uclass_id)
Simon Glass4131ad52016-05-01 11:36:08 -0600269{
270 struct blk_desc *desc;
271 int ret;
272 int i;
273
274 for (i = 0;; ++i) {
Bin Meng9efc2452023-09-26 16:43:41 +0800275 ret = blk_get_desc(uclass_id, i, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600276 if (ret == -ENODEV)
277 break;
278 else if (ret)
279 continue;
280 if (desc->type == DEV_TYPE_UNKNOWN)
281 continue; /* list only known devices */
282 printf("Device %d: ", i);
283 dev_print(desc);
284 }
285}
286
Simon Glassfada3f92022-09-17 09:00:09 -0600287int blk_print_device_num(enum uclass_id uclass_id, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -0600288{
289 struct blk_desc *desc;
290 int ret;
291
Bin Meng9efc2452023-09-26 16:43:41 +0800292 ret = blk_get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600293 if (ret)
294 return ret;
295 printf("\nIDE device %d: ", devnum);
296 dev_print(desc);
297
298 return 0;
299}
300
Simon Glassfada3f92022-09-17 09:00:09 -0600301int blk_show_device(enum uclass_id uclass_id, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -0600302{
303 struct blk_desc *desc;
304 int ret;
305
306 printf("\nDevice %d: ", devnum);
Bin Meng9efc2452023-09-26 16:43:41 +0800307 ret = blk_get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600308 if (ret == -ENODEV || ret == -ENOENT) {
309 printf("unknown device\n");
310 return -ENODEV;
311 }
312 if (ret)
313 return ret;
314 dev_print(desc);
315
316 if (desc->type == DEV_TYPE_UNKNOWN)
317 return -ENOENT;
318
319 return 0;
320}
321
Simon Glass13c2c292016-05-01 13:52:30 -0600322int blk_select_hwpart(struct udevice *dev, int hwpart)
323{
324 const struct blk_ops *ops = blk_get_ops(dev);
325
326 if (!ops)
327 return -ENOSYS;
328 if (!ops->select_hwpart)
329 return 0;
330
331 return ops->select_hwpart(dev, hwpart);
332}
333
334int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
335{
developerf50d8d12019-08-27 15:32:18 +0800336 return blk_select_hwpart(desc->bdev, hwpart);
Simon Glass13c2c292016-05-01 13:52:30 -0600337}
338
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200339static int _blk_next_device(int uclass_id, struct udevice **devp)
Simon Glasscceee552016-02-29 15:25:55 -0700340{
341 struct blk_desc *desc;
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200342 int ret = 0;
343
344 for (; *devp; uclass_find_next_device(devp)) {
345 desc = dev_get_uclass_plat(*devp);
346 if (desc->uclass_id == uclass_id) {
347 ret = device_probe(*devp);
348 if (!ret)
349 return 0;
350 }
351 }
Simon Glasscceee552016-02-29 15:25:55 -0700352
Simon Glasscceee552016-02-29 15:25:55 -0700353 if (ret)
354 return ret;
Simon Glasscceee552016-02-29 15:25:55 -0700355
356 return -ENODEV;
357}
358
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200359int blk_first_device(int uclass_id, struct udevice **devp)
360{
361 uclass_find_first_device(UCLASS_BLK, devp);
362
363 return _blk_next_device(uclass_id, devp);
364}
365
Simon Glasscceee552016-02-29 15:25:55 -0700366int blk_next_device(struct udevice **devp)
367{
368 struct blk_desc *desc;
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200369 int uclass_id;
Simon Glasscceee552016-02-29 15:25:55 -0700370
Simon Glass71fa5b42020-12-03 16:55:18 -0700371 desc = dev_get_uclass_plat(*devp);
Simon Glassfada3f92022-09-17 09:00:09 -0600372 uclass_id = desc->uclass_id;
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200373 uclass_find_next_device(devp);
374
375 return _blk_next_device(uclass_id, devp);
Simon Glasscceee552016-02-29 15:25:55 -0700376}
377
Simon Glassfada3f92022-09-17 09:00:09 -0600378int blk_find_device(int uclass_id, int devnum, struct udevice **devp)
Simon Glasscceee552016-02-29 15:25:55 -0700379{
380 struct uclass *uc;
381 struct udevice *dev;
382 int ret;
383
384 ret = uclass_get(UCLASS_BLK, &uc);
385 if (ret)
386 return ret;
387 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700388 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700389
Simon Glassfada3f92022-09-17 09:00:09 -0600390 debug("%s: uclass_id=%d, devnum=%d: %s, %d, %d\n", __func__,
391 uclass_id, devnum, dev->name, desc->uclass_id, desc->devnum);
392 if (desc->uclass_id == uclass_id && desc->devnum == devnum) {
Simon Glasscceee552016-02-29 15:25:55 -0700393 *devp = dev;
Simon Glassd5d4c102017-04-23 20:02:05 -0600394 return 0;
Simon Glasscceee552016-02-29 15:25:55 -0700395 }
396 }
397
398 return -ENODEV;
399}
400
Simon Glassfada3f92022-09-17 09:00:09 -0600401int blk_get_device(int uclass_id, int devnum, struct udevice **devp)
Simon Glassd5d4c102017-04-23 20:02:05 -0600402{
403 int ret;
404
Simon Glassfada3f92022-09-17 09:00:09 -0600405 ret = blk_find_device(uclass_id, devnum, devp);
Simon Glassd5d4c102017-04-23 20:02:05 -0600406 if (ret)
407 return ret;
408
409 return device_probe(*devp);
410}
411
Marek Vasut847e24f2023-08-14 01:49:59 +0200412struct blk_bounce_buffer {
413 struct udevice *dev;
414 struct bounce_buffer state;
415};
416
417static int blk_buffer_aligned(struct bounce_buffer *state)
418{
419#if IS_ENABLED(CONFIG_BOUNCE_BUFFER)
420 struct blk_bounce_buffer *bbstate =
421 container_of(state, struct blk_bounce_buffer, state);
422 struct udevice *dev = bbstate->dev;
423 const struct blk_ops *ops = blk_get_ops(dev);
424
425 if (ops->buffer_aligned)
426 return ops->buffer_aligned(dev, state);
427#endif /* CONFIG_BOUNCE_BUFFER */
428
429 return 1; /* Default, any buffer is OK */
430}
431
Simon Glass18861002022-10-20 18:22:54 -0600432long blk_read(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *buf)
Simon Glasscceee552016-02-29 15:25:55 -0700433{
Simon Glass18861002022-10-20 18:22:54 -0600434 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700435 const struct blk_ops *ops = blk_get_ops(dev);
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700436 ulong blks_read;
Simon Glasscceee552016-02-29 15:25:55 -0700437
438 if (!ops->read)
439 return -ENOSYS;
440
Simon Glass18861002022-10-20 18:22:54 -0600441 if (blkcache_read(desc->uclass_id, desc->devnum,
442 start, blkcnt, desc->blksz, buf))
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700443 return blkcnt;
Marek Vasut847e24f2023-08-14 01:49:59 +0200444
Johan Jonker10a986c2023-10-18 16:01:10 +0200445 if (IS_ENABLED(CONFIG_BOUNCE_BUFFER) && desc->bb) {
Marek Vasut847e24f2023-08-14 01:49:59 +0200446 struct blk_bounce_buffer bbstate = { .dev = dev };
447 int ret;
448
449 ret = bounce_buffer_start_extalign(&bbstate.state, buf,
450 blkcnt * desc->blksz,
451 GEN_BB_WRITE, desc->blksz,
452 blk_buffer_aligned);
453 if (ret)
454 return ret;
455
456 blks_read = ops->read(dev, start, blkcnt, bbstate.state.bounce_buffer);
457
458 bounce_buffer_stop(&bbstate.state);
459 } else {
460 blks_read = ops->read(dev, start, blkcnt, buf);
461 }
462
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700463 if (blks_read == blkcnt)
Simon Glass18861002022-10-20 18:22:54 -0600464 blkcache_fill(desc->uclass_id, desc->devnum, start, blkcnt,
465 desc->blksz, buf);
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700466
467 return blks_read;
Simon Glasscceee552016-02-29 15:25:55 -0700468}
469
Simon Glass18861002022-10-20 18:22:54 -0600470long blk_write(struct udevice *dev, lbaint_t start, lbaint_t blkcnt,
471 const void *buf)
Simon Glasscceee552016-02-29 15:25:55 -0700472{
Simon Glass18861002022-10-20 18:22:54 -0600473 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700474 const struct blk_ops *ops = blk_get_ops(dev);
Marek Vasut847e24f2023-08-14 01:49:59 +0200475 long blks_written;
Simon Glasscceee552016-02-29 15:25:55 -0700476
477 if (!ops->write)
478 return -ENOSYS;
479
Simon Glass18861002022-10-20 18:22:54 -0600480 blkcache_invalidate(desc->uclass_id, desc->devnum);
481
Johan Jonker10a986c2023-10-18 16:01:10 +0200482 if (IS_ENABLED(CONFIG_BOUNCE_BUFFER) && desc->bb) {
Marek Vasut847e24f2023-08-14 01:49:59 +0200483 struct blk_bounce_buffer bbstate = { .dev = dev };
484 int ret;
485
486 ret = bounce_buffer_start_extalign(&bbstate.state, (void *)buf,
487 blkcnt * desc->blksz,
488 GEN_BB_READ, desc->blksz,
489 blk_buffer_aligned);
490 if (ret)
491 return ret;
492
493 blks_written = ops->write(dev, start, blkcnt,
494 bbstate.state.bounce_buffer);
495
496 bounce_buffer_stop(&bbstate.state);
497 } else {
498 blks_written = ops->write(dev, start, blkcnt, buf);
499 }
500
501 return blks_written;
Simon Glasscceee552016-02-29 15:25:55 -0700502}
503
Simon Glass18861002022-10-20 18:22:54 -0600504long blk_erase(struct udevice *dev, lbaint_t start, lbaint_t blkcnt)
Simon Glasscceee552016-02-29 15:25:55 -0700505{
Simon Glass18861002022-10-20 18:22:54 -0600506 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700507 const struct blk_ops *ops = blk_get_ops(dev);
508
509 if (!ops->erase)
510 return -ENOSYS;
511
Simon Glass18861002022-10-20 18:22:54 -0600512 blkcache_invalidate(desc->uclass_id, desc->devnum);
513
Simon Glasscceee552016-02-29 15:25:55 -0700514 return ops->erase(dev, start, blkcnt);
515}
516
Simon Glass18861002022-10-20 18:22:54 -0600517ulong blk_dread(struct blk_desc *desc, lbaint_t start, lbaint_t blkcnt,
518 void *buffer)
519{
520 return blk_read(desc->bdev, start, blkcnt, buffer);
521}
522
523ulong blk_dwrite(struct blk_desc *desc, lbaint_t start, lbaint_t blkcnt,
524 const void *buffer)
525{
526 return blk_write(desc->bdev, start, blkcnt, buffer);
527}
528
529ulong blk_derase(struct blk_desc *desc, lbaint_t start, lbaint_t blkcnt)
530{
531 return blk_erase(desc->bdev, start, blkcnt);
532}
533
Simon Glassc0bcaaf2022-10-29 19:47:14 -0600534int blk_find_from_parent(struct udevice *parent, struct udevice **devp)
Simon Glass4f269132017-05-27 11:37:17 -0600535{
536 struct udevice *dev;
Simon Glass4f269132017-05-27 11:37:17 -0600537
Simon Glassc0bcaaf2022-10-29 19:47:14 -0600538 if (device_find_first_child_by_uclass(parent, UCLASS_BLK, &dev)) {
Simon Glass4f269132017-05-27 11:37:17 -0600539 debug("%s: No block device found for parent '%s'\n", __func__,
540 parent->name);
541 return -ENODEV;
542 }
Simon Glassc0bcaaf2022-10-29 19:47:14 -0600543 *devp = dev;
544
545 return 0;
546}
547
548int blk_get_from_parent(struct udevice *parent, struct udevice **devp)
549{
550 struct udevice *dev;
551 int ret;
552
553 ret = blk_find_from_parent(parent, &dev);
554 if (ret)
555 return ret;
Simon Glass4f269132017-05-27 11:37:17 -0600556 ret = device_probe(dev);
557 if (ret)
558 return ret;
559 *devp = dev;
560
561 return 0;
562}
563
Simon Glassf3086cf2022-04-24 23:31:03 -0600564const char *blk_get_devtype(struct udevice *dev)
565{
566 struct udevice *parent = dev_get_parent(dev);
567
568 return uclass_get_name(device_get_uclass_id(parent));
569};
570
Simon Glassfada3f92022-09-17 09:00:09 -0600571int blk_find_max_devnum(enum uclass_id uclass_id)
Simon Glassd089ba32016-05-01 11:36:28 -0600572{
573 struct udevice *dev;
574 int max_devnum = -ENODEV;
575 struct uclass *uc;
576 int ret;
577
578 ret = uclass_get(UCLASS_BLK, &uc);
579 if (ret)
580 return ret;
581 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700582 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glassd089ba32016-05-01 11:36:28 -0600583
Simon Glassfada3f92022-09-17 09:00:09 -0600584 if (desc->uclass_id == uclass_id && desc->devnum > max_devnum)
Simon Glassd089ba32016-05-01 11:36:28 -0600585 max_devnum = desc->devnum;
586 }
587
588 return max_devnum;
589}
590
Simon Glassfada3f92022-09-17 09:00:09 -0600591int blk_next_free_devnum(enum uclass_id uclass_id)
Simon Glassdbc38612017-04-23 20:02:06 -0600592{
593 int ret;
594
Simon Glassfada3f92022-09-17 09:00:09 -0600595 ret = blk_find_max_devnum(uclass_id);
Simon Glassdbc38612017-04-23 20:02:06 -0600596 if (ret == -ENODEV)
597 return 0;
598 if (ret < 0)
599 return ret;
600
601 return ret + 1;
602}
603
Simon Glassfc7a7442021-07-05 16:32:59 -0600604static int blk_flags_check(struct udevice *dev, enum blk_flag_t req_flags)
605{
606 const struct blk_desc *desc = dev_get_uclass_plat(dev);
607 enum blk_flag_t flags;
608
609 flags = desc->removable ? BLKF_REMOVABLE : BLKF_FIXED;
610
611 return flags & req_flags ? 0 : 1;
612}
613
Simon Glass8e61f932022-02-28 12:08:35 -0700614int blk_find_first(enum blk_flag_t flags, struct udevice **devp)
615{
616 int ret;
617
618 for (ret = uclass_find_first_device(UCLASS_BLK, devp);
619 *devp && !blk_flags_check(*devp, flags);
620 ret = uclass_find_next_device(devp))
621 return 0;
622
623 return -ENODEV;
624}
625
626int blk_find_next(enum blk_flag_t flags, struct udevice **devp)
627{
628 int ret;
629
630 for (ret = uclass_find_next_device(devp);
631 *devp && !blk_flags_check(*devp, flags);
632 ret = uclass_find_next_device(devp))
633 return 0;
634
635 return -ENODEV;
636}
637
Simon Glassfc7a7442021-07-05 16:32:59 -0600638int blk_first_device_err(enum blk_flag_t flags, struct udevice **devp)
639{
Michal Suchanekac9e9fc2022-10-12 21:58:01 +0200640 for (uclass_first_device(UCLASS_BLK, devp);
641 *devp;
642 uclass_next_device(devp)) {
Simon Glassfc7a7442021-07-05 16:32:59 -0600643 if (!blk_flags_check(*devp, flags))
644 return 0;
645 }
646
647 return -ENODEV;
648}
649
650int blk_next_device_err(enum blk_flag_t flags, struct udevice **devp)
651{
Michal Suchanekac9e9fc2022-10-12 21:58:01 +0200652 for (uclass_next_device(devp);
653 *devp;
654 uclass_next_device(devp)) {
Simon Glassfc7a7442021-07-05 16:32:59 -0600655 if (!blk_flags_check(*devp, flags))
656 return 0;
657 }
658
659 return -ENODEV;
660}
661
662int blk_count_devices(enum blk_flag_t flag)
663{
664 struct udevice *dev;
665 int count = 0;
666
667 blk_foreach_probe(flag, dev)
668 count++;
669
670 return count;
671}
672
Simon Glassfada3f92022-09-17 09:00:09 -0600673static int blk_claim_devnum(enum uclass_id uclass_id, int devnum)
Simon Glasse4fef742017-04-23 20:02:07 -0600674{
675 struct udevice *dev;
676 struct uclass *uc;
677 int ret;
678
679 ret = uclass_get(UCLASS_BLK, &uc);
680 if (ret)
681 return ret;
682 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700683 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasse4fef742017-04-23 20:02:07 -0600684
Simon Glassfada3f92022-09-17 09:00:09 -0600685 if (desc->uclass_id == uclass_id && desc->devnum == devnum) {
686 int next = blk_next_free_devnum(uclass_id);
Simon Glasse4fef742017-04-23 20:02:07 -0600687
688 if (next < 0)
689 return next;
690 desc->devnum = next;
691 return 0;
692 }
693 }
694
695 return -ENOENT;
696}
697
Simon Glasscceee552016-02-29 15:25:55 -0700698int blk_create_device(struct udevice *parent, const char *drv_name,
Simon Glassfada3f92022-09-17 09:00:09 -0600699 const char *name, int uclass_id, int devnum, int blksz,
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200700 lbaint_t lba, struct udevice **devp)
Simon Glasscceee552016-02-29 15:25:55 -0700701{
702 struct blk_desc *desc;
703 struct udevice *dev;
704 int ret;
705
Simon Glassd089ba32016-05-01 11:36:28 -0600706 if (devnum == -1) {
Simon Glassfada3f92022-09-17 09:00:09 -0600707 devnum = blk_next_free_devnum(uclass_id);
Simon Glasse4fef742017-04-23 20:02:07 -0600708 } else {
Simon Glassfada3f92022-09-17 09:00:09 -0600709 ret = blk_claim_devnum(uclass_id, devnum);
Simon Glasse4fef742017-04-23 20:02:07 -0600710 if (ret < 0 && ret != -ENOENT)
Simon Glassd089ba32016-05-01 11:36:28 -0600711 return ret;
Simon Glassd089ba32016-05-01 11:36:28 -0600712 }
Simon Glasse4fef742017-04-23 20:02:07 -0600713 if (devnum < 0)
714 return devnum;
Simon Glass77f7fb82016-05-01 13:52:22 -0600715 ret = device_bind_driver(parent, drv_name, name, &dev);
716 if (ret)
717 return ret;
Simon Glass71fa5b42020-12-03 16:55:18 -0700718 desc = dev_get_uclass_plat(dev);
Simon Glassfada3f92022-09-17 09:00:09 -0600719 desc->uclass_id = uclass_id;
Simon Glass77f7fb82016-05-01 13:52:22 -0600720 desc->blksz = blksz;
Heinrich Schuchardt09ba4ea2019-10-25 12:15:31 +0200721 desc->log2blksz = LOG2(desc->blksz);
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200722 desc->lba = lba;
Simon Glass77f7fb82016-05-01 13:52:22 -0600723 desc->part_type = PART_TYPE_UNKNOWN;
724 desc->bdev = dev;
Simon Glasscceee552016-02-29 15:25:55 -0700725 desc->devnum = devnum;
726 *devp = dev;
727
728 return 0;
729}
730
Simon Glass966b6952016-05-01 11:36:29 -0600731int blk_create_devicef(struct udevice *parent, const char *drv_name,
Simon Glassfada3f92022-09-17 09:00:09 -0600732 const char *name, int uclass_id, int devnum, int blksz,
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200733 lbaint_t lba, struct udevice **devp)
Simon Glass966b6952016-05-01 11:36:29 -0600734{
735 char dev_name[30], *str;
Simon Glass39e54922016-05-01 13:52:24 -0600736 int ret;
Simon Glass966b6952016-05-01 11:36:29 -0600737
738 snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name);
739 str = strdup(dev_name);
740 if (!str)
741 return -ENOMEM;
742
Simon Glassfada3f92022-09-17 09:00:09 -0600743 ret = blk_create_device(parent, drv_name, str, uclass_id, devnum,
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200744 blksz, lba, devp);
Simon Glass39e54922016-05-01 13:52:24 -0600745 if (ret) {
746 free(str);
747 return ret;
748 }
749 device_set_name_alloced(*devp);
750
Simon Glass44505972017-07-29 11:34:59 -0600751 return 0;
Simon Glass966b6952016-05-01 11:36:29 -0600752}
753
AKASHI Takahiro3e32dbe2021-12-10 15:49:29 +0900754int blk_probe_or_unbind(struct udevice *dev)
755{
756 int ret;
757
758 ret = device_probe(dev);
759 if (ret) {
760 log_debug("probing %s failed\n", dev->name);
761 device_unbind(dev);
762 }
763
764 return ret;
765}
766
Simon Glassfada3f92022-09-17 09:00:09 -0600767int blk_unbind_all(int uclass_id)
Simon Glasscceee552016-02-29 15:25:55 -0700768{
769 struct uclass *uc;
770 struct udevice *dev, *next;
771 int ret;
772
773 ret = uclass_get(UCLASS_BLK, &uc);
774 if (ret)
775 return ret;
776 uclass_foreach_dev_safe(dev, next, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700777 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700778
Simon Glassfada3f92022-09-17 09:00:09 -0600779 if (desc->uclass_id == uclass_id) {
Stefan Roese80b5bc92017-03-20 12:51:48 +0100780 ret = device_remove(dev, DM_REMOVE_NORMAL);
Simon Glasscceee552016-02-29 15:25:55 -0700781 if (ret)
782 return ret;
783 ret = device_unbind(dev);
784 if (ret)
785 return ret;
786 }
787 }
788
789 return 0;
790}
791
Marek Vasut14fafef2023-08-14 01:46:47 +0200792static int part_create_block_devices(struct udevice *blk_dev)
793{
794 int part, count;
795 struct blk_desc *desc = dev_get_uclass_plat(blk_dev);
796 struct disk_partition info;
797 struct disk_part *part_data;
798 char devname[32];
799 struct udevice *dev;
800 int ret;
801
802 if (!CONFIG_IS_ENABLED(PARTITIONS) || !blk_enabled())
803 return 0;
804
805 if (device_get_uclass_id(blk_dev) != UCLASS_BLK)
806 return 0;
807
808 /* Add devices for each partition */
809 for (count = 0, part = 1; part <= MAX_SEARCH_PARTITIONS; part++) {
810 if (part_get_info(desc, part, &info))
811 continue;
812 snprintf(devname, sizeof(devname), "%s:%d", blk_dev->name,
813 part);
814
815 ret = device_bind_driver(blk_dev, "blk_partition",
816 strdup(devname), &dev);
817 if (ret)
818 return ret;
819
820 part_data = dev_get_uclass_plat(dev);
821 part_data->partnum = part;
822 part_data->gpt_part_info = info;
823 count++;
824
825 ret = device_probe(dev);
826 if (ret) {
827 debug("Can't probe\n");
828 count--;
829 device_unbind(dev);
830
831 continue;
832 }
833 }
834 debug("%s: %d partitions found in %s\n", __func__, count,
835 blk_dev->name);
836
837 return 0;
838}
839
Bin Mengcbc3da82018-10-15 02:21:07 -0700840static int blk_post_probe(struct udevice *dev)
841{
Simon Glassf5ac3032022-08-11 19:34:45 -0600842 if (CONFIG_IS_ENABLED(PARTITIONS) && blk_enabled()) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700843 struct blk_desc *desc = dev_get_uclass_plat(dev);
Bin Mengcbc3da82018-10-15 02:21:07 -0700844
Ovidiu Panait76160a02020-07-24 14:12:21 +0300845 part_init(desc);
AKASHI Takahiro358e6c72022-04-19 10:05:10 +0900846
847 if (desc->part_type != PART_TYPE_UNKNOWN &&
848 part_create_block_devices(dev))
849 debug("*** creating partitions failed\n");
Ovidiu Panait76160a02020-07-24 14:12:21 +0300850 }
Bin Mengcbc3da82018-10-15 02:21:07 -0700851
852 return 0;
853}
854
Simon Glasscceee552016-02-29 15:25:55 -0700855UCLASS_DRIVER(blk) = {
856 .id = UCLASS_BLK,
857 .name = "blk",
Bin Mengcbc3da82018-10-15 02:21:07 -0700858 .post_probe = blk_post_probe,
Simon Glass71fa5b42020-12-03 16:55:18 -0700859 .per_device_plat_auto = sizeof(struct blk_desc),
Simon Glasscceee552016-02-29 15:25:55 -0700860};