1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2016 Google, Inc
4  * Written by Simon Glass <sjg@chromium.org>
5  */
6 
7 #define LOG_CATEGORY UCLASS_BLK
8 
9 #include <common.h>
10 #include <blk.h>
11 #include <dm.h>
12 #include <log.h>
13 #include <malloc.h>
14 #include <part.h>
15 #include <dm/device-internal.h>
16 #include <dm/lists.h>
17 #include <dm/uclass-internal.h>
18 #include <linux/err.h>
19 
20 static 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",
30 	[IF_TYPE_NVME]		= "nvme",
31 	[IF_TYPE_EFI]		= "efi",
32 	[IF_TYPE_VIRTIO]	= "virtio",
33 	[IF_TYPE_PVBLOCK]	= "pvblock",
34 };
35 
36 static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = {
37 	[IF_TYPE_IDE]		= UCLASS_IDE,
38 	[IF_TYPE_SCSI]		= UCLASS_SCSI,
39 	[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,
46 	[IF_TYPE_NVME]		= UCLASS_NVME,
47 	[IF_TYPE_EFI]		= UCLASS_EFI,
48 	[IF_TYPE_VIRTIO]	= UCLASS_VIRTIO,
49 	[IF_TYPE_PVBLOCK]	= UCLASS_PVBLOCK,
50 };
51 
if_typename_to_iftype(const char * if_typename)52 static 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 
if_type_to_uclass_id(enum if_type if_type)65 static enum uclass_id if_type_to_uclass_id(enum if_type if_type)
66 {
67 	return if_type_uclass_id[if_type];
68 }
69 
blk_get_if_type_name(enum if_type if_type)70 const char *blk_get_if_type_name(enum if_type if_type)
71 {
72 	return if_typename_str[if_type];
73 }
74 
blk_get_devnum_by_type(enum if_type if_type,int devnum)75 struct 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;
84 	desc = dev_get_uclass_plat(dev);
85 
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  */
blk_get_devnum_by_typename(const char * if_typename,int devnum)94 struct 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) {
119 		struct blk_desc *desc = dev_get_uclass_plat(dev);
120 
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 /**
145  * 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  */
blk_get_by_device(struct udevice * dev)151 struct blk_desc *blk_get_by_device(struct udevice *dev)
152 {
153 	struct udevice *child_dev;
154 
155 	device_foreach_child(child_dev, dev) {
156 		if (device_get_uclass_id(child_dev) != UCLASS_BLK)
157 			continue;
158 
159 		return dev_get_uclass_plat(child_dev);
160 	}
161 
162 	debug("%s: No block device found\n", __func__);
163 
164 	return NULL;
165 }
166 
167 /**
168  * 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  */
get_desc(enum if_type if_type,int devnum,struct blk_desc ** descp)177 static 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) {
189 		struct blk_desc *desc = dev_get_uclass_plat(dev);
190 
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 
199 				*descp = desc;
200 				return 0;
201 			} else if (desc->devnum > devnum) {
202 				found_more = true;
203 			}
204 		}
205 	}
206 
207 	return found_more ? -ENOENT : -ENODEV;
208 }
209 
blk_select_hwpart_devnum(enum if_type if_type,int devnum,int hwpart)210 int 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 
219 	return blk_select_hwpart(dev, hwpart);
220 }
221 
blk_list_part(enum if_type if_type)222 int 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 
blk_print_part_devnum(enum if_type if_type,int devnum)247 int 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 
blk_list_devices(enum if_type if_type)262 void 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 
blk_print_device_num(enum if_type if_type,int devnum)281 int 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 
blk_show_device(enum if_type if_type,int devnum)295 int 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 
blk_read_devnum(enum if_type if_type,int devnum,lbaint_t start,lbaint_t blkcnt,void * buffer)316 ulong 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 
330 	return n;
331 }
332 
blk_write_devnum(enum if_type if_type,int devnum,lbaint_t start,lbaint_t blkcnt,const void * buffer)333 ulong 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 
blk_select_hwpart(struct udevice * dev,int hwpart)345 int 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 
blk_dselect_hwpart(struct blk_desc * desc,int hwpart)357 int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
358 {
359 	return blk_select_hwpart(desc->bdev, hwpart);
360 }
361 
blk_first_device(int if_type,struct udevice ** devp)362 int blk_first_device(int if_type, struct udevice **devp)
363 {
364 	struct blk_desc *desc;
365 	int ret;
366 
367 	ret = uclass_find_first_device(UCLASS_BLK, devp);
368 	if (ret)
369 		return ret;
370 	if (!*devp)
371 		return -ENODEV;
372 	do {
373 		desc = dev_get_uclass_plat(*devp);
374 		if (desc->if_type == if_type)
375 			return 0;
376 		ret = uclass_find_next_device(devp);
377 		if (ret)
378 			return ret;
379 	} while (*devp);
380 
381 	return -ENODEV;
382 }
383 
blk_next_device(struct udevice ** devp)384 int blk_next_device(struct udevice **devp)
385 {
386 	struct blk_desc *desc;
387 	int ret, if_type;
388 
389 	desc = dev_get_uclass_plat(*devp);
390 	if_type = desc->if_type;
391 	do {
392 		ret = uclass_find_next_device(devp);
393 		if (ret)
394 			return ret;
395 		if (!*devp)
396 			return -ENODEV;
397 		desc = dev_get_uclass_plat(*devp);
398 		if (desc->if_type == if_type)
399 			return 0;
400 	} while (1);
401 }
402 
blk_find_device(int if_type,int devnum,struct udevice ** devp)403 int blk_find_device(int if_type, int devnum, struct udevice **devp)
404 {
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) {
413 		struct blk_desc *desc = dev_get_uclass_plat(dev);
414 
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;
419 			return 0;
420 		}
421 	}
422 
423 	return -ENODEV;
424 }
425 
blk_get_device(int if_type,int devnum,struct udevice ** devp)426 int 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 
blk_dread(struct blk_desc * block_dev,lbaint_t start,lbaint_t blkcnt,void * buffer)437 unsigned 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);
442 	ulong blks_read;
443 
444 	if (!ops->read)
445 		return -ENOSYS;
446 
447 	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;
456 }
457 
blk_dwrite(struct blk_desc * block_dev,lbaint_t start,lbaint_t blkcnt,const void * buffer)458 unsigned 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 
467 	blkcache_invalidate(block_dev->if_type, block_dev->devnum);
468 	return ops->write(dev, start, blkcnt, buffer);
469 }
470 
blk_derase(struct blk_desc * block_dev,lbaint_t start,lbaint_t blkcnt)471 unsigned 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 
480 	blkcache_invalidate(block_dev->if_type, block_dev->devnum);
481 	return ops->erase(dev, start, blkcnt);
482 }
483 
blk_get_from_parent(struct udevice * parent,struct udevice ** devp)484 int 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 
blk_find_max_devnum(enum if_type if_type)510 int 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) {
521 		struct blk_desc *desc = dev_get_uclass_plat(dev);
522 
523 		if (desc->if_type == if_type && desc->devnum > max_devnum)
524 			max_devnum = desc->devnum;
525 	}
526 
527 	return max_devnum;
528 }
529 
blk_next_free_devnum(enum if_type if_type)530 int blk_next_free_devnum(enum if_type if_type)
531 {
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 
blk_flags_check(struct udevice * dev,enum blk_flag_t req_flags)543 static 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 
blk_first_device_err(enum blk_flag_t flags,struct udevice ** devp)553 int 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 
blk_next_device_err(enum blk_flag_t flags,struct udevice ** devp)567 int 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 
blk_count_devices(enum blk_flag_t flag)581 int 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 
blk_claim_devnum(enum if_type if_type,int devnum)592 static 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) {
602 		struct blk_desc *desc = dev_get_uclass_plat(dev);
603 
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 
blk_create_device(struct udevice * parent,const char * drv_name,const char * name,int if_type,int devnum,int blksz,lbaint_t lba,struct udevice ** devp)617 int blk_create_device(struct udevice *parent, const char *drv_name,
618 		      const char *name, int if_type, int devnum, int blksz,
619 		      lbaint_t lba, struct udevice **devp)
620 {
621 	struct blk_desc *desc;
622 	struct udevice *dev;
623 	int ret;
624 
625 	if (devnum == -1) {
626 		devnum = blk_next_free_devnum(if_type);
627 	} else {
628 		ret = blk_claim_devnum(if_type, devnum);
629 		if (ret < 0 && ret != -ENOENT)
630 			return ret;
631 	}
632 	if (devnum < 0)
633 		return devnum;
634 	ret = device_bind_driver(parent, drv_name, name, &dev);
635 	if (ret)
636 		return ret;
637 	desc = dev_get_uclass_plat(dev);
638 	desc->if_type = if_type;
639 	desc->blksz = blksz;
640 	desc->log2blksz = LOG2(desc->blksz);
641 	desc->lba = lba;
642 	desc->part_type = PART_TYPE_UNKNOWN;
643 	desc->bdev = dev;
644 	desc->devnum = devnum;
645 	*devp = dev;
646 
647 	return 0;
648 }
649 
blk_create_devicef(struct udevice * parent,const char * drv_name,const char * name,int if_type,int devnum,int blksz,lbaint_t lba,struct udevice ** devp)650 int blk_create_devicef(struct udevice *parent, const char *drv_name,
651 		       const char *name, int if_type, int devnum, int blksz,
652 		       lbaint_t lba, struct udevice **devp)
653 {
654 	char dev_name[30], *str;
655 	int ret;
656 
657 	snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name);
658 	str = strdup(dev_name);
659 	if (!str)
660 		return -ENOMEM;
661 
662 	ret = blk_create_device(parent, drv_name, str, if_type, devnum,
663 				blksz, lba, devp);
664 	if (ret) {
665 		free(str);
666 		return ret;
667 	}
668 	device_set_name_alloced(*devp);
669 
670 	return 0;
671 }
672 
blk_unbind_all(int if_type)673 int 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) {
683 		struct blk_desc *desc = dev_get_uclass_plat(dev);
684 
685 		if (desc->if_type == if_type) {
686 			ret = device_remove(dev, DM_REMOVE_NORMAL);
687 			if (ret)
688 				return ret;
689 			ret = device_unbind(dev);
690 			if (ret)
691 				return ret;
692 		}
693 	}
694 
695 	return 0;
696 }
697 
blk_post_probe(struct udevice * dev)698 static int blk_post_probe(struct udevice *dev)
699 {
700 	if (IS_ENABLED(CONFIG_PARTITIONS) &&
701 	    IS_ENABLED(CONFIG_HAVE_BLOCK_DEVICE)) {
702 		struct blk_desc *desc = dev_get_uclass_plat(dev);
703 
704 		part_init(desc);
705 	}
706 
707 	return 0;
708 }
709 
710 UCLASS_DRIVER(blk) = {
711 	.id		= UCLASS_BLK,
712 	.name		= "blk",
713 	.post_probe	= blk_post_probe,
714 	.per_device_plat_auto	= sizeof(struct blk_desc),
715 };
716