blob: 100b931e5b349f33d36691a5c552675935c4be8c [file] [log] [blame]
Simon Glassc40fdca2016-05-01 13:52:35 -06001/*
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>
Simon Glass5aed4cb2016-06-12 23:30:17 -06009#include <malloc.h>
Simon Glassc40fdca2016-05-01 13:52:35 -060010#include <mmc.h>
Simon Glass5aed4cb2016-06-12 23:30:17 -060011#include "mmc_private.h"
Simon Glassc40fdca2016-05-01 13:52:35 -060012
13static struct list_head mmc_devices;
14static int cur_dev_num = -1;
15
Marek Vasutb5b838f2016-12-01 02:06:33 +010016#if !CONFIG_IS_ENABLED(MMC_TINY)
Simon Glassc40fdca2016-05-01 13:52:35 -060017struct 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
36int mmc_get_next_devnum(void)
37{
38 return cur_dev_num++;
39}
40
41struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
42{
43 return &mmc->block_dev;
44}
45
46int get_mmc_num(void)
47{
48 return cur_dev_num;
49}
50
51void 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}
Marek Vasutb5b838f2016-12-01 02:06:33 +010066#endif
Simon Glassc40fdca2016-05-01 13:52:35 -060067
68void mmc_list_init(void)
69{
70 INIT_LIST_HEAD(&mmc_devices);
71 cur_dev_num = 0;
72}
73
74void 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)
82void 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
111void print_mmc_devices(char separator) { }
112#endif
Simon Glass5aed4cb2016-06-12 23:30:17 -0600113
Marek Vasutb5b838f2016-12-01 02:06:33 +0100114#if CONFIG_IS_ENABLED(MMC_TINY)
115static 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
129struct 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
139void mmc_destroy(struct mmc *mmc)
140{
141}
142#else
Simon Glass5aed4cb2016-06-12 23:30:17 -0600143struct mmc *mmc_create(const struct mmc_config *cfg, void *priv)
144{
145 struct blk_desc *bdesc;
146 struct mmc *mmc;
147
148 /* quick validation */
Jaehoon Chung177381a2016-08-12 11:39:05 +0900149 if (cfg == NULL || cfg->f_min == 0 ||
150 cfg->f_max == 0 || cfg->b_max == 0)
Simon Glass5aed4cb2016-06-12 23:30:17 -0600151 return NULL;
152
Simon Glasse7881d82017-07-29 11:35:31 -0600153#if !CONFIG_IS_ENABLED(DM_MMC)
Jaehoon Chung177381a2016-08-12 11:39:05 +0900154 if (cfg->ops == NULL || cfg->ops->send_cmd == NULL)
155 return NULL;
156#endif
157
Simon Glass5aed4cb2016-06-12 23:30:17 -0600158 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
186void mmc_destroy(struct mmc *mmc)
187{
188 /* only freeing memory for now */
189 free(mmc);
190}
Marek Vasutb5b838f2016-12-01 02:06:33 +0100191#endif
Simon Glass5aed4cb2016-06-12 23:30:17 -0600192
193static 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
214static 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
230U_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};