]>
Commit | Line | Data |
---|---|---|
e7ecf7cb SG |
1 | /* |
2 | * Copyright (C) 2015 Google, Inc | |
3 | * Written by Simon Glass <[email protected]> | |
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 | |
8ca51e51 SG |
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 | ||
e7ecf7cb SG |
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 | ||
8ef761ed SG |
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), 0); | |
115 | } | |
116 | ||
117 | int mmc_get_next_devnum(void) | |
118 | { | |
119 | int ret; | |
120 | ||
121 | ret = get_mmc_num(); | |
122 | if (ret < 0) | |
123 | return ret; | |
124 | ||
125 | return ret + 1; | |
126 | } | |
127 | ||
128 | struct blk_desc *mmc_get_blk_desc(struct mmc *mmc) | |
129 | { | |
130 | struct blk_desc *desc; | |
131 | struct udevice *dev; | |
132 | ||
133 | device_find_first_child(mmc->dev, &dev); | |
134 | if (!dev) | |
135 | return NULL; | |
136 | desc = dev_get_uclass_platdata(dev); | |
137 | ||
138 | return desc; | |
139 | } | |
140 | ||
141 | void mmc_do_preinit(void) | |
142 | { | |
143 | struct udevice *dev; | |
144 | struct uclass *uc; | |
145 | int ret; | |
146 | ||
147 | ret = uclass_get(UCLASS_MMC, &uc); | |
148 | if (ret) | |
149 | return; | |
150 | uclass_foreach_dev(dev, uc) { | |
151 | struct mmc *m = mmc_get_mmc_dev(dev); | |
152 | ||
153 | if (!m) | |
154 | continue; | |
155 | #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT | |
156 | mmc_set_preinit(m, 1); | |
157 | #endif | |
158 | if (m->preinit) | |
159 | mmc_start_init(m); | |
160 | } | |
161 | } | |
162 | ||
163 | #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) | |
164 | void print_mmc_devices(char separator) | |
165 | { | |
166 | struct udevice *dev; | |
167 | char *mmc_type; | |
168 | bool first = true; | |
169 | ||
170 | for (uclass_first_device(UCLASS_MMC, &dev); | |
171 | dev; | |
172 | uclass_next_device(&dev)) { | |
173 | struct mmc *m = mmc_get_mmc_dev(dev); | |
174 | ||
175 | if (!first) { | |
176 | printf("%c", separator); | |
177 | if (separator != '\n') | |
178 | puts(" "); | |
179 | } | |
180 | if (m->has_init) | |
181 | mmc_type = IS_SD(m) ? "SD" : "eMMC"; | |
182 | else | |
183 | mmc_type = NULL; | |
184 | ||
185 | printf("%s: %d", m->cfg->name, mmc_get_blk_desc(m)->devnum); | |
186 | if (mmc_type) | |
187 | printf(" (%s)", mmc_type); | |
188 | } | |
189 | ||
190 | printf("\n"); | |
191 | } | |
192 | ||
193 | #else | |
194 | void print_mmc_devices(char separator) { } | |
195 | #endif | |
eede897e SG |
196 | |
197 | int mmc_bind(struct udevice *dev, struct mmc *mmc, const struct mmc_config *cfg) | |
198 | { | |
199 | struct blk_desc *bdesc; | |
200 | struct udevice *bdev; | |
201 | int ret; | |
202 | ||
203 | ret = blk_create_devicef(dev, "mmc_blk", "blk", IF_TYPE_MMC, -1, 512, | |
204 | 0, &bdev); | |
205 | if (ret) { | |
206 | debug("Cannot create block device\n"); | |
207 | return ret; | |
208 | } | |
209 | bdesc = dev_get_uclass_platdata(bdev); | |
210 | mmc->cfg = cfg; | |
211 | mmc->priv = dev; | |
212 | ||
213 | /* the following chunk was from mmc_register() */ | |
214 | ||
215 | /* Setup dsr related values */ | |
216 | mmc->dsr_imp = 0; | |
217 | mmc->dsr = 0xffffffff; | |
218 | /* Setup the universal parts of the block interface just once */ | |
219 | bdesc->removable = 1; | |
220 | ||
221 | /* setup initial part type */ | |
222 | bdesc->part_type = cfg->part_type; | |
223 | mmc->dev = dev; | |
224 | ||
225 | return 0; | |
226 | } | |
227 | ||
228 | int mmc_unbind(struct udevice *dev) | |
229 | { | |
230 | struct udevice *bdev; | |
231 | ||
232 | device_find_first_child(dev, &bdev); | |
233 | if (bdev) { | |
234 | device_remove(bdev); | |
235 | device_unbind(bdev); | |
236 | } | |
237 | ||
238 | return 0; | |
239 | } | |
240 | ||
241 | static int mmc_select_hwpart(struct udevice *bdev, int hwpart) | |
242 | { | |
243 | struct udevice *mmc_dev = dev_get_parent(bdev); | |
244 | struct mmc *mmc = mmc_get_mmc_dev(mmc_dev); | |
245 | struct blk_desc *desc = dev_get_uclass_platdata(bdev); | |
246 | int ret; | |
247 | ||
248 | if (desc->hwpart == hwpart) | |
249 | return 0; | |
250 | ||
251 | if (mmc->part_config == MMCPART_NOAVAILABLE) | |
252 | return -EMEDIUMTYPE; | |
253 | ||
254 | ret = mmc_switch_part(mmc, hwpart); | |
255 | if (ret) | |
256 | return ret; | |
257 | ||
258 | return 0; | |
259 | } | |
260 | ||
261 | static const struct blk_ops mmc_blk_ops = { | |
262 | .read = mmc_bread, | |
263 | #ifndef CONFIG_SPL_BUILD | |
264 | .write = mmc_bwrite, | |
265 | #endif | |
266 | .select_hwpart = mmc_select_hwpart, | |
267 | }; | |
268 | ||
269 | U_BOOT_DRIVER(mmc_blk) = { | |
270 | .name = "mmc_blk", | |
271 | .id = UCLASS_BLK, | |
272 | .ops = &mmc_blk_ops, | |
273 | }; | |
8ef761ed SG |
274 | #endif /* CONFIG_BLK */ |
275 | ||
e7ecf7cb SG |
276 | U_BOOT_DRIVER(mmc) = { |
277 | .name = "mmc", | |
278 | .id = UCLASS_MMC, | |
279 | }; | |
280 | ||
281 | UCLASS_DRIVER(mmc) = { | |
282 | .id = UCLASS_MMC, | |
283 | .name = "mmc", | |
284 | .flags = DM_UC_FLAG_SEQ_ALIAS, | |
285 | .per_device_auto_alloc_size = sizeof(struct mmc_uclass_priv), | |
286 | }; |