]> git.karo-electronics.de Git - karo-tx-uboot.git/blob - drivers/block/blk-uclass.c
6ba1026f5818efc61f69182112a79fd60d75fa1a
[karo-tx-uboot.git] / drivers / block / blk-uclass.c
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
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_SYSTEMACE]     = "ace",
25 };
26
27 static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = {
28         [IF_TYPE_IDE]           = UCLASS_INVALID,
29         [IF_TYPE_SCSI]          = UCLASS_INVALID,
30         [IF_TYPE_ATAPI]         = UCLASS_INVALID,
31         [IF_TYPE_USB]           = UCLASS_MASS_STORAGE,
32         [IF_TYPE_DOC]           = UCLASS_INVALID,
33         [IF_TYPE_MMC]           = UCLASS_MMC,
34         [IF_TYPE_SD]            = UCLASS_INVALID,
35         [IF_TYPE_SATA]          = UCLASS_AHCI,
36         [IF_TYPE_HOST]          = UCLASS_ROOT,
37         [IF_TYPE_SYSTEMACE]     = UCLASS_INVALID,
38 };
39
40 static enum if_type if_typename_to_iftype(const char *if_typename)
41 {
42         int i;
43
44         for (i = 0; i < IF_TYPE_COUNT; i++) {
45                 if (if_typename_str[i] &&
46                     !strcmp(if_typename, if_typename_str[i]))
47                         return i;
48         }
49
50         return IF_TYPE_UNKNOWN;
51 }
52
53 static enum uclass_id if_type_to_uclass_id(enum if_type if_type)
54 {
55         return if_type_uclass_id[if_type];
56 }
57
58 struct blk_desc *blk_get_devnum_by_type(enum if_type if_type, int devnum)
59 {
60         struct blk_desc *desc;
61         struct udevice *dev;
62         int ret;
63
64         ret = blk_get_device(if_type, devnum, &dev);
65         if (ret)
66                 return NULL;
67         desc = dev_get_uclass_platdata(dev);
68
69         return desc;
70 }
71
72 /*
73  * This function is complicated with driver model. We look up the interface
74  * name in a local table. This gives us an interface type which we can match
75  * against the uclass of the block device's parent.
76  */
77 struct blk_desc *blk_get_devnum_by_typename(const char *if_typename, int devnum)
78 {
79         enum uclass_id uclass_id;
80         enum if_type if_type;
81         struct udevice *dev;
82         struct uclass *uc;
83         int ret;
84
85         if_type = if_typename_to_iftype(if_typename);
86         if (if_type == IF_TYPE_UNKNOWN) {
87                 debug("%s: Unknown interface type '%s'\n", __func__,
88                       if_typename);
89                 return NULL;
90         }
91         uclass_id = if_type_to_uclass_id(if_type);
92         if (uclass_id == UCLASS_INVALID) {
93                 debug("%s: Unknown uclass for interface type'\n",
94                       if_typename_str[if_type]);
95                 return NULL;
96         }
97
98         ret = uclass_get(UCLASS_BLK, &uc);
99         if (ret)
100                 return NULL;
101         uclass_foreach_dev(dev, uc) {
102                 struct blk_desc *desc = dev_get_uclass_platdata(dev);
103
104                 debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
105                       if_type, devnum, dev->name, desc->if_type, desc->devnum);
106                 if (desc->devnum != devnum)
107                         continue;
108
109                 /* Find out the parent device uclass */
110                 if (device_get_uclass_id(dev->parent) != uclass_id) {
111                         debug("%s: parent uclass %d, this dev %d\n", __func__,
112                               device_get_uclass_id(dev->parent), uclass_id);
113                         continue;
114                 }
115
116                 if (device_probe(dev))
117                         return NULL;
118
119                 debug("%s: Device desc %p\n", __func__, desc);
120                 return desc;
121         }
122         debug("%s: No device found\n", __func__);
123
124         return NULL;
125 }
126
127 /**
128  * get_desc() - Get the block device descriptor for the given device number
129  *
130  * @if_type:    Interface type
131  * @devnum:     Device number (0 = first)
132  * @descp:      Returns block device descriptor on success
133  * @return 0 on success, -ENODEV if there is no such device and no device
134  * with a higher device number, -ENOENT if there is no such device but there
135  * is one with a higher number, or other -ve on other error.
136  */
137 static int get_desc(enum if_type if_type, int devnum, struct blk_desc **descp)
138 {
139         bool found_more = false;
140         struct udevice *dev;
141         struct uclass *uc;
142         int ret;
143
144         *descp = NULL;
145         ret = uclass_get(UCLASS_BLK, &uc);
146         if (ret)
147                 return ret;
148         uclass_foreach_dev(dev, uc) {
149                 struct blk_desc *desc = dev_get_uclass_platdata(dev);
150
151                 debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
152                       if_type, devnum, dev->name, desc->if_type, desc->devnum);
153                 if (desc->if_type == if_type) {
154                         if (desc->devnum == devnum) {
155                                 ret = device_probe(dev);
156                                 if (ret)
157                                         return ret;
158
159                         } else if (desc->devnum > devnum) {
160                                 found_more = true;
161                         }
162                 }
163         }
164
165         return found_more ? -ENOENT : -ENODEV;
166 }
167
168 int blk_select_hwpart_devnum(enum if_type if_type, int devnum, int hwpart)
169 {
170         struct udevice *dev;
171         int ret;
172
173         ret = blk_get_device(if_type, devnum, &dev);
174         if (ret)
175                 return ret;
176
177         return blk_select_hwpart(dev, hwpart);
178 }
179
180 int blk_list_part(enum if_type if_type)
181 {
182         struct blk_desc *desc;
183         int devnum, ok;
184         int ret;
185
186         for (ok = 0, devnum = 0;; ++devnum) {
187                 ret = get_desc(if_type, devnum, &desc);
188                 if (ret == -ENODEV)
189                         break;
190                 else if (ret)
191                         continue;
192                 if (desc->part_type != PART_TYPE_UNKNOWN) {
193                         ++ok;
194                         if (devnum)
195                                 putc('\n');
196                         part_print(desc);
197                 }
198         }
199         if (!ok)
200                 return -ENODEV;
201
202         return 0;
203 }
204
205 int blk_print_part_devnum(enum if_type if_type, int devnum)
206 {
207         struct blk_desc *desc;
208         int ret;
209
210         ret = get_desc(if_type, devnum, &desc);
211         if (ret)
212                 return ret;
213         if (desc->type == DEV_TYPE_UNKNOWN)
214                 return -ENOENT;
215         part_print(desc);
216
217         return 0;
218 }
219
220 void blk_list_devices(enum if_type if_type)
221 {
222         struct blk_desc *desc;
223         int ret;
224         int i;
225
226         for (i = 0;; ++i) {
227                 ret = get_desc(if_type, i, &desc);
228                 if (ret == -ENODEV)
229                         break;
230                 else if (ret)
231                         continue;
232                 if (desc->type == DEV_TYPE_UNKNOWN)
233                         continue;  /* list only known devices */
234                 printf("Device %d: ", i);
235                 dev_print(desc);
236         }
237 }
238
239 int blk_print_device_num(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         printf("\nIDE device %d: ", devnum);
248         dev_print(desc);
249
250         return 0;
251 }
252
253 int blk_show_device(enum if_type if_type, int devnum)
254 {
255         struct blk_desc *desc;
256         int ret;
257
258         printf("\nDevice %d: ", devnum);
259         ret = get_desc(if_type, devnum, &desc);
260         if (ret == -ENODEV || ret == -ENOENT) {
261                 printf("unknown device\n");
262                 return -ENODEV;
263         }
264         if (ret)
265                 return ret;
266         dev_print(desc);
267
268         if (desc->type == DEV_TYPE_UNKNOWN)
269                 return -ENOENT;
270
271         return 0;
272 }
273
274 ulong blk_read_devnum(enum if_type if_type, int devnum, lbaint_t start,
275                       lbaint_t blkcnt, void *buffer)
276 {
277         struct blk_desc *desc;
278         ulong n;
279         int ret;
280
281         ret = get_desc(if_type, devnum, &desc);
282         if (ret)
283                 return ret;
284         n = blk_dread(desc, start, blkcnt, buffer);
285         if (IS_ERR_VALUE(n))
286                 return n;
287
288         /* flush cache after read */
289         flush_cache((ulong)buffer, blkcnt * desc->blksz);
290
291         return n;
292 }
293
294 ulong blk_write_devnum(enum if_type if_type, int devnum, lbaint_t start,
295                        lbaint_t blkcnt, const void *buffer)
296 {
297         struct blk_desc *desc;
298         int ret;
299
300         ret = get_desc(if_type, devnum, &desc);
301         if (ret)
302                 return ret;
303         return blk_dwrite(desc, start, blkcnt, buffer);
304 }
305
306 int blk_select_hwpart(struct udevice *dev, int hwpart)
307 {
308         const struct blk_ops *ops = blk_get_ops(dev);
309
310         if (!ops)
311                 return -ENOSYS;
312         if (!ops->select_hwpart)
313                 return 0;
314
315         return ops->select_hwpart(dev, hwpart);
316 }
317
318 int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
319 {
320         return blk_select_hwpart(desc->bdev, hwpart);
321 }
322
323 int blk_first_device(int if_type, struct udevice **devp)
324 {
325         struct blk_desc *desc;
326         int ret;
327
328         ret = uclass_first_device(UCLASS_BLK, devp);
329         if (ret)
330                 return ret;
331         if (!*devp)
332                 return -ENODEV;
333         do {
334                 desc = dev_get_uclass_platdata(*devp);
335                 if (desc->if_type == if_type)
336                         return 0;
337                 ret = uclass_next_device(devp);
338                 if (ret)
339                         return ret;
340         } while (*devp);
341
342         return -ENODEV;
343 }
344
345 int blk_next_device(struct udevice **devp)
346 {
347         struct blk_desc *desc;
348         int ret, if_type;
349
350         desc = dev_get_uclass_platdata(*devp);
351         if_type = desc->if_type;
352         do {
353                 ret = uclass_next_device(devp);
354                 if (ret)
355                         return ret;
356                 if (!*devp)
357                         return -ENODEV;
358                 desc = dev_get_uclass_platdata(*devp);
359                 if (desc->if_type == if_type)
360                         return 0;
361         } while (1);
362 }
363
364 int blk_get_device(int if_type, int devnum, struct udevice **devp)
365 {
366         struct uclass *uc;
367         struct udevice *dev;
368         int ret;
369
370         ret = uclass_get(UCLASS_BLK, &uc);
371         if (ret)
372                 return ret;
373         uclass_foreach_dev(dev, uc) {
374                 struct blk_desc *desc = dev_get_uclass_platdata(dev);
375
376                 debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
377                       if_type, devnum, dev->name, desc->if_type, desc->devnum);
378                 if (desc->if_type == if_type && desc->devnum == devnum) {
379                         *devp = dev;
380                         return device_probe(dev);
381                 }
382         }
383
384         return -ENODEV;
385 }
386
387 unsigned long blk_dread(struct blk_desc *block_dev, lbaint_t start,
388                         lbaint_t blkcnt, void *buffer)
389 {
390         struct udevice *dev = block_dev->bdev;
391         const struct blk_ops *ops = blk_get_ops(dev);
392         ulong blks_read;
393
394         if (!ops->read)
395                 return -ENOSYS;
396
397         if (blkcache_read(block_dev->if_type, block_dev->devnum,
398                           start, blkcnt, block_dev->blksz, buffer))
399                 return blkcnt;
400         blks_read = ops->read(dev, start, blkcnt, buffer);
401         if (blks_read == blkcnt)
402                 blkcache_fill(block_dev->if_type, block_dev->devnum,
403                               start, blkcnt, block_dev->blksz, buffer);
404
405         return blks_read;
406 }
407
408 unsigned long blk_dwrite(struct blk_desc *block_dev, lbaint_t start,
409                          lbaint_t blkcnt, const void *buffer)
410 {
411         struct udevice *dev = block_dev->bdev;
412         const struct blk_ops *ops = blk_get_ops(dev);
413
414         if (!ops->write)
415                 return -ENOSYS;
416
417         blkcache_invalidate(block_dev->if_type, block_dev->devnum);
418         return ops->write(dev, start, blkcnt, buffer);
419 }
420
421 unsigned long blk_derase(struct blk_desc *block_dev, lbaint_t start,
422                          lbaint_t blkcnt)
423 {
424         struct udevice *dev = block_dev->bdev;
425         const struct blk_ops *ops = blk_get_ops(dev);
426
427         if (!ops->erase)
428                 return -ENOSYS;
429
430         blkcache_invalidate(block_dev->if_type, block_dev->devnum);
431         return ops->erase(dev, start, blkcnt);
432 }
433
434 int blk_prepare_device(struct udevice *dev)
435 {
436         struct blk_desc *desc = dev_get_uclass_platdata(dev);
437
438         part_init(desc);
439
440         return 0;
441 }
442
443 int blk_find_max_devnum(enum if_type if_type)
444 {
445         struct udevice *dev;
446         int max_devnum = -ENODEV;
447         struct uclass *uc;
448         int ret;
449
450         ret = uclass_get(UCLASS_BLK, &uc);
451         if (ret)
452                 return ret;
453         uclass_foreach_dev(dev, uc) {
454                 struct blk_desc *desc = dev_get_uclass_platdata(dev);
455
456                 if (desc->if_type == if_type && desc->devnum > max_devnum)
457                         max_devnum = desc->devnum;
458         }
459
460         return max_devnum;
461 }
462
463 int blk_create_device(struct udevice *parent, const char *drv_name,
464                       const char *name, int if_type, int devnum, int blksz,
465                       lbaint_t size, struct udevice **devp)
466 {
467         struct blk_desc *desc;
468         struct udevice *dev;
469         int ret;
470
471         if (devnum == -1) {
472                 ret = blk_find_max_devnum(if_type);
473                 if (ret == -ENODEV)
474                         devnum = 0;
475                 else if (ret < 0)
476                         return ret;
477                 else
478                         devnum = ret + 1;
479         }
480         ret = device_bind_driver(parent, drv_name, name, &dev);
481         if (ret)
482                 return ret;
483         desc = dev_get_uclass_platdata(dev);
484         desc->if_type = if_type;
485         desc->blksz = blksz;
486         desc->lba = size / blksz;
487         desc->part_type = PART_TYPE_UNKNOWN;
488         desc->bdev = dev;
489         desc->devnum = devnum;
490         *devp = dev;
491
492         return 0;
493 }
494
495 int blk_create_devicef(struct udevice *parent, const char *drv_name,
496                        const char *name, int if_type, int devnum, int blksz,
497                        lbaint_t size, struct udevice **devp)
498 {
499         char dev_name[30], *str;
500         int ret;
501
502         snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name);
503         str = strdup(dev_name);
504         if (!str)
505                 return -ENOMEM;
506
507         ret = blk_create_device(parent, drv_name, str, if_type, devnum,
508                                 blksz, size, devp);
509         if (ret) {
510                 free(str);
511                 return ret;
512         }
513         device_set_name_alloced(*devp);
514
515         return ret;
516 }
517
518 int blk_unbind_all(int if_type)
519 {
520         struct uclass *uc;
521         struct udevice *dev, *next;
522         int ret;
523
524         ret = uclass_get(UCLASS_BLK, &uc);
525         if (ret)
526                 return ret;
527         uclass_foreach_dev_safe(dev, next, uc) {
528                 struct blk_desc *desc = dev_get_uclass_platdata(dev);
529
530                 if (desc->if_type == if_type) {
531                         ret = device_remove(dev);
532                         if (ret)
533                                 return ret;
534                         ret = device_unbind(dev);
535                         if (ret)
536                                 return ret;
537                 }
538         }
539
540         return 0;
541 }
542
543 UCLASS_DRIVER(blk) = {
544         .id             = UCLASS_BLK,
545         .name           = "blk",
546         .per_device_platdata_auto_alloc_size = sizeof(struct blk_desc),
547 };