blob: 614b975e25c2b78d9c2198ebfd39f2c4ecf39e76 [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 Glass95e6e032022-08-11 19:34:57 -060020static struct {
21 enum uclass_id id;
22 const char *name;
Simon Glassfada3f92022-09-17 09:00:09 -060023} uclass_idname_str[] = {
Simon Glassdbfa32c2022-08-11 19:34:59 -060024 { UCLASS_IDE, "ide" },
25 { UCLASS_SCSI, "scsi" },
26 { UCLASS_USB, "usb" },
27 { UCLASS_MMC, "mmc" },
28 { UCLASS_AHCI, "sata" },
Simon Glasse57f8d42022-10-29 19:47:17 -060029 { UCLASS_HOST, "host" },
Simon Glassdbfa32c2022-08-11 19:34:59 -060030 { UCLASS_NVME, "nvme" },
Abdellatif El Khlifi857360c2023-04-17 10:11:52 +010031 { UCLASS_NVMXIP, "nvmxip" },
Simon Glassdbfa32c2022-08-11 19:34:59 -060032 { UCLASS_EFI_MEDIA, "efi" },
33 { UCLASS_EFI_LOADER, "efiloader" },
34 { UCLASS_VIRTIO, "virtio" },
35 { UCLASS_PVBLOCK, "pvblock" },
Tobias Waldekranz4f76dd32023-02-16 16:33:49 +010036 { UCLASS_BLKMAP, "blkmap" },
Simon Glass4131ad52016-05-01 11:36:08 -060037};
38
Simon Glassfada3f92022-09-17 09:00:09 -060039static enum uclass_id uclass_name_to_iftype(const char *uclass_idname)
Simon Glass4131ad52016-05-01 11:36:08 -060040{
41 int i;
42
Simon Glassfada3f92022-09-17 09:00:09 -060043 for (i = 0; i < ARRAY_SIZE(uclass_idname_str); i++) {
44 if (!strcmp(uclass_idname, uclass_idname_str[i].name))
45 return uclass_idname_str[i].id;
Simon Glass4131ad52016-05-01 11:36:08 -060046 }
47
Simon Glassdbfa32c2022-08-11 19:34:59 -060048 return UCLASS_INVALID;
Simon Glass4131ad52016-05-01 11:36:08 -060049}
50
Simon Glassfada3f92022-09-17 09:00:09 -060051static enum uclass_id conv_uclass_id(enum uclass_id uclass_id)
Simon Glass4131ad52016-05-01 11:36:08 -060052{
Simon Glassdbfa32c2022-08-11 19:34:59 -060053 /*
54 * This strange adjustment is used because we use UCLASS_MASS_STORAGE
55 * for USB storage devices, so need to return this as the uclass to
56 * use for USB. In fact USB_UCLASS is for USB controllers, not
57 * peripherals.
58 *
59 * The name of the UCLASS_MASS_STORAGE uclass driver is
60 * "usb_mass_storage", but we want to use "usb" in things like the
61 * 'part list' command and when showing interfaces.
62 *
63 * So for now we have this one-way conversion.
64 *
65 * The fix for this is possibly to:
66 * - rename UCLASS_MASS_STORAGE name to "usb"
67 * - rename UCLASS_USB name to "usb_ctlr"
68 * - use UCLASS_MASS_STORAGE instead of UCLASS_USB in if_typename_str
69 */
Simon Glassfada3f92022-09-17 09:00:09 -060070 if (uclass_id == UCLASS_USB)
Simon Glassdbfa32c2022-08-11 19:34:59 -060071 return UCLASS_MASS_STORAGE;
Simon Glassfada3f92022-09-17 09:00:09 -060072 return uclass_id;
Simon Glass4131ad52016-05-01 11:36:08 -060073}
74
Simon Glassfada3f92022-09-17 09:00:09 -060075const char *blk_get_uclass_name(enum uclass_id uclass_id)
Simon Glass85af5a42017-07-29 11:34:53 -060076{
Simon Glass95e6e032022-08-11 19:34:57 -060077 int i;
78
Simon Glassfada3f92022-09-17 09:00:09 -060079 for (i = 0; i < ARRAY_SIZE(uclass_idname_str); i++) {
80 if (uclass_idname_str[i].id == uclass_id)
81 return uclass_idname_str[i].name;
Simon Glass95e6e032022-08-11 19:34:57 -060082 }
83
84 return "(none)";
Simon Glass85af5a42017-07-29 11:34:53 -060085}
86
Simon Glassfada3f92022-09-17 09:00:09 -060087struct blk_desc *blk_get_devnum_by_uclass_id(enum uclass_id uclass_id, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -060088{
89 struct blk_desc *desc;
90 struct udevice *dev;
91 int ret;
92
Simon Glassfada3f92022-09-17 09:00:09 -060093 ret = blk_get_device(uclass_id, devnum, &dev);
Simon Glass4131ad52016-05-01 11:36:08 -060094 if (ret)
95 return NULL;
Simon Glass71fa5b42020-12-03 16:55:18 -070096 desc = dev_get_uclass_plat(dev);
Simon Glass4131ad52016-05-01 11:36:08 -060097
98 return desc;
99}
100
101/*
102 * This function is complicated with driver model. We look up the interface
103 * name in a local table. This gives us an interface type which we can match
104 * against the uclass of the block device's parent.
105 */
Simon Glassfada3f92022-09-17 09:00:09 -0600106struct blk_desc *blk_get_devnum_by_uclass_idname(const char *uclass_idname, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -0600107{
108 enum uclass_id uclass_id;
Simon Glass57b3d2e2022-08-11 19:35:01 -0600109 enum uclass_id type;
Simon Glass4131ad52016-05-01 11:36:08 -0600110 struct udevice *dev;
111 struct uclass *uc;
112 int ret;
113
Simon Glassfada3f92022-09-17 09:00:09 -0600114 type = uclass_name_to_iftype(uclass_idname);
Simon Glassdbfa32c2022-08-11 19:34:59 -0600115 if (type == UCLASS_INVALID) {
Simon Glass4131ad52016-05-01 11:36:08 -0600116 debug("%s: Unknown interface type '%s'\n", __func__,
Simon Glassfada3f92022-09-17 09:00:09 -0600117 uclass_idname);
Simon Glass4131ad52016-05-01 11:36:08 -0600118 return NULL;
119 }
Simon Glassfada3f92022-09-17 09:00:09 -0600120 uclass_id = conv_uclass_id(type);
Simon Glass4131ad52016-05-01 11:36:08 -0600121 if (uclass_id == UCLASS_INVALID) {
122 debug("%s: Unknown uclass for interface type'\n",
Simon Glassfada3f92022-09-17 09:00:09 -0600123 blk_get_uclass_name(type));
Simon Glass4131ad52016-05-01 11:36:08 -0600124 return NULL;
125 }
126
127 ret = uclass_get(UCLASS_BLK, &uc);
128 if (ret)
129 return NULL;
130 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700131 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glass4131ad52016-05-01 11:36:08 -0600132
Simon Glassfada3f92022-09-17 09:00:09 -0600133 debug("%s: uclass_id=%d, devnum=%d: %s, %d, %d\n", __func__,
134 type, devnum, dev->name, desc->uclass_id, desc->devnum);
Simon Glass4131ad52016-05-01 11:36:08 -0600135 if (desc->devnum != devnum)
136 continue;
137
138 /* Find out the parent device uclass */
139 if (device_get_uclass_id(dev->parent) != uclass_id) {
140 debug("%s: parent uclass %d, this dev %d\n", __func__,
141 device_get_uclass_id(dev->parent), uclass_id);
142 continue;
143 }
144
145 if (device_probe(dev))
146 return NULL;
147
148 debug("%s: Device desc %p\n", __func__, desc);
149 return desc;
150 }
151 debug("%s: No device found\n", __func__);
152
153 return NULL;
154}
155
156/**
Tien Fong Chee10378522018-07-06 16:26:36 +0800157 * blk_get_by_device() - Get the block device descriptor for the given device
158 * @dev: Instance of a storage device
159 *
160 * Return: With block device descriptor on success , NULL if there is no such
161 * block device.
162 */
163struct blk_desc *blk_get_by_device(struct udevice *dev)
164{
Simon Glasscfd72932019-09-25 08:55:56 -0600165 struct udevice *child_dev;
Tien Fong Chee10378522018-07-06 16:26:36 +0800166
Simon Glasscfd72932019-09-25 08:55:56 -0600167 device_foreach_child(child_dev, dev) {
Tien Fong Chee10378522018-07-06 16:26:36 +0800168 if (device_get_uclass_id(child_dev) != UCLASS_BLK)
169 continue;
170
Simon Glass71fa5b42020-12-03 16:55:18 -0700171 return dev_get_uclass_plat(child_dev);
Tien Fong Chee10378522018-07-06 16:26:36 +0800172 }
173
174 debug("%s: No block device found\n", __func__);
175
176 return NULL;
177}
178
179/**
Simon Glass4131ad52016-05-01 11:36:08 -0600180 * get_desc() - Get the block device descriptor for the given device number
181 *
Simon Glassfada3f92022-09-17 09:00:09 -0600182 * @uclass_id: Interface type
Simon Glass4131ad52016-05-01 11:36:08 -0600183 * @devnum: Device number (0 = first)
184 * @descp: Returns block device descriptor on success
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100185 * Return: 0 on success, -ENODEV if there is no such device and no device
Simon Glass4131ad52016-05-01 11:36:08 -0600186 * with a higher device number, -ENOENT if there is no such device but there
187 * is one with a higher number, or other -ve on other error.
188 */
Simon Glassfada3f92022-09-17 09:00:09 -0600189static int get_desc(enum uclass_id uclass_id, int devnum, struct blk_desc **descp)
Simon Glass4131ad52016-05-01 11:36:08 -0600190{
191 bool found_more = false;
192 struct udevice *dev;
193 struct uclass *uc;
194 int ret;
195
196 *descp = NULL;
197 ret = uclass_get(UCLASS_BLK, &uc);
198 if (ret)
199 return ret;
200 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700201 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glass4131ad52016-05-01 11:36:08 -0600202
Simon Glassfada3f92022-09-17 09:00:09 -0600203 debug("%s: uclass_id=%d, devnum=%d: %s, %d, %d\n", __func__,
204 uclass_id, devnum, dev->name, desc->uclass_id, desc->devnum);
205 if (desc->uclass_id == uclass_id) {
Simon Glass4131ad52016-05-01 11:36:08 -0600206 if (desc->devnum == devnum) {
207 ret = device_probe(dev);
208 if (ret)
209 return ret;
210
Michal Simekf438b6b2016-11-16 17:37:42 +0100211 *descp = desc;
212 return 0;
Simon Glass4131ad52016-05-01 11:36:08 -0600213 } else if (desc->devnum > devnum) {
214 found_more = true;
215 }
216 }
217 }
218
219 return found_more ? -ENOENT : -ENODEV;
220}
221
Simon Glassfada3f92022-09-17 09:00:09 -0600222int blk_select_hwpart_devnum(enum uclass_id uclass_id, int devnum, int hwpart)
Simon Glass13c2c292016-05-01 13:52:30 -0600223{
224 struct udevice *dev;
225 int ret;
226
Simon Glassfada3f92022-09-17 09:00:09 -0600227 ret = blk_get_device(uclass_id, devnum, &dev);
Simon Glass13c2c292016-05-01 13:52:30 -0600228 if (ret)
229 return ret;
230
developerf50d8d12019-08-27 15:32:18 +0800231 return blk_select_hwpart(dev, hwpart);
Simon Glass13c2c292016-05-01 13:52:30 -0600232}
233
Simon Glassfada3f92022-09-17 09:00:09 -0600234int blk_list_part(enum uclass_id uclass_id)
Simon Glass4131ad52016-05-01 11:36:08 -0600235{
236 struct blk_desc *desc;
237 int devnum, ok;
238 int ret;
239
240 for (ok = 0, devnum = 0;; ++devnum) {
Simon Glassfada3f92022-09-17 09:00:09 -0600241 ret = get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600242 if (ret == -ENODEV)
243 break;
244 else if (ret)
245 continue;
246 if (desc->part_type != PART_TYPE_UNKNOWN) {
247 ++ok;
248 if (devnum)
249 putc('\n');
250 part_print(desc);
251 }
252 }
253 if (!ok)
254 return -ENODEV;
255
256 return 0;
257}
258
Simon Glassfada3f92022-09-17 09:00:09 -0600259int blk_print_part_devnum(enum uclass_id uclass_id, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -0600260{
261 struct blk_desc *desc;
262 int ret;
263
Simon Glassfada3f92022-09-17 09:00:09 -0600264 ret = get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600265 if (ret)
266 return ret;
267 if (desc->type == DEV_TYPE_UNKNOWN)
268 return -ENOENT;
269 part_print(desc);
270
271 return 0;
272}
273
Simon Glassfada3f92022-09-17 09:00:09 -0600274void blk_list_devices(enum uclass_id uclass_id)
Simon Glass4131ad52016-05-01 11:36:08 -0600275{
276 struct blk_desc *desc;
277 int ret;
278 int i;
279
280 for (i = 0;; ++i) {
Simon Glassfada3f92022-09-17 09:00:09 -0600281 ret = get_desc(uclass_id, i, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600282 if (ret == -ENODEV)
283 break;
284 else if (ret)
285 continue;
286 if (desc->type == DEV_TYPE_UNKNOWN)
287 continue; /* list only known devices */
288 printf("Device %d: ", i);
289 dev_print(desc);
290 }
291}
292
Simon Glassfada3f92022-09-17 09:00:09 -0600293int blk_print_device_num(enum uclass_id uclass_id, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -0600294{
295 struct blk_desc *desc;
296 int ret;
297
Simon Glassfada3f92022-09-17 09:00:09 -0600298 ret = get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600299 if (ret)
300 return ret;
301 printf("\nIDE device %d: ", devnum);
302 dev_print(desc);
303
304 return 0;
305}
306
Simon Glassfada3f92022-09-17 09:00:09 -0600307int blk_show_device(enum uclass_id uclass_id, int devnum)
Simon Glass4131ad52016-05-01 11:36:08 -0600308{
309 struct blk_desc *desc;
310 int ret;
311
312 printf("\nDevice %d: ", devnum);
Simon Glassfada3f92022-09-17 09:00:09 -0600313 ret = get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600314 if (ret == -ENODEV || ret == -ENOENT) {
315 printf("unknown device\n");
316 return -ENODEV;
317 }
318 if (ret)
319 return ret;
320 dev_print(desc);
321
322 if (desc->type == DEV_TYPE_UNKNOWN)
323 return -ENOENT;
324
325 return 0;
326}
327
Simon Glassfada3f92022-09-17 09:00:09 -0600328ulong blk_read_devnum(enum uclass_id uclass_id, int devnum, lbaint_t start,
Simon Glass4131ad52016-05-01 11:36:08 -0600329 lbaint_t blkcnt, void *buffer)
330{
331 struct blk_desc *desc;
332 ulong n;
333 int ret;
334
Simon Glassfada3f92022-09-17 09:00:09 -0600335 ret = get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600336 if (ret)
337 return ret;
338 n = blk_dread(desc, start, blkcnt, buffer);
339 if (IS_ERR_VALUE(n))
340 return n;
341
Simon Glass4131ad52016-05-01 11:36:08 -0600342 return n;
343}
344
Simon Glassfada3f92022-09-17 09:00:09 -0600345ulong blk_write_devnum(enum uclass_id uclass_id, int devnum, lbaint_t start,
Simon Glass4131ad52016-05-01 11:36:08 -0600346 lbaint_t blkcnt, const void *buffer)
347{
348 struct blk_desc *desc;
349 int ret;
350
Simon Glassfada3f92022-09-17 09:00:09 -0600351 ret = get_desc(uclass_id, devnum, &desc);
Simon Glass4131ad52016-05-01 11:36:08 -0600352 if (ret)
353 return ret;
354 return blk_dwrite(desc, start, blkcnt, buffer);
355}
356
Simon Glass13c2c292016-05-01 13:52:30 -0600357int blk_select_hwpart(struct udevice *dev, int hwpart)
358{
359 const struct blk_ops *ops = blk_get_ops(dev);
360
361 if (!ops)
362 return -ENOSYS;
363 if (!ops->select_hwpart)
364 return 0;
365
366 return ops->select_hwpart(dev, hwpart);
367}
368
369int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
370{
developerf50d8d12019-08-27 15:32:18 +0800371 return blk_select_hwpart(desc->bdev, hwpart);
Simon Glass13c2c292016-05-01 13:52:30 -0600372}
373
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200374static int _blk_next_device(int uclass_id, struct udevice **devp)
Simon Glasscceee552016-02-29 15:25:55 -0700375{
376 struct blk_desc *desc;
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200377 int ret = 0;
378
379 for (; *devp; uclass_find_next_device(devp)) {
380 desc = dev_get_uclass_plat(*devp);
381 if (desc->uclass_id == uclass_id) {
382 ret = device_probe(*devp);
383 if (!ret)
384 return 0;
385 }
386 }
Simon Glasscceee552016-02-29 15:25:55 -0700387
Simon Glasscceee552016-02-29 15:25:55 -0700388 if (ret)
389 return ret;
Simon Glasscceee552016-02-29 15:25:55 -0700390
391 return -ENODEV;
392}
393
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200394int blk_first_device(int uclass_id, struct udevice **devp)
395{
396 uclass_find_first_device(UCLASS_BLK, devp);
397
398 return _blk_next_device(uclass_id, devp);
399}
400
Simon Glasscceee552016-02-29 15:25:55 -0700401int blk_next_device(struct udevice **devp)
402{
403 struct blk_desc *desc;
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200404 int uclass_id;
Simon Glasscceee552016-02-29 15:25:55 -0700405
Simon Glass71fa5b42020-12-03 16:55:18 -0700406 desc = dev_get_uclass_plat(*devp);
Simon Glassfada3f92022-09-17 09:00:09 -0600407 uclass_id = desc->uclass_id;
Michal Suchanekbad8ab62022-09-27 23:23:53 +0200408 uclass_find_next_device(devp);
409
410 return _blk_next_device(uclass_id, devp);
Simon Glasscceee552016-02-29 15:25:55 -0700411}
412
Simon Glassfada3f92022-09-17 09:00:09 -0600413int blk_find_device(int uclass_id, int devnum, struct udevice **devp)
Simon Glasscceee552016-02-29 15:25:55 -0700414{
415 struct uclass *uc;
416 struct udevice *dev;
417 int ret;
418
419 ret = uclass_get(UCLASS_BLK, &uc);
420 if (ret)
421 return ret;
422 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700423 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700424
Simon Glassfada3f92022-09-17 09:00:09 -0600425 debug("%s: uclass_id=%d, devnum=%d: %s, %d, %d\n", __func__,
426 uclass_id, devnum, dev->name, desc->uclass_id, desc->devnum);
427 if (desc->uclass_id == uclass_id && desc->devnum == devnum) {
Simon Glasscceee552016-02-29 15:25:55 -0700428 *devp = dev;
Simon Glassd5d4c102017-04-23 20:02:05 -0600429 return 0;
Simon Glasscceee552016-02-29 15:25:55 -0700430 }
431 }
432
433 return -ENODEV;
434}
435
Simon Glassfada3f92022-09-17 09:00:09 -0600436int blk_get_device(int uclass_id, int devnum, struct udevice **devp)
Simon Glassd5d4c102017-04-23 20:02:05 -0600437{
438 int ret;
439
Simon Glassfada3f92022-09-17 09:00:09 -0600440 ret = blk_find_device(uclass_id, devnum, devp);
Simon Glassd5d4c102017-04-23 20:02:05 -0600441 if (ret)
442 return ret;
443
444 return device_probe(*devp);
445}
446
Simon Glass18861002022-10-20 18:22:54 -0600447long blk_read(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *buf)
Simon Glasscceee552016-02-29 15:25:55 -0700448{
Simon Glass18861002022-10-20 18:22:54 -0600449 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700450 const struct blk_ops *ops = blk_get_ops(dev);
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700451 ulong blks_read;
Simon Glasscceee552016-02-29 15:25:55 -0700452
453 if (!ops->read)
454 return -ENOSYS;
455
Simon Glass18861002022-10-20 18:22:54 -0600456 if (blkcache_read(desc->uclass_id, desc->devnum,
457 start, blkcnt, desc->blksz, buf))
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700458 return blkcnt;
Simon Glass18861002022-10-20 18:22:54 -0600459 blks_read = ops->read(dev, start, blkcnt, buf);
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700460 if (blks_read == blkcnt)
Simon Glass18861002022-10-20 18:22:54 -0600461 blkcache_fill(desc->uclass_id, desc->devnum, start, blkcnt,
462 desc->blksz, buf);
Eric Nelsonfaf4f052016-03-28 10:05:44 -0700463
464 return blks_read;
Simon Glasscceee552016-02-29 15:25:55 -0700465}
466
Simon Glass18861002022-10-20 18:22:54 -0600467long blk_write(struct udevice *dev, lbaint_t start, lbaint_t blkcnt,
468 const void *buf)
Simon Glasscceee552016-02-29 15:25:55 -0700469{
Simon Glass18861002022-10-20 18:22:54 -0600470 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700471 const struct blk_ops *ops = blk_get_ops(dev);
472
473 if (!ops->write)
474 return -ENOSYS;
475
Simon Glass18861002022-10-20 18:22:54 -0600476 blkcache_invalidate(desc->uclass_id, desc->devnum);
477
478 return ops->write(dev, start, blkcnt, buf);
Simon Glasscceee552016-02-29 15:25:55 -0700479}
480
Simon Glass18861002022-10-20 18:22:54 -0600481long blk_erase(struct udevice *dev, lbaint_t start, lbaint_t blkcnt)
Simon Glasscceee552016-02-29 15:25:55 -0700482{
Simon Glass18861002022-10-20 18:22:54 -0600483 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700484 const struct blk_ops *ops = blk_get_ops(dev);
485
486 if (!ops->erase)
487 return -ENOSYS;
488
Simon Glass18861002022-10-20 18:22:54 -0600489 blkcache_invalidate(desc->uclass_id, desc->devnum);
490
Simon Glasscceee552016-02-29 15:25:55 -0700491 return ops->erase(dev, start, blkcnt);
492}
493
Simon Glass18861002022-10-20 18:22:54 -0600494ulong blk_dread(struct blk_desc *desc, lbaint_t start, lbaint_t blkcnt,
495 void *buffer)
496{
497 return blk_read(desc->bdev, start, blkcnt, buffer);
498}
499
500ulong blk_dwrite(struct blk_desc *desc, lbaint_t start, lbaint_t blkcnt,
501 const void *buffer)
502{
503 return blk_write(desc->bdev, start, blkcnt, buffer);
504}
505
506ulong blk_derase(struct blk_desc *desc, lbaint_t start, lbaint_t blkcnt)
507{
508 return blk_erase(desc->bdev, start, blkcnt);
509}
510
Simon Glassc0bcaaf2022-10-29 19:47:14 -0600511int blk_find_from_parent(struct udevice *parent, struct udevice **devp)
Simon Glass4f269132017-05-27 11:37:17 -0600512{
513 struct udevice *dev;
Simon Glass4f269132017-05-27 11:37:17 -0600514
Simon Glassc0bcaaf2022-10-29 19:47:14 -0600515 if (device_find_first_child_by_uclass(parent, UCLASS_BLK, &dev)) {
Simon Glass4f269132017-05-27 11:37:17 -0600516 debug("%s: No block device found for parent '%s'\n", __func__,
517 parent->name);
518 return -ENODEV;
519 }
Simon Glassc0bcaaf2022-10-29 19:47:14 -0600520 *devp = dev;
521
522 return 0;
523}
524
525int blk_get_from_parent(struct udevice *parent, struct udevice **devp)
526{
527 struct udevice *dev;
528 int ret;
529
530 ret = blk_find_from_parent(parent, &dev);
531 if (ret)
532 return ret;
Simon Glass4f269132017-05-27 11:37:17 -0600533 ret = device_probe(dev);
534 if (ret)
535 return ret;
536 *devp = dev;
537
538 return 0;
539}
540
Simon Glassf3086cf2022-04-24 23:31:03 -0600541const char *blk_get_devtype(struct udevice *dev)
542{
543 struct udevice *parent = dev_get_parent(dev);
544
545 return uclass_get_name(device_get_uclass_id(parent));
546};
547
Simon Glassfada3f92022-09-17 09:00:09 -0600548int blk_find_max_devnum(enum uclass_id uclass_id)
Simon Glassd089ba32016-05-01 11:36:28 -0600549{
550 struct udevice *dev;
551 int max_devnum = -ENODEV;
552 struct uclass *uc;
553 int ret;
554
555 ret = uclass_get(UCLASS_BLK, &uc);
556 if (ret)
557 return ret;
558 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700559 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glassd089ba32016-05-01 11:36:28 -0600560
Simon Glassfada3f92022-09-17 09:00:09 -0600561 if (desc->uclass_id == uclass_id && desc->devnum > max_devnum)
Simon Glassd089ba32016-05-01 11:36:28 -0600562 max_devnum = desc->devnum;
563 }
564
565 return max_devnum;
566}
567
Simon Glassfada3f92022-09-17 09:00:09 -0600568int blk_next_free_devnum(enum uclass_id uclass_id)
Simon Glassdbc38612017-04-23 20:02:06 -0600569{
570 int ret;
571
Simon Glassfada3f92022-09-17 09:00:09 -0600572 ret = blk_find_max_devnum(uclass_id);
Simon Glassdbc38612017-04-23 20:02:06 -0600573 if (ret == -ENODEV)
574 return 0;
575 if (ret < 0)
576 return ret;
577
578 return ret + 1;
579}
580
Simon Glassfc7a7442021-07-05 16:32:59 -0600581static int blk_flags_check(struct udevice *dev, enum blk_flag_t req_flags)
582{
583 const struct blk_desc *desc = dev_get_uclass_plat(dev);
584 enum blk_flag_t flags;
585
586 flags = desc->removable ? BLKF_REMOVABLE : BLKF_FIXED;
587
588 return flags & req_flags ? 0 : 1;
589}
590
Simon Glass8e61f932022-02-28 12:08:35 -0700591int blk_find_first(enum blk_flag_t flags, struct udevice **devp)
592{
593 int ret;
594
595 for (ret = uclass_find_first_device(UCLASS_BLK, devp);
596 *devp && !blk_flags_check(*devp, flags);
597 ret = uclass_find_next_device(devp))
598 return 0;
599
600 return -ENODEV;
601}
602
603int blk_find_next(enum blk_flag_t flags, struct udevice **devp)
604{
605 int ret;
606
607 for (ret = uclass_find_next_device(devp);
608 *devp && !blk_flags_check(*devp, flags);
609 ret = uclass_find_next_device(devp))
610 return 0;
611
612 return -ENODEV;
613}
614
Simon Glassfc7a7442021-07-05 16:32:59 -0600615int blk_first_device_err(enum blk_flag_t flags, struct udevice **devp)
616{
Michal Suchanekac9e9fc2022-10-12 21:58:01 +0200617 for (uclass_first_device(UCLASS_BLK, devp);
618 *devp;
619 uclass_next_device(devp)) {
Simon Glassfc7a7442021-07-05 16:32:59 -0600620 if (!blk_flags_check(*devp, flags))
621 return 0;
622 }
623
624 return -ENODEV;
625}
626
627int blk_next_device_err(enum blk_flag_t flags, struct udevice **devp)
628{
Michal Suchanekac9e9fc2022-10-12 21:58:01 +0200629 for (uclass_next_device(devp);
630 *devp;
631 uclass_next_device(devp)) {
Simon Glassfc7a7442021-07-05 16:32:59 -0600632 if (!blk_flags_check(*devp, flags))
633 return 0;
634 }
635
636 return -ENODEV;
637}
638
639int blk_count_devices(enum blk_flag_t flag)
640{
641 struct udevice *dev;
642 int count = 0;
643
644 blk_foreach_probe(flag, dev)
645 count++;
646
647 return count;
648}
649
Simon Glassfada3f92022-09-17 09:00:09 -0600650static int blk_claim_devnum(enum uclass_id uclass_id, int devnum)
Simon Glasse4fef742017-04-23 20:02:07 -0600651{
652 struct udevice *dev;
653 struct uclass *uc;
654 int ret;
655
656 ret = uclass_get(UCLASS_BLK, &uc);
657 if (ret)
658 return ret;
659 uclass_foreach_dev(dev, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700660 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasse4fef742017-04-23 20:02:07 -0600661
Simon Glassfada3f92022-09-17 09:00:09 -0600662 if (desc->uclass_id == uclass_id && desc->devnum == devnum) {
663 int next = blk_next_free_devnum(uclass_id);
Simon Glasse4fef742017-04-23 20:02:07 -0600664
665 if (next < 0)
666 return next;
667 desc->devnum = next;
668 return 0;
669 }
670 }
671
672 return -ENOENT;
673}
674
Simon Glasscceee552016-02-29 15:25:55 -0700675int blk_create_device(struct udevice *parent, const char *drv_name,
Simon Glassfada3f92022-09-17 09:00:09 -0600676 const char *name, int uclass_id, int devnum, int blksz,
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200677 lbaint_t lba, struct udevice **devp)
Simon Glasscceee552016-02-29 15:25:55 -0700678{
679 struct blk_desc *desc;
680 struct udevice *dev;
681 int ret;
682
Simon Glassd089ba32016-05-01 11:36:28 -0600683 if (devnum == -1) {
Simon Glassfada3f92022-09-17 09:00:09 -0600684 devnum = blk_next_free_devnum(uclass_id);
Simon Glasse4fef742017-04-23 20:02:07 -0600685 } else {
Simon Glassfada3f92022-09-17 09:00:09 -0600686 ret = blk_claim_devnum(uclass_id, devnum);
Simon Glasse4fef742017-04-23 20:02:07 -0600687 if (ret < 0 && ret != -ENOENT)
Simon Glassd089ba32016-05-01 11:36:28 -0600688 return ret;
Simon Glassd089ba32016-05-01 11:36:28 -0600689 }
Simon Glasse4fef742017-04-23 20:02:07 -0600690 if (devnum < 0)
691 return devnum;
Simon Glass77f7fb82016-05-01 13:52:22 -0600692 ret = device_bind_driver(parent, drv_name, name, &dev);
693 if (ret)
694 return ret;
Simon Glass71fa5b42020-12-03 16:55:18 -0700695 desc = dev_get_uclass_plat(dev);
Simon Glassfada3f92022-09-17 09:00:09 -0600696 desc->uclass_id = uclass_id;
Simon Glass77f7fb82016-05-01 13:52:22 -0600697 desc->blksz = blksz;
Heinrich Schuchardt09ba4ea2019-10-25 12:15:31 +0200698 desc->log2blksz = LOG2(desc->blksz);
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200699 desc->lba = lba;
Simon Glass77f7fb82016-05-01 13:52:22 -0600700 desc->part_type = PART_TYPE_UNKNOWN;
701 desc->bdev = dev;
Simon Glasscceee552016-02-29 15:25:55 -0700702 desc->devnum = devnum;
703 *devp = dev;
704
705 return 0;
706}
707
Simon Glass966b6952016-05-01 11:36:29 -0600708int blk_create_devicef(struct udevice *parent, const char *drv_name,
Simon Glassfada3f92022-09-17 09:00:09 -0600709 const char *name, int uclass_id, int devnum, int blksz,
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200710 lbaint_t lba, struct udevice **devp)
Simon Glass966b6952016-05-01 11:36:29 -0600711{
712 char dev_name[30], *str;
Simon Glass39e54922016-05-01 13:52:24 -0600713 int ret;
Simon Glass966b6952016-05-01 11:36:29 -0600714
715 snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name);
716 str = strdup(dev_name);
717 if (!str)
718 return -ENOMEM;
719
Simon Glassfada3f92022-09-17 09:00:09 -0600720 ret = blk_create_device(parent, drv_name, str, uclass_id, devnum,
Jean-Jacques Hiblot99b324a2017-06-09 16:45:18 +0200721 blksz, lba, devp);
Simon Glass39e54922016-05-01 13:52:24 -0600722 if (ret) {
723 free(str);
724 return ret;
725 }
726 device_set_name_alloced(*devp);
727
Simon Glass44505972017-07-29 11:34:59 -0600728 return 0;
Simon Glass966b6952016-05-01 11:36:29 -0600729}
730
AKASHI Takahiro3e32dbe2021-12-10 15:49:29 +0900731int blk_probe_or_unbind(struct udevice *dev)
732{
733 int ret;
734
735 ret = device_probe(dev);
736 if (ret) {
737 log_debug("probing %s failed\n", dev->name);
738 device_unbind(dev);
739 }
740
741 return ret;
742}
743
Simon Glassfada3f92022-09-17 09:00:09 -0600744int blk_unbind_all(int uclass_id)
Simon Glasscceee552016-02-29 15:25:55 -0700745{
746 struct uclass *uc;
747 struct udevice *dev, *next;
748 int ret;
749
750 ret = uclass_get(UCLASS_BLK, &uc);
751 if (ret)
752 return ret;
753 uclass_foreach_dev_safe(dev, next, uc) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700754 struct blk_desc *desc = dev_get_uclass_plat(dev);
Simon Glasscceee552016-02-29 15:25:55 -0700755
Simon Glassfada3f92022-09-17 09:00:09 -0600756 if (desc->uclass_id == uclass_id) {
Stefan Roese80b5bc92017-03-20 12:51:48 +0100757 ret = device_remove(dev, DM_REMOVE_NORMAL);
Simon Glasscceee552016-02-29 15:25:55 -0700758 if (ret)
759 return ret;
760 ret = device_unbind(dev);
761 if (ret)
762 return ret;
763 }
764 }
765
766 return 0;
767}
768
Bin Mengcbc3da82018-10-15 02:21:07 -0700769static int blk_post_probe(struct udevice *dev)
770{
Simon Glassf5ac3032022-08-11 19:34:45 -0600771 if (CONFIG_IS_ENABLED(PARTITIONS) && blk_enabled()) {
Simon Glass71fa5b42020-12-03 16:55:18 -0700772 struct blk_desc *desc = dev_get_uclass_plat(dev);
Bin Mengcbc3da82018-10-15 02:21:07 -0700773
Ovidiu Panait76160a02020-07-24 14:12:21 +0300774 part_init(desc);
AKASHI Takahiro358e6c72022-04-19 10:05:10 +0900775
776 if (desc->part_type != PART_TYPE_UNKNOWN &&
777 part_create_block_devices(dev))
778 debug("*** creating partitions failed\n");
Ovidiu Panait76160a02020-07-24 14:12:21 +0300779 }
Bin Mengcbc3da82018-10-15 02:21:07 -0700780
781 return 0;
782}
783
Simon Glasscceee552016-02-29 15:25:55 -0700784UCLASS_DRIVER(blk) = {
785 .id = UCLASS_BLK,
786 .name = "blk",
Bin Mengcbc3da82018-10-15 02:21:07 -0700787 .post_probe = blk_post_probe,
Simon Glass71fa5b42020-12-03 16:55:18 -0700788 .per_device_plat_auto = sizeof(struct blk_desc),
Simon Glasscceee552016-02-29 15:25:55 -0700789};