blob: 530276a9dd1e73b1b673cee047f32123936bb897 [file] [log] [blame]
Simon Glasse7ecf7c2015-06-23 15:38:48 -06001/*
2 * Copyright (C) 2015 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 <mmc.h>
10#include <dm.h>
Simon Glasseede8972016-06-12 23:30:16 -060011#include <dm/device-internal.h>
Simon Glasse7ecf7c2015-06-23 15:38:48 -060012#include <dm/lists.h>
13#include <dm/root.h>
Simon Glasseede8972016-06-12 23:30:16 -060014#include "mmc_private.h"
Simon Glasse7ecf7c2015-06-23 15:38:48 -060015
16struct mmc *mmc_get_mmc_dev(struct udevice *dev)
17{
18 struct mmc_uclass_priv *upriv;
19
20 if (!device_active(dev))
21 return NULL;
22 upriv = dev_get_uclass_priv(dev);
23 return upriv->mmc;
24}
25
Simon Glass8ef761e2016-05-01 13:52:39 -060026#ifdef CONFIG_BLK
27struct mmc *find_mmc_device(int dev_num)
28{
29 struct udevice *dev, *mmc_dev;
30 int ret;
31
32 ret = blk_get_device(IF_TYPE_MMC, dev_num, &dev);
33
34 if (ret) {
35#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
36 printf("MMC Device %d not found\n", dev_num);
37#endif
38 return NULL;
39 }
40
41 mmc_dev = dev_get_parent(dev);
42
43 return mmc_get_mmc_dev(mmc_dev);
44}
45
46int get_mmc_num(void)
47{
48 return max(blk_find_max_devnum(IF_TYPE_MMC), 0);
49}
50
51int mmc_get_next_devnum(void)
52{
53 int ret;
54
55 ret = get_mmc_num();
56 if (ret < 0)
57 return ret;
58
59 return ret + 1;
60}
61
62struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
63{
64 struct blk_desc *desc;
65 struct udevice *dev;
66
67 device_find_first_child(mmc->dev, &dev);
68 if (!dev)
69 return NULL;
70 desc = dev_get_uclass_platdata(dev);
71
72 return desc;
73}
74
75void mmc_do_preinit(void)
76{
77 struct udevice *dev;
78 struct uclass *uc;
79 int ret;
80
81 ret = uclass_get(UCLASS_MMC, &uc);
82 if (ret)
83 return;
84 uclass_foreach_dev(dev, uc) {
85 struct mmc *m = mmc_get_mmc_dev(dev);
86
87 if (!m)
88 continue;
89#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
90 mmc_set_preinit(m, 1);
91#endif
92 if (m->preinit)
93 mmc_start_init(m);
94 }
95}
96
97#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
98void print_mmc_devices(char separator)
99{
100 struct udevice *dev;
101 char *mmc_type;
102 bool first = true;
103
104 for (uclass_first_device(UCLASS_MMC, &dev);
105 dev;
106 uclass_next_device(&dev)) {
107 struct mmc *m = mmc_get_mmc_dev(dev);
108
109 if (!first) {
110 printf("%c", separator);
111 if (separator != '\n')
112 puts(" ");
113 }
114 if (m->has_init)
115 mmc_type = IS_SD(m) ? "SD" : "eMMC";
116 else
117 mmc_type = NULL;
118
119 printf("%s: %d", m->cfg->name, mmc_get_blk_desc(m)->devnum);
120 if (mmc_type)
121 printf(" (%s)", mmc_type);
122 }
123
124 printf("\n");
125}
126
127#else
128void print_mmc_devices(char separator) { }
129#endif
Simon Glasseede8972016-06-12 23:30:16 -0600130
131int mmc_bind(struct udevice *dev, struct mmc *mmc, const struct mmc_config *cfg)
132{
133 struct blk_desc *bdesc;
134 struct udevice *bdev;
135 int ret;
136
137 ret = blk_create_devicef(dev, "mmc_blk", "blk", IF_TYPE_MMC, -1, 512,
138 0, &bdev);
139 if (ret) {
140 debug("Cannot create block device\n");
141 return ret;
142 }
143 bdesc = dev_get_uclass_platdata(bdev);
144 mmc->cfg = cfg;
145 mmc->priv = dev;
146
147 /* the following chunk was from mmc_register() */
148
149 /* Setup dsr related values */
150 mmc->dsr_imp = 0;
151 mmc->dsr = 0xffffffff;
152 /* Setup the universal parts of the block interface just once */
153 bdesc->removable = 1;
154
155 /* setup initial part type */
156 bdesc->part_type = cfg->part_type;
157 mmc->dev = dev;
158
159 return 0;
160}
161
162int mmc_unbind(struct udevice *dev)
163{
164 struct udevice *bdev;
165
166 device_find_first_child(dev, &bdev);
167 if (bdev) {
168 device_remove(bdev);
169 device_unbind(bdev);
170 }
171
172 return 0;
173}
174
175static int mmc_select_hwpart(struct udevice *bdev, int hwpart)
176{
177 struct udevice *mmc_dev = dev_get_parent(bdev);
178 struct mmc *mmc = mmc_get_mmc_dev(mmc_dev);
179 struct blk_desc *desc = dev_get_uclass_platdata(bdev);
180 int ret;
181
182 if (desc->hwpart == hwpart)
183 return 0;
184
185 if (mmc->part_config == MMCPART_NOAVAILABLE)
186 return -EMEDIUMTYPE;
187
188 ret = mmc_switch_part(mmc, hwpart);
189 if (ret)
190 return ret;
191
192 return 0;
193}
194
195static const struct blk_ops mmc_blk_ops = {
196 .read = mmc_bread,
197#ifndef CONFIG_SPL_BUILD
198 .write = mmc_bwrite,
199#endif
200 .select_hwpart = mmc_select_hwpart,
201};
202
203U_BOOT_DRIVER(mmc_blk) = {
204 .name = "mmc_blk",
205 .id = UCLASS_BLK,
206 .ops = &mmc_blk_ops,
207};
Simon Glass8ef761e2016-05-01 13:52:39 -0600208#endif /* CONFIG_BLK */
209
Simon Glasse7ecf7c2015-06-23 15:38:48 -0600210U_BOOT_DRIVER(mmc) = {
211 .name = "mmc",
212 .id = UCLASS_MMC,
213};
214
215UCLASS_DRIVER(mmc) = {
216 .id = UCLASS_MMC,
217 .name = "mmc",
218 .flags = DM_UC_FLAG_SEQ_ALIAS,
219 .per_device_auto_alloc_size = sizeof(struct mmc_uclass_priv),
220};