xref: /rk3399_rockchip-uboot/drivers/block/blk-uclass.c (revision 48a18afb7cda2c6244fbb3c267cc16960c40f3fb)
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 uspinlock_t blk_lock;
16 
17 static 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",
27 	[IF_TYPE_SYSTEMACE]	= "ace",
28 	[IF_TYPE_NVME]		= "nvme",
29 	[IF_TYPE_RKNAND]	= "rknand",
30 	[IF_TYPE_SPINAND]	= "spinand",
31 	[IF_TYPE_SPINOR]	= "spinor",
32 	[IF_TYPE_RAMDISK]	= "ramdisk",
33 	[IF_TYPE_MTD]		= "mtd",
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_RKNAND]	= UCLASS_RKNAND,
48 	[IF_TYPE_SPINAND]	= UCLASS_SPI_FLASH,
49 	[IF_TYPE_SPINOR]	= UCLASS_SPI_FLASH,
50 	[IF_TYPE_RAMDISK]	= UCLASS_RAMDISK,
51 	[IF_TYPE_MTD]		= UCLASS_MTD,
52 	[IF_TYPE_SYSTEMACE]	= UCLASS_INVALID,
53 };
54 
55 enum if_type if_typename_to_iftype(const char *if_typename)
56 {
57 	int i;
58 
59 	for (i = 0; i < IF_TYPE_COUNT; i++) {
60 		if (if_typename_str[i] &&
61 		    !strcmp(if_typename, if_typename_str[i]))
62 			return i;
63 	}
64 
65 	return IF_TYPE_UNKNOWN;
66 }
67 
68 static enum uclass_id if_type_to_uclass_id(enum if_type if_type)
69 {
70 	return if_type_uclass_id[if_type];
71 }
72 
73 const char *blk_get_if_type_name(enum if_type if_type)
74 {
75 	return if_typename_str[if_type];
76 }
77 
78 struct blk_desc *blk_get_devnum_by_type(enum if_type if_type, int devnum)
79 {
80 	struct blk_desc *desc;
81 	struct udevice *dev;
82 	int ret;
83 
84 	ret = blk_get_device(if_type, devnum, &dev);
85 	if (ret)
86 		return NULL;
87 	desc = dev_get_uclass_platdata(dev);
88 
89 	return desc;
90 }
91 
92 /*
93  * This function is complicated with driver model. We look up the interface
94  * name in a local table. This gives us an interface type which we can match
95  * against the uclass of the block device's parent.
96  */
97 struct blk_desc *blk_get_devnum_by_typename(const char *if_typename, int devnum)
98 {
99 	enum uclass_id uclass_id;
100 	enum if_type if_type;
101 	struct udevice *dev;
102 	struct uclass *uc;
103 	int ret;
104 
105 	if_type = if_typename_to_iftype(if_typename);
106 	if (if_type == IF_TYPE_UNKNOWN) {
107 		debug("%s: Unknown interface type '%s'\n", __func__,
108 		      if_typename);
109 		return NULL;
110 	}
111 	uclass_id = if_type_to_uclass_id(if_type);
112 	if (uclass_id == UCLASS_INVALID) {
113 		debug("%s: Unknown uclass for interface type'\n",
114 		      if_typename_str[if_type]);
115 		return NULL;
116 	}
117 
118 	ret = uclass_get(UCLASS_BLK, &uc);
119 	if (ret)
120 		return NULL;
121 	uclass_foreach_dev(dev, uc) {
122 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
123 
124 		debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
125 		      if_type, devnum, dev->name, desc->if_type, desc->devnum);
126 		if (desc->devnum != devnum)
127 			continue;
128 
129 		/* Find out the parent device uclass */
130 		if (device_get_uclass_id(dev->parent) != uclass_id) {
131 #ifdef CONFIG_MTD_BLK
132 			/*
133 			 * The normal mtd block attachment steps are
134 			 * UCLASS_BLK -> UCLASS_MTD -> UCLASS_(SPI or NAND).
135 			 * Since the spi flash frame is attached to
136 			 * UCLASS_SPI_FLASH, this make mistake to find
137 			 * the UCLASS_MTD when find the mtd block device.
138 			 * Fix it here when enable CONFIG_MTD_BLK.
139 			 */
140 			if (device_get_uclass_id(dev->parent) == UCLASS_SPI_FLASH &&
141 			    if_type == IF_TYPE_MTD &&
142 			    devnum == BLK_MTD_SPI_NOR) {
143 				debug("Fix the spi flash uclass different\n");
144 			} else {
145 				debug("%s: parent uclass %d, this dev %d\n",
146 				      __func__,
147 				      device_get_uclass_id(dev->parent),
148 				      uclass_id);
149 				continue;
150 			}
151 #else
152 			debug("%s: parent uclass %d, this dev %d\n", __func__,
153 			      device_get_uclass_id(dev->parent), uclass_id);
154 			continue;
155 #endif
156 		}
157 
158 		if (device_probe(dev))
159 			return NULL;
160 
161 		debug("%s: Device desc %p\n", __func__, desc);
162 		return desc;
163 	}
164 	debug("%s: No device found\n", __func__);
165 
166 	return NULL;
167 }
168 
169 /**
170  * get_desc() - Get the block device descriptor for the given device number
171  *
172  * @if_type:	Interface type
173  * @devnum:	Device number (0 = first)
174  * @descp:	Returns block device descriptor on success
175  * @return 0 on success, -ENODEV if there is no such device and no device
176  * with a higher device number, -ENOENT if there is no such device but there
177  * is one with a higher number, or other -ve on other error.
178  */
179 static int get_desc(enum if_type if_type, int devnum, struct blk_desc **descp)
180 {
181 	bool found_more = false;
182 	struct udevice *dev;
183 	struct uclass *uc;
184 	int ret;
185 
186 	*descp = NULL;
187 	ret = uclass_get(UCLASS_BLK, &uc);
188 	if (ret)
189 		return ret;
190 	uclass_foreach_dev(dev, uc) {
191 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
192 
193 		debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
194 		      if_type, devnum, dev->name, desc->if_type, desc->devnum);
195 		if (desc->if_type == if_type) {
196 			if (desc->devnum == devnum) {
197 				ret = device_probe(dev);
198 				if (ret)
199 					return ret;
200 
201 				*descp = desc;
202 				return 0;
203 			} else if (desc->devnum > devnum) {
204 				found_more = true;
205 			}
206 		}
207 	}
208 
209 	return found_more ? -ENOENT : -ENODEV;
210 }
211 
212 int blk_select_hwpart_devnum(enum if_type if_type, int devnum, int hwpart)
213 {
214 	struct udevice *dev;
215 	int ret;
216 
217 	ret = blk_get_device(if_type, devnum, &dev);
218 	if (ret)
219 		return ret;
220 
221 	return blk_select_hwpart(dev, hwpart);
222 }
223 
224 int blk_list_part(enum if_type if_type)
225 {
226 	struct blk_desc *desc;
227 	int devnum, ok;
228 	int ret;
229 
230 	for (ok = 0, devnum = 0;; ++devnum) {
231 		ret = get_desc(if_type, devnum, &desc);
232 		if (ret == -ENODEV)
233 			break;
234 		else if (ret)
235 			continue;
236 		if (desc->part_type != PART_TYPE_UNKNOWN) {
237 			++ok;
238 			if (devnum)
239 				putc('\n');
240 			part_print(desc);
241 		}
242 	}
243 	if (!ok)
244 		return -ENODEV;
245 
246 	return 0;
247 }
248 
249 int blk_print_part_devnum(enum if_type if_type, int devnum)
250 {
251 	struct blk_desc *desc;
252 	int ret;
253 
254 	ret = get_desc(if_type, devnum, &desc);
255 	if (ret)
256 		return ret;
257 	if (desc->type == DEV_TYPE_UNKNOWN)
258 		return -ENOENT;
259 	part_print(desc);
260 
261 	return 0;
262 }
263 
264 void blk_list_devices(enum if_type if_type)
265 {
266 	struct blk_desc *desc;
267 	int ret;
268 	int i;
269 
270 	for (i = 0;; ++i) {
271 		ret = get_desc(if_type, i, &desc);
272 		if (ret == -ENODEV)
273 			break;
274 		else if (ret)
275 			continue;
276 		if (desc->type == DEV_TYPE_UNKNOWN)
277 			continue;  /* list only known devices */
278 		printf("Device %d: ", i);
279 		dev_print(desc);
280 	}
281 }
282 
283 int blk_print_device_num(enum if_type if_type, int devnum)
284 {
285 	struct blk_desc *desc;
286 	int ret;
287 
288 	ret = get_desc(if_type, devnum, &desc);
289 	if (ret)
290 		return ret;
291 	printf("\nIDE device %d: ", devnum);
292 	dev_print(desc);
293 
294 	return 0;
295 }
296 
297 int blk_show_device(enum if_type if_type, int devnum)
298 {
299 	struct blk_desc *desc;
300 	int ret;
301 
302 	printf("\nDevice %d: ", devnum);
303 	ret = get_desc(if_type, devnum, &desc);
304 	if (ret == -ENODEV || ret == -ENOENT) {
305 		printf("unknown device\n");
306 		return -ENODEV;
307 	}
308 	if (ret)
309 		return ret;
310 	dev_print(desc);
311 
312 	if (desc->type == DEV_TYPE_UNKNOWN)
313 		return -ENOENT;
314 
315 	return 0;
316 }
317 
318 ulong blk_read_devnum(enum if_type if_type, int devnum, lbaint_t start,
319 		      lbaint_t blkcnt, void *buffer)
320 {
321 	struct blk_desc *desc;
322 	ulong n;
323 	int ret;
324 
325 	ret = get_desc(if_type, devnum, &desc);
326 	if (ret)
327 		return ret;
328 	n = blk_dread(desc, start, blkcnt, buffer);
329 	if (IS_ERR_VALUE(n))
330 		return n;
331 
332 	return n;
333 }
334 
335 ulong blk_write_devnum(enum if_type if_type, int devnum, lbaint_t start,
336 		       lbaint_t blkcnt, const void *buffer)
337 {
338 	struct blk_desc *desc;
339 	int ret;
340 
341 	ret = get_desc(if_type, devnum, &desc);
342 	if (ret)
343 		return ret;
344 	return blk_dwrite(desc, start, blkcnt, buffer);
345 }
346 
347 ulong blk_write_zeroes_devnum(enum if_type if_type, int devnum, lbaint_t start,
348 			      lbaint_t blkcnt)
349 {
350 	struct blk_desc *desc;
351 	int ret;
352 
353 	ret = get_desc(if_type, devnum, &desc);
354 	if (ret)
355 		return ret;
356 	return blk_dwrite_zeroes(desc, start, blkcnt);
357 }
358 
359 ulong blk_erase_devnum(enum if_type if_type, int devnum, lbaint_t start,
360 		       lbaint_t blkcnt)
361 {
362 	struct blk_desc *desc;
363 	int ret;
364 
365 	ret = get_desc(if_type, devnum, &desc);
366 	if (ret)
367 		return ret;
368 	return blk_derase(desc, start, blkcnt);
369 }
370 
371 int blk_select_hwpart(struct udevice *dev, int hwpart)
372 {
373 	const struct blk_ops *ops = blk_get_ops(dev);
374 
375 	if (!ops)
376 		return -ENOSYS;
377 	if (!ops->select_hwpart)
378 		return 0;
379 
380 	return ops->select_hwpart(dev, hwpart);
381 }
382 
383 int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
384 {
385 	return blk_select_hwpart(desc->bdev, hwpart);
386 }
387 
388 int blk_first_device(int if_type, struct udevice **devp)
389 {
390 	struct blk_desc *desc;
391 	int ret;
392 
393 	ret = uclass_find_first_device(UCLASS_BLK, devp);
394 	if (ret)
395 		return ret;
396 	if (!*devp)
397 		return -ENODEV;
398 	do {
399 		desc = dev_get_uclass_platdata(*devp);
400 		if (desc->if_type == if_type)
401 			return 0;
402 		ret = uclass_find_next_device(devp);
403 		if (ret)
404 			return ret;
405 	} while (*devp);
406 
407 	return -ENODEV;
408 }
409 
410 int blk_next_device(struct udevice **devp)
411 {
412 	struct blk_desc *desc;
413 	int ret, if_type;
414 
415 	desc = dev_get_uclass_platdata(*devp);
416 	if_type = desc->if_type;
417 	do {
418 		ret = uclass_find_next_device(devp);
419 		if (ret)
420 			return ret;
421 		if (!*devp)
422 			return -ENODEV;
423 		desc = dev_get_uclass_platdata(*devp);
424 		if (desc->if_type == if_type)
425 			return 0;
426 	} while (1);
427 }
428 
429 int blk_find_device(int if_type, int devnum, struct udevice **devp)
430 {
431 	struct uclass *uc;
432 	struct udevice *dev;
433 	int ret;
434 
435 	ret = uclass_get(UCLASS_BLK, &uc);
436 	if (ret)
437 		return ret;
438 	uclass_foreach_dev(dev, uc) {
439 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
440 
441 		debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
442 		      if_type, devnum, dev->name, desc->if_type, desc->devnum);
443 		if (desc->if_type == if_type && desc->devnum == devnum) {
444 			*devp = dev;
445 			return 0;
446 		}
447 	}
448 
449 	return -ENODEV;
450 }
451 
452 int blk_get_device(int if_type, int devnum, struct udevice **devp)
453 {
454 	int ret;
455 
456 	ret = blk_find_device(if_type, devnum, devp);
457 	if (ret)
458 		return ret;
459 
460 	return device_probe(*devp);
461 }
462 
463 unsigned long blk_dread(struct blk_desc *block_dev, lbaint_t start,
464 			lbaint_t blkcnt, void *buffer)
465 {
466 	struct udevice *dev = block_dev->bdev;
467 	const struct blk_ops *ops = blk_get_ops(dev);
468 	ulong blks_read;
469 
470 	if (!ops->read)
471 		return -ENOSYS;
472 
473 	if (blkcache_read(block_dev->if_type, block_dev->devnum,
474 			  start, blkcnt, block_dev->blksz, buffer))
475 		return blkcnt;
476 
477 	u_spin_lock(&blk_lock);
478 	blks_read = ops->read(dev, start, blkcnt, buffer);
479 	u_spin_unlock(&blk_lock);
480 
481 	if (blks_read == blkcnt)
482 		blkcache_fill(block_dev->if_type, block_dev->devnum,
483 			      start, blkcnt, block_dev->blksz, buffer);
484 
485 	return blks_read;
486 }
487 
488 unsigned long blk_dwrite(struct blk_desc *block_dev, lbaint_t start,
489 			 lbaint_t blkcnt, const void *buffer)
490 {
491 	struct udevice *dev = block_dev->bdev;
492 	const struct blk_ops *ops = blk_get_ops(dev);
493 	ulong ret;
494 
495 	if (!ops->write)
496 		return -ENOSYS;
497 
498 	blkcache_invalidate(block_dev->if_type, block_dev->devnum);
499 
500 	u_spin_lock(&blk_lock);
501 	ret = ops->write(dev, start, blkcnt, buffer);
502 	u_spin_unlock(&blk_lock);
503 
504 	return ret;
505 }
506 
507 unsigned long blk_dwrite_zeroes(struct blk_desc *block_dev, lbaint_t start,
508 			       lbaint_t blkcnt)
509 {
510 	struct udevice *dev = block_dev->bdev;
511 	const struct blk_ops *ops = blk_get_ops(dev);
512 	ulong ret;
513 
514 	if (!ops->write_zeroes)
515 		return -ENOSYS;
516 
517 	blkcache_invalidate(block_dev->if_type, block_dev->devnum);
518 
519 	u_spin_lock(&blk_lock);
520 	ret = ops->write_zeroes(dev, start, blkcnt);
521 	u_spin_unlock(&blk_lock);
522 
523 	return ret;
524 }
525 
526 unsigned long blk_derase(struct blk_desc *block_dev, lbaint_t start,
527 			 lbaint_t blkcnt)
528 {
529 	struct udevice *dev = block_dev->bdev;
530 	const struct blk_ops *ops = blk_get_ops(dev);
531 	ulong ret;
532 
533 	if (!ops->erase)
534 		return -ENOSYS;
535 
536 	blkcache_invalidate(block_dev->if_type, block_dev->devnum);
537 
538 	u_spin_lock(&blk_lock);
539 	ret = ops->erase(dev, start, blkcnt);
540 	u_spin_unlock(&blk_lock);
541 
542 	return ret;
543 }
544 
545 int blk_prepare_device(struct udevice *dev)
546 {
547 	struct blk_desc *desc = dev_get_uclass_platdata(dev);
548 
549 	part_init(desc);
550 
551 	return 0;
552 }
553 
554 int blk_get_from_parent(struct udevice *parent, struct udevice **devp)
555 {
556 	struct udevice *dev;
557 	enum uclass_id id;
558 	int ret;
559 
560 	device_find_first_child(parent, &dev);
561 	if (!dev) {
562 		debug("%s: No block device found for parent '%s'\n", __func__,
563 		      parent->name);
564 		return -ENODEV;
565 	}
566 	id = device_get_uclass_id(dev);
567 	if (id != UCLASS_BLK) {
568 		debug("%s: Incorrect uclass %s for block device '%s'\n",
569 		      __func__, uclass_get_name(id), dev->name);
570 		return -ENOTBLK;
571 	}
572 	ret = device_probe(dev);
573 	if (ret)
574 		return ret;
575 	*devp = dev;
576 
577 	return 0;
578 }
579 
580 int blk_find_max_devnum(enum if_type if_type)
581 {
582 	struct udevice *dev;
583 	int max_devnum = -ENODEV;
584 	struct uclass *uc;
585 	int ret;
586 
587 	ret = uclass_get(UCLASS_BLK, &uc);
588 	if (ret)
589 		return ret;
590 	uclass_foreach_dev(dev, uc) {
591 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
592 
593 		if (desc->if_type == if_type && desc->devnum > max_devnum)
594 			max_devnum = desc->devnum;
595 	}
596 
597 	return max_devnum;
598 }
599 
600 static int blk_next_free_devnum(enum if_type if_type)
601 {
602 	int ret;
603 
604 	ret = blk_find_max_devnum(if_type);
605 	if (ret == -ENODEV)
606 		return 0;
607 	if (ret < 0)
608 		return ret;
609 
610 	return ret + 1;
611 }
612 
613 static int blk_claim_devnum(enum if_type if_type, int devnum)
614 {
615 	struct udevice *dev;
616 	struct uclass *uc;
617 	int ret;
618 
619 	ret = uclass_get(UCLASS_BLK, &uc);
620 	if (ret)
621 		return ret;
622 	uclass_foreach_dev(dev, uc) {
623 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
624 
625 		if (desc->if_type == if_type && desc->devnum == devnum) {
626 			int next = blk_next_free_devnum(if_type);
627 
628 			if (next < 0)
629 				return next;
630 #ifdef CONFIG_USING_KERNEL_DTB_V2
631 			/*
632 			 * Not allow devnum to be forced distributed.
633 			 * See commit (e48eeb9ea3 dm: blk: Improve block device claiming).
634 			 *
635 			 * fix like: "Device 'dwmmc@fe2b0000': seq 0 is in use by 'sdhci@fe310000'"
636 			 */
637 			if (!(gd->flags & GD_FLG_KDTB_READY))
638 #endif
639 			desc->devnum = next;
640 
641 			return 0;
642 		}
643 	}
644 
645 	return -ENOENT;
646 }
647 
648 int blk_create_device(struct udevice *parent, const char *drv_name,
649 		      const char *name, int if_type, int devnum, int blksz,
650 		      lbaint_t size, struct udevice **devp)
651 {
652 	struct blk_desc *desc;
653 	struct udevice *dev;
654 	int ret;
655 
656 	if (devnum == -1) {
657 		devnum = blk_next_free_devnum(if_type);
658 	} else {
659 		ret = blk_claim_devnum(if_type, devnum);
660 		if (ret < 0 && ret != -ENOENT)
661 			return ret;
662 	}
663 	if (devnum < 0)
664 		return devnum;
665 	ret = device_bind_driver(parent, drv_name, name, &dev);
666 	if (ret)
667 		return ret;
668 	desc = dev_get_uclass_platdata(dev);
669 	desc->if_type = if_type;
670 	desc->blksz = blksz;
671 	desc->rawblksz = blksz;
672 	desc->lba = size / blksz;
673 	desc->rawlba = size / blksz;
674 	desc->part_type = PART_TYPE_UNKNOWN;
675 	desc->bdev = dev;
676 	desc->devnum = devnum;
677 	*devp = dev;
678 
679 	return 0;
680 }
681 
682 int blk_create_devicef(struct udevice *parent, const char *drv_name,
683 		       const char *name, int if_type, int devnum, int blksz,
684 		       lbaint_t size, struct udevice **devp)
685 {
686 	char dev_name[30], *str;
687 	int ret;
688 
689 	snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name);
690 	str = strdup(dev_name);
691 	if (!str)
692 		return -ENOMEM;
693 
694 	ret = blk_create_device(parent, drv_name, str, if_type, devnum,
695 				blksz, size, devp);
696 	if (ret) {
697 		free(str);
698 		return ret;
699 	}
700 	device_set_name_alloced(*devp);
701 
702 	return 0;
703 }
704 
705 int blk_unbind_all(int if_type)
706 {
707 	struct uclass *uc;
708 	struct udevice *dev, *next;
709 	int ret;
710 
711 	ret = uclass_get(UCLASS_BLK, &uc);
712 	if (ret)
713 		return ret;
714 	uclass_foreach_dev_safe(dev, next, uc) {
715 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
716 
717 		if (desc->if_type == if_type) {
718 			ret = device_remove(dev, DM_REMOVE_NORMAL);
719 			if (ret)
720 				return ret;
721 			ret = device_unbind(dev);
722 			if (ret)
723 				return ret;
724 		}
725 	}
726 
727 	return 0;
728 }
729 
730 UCLASS_DRIVER(blk) = {
731 	.id		= UCLASS_BLK,
732 	.name		= "blk",
733 	.per_device_platdata_auto_alloc_size = sizeof(struct blk_desc),
734 };
735