blob: 4bda74bd067cefb06cca803089f00dfeed52ed27 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glass09d71aa2016-02-29 15:25:55 -07002/*
3 * Copyright (C) 2016 Google, Inc
4 * Written by Simon Glass <sjg@chromium.org>
Simon Glass09d71aa2016-02-29 15:25:55 -07005 */
6
7#include <common.h>
8#include <blk.h>
9#include <dm.h>
Simon Glass336d4612020-02-03 07:36:16 -070010#include <malloc.h>
Simon Glasse6f6f9e2020-05-10 11:39:58 -060011#include <part.h>
Simon Glass09d71aa2016-02-29 15:25:55 -070012#include <dm/device-internal.h>
13#include <dm/lists.h>
Stefan Roese8a5cbc02017-11-29 16:46:42 +010014#include <dm/uclass-internal.h>
Simon Glass61b29b82020-02-03 07:36:15 -070015#include <linux/err.h>
Simon Glass09d71aa2016-02-29 15:25:55 -070016
Simon Glassd508c822016-05-01 11:36:08 -060017static const char *if_typename_str[IF_TYPE_COUNT] = {
18 [IF_TYPE_IDE] = "ide",
19 [IF_TYPE_SCSI] = "scsi",
20 [IF_TYPE_ATAPI] = "atapi",
21 [IF_TYPE_USB] = "usb",
22 [IF_TYPE_DOC] = "doc",
23 [IF_TYPE_MMC] = "mmc",
24 [IF_TYPE_SD] = "sd",
25 [IF_TYPE_SATA] = "sata",
26 [IF_TYPE_HOST] = "host",
Zhikang Zhangffab6942017-08-03 02:30:56 -070027 [IF_TYPE_NVME] = "nvme",
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +010028 [IF_TYPE_EFI] = "efi",
Tuomas Tynkkynen4ad54ec2018-10-15 02:21:10 -070029 [IF_TYPE_VIRTIO] = "virtio",
Simon Glassd508c822016-05-01 11:36:08 -060030};
31
32static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = {
Bin Meng68e6f222017-09-10 05:12:51 -070033 [IF_TYPE_IDE] = UCLASS_IDE,
Michal Simeke8a016b2016-09-08 15:06:45 +020034 [IF_TYPE_SCSI] = UCLASS_SCSI,
Simon Glassd508c822016-05-01 11:36:08 -060035 [IF_TYPE_ATAPI] = UCLASS_INVALID,
36 [IF_TYPE_USB] = UCLASS_MASS_STORAGE,
37 [IF_TYPE_DOC] = UCLASS_INVALID,
38 [IF_TYPE_MMC] = UCLASS_MMC,
39 [IF_TYPE_SD] = UCLASS_INVALID,
40 [IF_TYPE_SATA] = UCLASS_AHCI,
41 [IF_TYPE_HOST] = UCLASS_ROOT,
Heinrich Schuchardt05ef48a2018-01-21 19:29:30 +010042 [IF_TYPE_NVME] = UCLASS_NVME,
43 [IF_TYPE_EFI] = UCLASS_EFI,
Tuomas Tynkkynen4ad54ec2018-10-15 02:21:10 -070044 [IF_TYPE_VIRTIO] = UCLASS_VIRTIO,
Simon Glassd508c822016-05-01 11:36:08 -060045};
46
47static enum if_type if_typename_to_iftype(const char *if_typename)
48{
49 int i;
50
51 for (i = 0; i < IF_TYPE_COUNT; i++) {
52 if (if_typename_str[i] &&
53 !strcmp(if_typename, if_typename_str[i]))
54 return i;
55 }
56
57 return IF_TYPE_UNKNOWN;
58}
59
60static enum uclass_id if_type_to_uclass_id(enum if_type if_type)
61{
62 return if_type_uclass_id[if_type];
63}
64
Simon Glass6faa4ed2017-07-29 11:34:53 -060065const char *blk_get_if_type_name(enum if_type if_type)
66{
67 return if_typename_str[if_type];
68}
69
Simon Glassd508c822016-05-01 11:36:08 -060070struct blk_desc *blk_get_devnum_by_type(enum if_type if_type, int devnum)
71{
72 struct blk_desc *desc;
73 struct udevice *dev;
74 int ret;
75
76 ret = blk_get_device(if_type, devnum, &dev);
77 if (ret)
78 return NULL;
79 desc = dev_get_uclass_platdata(dev);
80
81 return desc;
82}
83
84/*
85 * This function is complicated with driver model. We look up the interface
86 * name in a local table. This gives us an interface type which we can match
87 * against the uclass of the block device's parent.
88 */
89struct blk_desc *blk_get_devnum_by_typename(const char *if_typename, int devnum)
90{
91 enum uclass_id uclass_id;
92 enum if_type if_type;
93 struct udevice *dev;
94 struct uclass *uc;
95 int ret;
96
97 if_type = if_typename_to_iftype(if_typename);
98 if (if_type == IF_TYPE_UNKNOWN) {
99 debug("%s: Unknown interface type '%s'\n", __func__,
100 if_typename);
101 return NULL;
102 }
103 uclass_id = if_type_to_uclass_id(if_type);
104 if (uclass_id == UCLASS_INVALID) {
105 debug("%s: Unknown uclass for interface type'\n",
106 if_typename_str[if_type]);
107 return NULL;
108 }
109
110 ret = uclass_get(UCLASS_BLK, &uc);
111 if (ret)
112 return NULL;
113 uclass_foreach_dev(dev, uc) {
114 struct blk_desc *desc = dev_get_uclass_platdata(dev);
115
116 debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
117 if_type, devnum, dev->name, desc->if_type, desc->devnum);
118 if (desc->devnum != devnum)
119 continue;
120
121 /* Find out the parent device uclass */
122 if (device_get_uclass_id(dev->parent) != uclass_id) {
123 debug("%s: parent uclass %d, this dev %d\n", __func__,
124 device_get_uclass_id(dev->parent), uclass_id);
125 continue;
126 }
127
128 if (device_probe(dev))
129 return NULL;
130
131 debug("%s: Device desc %p\n", __func__, desc);
132 return desc;
133 }
134 debug("%s: No device found\n", __func__);
135
136 return NULL;
137}
138
139/**
Tien Fong Cheebc53d262018-07-06 16:26:36 +0800140 * blk_get_by_device() - Get the block device descriptor for the given device
141 * @dev: Instance of a storage device
142 *
143 * Return: With block device descriptor on success , NULL if there is no such
144 * block device.
145 */
146struct blk_desc *blk_get_by_device(struct udevice *dev)
147{
Simon Glasse5f73902019-09-25 08:55:56 -0600148 struct udevice *child_dev;
Tien Fong Cheebc53d262018-07-06 16:26:36 +0800149
Simon Glasse5f73902019-09-25 08:55:56 -0600150 device_foreach_child(child_dev, dev) {
Tien Fong Cheebc53d262018-07-06 16:26:36 +0800151 if (device_get_uclass_id(child_dev) != UCLASS_BLK)
152 continue;
153
154 return dev_get_uclass_platdata(child_dev);
155 }
156
157 debug("%s: No block device found\n", __func__);
158
159 return NULL;
160}
161
162/**
Simon Glassd508c822016-05-01 11:36:08 -0600163 * get_desc() - Get the block device descriptor for the given device number
164 *
165 * @if_type: Interface type
166 * @devnum: Device number (0 = first)
167 * @descp: Returns block device descriptor on success
168 * @return 0 on success, -ENODEV if there is no such device and no device
169 * with a higher device number, -ENOENT if there is no such device but there
170 * is one with a higher number, or other -ve on other error.
171 */
172static int get_desc(enum if_type if_type, int devnum, struct blk_desc **descp)
173{
174 bool found_more = false;
175 struct udevice *dev;
176 struct uclass *uc;
177 int ret;
178
179 *descp = NULL;
180 ret = uclass_get(UCLASS_BLK, &uc);
181 if (ret)
182 return ret;
183 uclass_foreach_dev(dev, uc) {
184 struct blk_desc *desc = dev_get_uclass_platdata(dev);
185
186 debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
187 if_type, devnum, dev->name, desc->if_type, desc->devnum);
188 if (desc->if_type == if_type) {
189 if (desc->devnum == devnum) {
190 ret = device_probe(dev);
191 if (ret)
192 return ret;
193
Michal Simek4408f6f2016-11-16 17:37:42 +0100194 *descp = desc;
195 return 0;
Simon Glassd508c822016-05-01 11:36:08 -0600196 } else if (desc->devnum > devnum) {
197 found_more = true;
198 }
199 }
200 }
201
202 return found_more ? -ENOENT : -ENODEV;
203}
204
Simon Glasscd0fb552016-05-01 13:52:30 -0600205int blk_select_hwpart_devnum(enum if_type if_type, int devnum, int hwpart)
206{
207 struct udevice *dev;
208 int ret;
209
210 ret = blk_get_device(if_type, devnum, &dev);
211 if (ret)
212 return ret;
213
Weijie Gao1ce88472019-08-27 15:32:18 +0800214 return blk_select_hwpart(dev, hwpart);
Simon Glasscd0fb552016-05-01 13:52:30 -0600215}
216
Simon Glassd508c822016-05-01 11:36:08 -0600217int blk_list_part(enum if_type if_type)
218{
219 struct blk_desc *desc;
220 int devnum, ok;
221 int ret;
222
223 for (ok = 0, devnum = 0;; ++devnum) {
224 ret = get_desc(if_type, devnum, &desc);
225 if (ret == -ENODEV)
226 break;
227 else if (ret)
228 continue;
229 if (desc->part_type != PART_TYPE_UNKNOWN) {
230 ++ok;
231 if (devnum)
232 putc('\n');
233 part_print(desc);
234 }
235 }
236 if (!ok)
237 return -ENODEV;
238
239 return 0;
240}
241
242int blk_print_part_devnum(enum if_type if_type, int devnum)
243{
244 struct blk_desc *desc;
245 int ret;
246
247 ret = get_desc(if_type, devnum, &desc);
248 if (ret)
249 return ret;
250 if (desc->type == DEV_TYPE_UNKNOWN)
251 return -ENOENT;
252 part_print(desc);
253
254 return 0;
255}
256
257void blk_list_devices(enum if_type if_type)
258{
259 struct blk_desc *desc;
260 int ret;
261 int i;
262
263 for (i = 0;; ++i) {
264 ret = get_desc(if_type, i, &desc);
265 if (ret == -ENODEV)
266 break;
267 else if (ret)
268 continue;
269 if (desc->type == DEV_TYPE_UNKNOWN)
270 continue; /* list only known devices */
271 printf("Device %d: ", i);
272 dev_print(desc);
273 }
274}
275
276int blk_print_device_num(enum if_type if_type, int devnum)
277{
278 struct blk_desc *desc;
279 int ret;
280
281 ret = get_desc(if_type, devnum, &desc);
282 if (ret)
283 return ret;
284 printf("\nIDE device %d: ", devnum);
285 dev_print(desc);
286
287 return 0;
288}
289
290int blk_show_device(enum if_type if_type, int devnum)
291{
292 struct blk_desc *desc;
293 int ret;
294
295 printf("\nDevice %d: ", devnum);
296 ret = get_desc(if_type, devnum, &desc);
297 if (ret == -ENODEV || ret == -ENOENT) {
298 printf("unknown device\n");
299 return -ENODEV;
300 }
301 if (ret)
302 return ret;
303 dev_print(desc);
304
305 if (desc->type == DEV_TYPE_UNKNOWN)
306 return -ENOENT;
307
308 return 0;
309}
310
311ulong blk_read_devnum(enum if_type if_type, int devnum, lbaint_t start,
312 lbaint_t blkcnt, void *buffer)
313{
314 struct blk_desc *desc;
315 ulong n;
316 int ret;
317
318 ret = get_desc(if_type, devnum, &desc);
319 if (ret)
320 return ret;
321 n = blk_dread(desc, start, blkcnt, buffer);
322 if (IS_ERR_VALUE(n))
323 return n;
324
Simon Glassd508c822016-05-01 11:36:08 -0600325 return n;
326}
327
328ulong blk_write_devnum(enum if_type if_type, int devnum, lbaint_t start,
329 lbaint_t blkcnt, const void *buffer)
330{
331 struct blk_desc *desc;
332 int ret;
333
334 ret = get_desc(if_type, devnum, &desc);
335 if (ret)
336 return ret;
337 return blk_dwrite(desc, start, blkcnt, buffer);
338}
339
Simon Glasscd0fb552016-05-01 13:52:30 -0600340int blk_select_hwpart(struct udevice *dev, int hwpart)
341{
342 const struct blk_ops *ops = blk_get_ops(dev);
343
344 if (!ops)
345 return -ENOSYS;
346 if (!ops->select_hwpart)
347 return 0;
348
349 return ops->select_hwpart(dev, hwpart);
350}
351
352int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
353{
Weijie Gao1ce88472019-08-27 15:32:18 +0800354 return blk_select_hwpart(desc->bdev, hwpart);
Simon Glasscd0fb552016-05-01 13:52:30 -0600355}
356
Simon Glass09d71aa2016-02-29 15:25:55 -0700357int blk_first_device(int if_type, struct udevice **devp)
358{
359 struct blk_desc *desc;
360 int ret;
361
Stefan Roese8a5cbc02017-11-29 16:46:42 +0100362 ret = uclass_find_first_device(UCLASS_BLK, devp);
Simon Glass09d71aa2016-02-29 15:25:55 -0700363 if (ret)
364 return ret;
365 if (!*devp)
366 return -ENODEV;
367 do {
368 desc = dev_get_uclass_platdata(*devp);
369 if (desc->if_type == if_type)
370 return 0;
Stefan Roese8a5cbc02017-11-29 16:46:42 +0100371 ret = uclass_find_next_device(devp);
Simon Glass09d71aa2016-02-29 15:25:55 -0700372 if (ret)
373 return ret;
374 } while (*devp);
375
376 return -ENODEV;
377}
378
379int blk_next_device(struct udevice **devp)
380{
381 struct blk_desc *desc;
382 int ret, if_type;
383
384 desc = dev_get_uclass_platdata(*devp);
385 if_type = desc->if_type;
386 do {
Stefan Roese8a5cbc02017-11-29 16:46:42 +0100387 ret = uclass_find_next_device(devp);
Simon Glass09d71aa2016-02-29 15:25:55 -0700388 if (ret)
389 return ret;
390 if (!*devp)
391 return -ENODEV;
392 desc = dev_get_uclass_platdata(*devp);
393 if (desc->if_type == if_type)
394 return 0;
395 } while (1);
396}
397
Simon Glass61392812017-04-23 20:02:05 -0600398int blk_find_device(int if_type, int devnum, struct udevice **devp)
Simon Glass09d71aa2016-02-29 15:25:55 -0700399{
400 struct uclass *uc;
401 struct udevice *dev;
402 int ret;
403
404 ret = uclass_get(UCLASS_BLK, &uc);
405 if (ret)
406 return ret;
407 uclass_foreach_dev(dev, uc) {
408 struct blk_desc *desc = dev_get_uclass_platdata(dev);
409
410 debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
411 if_type, devnum, dev->name, desc->if_type, desc->devnum);
412 if (desc->if_type == if_type && desc->devnum == devnum) {
413 *devp = dev;
Simon Glass61392812017-04-23 20:02:05 -0600414 return 0;
Simon Glass09d71aa2016-02-29 15:25:55 -0700415 }
416 }
417
418 return -ENODEV;
419}
420
Simon Glass61392812017-04-23 20:02:05 -0600421int blk_get_device(int if_type, int devnum, struct udevice **devp)
422{
423 int ret;
424
425 ret = blk_find_device(if_type, devnum, devp);
426 if (ret)
427 return ret;
428
429 return device_probe(*devp);
430}
431
Simon Glass09d71aa2016-02-29 15:25:55 -0700432unsigned long blk_dread(struct blk_desc *block_dev, lbaint_t start,
433 lbaint_t blkcnt, void *buffer)
434{
435 struct udevice *dev = block_dev->bdev;
436 const struct blk_ops *ops = blk_get_ops(dev);
Eric Nelsone40cf342016-03-28 10:05:44 -0700437 ulong blks_read;
Simon Glass09d71aa2016-02-29 15:25:55 -0700438
439 if (!ops->read)
440 return -ENOSYS;
441
Eric Nelsone40cf342016-03-28 10:05:44 -0700442 if (blkcache_read(block_dev->if_type, block_dev->devnum,
443 start, blkcnt, block_dev->blksz, buffer))
444 return blkcnt;
445 blks_read = ops->read(dev, start, blkcnt, buffer);
446 if (blks_read == blkcnt)
447 blkcache_fill(block_dev->if_type, block_dev->devnum,
448 start, blkcnt, block_dev->blksz, buffer);
449
450 return blks_read;
Simon Glass09d71aa2016-02-29 15:25:55 -0700451}
452
453unsigned long blk_dwrite(struct blk_desc *block_dev, lbaint_t start,
454 lbaint_t blkcnt, const void *buffer)
455{
456 struct udevice *dev = block_dev->bdev;
457 const struct blk_ops *ops = blk_get_ops(dev);
458
459 if (!ops->write)
460 return -ENOSYS;
461
Eric Nelsone40cf342016-03-28 10:05:44 -0700462 blkcache_invalidate(block_dev->if_type, block_dev->devnum);
Simon Glass09d71aa2016-02-29 15:25:55 -0700463 return ops->write(dev, start, blkcnt, buffer);
464}
465
466unsigned long blk_derase(struct blk_desc *block_dev, lbaint_t start,
467 lbaint_t blkcnt)
468{
469 struct udevice *dev = block_dev->bdev;
470 const struct blk_ops *ops = blk_get_ops(dev);
471
472 if (!ops->erase)
473 return -ENOSYS;
474
Eric Nelsone40cf342016-03-28 10:05:44 -0700475 blkcache_invalidate(block_dev->if_type, block_dev->devnum);
Simon Glass09d71aa2016-02-29 15:25:55 -0700476 return ops->erase(dev, start, blkcnt);
477}
478
Simon Glass9f103b92017-05-27 11:37:17 -0600479int blk_get_from_parent(struct udevice *parent, struct udevice **devp)
480{
481 struct udevice *dev;
482 enum uclass_id id;
483 int ret;
484
485 device_find_first_child(parent, &dev);
486 if (!dev) {
487 debug("%s: No block device found for parent '%s'\n", __func__,
488 parent->name);
489 return -ENODEV;
490 }
491 id = device_get_uclass_id(dev);
492 if (id != UCLASS_BLK) {
493 debug("%s: Incorrect uclass %s for block device '%s'\n",
494 __func__, uclass_get_name(id), dev->name);
495 return -ENOTBLK;
496 }
497 ret = device_probe(dev);
498 if (ret)
499 return ret;
500 *devp = dev;
501
502 return 0;
503}
504
Simon Glass52138fd2016-05-01 11:36:28 -0600505int blk_find_max_devnum(enum if_type if_type)
506{
507 struct udevice *dev;
508 int max_devnum = -ENODEV;
509 struct uclass *uc;
510 int ret;
511
512 ret = uclass_get(UCLASS_BLK, &uc);
513 if (ret)
514 return ret;
515 uclass_foreach_dev(dev, uc) {
516 struct blk_desc *desc = dev_get_uclass_platdata(dev);
517
518 if (desc->if_type == if_type && desc->devnum > max_devnum)
519 max_devnum = desc->devnum;
520 }
521
522 return max_devnum;
523}
524
Bin Mengc879eeb2018-10-15 02:21:09 -0700525int blk_next_free_devnum(enum if_type if_type)
Simon Glasse8abbb52017-04-23 20:02:06 -0600526{
527 int ret;
528
529 ret = blk_find_max_devnum(if_type);
530 if (ret == -ENODEV)
531 return 0;
532 if (ret < 0)
533 return ret;
534
535 return ret + 1;
536}
537
Simon Glasse48eeb92017-04-23 20:02:07 -0600538static int blk_claim_devnum(enum if_type if_type, int devnum)
539{
540 struct udevice *dev;
541 struct uclass *uc;
542 int ret;
543
544 ret = uclass_get(UCLASS_BLK, &uc);
545 if (ret)
546 return ret;
547 uclass_foreach_dev(dev, uc) {
548 struct blk_desc *desc = dev_get_uclass_platdata(dev);
549
550 if (desc->if_type == if_type && desc->devnum == devnum) {
551 int next = blk_next_free_devnum(if_type);
552
553 if (next < 0)
554 return next;
555 desc->devnum = next;
556 return 0;
557 }
558 }
559
560 return -ENOENT;
561}
562
Simon Glass09d71aa2016-02-29 15:25:55 -0700563int blk_create_device(struct udevice *parent, const char *drv_name,
564 const char *name, int if_type, int devnum, int blksz,
Jean-Jacques Hiblot5fe77022017-06-09 16:45:18 +0200565 lbaint_t lba, struct udevice **devp)
Simon Glass09d71aa2016-02-29 15:25:55 -0700566{
567 struct blk_desc *desc;
568 struct udevice *dev;
569 int ret;
570
Simon Glass52138fd2016-05-01 11:36:28 -0600571 if (devnum == -1) {
Simon Glasse48eeb92017-04-23 20:02:07 -0600572 devnum = blk_next_free_devnum(if_type);
573 } else {
574 ret = blk_claim_devnum(if_type, devnum);
575 if (ret < 0 && ret != -ENOENT)
Simon Glass52138fd2016-05-01 11:36:28 -0600576 return ret;
Simon Glass52138fd2016-05-01 11:36:28 -0600577 }
Simon Glasse48eeb92017-04-23 20:02:07 -0600578 if (devnum < 0)
579 return devnum;
Simon Glass72a85c02016-05-01 13:52:22 -0600580 ret = device_bind_driver(parent, drv_name, name, &dev);
581 if (ret)
582 return ret;
583 desc = dev_get_uclass_platdata(dev);
584 desc->if_type = if_type;
585 desc->blksz = blksz;
Heinrich Schuchardtee504142019-10-25 12:15:31 +0200586 desc->log2blksz = LOG2(desc->blksz);
Jean-Jacques Hiblot5fe77022017-06-09 16:45:18 +0200587 desc->lba = lba;
Simon Glass72a85c02016-05-01 13:52:22 -0600588 desc->part_type = PART_TYPE_UNKNOWN;
589 desc->bdev = dev;
Simon Glass09d71aa2016-02-29 15:25:55 -0700590 desc->devnum = devnum;
591 *devp = dev;
592
593 return 0;
594}
595
Simon Glass9107c972016-05-01 11:36:29 -0600596int blk_create_devicef(struct udevice *parent, const char *drv_name,
597 const char *name, int if_type, int devnum, int blksz,
Jean-Jacques Hiblot5fe77022017-06-09 16:45:18 +0200598 lbaint_t lba, struct udevice **devp)
Simon Glass9107c972016-05-01 11:36:29 -0600599{
600 char dev_name[30], *str;
Simon Glassd0773522016-05-01 13:52:24 -0600601 int ret;
Simon Glass9107c972016-05-01 11:36:29 -0600602
603 snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name);
604 str = strdup(dev_name);
605 if (!str)
606 return -ENOMEM;
607
Simon Glassd0773522016-05-01 13:52:24 -0600608 ret = blk_create_device(parent, drv_name, str, if_type, devnum,
Jean-Jacques Hiblot5fe77022017-06-09 16:45:18 +0200609 blksz, lba, devp);
Simon Glassd0773522016-05-01 13:52:24 -0600610 if (ret) {
611 free(str);
612 return ret;
613 }
614 device_set_name_alloced(*devp);
615
Simon Glass7074b2a2017-07-29 11:34:59 -0600616 return 0;
Simon Glass9107c972016-05-01 11:36:29 -0600617}
618
Simon Glass09d71aa2016-02-29 15:25:55 -0700619int blk_unbind_all(int if_type)
620{
621 struct uclass *uc;
622 struct udevice *dev, *next;
623 int ret;
624
625 ret = uclass_get(UCLASS_BLK, &uc);
626 if (ret)
627 return ret;
628 uclass_foreach_dev_safe(dev, next, uc) {
629 struct blk_desc *desc = dev_get_uclass_platdata(dev);
630
631 if (desc->if_type == if_type) {
Stefan Roese706865a2017-03-20 12:51:48 +0100632 ret = device_remove(dev, DM_REMOVE_NORMAL);
Simon Glass09d71aa2016-02-29 15:25:55 -0700633 if (ret)
634 return ret;
635 ret = device_unbind(dev);
636 if (ret)
637 return ret;
638 }
639 }
640
641 return 0;
642}
643
Bin Mengd0851c82018-10-15 02:21:07 -0700644static int blk_post_probe(struct udevice *dev)
645{
Tom Rini91ff6862018-12-05 08:23:38 -0500646#if defined(CONFIG_PARTITIONS) && defined(CONFIG_HAVE_BLOCK_DEVICE)
Bin Mengd0851c82018-10-15 02:21:07 -0700647 struct blk_desc *desc = dev_get_uclass_platdata(dev);
648
649 part_init(desc);
650#endif
651
652 return 0;
653}
654
Simon Glass09d71aa2016-02-29 15:25:55 -0700655UCLASS_DRIVER(blk) = {
656 .id = UCLASS_BLK,
657 .name = "blk",
Bin Mengd0851c82018-10-15 02:21:07 -0700658 .post_probe = blk_post_probe,
Simon Glass09d71aa2016-02-29 15:25:55 -0700659 .per_device_platdata_auto_alloc_size = sizeof(struct blk_desc),
660};