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