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