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