Home | History | Annotate | Download | only in mmc
      1 // SPDX-License-Identifier: GPL-2.0+
      2 /*
      3  * Copyright (C) 2016 Google, Inc
      4  * Written by Simon Glass <sjg (at) chromium.org>
      5  */
      6 
      7 #include <common.h>
      8 #include <malloc.h>
      9 #include <mmc.h>
     10 #include "mmc_private.h"
     11 
     12 static struct list_head mmc_devices;
     13 static int cur_dev_num = -1;
     14 
     15 #if CONFIG_IS_ENABLED(MMC_TINY)
     16 static struct mmc mmc_static;
     17 struct mmc *find_mmc_device(int dev_num)
     18 {
     19 	return &mmc_static;
     20 }
     21 
     22 void mmc_do_preinit(void)
     23 {
     24 	struct mmc *m = &mmc_static;
     25 #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
     26 	mmc_set_preinit(m, 1);
     27 #endif
     28 	if (m->preinit)
     29 		mmc_start_init(m);
     30 }
     31 
     32 struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
     33 {
     34 	return &mmc->block_dev;
     35 }
     36 #else
     37 struct mmc *find_mmc_device(int dev_num)
     38 {
     39 	struct mmc *m;
     40 	struct list_head *entry;
     41 
     42 	list_for_each(entry, &mmc_devices) {
     43 		m = list_entry(entry, struct mmc, link);
     44 
     45 		if (m->block_dev.devnum == dev_num)
     46 			return m;
     47 	}
     48 
     49 #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
     50 	printf("MMC Device %d not found\n", dev_num);
     51 #endif
     52 
     53 	return NULL;
     54 }
     55 
     56 int mmc_get_next_devnum(void)
     57 {
     58 	return cur_dev_num++;
     59 }
     60 
     61 struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
     62 {
     63 	return &mmc->block_dev;
     64 }
     65 
     66 int get_mmc_num(void)
     67 {
     68 	return cur_dev_num;
     69 }
     70 
     71 void mmc_do_preinit(void)
     72 {
     73 	struct mmc *m;
     74 	struct list_head *entry;
     75 
     76 	list_for_each(entry, &mmc_devices) {
     77 		m = list_entry(entry, struct mmc, link);
     78 
     79 #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
     80 		mmc_set_preinit(m, 1);
     81 #endif
     82 		if (m->preinit)
     83 			mmc_start_init(m);
     84 	}
     85 }
     86 #endif
     87 
     88 void mmc_list_init(void)
     89 {
     90 	INIT_LIST_HEAD(&mmc_devices);
     91 	cur_dev_num = 0;
     92 }
     93 
     94 void mmc_list_add(struct mmc *mmc)
     95 {
     96 	INIT_LIST_HEAD(&mmc->link);
     97 
     98 	list_add_tail(&mmc->link, &mmc_devices);
     99 }
    100 
    101 #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
    102 void print_mmc_devices(char separator)
    103 {
    104 	struct mmc *m;
    105 	struct list_head *entry;
    106 	char *mmc_type;
    107 
    108 	list_for_each(entry, &mmc_devices) {
    109 		m = list_entry(entry, struct mmc, link);
    110 
    111 		if (m->has_init)
    112 			mmc_type = IS_SD(m) ? "SD" : "eMMC";
    113 		else
    114 			mmc_type = NULL;
    115 
    116 		printf("%s: %d", m->cfg->name, m->block_dev.devnum);
    117 		if (mmc_type)
    118 			printf(" (%s)", mmc_type);
    119 
    120 		if (entry->next != &mmc_devices) {
    121 			printf("%c", separator);
    122 			if (separator != '\n')
    123 				puts(" ");
    124 		}
    125 	}
    126 
    127 	printf("\n");
    128 }
    129 
    130 #else
    131 void print_mmc_devices(char separator) { }
    132 #endif
    133 
    134 #if CONFIG_IS_ENABLED(MMC_TINY)
    135 static struct mmc mmc_static = {
    136 	.dsr_imp		= 0,
    137 	.dsr			= 0xffffffff,
    138 	.block_dev = {
    139 		.if_type	= IF_TYPE_MMC,
    140 		.removable	= 1,
    141 		.devnum		= 0,
    142 		.block_read	= mmc_bread,
    143 		.block_write	= mmc_bwrite,
    144 		.block_erase	= mmc_berase,
    145 		.part_type	= 0,
    146 	},
    147 };
    148 
    149 struct mmc *mmc_create(const struct mmc_config *cfg, void *priv)
    150 {
    151 	struct mmc *mmc = &mmc_static;
    152 
    153 	mmc->cfg = cfg;
    154 	mmc->priv = priv;
    155 
    156 	return mmc;
    157 }
    158 
    159 void mmc_destroy(struct mmc *mmc)
    160 {
    161 }
    162 #else
    163 struct mmc *mmc_create(const struct mmc_config *cfg, void *priv)
    164 {
    165 	struct blk_desc *bdesc;
    166 	struct mmc *mmc;
    167 
    168 	/* quick validation */
    169 	if (cfg == NULL || cfg->f_min == 0 ||
    170 	    cfg->f_max == 0 || cfg->b_max == 0)
    171 		return NULL;
    172 
    173 #if !CONFIG_IS_ENABLED(DM_MMC)
    174 	if (cfg->ops == NULL || cfg->ops->send_cmd == NULL)
    175 		return NULL;
    176 #endif
    177 
    178 	mmc = calloc(1, sizeof(*mmc));
    179 	if (mmc == NULL)
    180 		return NULL;
    181 
    182 	mmc->cfg = cfg;
    183 	mmc->priv = priv;
    184 
    185 	/* the following chunk was mmc_register() */
    186 
    187 	/* Setup dsr related values */
    188 	mmc->dsr_imp = 0;
    189 	mmc->dsr = 0xffffffff;
    190 	/* Setup the universal parts of the block interface just once */
    191 	bdesc = mmc_get_blk_desc(mmc);
    192 	bdesc->if_type = IF_TYPE_MMC;
    193 	bdesc->removable = 1;
    194 	bdesc->devnum = mmc_get_next_devnum();
    195 	bdesc->block_read = mmc_bread;
    196 	bdesc->block_write = mmc_bwrite;
    197 	bdesc->block_erase = mmc_berase;
    198 
    199 	/* setup initial part type */
    200 	bdesc->part_type = mmc->cfg->part_type;
    201 	mmc_list_add(mmc);
    202 
    203 	return mmc;
    204 }
    205 
    206 void mmc_destroy(struct mmc *mmc)
    207 {
    208 	/* only freeing memory for now */
    209 	free(mmc);
    210 }
    211 #endif
    212 
    213 static int mmc_select_hwpartp(struct blk_desc *desc, int hwpart)
    214 {
    215 	struct mmc *mmc = find_mmc_device(desc->devnum);
    216 	int ret;
    217 
    218 	if (!mmc)
    219 		return -ENODEV;
    220 
    221 	if (mmc->block_dev.hwpart == hwpart)
    222 		return 0;
    223 
    224 	if (mmc->part_config == MMCPART_NOAVAILABLE)
    225 		return -EMEDIUMTYPE;
    226 
    227 	ret = mmc_switch_part(mmc, hwpart);
    228 	if (ret)
    229 		return ret;
    230 
    231 	return 0;
    232 }
    233 
    234 static int mmc_get_dev(int dev, struct blk_desc **descp)
    235 {
    236 	struct mmc *mmc = find_mmc_device(dev);
    237 	int ret;
    238 
    239 	if (!mmc)
    240 		return -ENODEV;
    241 	ret = mmc_init(mmc);
    242 	if (ret)
    243 		return ret;
    244 
    245 	*descp = &mmc->block_dev;
    246 
    247 	return 0;
    248 }
    249 
    250 U_BOOT_LEGACY_BLK(mmc) = {
    251 	.if_typename	= "mmc",
    252 	.if_type	= IF_TYPE_MMC,
    253 	.max_devs	= -1,
    254 	.get_dev	= mmc_get_dev,
    255 	.select_hwpart	= mmc_select_hwpartp,
    256 };
    257