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