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 1409d71aacSSimon Glass int blk_first_device(int if_type, struct udevice **devp) 1509d71aacSSimon Glass { 1609d71aacSSimon Glass struct blk_desc *desc; 1709d71aacSSimon Glass int ret; 1809d71aacSSimon Glass 1909d71aacSSimon Glass ret = uclass_first_device(UCLASS_BLK, devp); 2009d71aacSSimon Glass if (ret) 2109d71aacSSimon Glass return ret; 2209d71aacSSimon Glass if (!*devp) 2309d71aacSSimon Glass return -ENODEV; 2409d71aacSSimon Glass do { 2509d71aacSSimon Glass desc = dev_get_uclass_platdata(*devp); 2609d71aacSSimon Glass if (desc->if_type == if_type) 2709d71aacSSimon Glass return 0; 2809d71aacSSimon Glass ret = uclass_next_device(devp); 2909d71aacSSimon Glass if (ret) 3009d71aacSSimon Glass return ret; 3109d71aacSSimon Glass } while (*devp); 3209d71aacSSimon Glass 3309d71aacSSimon Glass return -ENODEV; 3409d71aacSSimon Glass } 3509d71aacSSimon Glass 3609d71aacSSimon Glass int blk_next_device(struct udevice **devp) 3709d71aacSSimon Glass { 3809d71aacSSimon Glass struct blk_desc *desc; 3909d71aacSSimon Glass int ret, if_type; 4009d71aacSSimon Glass 4109d71aacSSimon Glass desc = dev_get_uclass_platdata(*devp); 4209d71aacSSimon Glass if_type = desc->if_type; 4309d71aacSSimon Glass do { 4409d71aacSSimon Glass ret = uclass_next_device(devp); 4509d71aacSSimon Glass if (ret) 4609d71aacSSimon Glass return ret; 4709d71aacSSimon Glass if (!*devp) 4809d71aacSSimon Glass return -ENODEV; 4909d71aacSSimon Glass desc = dev_get_uclass_platdata(*devp); 5009d71aacSSimon Glass if (desc->if_type == if_type) 5109d71aacSSimon Glass return 0; 5209d71aacSSimon Glass } while (1); 5309d71aacSSimon Glass } 5409d71aacSSimon Glass 5509d71aacSSimon Glass int blk_get_device(int if_type, int devnum, struct udevice **devp) 5609d71aacSSimon Glass { 5709d71aacSSimon Glass struct uclass *uc; 5809d71aacSSimon Glass struct udevice *dev; 5909d71aacSSimon Glass int ret; 6009d71aacSSimon Glass 6109d71aacSSimon Glass ret = uclass_get(UCLASS_BLK, &uc); 6209d71aacSSimon Glass if (ret) 6309d71aacSSimon Glass return ret; 6409d71aacSSimon Glass uclass_foreach_dev(dev, uc) { 6509d71aacSSimon Glass struct blk_desc *desc = dev_get_uclass_platdata(dev); 6609d71aacSSimon Glass 6709d71aacSSimon Glass debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__, 6809d71aacSSimon Glass if_type, devnum, dev->name, desc->if_type, desc->devnum); 6909d71aacSSimon Glass if (desc->if_type == if_type && desc->devnum == devnum) { 7009d71aacSSimon Glass *devp = dev; 7109d71aacSSimon Glass return device_probe(dev); 7209d71aacSSimon Glass } 7309d71aacSSimon Glass } 7409d71aacSSimon Glass 7509d71aacSSimon Glass return -ENODEV; 7609d71aacSSimon Glass } 7709d71aacSSimon Glass 7809d71aacSSimon Glass unsigned long blk_dread(struct blk_desc *block_dev, lbaint_t start, 7909d71aacSSimon Glass lbaint_t blkcnt, void *buffer) 8009d71aacSSimon Glass { 8109d71aacSSimon Glass struct udevice *dev = block_dev->bdev; 8209d71aacSSimon Glass const struct blk_ops *ops = blk_get_ops(dev); 83*e40cf34aSEric Nelson ulong blks_read; 8409d71aacSSimon Glass 8509d71aacSSimon Glass if (!ops->read) 8609d71aacSSimon Glass return -ENOSYS; 8709d71aacSSimon Glass 88*e40cf34aSEric Nelson if (blkcache_read(block_dev->if_type, block_dev->devnum, 89*e40cf34aSEric Nelson start, blkcnt, block_dev->blksz, buffer)) 90*e40cf34aSEric Nelson return blkcnt; 91*e40cf34aSEric Nelson blks_read = ops->read(dev, start, blkcnt, buffer); 92*e40cf34aSEric Nelson if (blks_read == blkcnt) 93*e40cf34aSEric Nelson blkcache_fill(block_dev->if_type, block_dev->devnum, 94*e40cf34aSEric Nelson start, blkcnt, block_dev->blksz, buffer); 95*e40cf34aSEric Nelson 96*e40cf34aSEric Nelson return blks_read; 9709d71aacSSimon Glass } 9809d71aacSSimon Glass 9909d71aacSSimon Glass unsigned long blk_dwrite(struct blk_desc *block_dev, lbaint_t start, 10009d71aacSSimon Glass lbaint_t blkcnt, const void *buffer) 10109d71aacSSimon Glass { 10209d71aacSSimon Glass struct udevice *dev = block_dev->bdev; 10309d71aacSSimon Glass const struct blk_ops *ops = blk_get_ops(dev); 10409d71aacSSimon Glass 10509d71aacSSimon Glass if (!ops->write) 10609d71aacSSimon Glass return -ENOSYS; 10709d71aacSSimon Glass 108*e40cf34aSEric Nelson blkcache_invalidate(block_dev->if_type, block_dev->devnum); 10909d71aacSSimon Glass return ops->write(dev, start, blkcnt, buffer); 11009d71aacSSimon Glass } 11109d71aacSSimon Glass 11209d71aacSSimon Glass unsigned long blk_derase(struct blk_desc *block_dev, lbaint_t start, 11309d71aacSSimon Glass lbaint_t blkcnt) 11409d71aacSSimon Glass { 11509d71aacSSimon Glass struct udevice *dev = block_dev->bdev; 11609d71aacSSimon Glass const struct blk_ops *ops = blk_get_ops(dev); 11709d71aacSSimon Glass 11809d71aacSSimon Glass if (!ops->erase) 11909d71aacSSimon Glass return -ENOSYS; 12009d71aacSSimon Glass 121*e40cf34aSEric Nelson blkcache_invalidate(block_dev->if_type, block_dev->devnum); 12209d71aacSSimon Glass return ops->erase(dev, start, blkcnt); 12309d71aacSSimon Glass } 12409d71aacSSimon Glass 12509d71aacSSimon Glass int blk_prepare_device(struct udevice *dev) 12609d71aacSSimon Glass { 12709d71aacSSimon Glass struct blk_desc *desc = dev_get_uclass_platdata(dev); 12809d71aacSSimon Glass 12909d71aacSSimon Glass part_init(desc); 13009d71aacSSimon Glass 13109d71aacSSimon Glass return 0; 13209d71aacSSimon Glass } 13309d71aacSSimon Glass 13409d71aacSSimon Glass int blk_create_device(struct udevice *parent, const char *drv_name, 13509d71aacSSimon Glass const char *name, int if_type, int devnum, int blksz, 13609d71aacSSimon Glass lbaint_t size, struct udevice **devp) 13709d71aacSSimon Glass { 13809d71aacSSimon Glass struct blk_desc *desc; 13909d71aacSSimon Glass struct udevice *dev; 14009d71aacSSimon Glass int ret; 14109d71aacSSimon Glass 14209d71aacSSimon Glass ret = device_bind_driver(parent, drv_name, name, &dev); 14309d71aacSSimon Glass if (ret) 14409d71aacSSimon Glass return ret; 14509d71aacSSimon Glass desc = dev_get_uclass_platdata(dev); 14609d71aacSSimon Glass desc->if_type = if_type; 14709d71aacSSimon Glass desc->blksz = blksz; 14809d71aacSSimon Glass desc->lba = size / blksz; 14909d71aacSSimon Glass desc->part_type = PART_TYPE_UNKNOWN; 15009d71aacSSimon Glass desc->bdev = dev; 15109d71aacSSimon Glass desc->devnum = devnum; 15209d71aacSSimon Glass *devp = dev; 15309d71aacSSimon Glass 15409d71aacSSimon Glass return 0; 15509d71aacSSimon Glass } 15609d71aacSSimon Glass 15709d71aacSSimon Glass int blk_unbind_all(int if_type) 15809d71aacSSimon Glass { 15909d71aacSSimon Glass struct uclass *uc; 16009d71aacSSimon Glass struct udevice *dev, *next; 16109d71aacSSimon Glass int ret; 16209d71aacSSimon Glass 16309d71aacSSimon Glass ret = uclass_get(UCLASS_BLK, &uc); 16409d71aacSSimon Glass if (ret) 16509d71aacSSimon Glass return ret; 16609d71aacSSimon Glass uclass_foreach_dev_safe(dev, next, uc) { 16709d71aacSSimon Glass struct blk_desc *desc = dev_get_uclass_platdata(dev); 16809d71aacSSimon Glass 16909d71aacSSimon Glass if (desc->if_type == if_type) { 17009d71aacSSimon Glass ret = device_remove(dev); 17109d71aacSSimon Glass if (ret) 17209d71aacSSimon Glass return ret; 17309d71aacSSimon Glass ret = device_unbind(dev); 17409d71aacSSimon Glass if (ret) 17509d71aacSSimon Glass return ret; 17609d71aacSSimon Glass } 17709d71aacSSimon Glass } 17809d71aacSSimon Glass 17909d71aacSSimon Glass return 0; 18009d71aacSSimon Glass } 18109d71aacSSimon Glass 18209d71aacSSimon Glass UCLASS_DRIVER(blk) = { 18309d71aacSSimon Glass .id = UCLASS_BLK, 18409d71aacSSimon Glass .name = "blk", 18509d71aacSSimon Glass .per_device_platdata_auto_alloc_size = sizeof(struct blk_desc), 18609d71aacSSimon Glass }; 187