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> 136a2ff3f4SStefan Roese #include <dm/uclass-internal.h> 1409d71aacSSimon Glass 15d508c82bSSimon Glass static const char *if_typename_str[IF_TYPE_COUNT] = { 16d508c82bSSimon Glass [IF_TYPE_IDE] = "ide", 17d508c82bSSimon Glass [IF_TYPE_SCSI] = "scsi", 18d508c82bSSimon Glass [IF_TYPE_ATAPI] = "atapi", 19d508c82bSSimon Glass [IF_TYPE_USB] = "usb", 20d508c82bSSimon Glass [IF_TYPE_DOC] = "doc", 21d508c82bSSimon Glass [IF_TYPE_MMC] = "mmc", 22d508c82bSSimon Glass [IF_TYPE_SD] = "sd", 23d508c82bSSimon Glass [IF_TYPE_SATA] = "sata", 24d508c82bSSimon Glass [IF_TYPE_HOST] = "host", 25d508c82bSSimon Glass [IF_TYPE_SYSTEMACE] = "ace", 26ffab6945SZhikang Zhang [IF_TYPE_NVME] = "nvme", 27441217e3SZhaoyifeng [IF_TYPE_RKNAND] = "rknand", 283872c3f4SDingqiang Lin [IF_TYPE_SPINAND] = "spinand", 293872c3f4SDingqiang Lin [IF_TYPE_SPINOR] = "spinor", 30a3fec70dSJoseph Chen [IF_TYPE_RAMDISK] = "ramdisk", 31054229abSJason Zhu [IF_TYPE_MTD] = "mtd", 32d508c82bSSimon Glass }; 33d508c82bSSimon Glass 34d508c82bSSimon Glass static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = { 3568e6f221SBin Meng [IF_TYPE_IDE] = UCLASS_IDE, 36e8a016b5SMichal Simek [IF_TYPE_SCSI] = UCLASS_SCSI, 37d508c82bSSimon Glass [IF_TYPE_ATAPI] = UCLASS_INVALID, 38d508c82bSSimon Glass [IF_TYPE_USB] = UCLASS_MASS_STORAGE, 39d508c82bSSimon Glass [IF_TYPE_DOC] = UCLASS_INVALID, 40d508c82bSSimon Glass [IF_TYPE_MMC] = UCLASS_MMC, 41d508c82bSSimon Glass [IF_TYPE_SD] = UCLASS_INVALID, 42d508c82bSSimon Glass [IF_TYPE_SATA] = UCLASS_AHCI, 43d508c82bSSimon Glass [IF_TYPE_HOST] = UCLASS_ROOT, 44ffab6945SZhikang Zhang [IF_TYPE_NVME] = UCLASS_NVME, 45441217e3SZhaoyifeng [IF_TYPE_RKNAND] = UCLASS_RKNAND, 463872c3f4SDingqiang Lin [IF_TYPE_SPINAND] = UCLASS_SPI_FLASH, 473872c3f4SDingqiang Lin [IF_TYPE_SPINOR] = UCLASS_SPI_FLASH, 48a3fec70dSJoseph Chen [IF_TYPE_RAMDISK] = UCLASS_RAMDISK, 49054229abSJason Zhu [IF_TYPE_MTD] = UCLASS_MTD, 50d508c82bSSimon Glass [IF_TYPE_SYSTEMACE] = UCLASS_INVALID, 51d508c82bSSimon Glass }; 52d508c82bSSimon Glass 531712dc5cSJoseph Chen enum if_type if_typename_to_iftype(const char *if_typename) 54d508c82bSSimon Glass { 55d508c82bSSimon Glass int i; 56d508c82bSSimon Glass 57d508c82bSSimon Glass for (i = 0; i < IF_TYPE_COUNT; i++) { 58d508c82bSSimon Glass if (if_typename_str[i] && 59d508c82bSSimon Glass !strcmp(if_typename, if_typename_str[i])) 60d508c82bSSimon Glass return i; 61d508c82bSSimon Glass } 62d508c82bSSimon Glass 63d508c82bSSimon Glass return IF_TYPE_UNKNOWN; 64d508c82bSSimon Glass } 65d508c82bSSimon Glass 66d508c82bSSimon Glass static enum uclass_id if_type_to_uclass_id(enum if_type if_type) 67d508c82bSSimon Glass { 68d508c82bSSimon Glass return if_type_uclass_id[if_type]; 69d508c82bSSimon Glass } 70d508c82bSSimon Glass 716faa4ed7SSimon Glass const char *blk_get_if_type_name(enum if_type if_type) 726faa4ed7SSimon Glass { 736faa4ed7SSimon Glass return if_typename_str[if_type]; 746faa4ed7SSimon Glass } 756faa4ed7SSimon Glass 76d508c82bSSimon Glass struct blk_desc *blk_get_devnum_by_type(enum if_type if_type, int devnum) 77d508c82bSSimon Glass { 78d508c82bSSimon Glass struct blk_desc *desc; 79d508c82bSSimon Glass struct udevice *dev; 80d508c82bSSimon Glass int ret; 81d508c82bSSimon Glass 82d508c82bSSimon Glass ret = blk_get_device(if_type, devnum, &dev); 83d508c82bSSimon Glass if (ret) 84d508c82bSSimon Glass return NULL; 85d508c82bSSimon Glass desc = dev_get_uclass_platdata(dev); 86d508c82bSSimon Glass 87d508c82bSSimon Glass return desc; 88d508c82bSSimon Glass } 89d508c82bSSimon Glass 90d508c82bSSimon Glass /* 91d508c82bSSimon Glass * This function is complicated with driver model. We look up the interface 92d508c82bSSimon Glass * name in a local table. This gives us an interface type which we can match 93d508c82bSSimon Glass * against the uclass of the block device's parent. 94d508c82bSSimon Glass */ 95d508c82bSSimon Glass struct blk_desc *blk_get_devnum_by_typename(const char *if_typename, int devnum) 96d508c82bSSimon Glass { 97d508c82bSSimon Glass enum uclass_id uclass_id; 98d508c82bSSimon Glass enum if_type if_type; 99d508c82bSSimon Glass struct udevice *dev; 100d508c82bSSimon Glass struct uclass *uc; 101d508c82bSSimon Glass int ret; 102d508c82bSSimon Glass 103d508c82bSSimon Glass if_type = if_typename_to_iftype(if_typename); 104d508c82bSSimon Glass if (if_type == IF_TYPE_UNKNOWN) { 105d508c82bSSimon Glass debug("%s: Unknown interface type '%s'\n", __func__, 106d508c82bSSimon Glass if_typename); 107d508c82bSSimon Glass return NULL; 108d508c82bSSimon Glass } 109d508c82bSSimon Glass uclass_id = if_type_to_uclass_id(if_type); 110d508c82bSSimon Glass if (uclass_id == UCLASS_INVALID) { 111d508c82bSSimon Glass debug("%s: Unknown uclass for interface type'\n", 112d508c82bSSimon Glass if_typename_str[if_type]); 113d508c82bSSimon Glass return NULL; 114d508c82bSSimon Glass } 115d508c82bSSimon Glass 116d508c82bSSimon Glass ret = uclass_get(UCLASS_BLK, &uc); 117d508c82bSSimon Glass if (ret) 118d508c82bSSimon Glass return NULL; 119d508c82bSSimon Glass uclass_foreach_dev(dev, uc) { 120d508c82bSSimon Glass struct blk_desc *desc = dev_get_uclass_platdata(dev); 121d508c82bSSimon Glass 122d508c82bSSimon Glass debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__, 123d508c82bSSimon Glass if_type, devnum, dev->name, desc->if_type, desc->devnum); 124d508c82bSSimon Glass if (desc->devnum != devnum) 125d508c82bSSimon Glass continue; 126d508c82bSSimon Glass 127d508c82bSSimon Glass /* Find out the parent device uclass */ 128d508c82bSSimon Glass if (device_get_uclass_id(dev->parent) != uclass_id) { 12982ee4254SJason Zhu #ifdef CONFIG_MTD_BLK 13082ee4254SJason Zhu /* 13182ee4254SJason Zhu * The normal mtd block attachment steps are 13282ee4254SJason Zhu * UCLASS_BLK -> UCLASS_MTD -> UCLASS_(SPI or NAND). 13382ee4254SJason Zhu * Since the spi flash frame is attached to 13482ee4254SJason Zhu * UCLASS_SPI_FLASH, this make mistake to find 13582ee4254SJason Zhu * the UCLASS_MTD when find the mtd block device. 13682ee4254SJason Zhu * Fix it here when enable CONFIG_MTD_BLK. 13782ee4254SJason Zhu */ 138a2875f15SJason Zhu if (device_get_uclass_id(dev->parent) == UCLASS_SPI_FLASH && 139a2875f15SJason Zhu if_type == IF_TYPE_MTD && 140a2875f15SJason Zhu devnum == BLK_MTD_SPI_NOR) { 14182ee4254SJason Zhu debug("Fix the spi flash uclass different\n"); 14282ee4254SJason Zhu } else { 14382ee4254SJason Zhu debug("%s: parent uclass %d, this dev %d\n", 14482ee4254SJason Zhu __func__, 14582ee4254SJason Zhu device_get_uclass_id(dev->parent), 14682ee4254SJason Zhu uclass_id); 14782ee4254SJason Zhu continue; 14882ee4254SJason Zhu } 14982ee4254SJason Zhu #else 150d508c82bSSimon Glass debug("%s: parent uclass %d, this dev %d\n", __func__, 151d508c82bSSimon Glass device_get_uclass_id(dev->parent), uclass_id); 152d508c82bSSimon Glass continue; 15382ee4254SJason Zhu #endif 154d508c82bSSimon Glass } 155d508c82bSSimon Glass 156d508c82bSSimon Glass if (device_probe(dev)) 157d508c82bSSimon Glass return NULL; 158d508c82bSSimon Glass 159d508c82bSSimon Glass debug("%s: Device desc %p\n", __func__, desc); 160d508c82bSSimon Glass return desc; 161d508c82bSSimon Glass } 162d508c82bSSimon Glass debug("%s: No device found\n", __func__); 163d508c82bSSimon Glass 164d508c82bSSimon Glass return NULL; 165d508c82bSSimon Glass } 166d508c82bSSimon Glass 167d508c82bSSimon Glass /** 168d508c82bSSimon Glass * get_desc() - Get the block device descriptor for the given device number 169d508c82bSSimon Glass * 170d508c82bSSimon Glass * @if_type: Interface type 171d508c82bSSimon Glass * @devnum: Device number (0 = first) 172d508c82bSSimon Glass * @descp: Returns block device descriptor on success 173d508c82bSSimon Glass * @return 0 on success, -ENODEV if there is no such device and no device 174d508c82bSSimon Glass * with a higher device number, -ENOENT if there is no such device but there 175d508c82bSSimon Glass * is one with a higher number, or other -ve on other error. 176d508c82bSSimon Glass */ 177d508c82bSSimon Glass static int get_desc(enum if_type if_type, int devnum, struct blk_desc **descp) 178d508c82bSSimon Glass { 179d508c82bSSimon Glass bool found_more = false; 180d508c82bSSimon Glass struct udevice *dev; 181d508c82bSSimon Glass struct uclass *uc; 182d508c82bSSimon Glass int ret; 183d508c82bSSimon Glass 184d508c82bSSimon Glass *descp = NULL; 185d508c82bSSimon Glass ret = uclass_get(UCLASS_BLK, &uc); 186d508c82bSSimon Glass if (ret) 187d508c82bSSimon Glass return ret; 188d508c82bSSimon Glass uclass_foreach_dev(dev, uc) { 189d508c82bSSimon Glass struct blk_desc *desc = dev_get_uclass_platdata(dev); 190d508c82bSSimon Glass 191d508c82bSSimon Glass debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__, 192d508c82bSSimon Glass if_type, devnum, dev->name, desc->if_type, desc->devnum); 193d508c82bSSimon Glass if (desc->if_type == if_type) { 194d508c82bSSimon Glass if (desc->devnum == devnum) { 195d508c82bSSimon Glass ret = device_probe(dev); 196d508c82bSSimon Glass if (ret) 197d508c82bSSimon Glass return ret; 198d508c82bSSimon Glass 1994408f6f4SMichal Simek *descp = desc; 2004408f6f4SMichal Simek return 0; 201d508c82bSSimon Glass } else if (desc->devnum > devnum) { 202d508c82bSSimon Glass found_more = true; 203d508c82bSSimon Glass } 204d508c82bSSimon Glass } 205d508c82bSSimon Glass } 206d508c82bSSimon Glass 207d508c82bSSimon Glass return found_more ? -ENOENT : -ENODEV; 208d508c82bSSimon Glass } 209d508c82bSSimon Glass 210cd0fb55bSSimon Glass int blk_select_hwpart_devnum(enum if_type if_type, int devnum, int hwpart) 211cd0fb55bSSimon Glass { 212cd0fb55bSSimon Glass struct udevice *dev; 213cd0fb55bSSimon Glass int ret; 214cd0fb55bSSimon Glass 215cd0fb55bSSimon Glass ret = blk_get_device(if_type, devnum, &dev); 216cd0fb55bSSimon Glass if (ret) 217cd0fb55bSSimon Glass return ret; 218cd0fb55bSSimon Glass 219cd0fb55bSSimon Glass return blk_select_hwpart(dev, hwpart); 220cd0fb55bSSimon Glass } 221cd0fb55bSSimon Glass 222d508c82bSSimon Glass int blk_list_part(enum if_type if_type) 223d508c82bSSimon Glass { 224d508c82bSSimon Glass struct blk_desc *desc; 225d508c82bSSimon Glass int devnum, ok; 226d508c82bSSimon Glass int ret; 227d508c82bSSimon Glass 228d508c82bSSimon Glass for (ok = 0, devnum = 0;; ++devnum) { 229d508c82bSSimon Glass ret = get_desc(if_type, devnum, &desc); 230d508c82bSSimon Glass if (ret == -ENODEV) 231d508c82bSSimon Glass break; 232d508c82bSSimon Glass else if (ret) 233d508c82bSSimon Glass continue; 234d508c82bSSimon Glass if (desc->part_type != PART_TYPE_UNKNOWN) { 235d508c82bSSimon Glass ++ok; 236d508c82bSSimon Glass if (devnum) 237d508c82bSSimon Glass putc('\n'); 238d508c82bSSimon Glass part_print(desc); 239d508c82bSSimon Glass } 240d508c82bSSimon Glass } 241d508c82bSSimon Glass if (!ok) 242d508c82bSSimon Glass return -ENODEV; 243d508c82bSSimon Glass 244d508c82bSSimon Glass return 0; 245d508c82bSSimon Glass } 246d508c82bSSimon Glass 247d508c82bSSimon Glass int blk_print_part_devnum(enum if_type if_type, int devnum) 248d508c82bSSimon Glass { 249d508c82bSSimon Glass struct blk_desc *desc; 250d508c82bSSimon Glass int ret; 251d508c82bSSimon Glass 252d508c82bSSimon Glass ret = get_desc(if_type, devnum, &desc); 253d508c82bSSimon Glass if (ret) 254d508c82bSSimon Glass return ret; 255d508c82bSSimon Glass if (desc->type == DEV_TYPE_UNKNOWN) 256d508c82bSSimon Glass return -ENOENT; 257d508c82bSSimon Glass part_print(desc); 258d508c82bSSimon Glass 259d508c82bSSimon Glass return 0; 260d508c82bSSimon Glass } 261d508c82bSSimon Glass 262d508c82bSSimon Glass void blk_list_devices(enum if_type if_type) 263d508c82bSSimon Glass { 264d508c82bSSimon Glass struct blk_desc *desc; 265d508c82bSSimon Glass int ret; 266d508c82bSSimon Glass int i; 267d508c82bSSimon Glass 268d508c82bSSimon Glass for (i = 0;; ++i) { 269d508c82bSSimon Glass ret = get_desc(if_type, i, &desc); 270d508c82bSSimon Glass if (ret == -ENODEV) 271d508c82bSSimon Glass break; 272d508c82bSSimon Glass else if (ret) 273d508c82bSSimon Glass continue; 274d508c82bSSimon Glass if (desc->type == DEV_TYPE_UNKNOWN) 275d508c82bSSimon Glass continue; /* list only known devices */ 276d508c82bSSimon Glass printf("Device %d: ", i); 277d508c82bSSimon Glass dev_print(desc); 278d508c82bSSimon Glass } 279d508c82bSSimon Glass } 280d508c82bSSimon Glass 281d508c82bSSimon Glass int blk_print_device_num(enum if_type if_type, int devnum) 282d508c82bSSimon Glass { 283d508c82bSSimon Glass struct blk_desc *desc; 284d508c82bSSimon Glass int ret; 285d508c82bSSimon Glass 286d508c82bSSimon Glass ret = get_desc(if_type, devnum, &desc); 287d508c82bSSimon Glass if (ret) 288d508c82bSSimon Glass return ret; 289d508c82bSSimon Glass printf("\nIDE device %d: ", devnum); 290d508c82bSSimon Glass dev_print(desc); 291d508c82bSSimon Glass 292d508c82bSSimon Glass return 0; 293d508c82bSSimon Glass } 294d508c82bSSimon Glass 295d508c82bSSimon Glass int blk_show_device(enum if_type if_type, int devnum) 296d508c82bSSimon Glass { 297d508c82bSSimon Glass struct blk_desc *desc; 298d508c82bSSimon Glass int ret; 299d508c82bSSimon Glass 300d508c82bSSimon Glass printf("\nDevice %d: ", devnum); 301d508c82bSSimon Glass ret = get_desc(if_type, devnum, &desc); 302d508c82bSSimon Glass if (ret == -ENODEV || ret == -ENOENT) { 303d508c82bSSimon Glass printf("unknown device\n"); 304d508c82bSSimon Glass return -ENODEV; 305d508c82bSSimon Glass } 306d508c82bSSimon Glass if (ret) 307d508c82bSSimon Glass return ret; 308d508c82bSSimon Glass dev_print(desc); 309d508c82bSSimon Glass 310d508c82bSSimon Glass if (desc->type == DEV_TYPE_UNKNOWN) 311d508c82bSSimon Glass return -ENOENT; 312d508c82bSSimon Glass 313d508c82bSSimon Glass return 0; 314d508c82bSSimon Glass } 315d508c82bSSimon Glass 316d508c82bSSimon Glass ulong blk_read_devnum(enum if_type if_type, int devnum, lbaint_t start, 317d508c82bSSimon Glass lbaint_t blkcnt, void *buffer) 318d508c82bSSimon Glass { 319d508c82bSSimon Glass struct blk_desc *desc; 320d508c82bSSimon Glass ulong n; 321d508c82bSSimon Glass int ret; 322d508c82bSSimon Glass 323d508c82bSSimon Glass ret = get_desc(if_type, devnum, &desc); 324d508c82bSSimon Glass if (ret) 325d508c82bSSimon Glass return ret; 326d508c82bSSimon Glass n = blk_dread(desc, start, blkcnt, buffer); 327d508c82bSSimon Glass if (IS_ERR_VALUE(n)) 328d508c82bSSimon Glass return n; 329d508c82bSSimon Glass 330d508c82bSSimon Glass return n; 331d508c82bSSimon Glass } 332d508c82bSSimon Glass 333d508c82bSSimon Glass ulong blk_write_devnum(enum if_type if_type, int devnum, lbaint_t start, 334d508c82bSSimon Glass lbaint_t blkcnt, const void *buffer) 335d508c82bSSimon Glass { 336d508c82bSSimon Glass struct blk_desc *desc; 337d508c82bSSimon Glass int ret; 338d508c82bSSimon Glass 339d508c82bSSimon Glass ret = get_desc(if_type, devnum, &desc); 340d508c82bSSimon Glass if (ret) 341d508c82bSSimon Glass return ret; 342d508c82bSSimon Glass return blk_dwrite(desc, start, blkcnt, buffer); 343d508c82bSSimon Glass } 344d508c82bSSimon Glass 345*874b2c13SShawn Lin ulong blk_write_zeroes_devnum(enum if_type if_type, int devnum, lbaint_t start, 346*874b2c13SShawn Lin lbaint_t blkcnt) 347*874b2c13SShawn Lin { 348*874b2c13SShawn Lin struct blk_desc *desc; 349*874b2c13SShawn Lin int ret; 350*874b2c13SShawn Lin 351*874b2c13SShawn Lin ret = get_desc(if_type, devnum, &desc); 352*874b2c13SShawn Lin if (ret) 353*874b2c13SShawn Lin return ret; 354*874b2c13SShawn Lin return blk_dwrite_zeroes(desc, start, blkcnt); 355*874b2c13SShawn Lin } 356*874b2c13SShawn Lin 357ad9dac3aSJoseph Chen ulong blk_erase_devnum(enum if_type if_type, int devnum, lbaint_t start, 358ad9dac3aSJoseph Chen lbaint_t blkcnt) 359ad9dac3aSJoseph Chen { 360ad9dac3aSJoseph Chen struct blk_desc *desc; 361ad9dac3aSJoseph Chen int ret; 362ad9dac3aSJoseph Chen 363ad9dac3aSJoseph Chen ret = get_desc(if_type, devnum, &desc); 364ad9dac3aSJoseph Chen if (ret) 365ad9dac3aSJoseph Chen return ret; 366ad9dac3aSJoseph Chen return blk_derase(desc, start, blkcnt); 367ad9dac3aSJoseph Chen } 368ad9dac3aSJoseph Chen 369cd0fb55bSSimon Glass int blk_select_hwpart(struct udevice *dev, int hwpart) 370cd0fb55bSSimon Glass { 371cd0fb55bSSimon Glass const struct blk_ops *ops = blk_get_ops(dev); 372cd0fb55bSSimon Glass 373cd0fb55bSSimon Glass if (!ops) 374cd0fb55bSSimon Glass return -ENOSYS; 375cd0fb55bSSimon Glass if (!ops->select_hwpart) 376cd0fb55bSSimon Glass return 0; 377cd0fb55bSSimon Glass 378cd0fb55bSSimon Glass return ops->select_hwpart(dev, hwpart); 379cd0fb55bSSimon Glass } 380cd0fb55bSSimon Glass 381cd0fb55bSSimon Glass int blk_dselect_hwpart(struct blk_desc *desc, int hwpart) 382cd0fb55bSSimon Glass { 383cd0fb55bSSimon Glass return blk_select_hwpart(desc->bdev, hwpart); 384cd0fb55bSSimon Glass } 385cd0fb55bSSimon Glass 38609d71aacSSimon Glass int blk_first_device(int if_type, struct udevice **devp) 38709d71aacSSimon Glass { 38809d71aacSSimon Glass struct blk_desc *desc; 38909d71aacSSimon Glass int ret; 39009d71aacSSimon Glass 3916a2ff3f4SStefan Roese ret = uclass_find_first_device(UCLASS_BLK, devp); 39209d71aacSSimon Glass if (ret) 39309d71aacSSimon Glass return ret; 39409d71aacSSimon Glass if (!*devp) 39509d71aacSSimon Glass return -ENODEV; 39609d71aacSSimon Glass do { 39709d71aacSSimon Glass desc = dev_get_uclass_platdata(*devp); 39809d71aacSSimon Glass if (desc->if_type == if_type) 39909d71aacSSimon Glass return 0; 4006a2ff3f4SStefan Roese ret = uclass_find_next_device(devp); 40109d71aacSSimon Glass if (ret) 40209d71aacSSimon Glass return ret; 40309d71aacSSimon Glass } while (*devp); 40409d71aacSSimon Glass 40509d71aacSSimon Glass return -ENODEV; 40609d71aacSSimon Glass } 40709d71aacSSimon Glass 40809d71aacSSimon Glass int blk_next_device(struct udevice **devp) 40909d71aacSSimon Glass { 41009d71aacSSimon Glass struct blk_desc *desc; 41109d71aacSSimon Glass int ret, if_type; 41209d71aacSSimon Glass 41309d71aacSSimon Glass desc = dev_get_uclass_platdata(*devp); 41409d71aacSSimon Glass if_type = desc->if_type; 41509d71aacSSimon Glass do { 4166a2ff3f4SStefan Roese ret = uclass_find_next_device(devp); 41709d71aacSSimon Glass if (ret) 41809d71aacSSimon Glass return ret; 41909d71aacSSimon Glass if (!*devp) 42009d71aacSSimon Glass return -ENODEV; 42109d71aacSSimon Glass desc = dev_get_uclass_platdata(*devp); 42209d71aacSSimon Glass if (desc->if_type == if_type) 42309d71aacSSimon Glass return 0; 42409d71aacSSimon Glass } while (1); 42509d71aacSSimon Glass } 42609d71aacSSimon Glass 4276139281aSSimon Glass int blk_find_device(int if_type, int devnum, struct udevice **devp) 42809d71aacSSimon Glass { 42909d71aacSSimon Glass struct uclass *uc; 43009d71aacSSimon Glass struct udevice *dev; 43109d71aacSSimon Glass int ret; 43209d71aacSSimon Glass 43309d71aacSSimon Glass ret = uclass_get(UCLASS_BLK, &uc); 43409d71aacSSimon Glass if (ret) 43509d71aacSSimon Glass return ret; 43609d71aacSSimon Glass uclass_foreach_dev(dev, uc) { 43709d71aacSSimon Glass struct blk_desc *desc = dev_get_uclass_platdata(dev); 43809d71aacSSimon Glass 43909d71aacSSimon Glass debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__, 44009d71aacSSimon Glass if_type, devnum, dev->name, desc->if_type, desc->devnum); 44109d71aacSSimon Glass if (desc->if_type == if_type && desc->devnum == devnum) { 44209d71aacSSimon Glass *devp = dev; 4436139281aSSimon Glass return 0; 44409d71aacSSimon Glass } 44509d71aacSSimon Glass } 44609d71aacSSimon Glass 44709d71aacSSimon Glass return -ENODEV; 44809d71aacSSimon Glass } 44909d71aacSSimon Glass 4506139281aSSimon Glass int blk_get_device(int if_type, int devnum, struct udevice **devp) 4516139281aSSimon Glass { 4526139281aSSimon Glass int ret; 4536139281aSSimon Glass 4546139281aSSimon Glass ret = blk_find_device(if_type, devnum, devp); 4556139281aSSimon Glass if (ret) 4566139281aSSimon Glass return ret; 4576139281aSSimon Glass 4586139281aSSimon Glass return device_probe(*devp); 4596139281aSSimon Glass } 4606139281aSSimon Glass 46109d71aacSSimon Glass unsigned long blk_dread(struct blk_desc *block_dev, lbaint_t start, 46209d71aacSSimon Glass lbaint_t blkcnt, void *buffer) 46309d71aacSSimon Glass { 46409d71aacSSimon Glass struct udevice *dev = block_dev->bdev; 46509d71aacSSimon Glass const struct blk_ops *ops = blk_get_ops(dev); 466e40cf34aSEric Nelson ulong blks_read; 46709d71aacSSimon Glass 46809d71aacSSimon Glass if (!ops->read) 46909d71aacSSimon Glass return -ENOSYS; 47009d71aacSSimon Glass 471e40cf34aSEric Nelson if (blkcache_read(block_dev->if_type, block_dev->devnum, 472e40cf34aSEric Nelson start, blkcnt, block_dev->blksz, buffer)) 473e40cf34aSEric Nelson return blkcnt; 474e40cf34aSEric Nelson blks_read = ops->read(dev, start, blkcnt, buffer); 475e40cf34aSEric Nelson if (blks_read == blkcnt) 476e40cf34aSEric Nelson blkcache_fill(block_dev->if_type, block_dev->devnum, 477e40cf34aSEric Nelson start, blkcnt, block_dev->blksz, buffer); 478e40cf34aSEric Nelson 479e40cf34aSEric Nelson return blks_read; 48009d71aacSSimon Glass } 48109d71aacSSimon Glass 48209d71aacSSimon Glass unsigned long blk_dwrite(struct blk_desc *block_dev, lbaint_t start, 48309d71aacSSimon Glass lbaint_t blkcnt, const void *buffer) 48409d71aacSSimon Glass { 48509d71aacSSimon Glass struct udevice *dev = block_dev->bdev; 48609d71aacSSimon Glass const struct blk_ops *ops = blk_get_ops(dev); 48709d71aacSSimon Glass 48809d71aacSSimon Glass if (!ops->write) 48909d71aacSSimon Glass return -ENOSYS; 49009d71aacSSimon Glass 491e40cf34aSEric Nelson blkcache_invalidate(block_dev->if_type, block_dev->devnum); 49209d71aacSSimon Glass return ops->write(dev, start, blkcnt, buffer); 49309d71aacSSimon Glass } 49409d71aacSSimon Glass 495*874b2c13SShawn Lin unsigned long blk_dwrite_zeroes(struct blk_desc *block_dev, lbaint_t start, 496*874b2c13SShawn Lin lbaint_t blkcnt) 497*874b2c13SShawn Lin { 498*874b2c13SShawn Lin struct udevice *dev = block_dev->bdev; 499*874b2c13SShawn Lin const struct blk_ops *ops = blk_get_ops(dev); 500*874b2c13SShawn Lin 501*874b2c13SShawn Lin if (!ops->write_zeroes) 502*874b2c13SShawn Lin return -ENOSYS; 503*874b2c13SShawn Lin 504*874b2c13SShawn Lin blkcache_invalidate(block_dev->if_type, block_dev->devnum); 505*874b2c13SShawn Lin return ops->write_zeroes(dev, start, blkcnt); 506*874b2c13SShawn Lin } 507*874b2c13SShawn Lin 50809d71aacSSimon Glass unsigned long blk_derase(struct blk_desc *block_dev, lbaint_t start, 50909d71aacSSimon Glass lbaint_t blkcnt) 51009d71aacSSimon Glass { 51109d71aacSSimon Glass struct udevice *dev = block_dev->bdev; 51209d71aacSSimon Glass const struct blk_ops *ops = blk_get_ops(dev); 51309d71aacSSimon Glass 51409d71aacSSimon Glass if (!ops->erase) 51509d71aacSSimon Glass return -ENOSYS; 51609d71aacSSimon Glass 517e40cf34aSEric Nelson blkcache_invalidate(block_dev->if_type, block_dev->devnum); 51809d71aacSSimon Glass return ops->erase(dev, start, blkcnt); 51909d71aacSSimon Glass } 52009d71aacSSimon Glass 52109d71aacSSimon Glass int blk_prepare_device(struct udevice *dev) 52209d71aacSSimon Glass { 52309d71aacSSimon Glass struct blk_desc *desc = dev_get_uclass_platdata(dev); 52409d71aacSSimon Glass 52509d71aacSSimon Glass part_init(desc); 52609d71aacSSimon Glass 52709d71aacSSimon Glass return 0; 52809d71aacSSimon Glass } 52909d71aacSSimon Glass 5309f103b9cSSimon Glass int blk_get_from_parent(struct udevice *parent, struct udevice **devp) 5319f103b9cSSimon Glass { 5329f103b9cSSimon Glass struct udevice *dev; 5339f103b9cSSimon Glass enum uclass_id id; 5349f103b9cSSimon Glass int ret; 5359f103b9cSSimon Glass 5369f103b9cSSimon Glass device_find_first_child(parent, &dev); 5379f103b9cSSimon Glass if (!dev) { 5389f103b9cSSimon Glass debug("%s: No block device found for parent '%s'\n", __func__, 5399f103b9cSSimon Glass parent->name); 5409f103b9cSSimon Glass return -ENODEV; 5419f103b9cSSimon Glass } 5429f103b9cSSimon Glass id = device_get_uclass_id(dev); 5439f103b9cSSimon Glass if (id != UCLASS_BLK) { 5449f103b9cSSimon Glass debug("%s: Incorrect uclass %s for block device '%s'\n", 5459f103b9cSSimon Glass __func__, uclass_get_name(id), dev->name); 5469f103b9cSSimon Glass return -ENOTBLK; 5479f103b9cSSimon Glass } 5489f103b9cSSimon Glass ret = device_probe(dev); 5499f103b9cSSimon Glass if (ret) 5509f103b9cSSimon Glass return ret; 5519f103b9cSSimon Glass *devp = dev; 5529f103b9cSSimon Glass 5539f103b9cSSimon Glass return 0; 5549f103b9cSSimon Glass } 5559f103b9cSSimon Glass 55652138fd4SSimon Glass int blk_find_max_devnum(enum if_type if_type) 55752138fd4SSimon Glass { 55852138fd4SSimon Glass struct udevice *dev; 55952138fd4SSimon Glass int max_devnum = -ENODEV; 56052138fd4SSimon Glass struct uclass *uc; 56152138fd4SSimon Glass int ret; 56252138fd4SSimon Glass 56352138fd4SSimon Glass ret = uclass_get(UCLASS_BLK, &uc); 56452138fd4SSimon Glass if (ret) 56552138fd4SSimon Glass return ret; 56652138fd4SSimon Glass uclass_foreach_dev(dev, uc) { 56752138fd4SSimon Glass struct blk_desc *desc = dev_get_uclass_platdata(dev); 56852138fd4SSimon Glass 56952138fd4SSimon Glass if (desc->if_type == if_type && desc->devnum > max_devnum) 57052138fd4SSimon Glass max_devnum = desc->devnum; 57152138fd4SSimon Glass } 57252138fd4SSimon Glass 57352138fd4SSimon Glass return max_devnum; 57452138fd4SSimon Glass } 57552138fd4SSimon Glass 576e8abbb53SSimon Glass static int blk_next_free_devnum(enum if_type if_type) 577e8abbb53SSimon Glass { 578e8abbb53SSimon Glass int ret; 579e8abbb53SSimon Glass 580e8abbb53SSimon Glass ret = blk_find_max_devnum(if_type); 581e8abbb53SSimon Glass if (ret == -ENODEV) 582e8abbb53SSimon Glass return 0; 583e8abbb53SSimon Glass if (ret < 0) 584e8abbb53SSimon Glass return ret; 585e8abbb53SSimon Glass 586e8abbb53SSimon Glass return ret + 1; 587e8abbb53SSimon Glass } 588e8abbb53SSimon Glass 589e48eeb9eSSimon Glass static int blk_claim_devnum(enum if_type if_type, int devnum) 590e48eeb9eSSimon Glass { 591e48eeb9eSSimon Glass struct udevice *dev; 592e48eeb9eSSimon Glass struct uclass *uc; 593e48eeb9eSSimon Glass int ret; 594e48eeb9eSSimon Glass 595e48eeb9eSSimon Glass ret = uclass_get(UCLASS_BLK, &uc); 596e48eeb9eSSimon Glass if (ret) 597e48eeb9eSSimon Glass return ret; 598e48eeb9eSSimon Glass uclass_foreach_dev(dev, uc) { 599e48eeb9eSSimon Glass struct blk_desc *desc = dev_get_uclass_platdata(dev); 600e48eeb9eSSimon Glass 601e48eeb9eSSimon Glass if (desc->if_type == if_type && desc->devnum == devnum) { 602e48eeb9eSSimon Glass int next = blk_next_free_devnum(if_type); 603e48eeb9eSSimon Glass 604e48eeb9eSSimon Glass if (next < 0) 605e48eeb9eSSimon Glass return next; 606d9da4b44SJoseph Chen #ifdef CONFIG_USING_KERNEL_DTB_V2 607d9da4b44SJoseph Chen /* 608d9da4b44SJoseph Chen * Not allow devnum to be forced distributed. 609d9da4b44SJoseph Chen * See commit (e48eeb9ea3 dm: blk: Improve block device claiming). 610d9da4b44SJoseph Chen * 611d9da4b44SJoseph Chen * fix like: "Device 'dwmmc@fe2b0000': seq 0 is in use by 'sdhci@fe310000'" 612d9da4b44SJoseph Chen */ 613d9da4b44SJoseph Chen if (!(gd->flags & GD_FLG_KDTB_READY)) 614d9da4b44SJoseph Chen #endif 615e48eeb9eSSimon Glass desc->devnum = next; 616d9da4b44SJoseph Chen 617e48eeb9eSSimon Glass return 0; 618e48eeb9eSSimon Glass } 619e48eeb9eSSimon Glass } 620e48eeb9eSSimon Glass 621e48eeb9eSSimon Glass return -ENOENT; 622e48eeb9eSSimon Glass } 623e48eeb9eSSimon Glass 62409d71aacSSimon Glass int blk_create_device(struct udevice *parent, const char *drv_name, 62509d71aacSSimon Glass const char *name, int if_type, int devnum, int blksz, 62609d71aacSSimon Glass lbaint_t size, struct udevice **devp) 62709d71aacSSimon Glass { 62809d71aacSSimon Glass struct blk_desc *desc; 62909d71aacSSimon Glass struct udevice *dev; 63009d71aacSSimon Glass int ret; 63109d71aacSSimon Glass 63252138fd4SSimon Glass if (devnum == -1) { 633e48eeb9eSSimon Glass devnum = blk_next_free_devnum(if_type); 634e48eeb9eSSimon Glass } else { 635e48eeb9eSSimon Glass ret = blk_claim_devnum(if_type, devnum); 636e48eeb9eSSimon Glass if (ret < 0 && ret != -ENOENT) 63752138fd4SSimon Glass return ret; 63852138fd4SSimon Glass } 639e48eeb9eSSimon Glass if (devnum < 0) 640e48eeb9eSSimon Glass return devnum; 64172a85c0dSSimon Glass ret = device_bind_driver(parent, drv_name, name, &dev); 64272a85c0dSSimon Glass if (ret) 64372a85c0dSSimon Glass return ret; 64472a85c0dSSimon Glass desc = dev_get_uclass_platdata(dev); 64572a85c0dSSimon Glass desc->if_type = if_type; 64672a85c0dSSimon Glass desc->blksz = blksz; 64752f5f55eSYifeng Zhao desc->rawblksz = blksz; 64872a85c0dSSimon Glass desc->lba = size / blksz; 64952f5f55eSYifeng Zhao desc->rawlba = size / blksz; 65072a85c0dSSimon Glass desc->part_type = PART_TYPE_UNKNOWN; 65172a85c0dSSimon Glass desc->bdev = dev; 65209d71aacSSimon Glass desc->devnum = devnum; 65309d71aacSSimon Glass *devp = dev; 65409d71aacSSimon Glass 65509d71aacSSimon Glass return 0; 65609d71aacSSimon Glass } 65709d71aacSSimon Glass 6589107c973SSimon Glass int blk_create_devicef(struct udevice *parent, const char *drv_name, 6599107c973SSimon Glass const char *name, int if_type, int devnum, int blksz, 6609107c973SSimon Glass lbaint_t size, struct udevice **devp) 6619107c973SSimon Glass { 6629107c973SSimon Glass char dev_name[30], *str; 663d0773524SSimon Glass int ret; 6649107c973SSimon Glass 6659107c973SSimon Glass snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name); 6669107c973SSimon Glass str = strdup(dev_name); 6679107c973SSimon Glass if (!str) 6689107c973SSimon Glass return -ENOMEM; 6699107c973SSimon Glass 670d0773524SSimon Glass ret = blk_create_device(parent, drv_name, str, if_type, devnum, 6719107c973SSimon Glass blksz, size, devp); 672d0773524SSimon Glass if (ret) { 673d0773524SSimon Glass free(str); 674d0773524SSimon Glass return ret; 675d0773524SSimon Glass } 676d0773524SSimon Glass device_set_name_alloced(*devp); 677d0773524SSimon Glass 6787074b2a3SSimon Glass return 0; 6799107c973SSimon Glass } 6809107c973SSimon Glass 68109d71aacSSimon Glass int blk_unbind_all(int if_type) 68209d71aacSSimon Glass { 68309d71aacSSimon Glass struct uclass *uc; 68409d71aacSSimon Glass struct udevice *dev, *next; 68509d71aacSSimon Glass int ret; 68609d71aacSSimon Glass 68709d71aacSSimon Glass ret = uclass_get(UCLASS_BLK, &uc); 68809d71aacSSimon Glass if (ret) 68909d71aacSSimon Glass return ret; 69009d71aacSSimon Glass uclass_foreach_dev_safe(dev, next, uc) { 69109d71aacSSimon Glass struct blk_desc *desc = dev_get_uclass_platdata(dev); 69209d71aacSSimon Glass 69309d71aacSSimon Glass if (desc->if_type == if_type) { 694706865afSStefan Roese ret = device_remove(dev, DM_REMOVE_NORMAL); 69509d71aacSSimon Glass if (ret) 69609d71aacSSimon Glass return ret; 69709d71aacSSimon Glass ret = device_unbind(dev); 69809d71aacSSimon Glass if (ret) 69909d71aacSSimon Glass return ret; 70009d71aacSSimon Glass } 70109d71aacSSimon Glass } 70209d71aacSSimon Glass 70309d71aacSSimon Glass return 0; 70409d71aacSSimon Glass } 70509d71aacSSimon Glass 70609d71aacSSimon Glass UCLASS_DRIVER(blk) = { 70709d71aacSSimon Glass .id = UCLASS_BLK, 70809d71aacSSimon Glass .name = "blk", 70909d71aacSSimon Glass .per_device_platdata_auto_alloc_size = sizeof(struct blk_desc), 71009d71aacSSimon Glass }; 711