1272cc70bSAndy Fleming /* 2272cc70bSAndy Fleming * Copyright 2008, Freescale Semiconductor, Inc 3272cc70bSAndy Fleming * Andy Fleming 4272cc70bSAndy Fleming * 5272cc70bSAndy Fleming * Based vaguely on the Linux code 6272cc70bSAndy Fleming * 71a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 8272cc70bSAndy Fleming */ 9272cc70bSAndy Fleming 10272cc70bSAndy Fleming #include <config.h> 11272cc70bSAndy Fleming #include <common.h> 12272cc70bSAndy Fleming #include <command.h> 138e3332e2SSjoerd Simons #include <dm.h> 148e3332e2SSjoerd Simons #include <dm/device-internal.h> 15d4622df3SStephen Warren #include <errno.h> 16272cc70bSAndy Fleming #include <mmc.h> 17272cc70bSAndy Fleming #include <part.h> 182051aefeSPeng Fan #include <power/regulator.h> 19272cc70bSAndy Fleming #include <malloc.h> 20cf92e05cSSimon Glass #include <memalign.h> 21272cc70bSAndy Fleming #include <linux/list.h> 229b1f942cSRabin Vincent #include <div64.h> 23da61fa5fSPaul Burton #include "mmc_private.h" 24272cc70bSAndy Fleming 253697e599SPeng Fan static const unsigned int sd_au_size[] = { 263697e599SPeng Fan 0, SZ_16K / 512, SZ_32K / 512, 273697e599SPeng Fan SZ_64K / 512, SZ_128K / 512, SZ_256K / 512, 283697e599SPeng Fan SZ_512K / 512, SZ_1M / 512, SZ_2M / 512, 293697e599SPeng Fan SZ_4M / 512, SZ_8M / 512, (SZ_8M + SZ_4M) / 512, 303697e599SPeng Fan SZ_16M / 512, (SZ_16M + SZ_8M) / 512, SZ_32M / 512, SZ_64M / 512, 313697e599SPeng Fan }; 323697e599SPeng Fan 33b5b838f1SMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY) 34b5b838f1SMarek Vasut static struct mmc mmc_static; 35b5b838f1SMarek Vasut struct mmc *find_mmc_device(int dev_num) 36b5b838f1SMarek Vasut { 37b5b838f1SMarek Vasut return &mmc_static; 38b5b838f1SMarek Vasut } 39b5b838f1SMarek Vasut 40b5b838f1SMarek Vasut void mmc_do_preinit(void) 41b5b838f1SMarek Vasut { 42b5b838f1SMarek Vasut struct mmc *m = &mmc_static; 43b5b838f1SMarek Vasut #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 44b5b838f1SMarek Vasut mmc_set_preinit(m, 1); 45b5b838f1SMarek Vasut #endif 46b5b838f1SMarek Vasut if (m->preinit) 47b5b838f1SMarek Vasut mmc_start_init(m); 48b5b838f1SMarek Vasut } 49b5b838f1SMarek Vasut 50b5b838f1SMarek Vasut struct blk_desc *mmc_get_blk_desc(struct mmc *mmc) 51b5b838f1SMarek Vasut { 52b5b838f1SMarek Vasut return &mmc->block_dev; 53b5b838f1SMarek Vasut } 54b5b838f1SMarek Vasut #endif 55b5b838f1SMarek Vasut 56e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 57750121c3SJeroen Hofstee __weak int board_mmc_getwp(struct mmc *mmc) 58d23d8d7eSNikita Kiryanov { 59d23d8d7eSNikita Kiryanov return -1; 60d23d8d7eSNikita Kiryanov } 61d23d8d7eSNikita Kiryanov 62d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc) 63d23d8d7eSNikita Kiryanov { 64d23d8d7eSNikita Kiryanov int wp; 65d23d8d7eSNikita Kiryanov 66d23d8d7eSNikita Kiryanov wp = board_mmc_getwp(mmc); 67d23d8d7eSNikita Kiryanov 68d4e1da4eSPeter Korsgaard if (wp < 0) { 6993bfd616SPantelis Antoniou if (mmc->cfg->ops->getwp) 7093bfd616SPantelis Antoniou wp = mmc->cfg->ops->getwp(mmc); 71d4e1da4eSPeter Korsgaard else 72d4e1da4eSPeter Korsgaard wp = 0; 73d4e1da4eSPeter Korsgaard } 74d23d8d7eSNikita Kiryanov 75d23d8d7eSNikita Kiryanov return wp; 76d23d8d7eSNikita Kiryanov } 77d23d8d7eSNikita Kiryanov 78cee9ab7cSJeroen Hofstee __weak int board_mmc_getcd(struct mmc *mmc) 79cee9ab7cSJeroen Hofstee { 8011fdade2SStefano Babic return -1; 8111fdade2SStefano Babic } 828ca51e51SSimon Glass #endif 8311fdade2SStefano Babic 848635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE 85c0c76ebaSSimon Glass void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd) 86c0c76ebaSSimon Glass { 87c0c76ebaSSimon Glass printf("CMD_SEND:%d\n", cmd->cmdidx); 88c0c76ebaSSimon Glass printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg); 89c0c76ebaSSimon Glass } 90c0c76ebaSSimon Glass 91c0c76ebaSSimon Glass void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret) 92c0c76ebaSSimon Glass { 935db2fe3aSRaffaele Recalcati int i; 945db2fe3aSRaffaele Recalcati u8 *ptr; 955db2fe3aSRaffaele Recalcati 967863ce58SBin Meng if (ret) { 977863ce58SBin Meng printf("\t\tRET\t\t\t %d\n", ret); 987863ce58SBin Meng } else { 995db2fe3aSRaffaele Recalcati switch (cmd->resp_type) { 1005db2fe3aSRaffaele Recalcati case MMC_RSP_NONE: 1015db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_NONE\n"); 1025db2fe3aSRaffaele Recalcati break; 1035db2fe3aSRaffaele Recalcati case MMC_RSP_R1: 1045db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n", 1055db2fe3aSRaffaele Recalcati cmd->response[0]); 1065db2fe3aSRaffaele Recalcati break; 1075db2fe3aSRaffaele Recalcati case MMC_RSP_R1b: 1085db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n", 1095db2fe3aSRaffaele Recalcati cmd->response[0]); 1105db2fe3aSRaffaele Recalcati break; 1115db2fe3aSRaffaele Recalcati case MMC_RSP_R2: 1125db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R2\t\t 0x%08X \n", 1135db2fe3aSRaffaele Recalcati cmd->response[0]); 1145db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1155db2fe3aSRaffaele Recalcati cmd->response[1]); 1165db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1175db2fe3aSRaffaele Recalcati cmd->response[2]); 1185db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1195db2fe3aSRaffaele Recalcati cmd->response[3]); 1205db2fe3aSRaffaele Recalcati printf("\n"); 1215db2fe3aSRaffaele Recalcati printf("\t\t\t\t\tDUMPING DATA\n"); 1225db2fe3aSRaffaele Recalcati for (i = 0; i < 4; i++) { 1235db2fe3aSRaffaele Recalcati int j; 1245db2fe3aSRaffaele Recalcati printf("\t\t\t\t\t%03d - ", i*4); 125146bec79SDirk Behme ptr = (u8 *)&cmd->response[i]; 1265db2fe3aSRaffaele Recalcati ptr += 3; 1275db2fe3aSRaffaele Recalcati for (j = 0; j < 4; j++) 1285db2fe3aSRaffaele Recalcati printf("%02X ", *ptr--); 1295db2fe3aSRaffaele Recalcati printf("\n"); 1305db2fe3aSRaffaele Recalcati } 1315db2fe3aSRaffaele Recalcati break; 1325db2fe3aSRaffaele Recalcati case MMC_RSP_R3: 1335db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n", 1345db2fe3aSRaffaele Recalcati cmd->response[0]); 1355db2fe3aSRaffaele Recalcati break; 1365db2fe3aSRaffaele Recalcati default: 1375db2fe3aSRaffaele Recalcati printf("\t\tERROR MMC rsp not supported\n"); 1385db2fe3aSRaffaele Recalcati break; 1395db2fe3aSRaffaele Recalcati } 1407863ce58SBin Meng } 141c0c76ebaSSimon Glass } 142c0c76ebaSSimon Glass 143c0c76ebaSSimon Glass void mmc_trace_state(struct mmc *mmc, struct mmc_cmd *cmd) 144c0c76ebaSSimon Glass { 145c0c76ebaSSimon Glass int status; 146c0c76ebaSSimon Glass 147c0c76ebaSSimon Glass status = (cmd->response[0] & MMC_STATUS_CURR_STATE) >> 9; 148c0c76ebaSSimon Glass printf("CURR STATE:%d\n", status); 149c0c76ebaSSimon Glass } 1505db2fe3aSRaffaele Recalcati #endif 151c0c76ebaSSimon Glass 152*35f9e196SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG) 153*35f9e196SJean-Jacques Hiblot const char *mmc_mode_name(enum bus_mode mode) 154*35f9e196SJean-Jacques Hiblot { 155*35f9e196SJean-Jacques Hiblot static const char *const names[] = { 156*35f9e196SJean-Jacques Hiblot [MMC_LEGACY] = "MMC legacy", 157*35f9e196SJean-Jacques Hiblot [SD_LEGACY] = "SD Legacy", 158*35f9e196SJean-Jacques Hiblot [MMC_HS] = "MMC High Speed (26MHz)", 159*35f9e196SJean-Jacques Hiblot [SD_HS] = "SD High Speed (50MHz)", 160*35f9e196SJean-Jacques Hiblot [UHS_SDR12] = "UHS SDR12 (25MHz)", 161*35f9e196SJean-Jacques Hiblot [UHS_SDR25] = "UHS SDR25 (50MHz)", 162*35f9e196SJean-Jacques Hiblot [UHS_SDR50] = "UHS SDR50 (100MHz)", 163*35f9e196SJean-Jacques Hiblot [UHS_SDR104] = "UHS SDR104 (208MHz)", 164*35f9e196SJean-Jacques Hiblot [UHS_DDR50] = "UHS DDR50 (50MHz)", 165*35f9e196SJean-Jacques Hiblot [MMC_HS_52] = "MMC High Speed (52MHz)", 166*35f9e196SJean-Jacques Hiblot [MMC_DDR_52] = "MMC DDR52 (52MHz)", 167*35f9e196SJean-Jacques Hiblot [MMC_HS_200] = "HS200 (200MHz)", 168*35f9e196SJean-Jacques Hiblot }; 169*35f9e196SJean-Jacques Hiblot 170*35f9e196SJean-Jacques Hiblot if (mode >= MMC_MODES_END) 171*35f9e196SJean-Jacques Hiblot return "Unknown mode"; 172*35f9e196SJean-Jacques Hiblot else 173*35f9e196SJean-Jacques Hiblot return names[mode]; 174*35f9e196SJean-Jacques Hiblot } 175*35f9e196SJean-Jacques Hiblot #endif 176*35f9e196SJean-Jacques Hiblot 177*35f9e196SJean-Jacques Hiblot static int mmc_select_mode(struct mmc *mmc, enum bus_mode mode) 178*35f9e196SJean-Jacques Hiblot { 179*35f9e196SJean-Jacques Hiblot mmc->selected_mode = mode; 180*35f9e196SJean-Jacques Hiblot debug("selecting mode %s (freq : %d MHz)\n", mmc_mode_name(mode), 181*35f9e196SJean-Jacques Hiblot mmc->tran_speed / 1000000); 182*35f9e196SJean-Jacques Hiblot return 0; 183*35f9e196SJean-Jacques Hiblot } 184*35f9e196SJean-Jacques Hiblot 185e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 186c0c76ebaSSimon Glass int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) 187c0c76ebaSSimon Glass { 188c0c76ebaSSimon Glass int ret; 189c0c76ebaSSimon Glass 190c0c76ebaSSimon Glass mmmc_trace_before_send(mmc, cmd); 191c0c76ebaSSimon Glass ret = mmc->cfg->ops->send_cmd(mmc, cmd, data); 192c0c76ebaSSimon Glass mmmc_trace_after_send(mmc, cmd, ret); 193c0c76ebaSSimon Glass 1948635ff9eSMarek Vasut return ret; 195272cc70bSAndy Fleming } 1968ca51e51SSimon Glass #endif 197272cc70bSAndy Fleming 198da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout) 1995d4fc8d9SRaffaele Recalcati { 2005d4fc8d9SRaffaele Recalcati struct mmc_cmd cmd; 201d617c426SJan Kloetzke int err, retries = 5; 2025d4fc8d9SRaffaele Recalcati 2035d4fc8d9SRaffaele Recalcati cmd.cmdidx = MMC_CMD_SEND_STATUS; 2045d4fc8d9SRaffaele Recalcati cmd.resp_type = MMC_RSP_R1; 205aaf3d41aSMarek Vasut if (!mmc_host_is_spi(mmc)) 206aaf3d41aSMarek Vasut cmd.cmdarg = mmc->rca << 16; 2075d4fc8d9SRaffaele Recalcati 2081677eef4SAndrew Gabbasov while (1) { 2095d4fc8d9SRaffaele Recalcati err = mmc_send_cmd(mmc, &cmd, NULL); 210d617c426SJan Kloetzke if (!err) { 211d617c426SJan Kloetzke if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) && 212d617c426SJan Kloetzke (cmd.response[0] & MMC_STATUS_CURR_STATE) != 213d617c426SJan Kloetzke MMC_STATE_PRG) 2145d4fc8d9SRaffaele Recalcati break; 215d617c426SJan Kloetzke else if (cmd.response[0] & MMC_STATUS_MASK) { 21656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 217d617c426SJan Kloetzke printf("Status Error: 0x%08X\n", 218d617c426SJan Kloetzke cmd.response[0]); 21956196826SPaul Burton #endif 220915ffa52SJaehoon Chung return -ECOMM; 221d617c426SJan Kloetzke } 222d617c426SJan Kloetzke } else if (--retries < 0) 223d617c426SJan Kloetzke return err; 2245d4fc8d9SRaffaele Recalcati 2251677eef4SAndrew Gabbasov if (timeout-- <= 0) 2261677eef4SAndrew Gabbasov break; 2275d4fc8d9SRaffaele Recalcati 2281677eef4SAndrew Gabbasov udelay(1000); 2291677eef4SAndrew Gabbasov } 2305d4fc8d9SRaffaele Recalcati 231c0c76ebaSSimon Glass mmc_trace_state(mmc, &cmd); 2325b0c942fSJongman Heo if (timeout <= 0) { 23356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2345d4fc8d9SRaffaele Recalcati printf("Timeout waiting card ready\n"); 23556196826SPaul Burton #endif 236915ffa52SJaehoon Chung return -ETIMEDOUT; 2375d4fc8d9SRaffaele Recalcati } 2385d4fc8d9SRaffaele Recalcati 2395d4fc8d9SRaffaele Recalcati return 0; 2405d4fc8d9SRaffaele Recalcati } 2415d4fc8d9SRaffaele Recalcati 242da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len) 243272cc70bSAndy Fleming { 244272cc70bSAndy Fleming struct mmc_cmd cmd; 245272cc70bSAndy Fleming 246786e8f81SAndrew Gabbasov if (mmc->ddr_mode) 247d22e3d46SJaehoon Chung return 0; 248d22e3d46SJaehoon Chung 249272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SET_BLOCKLEN; 250272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 251272cc70bSAndy Fleming cmd.cmdarg = len; 252272cc70bSAndy Fleming 253272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, NULL); 254272cc70bSAndy Fleming } 255272cc70bSAndy Fleming 256ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start, 257fdbb873eSKim Phillips lbaint_t blkcnt) 258272cc70bSAndy Fleming { 259272cc70bSAndy Fleming struct mmc_cmd cmd; 260272cc70bSAndy Fleming struct mmc_data data; 261272cc70bSAndy Fleming 2624a1a06bcSAlagu Sankar if (blkcnt > 1) 2634a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; 2644a1a06bcSAlagu Sankar else 265272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; 266272cc70bSAndy Fleming 267272cc70bSAndy Fleming if (mmc->high_capacity) 2684a1a06bcSAlagu Sankar cmd.cmdarg = start; 269272cc70bSAndy Fleming else 2704a1a06bcSAlagu Sankar cmd.cmdarg = start * mmc->read_bl_len; 271272cc70bSAndy Fleming 272272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 273272cc70bSAndy Fleming 274272cc70bSAndy Fleming data.dest = dst; 2754a1a06bcSAlagu Sankar data.blocks = blkcnt; 276272cc70bSAndy Fleming data.blocksize = mmc->read_bl_len; 277272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 278272cc70bSAndy Fleming 2794a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, &data)) 2804a1a06bcSAlagu Sankar return 0; 2814a1a06bcSAlagu Sankar 2824a1a06bcSAlagu Sankar if (blkcnt > 1) { 2834a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; 2844a1a06bcSAlagu Sankar cmd.cmdarg = 0; 2854a1a06bcSAlagu Sankar cmd.resp_type = MMC_RSP_R1b; 2864a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, NULL)) { 28756196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2884a1a06bcSAlagu Sankar printf("mmc fail to send stop cmd\n"); 28956196826SPaul Burton #endif 2904a1a06bcSAlagu Sankar return 0; 2914a1a06bcSAlagu Sankar } 292272cc70bSAndy Fleming } 293272cc70bSAndy Fleming 2944a1a06bcSAlagu Sankar return blkcnt; 295272cc70bSAndy Fleming } 296272cc70bSAndy Fleming 297c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK) 2987dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst) 29933fb211dSSimon Glass #else 3007dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, 3017dba0b93SSimon Glass void *dst) 30233fb211dSSimon Glass #endif 303272cc70bSAndy Fleming { 304c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK) 30533fb211dSSimon Glass struct blk_desc *block_dev = dev_get_uclass_platdata(dev); 30633fb211dSSimon Glass #endif 307bcce53d0SSimon Glass int dev_num = block_dev->devnum; 308873cc1d7SStephen Warren int err; 3094a1a06bcSAlagu Sankar lbaint_t cur, blocks_todo = blkcnt; 310272cc70bSAndy Fleming 3114a1a06bcSAlagu Sankar if (blkcnt == 0) 3124a1a06bcSAlagu Sankar return 0; 3134a1a06bcSAlagu Sankar 3144a1a06bcSAlagu Sankar struct mmc *mmc = find_mmc_device(dev_num); 315272cc70bSAndy Fleming if (!mmc) 316272cc70bSAndy Fleming return 0; 317272cc70bSAndy Fleming 318b5b838f1SMarek Vasut if (CONFIG_IS_ENABLED(MMC_TINY)) 319b5b838f1SMarek Vasut err = mmc_switch_part(mmc, block_dev->hwpart); 320b5b838f1SMarek Vasut else 32169f45cd5SSimon Glass err = blk_dselect_hwpart(block_dev, block_dev->hwpart); 322b5b838f1SMarek Vasut 323873cc1d7SStephen Warren if (err < 0) 324873cc1d7SStephen Warren return 0; 325873cc1d7SStephen Warren 326c40fdca6SSimon Glass if ((start + blkcnt) > block_dev->lba) { 32756196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 328ff8fef56SSascha Silbe printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", 329c40fdca6SSimon Glass start + blkcnt, block_dev->lba); 33056196826SPaul Burton #endif 331d2bf29e3SLei Wen return 0; 332d2bf29e3SLei Wen } 333272cc70bSAndy Fleming 33411692991SSimon Glass if (mmc_set_blocklen(mmc, mmc->read_bl_len)) { 33511692991SSimon Glass debug("%s: Failed to set blocklen\n", __func__); 336272cc70bSAndy Fleming return 0; 33711692991SSimon Glass } 338272cc70bSAndy Fleming 3394a1a06bcSAlagu Sankar do { 34093bfd616SPantelis Antoniou cur = (blocks_todo > mmc->cfg->b_max) ? 34193bfd616SPantelis Antoniou mmc->cfg->b_max : blocks_todo; 34211692991SSimon Glass if (mmc_read_blocks(mmc, dst, start, cur) != cur) { 34311692991SSimon Glass debug("%s: Failed to read blocks\n", __func__); 3444a1a06bcSAlagu Sankar return 0; 34511692991SSimon Glass } 3464a1a06bcSAlagu Sankar blocks_todo -= cur; 3474a1a06bcSAlagu Sankar start += cur; 3484a1a06bcSAlagu Sankar dst += cur * mmc->read_bl_len; 3494a1a06bcSAlagu Sankar } while (blocks_todo > 0); 350272cc70bSAndy Fleming 351272cc70bSAndy Fleming return blkcnt; 352272cc70bSAndy Fleming } 353272cc70bSAndy Fleming 354fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc) 355272cc70bSAndy Fleming { 356272cc70bSAndy Fleming struct mmc_cmd cmd; 357272cc70bSAndy Fleming int err; 358272cc70bSAndy Fleming 359272cc70bSAndy Fleming udelay(1000); 360272cc70bSAndy Fleming 361272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_GO_IDLE_STATE; 362272cc70bSAndy Fleming cmd.cmdarg = 0; 363272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_NONE; 364272cc70bSAndy Fleming 365272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 366272cc70bSAndy Fleming 367272cc70bSAndy Fleming if (err) 368272cc70bSAndy Fleming return err; 369272cc70bSAndy Fleming 370272cc70bSAndy Fleming udelay(2000); 371272cc70bSAndy Fleming 372272cc70bSAndy Fleming return 0; 373272cc70bSAndy Fleming } 374272cc70bSAndy Fleming 375fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc) 376272cc70bSAndy Fleming { 377272cc70bSAndy Fleming int timeout = 1000; 378272cc70bSAndy Fleming int err; 379272cc70bSAndy Fleming struct mmc_cmd cmd; 380272cc70bSAndy Fleming 3811677eef4SAndrew Gabbasov while (1) { 382272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 383272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 384272cc70bSAndy Fleming cmd.cmdarg = 0; 385272cc70bSAndy Fleming 386272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 387272cc70bSAndy Fleming 388272cc70bSAndy Fleming if (err) 389272cc70bSAndy Fleming return err; 390272cc70bSAndy Fleming 391272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_OP_COND; 392272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R3; 393250de12bSStefano Babic 394250de12bSStefano Babic /* 395250de12bSStefano Babic * Most cards do not answer if some reserved bits 396250de12bSStefano Babic * in the ocr are set. However, Some controller 397250de12bSStefano Babic * can set bit 7 (reserved for low voltages), but 398250de12bSStefano Babic * how to manage low voltages SD card is not yet 399250de12bSStefano Babic * specified. 400250de12bSStefano Babic */ 401d52ebf10SThomas Chou cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 : 40293bfd616SPantelis Antoniou (mmc->cfg->voltages & 0xff8000); 403272cc70bSAndy Fleming 404272cc70bSAndy Fleming if (mmc->version == SD_VERSION_2) 405272cc70bSAndy Fleming cmd.cmdarg |= OCR_HCS; 406272cc70bSAndy Fleming 407272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 408272cc70bSAndy Fleming 409272cc70bSAndy Fleming if (err) 410272cc70bSAndy Fleming return err; 411272cc70bSAndy Fleming 4121677eef4SAndrew Gabbasov if (cmd.response[0] & OCR_BUSY) 4131677eef4SAndrew Gabbasov break; 414272cc70bSAndy Fleming 4151677eef4SAndrew Gabbasov if (timeout-- <= 0) 416915ffa52SJaehoon Chung return -EOPNOTSUPP; 417272cc70bSAndy Fleming 4181677eef4SAndrew Gabbasov udelay(1000); 4191677eef4SAndrew Gabbasov } 4201677eef4SAndrew Gabbasov 421272cc70bSAndy Fleming if (mmc->version != SD_VERSION_2) 422272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 423272cc70bSAndy Fleming 424d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 425d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 426d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 427d52ebf10SThomas Chou cmd.cmdarg = 0; 428d52ebf10SThomas Chou 429d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 430d52ebf10SThomas Chou 431d52ebf10SThomas Chou if (err) 432d52ebf10SThomas Chou return err; 433d52ebf10SThomas Chou } 434d52ebf10SThomas Chou 435998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 436272cc70bSAndy Fleming 437272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 438272cc70bSAndy Fleming mmc->rca = 0; 439272cc70bSAndy Fleming 440272cc70bSAndy Fleming return 0; 441272cc70bSAndy Fleming } 442272cc70bSAndy Fleming 4435289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg) 444272cc70bSAndy Fleming { 4455289b535SAndrew Gabbasov struct mmc_cmd cmd; 446272cc70bSAndy Fleming int err; 447272cc70bSAndy Fleming 4485289b535SAndrew Gabbasov cmd.cmdidx = MMC_CMD_SEND_OP_COND; 4495289b535SAndrew Gabbasov cmd.resp_type = MMC_RSP_R3; 4505289b535SAndrew Gabbasov cmd.cmdarg = 0; 4515a20397bSRob Herring if (use_arg && !mmc_host_is_spi(mmc)) 4525a20397bSRob Herring cmd.cmdarg = OCR_HCS | 45393bfd616SPantelis Antoniou (mmc->cfg->voltages & 454a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_VOLTAGE_MASK)) | 455a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_ACCESS_MODE); 456e9550449SChe-Liang Chiou 4575289b535SAndrew Gabbasov err = mmc_send_cmd(mmc, &cmd, NULL); 458e9550449SChe-Liang Chiou if (err) 459e9550449SChe-Liang Chiou return err; 4605289b535SAndrew Gabbasov mmc->ocr = cmd.response[0]; 461e9550449SChe-Liang Chiou return 0; 462e9550449SChe-Liang Chiou } 463e9550449SChe-Liang Chiou 464750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc) 465e9550449SChe-Liang Chiou { 466e9550449SChe-Liang Chiou int err, i; 467e9550449SChe-Liang Chiou 468272cc70bSAndy Fleming /* Some cards seem to need this */ 469272cc70bSAndy Fleming mmc_go_idle(mmc); 470272cc70bSAndy Fleming 47131cacbabSRaffaele Recalcati /* Asking to the card its capabilities */ 472e9550449SChe-Liang Chiou for (i = 0; i < 2; i++) { 4735289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, i != 0); 47431cacbabSRaffaele Recalcati if (err) 47531cacbabSRaffaele Recalcati return err; 47631cacbabSRaffaele Recalcati 477e9550449SChe-Liang Chiou /* exit if not busy (flag seems to be inverted) */ 478a626c8d4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 479bd47c135SAndrew Gabbasov break; 480e9550449SChe-Liang Chiou } 481bd47c135SAndrew Gabbasov mmc->op_cond_pending = 1; 482bd47c135SAndrew Gabbasov return 0; 483e9550449SChe-Liang Chiou } 48431cacbabSRaffaele Recalcati 485750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc) 486e9550449SChe-Liang Chiou { 487e9550449SChe-Liang Chiou struct mmc_cmd cmd; 488e9550449SChe-Liang Chiou int timeout = 1000; 489e9550449SChe-Liang Chiou uint start; 490e9550449SChe-Liang Chiou int err; 491e9550449SChe-Liang Chiou 492e9550449SChe-Liang Chiou mmc->op_cond_pending = 0; 493cc17c01fSAndrew Gabbasov if (!(mmc->ocr & OCR_BUSY)) { 494d188b113SYangbo Lu /* Some cards seem to need this */ 495d188b113SYangbo Lu mmc_go_idle(mmc); 496d188b113SYangbo Lu 497e9550449SChe-Liang Chiou start = get_timer(0); 4981677eef4SAndrew Gabbasov while (1) { 4995289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, 1); 500272cc70bSAndy Fleming if (err) 501272cc70bSAndy Fleming return err; 5021677eef4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 5031677eef4SAndrew Gabbasov break; 504e9550449SChe-Liang Chiou if (get_timer(start) > timeout) 505915ffa52SJaehoon Chung return -EOPNOTSUPP; 506e9550449SChe-Liang Chiou udelay(100); 5071677eef4SAndrew Gabbasov } 508cc17c01fSAndrew Gabbasov } 509272cc70bSAndy Fleming 510d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 511d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 512d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 513d52ebf10SThomas Chou cmd.cmdarg = 0; 514d52ebf10SThomas Chou 515d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 516d52ebf10SThomas Chou 517d52ebf10SThomas Chou if (err) 518d52ebf10SThomas Chou return err; 519a626c8d4SAndrew Gabbasov 520a626c8d4SAndrew Gabbasov mmc->ocr = cmd.response[0]; 521d52ebf10SThomas Chou } 522d52ebf10SThomas Chou 523272cc70bSAndy Fleming mmc->version = MMC_VERSION_UNKNOWN; 524272cc70bSAndy Fleming 525272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 526def816a2SStephen Warren mmc->rca = 1; 527272cc70bSAndy Fleming 528272cc70bSAndy Fleming return 0; 529272cc70bSAndy Fleming } 530272cc70bSAndy Fleming 531272cc70bSAndy Fleming 532fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) 533272cc70bSAndy Fleming { 534272cc70bSAndy Fleming struct mmc_cmd cmd; 535272cc70bSAndy Fleming struct mmc_data data; 536272cc70bSAndy Fleming int err; 537272cc70bSAndy Fleming 538272cc70bSAndy Fleming /* Get the Card Status Register */ 539272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_EXT_CSD; 540272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 541272cc70bSAndy Fleming cmd.cmdarg = 0; 542272cc70bSAndy Fleming 543cdfd1ac6SYoshihiro Shimoda data.dest = (char *)ext_csd; 544272cc70bSAndy Fleming data.blocks = 1; 5458bfa195eSSimon Glass data.blocksize = MMC_MAX_BLOCK_LEN; 546272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 547272cc70bSAndy Fleming 548272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 549272cc70bSAndy Fleming 550272cc70bSAndy Fleming return err; 551272cc70bSAndy Fleming } 552272cc70bSAndy Fleming 553c40704f4SSimon Glass int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) 554272cc70bSAndy Fleming { 555272cc70bSAndy Fleming struct mmc_cmd cmd; 5565d4fc8d9SRaffaele Recalcati int timeout = 1000; 557a9003dc6SMaxime Ripard int retries = 3; 5585d4fc8d9SRaffaele Recalcati int ret; 559272cc70bSAndy Fleming 560272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SWITCH; 561272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 562272cc70bSAndy Fleming cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 563272cc70bSAndy Fleming (index << 16) | 564272cc70bSAndy Fleming (value << 8); 565272cc70bSAndy Fleming 566a9003dc6SMaxime Ripard while (retries > 0) { 5675d4fc8d9SRaffaele Recalcati ret = mmc_send_cmd(mmc, &cmd, NULL); 5685d4fc8d9SRaffaele Recalcati 5695d4fc8d9SRaffaele Recalcati /* Waiting for the ready status */ 570a9003dc6SMaxime Ripard if (!ret) { 57193ad0d18SJan Kloetzke ret = mmc_send_status(mmc, timeout); 572a9003dc6SMaxime Ripard return ret; 573a9003dc6SMaxime Ripard } 574a9003dc6SMaxime Ripard 575a9003dc6SMaxime Ripard retries--; 576a9003dc6SMaxime Ripard } 5775d4fc8d9SRaffaele Recalcati 5785d4fc8d9SRaffaele Recalcati return ret; 5795d4fc8d9SRaffaele Recalcati 580272cc70bSAndy Fleming } 581272cc70bSAndy Fleming 582fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc) 583272cc70bSAndy Fleming { 5848bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 585272cc70bSAndy Fleming char cardtype; 586272cc70bSAndy Fleming int err; 587272cc70bSAndy Fleming 588fc5b32fbSAndrew Gabbasov mmc->card_caps = 0; 589272cc70bSAndy Fleming 590d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 591d52ebf10SThomas Chou return 0; 592d52ebf10SThomas Chou 593272cc70bSAndy Fleming /* Only version 4 supports high-speed */ 594272cc70bSAndy Fleming if (mmc->version < MMC_VERSION_4) 595272cc70bSAndy Fleming return 0; 596272cc70bSAndy Fleming 597fc5b32fbSAndrew Gabbasov mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; 598fc5b32fbSAndrew Gabbasov 599272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 600272cc70bSAndy Fleming 601272cc70bSAndy Fleming if (err) 602272cc70bSAndy Fleming return err; 603272cc70bSAndy Fleming 6040560db18SLei Wen cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf; 605272cc70bSAndy Fleming 606272cc70bSAndy Fleming err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1); 607272cc70bSAndy Fleming 608272cc70bSAndy Fleming if (err) 609a5e27b41SHeiko Schocher return err; 610272cc70bSAndy Fleming 611272cc70bSAndy Fleming /* Now check to see that it worked */ 612272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 613272cc70bSAndy Fleming 614272cc70bSAndy Fleming if (err) 615272cc70bSAndy Fleming return err; 616272cc70bSAndy Fleming 617272cc70bSAndy Fleming /* No high-speed support */ 6180560db18SLei Wen if (!ext_csd[EXT_CSD_HS_TIMING]) 619272cc70bSAndy Fleming return 0; 620272cc70bSAndy Fleming 621272cc70bSAndy Fleming /* High Speed is set, there are two types: 52MHz and 26MHz */ 622d22e3d46SJaehoon Chung if (cardtype & EXT_CSD_CARD_TYPE_52) { 623201d5ac4SAndrew Gabbasov if (cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V) 624d22e3d46SJaehoon Chung mmc->card_caps |= MMC_MODE_DDR_52MHz; 625272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; 626d22e3d46SJaehoon Chung } else { 627272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS; 628d22e3d46SJaehoon Chung } 629272cc70bSAndy Fleming 630272cc70bSAndy Fleming return 0; 631272cc70bSAndy Fleming } 632272cc70bSAndy Fleming 633f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num) 634f866a46dSStephen Warren { 635f866a46dSStephen Warren switch (part_num) { 636f866a46dSStephen Warren case 0: 637f866a46dSStephen Warren mmc->capacity = mmc->capacity_user; 638f866a46dSStephen Warren break; 639f866a46dSStephen Warren case 1: 640f866a46dSStephen Warren case 2: 641f866a46dSStephen Warren mmc->capacity = mmc->capacity_boot; 642f866a46dSStephen Warren break; 643f866a46dSStephen Warren case 3: 644f866a46dSStephen Warren mmc->capacity = mmc->capacity_rpmb; 645f866a46dSStephen Warren break; 646f866a46dSStephen Warren case 4: 647f866a46dSStephen Warren case 5: 648f866a46dSStephen Warren case 6: 649f866a46dSStephen Warren case 7: 650f866a46dSStephen Warren mmc->capacity = mmc->capacity_gp[part_num - 4]; 651f866a46dSStephen Warren break; 652f866a46dSStephen Warren default: 653f866a46dSStephen Warren return -1; 654f866a46dSStephen Warren } 655f866a46dSStephen Warren 656c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len); 657f866a46dSStephen Warren 658f866a46dSStephen Warren return 0; 659f866a46dSStephen Warren } 660f866a46dSStephen Warren 6617dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num) 662bc897b1dSLei Wen { 663f866a46dSStephen Warren int ret; 664bc897b1dSLei Wen 665f866a46dSStephen Warren ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 666bc897b1dSLei Wen (mmc->part_config & ~PART_ACCESS_MASK) 667bc897b1dSLei Wen | (part_num & PART_ACCESS_MASK)); 668f866a46dSStephen Warren 6696dc93e70SPeter Bigot /* 6706dc93e70SPeter Bigot * Set the capacity if the switch succeeded or was intended 6716dc93e70SPeter Bigot * to return to representing the raw device. 6726dc93e70SPeter Bigot */ 673873cc1d7SStephen Warren if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) { 6746dc93e70SPeter Bigot ret = mmc_set_capacity(mmc, part_num); 675fdbb139fSSimon Glass mmc_get_blk_desc(mmc)->hwpart = part_num; 676873cc1d7SStephen Warren } 6776dc93e70SPeter Bigot 6786dc93e70SPeter Bigot return ret; 679bc897b1dSLei Wen } 680bc897b1dSLei Wen 681ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc, 682ac9da0e0SDiego Santa Cruz const struct mmc_hwpart_conf *conf, 683ac9da0e0SDiego Santa Cruz enum mmc_hwpart_conf_mode mode) 684ac9da0e0SDiego Santa Cruz { 685ac9da0e0SDiego Santa Cruz u8 part_attrs = 0; 686ac9da0e0SDiego Santa Cruz u32 enh_size_mult; 687ac9da0e0SDiego Santa Cruz u32 enh_start_addr; 688ac9da0e0SDiego Santa Cruz u32 gp_size_mult[4]; 689ac9da0e0SDiego Santa Cruz u32 max_enh_size_mult; 690ac9da0e0SDiego Santa Cruz u32 tot_enh_size_mult = 0; 6918dda5b0eSDiego Santa Cruz u8 wr_rel_set; 692ac9da0e0SDiego Santa Cruz int i, pidx, err; 693ac9da0e0SDiego Santa Cruz ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 694ac9da0e0SDiego Santa Cruz 695ac9da0e0SDiego Santa Cruz if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE) 696ac9da0e0SDiego Santa Cruz return -EINVAL; 697ac9da0e0SDiego Santa Cruz 698ac9da0e0SDiego Santa Cruz if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) { 699ac9da0e0SDiego Santa Cruz printf("eMMC >= 4.4 required for enhanced user data area\n"); 700ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 701ac9da0e0SDiego Santa Cruz } 702ac9da0e0SDiego Santa Cruz 703ac9da0e0SDiego Santa Cruz if (!(mmc->part_support & PART_SUPPORT)) { 704ac9da0e0SDiego Santa Cruz printf("Card does not support partitioning\n"); 705ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 706ac9da0e0SDiego Santa Cruz } 707ac9da0e0SDiego Santa Cruz 708ac9da0e0SDiego Santa Cruz if (!mmc->hc_wp_grp_size) { 709ac9da0e0SDiego Santa Cruz printf("Card does not define HC WP group size\n"); 710ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 711ac9da0e0SDiego Santa Cruz } 712ac9da0e0SDiego Santa Cruz 713ac9da0e0SDiego Santa Cruz /* check partition alignment and total enhanced size */ 714ac9da0e0SDiego Santa Cruz if (conf->user.enh_size) { 715ac9da0e0SDiego Santa Cruz if (conf->user.enh_size % mmc->hc_wp_grp_size || 716ac9da0e0SDiego Santa Cruz conf->user.enh_start % mmc->hc_wp_grp_size) { 717ac9da0e0SDiego Santa Cruz printf("User data enhanced area not HC WP group " 718ac9da0e0SDiego Santa Cruz "size aligned\n"); 719ac9da0e0SDiego Santa Cruz return -EINVAL; 720ac9da0e0SDiego Santa Cruz } 721ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_USR; 722ac9da0e0SDiego Santa Cruz enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size; 723ac9da0e0SDiego Santa Cruz if (mmc->high_capacity) { 724ac9da0e0SDiego Santa Cruz enh_start_addr = conf->user.enh_start; 725ac9da0e0SDiego Santa Cruz } else { 726ac9da0e0SDiego Santa Cruz enh_start_addr = (conf->user.enh_start << 9); 727ac9da0e0SDiego Santa Cruz } 728ac9da0e0SDiego Santa Cruz } else { 729ac9da0e0SDiego Santa Cruz enh_size_mult = 0; 730ac9da0e0SDiego Santa Cruz enh_start_addr = 0; 731ac9da0e0SDiego Santa Cruz } 732ac9da0e0SDiego Santa Cruz tot_enh_size_mult += enh_size_mult; 733ac9da0e0SDiego Santa Cruz 734ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 735ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) { 736ac9da0e0SDiego Santa Cruz printf("GP%i partition not HC WP group size " 737ac9da0e0SDiego Santa Cruz "aligned\n", pidx+1); 738ac9da0e0SDiego Santa Cruz return -EINVAL; 739ac9da0e0SDiego Santa Cruz } 740ac9da0e0SDiego Santa Cruz gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size; 741ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) { 742ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_GP(pidx); 743ac9da0e0SDiego Santa Cruz tot_enh_size_mult += gp_size_mult[pidx]; 744ac9da0e0SDiego Santa Cruz } 745ac9da0e0SDiego Santa Cruz } 746ac9da0e0SDiego Santa Cruz 747ac9da0e0SDiego Santa Cruz if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) { 748ac9da0e0SDiego Santa Cruz printf("Card does not support enhanced attribute\n"); 749ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 750ac9da0e0SDiego Santa Cruz } 751ac9da0e0SDiego Santa Cruz 752ac9da0e0SDiego Santa Cruz err = mmc_send_ext_csd(mmc, ext_csd); 753ac9da0e0SDiego Santa Cruz if (err) 754ac9da0e0SDiego Santa Cruz return err; 755ac9da0e0SDiego Santa Cruz 756ac9da0e0SDiego Santa Cruz max_enh_size_mult = 757ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) + 758ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) + 759ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]; 760ac9da0e0SDiego Santa Cruz if (tot_enh_size_mult > max_enh_size_mult) { 761ac9da0e0SDiego Santa Cruz printf("Total enhanced size exceeds maximum (%u > %u)\n", 762ac9da0e0SDiego Santa Cruz tot_enh_size_mult, max_enh_size_mult); 763ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 764ac9da0e0SDiego Santa Cruz } 765ac9da0e0SDiego Santa Cruz 7668dda5b0eSDiego Santa Cruz /* The default value of EXT_CSD_WR_REL_SET is device 7678dda5b0eSDiego Santa Cruz * dependent, the values can only be changed if the 7688dda5b0eSDiego Santa Cruz * EXT_CSD_HS_CTRL_REL bit is set. The values can be 7698dda5b0eSDiego Santa Cruz * changed only once and before partitioning is completed. */ 7708dda5b0eSDiego Santa Cruz wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 7718dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_change) { 7728dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_set) 7738dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_USR; 7748dda5b0eSDiego Santa Cruz else 7758dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR; 7768dda5b0eSDiego Santa Cruz } 7778dda5b0eSDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 7788dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_change) { 7798dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_set) 7808dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx); 7818dda5b0eSDiego Santa Cruz else 7828dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx); 7838dda5b0eSDiego Santa Cruz } 7848dda5b0eSDiego Santa Cruz } 7858dda5b0eSDiego Santa Cruz 7868dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] && 7878dda5b0eSDiego Santa Cruz !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) { 7888dda5b0eSDiego Santa Cruz puts("Card does not support host controlled partition write " 7898dda5b0eSDiego Santa Cruz "reliability settings\n"); 7908dda5b0eSDiego Santa Cruz return -EMEDIUMTYPE; 7918dda5b0eSDiego Santa Cruz } 7928dda5b0eSDiego Santa Cruz 793ac9da0e0SDiego Santa Cruz if (ext_csd[EXT_CSD_PARTITION_SETTING] & 794ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED) { 795ac9da0e0SDiego Santa Cruz printf("Card already partitioned\n"); 796ac9da0e0SDiego Santa Cruz return -EPERM; 797ac9da0e0SDiego Santa Cruz } 798ac9da0e0SDiego Santa Cruz 799ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_CHECK) 800ac9da0e0SDiego Santa Cruz return 0; 801ac9da0e0SDiego Santa Cruz 802ac9da0e0SDiego Santa Cruz /* Partitioning requires high-capacity size definitions */ 803ac9da0e0SDiego Santa Cruz if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) { 804ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 805ac9da0e0SDiego Santa Cruz EXT_CSD_ERASE_GROUP_DEF, 1); 806ac9da0e0SDiego Santa Cruz 807ac9da0e0SDiego Santa Cruz if (err) 808ac9da0e0SDiego Santa Cruz return err; 809ac9da0e0SDiego Santa Cruz 810ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 811ac9da0e0SDiego Santa Cruz 812ac9da0e0SDiego Santa Cruz /* update erase group size to be high-capacity */ 813ac9da0e0SDiego Santa Cruz mmc->erase_grp_size = 814ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 815ac9da0e0SDiego Santa Cruz 816ac9da0e0SDiego Santa Cruz } 817ac9da0e0SDiego Santa Cruz 818ac9da0e0SDiego Santa Cruz /* all OK, write the configuration */ 819ac9da0e0SDiego Santa Cruz for (i = 0; i < 4; i++) { 820ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 821ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_START_ADDR+i, 822ac9da0e0SDiego Santa Cruz (enh_start_addr >> (i*8)) & 0xFF); 823ac9da0e0SDiego Santa Cruz if (err) 824ac9da0e0SDiego Santa Cruz return err; 825ac9da0e0SDiego Santa Cruz } 826ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 827ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 828ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_SIZE_MULT+i, 829ac9da0e0SDiego Santa Cruz (enh_size_mult >> (i*8)) & 0xFF); 830ac9da0e0SDiego Santa Cruz if (err) 831ac9da0e0SDiego Santa Cruz return err; 832ac9da0e0SDiego Santa Cruz } 833ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 834ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 835ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 836ac9da0e0SDiego Santa Cruz EXT_CSD_GP_SIZE_MULT+pidx*3+i, 837ac9da0e0SDiego Santa Cruz (gp_size_mult[pidx] >> (i*8)) & 0xFF); 838ac9da0e0SDiego Santa Cruz if (err) 839ac9da0e0SDiego Santa Cruz return err; 840ac9da0e0SDiego Santa Cruz } 841ac9da0e0SDiego Santa Cruz } 842ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 843ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs); 844ac9da0e0SDiego Santa Cruz if (err) 845ac9da0e0SDiego Santa Cruz return err; 846ac9da0e0SDiego Santa Cruz 847ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_SET) 848ac9da0e0SDiego Santa Cruz return 0; 849ac9da0e0SDiego Santa Cruz 8508dda5b0eSDiego Santa Cruz /* The WR_REL_SET is a write-once register but shall be 8518dda5b0eSDiego Santa Cruz * written before setting PART_SETTING_COMPLETED. As it is 8528dda5b0eSDiego Santa Cruz * write-once we can only write it when completing the 8538dda5b0eSDiego Santa Cruz * partitioning. */ 8548dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) { 8558dda5b0eSDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 8568dda5b0eSDiego Santa Cruz EXT_CSD_WR_REL_SET, wr_rel_set); 8578dda5b0eSDiego Santa Cruz if (err) 8588dda5b0eSDiego Santa Cruz return err; 8598dda5b0eSDiego Santa Cruz } 8608dda5b0eSDiego Santa Cruz 861ac9da0e0SDiego Santa Cruz /* Setting PART_SETTING_COMPLETED confirms the partition 862ac9da0e0SDiego Santa Cruz * configuration but it only becomes effective after power 863ac9da0e0SDiego Santa Cruz * cycle, so we do not adjust the partition related settings 864ac9da0e0SDiego Santa Cruz * in the mmc struct. */ 865ac9da0e0SDiego Santa Cruz 866ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 867ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING, 868ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 869ac9da0e0SDiego Santa Cruz if (err) 870ac9da0e0SDiego Santa Cruz return err; 871ac9da0e0SDiego Santa Cruz 872ac9da0e0SDiego Santa Cruz return 0; 873ac9da0e0SDiego Santa Cruz } 874ac9da0e0SDiego Santa Cruz 875e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 87648972d90SThierry Reding int mmc_getcd(struct mmc *mmc) 87748972d90SThierry Reding { 87848972d90SThierry Reding int cd; 87948972d90SThierry Reding 88048972d90SThierry Reding cd = board_mmc_getcd(mmc); 88148972d90SThierry Reding 882d4e1da4eSPeter Korsgaard if (cd < 0) { 88393bfd616SPantelis Antoniou if (mmc->cfg->ops->getcd) 88493bfd616SPantelis Antoniou cd = mmc->cfg->ops->getcd(mmc); 885d4e1da4eSPeter Korsgaard else 886d4e1da4eSPeter Korsgaard cd = 1; 887d4e1da4eSPeter Korsgaard } 88848972d90SThierry Reding 88948972d90SThierry Reding return cd; 89048972d90SThierry Reding } 8918ca51e51SSimon Glass #endif 89248972d90SThierry Reding 893fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) 894272cc70bSAndy Fleming { 895272cc70bSAndy Fleming struct mmc_cmd cmd; 896272cc70bSAndy Fleming struct mmc_data data; 897272cc70bSAndy Fleming 898272cc70bSAndy Fleming /* Switch the frequency */ 899272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC; 900272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 901272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff; 902272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4)); 903272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4); 904272cc70bSAndy Fleming 905272cc70bSAndy Fleming data.dest = (char *)resp; 906272cc70bSAndy Fleming data.blocksize = 64; 907272cc70bSAndy Fleming data.blocks = 1; 908272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 909272cc70bSAndy Fleming 910272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 911272cc70bSAndy Fleming } 912272cc70bSAndy Fleming 913272cc70bSAndy Fleming 914fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc) 915272cc70bSAndy Fleming { 916272cc70bSAndy Fleming int err; 917272cc70bSAndy Fleming struct mmc_cmd cmd; 91818e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2); 91918e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16); 920272cc70bSAndy Fleming struct mmc_data data; 921272cc70bSAndy Fleming int timeout; 922272cc70bSAndy Fleming 923272cc70bSAndy Fleming mmc->card_caps = 0; 924272cc70bSAndy Fleming 925d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 926d52ebf10SThomas Chou return 0; 927d52ebf10SThomas Chou 928272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */ 929272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 930272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 931272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 932272cc70bSAndy Fleming 933272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 934272cc70bSAndy Fleming 935272cc70bSAndy Fleming if (err) 936272cc70bSAndy Fleming return err; 937272cc70bSAndy Fleming 938272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR; 939272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 940272cc70bSAndy Fleming cmd.cmdarg = 0; 941272cc70bSAndy Fleming 942272cc70bSAndy Fleming timeout = 3; 943272cc70bSAndy Fleming 944272cc70bSAndy Fleming retry_scr: 945f781dd38SAnton staaf data.dest = (char *)scr; 946272cc70bSAndy Fleming data.blocksize = 8; 947272cc70bSAndy Fleming data.blocks = 1; 948272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 949272cc70bSAndy Fleming 950272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 951272cc70bSAndy Fleming 952272cc70bSAndy Fleming if (err) { 953272cc70bSAndy Fleming if (timeout--) 954272cc70bSAndy Fleming goto retry_scr; 955272cc70bSAndy Fleming 956272cc70bSAndy Fleming return err; 957272cc70bSAndy Fleming } 958272cc70bSAndy Fleming 9594e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]); 9604e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]); 961272cc70bSAndy Fleming 962272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) { 963272cc70bSAndy Fleming case 0: 964272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 965272cc70bSAndy Fleming break; 966272cc70bSAndy Fleming case 1: 967272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10; 968272cc70bSAndy Fleming break; 969272cc70bSAndy Fleming case 2: 970272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 9711741c64dSJaehoon Chung if ((mmc->scr[0] >> 15) & 0x1) 9721741c64dSJaehoon Chung mmc->version = SD_VERSION_3; 973272cc70bSAndy Fleming break; 974272cc70bSAndy Fleming default: 975272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 976272cc70bSAndy Fleming break; 977272cc70bSAndy Fleming } 978272cc70bSAndy Fleming 979b44c7083SAlagu Sankar if (mmc->scr[0] & SD_DATA_4BIT) 980b44c7083SAlagu Sankar mmc->card_caps |= MMC_MODE_4BIT; 981b44c7083SAlagu Sankar 982272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */ 983272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0) 984272cc70bSAndy Fleming return 0; 985272cc70bSAndy Fleming 986272cc70bSAndy Fleming timeout = 4; 987272cc70bSAndy Fleming while (timeout--) { 988272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, 989f781dd38SAnton staaf (u8 *)switch_status); 990272cc70bSAndy Fleming 991272cc70bSAndy Fleming if (err) 992272cc70bSAndy Fleming return err; 993272cc70bSAndy Fleming 994272cc70bSAndy Fleming /* The high-speed function is busy. Try again */ 9954e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) 996272cc70bSAndy Fleming break; 997272cc70bSAndy Fleming } 998272cc70bSAndy Fleming 999272cc70bSAndy Fleming /* If high-speed isn't supported, we return */ 10004e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)) 1001272cc70bSAndy Fleming return 0; 1002272cc70bSAndy Fleming 10032c3fbf4cSMacpaul Lin /* 10042c3fbf4cSMacpaul Lin * If the host doesn't support SD_HIGHSPEED, do not switch card to 10052c3fbf4cSMacpaul Lin * HIGHSPEED mode even if the card support SD_HIGHSPPED. 10062c3fbf4cSMacpaul Lin * This can avoid furthur problem when the card runs in different 10072c3fbf4cSMacpaul Lin * mode between the host. 10082c3fbf4cSMacpaul Lin */ 100993bfd616SPantelis Antoniou if (!((mmc->cfg->host_caps & MMC_MODE_HS_52MHz) && 101093bfd616SPantelis Antoniou (mmc->cfg->host_caps & MMC_MODE_HS))) 10112c3fbf4cSMacpaul Lin return 0; 10122c3fbf4cSMacpaul Lin 1013f781dd38SAnton staaf err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status); 1014272cc70bSAndy Fleming 1015272cc70bSAndy Fleming if (err) 1016272cc70bSAndy Fleming return err; 1017272cc70bSAndy Fleming 10184e3d89baSYauhen Kharuzhy if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000) 1019272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS; 1020272cc70bSAndy Fleming 1021272cc70bSAndy Fleming return 0; 1022272cc70bSAndy Fleming } 1023272cc70bSAndy Fleming 10243697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc) 10253697e599SPeng Fan { 10263697e599SPeng Fan int err, i; 10273697e599SPeng Fan struct mmc_cmd cmd; 10283697e599SPeng Fan ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16); 10293697e599SPeng Fan struct mmc_data data; 10303697e599SPeng Fan int timeout = 3; 10313697e599SPeng Fan unsigned int au, eo, et, es; 10323697e599SPeng Fan 10333697e599SPeng Fan cmd.cmdidx = MMC_CMD_APP_CMD; 10343697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 10353697e599SPeng Fan cmd.cmdarg = mmc->rca << 16; 10363697e599SPeng Fan 10373697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, NULL); 10383697e599SPeng Fan if (err) 10393697e599SPeng Fan return err; 10403697e599SPeng Fan 10413697e599SPeng Fan cmd.cmdidx = SD_CMD_APP_SD_STATUS; 10423697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 10433697e599SPeng Fan cmd.cmdarg = 0; 10443697e599SPeng Fan 10453697e599SPeng Fan retry_ssr: 10463697e599SPeng Fan data.dest = (char *)ssr; 10473697e599SPeng Fan data.blocksize = 64; 10483697e599SPeng Fan data.blocks = 1; 10493697e599SPeng Fan data.flags = MMC_DATA_READ; 10503697e599SPeng Fan 10513697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, &data); 10523697e599SPeng Fan if (err) { 10533697e599SPeng Fan if (timeout--) 10543697e599SPeng Fan goto retry_ssr; 10553697e599SPeng Fan 10563697e599SPeng Fan return err; 10573697e599SPeng Fan } 10583697e599SPeng Fan 10593697e599SPeng Fan for (i = 0; i < 16; i++) 10603697e599SPeng Fan ssr[i] = be32_to_cpu(ssr[i]); 10613697e599SPeng Fan 10623697e599SPeng Fan au = (ssr[2] >> 12) & 0xF; 10633697e599SPeng Fan if ((au <= 9) || (mmc->version == SD_VERSION_3)) { 10643697e599SPeng Fan mmc->ssr.au = sd_au_size[au]; 10653697e599SPeng Fan es = (ssr[3] >> 24) & 0xFF; 10663697e599SPeng Fan es |= (ssr[2] & 0xFF) << 8; 10673697e599SPeng Fan et = (ssr[3] >> 18) & 0x3F; 10683697e599SPeng Fan if (es && et) { 10693697e599SPeng Fan eo = (ssr[3] >> 16) & 0x3; 10703697e599SPeng Fan mmc->ssr.erase_timeout = (et * 1000) / es; 10713697e599SPeng Fan mmc->ssr.erase_offset = eo * 1000; 10723697e599SPeng Fan } 10733697e599SPeng Fan } else { 10743697e599SPeng Fan debug("Invalid Allocation Unit Size.\n"); 10753697e599SPeng Fan } 10763697e599SPeng Fan 10773697e599SPeng Fan return 0; 10783697e599SPeng Fan } 10793697e599SPeng Fan 1080272cc70bSAndy Fleming /* frequency bases */ 1081272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */ 10825f837c2cSMike Frysinger static const int fbase[] = { 1083272cc70bSAndy Fleming 10000, 1084272cc70bSAndy Fleming 100000, 1085272cc70bSAndy Fleming 1000000, 1086272cc70bSAndy Fleming 10000000, 1087272cc70bSAndy Fleming }; 1088272cc70bSAndy Fleming 1089272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice 1090272cc70bSAndy Fleming * to platforms without floating point. 1091272cc70bSAndy Fleming */ 109261fe076fSSimon Glass static const u8 multipliers[] = { 1093272cc70bSAndy Fleming 0, /* reserved */ 1094272cc70bSAndy Fleming 10, 1095272cc70bSAndy Fleming 12, 1096272cc70bSAndy Fleming 13, 1097272cc70bSAndy Fleming 15, 1098272cc70bSAndy Fleming 20, 1099272cc70bSAndy Fleming 25, 1100272cc70bSAndy Fleming 30, 1101272cc70bSAndy Fleming 35, 1102272cc70bSAndy Fleming 40, 1103272cc70bSAndy Fleming 45, 1104272cc70bSAndy Fleming 50, 1105272cc70bSAndy Fleming 55, 1106272cc70bSAndy Fleming 60, 1107272cc70bSAndy Fleming 70, 1108272cc70bSAndy Fleming 80, 1109272cc70bSAndy Fleming }; 1110272cc70bSAndy Fleming 1111e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 1112fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc) 1113272cc70bSAndy Fleming { 111493bfd616SPantelis Antoniou if (mmc->cfg->ops->set_ios) 111593bfd616SPantelis Antoniou mmc->cfg->ops->set_ios(mmc); 1116272cc70bSAndy Fleming } 11178ca51e51SSimon Glass #endif 1118272cc70bSAndy Fleming 1119272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock) 1120272cc70bSAndy Fleming { 112193bfd616SPantelis Antoniou if (clock > mmc->cfg->f_max) 112293bfd616SPantelis Antoniou clock = mmc->cfg->f_max; 1123272cc70bSAndy Fleming 112493bfd616SPantelis Antoniou if (clock < mmc->cfg->f_min) 112593bfd616SPantelis Antoniou clock = mmc->cfg->f_min; 1126272cc70bSAndy Fleming 1127272cc70bSAndy Fleming mmc->clock = clock; 1128272cc70bSAndy Fleming 1129272cc70bSAndy Fleming mmc_set_ios(mmc); 1130272cc70bSAndy Fleming } 1131272cc70bSAndy Fleming 1132fdbb873eSKim Phillips static void mmc_set_bus_width(struct mmc *mmc, uint width) 1133272cc70bSAndy Fleming { 1134272cc70bSAndy Fleming mmc->bus_width = width; 1135272cc70bSAndy Fleming 1136272cc70bSAndy Fleming mmc_set_ios(mmc); 1137272cc70bSAndy Fleming } 1138272cc70bSAndy Fleming 11398ac8a263SJean-Jacques Hiblot static int sd_select_bus_freq_width(struct mmc *mmc) 11408ac8a263SJean-Jacques Hiblot { 11418ac8a263SJean-Jacques Hiblot int err; 11428ac8a263SJean-Jacques Hiblot struct mmc_cmd cmd; 11438ac8a263SJean-Jacques Hiblot 11448ac8a263SJean-Jacques Hiblot err = sd_change_freq(mmc); 11458ac8a263SJean-Jacques Hiblot if (err) 11468ac8a263SJean-Jacques Hiblot return err; 11478ac8a263SJean-Jacques Hiblot 11488ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */ 11498ac8a263SJean-Jacques Hiblot mmc->card_caps &= mmc->cfg->host_caps; 11508ac8a263SJean-Jacques Hiblot 11518ac8a263SJean-Jacques Hiblot if (mmc->card_caps & MMC_MODE_4BIT) { 11528ac8a263SJean-Jacques Hiblot cmd.cmdidx = MMC_CMD_APP_CMD; 11538ac8a263SJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 11548ac8a263SJean-Jacques Hiblot cmd.cmdarg = mmc->rca << 16; 11558ac8a263SJean-Jacques Hiblot 11568ac8a263SJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 11578ac8a263SJean-Jacques Hiblot if (err) 11588ac8a263SJean-Jacques Hiblot return err; 11598ac8a263SJean-Jacques Hiblot 11608ac8a263SJean-Jacques Hiblot cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; 11618ac8a263SJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 11628ac8a263SJean-Jacques Hiblot cmd.cmdarg = 2; 11638ac8a263SJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 11648ac8a263SJean-Jacques Hiblot if (err) 11658ac8a263SJean-Jacques Hiblot return err; 11668ac8a263SJean-Jacques Hiblot 11678ac8a263SJean-Jacques Hiblot mmc_set_bus_width(mmc, 4); 11688ac8a263SJean-Jacques Hiblot } 11698ac8a263SJean-Jacques Hiblot 11708ac8a263SJean-Jacques Hiblot err = sd_read_ssr(mmc); 11718ac8a263SJean-Jacques Hiblot if (err) 11728ac8a263SJean-Jacques Hiblot return err; 11738ac8a263SJean-Jacques Hiblot 1174*35f9e196SJean-Jacques Hiblot if (mmc->card_caps & MMC_MODE_HS) { 1175*35f9e196SJean-Jacques Hiblot mmc_select_mode(mmc, SD_HS); 11768ac8a263SJean-Jacques Hiblot mmc->tran_speed = 50000000; 1177*35f9e196SJean-Jacques Hiblot } else { 1178*35f9e196SJean-Jacques Hiblot mmc_select_mode(mmc, SD_LEGACY); 11798ac8a263SJean-Jacques Hiblot mmc->tran_speed = 25000000; 1180*35f9e196SJean-Jacques Hiblot } 11818ac8a263SJean-Jacques Hiblot 11828ac8a263SJean-Jacques Hiblot return 0; 11838ac8a263SJean-Jacques Hiblot } 11848ac8a263SJean-Jacques Hiblot 11857382e691SJean-Jacques Hiblot /* 11867382e691SJean-Jacques Hiblot * read the compare the part of ext csd that is constant. 11877382e691SJean-Jacques Hiblot * This can be used to check that the transfer is working 11887382e691SJean-Jacques Hiblot * as expected. 11897382e691SJean-Jacques Hiblot */ 11907382e691SJean-Jacques Hiblot static int mmc_read_and_compare_ext_csd(struct mmc *mmc) 11917382e691SJean-Jacques Hiblot { 11927382e691SJean-Jacques Hiblot int err; 11937382e691SJean-Jacques Hiblot const u8 *ext_csd = mmc->ext_csd; 11947382e691SJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 11957382e691SJean-Jacques Hiblot 11967382e691SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, test_csd); 11977382e691SJean-Jacques Hiblot if (err) 11987382e691SJean-Jacques Hiblot return err; 11997382e691SJean-Jacques Hiblot 12007382e691SJean-Jacques Hiblot /* Only compare read only fields */ 12017382e691SJean-Jacques Hiblot if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] 12027382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_PARTITIONING_SUPPORT] && 12037382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_WP_GRP_SIZE] 12047382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_WP_GRP_SIZE] && 12057382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_REV] 12067382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_REV] && 12077382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 12087382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] && 12097382e691SJean-Jacques Hiblot memcmp(&ext_csd[EXT_CSD_SEC_CNT], 12107382e691SJean-Jacques Hiblot &test_csd[EXT_CSD_SEC_CNT], 4) == 0) 12117382e691SJean-Jacques Hiblot return 0; 12127382e691SJean-Jacques Hiblot 12137382e691SJean-Jacques Hiblot return -EBADMSG; 12147382e691SJean-Jacques Hiblot } 12157382e691SJean-Jacques Hiblot 1216dfda9d88SJean-Jacques Hiblot static int mmc_select_bus_freq_width(struct mmc *mmc) 12178ac8a263SJean-Jacques Hiblot { 12188ac8a263SJean-Jacques Hiblot /* An array of possible bus widths in order of preference */ 12198ac8a263SJean-Jacques Hiblot static const unsigned int ext_csd_bits[] = { 12208ac8a263SJean-Jacques Hiblot EXT_CSD_DDR_BUS_WIDTH_8, 12218ac8a263SJean-Jacques Hiblot EXT_CSD_DDR_BUS_WIDTH_4, 12228ac8a263SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH_8, 12238ac8a263SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH_4, 12248ac8a263SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH_1, 12258ac8a263SJean-Jacques Hiblot }; 12268ac8a263SJean-Jacques Hiblot /* An array to map CSD bus widths to host cap bits */ 12278ac8a263SJean-Jacques Hiblot static const unsigned int ext_to_hostcaps[] = { 12288ac8a263SJean-Jacques Hiblot [EXT_CSD_DDR_BUS_WIDTH_4] = 12298ac8a263SJean-Jacques Hiblot MMC_MODE_DDR_52MHz | MMC_MODE_4BIT, 12308ac8a263SJean-Jacques Hiblot [EXT_CSD_DDR_BUS_WIDTH_8] = 12318ac8a263SJean-Jacques Hiblot MMC_MODE_DDR_52MHz | MMC_MODE_8BIT, 12328ac8a263SJean-Jacques Hiblot [EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT, 12338ac8a263SJean-Jacques Hiblot [EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT, 12348ac8a263SJean-Jacques Hiblot }; 12358ac8a263SJean-Jacques Hiblot /* An array to map chosen bus width to an integer */ 12368ac8a263SJean-Jacques Hiblot static const unsigned int widths[] = { 12378ac8a263SJean-Jacques Hiblot 8, 4, 8, 4, 1, 12388ac8a263SJean-Jacques Hiblot }; 12398ac8a263SJean-Jacques Hiblot int err; 12408ac8a263SJean-Jacques Hiblot int idx; 12418ac8a263SJean-Jacques Hiblot 12428ac8a263SJean-Jacques Hiblot err = mmc_change_freq(mmc); 12438ac8a263SJean-Jacques Hiblot if (err) 12448ac8a263SJean-Jacques Hiblot return err; 12458ac8a263SJean-Jacques Hiblot 12468ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */ 12478ac8a263SJean-Jacques Hiblot mmc->card_caps &= mmc->cfg->host_caps; 12488ac8a263SJean-Jacques Hiblot 12498ac8a263SJean-Jacques Hiblot /* Only version 4 of MMC supports wider bus widths */ 12508ac8a263SJean-Jacques Hiblot if (mmc->version < MMC_VERSION_4) 12518ac8a263SJean-Jacques Hiblot return 0; 12528ac8a263SJean-Jacques Hiblot 1253dfda9d88SJean-Jacques Hiblot if (!mmc->ext_csd) { 1254dfda9d88SJean-Jacques Hiblot debug("No ext_csd found!\n"); /* this should enver happen */ 1255dfda9d88SJean-Jacques Hiblot return -ENOTSUPP; 1256dfda9d88SJean-Jacques Hiblot } 1257dfda9d88SJean-Jacques Hiblot 12588ac8a263SJean-Jacques Hiblot for (idx = 0; idx < ARRAY_SIZE(ext_csd_bits); idx++) { 12598ac8a263SJean-Jacques Hiblot unsigned int extw = ext_csd_bits[idx]; 12608ac8a263SJean-Jacques Hiblot unsigned int caps = ext_to_hostcaps[extw]; 12618ac8a263SJean-Jacques Hiblot /* 12628ac8a263SJean-Jacques Hiblot * If the bus width is still not changed, 12638ac8a263SJean-Jacques Hiblot * don't try to set the default again. 12648ac8a263SJean-Jacques Hiblot * Otherwise, recover from switch attempts 12658ac8a263SJean-Jacques Hiblot * by switching to 1-bit bus width. 12668ac8a263SJean-Jacques Hiblot */ 12678ac8a263SJean-Jacques Hiblot if (extw == EXT_CSD_BUS_WIDTH_1 && 12688ac8a263SJean-Jacques Hiblot mmc->bus_width == 1) { 12698ac8a263SJean-Jacques Hiblot err = 0; 12708ac8a263SJean-Jacques Hiblot break; 12718ac8a263SJean-Jacques Hiblot } 12728ac8a263SJean-Jacques Hiblot 12738ac8a263SJean-Jacques Hiblot /* 12748ac8a263SJean-Jacques Hiblot * Check to make sure the card and controller support 12758ac8a263SJean-Jacques Hiblot * these capabilities 12768ac8a263SJean-Jacques Hiblot */ 12778ac8a263SJean-Jacques Hiblot if ((mmc->card_caps & caps) != caps) 12788ac8a263SJean-Jacques Hiblot continue; 12798ac8a263SJean-Jacques Hiblot 12808ac8a263SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 12818ac8a263SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, extw); 12828ac8a263SJean-Jacques Hiblot 12838ac8a263SJean-Jacques Hiblot if (err) 12848ac8a263SJean-Jacques Hiblot continue; 12858ac8a263SJean-Jacques Hiblot 12868ac8a263SJean-Jacques Hiblot mmc->ddr_mode = (caps & MMC_MODE_DDR_52MHz) ? 1 : 0; 12878ac8a263SJean-Jacques Hiblot mmc_set_bus_width(mmc, widths[idx]); 12888ac8a263SJean-Jacques Hiblot 12897382e691SJean-Jacques Hiblot err = mmc_read_and_compare_ext_csd(mmc); 12907382e691SJean-Jacques Hiblot if (!err) 12918ac8a263SJean-Jacques Hiblot break; 12928ac8a263SJean-Jacques Hiblot } 12938ac8a263SJean-Jacques Hiblot 12948ac8a263SJean-Jacques Hiblot if (err) 12958ac8a263SJean-Jacques Hiblot return err; 12968ac8a263SJean-Jacques Hiblot 1297*35f9e196SJean-Jacques Hiblot if (mmc->card_caps & MMC_MODE_HS_52MHz) { 1298*35f9e196SJean-Jacques Hiblot if (mmc->ddr_mode) 1299*35f9e196SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_DDR_52); 13008ac8a263SJean-Jacques Hiblot else 1301*35f9e196SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_HS_52); 1302*35f9e196SJean-Jacques Hiblot mmc->tran_speed = 52000000; 1303*35f9e196SJean-Jacques Hiblot } else if (mmc->card_caps & MMC_MODE_HS) { 1304*35f9e196SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_HS); 13058ac8a263SJean-Jacques Hiblot mmc->tran_speed = 26000000; 13068ac8a263SJean-Jacques Hiblot } 13078ac8a263SJean-Jacques Hiblot 13088ac8a263SJean-Jacques Hiblot return err; 13098ac8a263SJean-Jacques Hiblot } 13108ac8a263SJean-Jacques Hiblot 1311dfda9d88SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc) 1312c744b6f6SJean-Jacques Hiblot { 1313c744b6f6SJean-Jacques Hiblot int err, i; 1314c744b6f6SJean-Jacques Hiblot u64 capacity; 1315c744b6f6SJean-Jacques Hiblot bool has_parts = false; 1316c744b6f6SJean-Jacques Hiblot bool part_completed; 1317dfda9d88SJean-Jacques Hiblot u8 *ext_csd; 1318c744b6f6SJean-Jacques Hiblot 1319c744b6f6SJean-Jacques Hiblot if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4)) 1320c744b6f6SJean-Jacques Hiblot return 0; 1321c744b6f6SJean-Jacques Hiblot 1322dfda9d88SJean-Jacques Hiblot ext_csd = malloc_cache_aligned(MMC_MAX_BLOCK_LEN); 1323dfda9d88SJean-Jacques Hiblot if (!ext_csd) 1324dfda9d88SJean-Jacques Hiblot return -ENOMEM; 1325dfda9d88SJean-Jacques Hiblot 1326dfda9d88SJean-Jacques Hiblot mmc->ext_csd = ext_csd; 1327dfda9d88SJean-Jacques Hiblot 1328c744b6f6SJean-Jacques Hiblot /* check ext_csd version and capacity */ 1329c744b6f6SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, ext_csd); 1330c744b6f6SJean-Jacques Hiblot if (err) 1331c744b6f6SJean-Jacques Hiblot return err; 1332c744b6f6SJean-Jacques Hiblot if (ext_csd[EXT_CSD_REV] >= 2) { 1333c744b6f6SJean-Jacques Hiblot /* 1334c744b6f6SJean-Jacques Hiblot * According to the JEDEC Standard, the value of 1335c744b6f6SJean-Jacques Hiblot * ext_csd's capacity is valid if the value is more 1336c744b6f6SJean-Jacques Hiblot * than 2GB 1337c744b6f6SJean-Jacques Hiblot */ 1338c744b6f6SJean-Jacques Hiblot capacity = ext_csd[EXT_CSD_SEC_CNT] << 0 1339c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 1340c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 1341c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; 1342c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN; 1343c744b6f6SJean-Jacques Hiblot if ((capacity >> 20) > 2 * 1024) 1344c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity; 1345c744b6f6SJean-Jacques Hiblot } 1346c744b6f6SJean-Jacques Hiblot 1347c744b6f6SJean-Jacques Hiblot switch (ext_csd[EXT_CSD_REV]) { 1348c744b6f6SJean-Jacques Hiblot case 1: 1349c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_1; 1350c744b6f6SJean-Jacques Hiblot break; 1351c744b6f6SJean-Jacques Hiblot case 2: 1352c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_2; 1353c744b6f6SJean-Jacques Hiblot break; 1354c744b6f6SJean-Jacques Hiblot case 3: 1355c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_3; 1356c744b6f6SJean-Jacques Hiblot break; 1357c744b6f6SJean-Jacques Hiblot case 5: 1358c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_41; 1359c744b6f6SJean-Jacques Hiblot break; 1360c744b6f6SJean-Jacques Hiblot case 6: 1361c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_5; 1362c744b6f6SJean-Jacques Hiblot break; 1363c744b6f6SJean-Jacques Hiblot case 7: 1364c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_5_0; 1365c744b6f6SJean-Jacques Hiblot break; 1366c744b6f6SJean-Jacques Hiblot case 8: 1367c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_5_1; 1368c744b6f6SJean-Jacques Hiblot break; 1369c744b6f6SJean-Jacques Hiblot } 1370c744b6f6SJean-Jacques Hiblot 1371c744b6f6SJean-Jacques Hiblot /* The partition data may be non-zero but it is only 1372c744b6f6SJean-Jacques Hiblot * effective if PARTITION_SETTING_COMPLETED is set in 1373c744b6f6SJean-Jacques Hiblot * EXT_CSD, so ignore any data if this bit is not set, 1374c744b6f6SJean-Jacques Hiblot * except for enabling the high-capacity group size 1375c744b6f6SJean-Jacques Hiblot * definition (see below). 1376c744b6f6SJean-Jacques Hiblot */ 1377c744b6f6SJean-Jacques Hiblot part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] & 1378c744b6f6SJean-Jacques Hiblot EXT_CSD_PARTITION_SETTING_COMPLETED); 1379c744b6f6SJean-Jacques Hiblot 1380c744b6f6SJean-Jacques Hiblot /* store the partition info of emmc */ 1381c744b6f6SJean-Jacques Hiblot mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT]; 1382c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || 1383c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_BOOT_MULT]) 1384c744b6f6SJean-Jacques Hiblot mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; 1385c744b6f6SJean-Jacques Hiblot if (part_completed && 1386c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT)) 1387c744b6f6SJean-Jacques Hiblot mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]; 1388c744b6f6SJean-Jacques Hiblot 1389c744b6f6SJean-Jacques Hiblot mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17; 1390c744b6f6SJean-Jacques Hiblot 1391c744b6f6SJean-Jacques Hiblot mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17; 1392c744b6f6SJean-Jacques Hiblot 1393c744b6f6SJean-Jacques Hiblot for (i = 0; i < 4; i++) { 1394c744b6f6SJean-Jacques Hiblot int idx = EXT_CSD_GP_SIZE_MULT + i * 3; 1395c744b6f6SJean-Jacques Hiblot uint mult = (ext_csd[idx + 2] << 16) + 1396c744b6f6SJean-Jacques Hiblot (ext_csd[idx + 1] << 8) + ext_csd[idx]; 1397c744b6f6SJean-Jacques Hiblot if (mult) 1398c744b6f6SJean-Jacques Hiblot has_parts = true; 1399c744b6f6SJean-Jacques Hiblot if (!part_completed) 1400c744b6f6SJean-Jacques Hiblot continue; 1401c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] = mult; 1402c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= 1403c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1404c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1405c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] <<= 19; 1406c744b6f6SJean-Jacques Hiblot } 1407c744b6f6SJean-Jacques Hiblot 1408c744b6f6SJean-Jacques Hiblot if (part_completed) { 1409c744b6f6SJean-Jacques Hiblot mmc->enh_user_size = 1410c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) + 1411c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) + 1412c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_SIZE_MULT]; 1413c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1414c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1415c744b6f6SJean-Jacques Hiblot mmc->enh_user_size <<= 19; 1416c744b6f6SJean-Jacques Hiblot mmc->enh_user_start = 1417c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) + 1418c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) + 1419c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) + 1420c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_START_ADDR]; 1421c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity) 1422c744b6f6SJean-Jacques Hiblot mmc->enh_user_start <<= 9; 1423c744b6f6SJean-Jacques Hiblot } 1424c744b6f6SJean-Jacques Hiblot 1425c744b6f6SJean-Jacques Hiblot /* 1426c744b6f6SJean-Jacques Hiblot * Host needs to enable ERASE_GRP_DEF bit if device is 1427c744b6f6SJean-Jacques Hiblot * partitioned. This bit will be lost every time after a reset 1428c744b6f6SJean-Jacques Hiblot * or power off. This will affect erase size. 1429c744b6f6SJean-Jacques Hiblot */ 1430c744b6f6SJean-Jacques Hiblot if (part_completed) 1431c744b6f6SJean-Jacques Hiblot has_parts = true; 1432c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) && 1433c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) 1434c744b6f6SJean-Jacques Hiblot has_parts = true; 1435c744b6f6SJean-Jacques Hiblot if (has_parts) { 1436c744b6f6SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1437c744b6f6SJean-Jacques Hiblot EXT_CSD_ERASE_GROUP_DEF, 1); 1438c744b6f6SJean-Jacques Hiblot 1439c744b6f6SJean-Jacques Hiblot if (err) 1440c744b6f6SJean-Jacques Hiblot return err; 1441c744b6f6SJean-Jacques Hiblot 1442c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 1443c744b6f6SJean-Jacques Hiblot } 1444c744b6f6SJean-Jacques Hiblot 1445c744b6f6SJean-Jacques Hiblot if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) { 1446c744b6f6SJean-Jacques Hiblot /* Read out group size from ext_csd */ 1447c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = 1448c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 1449c744b6f6SJean-Jacques Hiblot /* 1450c744b6f6SJean-Jacques Hiblot * if high capacity and partition setting completed 1451c744b6f6SJean-Jacques Hiblot * SEC_COUNT is valid even if it is smaller than 2 GiB 1452c744b6f6SJean-Jacques Hiblot * JEDEC Standard JESD84-B45, 6.2.4 1453c744b6f6SJean-Jacques Hiblot */ 1454c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity && part_completed) { 1455c744b6f6SJean-Jacques Hiblot capacity = (ext_csd[EXT_CSD_SEC_CNT]) | 1456c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) | 1457c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) | 1458c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 3] << 24); 1459c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN; 1460c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity; 1461c744b6f6SJean-Jacques Hiblot } 1462c744b6f6SJean-Jacques Hiblot } else { 1463c744b6f6SJean-Jacques Hiblot /* Calculate the group size from the csd value. */ 1464c744b6f6SJean-Jacques Hiblot int erase_gsz, erase_gmul; 1465c744b6f6SJean-Jacques Hiblot 1466c744b6f6SJean-Jacques Hiblot erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; 1467c744b6f6SJean-Jacques Hiblot erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; 1468c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = (erase_gsz + 1) 1469c744b6f6SJean-Jacques Hiblot * (erase_gmul + 1); 1470c744b6f6SJean-Jacques Hiblot } 1471c744b6f6SJean-Jacques Hiblot 1472c744b6f6SJean-Jacques Hiblot mmc->hc_wp_grp_size = 1024 1473c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 1474c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1475c744b6f6SJean-Jacques Hiblot 1476c744b6f6SJean-Jacques Hiblot mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 1477c744b6f6SJean-Jacques Hiblot 1478c744b6f6SJean-Jacques Hiblot return 0; 1479c744b6f6SJean-Jacques Hiblot } 1480c744b6f6SJean-Jacques Hiblot 1481fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc) 1482272cc70bSAndy Fleming { 1483f866a46dSStephen Warren int err, i; 1484272cc70bSAndy Fleming uint mult, freq; 1485c744b6f6SJean-Jacques Hiblot u64 cmult, csize; 1486272cc70bSAndy Fleming struct mmc_cmd cmd; 1487c40fdca6SSimon Glass struct blk_desc *bdesc; 1488272cc70bSAndy Fleming 1489d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON 1490d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ 1491d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; 1492d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R1; 1493d52ebf10SThomas Chou cmd.cmdarg = 1; 1494d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 1495d52ebf10SThomas Chou 1496d52ebf10SThomas Chou if (err) 1497d52ebf10SThomas Chou return err; 1498d52ebf10SThomas Chou } 1499d52ebf10SThomas Chou #endif 1500d52ebf10SThomas Chou 1501272cc70bSAndy Fleming /* Put the Card in Identify Mode */ 1502d52ebf10SThomas Chou cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : 1503d52ebf10SThomas Chou MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ 1504272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1505272cc70bSAndy Fleming cmd.cmdarg = 0; 1506272cc70bSAndy Fleming 1507272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1508272cc70bSAndy Fleming 1509272cc70bSAndy Fleming if (err) 1510272cc70bSAndy Fleming return err; 1511272cc70bSAndy Fleming 1512272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16); 1513272cc70bSAndy Fleming 1514272cc70bSAndy Fleming /* 1515272cc70bSAndy Fleming * For MMC cards, set the Relative Address. 1516272cc70bSAndy Fleming * For SD cards, get the Relatvie Address. 1517272cc70bSAndy Fleming * This also puts the cards into Standby State 1518272cc70bSAndy Fleming */ 1519d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1520272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; 1521272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1522272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6; 1523272cc70bSAndy Fleming 1524272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1525272cc70bSAndy Fleming 1526272cc70bSAndy Fleming if (err) 1527272cc70bSAndy Fleming return err; 1528272cc70bSAndy Fleming 1529272cc70bSAndy Fleming if (IS_SD(mmc)) 1530998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff; 1531d52ebf10SThomas Chou } 1532272cc70bSAndy Fleming 1533272cc70bSAndy Fleming /* Get the Card-Specific Data */ 1534272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD; 1535272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1536272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1537272cc70bSAndy Fleming 1538272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1539272cc70bSAndy Fleming 1540272cc70bSAndy Fleming if (err) 1541272cc70bSAndy Fleming return err; 1542272cc70bSAndy Fleming 1543998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0]; 1544998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1]; 1545998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2]; 1546998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3]; 1547272cc70bSAndy Fleming 1548272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) { 15490b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf; 1550272cc70bSAndy Fleming 1551272cc70bSAndy Fleming switch (version) { 1552272cc70bSAndy Fleming case 0: 1553272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1554272cc70bSAndy Fleming break; 1555272cc70bSAndy Fleming case 1: 1556272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4; 1557272cc70bSAndy Fleming break; 1558272cc70bSAndy Fleming case 2: 1559272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2; 1560272cc70bSAndy Fleming break; 1561272cc70bSAndy Fleming case 3: 1562272cc70bSAndy Fleming mmc->version = MMC_VERSION_3; 1563272cc70bSAndy Fleming break; 1564272cc70bSAndy Fleming case 4: 1565272cc70bSAndy Fleming mmc->version = MMC_VERSION_4; 1566272cc70bSAndy Fleming break; 1567272cc70bSAndy Fleming default: 1568272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1569272cc70bSAndy Fleming break; 1570272cc70bSAndy Fleming } 1571272cc70bSAndy Fleming } 1572272cc70bSAndy Fleming 1573272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */ 15740b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)]; 15750b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; 1576272cc70bSAndy Fleming 1577*35f9e196SJean-Jacques Hiblot mmc->legacy_speed = freq * mult; 1578*35f9e196SJean-Jacques Hiblot mmc->tran_speed = mmc->legacy_speed; 1579*35f9e196SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_LEGACY); 1580272cc70bSAndy Fleming 1581ab71188cSMarkus Niebel mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); 1582998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); 1583272cc70bSAndy Fleming 1584272cc70bSAndy Fleming if (IS_SD(mmc)) 1585272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len; 1586272cc70bSAndy Fleming else 1587998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); 1588272cc70bSAndy Fleming 1589272cc70bSAndy Fleming if (mmc->high_capacity) { 1590272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16 1591272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16; 1592272cc70bSAndy Fleming cmult = 8; 1593272cc70bSAndy Fleming } else { 1594272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2 1595272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30; 1596272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15; 1597272cc70bSAndy Fleming } 1598272cc70bSAndy Fleming 1599f866a46dSStephen Warren mmc->capacity_user = (csize + 1) << (cmult + 2); 1600f866a46dSStephen Warren mmc->capacity_user *= mmc->read_bl_len; 1601f866a46dSStephen Warren mmc->capacity_boot = 0; 1602f866a46dSStephen Warren mmc->capacity_rpmb = 0; 1603f866a46dSStephen Warren for (i = 0; i < 4; i++) 1604f866a46dSStephen Warren mmc->capacity_gp[i] = 0; 1605272cc70bSAndy Fleming 16068bfa195eSSimon Glass if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN) 16078bfa195eSSimon Glass mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 1608272cc70bSAndy Fleming 16098bfa195eSSimon Glass if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) 16108bfa195eSSimon Glass mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 1611272cc70bSAndy Fleming 1612ab71188cSMarkus Niebel if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) { 1613ab71188cSMarkus Niebel cmd.cmdidx = MMC_CMD_SET_DSR; 1614ab71188cSMarkus Niebel cmd.cmdarg = (mmc->dsr & 0xffff) << 16; 1615ab71188cSMarkus Niebel cmd.resp_type = MMC_RSP_NONE; 1616ab71188cSMarkus Niebel if (mmc_send_cmd(mmc, &cmd, NULL)) 1617ab71188cSMarkus Niebel printf("MMC: SET_DSR failed\n"); 1618ab71188cSMarkus Niebel } 1619ab71188cSMarkus Niebel 1620272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */ 1621d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1622272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD; 1623fe8f7066SAjay Bhargav cmd.resp_type = MMC_RSP_R1; 1624272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1625272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1626272cc70bSAndy Fleming 1627272cc70bSAndy Fleming if (err) 1628272cc70bSAndy Fleming return err; 1629d52ebf10SThomas Chou } 1630272cc70bSAndy Fleming 1631e6f99a56SLei Wen /* 1632e6f99a56SLei Wen * For SD, its erase group is always one sector 1633e6f99a56SLei Wen */ 1634e6f99a56SLei Wen mmc->erase_grp_size = 1; 1635bc897b1dSLei Wen mmc->part_config = MMCPART_NOAVAILABLE; 1636c744b6f6SJean-Jacques Hiblot 1637dfda9d88SJean-Jacques Hiblot err = mmc_startup_v4(mmc); 16389cf199ebSDiego Santa Cruz if (err) 16399cf199ebSDiego Santa Cruz return err; 1640f866a46dSStephen Warren 1641c40fdca6SSimon Glass err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart); 1642f866a46dSStephen Warren if (err) 1643f866a46dSStephen Warren return err; 1644d23e2c09SSukumar Ghorai 1645272cc70bSAndy Fleming if (IS_SD(mmc)) 16468ac8a263SJean-Jacques Hiblot err = sd_select_bus_freq_width(mmc); 1647272cc70bSAndy Fleming else 1648dfda9d88SJean-Jacques Hiblot err = mmc_select_bus_freq_width(mmc); 1649272cc70bSAndy Fleming 1650272cc70bSAndy Fleming if (err) 1651272cc70bSAndy Fleming return err; 1652272cc70bSAndy Fleming 1653ad5fd922SJaehoon Chung mmc_set_clock(mmc, mmc->tran_speed); 1654272cc70bSAndy Fleming 16555af8f45cSAndrew Gabbasov /* Fix the block length for DDR mode */ 16565af8f45cSAndrew Gabbasov if (mmc->ddr_mode) { 16575af8f45cSAndrew Gabbasov mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 16585af8f45cSAndrew Gabbasov mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 16595af8f45cSAndrew Gabbasov } 16605af8f45cSAndrew Gabbasov 1661272cc70bSAndy Fleming /* fill in device description */ 1662c40fdca6SSimon Glass bdesc = mmc_get_blk_desc(mmc); 1663c40fdca6SSimon Glass bdesc->lun = 0; 1664c40fdca6SSimon Glass bdesc->hwpart = 0; 1665c40fdca6SSimon Glass bdesc->type = 0; 1666c40fdca6SSimon Glass bdesc->blksz = mmc->read_bl_len; 1667c40fdca6SSimon Glass bdesc->log2blksz = LOG2(bdesc->blksz); 1668c40fdca6SSimon Glass bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len); 1669fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \ 1670fc011f64SSjoerd Simons (defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \ 1671fc011f64SSjoerd Simons !defined(CONFIG_USE_TINY_PRINTF)) 1672c40fdca6SSimon Glass sprintf(bdesc->vendor, "Man %06x Snr %04x%04x", 1673babce5f6STaylor Hutt mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), 1674babce5f6STaylor Hutt (mmc->cid[3] >> 16) & 0xffff); 1675c40fdca6SSimon Glass sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff, 16760b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 1677babce5f6STaylor Hutt (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff, 1678babce5f6STaylor Hutt (mmc->cid[2] >> 24) & 0xff); 1679c40fdca6SSimon Glass sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf, 1680babce5f6STaylor Hutt (mmc->cid[2] >> 16) & 0xf); 168156196826SPaul Burton #else 1682c40fdca6SSimon Glass bdesc->vendor[0] = 0; 1683c40fdca6SSimon Glass bdesc->product[0] = 0; 1684c40fdca6SSimon Glass bdesc->revision[0] = 0; 168556196826SPaul Burton #endif 1686122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT) 1687c40fdca6SSimon Glass part_init(bdesc); 1688122efd43SMikhail Kshevetskiy #endif 1689272cc70bSAndy Fleming 1690272cc70bSAndy Fleming return 0; 1691272cc70bSAndy Fleming } 1692272cc70bSAndy Fleming 1693fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc) 1694272cc70bSAndy Fleming { 1695272cc70bSAndy Fleming struct mmc_cmd cmd; 1696272cc70bSAndy Fleming int err; 1697272cc70bSAndy Fleming 1698272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND; 1699272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ 170093bfd616SPantelis Antoniou cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa; 1701272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7; 1702272cc70bSAndy Fleming 1703272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1704272cc70bSAndy Fleming 1705272cc70bSAndy Fleming if (err) 1706272cc70bSAndy Fleming return err; 1707272cc70bSAndy Fleming 1708998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa) 1709915ffa52SJaehoon Chung return -EOPNOTSUPP; 1710272cc70bSAndy Fleming else 1711272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 1712272cc70bSAndy Fleming 1713272cc70bSAndy Fleming return 0; 1714272cc70bSAndy Fleming } 1715272cc70bSAndy Fleming 1716c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 171795de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */ 171895de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void) 171995de9ab2SPaul Kocialkowski { 172095de9ab2SPaul Kocialkowski } 172105cbeb7cSSimon Glass #endif 172295de9ab2SPaul Kocialkowski 17232051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc) 17242051aefeSPeng Fan { 1725c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 172606ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR) 17272051aefeSPeng Fan int ret; 17282051aefeSPeng Fan 17292051aefeSPeng Fan ret = device_get_supply_regulator(mmc->dev, "vmmc-supply", 173006ec045fSJean-Jacques Hiblot &mmc->vmmc_supply); 173106ec045fSJean-Jacques Hiblot if (ret) 1732288db7c7SJaehoon Chung debug("%s: No vmmc supply\n", mmc->dev->name); 17332051aefeSPeng Fan 173406ec045fSJean-Jacques Hiblot ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply", 173506ec045fSJean-Jacques Hiblot &mmc->vqmmc_supply); 173606ec045fSJean-Jacques Hiblot if (ret) 173706ec045fSJean-Jacques Hiblot debug("%s: No vqmmc supply\n", mmc->dev->name); 173806ec045fSJean-Jacques Hiblot 173906ec045fSJean-Jacques Hiblot if (mmc->vmmc_supply) { 174006ec045fSJean-Jacques Hiblot ret = regulator_set_enable(mmc->vmmc_supply, true); 17412051aefeSPeng Fan if (ret) { 17422051aefeSPeng Fan puts("Error enabling VMMC supply\n"); 17432051aefeSPeng Fan return ret; 17442051aefeSPeng Fan } 174506ec045fSJean-Jacques Hiblot } 17462051aefeSPeng Fan #endif 174705cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */ 174805cbeb7cSSimon Glass /* 174905cbeb7cSSimon Glass * Driver model should use a regulator, as above, rather than calling 175005cbeb7cSSimon Glass * out to board code. 175105cbeb7cSSimon Glass */ 175205cbeb7cSSimon Glass board_mmc_power_init(); 175305cbeb7cSSimon Glass #endif 17542051aefeSPeng Fan return 0; 17552051aefeSPeng Fan } 17562051aefeSPeng Fan 1757e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc) 1758272cc70bSAndy Fleming { 17598ca51e51SSimon Glass bool no_card; 1760afd5932bSMacpaul Lin int err; 1761272cc70bSAndy Fleming 1762ab769f22SPantelis Antoniou /* we pretend there's no card when init is NULL */ 17638ca51e51SSimon Glass no_card = mmc_getcd(mmc) == 0; 1764e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 17658ca51e51SSimon Glass no_card = no_card || (mmc->cfg->ops->init == NULL); 17668ca51e51SSimon Glass #endif 17678ca51e51SSimon Glass if (no_card) { 176848972d90SThierry Reding mmc->has_init = 0; 176956196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 177048972d90SThierry Reding printf("MMC: no card present\n"); 177156196826SPaul Burton #endif 1772915ffa52SJaehoon Chung return -ENOMEDIUM; 177348972d90SThierry Reding } 177448972d90SThierry Reding 1775bc897b1dSLei Wen if (mmc->has_init) 1776bc897b1dSLei Wen return 0; 1777bc897b1dSLei Wen 17785a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 17795a8dbdc6SYangbo Lu mmc_adapter_card_type_ident(); 17805a8dbdc6SYangbo Lu #endif 17812051aefeSPeng Fan err = mmc_power_init(mmc); 17822051aefeSPeng Fan if (err) 17832051aefeSPeng Fan return err; 178495de9ab2SPaul Kocialkowski 1785e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 17868ca51e51SSimon Glass /* The device has already been probed ready for use */ 17878ca51e51SSimon Glass #else 1788ab769f22SPantelis Antoniou /* made sure it's not NULL earlier */ 178993bfd616SPantelis Antoniou err = mmc->cfg->ops->init(mmc); 1790272cc70bSAndy Fleming if (err) 1791272cc70bSAndy Fleming return err; 17928ca51e51SSimon Glass #endif 1793786e8f81SAndrew Gabbasov mmc->ddr_mode = 0; 1794b86b85e2SIlya Yanok mmc_set_bus_width(mmc, 1); 1795b86b85e2SIlya Yanok mmc_set_clock(mmc, 1); 1796b86b85e2SIlya Yanok 1797272cc70bSAndy Fleming /* Reset the Card */ 1798272cc70bSAndy Fleming err = mmc_go_idle(mmc); 1799272cc70bSAndy Fleming 1800272cc70bSAndy Fleming if (err) 1801272cc70bSAndy Fleming return err; 1802272cc70bSAndy Fleming 1803bc897b1dSLei Wen /* The internal partition reset to user partition(0) at every CMD0*/ 1804c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->hwpart = 0; 1805bc897b1dSLei Wen 1806272cc70bSAndy Fleming /* Test for SD version 2 */ 1807272cc70bSAndy Fleming err = mmc_send_if_cond(mmc); 1808272cc70bSAndy Fleming 1809272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */ 1810272cc70bSAndy Fleming err = sd_send_op_cond(mmc); 1811272cc70bSAndy Fleming 1812272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */ 1813915ffa52SJaehoon Chung if (err == -ETIMEDOUT) { 1814272cc70bSAndy Fleming err = mmc_send_op_cond(mmc); 1815272cc70bSAndy Fleming 1816bd47c135SAndrew Gabbasov if (err) { 181756196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 1818272cc70bSAndy Fleming printf("Card did not respond to voltage select!\n"); 181956196826SPaul Burton #endif 1820915ffa52SJaehoon Chung return -EOPNOTSUPP; 1821272cc70bSAndy Fleming } 1822272cc70bSAndy Fleming } 1823272cc70bSAndy Fleming 1824bd47c135SAndrew Gabbasov if (!err) 1825e9550449SChe-Liang Chiou mmc->init_in_progress = 1; 1826e9550449SChe-Liang Chiou 1827e9550449SChe-Liang Chiou return err; 1828e9550449SChe-Liang Chiou } 1829e9550449SChe-Liang Chiou 1830e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc) 1831e9550449SChe-Liang Chiou { 1832e9550449SChe-Liang Chiou int err = 0; 1833e9550449SChe-Liang Chiou 1834bd47c135SAndrew Gabbasov mmc->init_in_progress = 0; 1835e9550449SChe-Liang Chiou if (mmc->op_cond_pending) 1836e9550449SChe-Liang Chiou err = mmc_complete_op_cond(mmc); 1837e9550449SChe-Liang Chiou 1838e9550449SChe-Liang Chiou if (!err) 1839bc897b1dSLei Wen err = mmc_startup(mmc); 1840bc897b1dSLei Wen if (err) 1841bc897b1dSLei Wen mmc->has_init = 0; 1842bc897b1dSLei Wen else 1843bc897b1dSLei Wen mmc->has_init = 1; 1844e9550449SChe-Liang Chiou return err; 1845e9550449SChe-Liang Chiou } 1846e9550449SChe-Liang Chiou 1847e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc) 1848e9550449SChe-Liang Chiou { 1849bd47c135SAndrew Gabbasov int err = 0; 1850ce9eca94SMarek Vasut __maybe_unused unsigned start; 1851c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 185233fb211dSSimon Glass struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev); 1853e9550449SChe-Liang Chiou 185433fb211dSSimon Glass upriv->mmc = mmc; 185533fb211dSSimon Glass #endif 1856e9550449SChe-Liang Chiou if (mmc->has_init) 1857e9550449SChe-Liang Chiou return 0; 1858d803fea5SMateusz Zalega 1859d803fea5SMateusz Zalega start = get_timer(0); 1860d803fea5SMateusz Zalega 1861e9550449SChe-Liang Chiou if (!mmc->init_in_progress) 1862e9550449SChe-Liang Chiou err = mmc_start_init(mmc); 1863e9550449SChe-Liang Chiou 1864bd47c135SAndrew Gabbasov if (!err) 1865e9550449SChe-Liang Chiou err = mmc_complete_init(mmc); 1866919b4858SJagan Teki if (err) 1867919b4858SJagan Teki printf("%s: %d, time %lu\n", __func__, err, get_timer(start)); 1868919b4858SJagan Teki 1869bc897b1dSLei Wen return err; 1870272cc70bSAndy Fleming } 1871272cc70bSAndy Fleming 1872ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val) 1873ab71188cSMarkus Niebel { 1874ab71188cSMarkus Niebel mmc->dsr = val; 1875ab71188cSMarkus Niebel return 0; 1876ab71188cSMarkus Niebel } 1877ab71188cSMarkus Niebel 1878cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */ 1879cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis) 1880272cc70bSAndy Fleming { 1881272cc70bSAndy Fleming return -1; 1882272cc70bSAndy Fleming } 1883272cc70bSAndy Fleming 1884cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */ 1885cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis) 1886cee9ab7cSJeroen Hofstee { 1887cee9ab7cSJeroen Hofstee return -1; 1888cee9ab7cSJeroen Hofstee } 1889272cc70bSAndy Fleming 1890e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit) 1891e9550449SChe-Liang Chiou { 1892e9550449SChe-Liang Chiou mmc->preinit = preinit; 1893e9550449SChe-Liang Chiou } 1894e9550449SChe-Liang Chiou 1895c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD) 18968e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 18978e3332e2SSjoerd Simons { 18988e3332e2SSjoerd Simons return 0; 18998e3332e2SSjoerd Simons } 1900c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC) 19018e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 19028e3332e2SSjoerd Simons { 19034a1db6d8SSimon Glass int ret, i; 19048e3332e2SSjoerd Simons struct uclass *uc; 19054a1db6d8SSimon Glass struct udevice *dev; 19068e3332e2SSjoerd Simons 19078e3332e2SSjoerd Simons ret = uclass_get(UCLASS_MMC, &uc); 19088e3332e2SSjoerd Simons if (ret) 19098e3332e2SSjoerd Simons return ret; 19108e3332e2SSjoerd Simons 19114a1db6d8SSimon Glass /* 19124a1db6d8SSimon Glass * Try to add them in sequence order. Really with driver model we 19134a1db6d8SSimon Glass * should allow holes, but the current MMC list does not allow that. 19144a1db6d8SSimon Glass * So if we request 0, 1, 3 we will get 0, 1, 2. 19154a1db6d8SSimon Glass */ 19164a1db6d8SSimon Glass for (i = 0; ; i++) { 19174a1db6d8SSimon Glass ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev); 19184a1db6d8SSimon Glass if (ret == -ENODEV) 19194a1db6d8SSimon Glass break; 19204a1db6d8SSimon Glass } 19214a1db6d8SSimon Glass uclass_foreach_dev(dev, uc) { 19224a1db6d8SSimon Glass ret = device_probe(dev); 19238e3332e2SSjoerd Simons if (ret) 19244a1db6d8SSimon Glass printf("%s - probe failed: %d\n", dev->name, ret); 19258e3332e2SSjoerd Simons } 19268e3332e2SSjoerd Simons 19278e3332e2SSjoerd Simons return 0; 19288e3332e2SSjoerd Simons } 19298e3332e2SSjoerd Simons #else 19308e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 19318e3332e2SSjoerd Simons { 19328e3332e2SSjoerd Simons if (board_mmc_init(bis) < 0) 19338e3332e2SSjoerd Simons cpu_mmc_init(bis); 19348e3332e2SSjoerd Simons 19358e3332e2SSjoerd Simons return 0; 19368e3332e2SSjoerd Simons } 19378e3332e2SSjoerd Simons #endif 1938e9550449SChe-Liang Chiou 1939272cc70bSAndy Fleming int mmc_initialize(bd_t *bis) 1940272cc70bSAndy Fleming { 19411b26bab1SDaniel Kochmański static int initialized = 0; 19428e3332e2SSjoerd Simons int ret; 19431b26bab1SDaniel Kochmański if (initialized) /* Avoid initializing mmc multiple times */ 19441b26bab1SDaniel Kochmański return 0; 19451b26bab1SDaniel Kochmański initialized = 1; 19461b26bab1SDaniel Kochmański 1947c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK) 1948b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY) 1949c40fdca6SSimon Glass mmc_list_init(); 1950c40fdca6SSimon Glass #endif 1951b5b838f1SMarek Vasut #endif 19528e3332e2SSjoerd Simons ret = mmc_probe(bis); 19538e3332e2SSjoerd Simons if (ret) 19548e3332e2SSjoerd Simons return ret; 1955272cc70bSAndy Fleming 1956bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD 1957272cc70bSAndy Fleming print_mmc_devices(','); 1958bb0dc108SYing Zhang #endif 1959272cc70bSAndy Fleming 1960c40fdca6SSimon Glass mmc_do_preinit(); 1961272cc70bSAndy Fleming return 0; 1962272cc70bSAndy Fleming } 1963cd3d4880STomas Melin 1964cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE 1965cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc) 1966cd3d4880STomas Melin { 1967cd3d4880STomas Melin int err; 1968cd3d4880STomas Melin ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 1969cd3d4880STomas Melin 1970cd3d4880STomas Melin err = mmc_send_ext_csd(mmc, ext_csd); 1971cd3d4880STomas Melin if (err) { 1972cd3d4880STomas Melin puts("Could not get ext_csd register values\n"); 1973cd3d4880STomas Melin return err; 1974cd3d4880STomas Melin } 1975cd3d4880STomas Melin 1976cd3d4880STomas Melin if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) { 1977cd3d4880STomas Melin puts("Background operations not supported on device\n"); 1978cd3d4880STomas Melin return -EMEDIUMTYPE; 1979cd3d4880STomas Melin } 1980cd3d4880STomas Melin 1981cd3d4880STomas Melin if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) { 1982cd3d4880STomas Melin puts("Background operations already enabled\n"); 1983cd3d4880STomas Melin return 0; 1984cd3d4880STomas Melin } 1985cd3d4880STomas Melin 1986cd3d4880STomas Melin err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1); 1987cd3d4880STomas Melin if (err) { 1988cd3d4880STomas Melin puts("Failed to enable manual background operations\n"); 1989cd3d4880STomas Melin return err; 1990cd3d4880STomas Melin } 1991cd3d4880STomas Melin 1992cd3d4880STomas Melin puts("Enabled manual background operations\n"); 1993cd3d4880STomas Melin 1994cd3d4880STomas Melin return 0; 1995cd3d4880STomas Melin } 1996cd3d4880STomas Melin #endif 1997