blob: c69fc4d518292192281e8357cde31106135dd83d [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 <common.h>
10#include <blk.h>
11#include <dm.h>
Simon Glass0f2af882020-05-10 11:40:05 -060012#include <log.h>
Simon Glass9bc15642020-02-03 07:36:16 -070013#include <malloc.h>
Simon Glass655306c2020-05-10 11:39:58 -060014#include <part.h>
Simon Glasscceee552016-02-29 15:25:55 -070015#include <dm/device-internal.h>
16#include <dm/lists.h>
Stefan Roeseef58a902017-11-29 16:46:42 +010017#include <dm/uclass-internal.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070018#include <linux/err.h>
Simon Glasscceee552016-02-29 15:25:55 -070019
Simon Glass95e6e032022-08-11 19:34:57 -060020static struct {
21 enum uclass_id id;
22 const char *name;
Simon Glassfada3f92022-09-17 09:00:09 -060023} uclass_idname_str[] = {
Simon Glassdbfa32c2022-08-11 19:34:59 -060024 { UCLASS_IDE, "ide" },
25 { UCLASS_SCSI, "scsi" },
26 { UCLASS_USB, "usb" },
27 { UCLASS_MMC, "mmc" },
28 { UCLASS_AHCI, "sata" },
Simon Glasse57f8d42022-10-29 19:47:17 -060029 { UCLASS_HOST, "host" },
Simon Glassdbfa32c2022-08-11 19:34:59 -060030 { UCLASS_NVME, "nvme" },
31 { UCLASS_EFI_MEDIA, "efi" },
32 { UCLASS_EFI_LOADER, "efiloader" },
33 { UCLASS_VIRTIO, "virtio" },
34 { UCLASS_PVBLOCK, "pvblock" },
Simon Glass4131ad52016-05-01 11:36:08 -060035};
36
Simon Glassfada3f92022-09-17 09:00:09 -060037static enum uclass_id uclass_name_to_iftype(const char *uclass_idname)
Simon Glass4131ad52016-05-01 11:36:08 -060038{
39 int i;
40
Simon Glassfada3f92022-09-17 09:00:09 -060041 for (i = 0; i < ARRAY_SIZE(uclass_idname_str); i++) {
42 if (!strcmp(uclass_idname, uclass_idname_str[i].name))
43 return uclass_idname_str[i].id;
Simon Glass4131ad52016-05-01 11:36:08 -060044 }
45
Simon Glassdbfa32c2022-08-11 19:34:59 -060046 return UCLASS_INVALID;
Simon Glass4131ad52016-05-01 11:36:08 -060047}
48
Simon Glassfada3f92022-09-17 09:00:09 -060049static enum uclass_id conv_uclass_id(enum uclass_id uclass_id)
Simon Glass4131ad52016-05-01 11:36:08 -060050{
Simon Glassdbfa32c2022-08-11 19:34:59 -060051 /*
52 * This strange adjustment is used because we use UCLASS_MASS_STORAGE
53 * for USB storage devices, so need to return this as the uclass to
54 * use for USB. In fact USB_UCLASS is for USB controllers, not
55 * peripherals.
56 *
57 * The name of the UCLASS_MASS_STORAGE uclass driver is
58 * "usb_mass_storage", but we want to use "usb" in things like the
59 * 'part list' command and when showing interfaces.
60 *
61 * So for now we have this one-way conversion.
62 *
63 * The fix for this is possibly to:
64 * - rename UCLASS_MASS_STORAGE name to "usb"
65 * - rename UCLASS_USB name to "usb_ctlr"
66 * - use UCLASS_MASS_STORAGE instead of UCLASS_USB in if_typename_str
67 */
Simon Glassfada3f92022-09-17 09:00:09 -060068 if (uclass_id == UCLASS_USB)
Simon Glassdbfa32c2022-08-11 19:34:59 -060069 return UCLASS_MASS_STORAGE;
Simon Glassfada3f92022-09-17 09:00:09 -060070 return uclass_id;
Simon Glass4131ad52016-05-01 11:36:08 -060071}
72
Simon Glassfada3f92022-09-17 09:00:09 -060073const char *blk_get_uclass_name(enum uclass_id uclass_id)
Simon Glass85af5a42017-07-29 11:34:53 -060074{
Simon Glass95e6e032022-08-11 19:34:57 -060075 int i;
76
Simon Glassfada3f92022-09-17 09:00:09 -060077 for (i = 0; i < ARRAY_SIZE(uclass_idname_str); i++) {
78 if (uclass_idname_str[i].id == uclass_id)
79 return uclass_idname_str[i].name;
Simon Glass95e6e032022-08-11 19:34:57 -060080 }
81
82 return "(none)";
Simon Glass85af5a42017-07-29 11:34:53 -060083}
84
Simon Glassfada3f92022-09-17 09:00:09 -060085struct blk_desc *blk_get_devnum_by_uclass_id(enum uclass_id uclass_id, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -060086{
87 struct blk_desc *desc;
88 struct udevice *dev;
89 int ret;
90
Simon Glassfada3f92022-09-17 09:00:09 -060091 ret = blk_get_device(uclass_id, devnum, &dev);
Simon Glass4131ad52016-05-01 11:36:08 -060092 if (ret)
93 return NULL;
Simon Glass71fa5b42020-12-03 16:55:18 -070094 desc = dev_get_uclass_plat(dev);
Simon Glass4131ad52016-05-01 11:36:08 -060095
96 return desc;
97}
98
99/*
100 * This function is complicated with driver model. We look up the interface
101 * name in a local table. This gives us an interface type which we can match
102 * against the uclass of the block device's parent.
103 */
Simon Glassfada3f92022-09-17 09:00:09 -0600104struct blk_desc *blk_get_devnum_by_uclass_idname(const char *uclass_idname, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -0600105{
106 enum uclass_id uclass_id;
Simon Glass57b3d2e2022-08-11 19:35:01 -0600107 enum uclass_id type;
Simon Glass4131ad52016-05-01 11:36:08 -0600108 struct udevice *dev;
109 struct uclass *uc;
110 int ret;
111
Simon Glassfada3f92022-09-17 09:00:09 -0600112 type = uclass_name_to_iftype(uclass_idname);
Simon Glassdbfa32c2022-08-11 19:34:59 -0600113 if (type == UCLASS_INVALID) {
Simon Glass4131ad52016-05-01 11:36:08 -0600114 debug("%s: Unknown interface type '%s'\n", __func__,
Simon Glassfada3f92022-09-17 09:00:09 -0600115 uclass_idname);
Simon Glass4131ad52016-05-01 11:36:08 -0600116 return NULL;
117 }
Simon Glassfada3f92022-09-17 09:00:09 -0600118 uclass_id = conv_uclass_id(type);
Simon Glass4131ad52016-05-01 11:36:08 -0600119 if (uclass_id == UCLASS_INVALID) {
120 debug("%s: Unknown uclass for interface type'\n",
Simon Glassfada3f92022-09-17 09:00:09 -0600121 blk_get_uclass_name(type));
Simon Glass4131ad52016-05-01 11:36:08 -0600122 return NULL;
123 }
124
125 ret = uclass_get(UCLASS_BLK, &uc);
126 if (ret)
127 return NULL;
128 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700129 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glass4131ad52016-05-01 11:36:08 -0600130
Simon Glassfada3f92022-09-17 09:00:09 -0600131 debug("%s: uclass_id=%d, devnum=%d: %s, %d, %d\n", __func__,
132 type, devnum, dev->name, desc->uclass_id, desc->devnum);
Simon Glass4131ad52016-05-01 11:36:08 -0600133 if (desc->devnum != devnum)
134 continue;
135
136 /* Find out the parent device uclass */
137 if (device_get_uclass_id(dev->parent) != uclass_id) {
138 debug("%s: parent uclass %d, this dev %d\n", __func__,
139 device_get_uclass_id(dev->parent), uclass_id);
140 continue;
141 }
142
143 if (device_probe(dev))
144 return NULL;
145
146 debug("%s: Device desc %p\n", __func__, desc);
147 return desc;
148 }
149 debug("%s: No device found\n", __func__);
150
151 return NULL;
152}
153
154/**
Tien Fong Chee10378522018-07-06 16:26:36 +0800155 * blk_get_by_device() - Get the block device descriptor for the given device
156 * @dev: Instance of a storage device
157 *
158 * Return: With block device descriptor on success , NULL if there is no such
159 * block device.
160 */
161struct blk_desc *blk_get_by_device(struct udevice *dev)
162{
Simon Glasscfd72932019-09-25 08:55:56 -0600163 struct udevice *child_dev;
Tien Fong Chee10378522018-07-06 16:26:36 +0800164
Simon Glasscfd72932019-09-25 08:55:56 -0600165 device_foreach_child(child_dev, dev) {
Tien Fong Chee10378522018-07-06 16:26:36 +0800166 if (device_get_uclass_id(child_dev) != UCLASS_BLK)
167 continue;
168
Simon Glass71fa5b42020-12-03 16:55:18 -0700169 return dev_get_uclass_plat(child_dev);
Tien Fong Chee10378522018-07-06 16:26:36 +0800170 }
171
172 debug("%s: No block device found\n", __func__);
173
174 return NULL;
175}
176
177/**
Simon Glass4131ad52016-05-01 11:36:08 -0600178 * get_desc() - Get the block device descriptor for the given device number
179 *
Simon Glassfada3f92022-09-17 09:00:09 -0600180 * @uclass_id: Interface type
Simon Glass4131ad52016-05-01 11:36:08 -0600181 * @devnum: Device number (0 = first)
182 * @descp: Returns block device descriptor on success
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100183 * Return: 0 on success, -ENODEV if there is no such device and no device
Simon Glass4131ad52016-05-01 11:36:08 -0600184 * with a higher device number, -ENOENT if there is no such device but there
185 * is one with a higher number, or other -ve on other error.
186 */
Simon Glassfada3f92022-09-17 09:00:09 -0600187static int get_desc(enum uclass_id uclass_id, int devnum, struct blk_desc **descp)
Simon Glass4131ad52016-05-01 11:36:08 -0600188{
189 bool found_more = false;
190 struct udevice *dev;
191 struct uclass *uc;
192 int ret;
193
194 *descp = NULL;
195 ret = uclass_get(UCLASS_BLK, &uc);
196 if (ret)
197 return ret;
198 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700199 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glass4131ad52016-05-01 11:36:08 -0600200
Simon Glassfada3f92022-09-17 09:00:09 -0600201 debug("%s: uclass_id=%d, devnum=%d: %s, %d, %d\n", __func__,
202 uclass_id, devnum, dev->name, desc->uclass_id, desc->devnum);
203 if (desc->uclass_id == uclass_id) {
Simon Glass4131ad52016-05-01 11:36:08 -0600204 if (desc->devnum == devnum) {
205 ret = device_probe(dev);
206 if (ret)
207 return ret;
208
Michal Simekf438b6b2016-11-16 17:37:42 +0100209 *descp = desc;
210 return 0;
Simon Glass4131ad52016-05-01 11:36:08 -0600211 } else if (desc->devnum > devnum) {
212 found_more = true;
213 }
214 }
215 }
216
217 return found_more ? -ENOENT : -ENODEV;
218}
219
Simon Glassfada3f92022-09-17 09:00:09 -0600220int blk_select_hwpart_devnum(enum uclass_id uclass_id, int devnum, int hwpart)
Simon Glass13c2c292016-05-01 13:52:30 -0600221{
222 struct udevice *dev;
223 int ret;
224
Simon Glassfada3f92022-09-17 09:00:09 -0600225 ret = blk_get_device(uclass_id, devnum, &dev);
Simon Glass13c2c292016-05-01 13:52:30 -0600226 if (ret)
227 return ret;
228
developerf50d8d12019-08-27 15:32:18 +0800229 return blk_select_hwpart(dev, hwpart);
Simon Glass13c2c292016-05-01 13:52:30 -0600230}
231
Simon Glassfada3f92022-09-17 09:00:09 -0600232int blk_list_part(enum uclass_id uclass_id)
Simon Glass4131ad52016-05-01 11:36:08 -0600233{
234 struct blk_desc *desc;
235 int devnum, ok;
236 int ret;
237
238 for (ok = 0, devnum = 0;; ++devnum) {
Simon Glassfada3f92022-09-17 09:00:09 -0600239 ret = get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600240 if (ret == -ENODEV)
241 break;
242 else if (ret)
243 continue;
244 if (desc->part_type != PART_TYPE_UNKNOWN) {
245 ++ok;
246 if (devnum)
247 putc('\n');
248 part_print(desc);
249 }
250 }
251 if (!ok)
252 return -ENODEV;
253
254 return 0;
255}
256
Simon Glassfada3f92022-09-17 09:00:09 -0600257int blk_print_part_devnum(enum uclass_id uclass_id, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -0600258{
259 struct blk_desc *desc;
260 int ret;
261
Simon Glassfada3f92022-09-17 09:00:09 -0600262 ret = get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600263 if (ret)
264 return ret;
265 if (desc->type == DEV_TYPE_UNKNOWN)
266 return -ENOENT;
267 part_print(desc);
268
269 return 0;
270}
271
Simon Glassfada3f92022-09-17 09:00:09 -0600272void blk_list_devices(enum uclass_id uclass_id)
Simon Glass4131ad52016-05-01 11:36:08 -0600273{
274 struct blk_desc *desc;
275 int ret;
276 int i;
277
278 for (i = 0;; ++i) {
Simon Glassfada3f92022-09-17 09:00:09 -0600279 ret = get_desc(uclass_id, i, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600280 if (ret == -ENODEV)
281 break;
282 else if (ret)
283 continue;
284 if (desc->type == DEV_TYPE_UNKNOWN)
285 continue; /* list only known devices */
286 printf("Device %d: ", i);
287 dev_print(desc);
288 }
289}
290
Simon Glassfada3f92022-09-17 09:00:09 -0600291int blk_print_device_num(enum uclass_id uclass_id, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -0600292{
293 struct blk_desc *desc;
294 int ret;
295
Simon Glassfada3f92022-09-17 09:00:09 -0600296 ret = get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600297 if (ret)
298 return ret;
299 printf("\nIDE device %d: ", devnum);
300 dev_print(desc);
301
302 return 0;
303}
304
Simon Glassfada3f92022-09-17 09:00:09 -0600305int blk_show_device(enum uclass_id uclass_id, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -0600306{
307 struct blk_desc *desc;
308 int ret;
309
310 printf("\nDevice %d: ", devnum);
Simon Glassfada3f92022-09-17 09:00:09 -0600311 ret = get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600312 if (ret == -ENODEV || ret == -ENOENT) {
313 printf("unknown device\n");
314 return -ENODEV;
315 }
316 if (ret)
317 return ret;
318 dev_print(desc);
319
320 if (desc->type == DEV_TYPE_UNKNOWN)
321 return -ENOENT;
322
323 return 0;
324}
325
Simon Glassfada3f92022-09-17 09:00:09 -0600326ulong blk_read_devnum(enum uclass_id uclass_id, int devnum, lbaint_t start,
Simon Glass4131ad52016-05-01 11:36:08 -0600327 lbaint_t blkcnt, void *buffer)
328{
329 struct blk_desc *desc;
330 ulong n;
331 int ret;
332
Simon Glassfada3f92022-09-17 09:00:09 -0600333 ret = get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600334 if (ret)
335 return ret;
336 n = blk_dread(desc, start, blkcnt, buffer);
337 if (IS_ERR_VALUE(n))
338 return n;
339
Simon Glass4131ad52016-05-01 11:36:08 -0600340 return n;
341}
342
Simon Glassfada3f92022-09-17 09:00:09 -0600343ulong blk_write_devnum(enum uclass_id uclass_id, int devnum, lbaint_t start,
Simon Glass4131ad52016-05-01 11:36:08 -0600344 lbaint_t blkcnt, const void *buffer)
345{
346 struct blk_desc *desc;
347 int ret;
348
Simon Glassfada3f92022-09-17 09:00:09 -0600349 ret = get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600350 if (ret)
351 return ret;
352 return blk_dwrite(desc, start, blkcnt, buffer);
353}
354
Simon Glass13c2c292016-05-01 13:52:30 -0600355int blk_select_hwpart(struct udevice *dev, int hwpart)
356{
357 const struct blk_ops *ops = blk_get_ops(dev);
358
359 if (!ops)
360 return -ENOSYS;
361 if (!ops->select_hwpart)
362 return 0;
363
364 return ops->select_hwpart(dev, hwpart);
365}
366
367int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
368{
developerf50d8d12019-08-27 15:32:18 +0800369 return blk_select_hwpart(desc->bdev, hwpart);
Simon Glass13c2c292016-05-01 13:52:30 -0600370}
371
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200372static int _blk_next_device(int uclass_id, struct udevice **devp)
Simon Glasscceee552016-02-29 15:25:55 -0700373{
374 struct blk_desc *desc;
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200375 int ret = 0;
376
377 for (; *devp; uclass_find_next_device(devp)) {
378 desc = dev_get_uclass_plat(*devp);
379 if (desc->uclass_id == uclass_id) {
380 ret = device_probe(*devp);
381 if (!ret)
382 return 0;
383 }
384 }
Simon Glasscceee552016-02-29 15:25:55 -0700385
Simon Glasscceee552016-02-29 15:25:55 -0700386 if (ret)
387 return ret;
Simon Glasscceee552016-02-29 15:25:55 -0700388
389 return -ENODEV;
390}
391
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200392int blk_first_device(int uclass_id, struct udevice **devp)
393{
394 uclass_find_first_device(UCLASS_BLK, devp);
395
396 return _blk_next_device(uclass_id, devp);
397}
398
Simon Glasscceee552016-02-29 15:25:55 -0700399int blk_next_device(struct udevice **devp)
400{
401 struct blk_desc *desc;
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200402 int uclass_id;
Simon Glasscceee552016-02-29 15:25:55 -0700403
Simon Glass71fa5b42020-12-03 16:55:18 -0700404 desc = dev_get_uclass_plat(*devp);
Simon Glassfada3f92022-09-17 09:00:09 -0600405 uclass_id = desc->uclass_id;
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200406 uclass_find_next_device(devp);
407
408 return _blk_next_device(uclass_id, devp);
Simon Glasscceee552016-02-29 15:25:55 -0700409}
410
Simon Glassfada3f92022-09-17 09:00:09 -0600411int blk_find_device(int uclass_id, int devnum, struct udevice **devp)
Simon Glasscceee552016-02-29 15:25:55 -0700412{
413 struct uclass *uc;
414 struct udevice *dev;
415 int ret;
416
417 ret = uclass_get(UCLASS_BLK, &uc);
418 if (ret)
419 return ret;
420 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700421 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700422
Simon Glassfada3f92022-09-17 09:00:09 -0600423 debug("%s: uclass_id=%d, devnum=%d: %s, %d, %d\n", __func__,
424 uclass_id, devnum, dev->name, desc->uclass_id, desc->devnum);
425 if (desc->uclass_id == uclass_id && desc->devnum == devnum) {
Simon Glasscceee552016-02-29 15:25:55 -0700426 *devp = dev;
Simon Glassd5d4c102017-04-23 20:02:05 -0600427 return 0;
Simon Glasscceee552016-02-29 15:25:55 -0700428 }
429 }
430
431 return -ENODEV;
432}
433
Simon Glassfada3f92022-09-17 09:00:09 -0600434int blk_get_device(int uclass_id, int devnum, struct udevice **devp)
Simon Glassd5d4c102017-04-23 20:02:05 -0600435{
436 int ret;
437
Simon Glassfada3f92022-09-17 09:00:09 -0600438 ret = blk_find_device(uclass_id, devnum, devp);
Simon Glassd5d4c102017-04-23 20:02:05 -0600439 if (ret)
440 return ret;
441
442 return device_probe(*devp);
443}
444
Simon Glass18861002022-10-20 18:22:54 -0600445long blk_read(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *buf)
Simon Glasscceee552016-02-29 15:25:55 -0700446{
Simon Glass18861002022-10-20 18:22:54 -0600447 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700448 const struct blk_ops *ops = blk_get_ops(dev);
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700449 ulong blks_read;
Simon Glasscceee552016-02-29 15:25:55 -0700450
451 if (!ops->read)
452 return -ENOSYS;
453
Simon Glass18861002022-10-20 18:22:54 -0600454 if (blkcache_read(desc->uclass_id, desc->devnum,
455 start, blkcnt, desc->blksz, buf))
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700456 return blkcnt;
Simon Glass18861002022-10-20 18:22:54 -0600457 blks_read = ops->read(dev, start, blkcnt, buf);
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700458 if (blks_read == blkcnt)
Simon Glass18861002022-10-20 18:22:54 -0600459 blkcache_fill(desc->uclass_id, desc->devnum, start, blkcnt,
460 desc->blksz, buf);
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700461
462 return blks_read;
Simon Glasscceee552016-02-29 15:25:55 -0700463}
464
Simon Glass18861002022-10-20 18:22:54 -0600465long blk_write(struct udevice *dev, lbaint_t start, lbaint_t blkcnt,
466 const void *buf)
Simon Glasscceee552016-02-29 15:25:55 -0700467{
Simon Glass18861002022-10-20 18:22:54 -0600468 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700469 const struct blk_ops *ops = blk_get_ops(dev);
470
471 if (!ops->write)
472 return -ENOSYS;
473
Simon Glass18861002022-10-20 18:22:54 -0600474 blkcache_invalidate(desc->uclass_id, desc->devnum);
475
476 return ops->write(dev, start, blkcnt, buf);
Simon Glasscceee552016-02-29 15:25:55 -0700477}
478
Simon Glass18861002022-10-20 18:22:54 -0600479long blk_erase(struct udevice *dev, lbaint_t start, lbaint_t blkcnt)
Simon Glasscceee552016-02-29 15:25:55 -0700480{
Simon Glass18861002022-10-20 18:22:54 -0600481 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700482 const struct blk_ops *ops = blk_get_ops(dev);
483
484 if (!ops->erase)
485 return -ENOSYS;
486
Simon Glass18861002022-10-20 18:22:54 -0600487 blkcache_invalidate(desc->uclass_id, desc->devnum);
488
Simon Glasscceee552016-02-29 15:25:55 -0700489 return ops->erase(dev, start, blkcnt);
490}
491
Simon Glass18861002022-10-20 18:22:54 -0600492ulong blk_dread(struct blk_desc *desc, lbaint_t start, lbaint_t blkcnt,
493 void *buffer)
494{
495 return blk_read(desc->bdev, start, blkcnt, buffer);
496}
497
498ulong blk_dwrite(struct blk_desc *desc, lbaint_t start, lbaint_t blkcnt,
499 const void *buffer)
500{
501 return blk_write(desc->bdev, start, blkcnt, buffer);
502}
503
504ulong blk_derase(struct blk_desc *desc, lbaint_t start, lbaint_t blkcnt)
505{
506 return blk_erase(desc->bdev, start, blkcnt);
507}
508
Simon Glassc0bcaaf2022-10-29 19:47:14 -0600509int blk_find_from_parent(struct udevice *parent, struct udevice **devp)
Simon Glass4f269132017-05-27 11:37:17 -0600510{
511 struct udevice *dev;
Simon Glass4f269132017-05-27 11:37:17 -0600512
Simon Glassc0bcaaf2022-10-29 19:47:14 -0600513 if (device_find_first_child_by_uclass(parent, UCLASS_BLK, &dev)) {
Simon Glass4f269132017-05-27 11:37:17 -0600514 debug("%s: No block device found for parent '%s'\n", __func__,
515 parent->name);
516 return -ENODEV;
517 }
Simon Glassc0bcaaf2022-10-29 19:47:14 -0600518 *devp = dev;
519
520 return 0;
521}
522
523int blk_get_from_parent(struct udevice *parent, struct udevice **devp)
524{
525 struct udevice *dev;
526 int ret;
527
528 ret = blk_find_from_parent(parent, &dev);
529 if (ret)
530 return ret;
Simon Glass4f269132017-05-27 11:37:17 -0600531 ret = device_probe(dev);
532 if (ret)
533 return ret;
534 *devp = dev;
535
536 return 0;
537}
538
Simon Glassf3086cf2022-04-24 23:31:03 -0600539const char *blk_get_devtype(struct udevice *dev)
540{
541 struct udevice *parent = dev_get_parent(dev);
542
543 return uclass_get_name(device_get_uclass_id(parent));
544};
545
Simon Glassfada3f92022-09-17 09:00:09 -0600546int blk_find_max_devnum(enum uclass_id uclass_id)
Simon Glassd089ba32016-05-01 11:36:28 -0600547{
548 struct udevice *dev;
549 int max_devnum = -ENODEV;
550 struct uclass *uc;
551 int ret;
552
553 ret = uclass_get(UCLASS_BLK, &uc);
554 if (ret)
555 return ret;
556 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700557 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glassd089ba32016-05-01 11:36:28 -0600558
Simon Glassfada3f92022-09-17 09:00:09 -0600559 if (desc->uclass_id == uclass_id && desc->devnum > max_devnum)
Simon Glassd089ba32016-05-01 11:36:28 -0600560 max_devnum = desc->devnum;
561 }
562
563 return max_devnum;
564}
565
Simon Glassfada3f92022-09-17 09:00:09 -0600566int blk_next_free_devnum(enum uclass_id uclass_id)
Simon Glassdbc38612017-04-23 20:02:06 -0600567{
568 int ret;
569
Simon Glassfada3f92022-09-17 09:00:09 -0600570 ret = blk_find_max_devnum(uclass_id);
Simon Glassdbc38612017-04-23 20:02:06 -0600571 if (ret == -ENODEV)
572 return 0;
573 if (ret < 0)
574 return ret;
575
576 return ret + 1;
577}
578
Simon Glassfc7a7442021-07-05 16:32:59 -0600579static int blk_flags_check(struct udevice *dev, enum blk_flag_t req_flags)
580{
581 const struct blk_desc *desc = dev_get_uclass_plat(dev);
582 enum blk_flag_t flags;
583
584 flags = desc->removable ? BLKF_REMOVABLE : BLKF_FIXED;
585
586 return flags & req_flags ? 0 : 1;
587}
588
Simon Glass8e61f932022-02-28 12:08:35 -0700589int blk_find_first(enum blk_flag_t flags, struct udevice **devp)
590{
591 int ret;
592
593 for (ret = uclass_find_first_device(UCLASS_BLK, devp);
594 *devp && !blk_flags_check(*devp, flags);
595 ret = uclass_find_next_device(devp))
596 return 0;
597
598 return -ENODEV;
599}
600
601int blk_find_next(enum blk_flag_t flags, struct udevice **devp)
602{
603 int ret;
604
605 for (ret = uclass_find_next_device(devp);
606 *devp && !blk_flags_check(*devp, flags);
607 ret = uclass_find_next_device(devp))
608 return 0;
609
610 return -ENODEV;
611}
612
Simon Glassfc7a7442021-07-05 16:32:59 -0600613int blk_first_device_err(enum blk_flag_t flags, struct udevice **devp)
614{
Michal Suchanekac9e9fc2022-10-12 21:58:01 +0200615 for (uclass_first_device(UCLASS_BLK, devp);
616 *devp;
617 uclass_next_device(devp)) {
Simon Glassfc7a7442021-07-05 16:32:59 -0600618 if (!blk_flags_check(*devp, flags))
619 return 0;
620 }
621
622 return -ENODEV;
623}
624
625int blk_next_device_err(enum blk_flag_t flags, struct udevice **devp)
626{
Michal Suchanekac9e9fc2022-10-12 21:58:01 +0200627 for (uclass_next_device(devp);
628 *devp;
629 uclass_next_device(devp)) {
Simon Glassfc7a7442021-07-05 16:32:59 -0600630 if (!blk_flags_check(*devp, flags))
631 return 0;
632 }
633
634 return -ENODEV;
635}
636
637int blk_count_devices(enum blk_flag_t flag)
638{
639 struct udevice *dev;
640 int count = 0;
641
642 blk_foreach_probe(flag, dev)
643 count++;
644
645 return count;
646}
647
Simon Glassfada3f92022-09-17 09:00:09 -0600648static int blk_claim_devnum(enum uclass_id uclass_id, int devnum)
Simon Glasse4fef742017-04-23 20:02:07 -0600649{
650 struct udevice *dev;
651 struct uclass *uc;
652 int ret;
653
654 ret = uclass_get(UCLASS_BLK, &uc);
655 if (ret)
656 return ret;
657 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700658 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasse4fef742017-04-23 20:02:07 -0600659
Simon Glassfada3f92022-09-17 09:00:09 -0600660 if (desc->uclass_id == uclass_id && desc->devnum == devnum) {
661 int next = blk_next_free_devnum(uclass_id);
Simon Glasse4fef742017-04-23 20:02:07 -0600662
663 if (next < 0)
664 return next;
665 desc->devnum = next;
666 return 0;
667 }
668 }
669
670 return -ENOENT;
671}
672
Simon Glasscceee552016-02-29 15:25:55 -0700673int blk_create_device(struct udevice *parent, const char *drv_name,
Simon Glassfada3f92022-09-17 09:00:09 -0600674 const char *name, int uclass_id, int devnum, int blksz,
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200675 lbaint_t lba, struct udevice **devp)
Simon Glasscceee552016-02-29 15:25:55 -0700676{
677 struct blk_desc *desc;
678 struct udevice *dev;
679 int ret;
680
Simon Glassd089ba32016-05-01 11:36:28 -0600681 if (devnum == -1) {
Simon Glassfada3f92022-09-17 09:00:09 -0600682 devnum = blk_next_free_devnum(uclass_id);
Simon Glasse4fef742017-04-23 20:02:07 -0600683 } else {
Simon Glassfada3f92022-09-17 09:00:09 -0600684 ret = blk_claim_devnum(uclass_id, devnum);
Simon Glasse4fef742017-04-23 20:02:07 -0600685 if (ret < 0 && ret != -ENOENT)
Simon Glassd089ba32016-05-01 11:36:28 -0600686 return ret;
Simon Glassd089ba32016-05-01 11:36:28 -0600687 }
Simon Glasse4fef742017-04-23 20:02:07 -0600688 if (devnum < 0)
689 return devnum;
Simon Glass77f7fb82016-05-01 13:52:22 -0600690 ret = device_bind_driver(parent, drv_name, name, &dev);
691 if (ret)
692 return ret;
Simon Glass71fa5b42020-12-03 16:55:18 -0700693 desc = dev_get_uclass_plat(dev);
Simon Glassfada3f92022-09-17 09:00:09 -0600694 desc->uclass_id = uclass_id;
Simon Glass77f7fb82016-05-01 13:52:22 -0600695 desc->blksz = blksz;
Heinrich Schuchardt09ba4ea2019-10-25 12:15:31 +0200696 desc->log2blksz = LOG2(desc->blksz);
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200697 desc->lba = lba;
Simon Glass77f7fb82016-05-01 13:52:22 -0600698 desc->part_type = PART_TYPE_UNKNOWN;
699 desc->bdev = dev;
Simon Glasscceee552016-02-29 15:25:55 -0700700 desc->devnum = devnum;
701 *devp = dev;
702
703 return 0;
704}
705
Simon Glass966b6952016-05-01 11:36:29 -0600706int blk_create_devicef(struct udevice *parent, const char *drv_name,
Simon Glassfada3f92022-09-17 09:00:09 -0600707 const char *name, int uclass_id, int devnum, int blksz,
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200708 lbaint_t lba, struct udevice **devp)
Simon Glass966b6952016-05-01 11:36:29 -0600709{
710 char dev_name[30], *str;
Simon Glass39e54922016-05-01 13:52:24 -0600711 int ret;
Simon Glass966b6952016-05-01 11:36:29 -0600712
713 snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name);
714 str = strdup(dev_name);
715 if (!str)
716 return -ENOMEM;
717
Simon Glassfada3f92022-09-17 09:00:09 -0600718 ret = blk_create_device(parent, drv_name, str, uclass_id, devnum,
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200719 blksz, lba, devp);
Simon Glass39e54922016-05-01 13:52:24 -0600720 if (ret) {
721 free(str);
722 return ret;
723 }
724 device_set_name_alloced(*devp);
725
Simon Glass44505972017-07-29 11:34:59 -0600726 return 0;
Simon Glass966b6952016-05-01 11:36:29 -0600727}
728
AKASHI Takahiro3e32dbe2021-12-10 15:49:29 +0900729int blk_probe_or_unbind(struct udevice *dev)
730{
731 int ret;
732
733 ret = device_probe(dev);
734 if (ret) {
735 log_debug("probing %s failed\n", dev->name);
736 device_unbind(dev);
737 }
738
739 return ret;
740}
741
Simon Glassfada3f92022-09-17 09:00:09 -0600742int blk_unbind_all(int uclass_id)
Simon Glasscceee552016-02-29 15:25:55 -0700743{
744 struct uclass *uc;
745 struct udevice *dev, *next;
746 int ret;
747
748 ret = uclass_get(UCLASS_BLK, &uc);
749 if (ret)
750 return ret;
751 uclass_foreach_dev_safe(dev, next, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700752 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700753
Simon Glassfada3f92022-09-17 09:00:09 -0600754 if (desc->uclass_id == uclass_id) {
Stefan Roese80b5bc92017-03-20 12:51:48 +0100755 ret = device_remove(dev, DM_REMOVE_NORMAL);
Simon Glasscceee552016-02-29 15:25:55 -0700756 if (ret)
757 return ret;
758 ret = device_unbind(dev);
759 if (ret)
760 return ret;
761 }
762 }
763
764 return 0;
765}
766
Bin Mengcbc3da82018-10-15 02:21:07 -0700767static int blk_post_probe(struct udevice *dev)
768{
Simon Glassf5ac3032022-08-11 19:34:45 -0600769 if (CONFIG_IS_ENABLED(PARTITIONS) && blk_enabled()) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700770 struct blk_desc *desc = dev_get_uclass_plat(dev);
Bin Mengcbc3da82018-10-15 02:21:07 -0700771
Ovidiu Panait76160a02020-07-24 14:12:21 +0300772 part_init(desc);
AKASHI Takahiro358e6c72022-04-19 10:05:10 +0900773
774 if (desc->part_type != PART_TYPE_UNKNOWN &&
775 part_create_block_devices(dev))
776 debug("*** creating partitions failed\n");
Ovidiu Panait76160a02020-07-24 14:12:21 +0300777 }
Bin Mengcbc3da82018-10-15 02:21:07 -0700778
779 return 0;
780}
781
Simon Glasscceee552016-02-29 15:25:55 -0700782UCLASS_DRIVER(blk) = {
783 .id = UCLASS_BLK,
784 .name = "blk",
Bin Mengcbc3da82018-10-15 02:21:07 -0700785 .post_probe = blk_post_probe,
Simon Glass71fa5b42020-12-03 16:55:18 -0700786 .per_device_plat_auto = sizeof(struct blk_desc),
Simon Glasscceee552016-02-29 15:25:55 -0700787};