xref: /openbmc/u-boot/drivers/mmc/mmc_legacy.c (revision 2399e401)
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>
9 #include <malloc.h>
10 #include <mmc.h>
11 #include "mmc_private.h"
12 
13 static struct list_head mmc_devices;
14 static int cur_dev_num = -1;
15 
16 #if !CONFIG_IS_ENABLED(MMC_TINY)
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 }
66 #endif
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
113 
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
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 */
149 	if (cfg == NULL || cfg->f_min == 0 ||
150 	    cfg->f_max == 0 || cfg->b_max == 0)
151 		return NULL;
152 
153 #ifndef CONFIG_DM_MMC_OPS
154 	if (cfg->ops == NULL || cfg->ops->send_cmd == NULL)
155 		return NULL;
156 #endif
157 
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 }
191 #endif
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 };
237