183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2c40fdca6SSimon Glass /*
3c40fdca6SSimon Glass * Copyright (C) 2016 Google, Inc
4c40fdca6SSimon Glass * Written by Simon Glass <sjg@chromium.org>
5c40fdca6SSimon Glass */
6c40fdca6SSimon Glass
7c40fdca6SSimon Glass #include <common.h>
85aed4cbbSSimon Glass #include <malloc.h>
9c40fdca6SSimon Glass #include <mmc.h>
105aed4cbbSSimon Glass #include "mmc_private.h"
11c40fdca6SSimon Glass
12c40fdca6SSimon Glass static struct list_head mmc_devices;
13c40fdca6SSimon Glass static int cur_dev_num = -1;
14c40fdca6SSimon Glass
15*62d77ceaSMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY)
16*62d77ceaSMarek Vasut static struct mmc mmc_static;
find_mmc_device(int dev_num)17*62d77ceaSMarek Vasut struct mmc *find_mmc_device(int dev_num)
18*62d77ceaSMarek Vasut {
19*62d77ceaSMarek Vasut return &mmc_static;
20*62d77ceaSMarek Vasut }
21*62d77ceaSMarek Vasut
mmc_do_preinit(void)22*62d77ceaSMarek Vasut void mmc_do_preinit(void)
23*62d77ceaSMarek Vasut {
24*62d77ceaSMarek Vasut struct mmc *m = &mmc_static;
25*62d77ceaSMarek Vasut #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
26*62d77ceaSMarek Vasut mmc_set_preinit(m, 1);
27*62d77ceaSMarek Vasut #endif
28*62d77ceaSMarek Vasut if (m->preinit)
29*62d77ceaSMarek Vasut mmc_start_init(m);
30*62d77ceaSMarek Vasut }
31*62d77ceaSMarek Vasut
mmc_get_blk_desc(struct mmc * mmc)32*62d77ceaSMarek Vasut struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
33*62d77ceaSMarek Vasut {
34*62d77ceaSMarek Vasut return &mmc->block_dev;
35*62d77ceaSMarek Vasut }
36*62d77ceaSMarek Vasut #else
find_mmc_device(int dev_num)37c40fdca6SSimon Glass struct mmc *find_mmc_device(int dev_num)
38c40fdca6SSimon Glass {
39c40fdca6SSimon Glass struct mmc *m;
40c40fdca6SSimon Glass struct list_head *entry;
41c40fdca6SSimon Glass
42c40fdca6SSimon Glass list_for_each(entry, &mmc_devices) {
43c40fdca6SSimon Glass m = list_entry(entry, struct mmc, link);
44c40fdca6SSimon Glass
45c40fdca6SSimon Glass if (m->block_dev.devnum == dev_num)
46c40fdca6SSimon Glass return m;
47c40fdca6SSimon Glass }
48c40fdca6SSimon Glass
49c40fdca6SSimon Glass #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
50c40fdca6SSimon Glass printf("MMC Device %d not found\n", dev_num);
51c40fdca6SSimon Glass #endif
52c40fdca6SSimon Glass
53c40fdca6SSimon Glass return NULL;
54c40fdca6SSimon Glass }
55c40fdca6SSimon Glass
mmc_get_next_devnum(void)56c40fdca6SSimon Glass int mmc_get_next_devnum(void)
57c40fdca6SSimon Glass {
58c40fdca6SSimon Glass return cur_dev_num++;
59c40fdca6SSimon Glass }
60c40fdca6SSimon Glass
mmc_get_blk_desc(struct mmc * mmc)61c40fdca6SSimon Glass struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
62c40fdca6SSimon Glass {
63c40fdca6SSimon Glass return &mmc->block_dev;
64c40fdca6SSimon Glass }
65c40fdca6SSimon Glass
get_mmc_num(void)66c40fdca6SSimon Glass int get_mmc_num(void)
67c40fdca6SSimon Glass {
68c40fdca6SSimon Glass return cur_dev_num;
69c40fdca6SSimon Glass }
70c40fdca6SSimon Glass
mmc_do_preinit(void)71c40fdca6SSimon Glass void mmc_do_preinit(void)
72c40fdca6SSimon Glass {
73c40fdca6SSimon Glass struct mmc *m;
74c40fdca6SSimon Glass struct list_head *entry;
75c40fdca6SSimon Glass
76c40fdca6SSimon Glass list_for_each(entry, &mmc_devices) {
77c40fdca6SSimon Glass m = list_entry(entry, struct mmc, link);
78c40fdca6SSimon Glass
79c40fdca6SSimon Glass #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
80c40fdca6SSimon Glass mmc_set_preinit(m, 1);
81c40fdca6SSimon Glass #endif
82c40fdca6SSimon Glass if (m->preinit)
83c40fdca6SSimon Glass mmc_start_init(m);
84c40fdca6SSimon Glass }
85c40fdca6SSimon Glass }
86b5b838f1SMarek Vasut #endif
87c40fdca6SSimon Glass
mmc_list_init(void)88c40fdca6SSimon Glass void mmc_list_init(void)
89c40fdca6SSimon Glass {
90c40fdca6SSimon Glass INIT_LIST_HEAD(&mmc_devices);
91c40fdca6SSimon Glass cur_dev_num = 0;
92c40fdca6SSimon Glass }
93c40fdca6SSimon Glass
mmc_list_add(struct mmc * mmc)94c40fdca6SSimon Glass void mmc_list_add(struct mmc *mmc)
95c40fdca6SSimon Glass {
96c40fdca6SSimon Glass INIT_LIST_HEAD(&mmc->link);
97c40fdca6SSimon Glass
98c40fdca6SSimon Glass list_add_tail(&mmc->link, &mmc_devices);
99c40fdca6SSimon Glass }
100c40fdca6SSimon Glass
101c40fdca6SSimon Glass #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
print_mmc_devices(char separator)102c40fdca6SSimon Glass void print_mmc_devices(char separator)
103c40fdca6SSimon Glass {
104c40fdca6SSimon Glass struct mmc *m;
105c40fdca6SSimon Glass struct list_head *entry;
106c40fdca6SSimon Glass char *mmc_type;
107c40fdca6SSimon Glass
108c40fdca6SSimon Glass list_for_each(entry, &mmc_devices) {
109c40fdca6SSimon Glass m = list_entry(entry, struct mmc, link);
110c40fdca6SSimon Glass
111c40fdca6SSimon Glass if (m->has_init)
112c40fdca6SSimon Glass mmc_type = IS_SD(m) ? "SD" : "eMMC";
113c40fdca6SSimon Glass else
114c40fdca6SSimon Glass mmc_type = NULL;
115c40fdca6SSimon Glass
116c40fdca6SSimon Glass printf("%s: %d", m->cfg->name, m->block_dev.devnum);
117c40fdca6SSimon Glass if (mmc_type)
118c40fdca6SSimon Glass printf(" (%s)", mmc_type);
119c40fdca6SSimon Glass
120c40fdca6SSimon Glass if (entry->next != &mmc_devices) {
121c40fdca6SSimon Glass printf("%c", separator);
122c40fdca6SSimon Glass if (separator != '\n')
123c40fdca6SSimon Glass puts(" ");
124c40fdca6SSimon Glass }
125c40fdca6SSimon Glass }
126c40fdca6SSimon Glass
127c40fdca6SSimon Glass printf("\n");
128c40fdca6SSimon Glass }
129c40fdca6SSimon Glass
130c40fdca6SSimon Glass #else
print_mmc_devices(char separator)131c40fdca6SSimon Glass void print_mmc_devices(char separator) { }
132c40fdca6SSimon Glass #endif
1335aed4cbbSSimon Glass
134b5b838f1SMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY)
135b5b838f1SMarek Vasut static struct mmc mmc_static = {
136b5b838f1SMarek Vasut .dsr_imp = 0,
137b5b838f1SMarek Vasut .dsr = 0xffffffff,
138b5b838f1SMarek Vasut .block_dev = {
139b5b838f1SMarek Vasut .if_type = IF_TYPE_MMC,
140b5b838f1SMarek Vasut .removable = 1,
141b5b838f1SMarek Vasut .devnum = 0,
142b5b838f1SMarek Vasut .block_read = mmc_bread,
143b5b838f1SMarek Vasut .block_write = mmc_bwrite,
144b5b838f1SMarek Vasut .block_erase = mmc_berase,
145b5b838f1SMarek Vasut .part_type = 0,
146b5b838f1SMarek Vasut },
147b5b838f1SMarek Vasut };
148b5b838f1SMarek Vasut
mmc_create(const struct mmc_config * cfg,void * priv)149b5b838f1SMarek Vasut struct mmc *mmc_create(const struct mmc_config *cfg, void *priv)
150b5b838f1SMarek Vasut {
151b5b838f1SMarek Vasut struct mmc *mmc = &mmc_static;
152b5b838f1SMarek Vasut
153b5b838f1SMarek Vasut mmc->cfg = cfg;
154b5b838f1SMarek Vasut mmc->priv = priv;
155b5b838f1SMarek Vasut
156b5b838f1SMarek Vasut return mmc;
157b5b838f1SMarek Vasut }
158b5b838f1SMarek Vasut
mmc_destroy(struct mmc * mmc)159b5b838f1SMarek Vasut void mmc_destroy(struct mmc *mmc)
160b5b838f1SMarek Vasut {
161b5b838f1SMarek Vasut }
162b5b838f1SMarek Vasut #else
mmc_create(const struct mmc_config * cfg,void * priv)1635aed4cbbSSimon Glass struct mmc *mmc_create(const struct mmc_config *cfg, void *priv)
1645aed4cbbSSimon Glass {
1655aed4cbbSSimon Glass struct blk_desc *bdesc;
1665aed4cbbSSimon Glass struct mmc *mmc;
1675aed4cbbSSimon Glass
1685aed4cbbSSimon Glass /* quick validation */
169177381a9SJaehoon Chung if (cfg == NULL || cfg->f_min == 0 ||
170177381a9SJaehoon Chung cfg->f_max == 0 || cfg->b_max == 0)
1715aed4cbbSSimon Glass return NULL;
1725aed4cbbSSimon Glass
173e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
174177381a9SJaehoon Chung if (cfg->ops == NULL || cfg->ops->send_cmd == NULL)
175177381a9SJaehoon Chung return NULL;
176177381a9SJaehoon Chung #endif
177177381a9SJaehoon Chung
1785aed4cbbSSimon Glass mmc = calloc(1, sizeof(*mmc));
1795aed4cbbSSimon Glass if (mmc == NULL)
1805aed4cbbSSimon Glass return NULL;
1815aed4cbbSSimon Glass
1825aed4cbbSSimon Glass mmc->cfg = cfg;
1835aed4cbbSSimon Glass mmc->priv = priv;
1845aed4cbbSSimon Glass
1855aed4cbbSSimon Glass /* the following chunk was mmc_register() */
1865aed4cbbSSimon Glass
1875aed4cbbSSimon Glass /* Setup dsr related values */
1885aed4cbbSSimon Glass mmc->dsr_imp = 0;
1895aed4cbbSSimon Glass mmc->dsr = 0xffffffff;
1905aed4cbbSSimon Glass /* Setup the universal parts of the block interface just once */
1915aed4cbbSSimon Glass bdesc = mmc_get_blk_desc(mmc);
1925aed4cbbSSimon Glass bdesc->if_type = IF_TYPE_MMC;
1935aed4cbbSSimon Glass bdesc->removable = 1;
1945aed4cbbSSimon Glass bdesc->devnum = mmc_get_next_devnum();
1955aed4cbbSSimon Glass bdesc->block_read = mmc_bread;
1965aed4cbbSSimon Glass bdesc->block_write = mmc_bwrite;
1975aed4cbbSSimon Glass bdesc->block_erase = mmc_berase;
1985aed4cbbSSimon Glass
1995aed4cbbSSimon Glass /* setup initial part type */
2005aed4cbbSSimon Glass bdesc->part_type = mmc->cfg->part_type;
2015aed4cbbSSimon Glass mmc_list_add(mmc);
2025aed4cbbSSimon Glass
2035aed4cbbSSimon Glass return mmc;
2045aed4cbbSSimon Glass }
2055aed4cbbSSimon Glass
mmc_destroy(struct mmc * mmc)2065aed4cbbSSimon Glass void mmc_destroy(struct mmc *mmc)
2075aed4cbbSSimon Glass {
2085aed4cbbSSimon Glass /* only freeing memory for now */
2095aed4cbbSSimon Glass free(mmc);
2105aed4cbbSSimon Glass }
211b5b838f1SMarek Vasut #endif
2125aed4cbbSSimon Glass
mmc_select_hwpartp(struct blk_desc * desc,int hwpart)2135aed4cbbSSimon Glass static int mmc_select_hwpartp(struct blk_desc *desc, int hwpart)
2145aed4cbbSSimon Glass {
2155aed4cbbSSimon Glass struct mmc *mmc = find_mmc_device(desc->devnum);
2165aed4cbbSSimon Glass int ret;
2175aed4cbbSSimon Glass
2185aed4cbbSSimon Glass if (!mmc)
2195aed4cbbSSimon Glass return -ENODEV;
2205aed4cbbSSimon Glass
2215aed4cbbSSimon Glass if (mmc->block_dev.hwpart == hwpart)
2225aed4cbbSSimon Glass return 0;
2235aed4cbbSSimon Glass
2245aed4cbbSSimon Glass if (mmc->part_config == MMCPART_NOAVAILABLE)
2255aed4cbbSSimon Glass return -EMEDIUMTYPE;
2265aed4cbbSSimon Glass
2275aed4cbbSSimon Glass ret = mmc_switch_part(mmc, hwpart);
2285aed4cbbSSimon Glass if (ret)
2295aed4cbbSSimon Glass return ret;
2305aed4cbbSSimon Glass
2315aed4cbbSSimon Glass return 0;
2325aed4cbbSSimon Glass }
2335aed4cbbSSimon Glass
mmc_get_dev(int dev,struct blk_desc ** descp)2345aed4cbbSSimon Glass static int mmc_get_dev(int dev, struct blk_desc **descp)
2355aed4cbbSSimon Glass {
2365aed4cbbSSimon Glass struct mmc *mmc = find_mmc_device(dev);
2375aed4cbbSSimon Glass int ret;
2385aed4cbbSSimon Glass
2395aed4cbbSSimon Glass if (!mmc)
2405aed4cbbSSimon Glass return -ENODEV;
2415aed4cbbSSimon Glass ret = mmc_init(mmc);
2425aed4cbbSSimon Glass if (ret)
2435aed4cbbSSimon Glass return ret;
2445aed4cbbSSimon Glass
2455aed4cbbSSimon Glass *descp = &mmc->block_dev;
2465aed4cbbSSimon Glass
2475aed4cbbSSimon Glass return 0;
2485aed4cbbSSimon Glass }
2495aed4cbbSSimon Glass
2505aed4cbbSSimon Glass U_BOOT_LEGACY_BLK(mmc) = {
2515aed4cbbSSimon Glass .if_typename = "mmc",
2525aed4cbbSSimon Glass .if_type = IF_TYPE_MMC,
2535aed4cbbSSimon Glass .max_devs = -1,
2545aed4cbbSSimon Glass .get_dev = mmc_get_dev,
2555aed4cbbSSimon Glass .select_hwpart = mmc_select_hwpartp,
2565aed4cbbSSimon Glass };
257