1 /* 2 * Copyright (C) 2016 Google, Inc 3 * Written by Simon Glass <sjg@chromium.org> 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #include <common.h> 9 #include <blk.h> 10 #include <dm.h> 11 #include <dm/device-internal.h> 12 #include <dm/lists.h> 13 14 int blk_first_device(int if_type, struct udevice **devp) 15 { 16 struct blk_desc *desc; 17 int ret; 18 19 ret = uclass_first_device(UCLASS_BLK, devp); 20 if (ret) 21 return ret; 22 if (!*devp) 23 return -ENODEV; 24 do { 25 desc = dev_get_uclass_platdata(*devp); 26 if (desc->if_type == if_type) 27 return 0; 28 ret = uclass_next_device(devp); 29 if (ret) 30 return ret; 31 } while (*devp); 32 33 return -ENODEV; 34 } 35 36 int blk_next_device(struct udevice **devp) 37 { 38 struct blk_desc *desc; 39 int ret, if_type; 40 41 desc = dev_get_uclass_platdata(*devp); 42 if_type = desc->if_type; 43 do { 44 ret = uclass_next_device(devp); 45 if (ret) 46 return ret; 47 if (!*devp) 48 return -ENODEV; 49 desc = dev_get_uclass_platdata(*devp); 50 if (desc->if_type == if_type) 51 return 0; 52 } while (1); 53 } 54 55 int blk_get_device(int if_type, int devnum, struct udevice **devp) 56 { 57 struct uclass *uc; 58 struct udevice *dev; 59 int ret; 60 61 ret = uclass_get(UCLASS_BLK, &uc); 62 if (ret) 63 return ret; 64 uclass_foreach_dev(dev, uc) { 65 struct blk_desc *desc = dev_get_uclass_platdata(dev); 66 67 debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__, 68 if_type, devnum, dev->name, desc->if_type, desc->devnum); 69 if (desc->if_type == if_type && desc->devnum == devnum) { 70 *devp = dev; 71 return device_probe(dev); 72 } 73 } 74 75 return -ENODEV; 76 } 77 78 unsigned long blk_dread(struct blk_desc *block_dev, lbaint_t start, 79 lbaint_t blkcnt, void *buffer) 80 { 81 struct udevice *dev = block_dev->bdev; 82 const struct blk_ops *ops = blk_get_ops(dev); 83 ulong blks_read; 84 85 if (!ops->read) 86 return -ENOSYS; 87 88 if (blkcache_read(block_dev->if_type, block_dev->devnum, 89 start, blkcnt, block_dev->blksz, buffer)) 90 return blkcnt; 91 blks_read = ops->read(dev, start, blkcnt, buffer); 92 if (blks_read == blkcnt) 93 blkcache_fill(block_dev->if_type, block_dev->devnum, 94 start, blkcnt, block_dev->blksz, buffer); 95 96 return blks_read; 97 } 98 99 unsigned long blk_dwrite(struct blk_desc *block_dev, lbaint_t start, 100 lbaint_t blkcnt, const void *buffer) 101 { 102 struct udevice *dev = block_dev->bdev; 103 const struct blk_ops *ops = blk_get_ops(dev); 104 105 if (!ops->write) 106 return -ENOSYS; 107 108 blkcache_invalidate(block_dev->if_type, block_dev->devnum); 109 return ops->write(dev, start, blkcnt, buffer); 110 } 111 112 unsigned long blk_derase(struct blk_desc *block_dev, lbaint_t start, 113 lbaint_t blkcnt) 114 { 115 struct udevice *dev = block_dev->bdev; 116 const struct blk_ops *ops = blk_get_ops(dev); 117 118 if (!ops->erase) 119 return -ENOSYS; 120 121 blkcache_invalidate(block_dev->if_type, block_dev->devnum); 122 return ops->erase(dev, start, blkcnt); 123 } 124 125 int blk_prepare_device(struct udevice *dev) 126 { 127 struct blk_desc *desc = dev_get_uclass_platdata(dev); 128 129 part_init(desc); 130 131 return 0; 132 } 133 134 int blk_create_device(struct udevice *parent, const char *drv_name, 135 const char *name, int if_type, int devnum, int blksz, 136 lbaint_t size, struct udevice **devp) 137 { 138 struct blk_desc *desc; 139 struct udevice *dev; 140 int ret; 141 142 ret = device_bind_driver(parent, drv_name, name, &dev); 143 if (ret) 144 return ret; 145 desc = dev_get_uclass_platdata(dev); 146 desc->if_type = if_type; 147 desc->blksz = blksz; 148 desc->lba = size / blksz; 149 desc->part_type = PART_TYPE_UNKNOWN; 150 desc->bdev = dev; 151 desc->devnum = devnum; 152 *devp = dev; 153 154 return 0; 155 } 156 157 int blk_unbind_all(int if_type) 158 { 159 struct uclass *uc; 160 struct udevice *dev, *next; 161 int ret; 162 163 ret = uclass_get(UCLASS_BLK, &uc); 164 if (ret) 165 return ret; 166 uclass_foreach_dev_safe(dev, next, uc) { 167 struct blk_desc *desc = dev_get_uclass_platdata(dev); 168 169 if (desc->if_type == if_type) { 170 ret = device_remove(dev); 171 if (ret) 172 return ret; 173 ret = device_unbind(dev); 174 if (ret) 175 return ret; 176 } 177 } 178 179 return 0; 180 } 181 182 UCLASS_DRIVER(blk) = { 183 .id = UCLASS_BLK, 184 .name = "blk", 185 .per_device_platdata_auto_alloc_size = sizeof(struct blk_desc), 186 }; 187