xref: /openbmc/u-boot/drivers/block/blk-uclass.c (revision 0691484a)
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 
84 	if (!ops->read)
85 		return -ENOSYS;
86 
87 	return ops->read(dev, start, blkcnt, buffer);
88 }
89 
90 unsigned long blk_dwrite(struct blk_desc *block_dev, lbaint_t start,
91 			 lbaint_t blkcnt, const void *buffer)
92 {
93 	struct udevice *dev = block_dev->bdev;
94 	const struct blk_ops *ops = blk_get_ops(dev);
95 
96 	if (!ops->write)
97 		return -ENOSYS;
98 
99 	return ops->write(dev, start, blkcnt, buffer);
100 }
101 
102 unsigned long blk_derase(struct blk_desc *block_dev, lbaint_t start,
103 			 lbaint_t blkcnt)
104 {
105 	struct udevice *dev = block_dev->bdev;
106 	const struct blk_ops *ops = blk_get_ops(dev);
107 
108 	if (!ops->erase)
109 		return -ENOSYS;
110 
111 	return ops->erase(dev, start, blkcnt);
112 }
113 
114 int blk_prepare_device(struct udevice *dev)
115 {
116 	struct blk_desc *desc = dev_get_uclass_platdata(dev);
117 
118 	part_init(desc);
119 
120 	return 0;
121 }
122 
123 int blk_create_device(struct udevice *parent, const char *drv_name,
124 		      const char *name, int if_type, int devnum, int blksz,
125 		      lbaint_t size, struct udevice **devp)
126 {
127 	struct blk_desc *desc;
128 	struct udevice *dev;
129 	int ret;
130 
131 	ret = device_bind_driver(parent, drv_name, name, &dev);
132 	if (ret)
133 		return ret;
134 	desc = dev_get_uclass_platdata(dev);
135 	desc->if_type = if_type;
136 	desc->blksz = blksz;
137 	desc->lba = size / blksz;
138 	desc->part_type = PART_TYPE_UNKNOWN;
139 	desc->bdev = dev;
140 	desc->devnum = devnum;
141 	*devp = dev;
142 
143 	return 0;
144 }
145 
146 int blk_unbind_all(int if_type)
147 {
148 	struct uclass *uc;
149 	struct udevice *dev, *next;
150 	int ret;
151 
152 	ret = uclass_get(UCLASS_BLK, &uc);
153 	if (ret)
154 		return ret;
155 	uclass_foreach_dev_safe(dev, next, uc) {
156 		struct blk_desc *desc = dev_get_uclass_platdata(dev);
157 
158 		if (desc->if_type == if_type) {
159 			ret = device_remove(dev);
160 			if (ret)
161 				return ret;
162 			ret = device_unbind(dev);
163 			if (ret)
164 				return ret;
165 		}
166 	}
167 
168 	return 0;
169 }
170 
171 UCLASS_DRIVER(blk) = {
172 	.id		= UCLASS_BLK,
173 	.name		= "blk",
174 	.per_device_platdata_auto_alloc_size = sizeof(struct blk_desc),
175 };
176