+// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2016 Google, Inc
+ * Copyright 2020 NXP
* Written by Simon Glass <sjg@chromium.org>
- *
- * SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
+#include <log.h>
+#include <malloc.h>
#include <mmc.h>
+#include "mmc_private.h"
static struct list_head mmc_devices;
static int cur_dev_num = -1;
+#if CONFIG_IS_ENABLED(MMC_TINY)
+static struct mmc mmc_static;
+struct mmc *find_mmc_device(int dev_num)
+{
+ return &mmc_static;
+}
+
+void mmc_do_preinit(void)
+{
+ struct mmc *m = &mmc_static;
+ if (m->preinit)
+ mmc_start_init(m);
+}
+
+struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
+{
+ return &mmc->block_dev;
+}
+#else
struct mmc *find_mmc_device(int dev_num)
{
struct mmc *m;
list_for_each(entry, &mmc_devices) {
m = list_entry(entry, struct mmc, link);
-#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
- mmc_set_preinit(m, 1);
-#endif
if (m->preinit)
mmc_start_init(m);
}
}
+#endif
void mmc_list_init(void)
{
#else
void print_mmc_devices(char separator) { }
#endif
+
+#if CONFIG_IS_ENABLED(MMC_TINY)
+static struct mmc mmc_static = {
+ .dsr_imp = 0,
+ .dsr = 0xffffffff,
+ .block_dev = {
+ .if_type = IF_TYPE_MMC,
+ .removable = 1,
+ .devnum = 0,
+ .block_read = mmc_bread,
+ .block_write = mmc_bwrite,
+ .block_erase = mmc_berase,
+ .part_type = 0,
+ },
+};
+
+struct mmc *mmc_create(const struct mmc_config *cfg, void *priv)
+{
+ struct mmc *mmc = &mmc_static;
+
+ /* First MMC device registered, fail to register a new one.
+ * Given users are not expecting this to fail, instead
+ * of failing let's just return the only MMC device
+ */
+ if (mmc->cfg) {
+ debug("Warning: MMC_TINY doesn't support multiple MMC devices\n");
+ return mmc;
+ }
+
+ mmc->cfg = cfg;
+ mmc->priv = priv;
+
+ return mmc;
+}
+
+void mmc_destroy(struct mmc *mmc)
+{
+}
+#else
+struct mmc *mmc_create(const struct mmc_config *cfg, void *priv)
+{
+ struct blk_desc *bdesc;
+ struct mmc *mmc;
+
+ /* quick validation */
+ if (cfg == NULL || cfg->f_min == 0 ||
+ cfg->f_max == 0 || cfg->b_max == 0)
+ return NULL;
+
+#if !CONFIG_IS_ENABLED(DM_MMC)
+ if (cfg->ops == NULL || cfg->ops->send_cmd == NULL)
+ return NULL;
+#endif
+
+ mmc = calloc(1, sizeof(*mmc));
+ if (mmc == NULL)
+ return NULL;
+
+ mmc->cfg = cfg;
+ mmc->priv = priv;
+
+ /* the following chunk was mmc_register() */
+
+ /* Setup dsr related values */
+ mmc->dsr_imp = 0;
+ mmc->dsr = 0xffffffff;
+ /* Setup the universal parts of the block interface just once */
+ bdesc = mmc_get_blk_desc(mmc);
+ bdesc->if_type = IF_TYPE_MMC;
+ bdesc->removable = 1;
+ bdesc->devnum = mmc_get_next_devnum();
+ bdesc->block_read = mmc_bread;
+ bdesc->block_write = mmc_bwrite;
+ bdesc->block_erase = mmc_berase;
+
+ /* setup initial part type */
+ bdesc->part_type = mmc->cfg->part_type;
+ mmc_list_add(mmc);
+
+ return mmc;
+}
+
+void mmc_destroy(struct mmc *mmc)
+{
+ /* only freeing memory for now */
+ free(mmc);
+}
+#endif
+
+static int mmc_select_hwpartp(struct blk_desc *desc, int hwpart)
+{
+ struct mmc *mmc = find_mmc_device(desc->devnum);
+ int ret;
+
+ if (!mmc)
+ return -ENODEV;
+
+ if (mmc->block_dev.hwpart == hwpart)
+ return 0;
+
+ if (mmc->part_config == MMCPART_NOAVAILABLE)
+ return -EMEDIUMTYPE;
+
+ ret = mmc_switch_part(mmc, hwpart);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int mmc_get_dev(int dev, struct blk_desc **descp)
+{
+ struct mmc *mmc = find_mmc_device(dev);
+ int ret;
+
+ if (!mmc)
+ return -ENODEV;
+ ret = mmc_init(mmc);
+ if (ret)
+ return ret;
+
+ *descp = &mmc->block_dev;
+
+ return 0;
+}
+
+U_BOOT_LEGACY_BLK(mmc) = {
+ .if_typename = "mmc",
+ .if_type = IF_TYPE_MMC,
+ .max_devs = -1,
+ .get_dev = mmc_get_dev,
+ .select_hwpart = mmc_select_hwpartp,
+};