]>
Commit | Line | Data |
---|---|---|
c40fdca6 SG |
1 | /* |
2 | * Copyright (C) 2016 Google, Inc | |
3 | * Written by Simon Glass <sjg@chromium.org> | |
4 | * | |
5 | * SPDX-License-Identifier: GPL-2.0+ | |
6 | */ | |
7 | ||
8 | #include <common.h> | |
5aed4cbb | 9 | #include <malloc.h> |
c40fdca6 | 10 | #include <mmc.h> |
5aed4cbb | 11 | #include "mmc_private.h" |
c40fdca6 SG |
12 | |
13 | static struct list_head mmc_devices; | |
14 | static int cur_dev_num = -1; | |
15 | ||
b5b838f1 | 16 | #if !CONFIG_IS_ENABLED(MMC_TINY) |
c40fdca6 SG |
17 | struct mmc *find_mmc_device(int dev_num) |
18 | { | |
19 | struct mmc *m; | |
20 | struct list_head *entry; | |
21 | ||
22 | list_for_each(entry, &mmc_devices) { | |
23 | m = list_entry(entry, struct mmc, link); | |
24 | ||
25 | if (m->block_dev.devnum == dev_num) | |
26 | return m; | |
27 | } | |
28 | ||
29 | #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) | |
30 | printf("MMC Device %d not found\n", dev_num); | |
31 | #endif | |
32 | ||
33 | return NULL; | |
34 | } | |
35 | ||
36 | int mmc_get_next_devnum(void) | |
37 | { | |
38 | return cur_dev_num++; | |
39 | } | |
40 | ||
41 | struct blk_desc *mmc_get_blk_desc(struct mmc *mmc) | |
42 | { | |
43 | return &mmc->block_dev; | |
44 | } | |
45 | ||
46 | int get_mmc_num(void) | |
47 | { | |
48 | return cur_dev_num; | |
49 | } | |
50 | ||
51 | void mmc_do_preinit(void) | |
52 | { | |
53 | struct mmc *m; | |
54 | struct list_head *entry; | |
55 | ||
56 | list_for_each(entry, &mmc_devices) { | |
57 | m = list_entry(entry, struct mmc, link); | |
58 | ||
59 | #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT | |
60 | mmc_set_preinit(m, 1); | |
61 | #endif | |
62 | if (m->preinit) | |
63 | mmc_start_init(m); | |
64 | } | |
65 | } | |
b5b838f1 | 66 | #endif |
c40fdca6 SG |
67 | |
68 | void mmc_list_init(void) | |
69 | { | |
70 | INIT_LIST_HEAD(&mmc_devices); | |
71 | cur_dev_num = 0; | |
72 | } | |
73 | ||
74 | void mmc_list_add(struct mmc *mmc) | |
75 | { | |
76 | INIT_LIST_HEAD(&mmc->link); | |
77 | ||
78 | list_add_tail(&mmc->link, &mmc_devices); | |
79 | } | |
80 | ||
81 | #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) | |
82 | void print_mmc_devices(char separator) | |
83 | { | |
84 | struct mmc *m; | |
85 | struct list_head *entry; | |
86 | char *mmc_type; | |
87 | ||
88 | list_for_each(entry, &mmc_devices) { | |
89 | m = list_entry(entry, struct mmc, link); | |
90 | ||
91 | if (m->has_init) | |
92 | mmc_type = IS_SD(m) ? "SD" : "eMMC"; | |
93 | else | |
94 | mmc_type = NULL; | |
95 | ||
96 | printf("%s: %d", m->cfg->name, m->block_dev.devnum); | |
97 | if (mmc_type) | |
98 | printf(" (%s)", mmc_type); | |
99 | ||
100 | if (entry->next != &mmc_devices) { | |
101 | printf("%c", separator); | |
102 | if (separator != '\n') | |
103 | puts(" "); | |
104 | } | |
105 | } | |
106 | ||
107 | printf("\n"); | |
108 | } | |
109 | ||
110 | #else | |
111 | void print_mmc_devices(char separator) { } | |
112 | #endif | |
5aed4cbb | 113 | |
b5b838f1 MV |
114 | #if CONFIG_IS_ENABLED(MMC_TINY) |
115 | static struct mmc mmc_static = { | |
116 | .dsr_imp = 0, | |
117 | .dsr = 0xffffffff, | |
118 | .block_dev = { | |
119 | .if_type = IF_TYPE_MMC, | |
120 | .removable = 1, | |
121 | .devnum = 0, | |
122 | .block_read = mmc_bread, | |
123 | .block_write = mmc_bwrite, | |
124 | .block_erase = mmc_berase, | |
125 | .part_type = 0, | |
126 | }, | |
127 | }; | |
128 | ||
129 | struct mmc *mmc_create(const struct mmc_config *cfg, void *priv) | |
130 | { | |
131 | struct mmc *mmc = &mmc_static; | |
132 | ||
133 | mmc->cfg = cfg; | |
134 | mmc->priv = priv; | |
135 | ||
136 | return mmc; | |
137 | } | |
138 | ||
139 | void mmc_destroy(struct mmc *mmc) | |
140 | { | |
141 | } | |
142 | #else | |
5aed4cbb SG |
143 | struct mmc *mmc_create(const struct mmc_config *cfg, void *priv) |
144 | { | |
145 | struct blk_desc *bdesc; | |
146 | struct mmc *mmc; | |
147 | ||
148 | /* quick validation */ | |
177381a9 JC |
149 | if (cfg == NULL || cfg->f_min == 0 || |
150 | cfg->f_max == 0 || cfg->b_max == 0) | |
5aed4cbb SG |
151 | return NULL; |
152 | ||
177381a9 JC |
153 | #ifndef CONFIG_DM_MMC_OPS |
154 | if (cfg->ops == NULL || cfg->ops->send_cmd == NULL) | |
155 | return NULL; | |
156 | #endif | |
157 | ||
5aed4cbb SG |
158 | mmc = calloc(1, sizeof(*mmc)); |
159 | if (mmc == NULL) | |
160 | return NULL; | |
161 | ||
162 | mmc->cfg = cfg; | |
163 | mmc->priv = priv; | |
164 | ||
165 | /* the following chunk was mmc_register() */ | |
166 | ||
167 | /* Setup dsr related values */ | |
168 | mmc->dsr_imp = 0; | |
169 | mmc->dsr = 0xffffffff; | |
170 | /* Setup the universal parts of the block interface just once */ | |
171 | bdesc = mmc_get_blk_desc(mmc); | |
172 | bdesc->if_type = IF_TYPE_MMC; | |
173 | bdesc->removable = 1; | |
174 | bdesc->devnum = mmc_get_next_devnum(); | |
175 | bdesc->block_read = mmc_bread; | |
176 | bdesc->block_write = mmc_bwrite; | |
177 | bdesc->block_erase = mmc_berase; | |
178 | ||
179 | /* setup initial part type */ | |
180 | bdesc->part_type = mmc->cfg->part_type; | |
181 | mmc_list_add(mmc); | |
182 | ||
183 | return mmc; | |
184 | } | |
185 | ||
186 | void mmc_destroy(struct mmc *mmc) | |
187 | { | |
188 | /* only freeing memory for now */ | |
189 | free(mmc); | |
190 | } | |
b5b838f1 | 191 | #endif |
5aed4cbb SG |
192 | |
193 | static int mmc_select_hwpartp(struct blk_desc *desc, int hwpart) | |
194 | { | |
195 | struct mmc *mmc = find_mmc_device(desc->devnum); | |
196 | int ret; | |
197 | ||
198 | if (!mmc) | |
199 | return -ENODEV; | |
200 | ||
201 | if (mmc->block_dev.hwpart == hwpart) | |
202 | return 0; | |
203 | ||
204 | if (mmc->part_config == MMCPART_NOAVAILABLE) | |
205 | return -EMEDIUMTYPE; | |
206 | ||
207 | ret = mmc_switch_part(mmc, hwpart); | |
208 | if (ret) | |
209 | return ret; | |
210 | ||
211 | return 0; | |
212 | } | |
213 | ||
214 | static int mmc_get_dev(int dev, struct blk_desc **descp) | |
215 | { | |
216 | struct mmc *mmc = find_mmc_device(dev); | |
217 | int ret; | |
218 | ||
219 | if (!mmc) | |
220 | return -ENODEV; | |
221 | ret = mmc_init(mmc); | |
222 | if (ret) | |
223 | return ret; | |
224 | ||
225 | *descp = &mmc->block_dev; | |
226 | ||
227 | return 0; | |
228 | } | |
229 | ||
230 | U_BOOT_LEGACY_BLK(mmc) = { | |
231 | .if_typename = "mmc", | |
232 | .if_type = IF_TYPE_MMC, | |
233 | .max_devs = -1, | |
234 | .get_dev = mmc_get_dev, | |
235 | .select_hwpart = mmc_select_hwpartp, | |
236 | }; |