Merge https://gitlab.denx.de/u-boot/custodians/u-boot-fsl-qoriq
[platform/kernel/u-boot.git] / drivers / mmc / mmc_legacy.c
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;
19 struct mmc *find_mmc_device(int dev_num)
20 {
21         return &mmc_static;
22 }
23
24 void mmc_do_preinit(void)
25 {
26         struct mmc *m = &mmc_static;
27         if (m->preinit)
28                 mmc_start_init(m);
29 }
30
31 struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
32 {
33         return &mmc->block_dev;
34 }
35 #else
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
55 int mmc_get_next_devnum(void)
56 {
57         return cur_dev_num++;
58 }
59
60 struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
61 {
62         return &mmc->block_dev;
63 }
64
65 int get_mmc_num(void)
66 {
67         return cur_dev_num;
68 }
69
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
84 void mmc_list_init(void)
85 {
86         INIT_LIST_HEAD(&mmc_devices);
87         cur_dev_num = 0;
88 }
89
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)
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
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
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
164 void mmc_destroy(struct mmc *mmc)
165 {
166 }
167 #else
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
211 void mmc_destroy(struct mmc *mmc)
212 {
213         /* only freeing memory for now */
214         free(mmc);
215 }
216 #endif
217
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
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 };