xref: /openbmc/u-boot/drivers/mmc/mmc-uclass.c (revision fc47cf9d)
1 /*
2  * Copyright (C) 2015 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 <mmc.h>
10 #include <dm.h>
11 #include <dm/device-internal.h>
12 #include <dm/lists.h>
13 #include <dm/root.h>
14 #include "mmc_private.h"
15 
16 #ifdef CONFIG_DM_MMC_OPS
17 int dm_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
18 		    struct mmc_data *data)
19 {
20 	struct mmc *mmc = mmc_get_mmc_dev(dev);
21 	struct dm_mmc_ops *ops = mmc_get_ops(dev);
22 	int ret;
23 
24 	mmmc_trace_before_send(mmc, cmd);
25 	if (ops->send_cmd)
26 		ret = ops->send_cmd(dev, cmd, data);
27 	else
28 		ret = -ENOSYS;
29 	mmmc_trace_after_send(mmc, cmd, ret);
30 
31 	return ret;
32 }
33 
34 int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
35 {
36 	return dm_mmc_send_cmd(mmc->dev, cmd, data);
37 }
38 
39 int dm_mmc_set_ios(struct udevice *dev)
40 {
41 	struct dm_mmc_ops *ops = mmc_get_ops(dev);
42 
43 	if (!ops->set_ios)
44 		return -ENOSYS;
45 	return ops->set_ios(dev);
46 }
47 
48 int mmc_set_ios(struct mmc *mmc)
49 {
50 	return dm_mmc_set_ios(mmc->dev);
51 }
52 
53 int dm_mmc_get_wp(struct udevice *dev)
54 {
55 	struct dm_mmc_ops *ops = mmc_get_ops(dev);
56 
57 	if (!ops->get_wp)
58 		return -ENOSYS;
59 	return ops->get_wp(dev);
60 }
61 
62 int mmc_getwp(struct mmc *mmc)
63 {
64 	return dm_mmc_get_wp(mmc->dev);
65 }
66 
67 int dm_mmc_get_cd(struct udevice *dev)
68 {
69 	struct dm_mmc_ops *ops = mmc_get_ops(dev);
70 
71 	if (!ops->get_cd)
72 		return -ENOSYS;
73 	return ops->get_cd(dev);
74 }
75 
76 int mmc_getcd(struct mmc *mmc)
77 {
78 	return dm_mmc_get_cd(mmc->dev);
79 }
80 #endif
81 
82 struct mmc *mmc_get_mmc_dev(struct udevice *dev)
83 {
84 	struct mmc_uclass_priv *upriv;
85 
86 	if (!device_active(dev))
87 		return NULL;
88 	upriv = dev_get_uclass_priv(dev);
89 	return upriv->mmc;
90 }
91 
92 #ifdef CONFIG_BLK
93 struct mmc *find_mmc_device(int dev_num)
94 {
95 	struct udevice *dev, *mmc_dev;
96 	int ret;
97 
98 	ret = blk_get_device(IF_TYPE_MMC, dev_num, &dev);
99 
100 	if (ret) {
101 #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
102 		printf("MMC Device %d not found\n", dev_num);
103 #endif
104 		return NULL;
105 	}
106 
107 	mmc_dev = dev_get_parent(dev);
108 
109 	return mmc_get_mmc_dev(mmc_dev);
110 }
111 
112 int get_mmc_num(void)
113 {
114 	return max((blk_find_max_devnum(IF_TYPE_MMC) + 1), 0);
115 }
116 
117 int mmc_get_next_devnum(void)
118 {
119 	return blk_find_max_devnum(IF_TYPE_MMC);
120 }
121 
122 struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
123 {
124 	struct blk_desc *desc;
125 	struct udevice *dev;
126 
127 	device_find_first_child(mmc->dev, &dev);
128 	if (!dev)
129 		return NULL;
130 	desc = dev_get_uclass_platdata(dev);
131 
132 	return desc;
133 }
134 
135 void mmc_do_preinit(void)
136 {
137 	struct udevice *dev;
138 	struct uclass *uc;
139 	int ret;
140 
141 	ret = uclass_get(UCLASS_MMC, &uc);
142 	if (ret)
143 		return;
144 	uclass_foreach_dev(dev, uc) {
145 		struct mmc *m = mmc_get_mmc_dev(dev);
146 
147 		if (!m)
148 			continue;
149 #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
150 		mmc_set_preinit(m, 1);
151 #endif
152 		if (m->preinit)
153 			mmc_start_init(m);
154 	}
155 }
156 
157 #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
158 void print_mmc_devices(char separator)
159 {
160 	struct udevice *dev;
161 	char *mmc_type;
162 	bool first = true;
163 
164 	for (uclass_first_device(UCLASS_MMC, &dev);
165 	     dev;
166 	     uclass_next_device(&dev), first = false) {
167 		struct mmc *m = mmc_get_mmc_dev(dev);
168 
169 		if (!first) {
170 			printf("%c", separator);
171 			if (separator != '\n')
172 				puts(" ");
173 		}
174 		if (m->has_init)
175 			mmc_type = IS_SD(m) ? "SD" : "eMMC";
176 		else
177 			mmc_type = NULL;
178 
179 		printf("%s: %d", m->cfg->name, mmc_get_blk_desc(m)->devnum);
180 		if (mmc_type)
181 			printf(" (%s)", mmc_type);
182 	}
183 
184 	printf("\n");
185 }
186 
187 #else
188 void print_mmc_devices(char separator) { }
189 #endif
190 
191 int mmc_bind(struct udevice *dev, struct mmc *mmc, const struct mmc_config *cfg)
192 {
193 	struct blk_desc *bdesc;
194 	struct udevice *bdev;
195 	int ret;
196 
197 	ret = blk_create_devicef(dev, "mmc_blk", "blk", IF_TYPE_MMC, -1, 512,
198 				 0, &bdev);
199 	if (ret) {
200 		debug("Cannot create block device\n");
201 		return ret;
202 	}
203 	bdesc = dev_get_uclass_platdata(bdev);
204 	mmc->cfg = cfg;
205 	mmc->priv = dev;
206 
207 	/* the following chunk was from mmc_register() */
208 
209 	/* Setup dsr related values */
210 	mmc->dsr_imp = 0;
211 	mmc->dsr = 0xffffffff;
212 	/* Setup the universal parts of the block interface just once */
213 	bdesc->removable = 1;
214 
215 	/* setup initial part type */
216 	bdesc->part_type = cfg->part_type;
217 	mmc->dev = dev;
218 
219 	return 0;
220 }
221 
222 int mmc_unbind(struct udevice *dev)
223 {
224 	struct udevice *bdev;
225 
226 	device_find_first_child(dev, &bdev);
227 	if (bdev) {
228 		device_remove(bdev);
229 		device_unbind(bdev);
230 	}
231 
232 	return 0;
233 }
234 
235 static int mmc_select_hwpart(struct udevice *bdev, int hwpart)
236 {
237 	struct udevice *mmc_dev = dev_get_parent(bdev);
238 	struct mmc *mmc = mmc_get_mmc_dev(mmc_dev);
239 	struct blk_desc *desc = dev_get_uclass_platdata(bdev);
240 
241 	if (desc->hwpart == hwpart)
242 		return 0;
243 
244 	if (mmc->part_config == MMCPART_NOAVAILABLE)
245 		return -EMEDIUMTYPE;
246 
247 	return mmc_switch_part(mmc, hwpart);
248 }
249 
250 static const struct blk_ops mmc_blk_ops = {
251 	.read	= mmc_bread,
252 #ifndef CONFIG_SPL_BUILD
253 	.write	= mmc_bwrite,
254 	.erase	= mmc_berase,
255 #endif
256 	.select_hwpart	= mmc_select_hwpart,
257 };
258 
259 U_BOOT_DRIVER(mmc_blk) = {
260 	.name		= "mmc_blk",
261 	.id		= UCLASS_BLK,
262 	.ops		= &mmc_blk_ops,
263 };
264 #endif /* CONFIG_BLK */
265 
266 U_BOOT_DRIVER(mmc) = {
267 	.name	= "mmc",
268 	.id	= UCLASS_MMC,
269 };
270 
271 UCLASS_DRIVER(mmc) = {
272 	.id		= UCLASS_MMC,
273 	.name		= "mmc",
274 	.flags		= DM_UC_FLAG_SEQ_ALIAS,
275 	.per_device_auto_alloc_size = sizeof(struct mmc_uclass_priv),
276 };
277