xref: /rk3399_rockchip-uboot/drivers/block/blk-uclass.c (revision c96f14bde1f2d5d1a2c987602494a428bef46b0b)
1 /*
2  * Copyright (C) 2016 Google, Inc
3  * Written by Simon Glass <sjg@chromium.org>
4  *
5  * SPDX-License-Identifier:	GPL-2.0+
6  */
7 
8 #include <common.h>
9 #include <blk.h>
10 #include <dm.h>
11 #include <dm/device-internal.h>
12 #include <dm/lists.h>
13 #include <dm/uclass-internal.h>
14 
15 static const char *if_typename_str[IF_TYPE_COUNT] = {
16 	[IF_TYPE_IDE]		= "ide",
17 	[IF_TYPE_SCSI]		= "scsi",
18 	[IF_TYPE_ATAPI]		= "atapi",
19 	[IF_TYPE_USB]		= "usb",
20 	[IF_TYPE_DOC]		= "doc",
21 	[IF_TYPE_MMC]		= "mmc",
22 	[IF_TYPE_SD]		= "sd",
23 	[IF_TYPE_SATA]		= "sata",
24 	[IF_TYPE_HOST]		= "host",
25 	[IF_TYPE_SYSTEMACE]	= "ace",
26 	[IF_TYPE_NVME]		= "nvme",
27 	[IF_TYPE_RKNAND]	= "rknand",
28 	[IF_TYPE_SPINAND]	= "spinand",
29 	[IF_TYPE_SPINOR]	= "spinor",
30 	[IF_TYPE_RAMDISK]	= "ramdisk",
31 	[IF_TYPE_MTD]		= "mtd",
32 };
33 
34 static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = {
35 	[IF_TYPE_IDE]		= UCLASS_IDE,
36 	[IF_TYPE_SCSI]		= UCLASS_SCSI,
37 	[IF_TYPE_ATAPI]		= UCLASS_INVALID,
38 	[IF_TYPE_USB]		= UCLASS_MASS_STORAGE,
39 	[IF_TYPE_DOC]		= UCLASS_INVALID,
40 	[IF_TYPE_MMC]		= UCLASS_MMC,
41 	[IF_TYPE_SD]		= UCLASS_INVALID,
42 	[IF_TYPE_SATA]		= UCLASS_AHCI,
43 	[IF_TYPE_HOST]		= UCLASS_ROOT,
44 	[IF_TYPE_NVME]		= UCLASS_NVME,
45 	[IF_TYPE_RKNAND]	= UCLASS_RKNAND,
46 	[IF_TYPE_SPINAND]	= UCLASS_SPI_FLASH,
47 	[IF_TYPE_SPINOR]	= UCLASS_SPI_FLASH,
48 	[IF_TYPE_RAMDISK]	= UCLASS_RAMDISK,
49 	[IF_TYPE_MTD]		= UCLASS_MTD,
50 	[IF_TYPE_SYSTEMACE]	= UCLASS_INVALID,
51 };
52 
if_typename_to_iftype(const char * if_typename)53 enum if_type if_typename_to_iftype(const char *if_typename)
54 {
55 	int i;
56 
57 	for (i = 0; i < IF_TYPE_COUNT; i++) {
58 		if (if_typename_str[i] &&
59 		    !strcmp(if_typename, if_typename_str[i]))
60 			return i;
61 	}
62 
63 	return IF_TYPE_UNKNOWN;
64 }
65 
if_type_to_uclass_id(enum if_type if_type)66 static enum uclass_id if_type_to_uclass_id(enum if_type if_type)
67 {
68 	return if_type_uclass_id[if_type];
69 }
70 
blk_get_if_type_name(enum if_type if_type)71 const char *blk_get_if_type_name(enum if_type if_type)
72 {
73 	return if_typename_str[if_type];
74 }
75 
blk_get_devnum_by_type(enum if_type if_type,int devnum)76 struct blk_desc *blk_get_devnum_by_type(enum if_type if_type, int devnum)
77 {
78 	struct blk_desc *desc;
79 	struct udevice *dev;
80 	int ret;
81 
82 	ret = blk_get_device(if_type, devnum, &dev);
83 	if (ret)
84 		return NULL;
85 	desc = dev_get_uclass_platdata(dev);
86 
87 	return desc;
88 }
89 
90 /*
91  * This function is complicated with driver model. We look up the interface
92  * name in a local table. This gives us an interface type which we can match
93  * against the uclass of the block device's parent.
94  */
blk_get_devnum_by_typename(const char * if_typename,int devnum)95 struct blk_desc *blk_get_devnum_by_typename(const char *if_typename, int devnum)
96 {
97 	enum uclass_id uclass_id;
98 	enum if_type if_type;
99 	struct udevice *dev;
100 	struct uclass *uc;
101 	int ret;
102 
103 	if_type = if_typename_to_iftype(if_typename);
104 	if (if_type == IF_TYPE_UNKNOWN) {
105 		debug("%s: Unknown interface type '%s'\n", __func__,
106 		      if_typename);
107 		return NULL;
108 	}
109 	uclass_id = if_type_to_uclass_id(if_type);
110 	if (uclass_id == UCLASS_INVALID) {
111 		debug("%s: Unknown uclass for interface type'\n",
112 		      if_typename_str[if_type]);
113 		return NULL;
114 	}
115 
116 	ret = uclass_get(UCLASS_BLK, &uc);
117 	if (ret)
118 		return NULL;
119 	uclass_foreach_dev(dev, uc) {
120 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
121 
122 		debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
123 		      if_type, devnum, dev->name, desc->if_type, desc->devnum);
124 		if (desc->devnum != devnum)
125 			continue;
126 
127 		/* Find out the parent device uclass */
128 		if (device_get_uclass_id(dev->parent) != uclass_id) {
129 #ifdef CONFIG_MTD_BLK
130 			/*
131 			 * The normal mtd block attachment steps are
132 			 * UCLASS_BLK -> UCLASS_MTD -> UCLASS_(SPI or NAND).
133 			 * Since the spi flash frame is attached to
134 			 * UCLASS_SPI_FLASH, this make mistake to find
135 			 * the UCLASS_MTD when find the mtd block device.
136 			 * Fix it here when enable CONFIG_MTD_BLK.
137 			 */
138 			if (device_get_uclass_id(dev->parent) == UCLASS_SPI_FLASH &&
139 			    if_type == IF_TYPE_MTD &&
140 			    devnum == BLK_MTD_SPI_NOR) {
141 				debug("Fix the spi flash uclass different\n");
142 			} else {
143 				debug("%s: parent uclass %d, this dev %d\n",
144 				      __func__,
145 				      device_get_uclass_id(dev->parent),
146 				      uclass_id);
147 				continue;
148 			}
149 #else
150 			debug("%s: parent uclass %d, this dev %d\n", __func__,
151 			      device_get_uclass_id(dev->parent), uclass_id);
152 			continue;
153 #endif
154 		}
155 
156 		if (device_probe(dev))
157 			return NULL;
158 
159 		debug("%s: Device desc %p\n", __func__, desc);
160 		return desc;
161 	}
162 	debug("%s: No 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_platdata(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_write_zeroes_devnum(enum if_type if_type,int devnum,lbaint_t start,lbaint_t blkcnt)345 ulong blk_write_zeroes_devnum(enum if_type if_type, int devnum, lbaint_t start,
346 			      lbaint_t blkcnt)
347 {
348 	struct blk_desc *desc;
349 	int ret;
350 
351 	ret = get_desc(if_type, devnum, &desc);
352 	if (ret)
353 		return ret;
354 	return blk_dwrite_zeroes(desc, start, blkcnt);
355 }
356 
blk_erase_devnum(enum if_type if_type,int devnum,lbaint_t start,lbaint_t blkcnt)357 ulong blk_erase_devnum(enum if_type if_type, int devnum, lbaint_t start,
358 		       lbaint_t blkcnt)
359 {
360 	struct blk_desc *desc;
361 	int ret;
362 
363 	ret = get_desc(if_type, devnum, &desc);
364 	if (ret)
365 		return ret;
366 	return blk_derase(desc, start, blkcnt);
367 }
368 
blk_select_hwpart(struct udevice * dev,int hwpart)369 int blk_select_hwpart(struct udevice *dev, int hwpart)
370 {
371 	const struct blk_ops *ops = blk_get_ops(dev);
372 
373 	if (!ops)
374 		return -ENOSYS;
375 	if (!ops->select_hwpart)
376 		return 0;
377 
378 	return ops->select_hwpart(dev, hwpart);
379 }
380 
blk_dselect_hwpart(struct blk_desc * desc,int hwpart)381 int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
382 {
383 	return blk_select_hwpart(desc->bdev, hwpart);
384 }
385 
blk_first_device(int if_type,struct udevice ** devp)386 int blk_first_device(int if_type, struct udevice **devp)
387 {
388 	struct blk_desc *desc;
389 	int ret;
390 
391 	ret = uclass_find_first_device(UCLASS_BLK, devp);
392 	if (ret)
393 		return ret;
394 	if (!*devp)
395 		return -ENODEV;
396 	do {
397 		desc = dev_get_uclass_platdata(*devp);
398 		if (desc->if_type == if_type)
399 			return 0;
400 		ret = uclass_find_next_device(devp);
401 		if (ret)
402 			return ret;
403 	} while (*devp);
404 
405 	return -ENODEV;
406 }
407 
blk_next_device(struct udevice ** devp)408 int blk_next_device(struct udevice **devp)
409 {
410 	struct blk_desc *desc;
411 	int ret, if_type;
412 
413 	desc = dev_get_uclass_platdata(*devp);
414 	if_type = desc->if_type;
415 	do {
416 		ret = uclass_find_next_device(devp);
417 		if (ret)
418 			return ret;
419 		if (!*devp)
420 			return -ENODEV;
421 		desc = dev_get_uclass_platdata(*devp);
422 		if (desc->if_type == if_type)
423 			return 0;
424 	} while (1);
425 }
426 
blk_find_device(int if_type,int devnum,struct udevice ** devp)427 int blk_find_device(int if_type, int devnum, struct udevice **devp)
428 {
429 	struct uclass *uc;
430 	struct udevice *dev;
431 	int ret;
432 
433 	ret = uclass_get(UCLASS_BLK, &uc);
434 	if (ret)
435 		return ret;
436 	uclass_foreach_dev(dev, uc) {
437 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
438 
439 		debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
440 		      if_type, devnum, dev->name, desc->if_type, desc->devnum);
441 		if (desc->if_type == if_type && desc->devnum == devnum) {
442 			*devp = dev;
443 			return 0;
444 		}
445 	}
446 
447 	return -ENODEV;
448 }
449 
blk_get_device(int if_type,int devnum,struct udevice ** devp)450 int blk_get_device(int if_type, int devnum, struct udevice **devp)
451 {
452 	int ret;
453 
454 	ret = blk_find_device(if_type, devnum, devp);
455 	if (ret)
456 		return ret;
457 
458 	return device_probe(*devp);
459 }
460 
blk_dread(struct blk_desc * block_dev,lbaint_t start,lbaint_t blkcnt,void * buffer)461 unsigned long blk_dread(struct blk_desc *block_dev, lbaint_t start,
462 			lbaint_t blkcnt, void *buffer)
463 {
464 	struct udevice *dev = block_dev->bdev;
465 	const struct blk_ops *ops = blk_get_ops(dev);
466 	ulong blks_read;
467 
468 	if (!ops->read)
469 		return -ENOSYS;
470 
471 	if (blkcache_read(block_dev->if_type, block_dev->devnum,
472 			  start, blkcnt, block_dev->blksz, buffer))
473 		return blkcnt;
474 
475 	u_spin_lock(&block_dev->blk_lock);
476 	blks_read = ops->read(dev, start, blkcnt, buffer);
477 	u_spin_unlock(&block_dev->blk_lock);
478 
479 	if (blks_read == blkcnt)
480 		blkcache_fill(block_dev->if_type, block_dev->devnum,
481 			      start, blkcnt, block_dev->blksz, buffer);
482 
483 	return blks_read;
484 }
485 
blk_dwrite(struct blk_desc * block_dev,lbaint_t start,lbaint_t blkcnt,const void * buffer)486 unsigned long blk_dwrite(struct blk_desc *block_dev, lbaint_t start,
487 			 lbaint_t blkcnt, const void *buffer)
488 {
489 	struct udevice *dev = block_dev->bdev;
490 	const struct blk_ops *ops = blk_get_ops(dev);
491 	ulong ret;
492 
493 	if (!ops->write)
494 		return -ENOSYS;
495 
496 	blkcache_invalidate(block_dev->if_type, block_dev->devnum);
497 
498 	u_spin_lock(&block_dev->blk_lock);
499 	ret = ops->write(dev, start, blkcnt, buffer);
500 	u_spin_unlock(&block_dev->blk_lock);
501 
502 	return ret;
503 }
504 
blk_dwrite_zeroes(struct blk_desc * block_dev,lbaint_t start,lbaint_t blkcnt)505 unsigned long blk_dwrite_zeroes(struct blk_desc *block_dev, lbaint_t start,
506 			       lbaint_t blkcnt)
507 {
508 	struct udevice *dev = block_dev->bdev;
509 	const struct blk_ops *ops = blk_get_ops(dev);
510 	ulong ret;
511 
512 	if (!ops->write_zeroes)
513 		return -ENOSYS;
514 
515 	blkcache_invalidate(block_dev->if_type, block_dev->devnum);
516 
517 	u_spin_lock(&block_dev->blk_lock);
518 	ret = ops->write_zeroes(dev, start, blkcnt);
519 	u_spin_unlock(&block_dev->blk_lock);
520 
521 	return ret;
522 }
523 
blk_derase(struct blk_desc * block_dev,lbaint_t start,lbaint_t blkcnt)524 unsigned long blk_derase(struct blk_desc *block_dev, lbaint_t start,
525 			 lbaint_t blkcnt)
526 {
527 	struct udevice *dev = block_dev->bdev;
528 	const struct blk_ops *ops = blk_get_ops(dev);
529 	ulong ret;
530 
531 	if (!ops->erase)
532 		return -ENOSYS;
533 
534 	blkcache_invalidate(block_dev->if_type, block_dev->devnum);
535 
536 	u_spin_lock(&block_dev->blk_lock);
537 	ret = ops->erase(dev, start, blkcnt);
538 	u_spin_unlock(&block_dev->blk_lock);
539 
540 	return ret;
541 }
542 
blk_prepare_device(struct udevice * dev)543 int blk_prepare_device(struct udevice *dev)
544 {
545 	struct blk_desc *desc = dev_get_uclass_platdata(dev);
546 
547 	part_init(desc);
548 
549 	return 0;
550 }
551 
blk_get_from_parent(struct udevice * parent,struct udevice ** devp)552 int blk_get_from_parent(struct udevice *parent, struct udevice **devp)
553 {
554 	struct udevice *dev;
555 	enum uclass_id id;
556 	int ret;
557 
558 	device_find_first_child(parent, &dev);
559 	if (!dev) {
560 		debug("%s: No block device found for parent '%s'\n", __func__,
561 		      parent->name);
562 		return -ENODEV;
563 	}
564 	id = device_get_uclass_id(dev);
565 	if (id != UCLASS_BLK) {
566 		debug("%s: Incorrect uclass %s for block device '%s'\n",
567 		      __func__, uclass_get_name(id), dev->name);
568 		return -ENOTBLK;
569 	}
570 	ret = device_probe(dev);
571 	if (ret)
572 		return ret;
573 	*devp = dev;
574 
575 	return 0;
576 }
577 
blk_find_max_devnum(enum if_type if_type)578 int blk_find_max_devnum(enum if_type if_type)
579 {
580 	struct udevice *dev;
581 	int max_devnum = -ENODEV;
582 	struct uclass *uc;
583 	int ret;
584 
585 	ret = uclass_get(UCLASS_BLK, &uc);
586 	if (ret)
587 		return ret;
588 	uclass_foreach_dev(dev, uc) {
589 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
590 
591 		if (desc->if_type == if_type && desc->devnum > max_devnum)
592 			max_devnum = desc->devnum;
593 	}
594 
595 	return max_devnum;
596 }
597 
blk_next_free_devnum(enum if_type if_type)598 static int blk_next_free_devnum(enum if_type if_type)
599 {
600 	int ret;
601 
602 	ret = blk_find_max_devnum(if_type);
603 	if (ret == -ENODEV)
604 		return 0;
605 	if (ret < 0)
606 		return ret;
607 
608 	return ret + 1;
609 }
610 
blk_claim_devnum(enum if_type if_type,int devnum)611 static int blk_claim_devnum(enum if_type if_type, int devnum)
612 {
613 	struct udevice *dev;
614 	struct uclass *uc;
615 	int ret;
616 
617 	ret = uclass_get(UCLASS_BLK, &uc);
618 	if (ret)
619 		return ret;
620 	uclass_foreach_dev(dev, uc) {
621 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
622 
623 		if (desc->if_type == if_type && desc->devnum == devnum) {
624 			int next = blk_next_free_devnum(if_type);
625 
626 			if (next < 0)
627 				return next;
628 #ifdef CONFIG_USING_KERNEL_DTB_V2
629 			/*
630 			 * Not allow devnum to be forced distributed.
631 			 * See commit (e48eeb9ea3 dm: blk: Improve block device claiming).
632 			 *
633 			 * fix like: "Device 'dwmmc@fe2b0000': seq 0 is in use by 'sdhci@fe310000'"
634 			 */
635 			if (!(gd->flags & GD_FLG_KDTB_READY))
636 #endif
637 			desc->devnum = next;
638 
639 			return 0;
640 		}
641 	}
642 
643 	return -ENOENT;
644 }
645 
blk_create_device(struct udevice * parent,const char * drv_name,const char * name,int if_type,int devnum,int blksz,lbaint_t size,struct udevice ** devp)646 int blk_create_device(struct udevice *parent, const char *drv_name,
647 		      const char *name, int if_type, int devnum, int blksz,
648 		      lbaint_t size, struct udevice **devp)
649 {
650 	struct blk_desc *desc;
651 	struct udevice *dev;
652 	int ret;
653 
654 	if (devnum == -1) {
655 		devnum = blk_next_free_devnum(if_type);
656 	} else {
657 		ret = blk_claim_devnum(if_type, devnum);
658 		if (ret < 0 && ret != -ENOENT)
659 			return ret;
660 	}
661 	if (devnum < 0)
662 		return devnum;
663 	ret = device_bind_driver(parent, drv_name, name, &dev);
664 	if (ret)
665 		return ret;
666 	desc = dev_get_uclass_platdata(dev);
667 	desc->if_type = if_type;
668 	desc->blksz = blksz;
669 	desc->rawblksz = blksz;
670 	desc->lba = size / blksz;
671 	desc->rawlba = size / blksz;
672 	desc->part_type = PART_TYPE_UNKNOWN;
673 	desc->bdev = dev;
674 	desc->devnum = devnum;
675 	*devp = dev;
676 
677 	return 0;
678 }
679 
blk_create_devicef(struct udevice * parent,const char * drv_name,const char * name,int if_type,int devnum,int blksz,lbaint_t size,struct udevice ** devp)680 int blk_create_devicef(struct udevice *parent, const char *drv_name,
681 		       const char *name, int if_type, int devnum, int blksz,
682 		       lbaint_t size, struct udevice **devp)
683 {
684 	char dev_name[30], *str;
685 	int ret;
686 
687 	snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name);
688 	str = strdup(dev_name);
689 	if (!str)
690 		return -ENOMEM;
691 
692 	ret = blk_create_device(parent, drv_name, str, if_type, devnum,
693 				blksz, size, devp);
694 	if (ret) {
695 		free(str);
696 		return ret;
697 	}
698 	device_set_name_alloced(*devp);
699 
700 	return 0;
701 }
702 
blk_unbind_all(int if_type)703 int blk_unbind_all(int if_type)
704 {
705 	struct uclass *uc;
706 	struct udevice *dev, *next;
707 	int ret;
708 
709 	ret = uclass_get(UCLASS_BLK, &uc);
710 	if (ret)
711 		return ret;
712 	uclass_foreach_dev_safe(dev, next, uc) {
713 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
714 
715 		if (desc->if_type == if_type) {
716 			ret = device_remove(dev, DM_REMOVE_NORMAL);
717 			if (ret)
718 				return ret;
719 			ret = device_unbind(dev);
720 			if (ret)
721 				return ret;
722 		}
723 	}
724 
725 	return 0;
726 }
727 
728 UCLASS_DRIVER(blk) = {
729 	.id		= UCLASS_BLK,
730 	.name		= "blk",
731 	.per_device_platdata_auto_alloc_size = sizeof(struct blk_desc),
732 };
733