]>
Commit | Line | Data |
---|---|---|
e7ecf7cb SG |
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> | |
eede897e | 11 | #include <dm/device-internal.h> |
e7ecf7cb SG |
12 | #include <dm/lists.h> |
13 | #include <dm/root.h> | |
eede897e | 14 | #include "mmc_private.h" |
e7ecf7cb | 15 | |
02ad33aa JC |
16 | DECLARE_GLOBAL_DATA_PTR; |
17 | ||
8ca51e51 SG |
18 | int dm_mmc_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, |
19 | struct mmc_data *data) | |
20 | { | |
21 | struct mmc *mmc = mmc_get_mmc_dev(dev); | |
22 | struct dm_mmc_ops *ops = mmc_get_ops(dev); | |
23 | int ret; | |
24 | ||
25 | mmmc_trace_before_send(mmc, cmd); | |
26 | if (ops->send_cmd) | |
27 | ret = ops->send_cmd(dev, cmd, data); | |
28 | else | |
29 | ret = -ENOSYS; | |
30 | mmmc_trace_after_send(mmc, cmd, ret); | |
31 | ||
32 | return ret; | |
33 | } | |
34 | ||
35 | int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) | |
36 | { | |
37 | return dm_mmc_send_cmd(mmc->dev, cmd, data); | |
38 | } | |
39 | ||
40 | int dm_mmc_set_ios(struct udevice *dev) | |
41 | { | |
42 | struct dm_mmc_ops *ops = mmc_get_ops(dev); | |
43 | ||
44 | if (!ops->set_ios) | |
45 | return -ENOSYS; | |
46 | return ops->set_ios(dev); | |
47 | } | |
48 | ||
49 | int mmc_set_ios(struct mmc *mmc) | |
50 | { | |
51 | return dm_mmc_set_ios(mmc->dev); | |
52 | } | |
53 | ||
318a7a57 JJH |
54 | void dm_mmc_send_init_stream(struct udevice *dev) |
55 | { | |
56 | struct dm_mmc_ops *ops = mmc_get_ops(dev); | |
57 | ||
58 | if (ops->send_init_stream) | |
59 | ops->send_init_stream(dev); | |
60 | } | |
61 | ||
62 | void mmc_send_init_stream(struct mmc *mmc) | |
63 | { | |
64 | dm_mmc_send_init_stream(mmc->dev); | |
65 | } | |
66 | ||
c10b85d6 JJH |
67 | int dm_mmc_wait_dat0(struct udevice *dev, int state, int timeout) |
68 | { | |
69 | struct dm_mmc_ops *ops = mmc_get_ops(dev); | |
70 | ||
71 | if (!ops->wait_dat0) | |
72 | return -ENOSYS; | |
73 | return ops->wait_dat0(dev, state, timeout); | |
74 | } | |
75 | ||
76 | int mmc_wait_dat0(struct mmc *mmc, int state, int timeout) | |
77 | { | |
78 | return dm_mmc_wait_dat0(mmc->dev, state, timeout); | |
79 | } | |
80 | ||
8ca51e51 SG |
81 | int dm_mmc_get_wp(struct udevice *dev) |
82 | { | |
83 | struct dm_mmc_ops *ops = mmc_get_ops(dev); | |
84 | ||
85 | if (!ops->get_wp) | |
86 | return -ENOSYS; | |
87 | return ops->get_wp(dev); | |
88 | } | |
89 | ||
90 | int mmc_getwp(struct mmc *mmc) | |
91 | { | |
92 | return dm_mmc_get_wp(mmc->dev); | |
93 | } | |
94 | ||
95 | int dm_mmc_get_cd(struct udevice *dev) | |
96 | { | |
97 | struct dm_mmc_ops *ops = mmc_get_ops(dev); | |
98 | ||
99 | if (!ops->get_cd) | |
100 | return -ENOSYS; | |
101 | return ops->get_cd(dev); | |
102 | } | |
103 | ||
104 | int mmc_getcd(struct mmc *mmc) | |
105 | { | |
106 | return dm_mmc_get_cd(mmc->dev); | |
107 | } | |
8ca51e51 | 108 | |
ec841209 KVA |
109 | int dm_mmc_execute_tuning(struct udevice *dev, uint opcode) |
110 | { | |
111 | struct dm_mmc_ops *ops = mmc_get_ops(dev); | |
112 | ||
113 | if (!ops->execute_tuning) | |
114 | return -ENOSYS; | |
115 | return ops->execute_tuning(dev, opcode); | |
116 | } | |
117 | ||
118 | int mmc_execute_tuning(struct mmc *mmc, uint opcode) | |
119 | { | |
120 | return dm_mmc_execute_tuning(mmc->dev, opcode); | |
121 | } | |
122 | ||
e7ecf7cb SG |
123 | struct mmc *mmc_get_mmc_dev(struct udevice *dev) |
124 | { | |
125 | struct mmc_uclass_priv *upriv; | |
126 | ||
127 | if (!device_active(dev)) | |
128 | return NULL; | |
129 | upriv = dev_get_uclass_priv(dev); | |
130 | return upriv->mmc; | |
131 | } | |
132 | ||
c4d660d4 | 133 | #if CONFIG_IS_ENABLED(BLK) |
8ef761ed SG |
134 | struct mmc *find_mmc_device(int dev_num) |
135 | { | |
136 | struct udevice *dev, *mmc_dev; | |
137 | int ret; | |
138 | ||
97525647 | 139 | ret = blk_find_device(IF_TYPE_MMC, dev_num, &dev); |
8ef761ed SG |
140 | |
141 | if (ret) { | |
142 | #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) | |
143 | printf("MMC Device %d not found\n", dev_num); | |
144 | #endif | |
145 | return NULL; | |
146 | } | |
147 | ||
148 | mmc_dev = dev_get_parent(dev); | |
149 | ||
97525647 SG |
150 | struct mmc *mmc = mmc_get_mmc_dev(mmc_dev); |
151 | ||
152 | return mmc; | |
8ef761ed SG |
153 | } |
154 | ||
155 | int get_mmc_num(void) | |
156 | { | |
46683f3d | 157 | return max((blk_find_max_devnum(IF_TYPE_MMC) + 1), 0); |
8ef761ed SG |
158 | } |
159 | ||
160 | int mmc_get_next_devnum(void) | |
161 | { | |
dd399cb7 | 162 | return blk_find_max_devnum(IF_TYPE_MMC); |
8ef761ed SG |
163 | } |
164 | ||
165 | struct blk_desc *mmc_get_blk_desc(struct mmc *mmc) | |
166 | { | |
167 | struct blk_desc *desc; | |
168 | struct udevice *dev; | |
169 | ||
170 | device_find_first_child(mmc->dev, &dev); | |
171 | if (!dev) | |
172 | return NULL; | |
173 | desc = dev_get_uclass_platdata(dev); | |
174 | ||
175 | return desc; | |
176 | } | |
177 | ||
178 | void mmc_do_preinit(void) | |
179 | { | |
180 | struct udevice *dev; | |
181 | struct uclass *uc; | |
182 | int ret; | |
183 | ||
184 | ret = uclass_get(UCLASS_MMC, &uc); | |
185 | if (ret) | |
186 | return; | |
187 | uclass_foreach_dev(dev, uc) { | |
188 | struct mmc *m = mmc_get_mmc_dev(dev); | |
189 | ||
190 | if (!m) | |
191 | continue; | |
192 | #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT | |
193 | mmc_set_preinit(m, 1); | |
194 | #endif | |
195 | if (m->preinit) | |
196 | mmc_start_init(m); | |
197 | } | |
198 | } | |
199 | ||
200 | #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) | |
201 | void print_mmc_devices(char separator) | |
202 | { | |
203 | struct udevice *dev; | |
204 | char *mmc_type; | |
205 | bool first = true; | |
206 | ||
207 | for (uclass_first_device(UCLASS_MMC, &dev); | |
208 | dev; | |
1bd4f92c | 209 | uclass_next_device(&dev), first = false) { |
8ef761ed SG |
210 | struct mmc *m = mmc_get_mmc_dev(dev); |
211 | ||
212 | if (!first) { | |
213 | printf("%c", separator); | |
214 | if (separator != '\n') | |
215 | puts(" "); | |
216 | } | |
217 | if (m->has_init) | |
218 | mmc_type = IS_SD(m) ? "SD" : "eMMC"; | |
219 | else | |
220 | mmc_type = NULL; | |
221 | ||
222 | printf("%s: %d", m->cfg->name, mmc_get_blk_desc(m)->devnum); | |
223 | if (mmc_type) | |
224 | printf(" (%s)", mmc_type); | |
225 | } | |
226 | ||
227 | printf("\n"); | |
228 | } | |
229 | ||
230 | #else | |
231 | void print_mmc_devices(char separator) { } | |
232 | #endif | |
eede897e SG |
233 | |
234 | int mmc_bind(struct udevice *dev, struct mmc *mmc, const struct mmc_config *cfg) | |
235 | { | |
236 | struct blk_desc *bdesc; | |
237 | struct udevice *bdev; | |
02ad33aa JC |
238 | int ret, devnum = -1; |
239 | ||
66656020 SG |
240 | if (!mmc_get_ops(dev)) |
241 | return -ENOSYS; | |
02ad33aa JC |
242 | #ifndef CONFIG_SPL_BUILD |
243 | /* Use the fixed index with aliase node's index */ | |
66e0ed5c SG |
244 | ret = dev_read_alias_seq(dev, &devnum); |
245 | debug("%s: alias ret=%d, devnum=%d\n", __func__, ret, devnum); | |
02ad33aa | 246 | #endif |
eede897e | 247 | |
02ad33aa JC |
248 | ret = blk_create_devicef(dev, "mmc_blk", "blk", IF_TYPE_MMC, |
249 | devnum, 512, 0, &bdev); | |
eede897e SG |
250 | if (ret) { |
251 | debug("Cannot create block device\n"); | |
252 | return ret; | |
253 | } | |
254 | bdesc = dev_get_uclass_platdata(bdev); | |
255 | mmc->cfg = cfg; | |
256 | mmc->priv = dev; | |
257 | ||
258 | /* the following chunk was from mmc_register() */ | |
259 | ||
260 | /* Setup dsr related values */ | |
261 | mmc->dsr_imp = 0; | |
262 | mmc->dsr = 0xffffffff; | |
263 | /* Setup the universal parts of the block interface just once */ | |
264 | bdesc->removable = 1; | |
265 | ||
266 | /* setup initial part type */ | |
267 | bdesc->part_type = cfg->part_type; | |
268 | mmc->dev = dev; | |
269 | ||
270 | return 0; | |
271 | } | |
272 | ||
273 | int mmc_unbind(struct udevice *dev) | |
274 | { | |
275 | struct udevice *bdev; | |
276 | ||
277 | device_find_first_child(dev, &bdev); | |
278 | if (bdev) { | |
706865af | 279 | device_remove(bdev, DM_REMOVE_NORMAL); |
eede897e SG |
280 | device_unbind(bdev); |
281 | } | |
282 | ||
283 | return 0; | |
284 | } | |
285 | ||
286 | static int mmc_select_hwpart(struct udevice *bdev, int hwpart) | |
287 | { | |
288 | struct udevice *mmc_dev = dev_get_parent(bdev); | |
289 | struct mmc *mmc = mmc_get_mmc_dev(mmc_dev); | |
290 | struct blk_desc *desc = dev_get_uclass_platdata(bdev); | |
eede897e SG |
291 | |
292 | if (desc->hwpart == hwpart) | |
293 | return 0; | |
294 | ||
295 | if (mmc->part_config == MMCPART_NOAVAILABLE) | |
296 | return -EMEDIUMTYPE; | |
297 | ||
dd399cb7 | 298 | return mmc_switch_part(mmc, hwpart); |
eede897e SG |
299 | } |
300 | ||
a0269bb6 FA |
301 | static int mmc_blk_probe(struct udevice *dev) |
302 | { | |
854f9a71 SG |
303 | struct udevice *mmc_dev = dev_get_parent(dev); |
304 | struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc_dev); | |
305 | struct mmc *mmc = upriv->mmc; | |
306 | int ret; | |
307 | ||
308 | ret = mmc_init(mmc); | |
309 | if (ret) { | |
310 | debug("%s: mmc_init() failed (err=%d)\n", __func__, ret); | |
311 | return ret; | |
312 | } | |
a0269bb6 | 313 | |
854f9a71 | 314 | return 0; |
a0269bb6 FA |
315 | } |
316 | ||
eede897e SG |
317 | static const struct blk_ops mmc_blk_ops = { |
318 | .read = mmc_bread, | |
319 | #ifndef CONFIG_SPL_BUILD | |
320 | .write = mmc_bwrite, | |
561e624c | 321 | .erase = mmc_berase, |
eede897e SG |
322 | #endif |
323 | .select_hwpart = mmc_select_hwpart, | |
324 | }; | |
325 | ||
326 | U_BOOT_DRIVER(mmc_blk) = { | |
327 | .name = "mmc_blk", | |
328 | .id = UCLASS_BLK, | |
329 | .ops = &mmc_blk_ops, | |
a0269bb6 | 330 | .probe = mmc_blk_probe, |
eede897e | 331 | }; |
8ef761ed SG |
332 | #endif /* CONFIG_BLK */ |
333 | ||
e7ecf7cb SG |
334 | U_BOOT_DRIVER(mmc) = { |
335 | .name = "mmc", | |
336 | .id = UCLASS_MMC, | |
337 | }; | |
338 | ||
339 | UCLASS_DRIVER(mmc) = { | |
340 | .id = UCLASS_MMC, | |
341 | .name = "mmc", | |
342 | .flags = DM_UC_FLAG_SEQ_ALIAS, | |
343 | .per_device_auto_alloc_size = sizeof(struct mmc_uclass_priv), | |
344 | }; |