]>
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 | 12 | #include <dm/lists.h> |
eede897e | 13 | #include "mmc_private.h" |
e7ecf7cb | 14 | |
02ad33aa JC |
15 | DECLARE_GLOBAL_DATA_PTR; |
16 | ||
8ca51e51 SG |
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 | ||
318a7a57 JJH |
53 | void dm_mmc_send_init_stream(struct udevice *dev) |
54 | { | |
55 | struct dm_mmc_ops *ops = mmc_get_ops(dev); | |
56 | ||
57 | if (ops->send_init_stream) | |
58 | ops->send_init_stream(dev); | |
59 | } | |
60 | ||
61 | void mmc_send_init_stream(struct mmc *mmc) | |
62 | { | |
63 | dm_mmc_send_init_stream(mmc->dev); | |
64 | } | |
65 | ||
f99c2efe | 66 | #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) |
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 | } | |
f99c2efe | 80 | #endif |
c10b85d6 | 81 | |
8ca51e51 SG |
82 | int dm_mmc_get_wp(struct udevice *dev) |
83 | { | |
84 | struct dm_mmc_ops *ops = mmc_get_ops(dev); | |
85 | ||
86 | if (!ops->get_wp) | |
87 | return -ENOSYS; | |
88 | return ops->get_wp(dev); | |
89 | } | |
90 | ||
91 | int mmc_getwp(struct mmc *mmc) | |
92 | { | |
93 | return dm_mmc_get_wp(mmc->dev); | |
94 | } | |
95 | ||
96 | int dm_mmc_get_cd(struct udevice *dev) | |
97 | { | |
98 | struct dm_mmc_ops *ops = mmc_get_ops(dev); | |
99 | ||
100 | if (!ops->get_cd) | |
101 | return -ENOSYS; | |
102 | return ops->get_cd(dev); | |
103 | } | |
104 | ||
105 | int mmc_getcd(struct mmc *mmc) | |
106 | { | |
107 | return dm_mmc_get_cd(mmc->dev); | |
108 | } | |
8ca51e51 | 109 | |
f99c2efe | 110 | #ifdef MMC_SUPPORTS_TUNING |
ec841209 KVA |
111 | int dm_mmc_execute_tuning(struct udevice *dev, uint opcode) |
112 | { | |
113 | struct dm_mmc_ops *ops = mmc_get_ops(dev); | |
114 | ||
115 | if (!ops->execute_tuning) | |
116 | return -ENOSYS; | |
117 | return ops->execute_tuning(dev, opcode); | |
118 | } | |
119 | ||
120 | int mmc_execute_tuning(struct mmc *mmc, uint opcode) | |
121 | { | |
122 | return dm_mmc_execute_tuning(mmc->dev, opcode); | |
123 | } | |
f99c2efe | 124 | #endif |
ec841209 | 125 | |
7abff2c3 | 126 | int mmc_of_parse(struct udevice *dev, struct mmc_config *cfg) |
9215ef5e KVA |
127 | { |
128 | int val; | |
129 | ||
7abff2c3 | 130 | val = dev_read_u32_default(dev, "bus-width", 1); |
9215ef5e KVA |
131 | |
132 | switch (val) { | |
133 | case 0x8: | |
134 | cfg->host_caps |= MMC_MODE_8BIT; | |
135 | /* fall through */ | |
136 | case 0x4: | |
137 | cfg->host_caps |= MMC_MODE_4BIT; | |
138 | /* fall through */ | |
139 | case 0x1: | |
140 | cfg->host_caps |= MMC_MODE_1BIT; | |
141 | break; | |
142 | default: | |
4b28f7bc MY |
143 | dev_err(dev, "Invalid \"bus-width\" value %u!\n", val); |
144 | return -EINVAL; | |
9215ef5e KVA |
145 | } |
146 | ||
c42ee367 MY |
147 | /* f_max is obtained from the optional "max-frequency" property */ |
148 | dev_read_u32(dev, "max-frequency", &cfg->f_max); | |
9215ef5e | 149 | |
7abff2c3 | 150 | if (dev_read_bool(dev, "cap-sd-highspeed")) |
9215ef5e | 151 | cfg->host_caps |= MMC_CAP(SD_HS); |
7abff2c3 | 152 | if (dev_read_bool(dev, "cap-mmc-highspeed")) |
9215ef5e | 153 | cfg->host_caps |= MMC_CAP(MMC_HS); |
7abff2c3 | 154 | if (dev_read_bool(dev, "sd-uhs-sdr12")) |
9215ef5e | 155 | cfg->host_caps |= MMC_CAP(UHS_SDR12); |
7abff2c3 | 156 | if (dev_read_bool(dev, "sd-uhs-sdr25")) |
9215ef5e | 157 | cfg->host_caps |= MMC_CAP(UHS_SDR25); |
7abff2c3 | 158 | if (dev_read_bool(dev, "sd-uhs-sdr50")) |
9215ef5e | 159 | cfg->host_caps |= MMC_CAP(UHS_SDR50); |
7abff2c3 | 160 | if (dev_read_bool(dev, "sd-uhs-sdr104")) |
9215ef5e | 161 | cfg->host_caps |= MMC_CAP(UHS_SDR104); |
7abff2c3 | 162 | if (dev_read_bool(dev, "sd-uhs-ddr50")) |
9215ef5e | 163 | cfg->host_caps |= MMC_CAP(UHS_DDR50); |
7abff2c3 | 164 | if (dev_read_bool(dev, "mmc-ddr-1_8v")) |
9215ef5e | 165 | cfg->host_caps |= MMC_CAP(MMC_DDR_52); |
7abff2c3 JJH |
166 | if (dev_read_bool(dev, "mmc-ddr-1_2v")) |
167 | cfg->host_caps |= MMC_CAP(MMC_DDR_52); | |
168 | if (dev_read_bool(dev, "mmc-hs200-1_8v")) | |
169 | cfg->host_caps |= MMC_CAP(MMC_HS_200); | |
170 | if (dev_read_bool(dev, "mmc-hs200-1_2v")) | |
9215ef5e KVA |
171 | cfg->host_caps |= MMC_CAP(MMC_HS_200); |
172 | ||
173 | return 0; | |
174 | } | |
175 | ||
e7ecf7cb SG |
176 | struct mmc *mmc_get_mmc_dev(struct udevice *dev) |
177 | { | |
178 | struct mmc_uclass_priv *upriv; | |
179 | ||
180 | if (!device_active(dev)) | |
181 | return NULL; | |
182 | upriv = dev_get_uclass_priv(dev); | |
183 | return upriv->mmc; | |
184 | } | |
185 | ||
c4d660d4 | 186 | #if CONFIG_IS_ENABLED(BLK) |
8ef761ed SG |
187 | struct mmc *find_mmc_device(int dev_num) |
188 | { | |
189 | struct udevice *dev, *mmc_dev; | |
190 | int ret; | |
191 | ||
97525647 | 192 | ret = blk_find_device(IF_TYPE_MMC, dev_num, &dev); |
8ef761ed SG |
193 | |
194 | if (ret) { | |
195 | #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) | |
196 | printf("MMC Device %d not found\n", dev_num); | |
197 | #endif | |
198 | return NULL; | |
199 | } | |
200 | ||
201 | mmc_dev = dev_get_parent(dev); | |
202 | ||
97525647 SG |
203 | struct mmc *mmc = mmc_get_mmc_dev(mmc_dev); |
204 | ||
205 | return mmc; | |
8ef761ed SG |
206 | } |
207 | ||
208 | int get_mmc_num(void) | |
209 | { | |
46683f3d | 210 | return max((blk_find_max_devnum(IF_TYPE_MMC) + 1), 0); |
8ef761ed SG |
211 | } |
212 | ||
213 | int mmc_get_next_devnum(void) | |
214 | { | |
dd399cb7 | 215 | return blk_find_max_devnum(IF_TYPE_MMC); |
8ef761ed SG |
216 | } |
217 | ||
218 | struct blk_desc *mmc_get_blk_desc(struct mmc *mmc) | |
219 | { | |
220 | struct blk_desc *desc; | |
221 | struct udevice *dev; | |
222 | ||
223 | device_find_first_child(mmc->dev, &dev); | |
224 | if (!dev) | |
225 | return NULL; | |
226 | desc = dev_get_uclass_platdata(dev); | |
227 | ||
228 | return desc; | |
229 | } | |
230 | ||
231 | void mmc_do_preinit(void) | |
232 | { | |
233 | struct udevice *dev; | |
234 | struct uclass *uc; | |
235 | int ret; | |
236 | ||
237 | ret = uclass_get(UCLASS_MMC, &uc); | |
238 | if (ret) | |
239 | return; | |
240 | uclass_foreach_dev(dev, uc) { | |
241 | struct mmc *m = mmc_get_mmc_dev(dev); | |
242 | ||
243 | if (!m) | |
244 | continue; | |
245 | #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT | |
246 | mmc_set_preinit(m, 1); | |
247 | #endif | |
248 | if (m->preinit) | |
249 | mmc_start_init(m); | |
250 | } | |
251 | } | |
252 | ||
253 | #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) | |
254 | void print_mmc_devices(char separator) | |
255 | { | |
256 | struct udevice *dev; | |
257 | char *mmc_type; | |
258 | bool first = true; | |
259 | ||
260 | for (uclass_first_device(UCLASS_MMC, &dev); | |
261 | dev; | |
1bd4f92c | 262 | uclass_next_device(&dev), first = false) { |
8ef761ed SG |
263 | struct mmc *m = mmc_get_mmc_dev(dev); |
264 | ||
265 | if (!first) { | |
266 | printf("%c", separator); | |
267 | if (separator != '\n') | |
268 | puts(" "); | |
269 | } | |
270 | if (m->has_init) | |
271 | mmc_type = IS_SD(m) ? "SD" : "eMMC"; | |
272 | else | |
273 | mmc_type = NULL; | |
274 | ||
275 | printf("%s: %d", m->cfg->name, mmc_get_blk_desc(m)->devnum); | |
276 | if (mmc_type) | |
277 | printf(" (%s)", mmc_type); | |
278 | } | |
279 | ||
280 | printf("\n"); | |
281 | } | |
282 | ||
283 | #else | |
284 | void print_mmc_devices(char separator) { } | |
285 | #endif | |
eede897e SG |
286 | |
287 | int mmc_bind(struct udevice *dev, struct mmc *mmc, const struct mmc_config *cfg) | |
288 | { | |
289 | struct blk_desc *bdesc; | |
290 | struct udevice *bdev; | |
02ad33aa JC |
291 | int ret, devnum = -1; |
292 | ||
66656020 SG |
293 | if (!mmc_get_ops(dev)) |
294 | return -ENOSYS; | |
02ad33aa JC |
295 | #ifndef CONFIG_SPL_BUILD |
296 | /* Use the fixed index with aliase node's index */ | |
66e0ed5c SG |
297 | ret = dev_read_alias_seq(dev, &devnum); |
298 | debug("%s: alias ret=%d, devnum=%d\n", __func__, ret, devnum); | |
02ad33aa | 299 | #endif |
eede897e | 300 | |
02ad33aa JC |
301 | ret = blk_create_devicef(dev, "mmc_blk", "blk", IF_TYPE_MMC, |
302 | devnum, 512, 0, &bdev); | |
eede897e SG |
303 | if (ret) { |
304 | debug("Cannot create block device\n"); | |
305 | return ret; | |
306 | } | |
307 | bdesc = dev_get_uclass_platdata(bdev); | |
308 | mmc->cfg = cfg; | |
309 | mmc->priv = dev; | |
310 | ||
311 | /* the following chunk was from mmc_register() */ | |
312 | ||
313 | /* Setup dsr related values */ | |
314 | mmc->dsr_imp = 0; | |
315 | mmc->dsr = 0xffffffff; | |
316 | /* Setup the universal parts of the block interface just once */ | |
317 | bdesc->removable = 1; | |
318 | ||
319 | /* setup initial part type */ | |
320 | bdesc->part_type = cfg->part_type; | |
321 | mmc->dev = dev; | |
322 | ||
323 | return 0; | |
324 | } | |
325 | ||
326 | int mmc_unbind(struct udevice *dev) | |
327 | { | |
328 | struct udevice *bdev; | |
329 | ||
330 | device_find_first_child(dev, &bdev); | |
331 | if (bdev) { | |
706865af | 332 | device_remove(bdev, DM_REMOVE_NORMAL); |
eede897e SG |
333 | device_unbind(bdev); |
334 | } | |
335 | ||
336 | return 0; | |
337 | } | |
338 | ||
339 | static int mmc_select_hwpart(struct udevice *bdev, int hwpart) | |
340 | { | |
341 | struct udevice *mmc_dev = dev_get_parent(bdev); | |
342 | struct mmc *mmc = mmc_get_mmc_dev(mmc_dev); | |
343 | struct blk_desc *desc = dev_get_uclass_platdata(bdev); | |
eede897e SG |
344 | |
345 | if (desc->hwpart == hwpart) | |
346 | return 0; | |
347 | ||
348 | if (mmc->part_config == MMCPART_NOAVAILABLE) | |
349 | return -EMEDIUMTYPE; | |
350 | ||
dd399cb7 | 351 | return mmc_switch_part(mmc, hwpart); |
eede897e SG |
352 | } |
353 | ||
a0269bb6 FA |
354 | static int mmc_blk_probe(struct udevice *dev) |
355 | { | |
854f9a71 SG |
356 | struct udevice *mmc_dev = dev_get_parent(dev); |
357 | struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc_dev); | |
358 | struct mmc *mmc = upriv->mmc; | |
359 | int ret; | |
360 | ||
361 | ret = mmc_init(mmc); | |
362 | if (ret) { | |
363 | debug("%s: mmc_init() failed (err=%d)\n", __func__, ret); | |
364 | return ret; | |
365 | } | |
a0269bb6 | 366 | |
854f9a71 | 367 | return 0; |
a0269bb6 FA |
368 | } |
369 | ||
eede897e SG |
370 | static const struct blk_ops mmc_blk_ops = { |
371 | .read = mmc_bread, | |
d6400c3f | 372 | #if CONFIG_IS_ENABLED(MMC_WRITE) |
eede897e | 373 | .write = mmc_bwrite, |
561e624c | 374 | .erase = mmc_berase, |
eede897e SG |
375 | #endif |
376 | .select_hwpart = mmc_select_hwpart, | |
377 | }; | |
378 | ||
379 | U_BOOT_DRIVER(mmc_blk) = { | |
380 | .name = "mmc_blk", | |
381 | .id = UCLASS_BLK, | |
382 | .ops = &mmc_blk_ops, | |
a0269bb6 | 383 | .probe = mmc_blk_probe, |
eede897e | 384 | }; |
8ef761ed SG |
385 | #endif /* CONFIG_BLK */ |
386 | ||
e7ecf7cb SG |
387 | U_BOOT_DRIVER(mmc) = { |
388 | .name = "mmc", | |
389 | .id = UCLASS_MMC, | |
390 | }; | |
391 | ||
392 | UCLASS_DRIVER(mmc) = { | |
393 | .id = UCLASS_MMC, | |
394 | .name = "mmc", | |
395 | .flags = DM_UC_FLAG_SEQ_ALIAS, | |
396 | .per_device_auto_alloc_size = sizeof(struct mmc_uclass_priv), | |
397 | }; |