1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2016 Google, Inc 4 * Written by Simon Glass <sjg@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