blob: 4ae8af6d609ac9c3dc8ed8c1185e9ed134591f1f [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glasscceee552016-02-29 15:25:55 -07002/*
3 * Copyright (C) 2016 Google, Inc
4 * Written by Simon Glass <sjg@chromium.org>
Simon Glasscceee552016-02-29 15:25:55 -07005 */
6
Patrick Delaunay81313352021-04-27 11:02:19 +02007#define LOG_CATEGORY UCLASS_BLK
8
Simon Glasscceee552016-02-29 15:25:55 -07009#include <common.h>
10#include <blk.h>
11#include <dm.h>
Simon Glass0f2af882020-05-10 11:40:05 -060012#include <log.h>
Simon Glass9bc15642020-02-03 07:36:16 -070013#include <malloc.h>
Simon Glass655306c2020-05-10 11:39:58 -060014#include <part.h>
Simon Glasscceee552016-02-29 15:25:55 -070015#include <dm/device-internal.h>
16#include <dm/lists.h>
Stefan Roeseef58a902017-11-29 16:46:42 +010017#include <dm/uclass-internal.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070018#include <linux/err.h>
Simon Glasscceee552016-02-29 15:25:55 -070019
Simon Glass4131ad52016-05-01 11:36:08 -060020static 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",
Zhikang Zhang182fccd2017-08-03 02:30:56 -070030 [IF_TYPE_NVME] = "nvme",
Simon Glass507ab962021-12-04 08:56:31 -070031 [IF_TYPE_EFI_MEDIA] = "efi",
Simon Glass15c4d672021-12-04 08:56:30 -070032 [IF_TYPE_EFI_LOADER] = "efiloader",
Tuomas Tynkkynend4580062018-10-15 02:21:10 -070033 [IF_TYPE_VIRTIO] = "virtio",
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +030034 [IF_TYPE_PVBLOCK] = "pvblock",
Simon Glass4131ad52016-05-01 11:36:08 -060035};
36
37static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = {
Bin Mengb650afa2017-09-10 05:12:51 -070038 [IF_TYPE_IDE] = UCLASS_IDE,
Michal Simekc886f352016-09-08 15:06:45 +020039 [IF_TYPE_SCSI] = UCLASS_SCSI,
Simon Glass4131ad52016-05-01 11:36:08 -060040 [IF_TYPE_ATAPI] = UCLASS_INVALID,
41 [IF_TYPE_USB] = UCLASS_MASS_STORAGE,
42 [IF_TYPE_DOC] = UCLASS_INVALID,
43 [IF_TYPE_MMC] = UCLASS_MMC,
44 [IF_TYPE_SD] = UCLASS_INVALID,
45 [IF_TYPE_SATA] = UCLASS_AHCI,
46 [IF_TYPE_HOST] = UCLASS_ROOT,
Heinrich Schuchardt11206f42018-01-21 19:29:30 +010047 [IF_TYPE_NVME] = UCLASS_NVME,
Simon Glass507ab962021-12-04 08:56:31 -070048 [IF_TYPE_EFI_MEDIA] = UCLASS_EFI_MEDIA,
Simon Glass15c4d672021-12-04 08:56:30 -070049 [IF_TYPE_EFI_LOADER] = UCLASS_EFI_LOADER,
Tuomas Tynkkynend4580062018-10-15 02:21:10 -070050 [IF_TYPE_VIRTIO] = UCLASS_VIRTIO,
Anastasiia Lukianenko4fec7f82020-08-06 12:42:55 +030051 [IF_TYPE_PVBLOCK] = UCLASS_PVBLOCK,
Simon Glass4131ad52016-05-01 11:36:08 -060052};
53
54static enum if_type if_typename_to_iftype(const char *if_typename)
55{
56 int i;
57
58 for (i = 0; i < IF_TYPE_COUNT; i++) {
59 if (if_typename_str[i] &&
60 !strcmp(if_typename, if_typename_str[i]))
61 return i;
62 }
63
64 return IF_TYPE_UNKNOWN;
65}
66
67static enum uclass_id if_type_to_uclass_id(enum if_type if_type)
68{
69 return if_type_uclass_id[if_type];
70}
71
Simon Glass85af5a42017-07-29 11:34:53 -060072const char *blk_get_if_type_name(enum if_type if_type)
73{
74 return if_typename_str[if_type];
75}
76
Simon Glass4131ad52016-05-01 11:36:08 -060077struct blk_desc *blk_get_devnum_by_type(enum if_type if_type, int devnum)
78{
79 struct blk_desc *desc;
80 struct udevice *dev;
81 int ret;
82
83 ret = blk_get_device(if_type, devnum, &dev);
84 if (ret)
85 return NULL;
Simon Glass71fa5b42020-12-03 16:55:18 -070086 desc = dev_get_uclass_plat(dev);
Simon Glass4131ad52016-05-01 11:36:08 -060087
88 return desc;
89}
90
91/*
92 * This function is complicated with driver model. We look up the interface
93 * name in a local table. This gives us an interface type which we can match
94 * against the uclass of the block device's parent.
95 */
96struct blk_desc *blk_get_devnum_by_typename(const char *if_typename, int devnum)
97{
98 enum uclass_id uclass_id;
99 enum if_type if_type;
100 struct udevice *dev;
101 struct uclass *uc;
102 int ret;
103
104 if_type = if_typename_to_iftype(if_typename);
105 if (if_type == IF_TYPE_UNKNOWN) {
106 debug("%s: Unknown interface type '%s'\n", __func__,
107 if_typename);
108 return NULL;
109 }
110 uclass_id = if_type_to_uclass_id(if_type);
111 if (uclass_id == UCLASS_INVALID) {
112 debug("%s: Unknown uclass for interface type'\n",
113 if_typename_str[if_type]);
114 return NULL;
115 }
116
117 ret = uclass_get(UCLASS_BLK, &uc);
118 if (ret)
119 return NULL;
120 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700121 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glass4131ad52016-05-01 11:36:08 -0600122
123 debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
124 if_type, devnum, dev->name, desc->if_type, desc->devnum);
125 if (desc->devnum != devnum)
126 continue;
127
128 /* Find out the parent device uclass */
129 if (device_get_uclass_id(dev->parent) != uclass_id) {
130 debug("%s: parent uclass %d, this dev %d\n", __func__,
131 device_get_uclass_id(dev->parent), uclass_id);
132 continue;
133 }
134
135 if (device_probe(dev))
136 return NULL;
137
138 debug("%s: Device desc %p\n", __func__, desc);
139 return desc;
140 }
141 debug("%s: No device found\n", __func__);
142
143 return NULL;
144}
145
146/**
Tien Fong Chee10378522018-07-06 16:26:36 +0800147 * blk_get_by_device() - Get the block device descriptor for the given device
148 * @dev: Instance of a storage device
149 *
150 * Return: With block device descriptor on success , NULL if there is no such
151 * block device.
152 */
153struct blk_desc *blk_get_by_device(struct udevice *dev)
154{
Simon Glasscfd72932019-09-25 08:55:56 -0600155 struct udevice *child_dev;
Tien Fong Chee10378522018-07-06 16:26:36 +0800156
Simon Glasscfd72932019-09-25 08:55:56 -0600157 device_foreach_child(child_dev, dev) {
Tien Fong Chee10378522018-07-06 16:26:36 +0800158 if (device_get_uclass_id(child_dev) != UCLASS_BLK)
159 continue;
160
Simon Glass71fa5b42020-12-03 16:55:18 -0700161 return dev_get_uclass_plat(child_dev);
Tien Fong Chee10378522018-07-06 16:26:36 +0800162 }
163
164 debug("%s: No block device found\n", __func__);
165
166 return NULL;
167}
168
169/**
Simon Glass4131ad52016-05-01 11:36:08 -0600170 * 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 */
179static 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) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700191 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glass4131ad52016-05-01 11:36:08 -0600192
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
Michal Simekf438b6b2016-11-16 17:37:42 +0100201 *descp = desc;
202 return 0;
Simon Glass4131ad52016-05-01 11:36:08 -0600203 } else if (desc->devnum > devnum) {
204 found_more = true;
205 }
206 }
207 }
208
209 return found_more ? -ENOENT : -ENODEV;
210}
211
Simon Glass13c2c292016-05-01 13:52:30 -0600212int 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
developerf50d8d12019-08-27 15:32:18 +0800221 return blk_select_hwpart(dev, hwpart);
Simon Glass13c2c292016-05-01 13:52:30 -0600222}
223
Simon Glass4131ad52016-05-01 11:36:08 -0600224int 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
249int 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
264void 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
283int 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
297int 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
318ulong 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
Simon Glass4131ad52016-05-01 11:36:08 -0600332 return n;
333}
334
335ulong 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
Simon Glass13c2c292016-05-01 13:52:30 -0600347int blk_select_hwpart(struct udevice *dev, int hwpart)
348{
349 const struct blk_ops *ops = blk_get_ops(dev);
350
351 if (!ops)
352 return -ENOSYS;
353 if (!ops->select_hwpart)
354 return 0;
355
356 return ops->select_hwpart(dev, hwpart);
357}
358
359int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
360{
developerf50d8d12019-08-27 15:32:18 +0800361 return blk_select_hwpart(desc->bdev, hwpart);
Simon Glass13c2c292016-05-01 13:52:30 -0600362}
363
Simon Glasscceee552016-02-29 15:25:55 -0700364int blk_first_device(int if_type, struct udevice **devp)
365{
366 struct blk_desc *desc;
367 int ret;
368
Stefan Roeseef58a902017-11-29 16:46:42 +0100369 ret = uclass_find_first_device(UCLASS_BLK, devp);
Simon Glasscceee552016-02-29 15:25:55 -0700370 if (ret)
371 return ret;
372 if (!*devp)
373 return -ENODEV;
374 do {
Simon Glass71fa5b42020-12-03 16:55:18 -0700375 desc = dev_get_uclass_plat(*devp);
Simon Glasscceee552016-02-29 15:25:55 -0700376 if (desc->if_type == if_type)
377 return 0;
Stefan Roeseef58a902017-11-29 16:46:42 +0100378 ret = uclass_find_next_device(devp);
Simon Glasscceee552016-02-29 15:25:55 -0700379 if (ret)
380 return ret;
381 } while (*devp);
382
383 return -ENODEV;
384}
385
386int blk_next_device(struct udevice **devp)
387{
388 struct blk_desc *desc;
389 int ret, if_type;
390
Simon Glass71fa5b42020-12-03 16:55:18 -0700391 desc = dev_get_uclass_plat(*devp);
Simon Glasscceee552016-02-29 15:25:55 -0700392 if_type = desc->if_type;
393 do {
Stefan Roeseef58a902017-11-29 16:46:42 +0100394 ret = uclass_find_next_device(devp);
Simon Glasscceee552016-02-29 15:25:55 -0700395 if (ret)
396 return ret;
397 if (!*devp)
398 return -ENODEV;
Simon Glass71fa5b42020-12-03 16:55:18 -0700399 desc = dev_get_uclass_plat(*devp);
Simon Glasscceee552016-02-29 15:25:55 -0700400 if (desc->if_type == if_type)
401 return 0;
402 } while (1);
403}
404
Simon Glassd5d4c102017-04-23 20:02:05 -0600405int blk_find_device(int if_type, int devnum, struct udevice **devp)
Simon Glasscceee552016-02-29 15:25:55 -0700406{
407 struct uclass *uc;
408 struct udevice *dev;
409 int ret;
410
411 ret = uclass_get(UCLASS_BLK, &uc);
412 if (ret)
413 return ret;
414 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700415 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700416
417 debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
418 if_type, devnum, dev->name, desc->if_type, desc->devnum);
419 if (desc->if_type == if_type && desc->devnum == devnum) {
420 *devp = dev;
Simon Glassd5d4c102017-04-23 20:02:05 -0600421 return 0;
Simon Glasscceee552016-02-29 15:25:55 -0700422 }
423 }
424
425 return -ENODEV;
426}
427
Simon Glassd5d4c102017-04-23 20:02:05 -0600428int blk_get_device(int if_type, int devnum, struct udevice **devp)
429{
430 int ret;
431
432 ret = blk_find_device(if_type, devnum, devp);
433 if (ret)
434 return ret;
435
436 return device_probe(*devp);
437}
438
Simon Glasscceee552016-02-29 15:25:55 -0700439unsigned long blk_dread(struct blk_desc *block_dev, lbaint_t start,
440 lbaint_t blkcnt, void *buffer)
441{
442 struct udevice *dev = block_dev->bdev;
443 const struct blk_ops *ops = blk_get_ops(dev);
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700444 ulong blks_read;
Simon Glasscceee552016-02-29 15:25:55 -0700445
446 if (!ops->read)
447 return -ENOSYS;
448
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700449 if (blkcache_read(block_dev->if_type, block_dev->devnum,
450 start, blkcnt, block_dev->blksz, buffer))
451 return blkcnt;
452 blks_read = ops->read(dev, start, blkcnt, buffer);
453 if (blks_read == blkcnt)
454 blkcache_fill(block_dev->if_type, block_dev->devnum,
455 start, blkcnt, block_dev->blksz, buffer);
456
457 return blks_read;
Simon Glasscceee552016-02-29 15:25:55 -0700458}
459
460unsigned long blk_dwrite(struct blk_desc *block_dev, lbaint_t start,
461 lbaint_t blkcnt, const void *buffer)
462{
463 struct udevice *dev = block_dev->bdev;
464 const struct blk_ops *ops = blk_get_ops(dev);
465
466 if (!ops->write)
467 return -ENOSYS;
468
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700469 blkcache_invalidate(block_dev->if_type, block_dev->devnum);
Simon Glasscceee552016-02-29 15:25:55 -0700470 return ops->write(dev, start, blkcnt, buffer);
471}
472
473unsigned long blk_derase(struct blk_desc *block_dev, lbaint_t start,
474 lbaint_t blkcnt)
475{
476 struct udevice *dev = block_dev->bdev;
477 const struct blk_ops *ops = blk_get_ops(dev);
478
479 if (!ops->erase)
480 return -ENOSYS;
481
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700482 blkcache_invalidate(block_dev->if_type, block_dev->devnum);
Simon Glasscceee552016-02-29 15:25:55 -0700483 return ops->erase(dev, start, blkcnt);
484}
485
Simon Glass4f269132017-05-27 11:37:17 -0600486int blk_get_from_parent(struct udevice *parent, struct udevice **devp)
487{
488 struct udevice *dev;
489 enum uclass_id id;
490 int ret;
491
492 device_find_first_child(parent, &dev);
493 if (!dev) {
494 debug("%s: No block device found for parent '%s'\n", __func__,
495 parent->name);
496 return -ENODEV;
497 }
498 id = device_get_uclass_id(dev);
499 if (id != UCLASS_BLK) {
500 debug("%s: Incorrect uclass %s for block device '%s'\n",
501 __func__, uclass_get_name(id), dev->name);
502 return -ENOTBLK;
503 }
504 ret = device_probe(dev);
505 if (ret)
506 return ret;
507 *devp = dev;
508
509 return 0;
510}
511
Simon Glassd089ba32016-05-01 11:36:28 -0600512int blk_find_max_devnum(enum if_type if_type)
513{
514 struct udevice *dev;
515 int max_devnum = -ENODEV;
516 struct uclass *uc;
517 int ret;
518
519 ret = uclass_get(UCLASS_BLK, &uc);
520 if (ret)
521 return ret;
522 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700523 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glassd089ba32016-05-01 11:36:28 -0600524
525 if (desc->if_type == if_type && desc->devnum > max_devnum)
526 max_devnum = desc->devnum;
527 }
528
529 return max_devnum;
530}
531
Bin Mengfd5eda72018-10-15 02:21:09 -0700532int blk_next_free_devnum(enum if_type if_type)
Simon Glassdbc38612017-04-23 20:02:06 -0600533{
534 int ret;
535
536 ret = blk_find_max_devnum(if_type);
537 if (ret == -ENODEV)
538 return 0;
539 if (ret < 0)
540 return ret;
541
542 return ret + 1;
543}
544
Simon Glassfc7a7442021-07-05 16:32:59 -0600545static int blk_flags_check(struct udevice *dev, enum blk_flag_t req_flags)
546{
547 const struct blk_desc *desc = dev_get_uclass_plat(dev);
548 enum blk_flag_t flags;
549
550 flags = desc->removable ? BLKF_REMOVABLE : BLKF_FIXED;
551
552 return flags & req_flags ? 0 : 1;
553}
554
555int blk_first_device_err(enum blk_flag_t flags, struct udevice **devp)
556{
557 int ret;
558
559 for (ret = uclass_first_device_err(UCLASS_BLK, devp);
560 !ret;
561 ret = uclass_next_device_err(devp)) {
562 if (!blk_flags_check(*devp, flags))
563 return 0;
564 }
565
566 return -ENODEV;
567}
568
569int blk_next_device_err(enum blk_flag_t flags, struct udevice **devp)
570{
571 int ret;
572
573 for (ret = uclass_next_device_err(devp);
574 !ret;
575 ret = uclass_next_device_err(devp)) {
576 if (!blk_flags_check(*devp, flags))
577 return 0;
578 }
579
580 return -ENODEV;
581}
582
583int blk_count_devices(enum blk_flag_t flag)
584{
585 struct udevice *dev;
586 int count = 0;
587
588 blk_foreach_probe(flag, dev)
589 count++;
590
591 return count;
592}
593
Simon Glasse4fef742017-04-23 20:02:07 -0600594static int blk_claim_devnum(enum if_type if_type, int devnum)
595{
596 struct udevice *dev;
597 struct uclass *uc;
598 int ret;
599
600 ret = uclass_get(UCLASS_BLK, &uc);
601 if (ret)
602 return ret;
603 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700604 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasse4fef742017-04-23 20:02:07 -0600605
606 if (desc->if_type == if_type && desc->devnum == devnum) {
607 int next = blk_next_free_devnum(if_type);
608
609 if (next < 0)
610 return next;
611 desc->devnum = next;
612 return 0;
613 }
614 }
615
616 return -ENOENT;
617}
618
Simon Glasscceee552016-02-29 15:25:55 -0700619int blk_create_device(struct udevice *parent, const char *drv_name,
620 const char *name, int if_type, int devnum, int blksz,
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200621 lbaint_t lba, struct udevice **devp)
Simon Glasscceee552016-02-29 15:25:55 -0700622{
623 struct blk_desc *desc;
624 struct udevice *dev;
625 int ret;
626
Simon Glassd089ba32016-05-01 11:36:28 -0600627 if (devnum == -1) {
Simon Glasse4fef742017-04-23 20:02:07 -0600628 devnum = blk_next_free_devnum(if_type);
629 } else {
630 ret = blk_claim_devnum(if_type, devnum);
631 if (ret < 0 && ret != -ENOENT)
Simon Glassd089ba32016-05-01 11:36:28 -0600632 return ret;
Simon Glassd089ba32016-05-01 11:36:28 -0600633 }
Simon Glasse4fef742017-04-23 20:02:07 -0600634 if (devnum < 0)
635 return devnum;
Simon Glass77f7fb82016-05-01 13:52:22 -0600636 ret = device_bind_driver(parent, drv_name, name, &dev);
637 if (ret)
638 return ret;
Simon Glass71fa5b42020-12-03 16:55:18 -0700639 desc = dev_get_uclass_plat(dev);
Simon Glass77f7fb82016-05-01 13:52:22 -0600640 desc->if_type = if_type;
641 desc->blksz = blksz;
Heinrich Schuchardt09ba4ea2019-10-25 12:15:31 +0200642 desc->log2blksz = LOG2(desc->blksz);
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200643 desc->lba = lba;
Simon Glass77f7fb82016-05-01 13:52:22 -0600644 desc->part_type = PART_TYPE_UNKNOWN;
645 desc->bdev = dev;
Simon Glasscceee552016-02-29 15:25:55 -0700646 desc->devnum = devnum;
647 *devp = dev;
648
649 return 0;
650}
651
Simon Glass966b6952016-05-01 11:36:29 -0600652int blk_create_devicef(struct udevice *parent, const char *drv_name,
653 const char *name, int if_type, int devnum, int blksz,
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200654 lbaint_t lba, struct udevice **devp)
Simon Glass966b6952016-05-01 11:36:29 -0600655{
656 char dev_name[30], *str;
Simon Glass39e54922016-05-01 13:52:24 -0600657 int ret;
Simon Glass966b6952016-05-01 11:36:29 -0600658
659 snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name);
660 str = strdup(dev_name);
661 if (!str)
662 return -ENOMEM;
663
Simon Glass39e54922016-05-01 13:52:24 -0600664 ret = blk_create_device(parent, drv_name, str, if_type, devnum,
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200665 blksz, lba, devp);
Simon Glass39e54922016-05-01 13:52:24 -0600666 if (ret) {
667 free(str);
668 return ret;
669 }
670 device_set_name_alloced(*devp);
671
Simon Glass44505972017-07-29 11:34:59 -0600672 return 0;
Simon Glass966b6952016-05-01 11:36:29 -0600673}
674
Simon Glasscceee552016-02-29 15:25:55 -0700675int blk_unbind_all(int if_type)
676{
677 struct uclass *uc;
678 struct udevice *dev, *next;
679 int ret;
680
681 ret = uclass_get(UCLASS_BLK, &uc);
682 if (ret)
683 return ret;
684 uclass_foreach_dev_safe(dev, next, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700685 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700686
687 if (desc->if_type == if_type) {
Stefan Roese80b5bc92017-03-20 12:51:48 +0100688 ret = device_remove(dev, DM_REMOVE_NORMAL);
Simon Glasscceee552016-02-29 15:25:55 -0700689 if (ret)
690 return ret;
691 ret = device_unbind(dev);
692 if (ret)
693 return ret;
694 }
695 }
696
697 return 0;
698}
699
Bin Mengcbc3da82018-10-15 02:21:07 -0700700static int blk_post_probe(struct udevice *dev)
701{
Ovidiu Panait76160a02020-07-24 14:12:21 +0300702 if (IS_ENABLED(CONFIG_PARTITIONS) &&
703 IS_ENABLED(CONFIG_HAVE_BLOCK_DEVICE)) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700704 struct blk_desc *desc = dev_get_uclass_plat(dev);
Bin Mengcbc3da82018-10-15 02:21:07 -0700705
Ovidiu Panait76160a02020-07-24 14:12:21 +0300706 part_init(desc);
707 }
Bin Mengcbc3da82018-10-15 02:21:07 -0700708
709 return 0;
710}
711
Simon Glasscceee552016-02-29 15:25:55 -0700712UCLASS_DRIVER(blk) = {
713 .id = UCLASS_BLK,
714 .name = "blk",
Bin Mengcbc3da82018-10-15 02:21:07 -0700715 .post_probe = blk_post_probe,
Simon Glass71fa5b42020-12-03 16:55:18 -0700716 .per_device_plat_auto = sizeof(struct blk_desc),
Simon Glasscceee552016-02-29 15:25:55 -0700717};