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