109d71aacSSimon Glass /* 209d71aacSSimon Glass * Copyright (C) 2016 Google, Inc 309d71aacSSimon Glass * Written by Simon Glass <sjg@chromium.org> 409d71aacSSimon Glass * 509d71aacSSimon Glass * SPDX-License-Identifier: GPL-2.0+ 609d71aacSSimon Glass */ 709d71aacSSimon Glass 809d71aacSSimon Glass #include <common.h> 909d71aacSSimon Glass #include <blk.h> 1009d71aacSSimon Glass #include <dm.h> 1109d71aacSSimon Glass #include <dm/device-internal.h> 1209d71aacSSimon Glass #include <dm/lists.h> 1309d71aacSSimon Glass 14d508c82bSSimon Glass static const char *if_typename_str[IF_TYPE_COUNT] = { 15d508c82bSSimon Glass [IF_TYPE_IDE] = "ide", 16d508c82bSSimon Glass [IF_TYPE_SCSI] = "scsi", 17d508c82bSSimon Glass [IF_TYPE_ATAPI] = "atapi", 18d508c82bSSimon Glass [IF_TYPE_USB] = "usb", 19d508c82bSSimon Glass [IF_TYPE_DOC] = "doc", 20d508c82bSSimon Glass [IF_TYPE_MMC] = "mmc", 21d508c82bSSimon Glass [IF_TYPE_SD] = "sd", 22d508c82bSSimon Glass [IF_TYPE_SATA] = "sata", 23d508c82bSSimon Glass [IF_TYPE_HOST] = "host", 24d508c82bSSimon Glass [IF_TYPE_SYSTEMACE] = "ace", 25d508c82bSSimon Glass }; 26d508c82bSSimon Glass 27d508c82bSSimon Glass static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = { 28d508c82bSSimon Glass [IF_TYPE_IDE] = UCLASS_INVALID, 29d508c82bSSimon Glass [IF_TYPE_SCSI] = UCLASS_INVALID, 30d508c82bSSimon Glass [IF_TYPE_ATAPI] = UCLASS_INVALID, 31d508c82bSSimon Glass [IF_TYPE_USB] = UCLASS_MASS_STORAGE, 32d508c82bSSimon Glass [IF_TYPE_DOC] = UCLASS_INVALID, 33d508c82bSSimon Glass [IF_TYPE_MMC] = UCLASS_MMC, 34d508c82bSSimon Glass [IF_TYPE_SD] = UCLASS_INVALID, 35d508c82bSSimon Glass [IF_TYPE_SATA] = UCLASS_AHCI, 36d508c82bSSimon Glass [IF_TYPE_HOST] = UCLASS_ROOT, 37d508c82bSSimon Glass [IF_TYPE_SYSTEMACE] = UCLASS_INVALID, 38d508c82bSSimon Glass }; 39d508c82bSSimon Glass 40d508c82bSSimon Glass static enum if_type if_typename_to_iftype(const char *if_typename) 41d508c82bSSimon Glass { 42d508c82bSSimon Glass int i; 43d508c82bSSimon Glass 44d508c82bSSimon Glass for (i = 0; i < IF_TYPE_COUNT; i++) { 45d508c82bSSimon Glass if (if_typename_str[i] && 46d508c82bSSimon Glass !strcmp(if_typename, if_typename_str[i])) 47d508c82bSSimon Glass return i; 48d508c82bSSimon Glass } 49d508c82bSSimon Glass 50d508c82bSSimon Glass return IF_TYPE_UNKNOWN; 51d508c82bSSimon Glass } 52d508c82bSSimon Glass 53d508c82bSSimon Glass static enum uclass_id if_type_to_uclass_id(enum if_type if_type) 54d508c82bSSimon Glass { 55d508c82bSSimon Glass return if_type_uclass_id[if_type]; 56d508c82bSSimon Glass } 57d508c82bSSimon Glass 58d508c82bSSimon Glass struct blk_desc *blk_get_devnum_by_type(enum if_type if_type, int devnum) 59d508c82bSSimon Glass { 60d508c82bSSimon Glass struct blk_desc *desc; 61d508c82bSSimon Glass struct udevice *dev; 62d508c82bSSimon Glass int ret; 63d508c82bSSimon Glass 64d508c82bSSimon Glass ret = blk_get_device(if_type, devnum, &dev); 65d508c82bSSimon Glass if (ret) 66d508c82bSSimon Glass return NULL; 67d508c82bSSimon Glass desc = dev_get_uclass_platdata(dev); 68d508c82bSSimon Glass 69d508c82bSSimon Glass return desc; 70d508c82bSSimon Glass } 71d508c82bSSimon Glass 72d508c82bSSimon Glass /* 73d508c82bSSimon Glass * This function is complicated with driver model. We look up the interface 74d508c82bSSimon Glass * name in a local table. This gives us an interface type which we can match 75d508c82bSSimon Glass * against the uclass of the block device's parent. 76d508c82bSSimon Glass */ 77d508c82bSSimon Glass struct blk_desc *blk_get_devnum_by_typename(const char *if_typename, int devnum) 78d508c82bSSimon Glass { 79d508c82bSSimon Glass enum uclass_id uclass_id; 80d508c82bSSimon Glass enum if_type if_type; 81d508c82bSSimon Glass struct udevice *dev; 82d508c82bSSimon Glass struct uclass *uc; 83d508c82bSSimon Glass int ret; 84d508c82bSSimon Glass 85d508c82bSSimon Glass if_type = if_typename_to_iftype(if_typename); 86d508c82bSSimon Glass if (if_type == IF_TYPE_UNKNOWN) { 87d508c82bSSimon Glass debug("%s: Unknown interface type '%s'\n", __func__, 88d508c82bSSimon Glass if_typename); 89d508c82bSSimon Glass return NULL; 90d508c82bSSimon Glass } 91d508c82bSSimon Glass uclass_id = if_type_to_uclass_id(if_type); 92d508c82bSSimon Glass if (uclass_id == UCLASS_INVALID) { 93d508c82bSSimon Glass debug("%s: Unknown uclass for interface type'\n", 94d508c82bSSimon Glass if_typename_str[if_type]); 95d508c82bSSimon Glass return NULL; 96d508c82bSSimon Glass } 97d508c82bSSimon Glass 98d508c82bSSimon Glass ret = uclass_get(UCLASS_BLK, &uc); 99d508c82bSSimon Glass if (ret) 100d508c82bSSimon Glass return NULL; 101d508c82bSSimon Glass uclass_foreach_dev(dev, uc) { 102d508c82bSSimon Glass struct blk_desc *desc = dev_get_uclass_platdata(dev); 103d508c82bSSimon Glass 104d508c82bSSimon Glass debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__, 105d508c82bSSimon Glass if_type, devnum, dev->name, desc->if_type, desc->devnum); 106d508c82bSSimon Glass if (desc->devnum != devnum) 107d508c82bSSimon Glass continue; 108d508c82bSSimon Glass 109d508c82bSSimon Glass /* Find out the parent device uclass */ 110d508c82bSSimon Glass if (device_get_uclass_id(dev->parent) != uclass_id) { 111d508c82bSSimon Glass debug("%s: parent uclass %d, this dev %d\n", __func__, 112d508c82bSSimon Glass device_get_uclass_id(dev->parent), uclass_id); 113d508c82bSSimon Glass continue; 114d508c82bSSimon Glass } 115d508c82bSSimon Glass 116d508c82bSSimon Glass if (device_probe(dev)) 117d508c82bSSimon Glass return NULL; 118d508c82bSSimon Glass 119d508c82bSSimon Glass debug("%s: Device desc %p\n", __func__, desc); 120d508c82bSSimon Glass return desc; 121d508c82bSSimon Glass } 122d508c82bSSimon Glass debug("%s: No device found\n", __func__); 123d508c82bSSimon Glass 124d508c82bSSimon Glass return NULL; 125d508c82bSSimon Glass } 126d508c82bSSimon Glass 127d508c82bSSimon Glass /** 128d508c82bSSimon Glass * get_desc() - Get the block device descriptor for the given device number 129d508c82bSSimon Glass * 130d508c82bSSimon Glass * @if_type: Interface type 131d508c82bSSimon Glass * @devnum: Device number (0 = first) 132d508c82bSSimon Glass * @descp: Returns block device descriptor on success 133d508c82bSSimon Glass * @return 0 on success, -ENODEV if there is no such device and no device 134d508c82bSSimon Glass * with a higher device number, -ENOENT if there is no such device but there 135d508c82bSSimon Glass * is one with a higher number, or other -ve on other error. 136d508c82bSSimon Glass */ 137d508c82bSSimon Glass static int get_desc(enum if_type if_type, int devnum, struct blk_desc **descp) 138d508c82bSSimon Glass { 139d508c82bSSimon Glass bool found_more = false; 140d508c82bSSimon Glass struct udevice *dev; 141d508c82bSSimon Glass struct uclass *uc; 142d508c82bSSimon Glass int ret; 143d508c82bSSimon Glass 144d508c82bSSimon Glass *descp = NULL; 145d508c82bSSimon Glass ret = uclass_get(UCLASS_BLK, &uc); 146d508c82bSSimon Glass if (ret) 147d508c82bSSimon Glass return ret; 148d508c82bSSimon Glass uclass_foreach_dev(dev, uc) { 149d508c82bSSimon Glass struct blk_desc *desc = dev_get_uclass_platdata(dev); 150d508c82bSSimon Glass 151d508c82bSSimon Glass debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__, 152d508c82bSSimon Glass if_type, devnum, dev->name, desc->if_type, desc->devnum); 153d508c82bSSimon Glass if (desc->if_type == if_type) { 154d508c82bSSimon Glass if (desc->devnum == devnum) { 155d508c82bSSimon Glass ret = device_probe(dev); 156d508c82bSSimon Glass if (ret) 157d508c82bSSimon Glass return ret; 158d508c82bSSimon Glass 159d508c82bSSimon Glass } else if (desc->devnum > devnum) { 160d508c82bSSimon Glass found_more = true; 161d508c82bSSimon Glass } 162d508c82bSSimon Glass } 163d508c82bSSimon Glass } 164d508c82bSSimon Glass 165d508c82bSSimon Glass return found_more ? -ENOENT : -ENODEV; 166d508c82bSSimon Glass } 167d508c82bSSimon Glass 168*cd0fb55bSSimon Glass int blk_select_hwpart_devnum(enum if_type if_type, int devnum, int hwpart) 169*cd0fb55bSSimon Glass { 170*cd0fb55bSSimon Glass struct udevice *dev; 171*cd0fb55bSSimon Glass int ret; 172*cd0fb55bSSimon Glass 173*cd0fb55bSSimon Glass ret = blk_get_device(if_type, devnum, &dev); 174*cd0fb55bSSimon Glass if (ret) 175*cd0fb55bSSimon Glass return ret; 176*cd0fb55bSSimon Glass 177*cd0fb55bSSimon Glass return blk_select_hwpart(dev, hwpart); 178*cd0fb55bSSimon Glass } 179*cd0fb55bSSimon Glass 180d508c82bSSimon Glass int blk_list_part(enum if_type if_type) 181d508c82bSSimon Glass { 182d508c82bSSimon Glass struct blk_desc *desc; 183d508c82bSSimon Glass int devnum, ok; 184d508c82bSSimon Glass int ret; 185d508c82bSSimon Glass 186d508c82bSSimon Glass for (ok = 0, devnum = 0;; ++devnum) { 187d508c82bSSimon Glass ret = get_desc(if_type, devnum, &desc); 188d508c82bSSimon Glass if (ret == -ENODEV) 189d508c82bSSimon Glass break; 190d508c82bSSimon Glass else if (ret) 191d508c82bSSimon Glass continue; 192d508c82bSSimon Glass if (desc->part_type != PART_TYPE_UNKNOWN) { 193d508c82bSSimon Glass ++ok; 194d508c82bSSimon Glass if (devnum) 195d508c82bSSimon Glass putc('\n'); 196d508c82bSSimon Glass part_print(desc); 197d508c82bSSimon Glass } 198d508c82bSSimon Glass } 199d508c82bSSimon Glass if (!ok) 200d508c82bSSimon Glass return -ENODEV; 201d508c82bSSimon Glass 202d508c82bSSimon Glass return 0; 203d508c82bSSimon Glass } 204d508c82bSSimon Glass 205d508c82bSSimon Glass int blk_print_part_devnum(enum if_type if_type, int devnum) 206d508c82bSSimon Glass { 207d508c82bSSimon Glass struct blk_desc *desc; 208d508c82bSSimon Glass int ret; 209d508c82bSSimon Glass 210d508c82bSSimon Glass ret = get_desc(if_type, devnum, &desc); 211d508c82bSSimon Glass if (ret) 212d508c82bSSimon Glass return ret; 213d508c82bSSimon Glass if (desc->type == DEV_TYPE_UNKNOWN) 214d508c82bSSimon Glass return -ENOENT; 215d508c82bSSimon Glass part_print(desc); 216d508c82bSSimon Glass 217d508c82bSSimon Glass return 0; 218d508c82bSSimon Glass } 219d508c82bSSimon Glass 220d508c82bSSimon Glass void blk_list_devices(enum if_type if_type) 221d508c82bSSimon Glass { 222d508c82bSSimon Glass struct blk_desc *desc; 223d508c82bSSimon Glass int ret; 224d508c82bSSimon Glass int i; 225d508c82bSSimon Glass 226d508c82bSSimon Glass for (i = 0;; ++i) { 227d508c82bSSimon Glass ret = get_desc(if_type, i, &desc); 228d508c82bSSimon Glass if (ret == -ENODEV) 229d508c82bSSimon Glass break; 230d508c82bSSimon Glass else if (ret) 231d508c82bSSimon Glass continue; 232d508c82bSSimon Glass if (desc->type == DEV_TYPE_UNKNOWN) 233d508c82bSSimon Glass continue; /* list only known devices */ 234d508c82bSSimon Glass printf("Device %d: ", i); 235d508c82bSSimon Glass dev_print(desc); 236d508c82bSSimon Glass } 237d508c82bSSimon Glass } 238d508c82bSSimon Glass 239d508c82bSSimon Glass int blk_print_device_num(enum if_type if_type, int devnum) 240d508c82bSSimon Glass { 241d508c82bSSimon Glass struct blk_desc *desc; 242d508c82bSSimon Glass int ret; 243d508c82bSSimon Glass 244d508c82bSSimon Glass ret = get_desc(if_type, devnum, &desc); 245d508c82bSSimon Glass if (ret) 246d508c82bSSimon Glass return ret; 247d508c82bSSimon Glass printf("\nIDE device %d: ", devnum); 248d508c82bSSimon Glass dev_print(desc); 249d508c82bSSimon Glass 250d508c82bSSimon Glass return 0; 251d508c82bSSimon Glass } 252d508c82bSSimon Glass 253d508c82bSSimon Glass int blk_show_device(enum if_type if_type, int devnum) 254d508c82bSSimon Glass { 255d508c82bSSimon Glass struct blk_desc *desc; 256d508c82bSSimon Glass int ret; 257d508c82bSSimon Glass 258d508c82bSSimon Glass printf("\nDevice %d: ", devnum); 259d508c82bSSimon Glass ret = get_desc(if_type, devnum, &desc); 260d508c82bSSimon Glass if (ret == -ENODEV || ret == -ENOENT) { 261d508c82bSSimon Glass printf("unknown device\n"); 262d508c82bSSimon Glass return -ENODEV; 263d508c82bSSimon Glass } 264d508c82bSSimon Glass if (ret) 265d508c82bSSimon Glass return ret; 266d508c82bSSimon Glass dev_print(desc); 267d508c82bSSimon Glass 268d508c82bSSimon Glass if (desc->type == DEV_TYPE_UNKNOWN) 269d508c82bSSimon Glass return -ENOENT; 270d508c82bSSimon Glass 271d508c82bSSimon Glass return 0; 272d508c82bSSimon Glass } 273d508c82bSSimon Glass 274d508c82bSSimon Glass ulong blk_read_devnum(enum if_type if_type, int devnum, lbaint_t start, 275d508c82bSSimon Glass lbaint_t blkcnt, void *buffer) 276d508c82bSSimon Glass { 277d508c82bSSimon Glass struct blk_desc *desc; 278d508c82bSSimon Glass ulong n; 279d508c82bSSimon Glass int ret; 280d508c82bSSimon Glass 281d508c82bSSimon Glass ret = get_desc(if_type, devnum, &desc); 282d508c82bSSimon Glass if (ret) 283d508c82bSSimon Glass return ret; 284d508c82bSSimon Glass n = blk_dread(desc, start, blkcnt, buffer); 285d508c82bSSimon Glass if (IS_ERR_VALUE(n)) 286d508c82bSSimon Glass return n; 287d508c82bSSimon Glass 288d508c82bSSimon Glass /* flush cache after read */ 289d508c82bSSimon Glass flush_cache((ulong)buffer, blkcnt * desc->blksz); 290d508c82bSSimon Glass 291d508c82bSSimon Glass return n; 292d508c82bSSimon Glass } 293d508c82bSSimon Glass 294d508c82bSSimon Glass ulong blk_write_devnum(enum if_type if_type, int devnum, lbaint_t start, 295d508c82bSSimon Glass lbaint_t blkcnt, const void *buffer) 296d508c82bSSimon Glass { 297d508c82bSSimon Glass struct blk_desc *desc; 298d508c82bSSimon Glass int ret; 299d508c82bSSimon Glass 300d508c82bSSimon Glass ret = get_desc(if_type, devnum, &desc); 301d508c82bSSimon Glass if (ret) 302d508c82bSSimon Glass return ret; 303d508c82bSSimon Glass return blk_dwrite(desc, start, blkcnt, buffer); 304d508c82bSSimon Glass } 305d508c82bSSimon Glass 306*cd0fb55bSSimon Glass int blk_select_hwpart(struct udevice *dev, int hwpart) 307*cd0fb55bSSimon Glass { 308*cd0fb55bSSimon Glass const struct blk_ops *ops = blk_get_ops(dev); 309*cd0fb55bSSimon Glass 310*cd0fb55bSSimon Glass if (!ops) 311*cd0fb55bSSimon Glass return -ENOSYS; 312*cd0fb55bSSimon Glass if (!ops->select_hwpart) 313*cd0fb55bSSimon Glass return 0; 314*cd0fb55bSSimon Glass 315*cd0fb55bSSimon Glass return ops->select_hwpart(dev, hwpart); 316*cd0fb55bSSimon Glass } 317*cd0fb55bSSimon Glass 318*cd0fb55bSSimon Glass int blk_dselect_hwpart(struct blk_desc *desc, int hwpart) 319*cd0fb55bSSimon Glass { 320*cd0fb55bSSimon Glass return blk_select_hwpart(desc->bdev, hwpart); 321*cd0fb55bSSimon Glass } 322*cd0fb55bSSimon Glass 32309d71aacSSimon Glass int blk_first_device(int if_type, struct udevice **devp) 32409d71aacSSimon Glass { 32509d71aacSSimon Glass struct blk_desc *desc; 32609d71aacSSimon Glass int ret; 32709d71aacSSimon Glass 32809d71aacSSimon Glass ret = uclass_first_device(UCLASS_BLK, devp); 32909d71aacSSimon Glass if (ret) 33009d71aacSSimon Glass return ret; 33109d71aacSSimon Glass if (!*devp) 33209d71aacSSimon Glass return -ENODEV; 33309d71aacSSimon Glass do { 33409d71aacSSimon Glass desc = dev_get_uclass_platdata(*devp); 33509d71aacSSimon Glass if (desc->if_type == if_type) 33609d71aacSSimon Glass return 0; 33709d71aacSSimon Glass ret = uclass_next_device(devp); 33809d71aacSSimon Glass if (ret) 33909d71aacSSimon Glass return ret; 34009d71aacSSimon Glass } while (*devp); 34109d71aacSSimon Glass 34209d71aacSSimon Glass return -ENODEV; 34309d71aacSSimon Glass } 34409d71aacSSimon Glass 34509d71aacSSimon Glass int blk_next_device(struct udevice **devp) 34609d71aacSSimon Glass { 34709d71aacSSimon Glass struct blk_desc *desc; 34809d71aacSSimon Glass int ret, if_type; 34909d71aacSSimon Glass 35009d71aacSSimon Glass desc = dev_get_uclass_platdata(*devp); 35109d71aacSSimon Glass if_type = desc->if_type; 35209d71aacSSimon Glass do { 35309d71aacSSimon Glass ret = uclass_next_device(devp); 35409d71aacSSimon Glass if (ret) 35509d71aacSSimon Glass return ret; 35609d71aacSSimon Glass if (!*devp) 35709d71aacSSimon Glass return -ENODEV; 35809d71aacSSimon Glass desc = dev_get_uclass_platdata(*devp); 35909d71aacSSimon Glass if (desc->if_type == if_type) 36009d71aacSSimon Glass return 0; 36109d71aacSSimon Glass } while (1); 36209d71aacSSimon Glass } 36309d71aacSSimon Glass 36409d71aacSSimon Glass int blk_get_device(int if_type, int devnum, struct udevice **devp) 36509d71aacSSimon Glass { 36609d71aacSSimon Glass struct uclass *uc; 36709d71aacSSimon Glass struct udevice *dev; 36809d71aacSSimon Glass int ret; 36909d71aacSSimon Glass 37009d71aacSSimon Glass ret = uclass_get(UCLASS_BLK, &uc); 37109d71aacSSimon Glass if (ret) 37209d71aacSSimon Glass return ret; 37309d71aacSSimon Glass uclass_foreach_dev(dev, uc) { 37409d71aacSSimon Glass struct blk_desc *desc = dev_get_uclass_platdata(dev); 37509d71aacSSimon Glass 37609d71aacSSimon Glass debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__, 37709d71aacSSimon Glass if_type, devnum, dev->name, desc->if_type, desc->devnum); 37809d71aacSSimon Glass if (desc->if_type == if_type && desc->devnum == devnum) { 37909d71aacSSimon Glass *devp = dev; 38009d71aacSSimon Glass return device_probe(dev); 38109d71aacSSimon Glass } 38209d71aacSSimon Glass } 38309d71aacSSimon Glass 38409d71aacSSimon Glass return -ENODEV; 38509d71aacSSimon Glass } 38609d71aacSSimon Glass 38709d71aacSSimon Glass unsigned long blk_dread(struct blk_desc *block_dev, lbaint_t start, 38809d71aacSSimon Glass lbaint_t blkcnt, void *buffer) 38909d71aacSSimon Glass { 39009d71aacSSimon Glass struct udevice *dev = block_dev->bdev; 39109d71aacSSimon Glass const struct blk_ops *ops = blk_get_ops(dev); 392e40cf34aSEric Nelson ulong blks_read; 39309d71aacSSimon Glass 39409d71aacSSimon Glass if (!ops->read) 39509d71aacSSimon Glass return -ENOSYS; 39609d71aacSSimon Glass 397e40cf34aSEric Nelson if (blkcache_read(block_dev->if_type, block_dev->devnum, 398e40cf34aSEric Nelson start, blkcnt, block_dev->blksz, buffer)) 399e40cf34aSEric Nelson return blkcnt; 400e40cf34aSEric Nelson blks_read = ops->read(dev, start, blkcnt, buffer); 401e40cf34aSEric Nelson if (blks_read == blkcnt) 402e40cf34aSEric Nelson blkcache_fill(block_dev->if_type, block_dev->devnum, 403e40cf34aSEric Nelson start, blkcnt, block_dev->blksz, buffer); 404e40cf34aSEric Nelson 405e40cf34aSEric Nelson return blks_read; 40609d71aacSSimon Glass } 40709d71aacSSimon Glass 40809d71aacSSimon Glass unsigned long blk_dwrite(struct blk_desc *block_dev, lbaint_t start, 40909d71aacSSimon Glass lbaint_t blkcnt, const void *buffer) 41009d71aacSSimon Glass { 41109d71aacSSimon Glass struct udevice *dev = block_dev->bdev; 41209d71aacSSimon Glass const struct blk_ops *ops = blk_get_ops(dev); 41309d71aacSSimon Glass 41409d71aacSSimon Glass if (!ops->write) 41509d71aacSSimon Glass return -ENOSYS; 41609d71aacSSimon Glass 417e40cf34aSEric Nelson blkcache_invalidate(block_dev->if_type, block_dev->devnum); 41809d71aacSSimon Glass return ops->write(dev, start, blkcnt, buffer); 41909d71aacSSimon Glass } 42009d71aacSSimon Glass 42109d71aacSSimon Glass unsigned long blk_derase(struct blk_desc *block_dev, lbaint_t start, 42209d71aacSSimon Glass lbaint_t blkcnt) 42309d71aacSSimon Glass { 42409d71aacSSimon Glass struct udevice *dev = block_dev->bdev; 42509d71aacSSimon Glass const struct blk_ops *ops = blk_get_ops(dev); 42609d71aacSSimon Glass 42709d71aacSSimon Glass if (!ops->erase) 42809d71aacSSimon Glass return -ENOSYS; 42909d71aacSSimon Glass 430e40cf34aSEric Nelson blkcache_invalidate(block_dev->if_type, block_dev->devnum); 43109d71aacSSimon Glass return ops->erase(dev, start, blkcnt); 43209d71aacSSimon Glass } 43309d71aacSSimon Glass 43409d71aacSSimon Glass int blk_prepare_device(struct udevice *dev) 43509d71aacSSimon Glass { 43609d71aacSSimon Glass struct blk_desc *desc = dev_get_uclass_platdata(dev); 43709d71aacSSimon Glass 43809d71aacSSimon Glass part_init(desc); 43909d71aacSSimon Glass 44009d71aacSSimon Glass return 0; 44109d71aacSSimon Glass } 44209d71aacSSimon Glass 44352138fd4SSimon Glass int blk_find_max_devnum(enum if_type if_type) 44452138fd4SSimon Glass { 44552138fd4SSimon Glass struct udevice *dev; 44652138fd4SSimon Glass int max_devnum = -ENODEV; 44752138fd4SSimon Glass struct uclass *uc; 44852138fd4SSimon Glass int ret; 44952138fd4SSimon Glass 45052138fd4SSimon Glass ret = uclass_get(UCLASS_BLK, &uc); 45152138fd4SSimon Glass if (ret) 45252138fd4SSimon Glass return ret; 45352138fd4SSimon Glass uclass_foreach_dev(dev, uc) { 45452138fd4SSimon Glass struct blk_desc *desc = dev_get_uclass_platdata(dev); 45552138fd4SSimon Glass 45652138fd4SSimon Glass if (desc->if_type == if_type && desc->devnum > max_devnum) 45752138fd4SSimon Glass max_devnum = desc->devnum; 45852138fd4SSimon Glass } 45952138fd4SSimon Glass 46052138fd4SSimon Glass return max_devnum; 46152138fd4SSimon Glass } 46252138fd4SSimon Glass 46309d71aacSSimon Glass int blk_create_device(struct udevice *parent, const char *drv_name, 46409d71aacSSimon Glass const char *name, int if_type, int devnum, int blksz, 46509d71aacSSimon Glass lbaint_t size, struct udevice **devp) 46609d71aacSSimon Glass { 46709d71aacSSimon Glass struct blk_desc *desc; 46809d71aacSSimon Glass struct udevice *dev; 46909d71aacSSimon Glass int ret; 47009d71aacSSimon Glass 47152138fd4SSimon Glass if (devnum == -1) { 47252138fd4SSimon Glass ret = blk_find_max_devnum(if_type); 47352138fd4SSimon Glass if (ret == -ENODEV) 47452138fd4SSimon Glass devnum = 0; 47552138fd4SSimon Glass else if (ret < 0) 47652138fd4SSimon Glass return ret; 47752138fd4SSimon Glass else 47852138fd4SSimon Glass devnum = ret + 1; 47952138fd4SSimon Glass } 48072a85c0dSSimon Glass ret = device_bind_driver(parent, drv_name, name, &dev); 48172a85c0dSSimon Glass if (ret) 48272a85c0dSSimon Glass return ret; 48372a85c0dSSimon Glass desc = dev_get_uclass_platdata(dev); 48472a85c0dSSimon Glass desc->if_type = if_type; 48572a85c0dSSimon Glass desc->blksz = blksz; 48672a85c0dSSimon Glass desc->lba = size / blksz; 48772a85c0dSSimon Glass desc->part_type = PART_TYPE_UNKNOWN; 48872a85c0dSSimon Glass desc->bdev = dev; 48909d71aacSSimon Glass desc->devnum = devnum; 49009d71aacSSimon Glass *devp = dev; 49109d71aacSSimon Glass 49209d71aacSSimon Glass return 0; 49309d71aacSSimon Glass } 49409d71aacSSimon Glass 4959107c973SSimon Glass int blk_create_devicef(struct udevice *parent, const char *drv_name, 4969107c973SSimon Glass const char *name, int if_type, int devnum, int blksz, 4979107c973SSimon Glass lbaint_t size, struct udevice **devp) 4989107c973SSimon Glass { 4999107c973SSimon Glass char dev_name[30], *str; 500d0773524SSimon Glass int ret; 5019107c973SSimon Glass 5029107c973SSimon Glass snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name); 5039107c973SSimon Glass str = strdup(dev_name); 5049107c973SSimon Glass if (!str) 5059107c973SSimon Glass return -ENOMEM; 5069107c973SSimon Glass 507d0773524SSimon Glass ret = blk_create_device(parent, drv_name, str, if_type, devnum, 5089107c973SSimon Glass blksz, size, devp); 509d0773524SSimon Glass if (ret) { 510d0773524SSimon Glass free(str); 511d0773524SSimon Glass return ret; 512d0773524SSimon Glass } 513d0773524SSimon Glass device_set_name_alloced(*devp); 514d0773524SSimon Glass 515d0773524SSimon Glass return ret; 5169107c973SSimon Glass } 5179107c973SSimon Glass 51809d71aacSSimon Glass int blk_unbind_all(int if_type) 51909d71aacSSimon Glass { 52009d71aacSSimon Glass struct uclass *uc; 52109d71aacSSimon Glass struct udevice *dev, *next; 52209d71aacSSimon Glass int ret; 52309d71aacSSimon Glass 52409d71aacSSimon Glass ret = uclass_get(UCLASS_BLK, &uc); 52509d71aacSSimon Glass if (ret) 52609d71aacSSimon Glass return ret; 52709d71aacSSimon Glass uclass_foreach_dev_safe(dev, next, uc) { 52809d71aacSSimon Glass struct blk_desc *desc = dev_get_uclass_platdata(dev); 52909d71aacSSimon Glass 53009d71aacSSimon Glass if (desc->if_type == if_type) { 53109d71aacSSimon Glass ret = device_remove(dev); 53209d71aacSSimon Glass if (ret) 53309d71aacSSimon Glass return ret; 53409d71aacSSimon Glass ret = device_unbind(dev); 53509d71aacSSimon Glass if (ret) 53609d71aacSSimon Glass return ret; 53709d71aacSSimon Glass } 53809d71aacSSimon Glass } 53909d71aacSSimon Glass 54009d71aacSSimon Glass return 0; 54109d71aacSSimon Glass } 54209d71aacSSimon Glass 54309d71aacSSimon Glass UCLASS_DRIVER(blk) = { 54409d71aacSSimon Glass .id = UCLASS_BLK, 54509d71aacSSimon Glass .name = "blk", 54609d71aacSSimon Glass .per_device_platdata_auto_alloc_size = sizeof(struct blk_desc), 54709d71aacSSimon Glass }; 548