blob: 83682dcc181a5c7c5702a9bd3a72ac5a0e0bd018 [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 Glass4131ad52016-05-01 11:36:08 -060020static const char *if_typename_str[IF_TYPE_COUNT] = {
21 [IF_TYPE_IDE] = "ide",
22 [IF_TYPE_SCSI] = "scsi",
23 [IF_TYPE_ATAPI] = "atapi",
24 [IF_TYPE_USB] = "usb",
25 [IF_TYPE_DOC] = "doc",
26 [IF_TYPE_MMC] = "mmc",
27 [IF_TYPE_SD] = "sd",
28 [IF_TYPE_SATA] = "sata",
29 [IF_TYPE_HOST] = "host",
Zhikang Zhang182fccd2017-08-03 02:30:56 -070030 [IF_TYPE_NVME] = "nvme",
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010031 [IF_TYPE_EFI] = "efi",
Tuomas Tynkkynend4580062018-10-15 02:21:10 -070032 [IF_TYPE_VIRTIO] = "virtio",
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +030033 [IF_TYPE_PVBLOCK] = "pvblock",
Simon Glass4131ad52016-05-01 11:36:08 -060034};
35
36static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = {
Bin Mengb650afa2017-09-10 05:12:51 -070037 [IF_TYPE_IDE] = UCLASS_IDE,
Michal Simekc886f352016-09-08 15:06:45 +020038 [IF_TYPE_SCSI] = UCLASS_SCSI,
Simon Glass4131ad52016-05-01 11:36:08 -060039 [IF_TYPE_ATAPI] = UCLASS_INVALID,
40 [IF_TYPE_USB] = UCLASS_MASS_STORAGE,
41 [IF_TYPE_DOC] = UCLASS_INVALID,
42 [IF_TYPE_MMC] = UCLASS_MMC,
43 [IF_TYPE_SD] = UCLASS_INVALID,
44 [IF_TYPE_SATA] = UCLASS_AHCI,
45 [IF_TYPE_HOST] = UCLASS_ROOT,
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010046 [IF_TYPE_NVME] = UCLASS_NVME,
47 [IF_TYPE_EFI] = UCLASS_EFI,
Tuomas Tynkkynend4580062018-10-15 02:21:10 -070048 [IF_TYPE_VIRTIO] = UCLASS_VIRTIO,
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +030049 [IF_TYPE_PVBLOCK] = UCLASS_PVBLOCK,
Simon Glass4131ad52016-05-01 11:36:08 -060050};
51
52static enum if_type if_typename_to_iftype(const char *if_typename)
53{
54 int i;
55
56 for (i = 0; i < IF_TYPE_COUNT; i++) {
57 if (if_typename_str[i] &&
58 !strcmp(if_typename, if_typename_str[i]))
59 return i;
60 }
61
62 return IF_TYPE_UNKNOWN;
63}
64
65static enum uclass_id if_type_to_uclass_id(enum if_type if_type)
66{
67 return if_type_uclass_id[if_type];
68}
69
Simon Glass85af5a42017-07-29 11:34:53 -060070const char *blk_get_if_type_name(enum if_type if_type)
71{
72 return if_typename_str[if_type];
73}
74
Simon Glass4131ad52016-05-01 11:36:08 -060075struct blk_desc *blk_get_devnum_by_type(enum if_type if_type, int devnum)
76{
77 struct blk_desc *desc;
78 struct udevice *dev;
79 int ret;
80
81 ret = blk_get_device(if_type, devnum, &dev);
82 if (ret)
83 return NULL;
Simon Glass71fa5b42020-12-03 16:55:18 -070084 desc = dev_get_uclass_plat(dev);
Simon Glass4131ad52016-05-01 11:36:08 -060085
86 return desc;
87}
88
89/*
90 * This function is complicated with driver model. We look up the interface
91 * name in a local table. This gives us an interface type which we can match
92 * against the uclass of the block device's parent.
93 */
94struct blk_desc *blk_get_devnum_by_typename(const char *if_typename, int devnum)
95{
96 enum uclass_id uclass_id;
97 enum if_type if_type;
98 struct udevice *dev;
99 struct uclass *uc;
100 int ret;
101
102 if_type = if_typename_to_iftype(if_typename);
103 if (if_type == IF_TYPE_UNKNOWN) {
104 debug("%s: Unknown interface type '%s'\n", __func__,
105 if_typename);
106 return NULL;
107 }
108 uclass_id = if_type_to_uclass_id(if_type);
109 if (uclass_id == UCLASS_INVALID) {
110 debug("%s: Unknown uclass for interface type'\n",
111 if_typename_str[if_type]);
112 return NULL;
113 }
114
115 ret = uclass_get(UCLASS_BLK, &uc);
116 if (ret)
117 return NULL;
118 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700119 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glass4131ad52016-05-01 11:36:08 -0600120
121 debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
122 if_type, devnum, dev->name, desc->if_type, desc->devnum);
123 if (desc->devnum != devnum)
124 continue;
125
126 /* Find out the parent device uclass */
127 if (device_get_uclass_id(dev->parent) != uclass_id) {
128 debug("%s: parent uclass %d, this dev %d\n", __func__,
129 device_get_uclass_id(dev->parent), uclass_id);
130 continue;
131 }
132
133 if (device_probe(dev))
134 return NULL;
135
136 debug("%s: Device desc %p\n", __func__, desc);
137 return desc;
138 }
139 debug("%s: No device found\n", __func__);
140
141 return NULL;
142}
143
144/**
Tien Fong Chee10378522018-07-06 16:26:36 +0800145 * blk_get_by_device() - Get the block device descriptor for the given device
146 * @dev: Instance of a storage device
147 *
148 * Return: With block device descriptor on success , NULL if there is no such
149 * block device.
150 */
151struct blk_desc *blk_get_by_device(struct udevice *dev)
152{
Simon Glasscfd72932019-09-25 08:55:56 -0600153 struct udevice *child_dev;
Tien Fong Chee10378522018-07-06 16:26:36 +0800154
Simon Glasscfd72932019-09-25 08:55:56 -0600155 device_foreach_child(child_dev, dev) {
Tien Fong Chee10378522018-07-06 16:26:36 +0800156 if (device_get_uclass_id(child_dev) != UCLASS_BLK)
157 continue;
158
Simon Glass71fa5b42020-12-03 16:55:18 -0700159 return dev_get_uclass_plat(child_dev);
Tien Fong Chee10378522018-07-06 16:26:36 +0800160 }
161
162 debug("%s: No block device found\n", __func__);
163
164 return NULL;
165}
166
167/**
Simon Glass4131ad52016-05-01 11:36:08 -0600168 * get_desc() - Get the block device descriptor for the given device number
169 *
170 * @if_type: Interface type
171 * @devnum: Device number (0 = first)
172 * @descp: Returns block device descriptor on success
173 * @return 0 on success, -ENODEV if there is no such device and no device
174 * with a higher device number, -ENOENT if there is no such device but there
175 * is one with a higher number, or other -ve on other error.
176 */
177static int get_desc(enum if_type if_type, int devnum, struct blk_desc **descp)
178{
179 bool found_more = false;
180 struct udevice *dev;
181 struct uclass *uc;
182 int ret;
183
184 *descp = NULL;
185 ret = uclass_get(UCLASS_BLK, &uc);
186 if (ret)
187 return ret;
188 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700189 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glass4131ad52016-05-01 11:36:08 -0600190
191 debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
192 if_type, devnum, dev->name, desc->if_type, desc->devnum);
193 if (desc->if_type == if_type) {
194 if (desc->devnum == devnum) {
195 ret = device_probe(dev);
196 if (ret)
197 return ret;
198
Michal Simekf438b6b2016-11-16 17:37:42 +0100199 *descp = desc;
200 return 0;
Simon Glass4131ad52016-05-01 11:36:08 -0600201 } else if (desc->devnum > devnum) {
202 found_more = true;
203 }
204 }
205 }
206
207 return found_more ? -ENOENT : -ENODEV;
208}
209
Simon Glass13c2c292016-05-01 13:52:30 -0600210int blk_select_hwpart_devnum(enum if_type if_type, int devnum, int hwpart)
211{
212 struct udevice *dev;
213 int ret;
214
215 ret = blk_get_device(if_type, devnum, &dev);
216 if (ret)
217 return ret;
218
developerf50d8d12019-08-27 15:32:18 +0800219 return blk_select_hwpart(dev, hwpart);
Simon Glass13c2c292016-05-01 13:52:30 -0600220}
221
Simon Glass4131ad52016-05-01 11:36:08 -0600222int blk_list_part(enum if_type if_type)
223{
224 struct blk_desc *desc;
225 int devnum, ok;
226 int ret;
227
228 for (ok = 0, devnum = 0;; ++devnum) {
229 ret = get_desc(if_type, devnum, &desc);
230 if (ret == -ENODEV)
231 break;
232 else if (ret)
233 continue;
234 if (desc->part_type != PART_TYPE_UNKNOWN) {
235 ++ok;
236 if (devnum)
237 putc('\n');
238 part_print(desc);
239 }
240 }
241 if (!ok)
242 return -ENODEV;
243
244 return 0;
245}
246
247int blk_print_part_devnum(enum if_type if_type, int devnum)
248{
249 struct blk_desc *desc;
250 int ret;
251
252 ret = get_desc(if_type, devnum, &desc);
253 if (ret)
254 return ret;
255 if (desc->type == DEV_TYPE_UNKNOWN)
256 return -ENOENT;
257 part_print(desc);
258
259 return 0;
260}
261
262void blk_list_devices(enum if_type if_type)
263{
264 struct blk_desc *desc;
265 int ret;
266 int i;
267
268 for (i = 0;; ++i) {
269 ret = get_desc(if_type, i, &desc);
270 if (ret == -ENODEV)
271 break;
272 else if (ret)
273 continue;
274 if (desc->type == DEV_TYPE_UNKNOWN)
275 continue; /* list only known devices */
276 printf("Device %d: ", i);
277 dev_print(desc);
278 }
279}
280
281int blk_print_device_num(enum if_type if_type, int devnum)
282{
283 struct blk_desc *desc;
284 int ret;
285
286 ret = get_desc(if_type, devnum, &desc);
287 if (ret)
288 return ret;
289 printf("\nIDE device %d: ", devnum);
290 dev_print(desc);
291
292 return 0;
293}
294
295int blk_show_device(enum if_type if_type, int devnum)
296{
297 struct blk_desc *desc;
298 int ret;
299
300 printf("\nDevice %d: ", devnum);
301 ret = get_desc(if_type, devnum, &desc);
302 if (ret == -ENODEV || ret == -ENOENT) {
303 printf("unknown device\n");
304 return -ENODEV;
305 }
306 if (ret)
307 return ret;
308 dev_print(desc);
309
310 if (desc->type == DEV_TYPE_UNKNOWN)
311 return -ENOENT;
312
313 return 0;
314}
315
316ulong blk_read_devnum(enum if_type if_type, int devnum, lbaint_t start,
317 lbaint_t blkcnt, void *buffer)
318{
319 struct blk_desc *desc;
320 ulong n;
321 int ret;
322
323 ret = get_desc(if_type, devnum, &desc);
324 if (ret)
325 return ret;
326 n = blk_dread(desc, start, blkcnt, buffer);
327 if (IS_ERR_VALUE(n))
328 return n;
329
Simon Glass4131ad52016-05-01 11:36:08 -0600330 return n;
331}
332
333ulong blk_write_devnum(enum if_type if_type, int devnum, lbaint_t start,
334 lbaint_t blkcnt, const void *buffer)
335{
336 struct blk_desc *desc;
337 int ret;
338
339 ret = get_desc(if_type, devnum, &desc);
340 if (ret)
341 return ret;
342 return blk_dwrite(desc, start, blkcnt, buffer);
343}
344
Simon Glass13c2c292016-05-01 13:52:30 -0600345int blk_select_hwpart(struct udevice *dev, int hwpart)
346{
347 const struct blk_ops *ops = blk_get_ops(dev);
348
349 if (!ops)
350 return -ENOSYS;
351 if (!ops->select_hwpart)
352 return 0;
353
354 return ops->select_hwpart(dev, hwpart);
355}
356
357int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
358{
developerf50d8d12019-08-27 15:32:18 +0800359 return blk_select_hwpart(desc->bdev, hwpart);
Simon Glass13c2c292016-05-01 13:52:30 -0600360}
361
Simon Glasscceee552016-02-29 15:25:55 -0700362int blk_first_device(int if_type, struct udevice **devp)
363{
364 struct blk_desc *desc;
365 int ret;
366
Stefan Roeseef58a902017-11-29 16:46:42 +0100367 ret = uclass_find_first_device(UCLASS_BLK, devp);
Simon Glasscceee552016-02-29 15:25:55 -0700368 if (ret)
369 return ret;
370 if (!*devp)
371 return -ENODEV;
372 do {
Simon Glass71fa5b42020-12-03 16:55:18 -0700373 desc = dev_get_uclass_plat(*devp);
Simon Glasscceee552016-02-29 15:25:55 -0700374 if (desc->if_type == if_type)
375 return 0;
Stefan Roeseef58a902017-11-29 16:46:42 +0100376 ret = uclass_find_next_device(devp);
Simon Glasscceee552016-02-29 15:25:55 -0700377 if (ret)
378 return ret;
379 } while (*devp);
380
381 return -ENODEV;
382}
383
384int blk_next_device(struct udevice **devp)
385{
386 struct blk_desc *desc;
387 int ret, if_type;
388
Simon Glass71fa5b42020-12-03 16:55:18 -0700389 desc = dev_get_uclass_plat(*devp);
Simon Glasscceee552016-02-29 15:25:55 -0700390 if_type = desc->if_type;
391 do {
Stefan Roeseef58a902017-11-29 16:46:42 +0100392 ret = uclass_find_next_device(devp);
Simon Glasscceee552016-02-29 15:25:55 -0700393 if (ret)
394 return ret;
395 if (!*devp)
396 return -ENODEV;
Simon Glass71fa5b42020-12-03 16:55:18 -0700397 desc = dev_get_uclass_plat(*devp);
Simon Glasscceee552016-02-29 15:25:55 -0700398 if (desc->if_type == if_type)
399 return 0;
400 } while (1);
401}
402
Simon Glassd5d4c102017-04-23 20:02:05 -0600403int blk_find_device(int if_type, int devnum, struct udevice **devp)
Simon Glasscceee552016-02-29 15:25:55 -0700404{
405 struct uclass *uc;
406 struct udevice *dev;
407 int ret;
408
409 ret = uclass_get(UCLASS_BLK, &uc);
410 if (ret)
411 return ret;
412 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700413 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700414
415 debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
416 if_type, devnum, dev->name, desc->if_type, desc->devnum);
417 if (desc->if_type == if_type && desc->devnum == devnum) {
418 *devp = dev;
Simon Glassd5d4c102017-04-23 20:02:05 -0600419 return 0;
Simon Glasscceee552016-02-29 15:25:55 -0700420 }
421 }
422
423 return -ENODEV;
424}
425
Simon Glassd5d4c102017-04-23 20:02:05 -0600426int blk_get_device(int if_type, int devnum, struct udevice **devp)
427{
428 int ret;
429
430 ret = blk_find_device(if_type, devnum, devp);
431 if (ret)
432 return ret;
433
434 return device_probe(*devp);
435}
436
Simon Glasscceee552016-02-29 15:25:55 -0700437unsigned long blk_dread(struct blk_desc *block_dev, lbaint_t start,
438 lbaint_t blkcnt, void *buffer)
439{
440 struct udevice *dev = block_dev->bdev;
441 const struct blk_ops *ops = blk_get_ops(dev);
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700442 ulong blks_read;
Simon Glasscceee552016-02-29 15:25:55 -0700443
444 if (!ops->read)
445 return -ENOSYS;
446
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700447 if (blkcache_read(block_dev->if_type, block_dev->devnum,
448 start, blkcnt, block_dev->blksz, buffer))
449 return blkcnt;
450 blks_read = ops->read(dev, start, blkcnt, buffer);
451 if (blks_read == blkcnt)
452 blkcache_fill(block_dev->if_type, block_dev->devnum,
453 start, blkcnt, block_dev->blksz, buffer);
454
455 return blks_read;
Simon Glasscceee552016-02-29 15:25:55 -0700456}
457
458unsigned long blk_dwrite(struct blk_desc *block_dev, lbaint_t start,
459 lbaint_t blkcnt, const void *buffer)
460{
461 struct udevice *dev = block_dev->bdev;
462 const struct blk_ops *ops = blk_get_ops(dev);
463
464 if (!ops->write)
465 return -ENOSYS;
466
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700467 blkcache_invalidate(block_dev->if_type, block_dev->devnum);
Simon Glasscceee552016-02-29 15:25:55 -0700468 return ops->write(dev, start, blkcnt, buffer);
469}
470
471unsigned long blk_derase(struct blk_desc *block_dev, lbaint_t start,
472 lbaint_t blkcnt)
473{
474 struct udevice *dev = block_dev->bdev;
475 const struct blk_ops *ops = blk_get_ops(dev);
476
477 if (!ops->erase)
478 return -ENOSYS;
479
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700480 blkcache_invalidate(block_dev->if_type, block_dev->devnum);
Simon Glasscceee552016-02-29 15:25:55 -0700481 return ops->erase(dev, start, blkcnt);
482}
483
Simon Glass4f269132017-05-27 11:37:17 -0600484int blk_get_from_parent(struct udevice *parent, struct udevice **devp)
485{
486 struct udevice *dev;
487 enum uclass_id id;
488 int ret;
489
490 device_find_first_child(parent, &dev);
491 if (!dev) {
492 debug("%s: No block device found for parent '%s'\n", __func__,
493 parent->name);
494 return -ENODEV;
495 }
496 id = device_get_uclass_id(dev);
497 if (id != UCLASS_BLK) {
498 debug("%s: Incorrect uclass %s for block device '%s'\n",
499 __func__, uclass_get_name(id), dev->name);
500 return -ENOTBLK;
501 }
502 ret = device_probe(dev);
503 if (ret)
504 return ret;
505 *devp = dev;
506
507 return 0;
508}
509
Simon Glassd089ba32016-05-01 11:36:28 -0600510int blk_find_max_devnum(enum if_type if_type)
511{
512 struct udevice *dev;
513 int max_devnum = -ENODEV;
514 struct uclass *uc;
515 int ret;
516
517 ret = uclass_get(UCLASS_BLK, &uc);
518 if (ret)
519 return ret;
520 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700521 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glassd089ba32016-05-01 11:36:28 -0600522
523 if (desc->if_type == if_type && desc->devnum > max_devnum)
524 max_devnum = desc->devnum;
525 }
526
527 return max_devnum;
528}
529
Bin Mengfd5eda72018-10-15 02:21:09 -0700530int blk_next_free_devnum(enum if_type if_type)
Simon Glassdbc38612017-04-23 20:02:06 -0600531{
532 int ret;
533
534 ret = blk_find_max_devnum(if_type);
535 if (ret == -ENODEV)
536 return 0;
537 if (ret < 0)
538 return ret;
539
540 return ret + 1;
541}
542
Simon Glassfc7a7442021-07-05 16:32:59 -0600543static int blk_flags_check(struct udevice *dev, enum blk_flag_t req_flags)
544{
545 const struct blk_desc *desc = dev_get_uclass_plat(dev);
546 enum blk_flag_t flags;
547
548 flags = desc->removable ? BLKF_REMOVABLE : BLKF_FIXED;
549
550 return flags & req_flags ? 0 : 1;
551}
552
553int blk_first_device_err(enum blk_flag_t flags, struct udevice **devp)
554{
555 int ret;
556
557 for (ret = uclass_first_device_err(UCLASS_BLK, devp);
558 !ret;
559 ret = uclass_next_device_err(devp)) {
560 if (!blk_flags_check(*devp, flags))
561 return 0;
562 }
563
564 return -ENODEV;
565}
566
567int blk_next_device_err(enum blk_flag_t flags, struct udevice **devp)
568{
569 int ret;
570
571 for (ret = uclass_next_device_err(devp);
572 !ret;
573 ret = uclass_next_device_err(devp)) {
574 if (!blk_flags_check(*devp, flags))
575 return 0;
576 }
577
578 return -ENODEV;
579}
580
581int blk_count_devices(enum blk_flag_t flag)
582{
583 struct udevice *dev;
584 int count = 0;
585
586 blk_foreach_probe(flag, dev)
587 count++;
588
589 return count;
590}
591
Simon Glasse4fef742017-04-23 20:02:07 -0600592static int blk_claim_devnum(enum if_type if_type, int devnum)
593{
594 struct udevice *dev;
595 struct uclass *uc;
596 int ret;
597
598 ret = uclass_get(UCLASS_BLK, &uc);
599 if (ret)
600 return ret;
601 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700602 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasse4fef742017-04-23 20:02:07 -0600603
604 if (desc->if_type == if_type && desc->devnum == devnum) {
605 int next = blk_next_free_devnum(if_type);
606
607 if (next < 0)
608 return next;
609 desc->devnum = next;
610 return 0;
611 }
612 }
613
614 return -ENOENT;
615}
616
Simon Glasscceee552016-02-29 15:25:55 -0700617int blk_create_device(struct udevice *parent, const char *drv_name,
618 const char *name, int if_type, int devnum, int blksz,
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200619 lbaint_t lba, struct udevice **devp)
Simon Glasscceee552016-02-29 15:25:55 -0700620{
621 struct blk_desc *desc;
622 struct udevice *dev;
623 int ret;
624
Simon Glassd089ba32016-05-01 11:36:28 -0600625 if (devnum == -1) {
Simon Glasse4fef742017-04-23 20:02:07 -0600626 devnum = blk_next_free_devnum(if_type);
627 } else {
628 ret = blk_claim_devnum(if_type, devnum);
629 if (ret < 0 && ret != -ENOENT)
Simon Glassd089ba32016-05-01 11:36:28 -0600630 return ret;
Simon Glassd089ba32016-05-01 11:36:28 -0600631 }
Simon Glasse4fef742017-04-23 20:02:07 -0600632 if (devnum < 0)
633 return devnum;
Simon Glass77f7fb82016-05-01 13:52:22 -0600634 ret = device_bind_driver(parent, drv_name, name, &dev);
635 if (ret)
636 return ret;
Simon Glass71fa5b42020-12-03 16:55:18 -0700637 desc = dev_get_uclass_plat(dev);
Simon Glass77f7fb82016-05-01 13:52:22 -0600638 desc->if_type = if_type;
639 desc->blksz = blksz;
Heinrich Schuchardt09ba4ea2019-10-25 12:15:31 +0200640 desc->log2blksz = LOG2(desc->blksz);
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200641 desc->lba = lba;
Simon Glass77f7fb82016-05-01 13:52:22 -0600642 desc->part_type = PART_TYPE_UNKNOWN;
643 desc->bdev = dev;
Simon Glasscceee552016-02-29 15:25:55 -0700644 desc->devnum = devnum;
645 *devp = dev;
646
647 return 0;
648}
649
Simon Glass966b6952016-05-01 11:36:29 -0600650int blk_create_devicef(struct udevice *parent, const char *drv_name,
651 const char *name, int if_type, int devnum, int blksz,
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200652 lbaint_t lba, struct udevice **devp)
Simon Glass966b6952016-05-01 11:36:29 -0600653{
654 char dev_name[30], *str;
Simon Glass39e54922016-05-01 13:52:24 -0600655 int ret;
Simon Glass966b6952016-05-01 11:36:29 -0600656
657 snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name);
658 str = strdup(dev_name);
659 if (!str)
660 return -ENOMEM;
661
Simon Glass39e54922016-05-01 13:52:24 -0600662 ret = blk_create_device(parent, drv_name, str, if_type, devnum,
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200663 blksz, lba, devp);
Simon Glass39e54922016-05-01 13:52:24 -0600664 if (ret) {
665 free(str);
666 return ret;
667 }
668 device_set_name_alloced(*devp);
669
Simon Glass44505972017-07-29 11:34:59 -0600670 return 0;
Simon Glass966b6952016-05-01 11:36:29 -0600671}
672
Simon Glasscceee552016-02-29 15:25:55 -0700673int blk_unbind_all(int if_type)
674{
675 struct uclass *uc;
676 struct udevice *dev, *next;
677 int ret;
678
679 ret = uclass_get(UCLASS_BLK, &uc);
680 if (ret)
681 return ret;
682 uclass_foreach_dev_safe(dev, next, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700683 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700684
685 if (desc->if_type == if_type) {
Stefan Roese80b5bc92017-03-20 12:51:48 +0100686 ret = device_remove(dev, DM_REMOVE_NORMAL);
Simon Glasscceee552016-02-29 15:25:55 -0700687 if (ret)
688 return ret;
689 ret = device_unbind(dev);
690 if (ret)
691 return ret;
692 }
693 }
694
695 return 0;
696}
697
Bin Mengcbc3da82018-10-15 02:21:07 -0700698static int blk_post_probe(struct udevice *dev)
699{
Ovidiu Panait76160a02020-07-24 14:12:21 +0300700 if (IS_ENABLED(CONFIG_PARTITIONS) &&
701 IS_ENABLED(CONFIG_HAVE_BLOCK_DEVICE)) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700702 struct blk_desc *desc = dev_get_uclass_plat(dev);
Bin Mengcbc3da82018-10-15 02:21:07 -0700703
Ovidiu Panait76160a02020-07-24 14:12:21 +0300704 part_init(desc);
705 }
Bin Mengcbc3da82018-10-15 02:21:07 -0700706
707 return 0;
708}
709
Simon Glasscceee552016-02-29 15:25:55 -0700710UCLASS_DRIVER(blk) = {
711 .id = UCLASS_BLK,
712 .name = "blk",
Bin Mengcbc3da82018-10-15 02:21:07 -0700713 .post_probe = blk_post_probe,
Simon Glass71fa5b42020-12-03 16:55:18 -0700714 .per_device_plat_auto = sizeof(struct blk_desc),
Simon Glasscceee552016-02-29 15:25:55 -0700715};