blob: a101ee43fde506d27a34c655b5025f4614e60376 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Simon Glassc40fdca2016-05-01 13:52:35 -06002/*
3 * Copyright (C) 2016 Google, Inc
Yangbo Lu39913ac2020-06-17 18:08:58 +08004 * Copyright 2020 NXP
Simon Glassc40fdca2016-05-01 13:52:35 -06005 * Written by Simon Glass <sjg@chromium.org>
Simon Glassc40fdca2016-05-01 13:52:35 -06006 */
7
8#include <common.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -06009#include <log.h>
Simon Glass5aed4cb2016-06-12 23:30:17 -060010#include <malloc.h>
Simon Glassc40fdca2016-05-01 13:52:35 -060011#include <mmc.h>
Simon Glass5aed4cb2016-06-12 23:30:17 -060012#include "mmc_private.h"
Simon Glassc40fdca2016-05-01 13:52:35 -060013
14static struct list_head mmc_devices;
15static int cur_dev_num = -1;
16
Marek Vasut62d77ce2018-04-15 00:37:11 +020017#if CONFIG_IS_ENABLED(MMC_TINY)
18static struct mmc mmc_static;
19struct mmc *find_mmc_device(int dev_num)
20{
21 return &mmc_static;
22}
23
24void mmc_do_preinit(void)
25{
26 struct mmc *m = &mmc_static;
Marek Vasut62d77ce2018-04-15 00:37:11 +020027 if (m->preinit)
28 mmc_start_init(m);
29}
30
31struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
32{
33 return &mmc->block_dev;
34}
35#else
Simon Glassc40fdca2016-05-01 13:52:35 -060036struct 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
55int mmc_get_next_devnum(void)
56{
57 return cur_dev_num++;
58}
59
60struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
61{
62 return &mmc->block_dev;
63}
64
65int get_mmc_num(void)
66{
67 return cur_dev_num;
68}
69
70void 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
Simon Glassc40fdca2016-05-01 13:52:35 -060078 if (m->preinit)
79 mmc_start_init(m);
80 }
81}
Marek Vasutb5b838f2016-12-01 02:06:33 +010082#endif
Simon Glassc40fdca2016-05-01 13:52:35 -060083
84void mmc_list_init(void)
85{
86 INIT_LIST_HEAD(&mmc_devices);
87 cur_dev_num = 0;
88}
89
90void 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)
98void 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
127void print_mmc_devices(char separator) { }
128#endif
Simon Glass5aed4cb2016-06-12 23:30:17 -0600129
Marek Vasutb5b838f2016-12-01 02:06:33 +0100130#if CONFIG_IS_ENABLED(MMC_TINY)
131static struct mmc mmc_static = {
132 .dsr_imp = 0,
133 .dsr = 0xffffffff,
134 .block_dev = {
Simon Glass8149b152022-09-17 09:00:09 -0600135 .uclass_id = UCLASS_MMC,
Marek Vasutb5b838f2016-12-01 02:06:33 +0100136 .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
145struct mmc *mmc_create(const struct mmc_config *cfg, void *priv)
146{
147 struct mmc *mmc = &mmc_static;
148
Ezequiel Garciad66fb5b2019-05-25 19:25:22 -0300149 /* 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
Marek Vasutb5b838f2016-12-01 02:06:33 +0100158 mmc->cfg = cfg;
159 mmc->priv = priv;
160
161 return mmc;
162}
163
164void mmc_destroy(struct mmc *mmc)
165{
166}
167#else
Simon Glass5aed4cb2016-06-12 23:30:17 -0600168struct mmc *mmc_create(const struct mmc_config *cfg, void *priv)
169{
170 struct blk_desc *bdesc;
171 struct mmc *mmc;
172
173 /* quick validation */
Jaehoon Chung177381a2016-08-12 11:39:05 +0900174 if (cfg == NULL || cfg->f_min == 0 ||
175 cfg->f_max == 0 || cfg->b_max == 0)
Simon Glass5aed4cb2016-06-12 23:30:17 -0600176 return NULL;
177
Simon Glasse7881d82017-07-29 11:35:31 -0600178#if !CONFIG_IS_ENABLED(DM_MMC)
Jaehoon Chung177381a2016-08-12 11:39:05 +0900179 if (cfg->ops == NULL || cfg->ops->send_cmd == NULL)
180 return NULL;
181#endif
182
Simon Glass5aed4cb2016-06-12 23:30:17 -0600183 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);
Simon Glass8149b152022-09-17 09:00:09 -0600197 bdesc->uclass_id = UCLASS_MMC;
Simon Glass5aed4cb2016-06-12 23:30:17 -0600198 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
211void mmc_destroy(struct mmc *mmc)
212{
213 /* only freeing memory for now */
214 free(mmc);
215}
Marek Vasutb5b838f2016-12-01 02:06:33 +0100216#endif
Simon Glass5aed4cb2016-06-12 23:30:17 -0600217
218static 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
239static 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
255U_BOOT_LEGACY_BLK(mmc) = {
Simon Glass8149b152022-09-17 09:00:09 -0600256 .uclass_idname = "mmc",
257 .uclass_id = UCLASS_MMC,
Simon Glass5aed4cb2016-06-12 23:30:17 -0600258 .max_devs = -1,
259 .get_dev = mmc_get_dev,
260 .select_hwpart = mmc_select_hwpartp,
261};