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