mx6sabresd: convert to DM_VIDEO
[oweals/u-boot.git] / drivers / block / blk-uclass.c
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 #include <common.h>
8 #include <blk.h>
9 #include <dm.h>
10 #include <dm/device-internal.h>
11 #include <dm/lists.h>
12 #include <dm/uclass-internal.h>
13
14 static const char *if_typename_str[IF_TYPE_COUNT] = {
15         [IF_TYPE_IDE]           = "ide",
16         [IF_TYPE_SCSI]          = "scsi",
17         [IF_TYPE_ATAPI]         = "atapi",
18         [IF_TYPE_USB]           = "usb",
19         [IF_TYPE_DOC]           = "doc",
20         [IF_TYPE_MMC]           = "mmc",
21         [IF_TYPE_SD]            = "sd",
22         [IF_TYPE_SATA]          = "sata",
23         [IF_TYPE_HOST]          = "host",
24         [IF_TYPE_NVME]          = "nvme",
25         [IF_TYPE_EFI]           = "efi",
26         [IF_TYPE_VIRTIO]        = "virtio",
27 };
28
29 static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = {
30         [IF_TYPE_IDE]           = UCLASS_IDE,
31         [IF_TYPE_SCSI]          = UCLASS_SCSI,
32         [IF_TYPE_ATAPI]         = UCLASS_INVALID,
33         [IF_TYPE_USB]           = UCLASS_MASS_STORAGE,
34         [IF_TYPE_DOC]           = UCLASS_INVALID,
35         [IF_TYPE_MMC]           = UCLASS_MMC,
36         [IF_TYPE_SD]            = UCLASS_INVALID,
37         [IF_TYPE_SATA]          = UCLASS_AHCI,
38         [IF_TYPE_HOST]          = UCLASS_ROOT,
39         [IF_TYPE_NVME]          = UCLASS_NVME,
40         [IF_TYPE_EFI]           = UCLASS_EFI,
41         [IF_TYPE_VIRTIO]        = UCLASS_VIRTIO,
42 };
43
44 static enum if_type if_typename_to_iftype(const char *if_typename)
45 {
46         int i;
47
48         for (i = 0; i < IF_TYPE_COUNT; i++) {
49                 if (if_typename_str[i] &&
50                     !strcmp(if_typename, if_typename_str[i]))
51                         return i;
52         }
53
54         return IF_TYPE_UNKNOWN;
55 }
56
57 static enum uclass_id if_type_to_uclass_id(enum if_type if_type)
58 {
59         return if_type_uclass_id[if_type];
60 }
61
62 const char *blk_get_if_type_name(enum if_type if_type)
63 {
64         return if_typename_str[if_type];
65 }
66
67 struct blk_desc *blk_get_devnum_by_type(enum if_type if_type, int devnum)
68 {
69         struct blk_desc *desc;
70         struct udevice *dev;
71         int ret;
72
73         ret = blk_get_device(if_type, devnum, &dev);
74         if (ret)
75                 return NULL;
76         desc = dev_get_uclass_platdata(dev);
77
78         return desc;
79 }
80
81 /*
82  * This function is complicated with driver model. We look up the interface
83  * name in a local table. This gives us an interface type which we can match
84  * against the uclass of the block device's parent.
85  */
86 struct blk_desc *blk_get_devnum_by_typename(const char *if_typename, int devnum)
87 {
88         enum uclass_id uclass_id;
89         enum if_type if_type;
90         struct udevice *dev;
91         struct uclass *uc;
92         int ret;
93
94         if_type = if_typename_to_iftype(if_typename);
95         if (if_type == IF_TYPE_UNKNOWN) {
96                 debug("%s: Unknown interface type '%s'\n", __func__,
97                       if_typename);
98                 return NULL;
99         }
100         uclass_id = if_type_to_uclass_id(if_type);
101         if (uclass_id == UCLASS_INVALID) {
102                 debug("%s: Unknown uclass for interface type'\n",
103                       if_typename_str[if_type]);
104                 return NULL;
105         }
106
107         ret = uclass_get(UCLASS_BLK, &uc);
108         if (ret)
109                 return NULL;
110         uclass_foreach_dev(dev, uc) {
111                 struct blk_desc *desc = dev_get_uclass_platdata(dev);
112
113                 debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
114                       if_type, devnum, dev->name, desc->if_type, desc->devnum);
115                 if (desc->devnum != devnum)
116                         continue;
117
118                 /* Find out the parent device uclass */
119                 if (device_get_uclass_id(dev->parent) != uclass_id) {
120                         debug("%s: parent uclass %d, this dev %d\n", __func__,
121                               device_get_uclass_id(dev->parent), uclass_id);
122                         continue;
123                 }
124
125                 if (device_probe(dev))
126                         return NULL;
127
128                 debug("%s: Device desc %p\n", __func__, desc);
129                 return desc;
130         }
131         debug("%s: No device found\n", __func__);
132
133         return NULL;
134 }
135
136 /**
137  * blk_get_by_device() - Get the block device descriptor for the given device
138  * @dev:        Instance of a storage device
139  *
140  * Return: With block device descriptor on success , NULL if there is no such
141  *         block device.
142  */
143 struct blk_desc *blk_get_by_device(struct udevice *dev)
144 {
145         struct udevice *child_dev, *next;
146
147         device_foreach_child_safe(child_dev, next, dev) {
148                 if (device_get_uclass_id(child_dev) != UCLASS_BLK)
149                         continue;
150
151                 return dev_get_uclass_platdata(child_dev);
152         }
153
154         debug("%s: No block device found\n", __func__);
155
156         return NULL;
157 }
158
159 /**
160  * get_desc() - Get the block device descriptor for the given device number
161  *
162  * @if_type:    Interface type
163  * @devnum:     Device number (0 = first)
164  * @descp:      Returns block device descriptor on success
165  * @return 0 on success, -ENODEV if there is no such device and no device
166  * with a higher device number, -ENOENT if there is no such device but there
167  * is one with a higher number, or other -ve on other error.
168  */
169 static int get_desc(enum if_type if_type, int devnum, struct blk_desc **descp)
170 {
171         bool found_more = false;
172         struct udevice *dev;
173         struct uclass *uc;
174         int ret;
175
176         *descp = NULL;
177         ret = uclass_get(UCLASS_BLK, &uc);
178         if (ret)
179                 return ret;
180         uclass_foreach_dev(dev, uc) {
181                 struct blk_desc *desc = dev_get_uclass_platdata(dev);
182
183                 debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
184                       if_type, devnum, dev->name, desc->if_type, desc->devnum);
185                 if (desc->if_type == if_type) {
186                         if (desc->devnum == devnum) {
187                                 ret = device_probe(dev);
188                                 if (ret)
189                                         return ret;
190
191                                 *descp = desc;
192                                 return 0;
193                         } else if (desc->devnum > devnum) {
194                                 found_more = true;
195                         }
196                 }
197         }
198
199         return found_more ? -ENOENT : -ENODEV;
200 }
201
202 int blk_select_hwpart_devnum(enum if_type if_type, int devnum, int hwpart)
203 {
204         struct udevice *dev;
205         int ret;
206
207         ret = blk_get_device(if_type, devnum, &dev);
208         if (ret)
209                 return ret;
210
211         return blk_select_hwpart(dev, hwpart);
212 }
213
214 int blk_list_part(enum if_type if_type)
215 {
216         struct blk_desc *desc;
217         int devnum, ok;
218         int ret;
219
220         for (ok = 0, devnum = 0;; ++devnum) {
221                 ret = get_desc(if_type, devnum, &desc);
222                 if (ret == -ENODEV)
223                         break;
224                 else if (ret)
225                         continue;
226                 if (desc->part_type != PART_TYPE_UNKNOWN) {
227                         ++ok;
228                         if (devnum)
229                                 putc('\n');
230                         part_print(desc);
231                 }
232         }
233         if (!ok)
234                 return -ENODEV;
235
236         return 0;
237 }
238
239 int blk_print_part_devnum(enum if_type if_type, int devnum)
240 {
241         struct blk_desc *desc;
242         int ret;
243
244         ret = get_desc(if_type, devnum, &desc);
245         if (ret)
246                 return ret;
247         if (desc->type == DEV_TYPE_UNKNOWN)
248                 return -ENOENT;
249         part_print(desc);
250
251         return 0;
252 }
253
254 void blk_list_devices(enum if_type if_type)
255 {
256         struct blk_desc *desc;
257         int ret;
258         int i;
259
260         for (i = 0;; ++i) {
261                 ret = get_desc(if_type, i, &desc);
262                 if (ret == -ENODEV)
263                         break;
264                 else if (ret)
265                         continue;
266                 if (desc->type == DEV_TYPE_UNKNOWN)
267                         continue;  /* list only known devices */
268                 printf("Device %d: ", i);
269                 dev_print(desc);
270         }
271 }
272
273 int blk_print_device_num(enum if_type if_type, int devnum)
274 {
275         struct blk_desc *desc;
276         int ret;
277
278         ret = get_desc(if_type, devnum, &desc);
279         if (ret)
280                 return ret;
281         printf("\nIDE device %d: ", devnum);
282         dev_print(desc);
283
284         return 0;
285 }
286
287 int blk_show_device(enum if_type if_type, int devnum)
288 {
289         struct blk_desc *desc;
290         int ret;
291
292         printf("\nDevice %d: ", devnum);
293         ret = get_desc(if_type, devnum, &desc);
294         if (ret == -ENODEV || ret == -ENOENT) {
295                 printf("unknown device\n");
296                 return -ENODEV;
297         }
298         if (ret)
299                 return ret;
300         dev_print(desc);
301
302         if (desc->type == DEV_TYPE_UNKNOWN)
303                 return -ENOENT;
304
305         return 0;
306 }
307
308 ulong blk_read_devnum(enum if_type if_type, int devnum, lbaint_t start,
309                       lbaint_t blkcnt, void *buffer)
310 {
311         struct blk_desc *desc;
312         ulong n;
313         int ret;
314
315         ret = get_desc(if_type, devnum, &desc);
316         if (ret)
317                 return ret;
318         n = blk_dread(desc, start, blkcnt, buffer);
319         if (IS_ERR_VALUE(n))
320                 return n;
321
322         return n;
323 }
324
325 ulong blk_write_devnum(enum if_type if_type, int devnum, lbaint_t start,
326                        lbaint_t blkcnt, const void *buffer)
327 {
328         struct blk_desc *desc;
329         int ret;
330
331         ret = get_desc(if_type, devnum, &desc);
332         if (ret)
333                 return ret;
334         return blk_dwrite(desc, start, blkcnt, buffer);
335 }
336
337 int blk_select_hwpart(struct udevice *dev, int hwpart)
338 {
339         const struct blk_ops *ops = blk_get_ops(dev);
340
341         if (!ops)
342                 return -ENOSYS;
343         if (!ops->select_hwpart)
344                 return 0;
345
346         return ops->select_hwpart(dev, hwpart);
347 }
348
349 int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
350 {
351         return blk_select_hwpart(desc->bdev, hwpart);
352 }
353
354 int blk_first_device(int if_type, struct udevice **devp)
355 {
356         struct blk_desc *desc;
357         int ret;
358
359         ret = uclass_find_first_device(UCLASS_BLK, devp);
360         if (ret)
361                 return ret;
362         if (!*devp)
363                 return -ENODEV;
364         do {
365                 desc = dev_get_uclass_platdata(*devp);
366                 if (desc->if_type == if_type)
367                         return 0;
368                 ret = uclass_find_next_device(devp);
369                 if (ret)
370                         return ret;
371         } while (*devp);
372
373         return -ENODEV;
374 }
375
376 int blk_next_device(struct udevice **devp)
377 {
378         struct blk_desc *desc;
379         int ret, if_type;
380
381         desc = dev_get_uclass_platdata(*devp);
382         if_type = desc->if_type;
383         do {
384                 ret = uclass_find_next_device(devp);
385                 if (ret)
386                         return ret;
387                 if (!*devp)
388                         return -ENODEV;
389                 desc = dev_get_uclass_platdata(*devp);
390                 if (desc->if_type == if_type)
391                         return 0;
392         } while (1);
393 }
394
395 int blk_find_device(int if_type, int devnum, struct udevice **devp)
396 {
397         struct uclass *uc;
398         struct udevice *dev;
399         int ret;
400
401         ret = uclass_get(UCLASS_BLK, &uc);
402         if (ret)
403                 return ret;
404         uclass_foreach_dev(dev, uc) {
405                 struct blk_desc *desc = dev_get_uclass_platdata(dev);
406
407                 debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
408                       if_type, devnum, dev->name, desc->if_type, desc->devnum);
409                 if (desc->if_type == if_type && desc->devnum == devnum) {
410                         *devp = dev;
411                         return 0;
412                 }
413         }
414
415         return -ENODEV;
416 }
417
418 int blk_get_device(int if_type, int devnum, struct udevice **devp)
419 {
420         int ret;
421
422         ret = blk_find_device(if_type, devnum, devp);
423         if (ret)
424                 return ret;
425
426         return device_probe(*devp);
427 }
428
429 unsigned long blk_dread(struct blk_desc *block_dev, lbaint_t start,
430                         lbaint_t blkcnt, void *buffer)
431 {
432         struct udevice *dev = block_dev->bdev;
433         const struct blk_ops *ops = blk_get_ops(dev);
434         ulong blks_read;
435
436         if (!ops->read)
437                 return -ENOSYS;
438
439         if (blkcache_read(block_dev->if_type, block_dev->devnum,
440                           start, blkcnt, block_dev->blksz, buffer))
441                 return blkcnt;
442         blks_read = ops->read(dev, start, blkcnt, buffer);
443         if (blks_read == blkcnt)
444                 blkcache_fill(block_dev->if_type, block_dev->devnum,
445                               start, blkcnt, block_dev->blksz, buffer);
446
447         return blks_read;
448 }
449
450 unsigned long blk_dwrite(struct blk_desc *block_dev, lbaint_t start,
451                          lbaint_t blkcnt, const void *buffer)
452 {
453         struct udevice *dev = block_dev->bdev;
454         const struct blk_ops *ops = blk_get_ops(dev);
455
456         if (!ops->write)
457                 return -ENOSYS;
458
459         blkcache_invalidate(block_dev->if_type, block_dev->devnum);
460         return ops->write(dev, start, blkcnt, buffer);
461 }
462
463 unsigned long blk_derase(struct blk_desc *block_dev, lbaint_t start,
464                          lbaint_t blkcnt)
465 {
466         struct udevice *dev = block_dev->bdev;
467         const struct blk_ops *ops = blk_get_ops(dev);
468
469         if (!ops->erase)
470                 return -ENOSYS;
471
472         blkcache_invalidate(block_dev->if_type, block_dev->devnum);
473         return ops->erase(dev, start, blkcnt);
474 }
475
476 int blk_get_from_parent(struct udevice *parent, struct udevice **devp)
477 {
478         struct udevice *dev;
479         enum uclass_id id;
480         int ret;
481
482         device_find_first_child(parent, &dev);
483         if (!dev) {
484                 debug("%s: No block device found for parent '%s'\n", __func__,
485                       parent->name);
486                 return -ENODEV;
487         }
488         id = device_get_uclass_id(dev);
489         if (id != UCLASS_BLK) {
490                 debug("%s: Incorrect uclass %s for block device '%s'\n",
491                       __func__, uclass_get_name(id), dev->name);
492                 return -ENOTBLK;
493         }
494         ret = device_probe(dev);
495         if (ret)
496                 return ret;
497         *devp = dev;
498
499         return 0;
500 }
501
502 int blk_find_max_devnum(enum if_type if_type)
503 {
504         struct udevice *dev;
505         int max_devnum = -ENODEV;
506         struct uclass *uc;
507         int ret;
508
509         ret = uclass_get(UCLASS_BLK, &uc);
510         if (ret)
511                 return ret;
512         uclass_foreach_dev(dev, uc) {
513                 struct blk_desc *desc = dev_get_uclass_platdata(dev);
514
515                 if (desc->if_type == if_type && desc->devnum > max_devnum)
516                         max_devnum = desc->devnum;
517         }
518
519         return max_devnum;
520 }
521
522 int blk_next_free_devnum(enum if_type if_type)
523 {
524         int ret;
525
526         ret = blk_find_max_devnum(if_type);
527         if (ret == -ENODEV)
528                 return 0;
529         if (ret < 0)
530                 return ret;
531
532         return ret + 1;
533 }
534
535 static int blk_claim_devnum(enum if_type if_type, int devnum)
536 {
537         struct udevice *dev;
538         struct uclass *uc;
539         int ret;
540
541         ret = uclass_get(UCLASS_BLK, &uc);
542         if (ret)
543                 return ret;
544         uclass_foreach_dev(dev, uc) {
545                 struct blk_desc *desc = dev_get_uclass_platdata(dev);
546
547                 if (desc->if_type == if_type && desc->devnum == devnum) {
548                         int next = blk_next_free_devnum(if_type);
549
550                         if (next < 0)
551                                 return next;
552                         desc->devnum = next;
553                         return 0;
554                 }
555         }
556
557         return -ENOENT;
558 }
559
560 int blk_create_device(struct udevice *parent, const char *drv_name,
561                       const char *name, int if_type, int devnum, int blksz,
562                       lbaint_t lba, struct udevice **devp)
563 {
564         struct blk_desc *desc;
565         struct udevice *dev;
566         int ret;
567
568         if (devnum == -1) {
569                 devnum = blk_next_free_devnum(if_type);
570         } else {
571                 ret = blk_claim_devnum(if_type, devnum);
572                 if (ret < 0 && ret != -ENOENT)
573                         return ret;
574         }
575         if (devnum < 0)
576                 return devnum;
577         ret = device_bind_driver(parent, drv_name, name, &dev);
578         if (ret)
579                 return ret;
580         desc = dev_get_uclass_platdata(dev);
581         desc->if_type = if_type;
582         desc->blksz = blksz;
583         desc->lba = lba;
584         desc->part_type = PART_TYPE_UNKNOWN;
585         desc->bdev = dev;
586         desc->devnum = devnum;
587         *devp = dev;
588
589         return 0;
590 }
591
592 int blk_create_devicef(struct udevice *parent, const char *drv_name,
593                        const char *name, int if_type, int devnum, int blksz,
594                        lbaint_t lba, struct udevice **devp)
595 {
596         char dev_name[30], *str;
597         int ret;
598
599         snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name);
600         str = strdup(dev_name);
601         if (!str)
602                 return -ENOMEM;
603
604         ret = blk_create_device(parent, drv_name, str, if_type, devnum,
605                                 blksz, lba, devp);
606         if (ret) {
607                 free(str);
608                 return ret;
609         }
610         device_set_name_alloced(*devp);
611
612         return 0;
613 }
614
615 int blk_unbind_all(int if_type)
616 {
617         struct uclass *uc;
618         struct udevice *dev, *next;
619         int ret;
620
621         ret = uclass_get(UCLASS_BLK, &uc);
622         if (ret)
623                 return ret;
624         uclass_foreach_dev_safe(dev, next, uc) {
625                 struct blk_desc *desc = dev_get_uclass_platdata(dev);
626
627                 if (desc->if_type == if_type) {
628                         ret = device_remove(dev, DM_REMOVE_NORMAL);
629                         if (ret)
630                                 return ret;
631                         ret = device_unbind(dev);
632                         if (ret)
633                                 return ret;
634                 }
635         }
636
637         return 0;
638 }
639
640 static int blk_post_probe(struct udevice *dev)
641 {
642 #if defined(CONFIG_PARTITIONS) && defined(CONFIG_HAVE_BLOCK_DEVICE)
643         struct blk_desc *desc = dev_get_uclass_platdata(dev);
644
645         part_init(desc);
646 #endif
647
648         return 0;
649 }
650
651 UCLASS_DRIVER(blk) = {
652         .id             = UCLASS_BLK,
653         .name           = "blk",
654         .post_probe     = blk_post_probe,
655         .per_device_platdata_auto_alloc_size = sizeof(struct blk_desc),
656 };