uboot/drivers/mmc/mmc_legacy.c
<<
>>
Prefs
   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
  14static struct list_head mmc_devices;
  15static int cur_dev_num = -1;
  16
  17#if CONFIG_IS_ENABLED(MMC_TINY)
  18static struct mmc mmc_static;
  19struct mmc *find_mmc_device(int dev_num)
  20{
  21        return &mmc_static;
  22}
  23
  24void mmc_do_preinit(void)
  25{
  26        struct mmc *m = &mmc_static;
  27        if (m->preinit)
  28                mmc_start_init(m);
  29}
  30
  31struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
  32{
  33        return &mmc->block_dev;
  34}
  35#else
  36struct 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
  55int mmc_get_next_devnum(void)
  56{
  57        return cur_dev_num++;
  58}
  59
  60struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
  61{
  62        return &mmc->block_dev;
  63}
  64
  65int get_mmc_num(void)
  66{
  67        return cur_dev_num;
  68}
  69
  70void 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
  84void mmc_list_init(void)
  85{
  86        INIT_LIST_HEAD(&mmc_devices);
  87        cur_dev_num = 0;
  88}
  89
  90void 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)
  98void 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
 127void print_mmc_devices(char separator) { }
 128#endif
 129
 130#if CONFIG_IS_ENABLED(MMC_TINY)
 131static struct mmc mmc_static = {
 132        .dsr_imp                = 0,
 133        .dsr                    = 0xffffffff,
 134        .block_dev = {
 135                .uclass_id      = UCLASS_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
 145struct 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
 164void mmc_destroy(struct mmc *mmc)
 165{
 166}
 167#else
 168struct 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->uclass_id = UCLASS_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
 211void mmc_destroy(struct mmc *mmc)
 212{
 213        /* only freeing memory for now */
 214        free(mmc);
 215}
 216#endif
 217
 218static 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
 239static 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
 255U_BOOT_LEGACY_BLK(mmc) = {
 256        .uclass_idname  = "mmc",
 257        .uclass_id      = UCLASS_MMC,
 258        .max_devs       = -1,
 259        .get_dev        = mmc_get_dev,
 260        .select_hwpart  = mmc_select_hwpartp,
 261};
 262