xref: /openbmc/u-boot/drivers/block/blk-uclass.c (revision ae4dc15d)
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