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