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 15235f9e196SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG) 15335f9e196SJean-Jacques Hiblot const char *mmc_mode_name(enum bus_mode mode) 15435f9e196SJean-Jacques Hiblot { 15535f9e196SJean-Jacques Hiblot static const char *const names[] = { 15635f9e196SJean-Jacques Hiblot [MMC_LEGACY] = "MMC legacy", 15735f9e196SJean-Jacques Hiblot [SD_LEGACY] = "SD Legacy", 15835f9e196SJean-Jacques Hiblot [MMC_HS] = "MMC High Speed (26MHz)", 15935f9e196SJean-Jacques Hiblot [SD_HS] = "SD High Speed (50MHz)", 16035f9e196SJean-Jacques Hiblot [UHS_SDR12] = "UHS SDR12 (25MHz)", 16135f9e196SJean-Jacques Hiblot [UHS_SDR25] = "UHS SDR25 (50MHz)", 16235f9e196SJean-Jacques Hiblot [UHS_SDR50] = "UHS SDR50 (100MHz)", 16335f9e196SJean-Jacques Hiblot [UHS_SDR104] = "UHS SDR104 (208MHz)", 16435f9e196SJean-Jacques Hiblot [UHS_DDR50] = "UHS DDR50 (50MHz)", 16535f9e196SJean-Jacques Hiblot [MMC_HS_52] = "MMC High Speed (52MHz)", 16635f9e196SJean-Jacques Hiblot [MMC_DDR_52] = "MMC DDR52 (52MHz)", 16735f9e196SJean-Jacques Hiblot [MMC_HS_200] = "HS200 (200MHz)", 16835f9e196SJean-Jacques Hiblot }; 16935f9e196SJean-Jacques Hiblot 17035f9e196SJean-Jacques Hiblot if (mode >= MMC_MODES_END) 17135f9e196SJean-Jacques Hiblot return "Unknown mode"; 17235f9e196SJean-Jacques Hiblot else 17335f9e196SJean-Jacques Hiblot return names[mode]; 17435f9e196SJean-Jacques Hiblot } 17535f9e196SJean-Jacques Hiblot #endif 17635f9e196SJean-Jacques Hiblot 177*05038576SJean-Jacques Hiblot static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode) 178*05038576SJean-Jacques Hiblot { 179*05038576SJean-Jacques Hiblot static const int freqs[] = { 180*05038576SJean-Jacques Hiblot [SD_LEGACY] = 25000000, 181*05038576SJean-Jacques Hiblot [MMC_HS] = 26000000, 182*05038576SJean-Jacques Hiblot [SD_HS] = 50000000, 183*05038576SJean-Jacques Hiblot [UHS_SDR12] = 25000000, 184*05038576SJean-Jacques Hiblot [UHS_SDR25] = 50000000, 185*05038576SJean-Jacques Hiblot [UHS_SDR50] = 100000000, 186*05038576SJean-Jacques Hiblot [UHS_SDR104] = 208000000, 187*05038576SJean-Jacques Hiblot [UHS_DDR50] = 50000000, 188*05038576SJean-Jacques Hiblot [MMC_HS_52] = 52000000, 189*05038576SJean-Jacques Hiblot [MMC_DDR_52] = 52000000, 190*05038576SJean-Jacques Hiblot [MMC_HS_200] = 200000000, 191*05038576SJean-Jacques Hiblot }; 192*05038576SJean-Jacques Hiblot 193*05038576SJean-Jacques Hiblot if (mode == MMC_LEGACY) 194*05038576SJean-Jacques Hiblot return mmc->legacy_speed; 195*05038576SJean-Jacques Hiblot else if (mode >= MMC_MODES_END) 196*05038576SJean-Jacques Hiblot return 0; 197*05038576SJean-Jacques Hiblot else 198*05038576SJean-Jacques Hiblot return freqs[mode]; 199*05038576SJean-Jacques Hiblot } 200*05038576SJean-Jacques Hiblot 20135f9e196SJean-Jacques Hiblot static int mmc_select_mode(struct mmc *mmc, enum bus_mode mode) 20235f9e196SJean-Jacques Hiblot { 20335f9e196SJean-Jacques Hiblot mmc->selected_mode = mode; 204*05038576SJean-Jacques Hiblot mmc->tran_speed = mmc_mode2freq(mmc, mode); 20535f9e196SJean-Jacques Hiblot debug("selecting mode %s (freq : %d MHz)\n", mmc_mode_name(mode), 20635f9e196SJean-Jacques Hiblot mmc->tran_speed / 1000000); 20735f9e196SJean-Jacques Hiblot return 0; 20835f9e196SJean-Jacques Hiblot } 20935f9e196SJean-Jacques Hiblot 210e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 211c0c76ebaSSimon Glass int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) 212c0c76ebaSSimon Glass { 213c0c76ebaSSimon Glass int ret; 214c0c76ebaSSimon Glass 215c0c76ebaSSimon Glass mmmc_trace_before_send(mmc, cmd); 216c0c76ebaSSimon Glass ret = mmc->cfg->ops->send_cmd(mmc, cmd, data); 217c0c76ebaSSimon Glass mmmc_trace_after_send(mmc, cmd, ret); 218c0c76ebaSSimon Glass 2198635ff9eSMarek Vasut return ret; 220272cc70bSAndy Fleming } 2218ca51e51SSimon Glass #endif 222272cc70bSAndy Fleming 223da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout) 2245d4fc8d9SRaffaele Recalcati { 2255d4fc8d9SRaffaele Recalcati struct mmc_cmd cmd; 226d617c426SJan Kloetzke int err, retries = 5; 2275d4fc8d9SRaffaele Recalcati 2285d4fc8d9SRaffaele Recalcati cmd.cmdidx = MMC_CMD_SEND_STATUS; 2295d4fc8d9SRaffaele Recalcati cmd.resp_type = MMC_RSP_R1; 230aaf3d41aSMarek Vasut if (!mmc_host_is_spi(mmc)) 231aaf3d41aSMarek Vasut cmd.cmdarg = mmc->rca << 16; 2325d4fc8d9SRaffaele Recalcati 2331677eef4SAndrew Gabbasov while (1) { 2345d4fc8d9SRaffaele Recalcati err = mmc_send_cmd(mmc, &cmd, NULL); 235d617c426SJan Kloetzke if (!err) { 236d617c426SJan Kloetzke if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) && 237d617c426SJan Kloetzke (cmd.response[0] & MMC_STATUS_CURR_STATE) != 238d617c426SJan Kloetzke MMC_STATE_PRG) 2395d4fc8d9SRaffaele Recalcati break; 240d617c426SJan Kloetzke else if (cmd.response[0] & MMC_STATUS_MASK) { 24156196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 242d617c426SJan Kloetzke printf("Status Error: 0x%08X\n", 243d617c426SJan Kloetzke cmd.response[0]); 24456196826SPaul Burton #endif 245915ffa52SJaehoon Chung return -ECOMM; 246d617c426SJan Kloetzke } 247d617c426SJan Kloetzke } else if (--retries < 0) 248d617c426SJan Kloetzke return err; 2495d4fc8d9SRaffaele Recalcati 2501677eef4SAndrew Gabbasov if (timeout-- <= 0) 2511677eef4SAndrew Gabbasov break; 2525d4fc8d9SRaffaele Recalcati 2531677eef4SAndrew Gabbasov udelay(1000); 2541677eef4SAndrew Gabbasov } 2555d4fc8d9SRaffaele Recalcati 256c0c76ebaSSimon Glass mmc_trace_state(mmc, &cmd); 2575b0c942fSJongman Heo if (timeout <= 0) { 25856196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2595d4fc8d9SRaffaele Recalcati printf("Timeout waiting card ready\n"); 26056196826SPaul Burton #endif 261915ffa52SJaehoon Chung return -ETIMEDOUT; 2625d4fc8d9SRaffaele Recalcati } 2635d4fc8d9SRaffaele Recalcati 2645d4fc8d9SRaffaele Recalcati return 0; 2655d4fc8d9SRaffaele Recalcati } 2665d4fc8d9SRaffaele Recalcati 267da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len) 268272cc70bSAndy Fleming { 269272cc70bSAndy Fleming struct mmc_cmd cmd; 270272cc70bSAndy Fleming 271786e8f81SAndrew Gabbasov if (mmc->ddr_mode) 272d22e3d46SJaehoon Chung return 0; 273d22e3d46SJaehoon Chung 274272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SET_BLOCKLEN; 275272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 276272cc70bSAndy Fleming cmd.cmdarg = len; 277272cc70bSAndy Fleming 278272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, NULL); 279272cc70bSAndy Fleming } 280272cc70bSAndy Fleming 281ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start, 282fdbb873eSKim Phillips lbaint_t blkcnt) 283272cc70bSAndy Fleming { 284272cc70bSAndy Fleming struct mmc_cmd cmd; 285272cc70bSAndy Fleming struct mmc_data data; 286272cc70bSAndy Fleming 2874a1a06bcSAlagu Sankar if (blkcnt > 1) 2884a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; 2894a1a06bcSAlagu Sankar else 290272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; 291272cc70bSAndy Fleming 292272cc70bSAndy Fleming if (mmc->high_capacity) 2934a1a06bcSAlagu Sankar cmd.cmdarg = start; 294272cc70bSAndy Fleming else 2954a1a06bcSAlagu Sankar cmd.cmdarg = start * mmc->read_bl_len; 296272cc70bSAndy Fleming 297272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 298272cc70bSAndy Fleming 299272cc70bSAndy Fleming data.dest = dst; 3004a1a06bcSAlagu Sankar data.blocks = blkcnt; 301272cc70bSAndy Fleming data.blocksize = mmc->read_bl_len; 302272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 303272cc70bSAndy Fleming 3044a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, &data)) 3054a1a06bcSAlagu Sankar return 0; 3064a1a06bcSAlagu Sankar 3074a1a06bcSAlagu Sankar if (blkcnt > 1) { 3084a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; 3094a1a06bcSAlagu Sankar cmd.cmdarg = 0; 3104a1a06bcSAlagu Sankar cmd.resp_type = MMC_RSP_R1b; 3114a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, NULL)) { 31256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 3134a1a06bcSAlagu Sankar printf("mmc fail to send stop cmd\n"); 31456196826SPaul Burton #endif 3154a1a06bcSAlagu Sankar return 0; 3164a1a06bcSAlagu Sankar } 317272cc70bSAndy Fleming } 318272cc70bSAndy Fleming 3194a1a06bcSAlagu Sankar return blkcnt; 320272cc70bSAndy Fleming } 321272cc70bSAndy Fleming 322c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK) 3237dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst) 32433fb211dSSimon Glass #else 3257dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, 3267dba0b93SSimon Glass void *dst) 32733fb211dSSimon Glass #endif 328272cc70bSAndy Fleming { 329c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK) 33033fb211dSSimon Glass struct blk_desc *block_dev = dev_get_uclass_platdata(dev); 33133fb211dSSimon Glass #endif 332bcce53d0SSimon Glass int dev_num = block_dev->devnum; 333873cc1d7SStephen Warren int err; 3344a1a06bcSAlagu Sankar lbaint_t cur, blocks_todo = blkcnt; 335272cc70bSAndy Fleming 3364a1a06bcSAlagu Sankar if (blkcnt == 0) 3374a1a06bcSAlagu Sankar return 0; 3384a1a06bcSAlagu Sankar 3394a1a06bcSAlagu Sankar struct mmc *mmc = find_mmc_device(dev_num); 340272cc70bSAndy Fleming if (!mmc) 341272cc70bSAndy Fleming return 0; 342272cc70bSAndy Fleming 343b5b838f1SMarek Vasut if (CONFIG_IS_ENABLED(MMC_TINY)) 344b5b838f1SMarek Vasut err = mmc_switch_part(mmc, block_dev->hwpart); 345b5b838f1SMarek Vasut else 34669f45cd5SSimon Glass err = blk_dselect_hwpart(block_dev, block_dev->hwpart); 347b5b838f1SMarek Vasut 348873cc1d7SStephen Warren if (err < 0) 349873cc1d7SStephen Warren return 0; 350873cc1d7SStephen Warren 351c40fdca6SSimon Glass if ((start + blkcnt) > block_dev->lba) { 35256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 353ff8fef56SSascha Silbe printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", 354c40fdca6SSimon Glass start + blkcnt, block_dev->lba); 35556196826SPaul Burton #endif 356d2bf29e3SLei Wen return 0; 357d2bf29e3SLei Wen } 358272cc70bSAndy Fleming 35911692991SSimon Glass if (mmc_set_blocklen(mmc, mmc->read_bl_len)) { 36011692991SSimon Glass debug("%s: Failed to set blocklen\n", __func__); 361272cc70bSAndy Fleming return 0; 36211692991SSimon Glass } 363272cc70bSAndy Fleming 3644a1a06bcSAlagu Sankar do { 36593bfd616SPantelis Antoniou cur = (blocks_todo > mmc->cfg->b_max) ? 36693bfd616SPantelis Antoniou mmc->cfg->b_max : blocks_todo; 36711692991SSimon Glass if (mmc_read_blocks(mmc, dst, start, cur) != cur) { 36811692991SSimon Glass debug("%s: Failed to read blocks\n", __func__); 3694a1a06bcSAlagu Sankar return 0; 37011692991SSimon Glass } 3714a1a06bcSAlagu Sankar blocks_todo -= cur; 3724a1a06bcSAlagu Sankar start += cur; 3734a1a06bcSAlagu Sankar dst += cur * mmc->read_bl_len; 3744a1a06bcSAlagu Sankar } while (blocks_todo > 0); 375272cc70bSAndy Fleming 376272cc70bSAndy Fleming return blkcnt; 377272cc70bSAndy Fleming } 378272cc70bSAndy Fleming 379fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc) 380272cc70bSAndy Fleming { 381272cc70bSAndy Fleming struct mmc_cmd cmd; 382272cc70bSAndy Fleming int err; 383272cc70bSAndy Fleming 384272cc70bSAndy Fleming udelay(1000); 385272cc70bSAndy Fleming 386272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_GO_IDLE_STATE; 387272cc70bSAndy Fleming cmd.cmdarg = 0; 388272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_NONE; 389272cc70bSAndy Fleming 390272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 391272cc70bSAndy Fleming 392272cc70bSAndy Fleming if (err) 393272cc70bSAndy Fleming return err; 394272cc70bSAndy Fleming 395272cc70bSAndy Fleming udelay(2000); 396272cc70bSAndy Fleming 397272cc70bSAndy Fleming return 0; 398272cc70bSAndy Fleming } 399272cc70bSAndy Fleming 400fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc) 401272cc70bSAndy Fleming { 402272cc70bSAndy Fleming int timeout = 1000; 403272cc70bSAndy Fleming int err; 404272cc70bSAndy Fleming struct mmc_cmd cmd; 405272cc70bSAndy Fleming 4061677eef4SAndrew Gabbasov while (1) { 407272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 408272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 409272cc70bSAndy Fleming cmd.cmdarg = 0; 410272cc70bSAndy Fleming 411272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 412272cc70bSAndy Fleming 413272cc70bSAndy Fleming if (err) 414272cc70bSAndy Fleming return err; 415272cc70bSAndy Fleming 416272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_OP_COND; 417272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R3; 418250de12bSStefano Babic 419250de12bSStefano Babic /* 420250de12bSStefano Babic * Most cards do not answer if some reserved bits 421250de12bSStefano Babic * in the ocr are set. However, Some controller 422250de12bSStefano Babic * can set bit 7 (reserved for low voltages), but 423250de12bSStefano Babic * how to manage low voltages SD card is not yet 424250de12bSStefano Babic * specified. 425250de12bSStefano Babic */ 426d52ebf10SThomas Chou cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 : 42793bfd616SPantelis Antoniou (mmc->cfg->voltages & 0xff8000); 428272cc70bSAndy Fleming 429272cc70bSAndy Fleming if (mmc->version == SD_VERSION_2) 430272cc70bSAndy Fleming cmd.cmdarg |= OCR_HCS; 431272cc70bSAndy Fleming 432272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 433272cc70bSAndy Fleming 434272cc70bSAndy Fleming if (err) 435272cc70bSAndy Fleming return err; 436272cc70bSAndy Fleming 4371677eef4SAndrew Gabbasov if (cmd.response[0] & OCR_BUSY) 4381677eef4SAndrew Gabbasov break; 439272cc70bSAndy Fleming 4401677eef4SAndrew Gabbasov if (timeout-- <= 0) 441915ffa52SJaehoon Chung return -EOPNOTSUPP; 442272cc70bSAndy Fleming 4431677eef4SAndrew Gabbasov udelay(1000); 4441677eef4SAndrew Gabbasov } 4451677eef4SAndrew Gabbasov 446272cc70bSAndy Fleming if (mmc->version != SD_VERSION_2) 447272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 448272cc70bSAndy Fleming 449d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 450d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 451d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 452d52ebf10SThomas Chou cmd.cmdarg = 0; 453d52ebf10SThomas Chou 454d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 455d52ebf10SThomas Chou 456d52ebf10SThomas Chou if (err) 457d52ebf10SThomas Chou return err; 458d52ebf10SThomas Chou } 459d52ebf10SThomas Chou 460998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 461272cc70bSAndy Fleming 462272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 463272cc70bSAndy Fleming mmc->rca = 0; 464272cc70bSAndy Fleming 465272cc70bSAndy Fleming return 0; 466272cc70bSAndy Fleming } 467272cc70bSAndy Fleming 4685289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg) 469272cc70bSAndy Fleming { 4705289b535SAndrew Gabbasov struct mmc_cmd cmd; 471272cc70bSAndy Fleming int err; 472272cc70bSAndy Fleming 4735289b535SAndrew Gabbasov cmd.cmdidx = MMC_CMD_SEND_OP_COND; 4745289b535SAndrew Gabbasov cmd.resp_type = MMC_RSP_R3; 4755289b535SAndrew Gabbasov cmd.cmdarg = 0; 4765a20397bSRob Herring if (use_arg && !mmc_host_is_spi(mmc)) 4775a20397bSRob Herring cmd.cmdarg = OCR_HCS | 47893bfd616SPantelis Antoniou (mmc->cfg->voltages & 479a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_VOLTAGE_MASK)) | 480a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_ACCESS_MODE); 481e9550449SChe-Liang Chiou 4825289b535SAndrew Gabbasov err = mmc_send_cmd(mmc, &cmd, NULL); 483e9550449SChe-Liang Chiou if (err) 484e9550449SChe-Liang Chiou return err; 4855289b535SAndrew Gabbasov mmc->ocr = cmd.response[0]; 486e9550449SChe-Liang Chiou return 0; 487e9550449SChe-Liang Chiou } 488e9550449SChe-Liang Chiou 489750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc) 490e9550449SChe-Liang Chiou { 491e9550449SChe-Liang Chiou int err, i; 492e9550449SChe-Liang Chiou 493272cc70bSAndy Fleming /* Some cards seem to need this */ 494272cc70bSAndy Fleming mmc_go_idle(mmc); 495272cc70bSAndy Fleming 49631cacbabSRaffaele Recalcati /* Asking to the card its capabilities */ 497e9550449SChe-Liang Chiou for (i = 0; i < 2; i++) { 4985289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, i != 0); 49931cacbabSRaffaele Recalcati if (err) 50031cacbabSRaffaele Recalcati return err; 50131cacbabSRaffaele Recalcati 502e9550449SChe-Liang Chiou /* exit if not busy (flag seems to be inverted) */ 503a626c8d4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 504bd47c135SAndrew Gabbasov break; 505e9550449SChe-Liang Chiou } 506bd47c135SAndrew Gabbasov mmc->op_cond_pending = 1; 507bd47c135SAndrew Gabbasov return 0; 508e9550449SChe-Liang Chiou } 50931cacbabSRaffaele Recalcati 510750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc) 511e9550449SChe-Liang Chiou { 512e9550449SChe-Liang Chiou struct mmc_cmd cmd; 513e9550449SChe-Liang Chiou int timeout = 1000; 514e9550449SChe-Liang Chiou uint start; 515e9550449SChe-Liang Chiou int err; 516e9550449SChe-Liang Chiou 517e9550449SChe-Liang Chiou mmc->op_cond_pending = 0; 518cc17c01fSAndrew Gabbasov if (!(mmc->ocr & OCR_BUSY)) { 519d188b113SYangbo Lu /* Some cards seem to need this */ 520d188b113SYangbo Lu mmc_go_idle(mmc); 521d188b113SYangbo Lu 522e9550449SChe-Liang Chiou start = get_timer(0); 5231677eef4SAndrew Gabbasov while (1) { 5245289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, 1); 525272cc70bSAndy Fleming if (err) 526272cc70bSAndy Fleming return err; 5271677eef4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 5281677eef4SAndrew Gabbasov break; 529e9550449SChe-Liang Chiou if (get_timer(start) > timeout) 530915ffa52SJaehoon Chung return -EOPNOTSUPP; 531e9550449SChe-Liang Chiou udelay(100); 5321677eef4SAndrew Gabbasov } 533cc17c01fSAndrew Gabbasov } 534272cc70bSAndy Fleming 535d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 536d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 537d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 538d52ebf10SThomas Chou cmd.cmdarg = 0; 539d52ebf10SThomas Chou 540d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 541d52ebf10SThomas Chou 542d52ebf10SThomas Chou if (err) 543d52ebf10SThomas Chou return err; 544a626c8d4SAndrew Gabbasov 545a626c8d4SAndrew Gabbasov mmc->ocr = cmd.response[0]; 546d52ebf10SThomas Chou } 547d52ebf10SThomas Chou 548272cc70bSAndy Fleming mmc->version = MMC_VERSION_UNKNOWN; 549272cc70bSAndy Fleming 550272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 551def816a2SStephen Warren mmc->rca = 1; 552272cc70bSAndy Fleming 553272cc70bSAndy Fleming return 0; 554272cc70bSAndy Fleming } 555272cc70bSAndy Fleming 556272cc70bSAndy Fleming 557fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) 558272cc70bSAndy Fleming { 559272cc70bSAndy Fleming struct mmc_cmd cmd; 560272cc70bSAndy Fleming struct mmc_data data; 561272cc70bSAndy Fleming int err; 562272cc70bSAndy Fleming 563272cc70bSAndy Fleming /* Get the Card Status Register */ 564272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_EXT_CSD; 565272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 566272cc70bSAndy Fleming cmd.cmdarg = 0; 567272cc70bSAndy Fleming 568cdfd1ac6SYoshihiro Shimoda data.dest = (char *)ext_csd; 569272cc70bSAndy Fleming data.blocks = 1; 5708bfa195eSSimon Glass data.blocksize = MMC_MAX_BLOCK_LEN; 571272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 572272cc70bSAndy Fleming 573272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 574272cc70bSAndy Fleming 575272cc70bSAndy Fleming return err; 576272cc70bSAndy Fleming } 577272cc70bSAndy Fleming 578c40704f4SSimon Glass int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) 579272cc70bSAndy Fleming { 580272cc70bSAndy Fleming struct mmc_cmd cmd; 5815d4fc8d9SRaffaele Recalcati int timeout = 1000; 582a9003dc6SMaxime Ripard int retries = 3; 5835d4fc8d9SRaffaele Recalcati int ret; 584272cc70bSAndy Fleming 585272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SWITCH; 586272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 587272cc70bSAndy Fleming cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 588272cc70bSAndy Fleming (index << 16) | 589272cc70bSAndy Fleming (value << 8); 590272cc70bSAndy Fleming 591a9003dc6SMaxime Ripard while (retries > 0) { 5925d4fc8d9SRaffaele Recalcati ret = mmc_send_cmd(mmc, &cmd, NULL); 5935d4fc8d9SRaffaele Recalcati 5945d4fc8d9SRaffaele Recalcati /* Waiting for the ready status */ 595a9003dc6SMaxime Ripard if (!ret) { 59693ad0d18SJan Kloetzke ret = mmc_send_status(mmc, timeout); 597a9003dc6SMaxime Ripard return ret; 598a9003dc6SMaxime Ripard } 599a9003dc6SMaxime Ripard 600a9003dc6SMaxime Ripard retries--; 601a9003dc6SMaxime Ripard } 6025d4fc8d9SRaffaele Recalcati 6035d4fc8d9SRaffaele Recalcati return ret; 6045d4fc8d9SRaffaele Recalcati 605272cc70bSAndy Fleming } 606272cc70bSAndy Fleming 607fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc) 608272cc70bSAndy Fleming { 6098bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 610272cc70bSAndy Fleming char cardtype; 611272cc70bSAndy Fleming int err; 612272cc70bSAndy Fleming 613fc5b32fbSAndrew Gabbasov mmc->card_caps = 0; 614272cc70bSAndy Fleming 615d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 616d52ebf10SThomas Chou return 0; 617d52ebf10SThomas Chou 618272cc70bSAndy Fleming /* Only version 4 supports high-speed */ 619272cc70bSAndy Fleming if (mmc->version < MMC_VERSION_4) 620272cc70bSAndy Fleming return 0; 621272cc70bSAndy Fleming 622fc5b32fbSAndrew Gabbasov mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; 623fc5b32fbSAndrew Gabbasov 624272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 625272cc70bSAndy Fleming 626272cc70bSAndy Fleming if (err) 627272cc70bSAndy Fleming return err; 628272cc70bSAndy Fleming 6290560db18SLei Wen cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf; 630272cc70bSAndy Fleming 631272cc70bSAndy Fleming err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1); 632272cc70bSAndy Fleming 633272cc70bSAndy Fleming if (err) 634a5e27b41SHeiko Schocher return err; 635272cc70bSAndy Fleming 636272cc70bSAndy Fleming /* Now check to see that it worked */ 637272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 638272cc70bSAndy Fleming 639272cc70bSAndy Fleming if (err) 640272cc70bSAndy Fleming return err; 641272cc70bSAndy Fleming 642272cc70bSAndy Fleming /* No high-speed support */ 6430560db18SLei Wen if (!ext_csd[EXT_CSD_HS_TIMING]) 644272cc70bSAndy Fleming return 0; 645272cc70bSAndy Fleming 646272cc70bSAndy Fleming /* High Speed is set, there are two types: 52MHz and 26MHz */ 647d22e3d46SJaehoon Chung if (cardtype & EXT_CSD_CARD_TYPE_52) { 648201d5ac4SAndrew Gabbasov if (cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V) 649d22e3d46SJaehoon Chung mmc->card_caps |= MMC_MODE_DDR_52MHz; 650272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; 651d22e3d46SJaehoon Chung } else { 652272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS; 653d22e3d46SJaehoon Chung } 654272cc70bSAndy Fleming 655272cc70bSAndy Fleming return 0; 656272cc70bSAndy Fleming } 657272cc70bSAndy Fleming 658f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num) 659f866a46dSStephen Warren { 660f866a46dSStephen Warren switch (part_num) { 661f866a46dSStephen Warren case 0: 662f866a46dSStephen Warren mmc->capacity = mmc->capacity_user; 663f866a46dSStephen Warren break; 664f866a46dSStephen Warren case 1: 665f866a46dSStephen Warren case 2: 666f866a46dSStephen Warren mmc->capacity = mmc->capacity_boot; 667f866a46dSStephen Warren break; 668f866a46dSStephen Warren case 3: 669f866a46dSStephen Warren mmc->capacity = mmc->capacity_rpmb; 670f866a46dSStephen Warren break; 671f866a46dSStephen Warren case 4: 672f866a46dSStephen Warren case 5: 673f866a46dSStephen Warren case 6: 674f866a46dSStephen Warren case 7: 675f866a46dSStephen Warren mmc->capacity = mmc->capacity_gp[part_num - 4]; 676f866a46dSStephen Warren break; 677f866a46dSStephen Warren default: 678f866a46dSStephen Warren return -1; 679f866a46dSStephen Warren } 680f866a46dSStephen Warren 681c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len); 682f866a46dSStephen Warren 683f866a46dSStephen Warren return 0; 684f866a46dSStephen Warren } 685f866a46dSStephen Warren 6867dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num) 687bc897b1dSLei Wen { 688f866a46dSStephen Warren int ret; 689bc897b1dSLei Wen 690f866a46dSStephen Warren ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 691bc897b1dSLei Wen (mmc->part_config & ~PART_ACCESS_MASK) 692bc897b1dSLei Wen | (part_num & PART_ACCESS_MASK)); 693f866a46dSStephen Warren 6946dc93e70SPeter Bigot /* 6956dc93e70SPeter Bigot * Set the capacity if the switch succeeded or was intended 6966dc93e70SPeter Bigot * to return to representing the raw device. 6976dc93e70SPeter Bigot */ 698873cc1d7SStephen Warren if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) { 6996dc93e70SPeter Bigot ret = mmc_set_capacity(mmc, part_num); 700fdbb139fSSimon Glass mmc_get_blk_desc(mmc)->hwpart = part_num; 701873cc1d7SStephen Warren } 7026dc93e70SPeter Bigot 7036dc93e70SPeter Bigot return ret; 704bc897b1dSLei Wen } 705bc897b1dSLei Wen 706ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc, 707ac9da0e0SDiego Santa Cruz const struct mmc_hwpart_conf *conf, 708ac9da0e0SDiego Santa Cruz enum mmc_hwpart_conf_mode mode) 709ac9da0e0SDiego Santa Cruz { 710ac9da0e0SDiego Santa Cruz u8 part_attrs = 0; 711ac9da0e0SDiego Santa Cruz u32 enh_size_mult; 712ac9da0e0SDiego Santa Cruz u32 enh_start_addr; 713ac9da0e0SDiego Santa Cruz u32 gp_size_mult[4]; 714ac9da0e0SDiego Santa Cruz u32 max_enh_size_mult; 715ac9da0e0SDiego Santa Cruz u32 tot_enh_size_mult = 0; 7168dda5b0eSDiego Santa Cruz u8 wr_rel_set; 717ac9da0e0SDiego Santa Cruz int i, pidx, err; 718ac9da0e0SDiego Santa Cruz ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 719ac9da0e0SDiego Santa Cruz 720ac9da0e0SDiego Santa Cruz if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE) 721ac9da0e0SDiego Santa Cruz return -EINVAL; 722ac9da0e0SDiego Santa Cruz 723ac9da0e0SDiego Santa Cruz if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) { 724ac9da0e0SDiego Santa Cruz printf("eMMC >= 4.4 required for enhanced user data area\n"); 725ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 726ac9da0e0SDiego Santa Cruz } 727ac9da0e0SDiego Santa Cruz 728ac9da0e0SDiego Santa Cruz if (!(mmc->part_support & PART_SUPPORT)) { 729ac9da0e0SDiego Santa Cruz printf("Card does not support partitioning\n"); 730ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 731ac9da0e0SDiego Santa Cruz } 732ac9da0e0SDiego Santa Cruz 733ac9da0e0SDiego Santa Cruz if (!mmc->hc_wp_grp_size) { 734ac9da0e0SDiego Santa Cruz printf("Card does not define HC WP group size\n"); 735ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 736ac9da0e0SDiego Santa Cruz } 737ac9da0e0SDiego Santa Cruz 738ac9da0e0SDiego Santa Cruz /* check partition alignment and total enhanced size */ 739ac9da0e0SDiego Santa Cruz if (conf->user.enh_size) { 740ac9da0e0SDiego Santa Cruz if (conf->user.enh_size % mmc->hc_wp_grp_size || 741ac9da0e0SDiego Santa Cruz conf->user.enh_start % mmc->hc_wp_grp_size) { 742ac9da0e0SDiego Santa Cruz printf("User data enhanced area not HC WP group " 743ac9da0e0SDiego Santa Cruz "size aligned\n"); 744ac9da0e0SDiego Santa Cruz return -EINVAL; 745ac9da0e0SDiego Santa Cruz } 746ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_USR; 747ac9da0e0SDiego Santa Cruz enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size; 748ac9da0e0SDiego Santa Cruz if (mmc->high_capacity) { 749ac9da0e0SDiego Santa Cruz enh_start_addr = conf->user.enh_start; 750ac9da0e0SDiego Santa Cruz } else { 751ac9da0e0SDiego Santa Cruz enh_start_addr = (conf->user.enh_start << 9); 752ac9da0e0SDiego Santa Cruz } 753ac9da0e0SDiego Santa Cruz } else { 754ac9da0e0SDiego Santa Cruz enh_size_mult = 0; 755ac9da0e0SDiego Santa Cruz enh_start_addr = 0; 756ac9da0e0SDiego Santa Cruz } 757ac9da0e0SDiego Santa Cruz tot_enh_size_mult += enh_size_mult; 758ac9da0e0SDiego Santa Cruz 759ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 760ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) { 761ac9da0e0SDiego Santa Cruz printf("GP%i partition not HC WP group size " 762ac9da0e0SDiego Santa Cruz "aligned\n", pidx+1); 763ac9da0e0SDiego Santa Cruz return -EINVAL; 764ac9da0e0SDiego Santa Cruz } 765ac9da0e0SDiego Santa Cruz gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size; 766ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) { 767ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_GP(pidx); 768ac9da0e0SDiego Santa Cruz tot_enh_size_mult += gp_size_mult[pidx]; 769ac9da0e0SDiego Santa Cruz } 770ac9da0e0SDiego Santa Cruz } 771ac9da0e0SDiego Santa Cruz 772ac9da0e0SDiego Santa Cruz if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) { 773ac9da0e0SDiego Santa Cruz printf("Card does not support enhanced attribute\n"); 774ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 775ac9da0e0SDiego Santa Cruz } 776ac9da0e0SDiego Santa Cruz 777ac9da0e0SDiego Santa Cruz err = mmc_send_ext_csd(mmc, ext_csd); 778ac9da0e0SDiego Santa Cruz if (err) 779ac9da0e0SDiego Santa Cruz return err; 780ac9da0e0SDiego Santa Cruz 781ac9da0e0SDiego Santa Cruz max_enh_size_mult = 782ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) + 783ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) + 784ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]; 785ac9da0e0SDiego Santa Cruz if (tot_enh_size_mult > max_enh_size_mult) { 786ac9da0e0SDiego Santa Cruz printf("Total enhanced size exceeds maximum (%u > %u)\n", 787ac9da0e0SDiego Santa Cruz tot_enh_size_mult, max_enh_size_mult); 788ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 789ac9da0e0SDiego Santa Cruz } 790ac9da0e0SDiego Santa Cruz 7918dda5b0eSDiego Santa Cruz /* The default value of EXT_CSD_WR_REL_SET is device 7928dda5b0eSDiego Santa Cruz * dependent, the values can only be changed if the 7938dda5b0eSDiego Santa Cruz * EXT_CSD_HS_CTRL_REL bit is set. The values can be 7948dda5b0eSDiego Santa Cruz * changed only once and before partitioning is completed. */ 7958dda5b0eSDiego Santa Cruz wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 7968dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_change) { 7978dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_set) 7988dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_USR; 7998dda5b0eSDiego Santa Cruz else 8008dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR; 8018dda5b0eSDiego Santa Cruz } 8028dda5b0eSDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 8038dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_change) { 8048dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_set) 8058dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx); 8068dda5b0eSDiego Santa Cruz else 8078dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx); 8088dda5b0eSDiego Santa Cruz } 8098dda5b0eSDiego Santa Cruz } 8108dda5b0eSDiego Santa Cruz 8118dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] && 8128dda5b0eSDiego Santa Cruz !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) { 8138dda5b0eSDiego Santa Cruz puts("Card does not support host controlled partition write " 8148dda5b0eSDiego Santa Cruz "reliability settings\n"); 8158dda5b0eSDiego Santa Cruz return -EMEDIUMTYPE; 8168dda5b0eSDiego Santa Cruz } 8178dda5b0eSDiego Santa Cruz 818ac9da0e0SDiego Santa Cruz if (ext_csd[EXT_CSD_PARTITION_SETTING] & 819ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED) { 820ac9da0e0SDiego Santa Cruz printf("Card already partitioned\n"); 821ac9da0e0SDiego Santa Cruz return -EPERM; 822ac9da0e0SDiego Santa Cruz } 823ac9da0e0SDiego Santa Cruz 824ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_CHECK) 825ac9da0e0SDiego Santa Cruz return 0; 826ac9da0e0SDiego Santa Cruz 827ac9da0e0SDiego Santa Cruz /* Partitioning requires high-capacity size definitions */ 828ac9da0e0SDiego Santa Cruz if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) { 829ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 830ac9da0e0SDiego Santa Cruz EXT_CSD_ERASE_GROUP_DEF, 1); 831ac9da0e0SDiego Santa Cruz 832ac9da0e0SDiego Santa Cruz if (err) 833ac9da0e0SDiego Santa Cruz return err; 834ac9da0e0SDiego Santa Cruz 835ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 836ac9da0e0SDiego Santa Cruz 837ac9da0e0SDiego Santa Cruz /* update erase group size to be high-capacity */ 838ac9da0e0SDiego Santa Cruz mmc->erase_grp_size = 839ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 840ac9da0e0SDiego Santa Cruz 841ac9da0e0SDiego Santa Cruz } 842ac9da0e0SDiego Santa Cruz 843ac9da0e0SDiego Santa Cruz /* all OK, write the configuration */ 844ac9da0e0SDiego Santa Cruz for (i = 0; i < 4; i++) { 845ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 846ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_START_ADDR+i, 847ac9da0e0SDiego Santa Cruz (enh_start_addr >> (i*8)) & 0xFF); 848ac9da0e0SDiego Santa Cruz if (err) 849ac9da0e0SDiego Santa Cruz return err; 850ac9da0e0SDiego Santa Cruz } 851ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 852ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 853ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_SIZE_MULT+i, 854ac9da0e0SDiego Santa Cruz (enh_size_mult >> (i*8)) & 0xFF); 855ac9da0e0SDiego Santa Cruz if (err) 856ac9da0e0SDiego Santa Cruz return err; 857ac9da0e0SDiego Santa Cruz } 858ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 859ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 860ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 861ac9da0e0SDiego Santa Cruz EXT_CSD_GP_SIZE_MULT+pidx*3+i, 862ac9da0e0SDiego Santa Cruz (gp_size_mult[pidx] >> (i*8)) & 0xFF); 863ac9da0e0SDiego Santa Cruz if (err) 864ac9da0e0SDiego Santa Cruz return err; 865ac9da0e0SDiego Santa Cruz } 866ac9da0e0SDiego Santa Cruz } 867ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 868ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs); 869ac9da0e0SDiego Santa Cruz if (err) 870ac9da0e0SDiego Santa Cruz return err; 871ac9da0e0SDiego Santa Cruz 872ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_SET) 873ac9da0e0SDiego Santa Cruz return 0; 874ac9da0e0SDiego Santa Cruz 8758dda5b0eSDiego Santa Cruz /* The WR_REL_SET is a write-once register but shall be 8768dda5b0eSDiego Santa Cruz * written before setting PART_SETTING_COMPLETED. As it is 8778dda5b0eSDiego Santa Cruz * write-once we can only write it when completing the 8788dda5b0eSDiego Santa Cruz * partitioning. */ 8798dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) { 8808dda5b0eSDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 8818dda5b0eSDiego Santa Cruz EXT_CSD_WR_REL_SET, wr_rel_set); 8828dda5b0eSDiego Santa Cruz if (err) 8838dda5b0eSDiego Santa Cruz return err; 8848dda5b0eSDiego Santa Cruz } 8858dda5b0eSDiego Santa Cruz 886ac9da0e0SDiego Santa Cruz /* Setting PART_SETTING_COMPLETED confirms the partition 887ac9da0e0SDiego Santa Cruz * configuration but it only becomes effective after power 888ac9da0e0SDiego Santa Cruz * cycle, so we do not adjust the partition related settings 889ac9da0e0SDiego Santa Cruz * in the mmc struct. */ 890ac9da0e0SDiego Santa Cruz 891ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 892ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING, 893ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 894ac9da0e0SDiego Santa Cruz if (err) 895ac9da0e0SDiego Santa Cruz return err; 896ac9da0e0SDiego Santa Cruz 897ac9da0e0SDiego Santa Cruz return 0; 898ac9da0e0SDiego Santa Cruz } 899ac9da0e0SDiego Santa Cruz 900e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 90148972d90SThierry Reding int mmc_getcd(struct mmc *mmc) 90248972d90SThierry Reding { 90348972d90SThierry Reding int cd; 90448972d90SThierry Reding 90548972d90SThierry Reding cd = board_mmc_getcd(mmc); 90648972d90SThierry Reding 907d4e1da4eSPeter Korsgaard if (cd < 0) { 90893bfd616SPantelis Antoniou if (mmc->cfg->ops->getcd) 90993bfd616SPantelis Antoniou cd = mmc->cfg->ops->getcd(mmc); 910d4e1da4eSPeter Korsgaard else 911d4e1da4eSPeter Korsgaard cd = 1; 912d4e1da4eSPeter Korsgaard } 91348972d90SThierry Reding 91448972d90SThierry Reding return cd; 91548972d90SThierry Reding } 9168ca51e51SSimon Glass #endif 91748972d90SThierry Reding 918fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) 919272cc70bSAndy Fleming { 920272cc70bSAndy Fleming struct mmc_cmd cmd; 921272cc70bSAndy Fleming struct mmc_data data; 922272cc70bSAndy Fleming 923272cc70bSAndy Fleming /* Switch the frequency */ 924272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC; 925272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 926272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff; 927272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4)); 928272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4); 929272cc70bSAndy Fleming 930272cc70bSAndy Fleming data.dest = (char *)resp; 931272cc70bSAndy Fleming data.blocksize = 64; 932272cc70bSAndy Fleming data.blocks = 1; 933272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 934272cc70bSAndy Fleming 935272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 936272cc70bSAndy Fleming } 937272cc70bSAndy Fleming 938272cc70bSAndy Fleming 939fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc) 940272cc70bSAndy Fleming { 941272cc70bSAndy Fleming int err; 942272cc70bSAndy Fleming struct mmc_cmd cmd; 94318e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2); 94418e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16); 945272cc70bSAndy Fleming struct mmc_data data; 946272cc70bSAndy Fleming int timeout; 947272cc70bSAndy Fleming 948272cc70bSAndy Fleming mmc->card_caps = 0; 949272cc70bSAndy Fleming 950d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 951d52ebf10SThomas Chou return 0; 952d52ebf10SThomas Chou 953272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */ 954272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 955272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 956272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 957272cc70bSAndy Fleming 958272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 959272cc70bSAndy Fleming 960272cc70bSAndy Fleming if (err) 961272cc70bSAndy Fleming return err; 962272cc70bSAndy Fleming 963272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR; 964272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 965272cc70bSAndy Fleming cmd.cmdarg = 0; 966272cc70bSAndy Fleming 967272cc70bSAndy Fleming timeout = 3; 968272cc70bSAndy Fleming 969272cc70bSAndy Fleming retry_scr: 970f781dd38SAnton staaf data.dest = (char *)scr; 971272cc70bSAndy Fleming data.blocksize = 8; 972272cc70bSAndy Fleming data.blocks = 1; 973272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 974272cc70bSAndy Fleming 975272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 976272cc70bSAndy Fleming 977272cc70bSAndy Fleming if (err) { 978272cc70bSAndy Fleming if (timeout--) 979272cc70bSAndy Fleming goto retry_scr; 980272cc70bSAndy Fleming 981272cc70bSAndy Fleming return err; 982272cc70bSAndy Fleming } 983272cc70bSAndy Fleming 9844e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]); 9854e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]); 986272cc70bSAndy Fleming 987272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) { 988272cc70bSAndy Fleming case 0: 989272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 990272cc70bSAndy Fleming break; 991272cc70bSAndy Fleming case 1: 992272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10; 993272cc70bSAndy Fleming break; 994272cc70bSAndy Fleming case 2: 995272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 9961741c64dSJaehoon Chung if ((mmc->scr[0] >> 15) & 0x1) 9971741c64dSJaehoon Chung mmc->version = SD_VERSION_3; 998272cc70bSAndy Fleming break; 999272cc70bSAndy Fleming default: 1000272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1001272cc70bSAndy Fleming break; 1002272cc70bSAndy Fleming } 1003272cc70bSAndy Fleming 1004b44c7083SAlagu Sankar if (mmc->scr[0] & SD_DATA_4BIT) 1005b44c7083SAlagu Sankar mmc->card_caps |= MMC_MODE_4BIT; 1006b44c7083SAlagu Sankar 1007272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */ 1008272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0) 1009272cc70bSAndy Fleming return 0; 1010272cc70bSAndy Fleming 1011272cc70bSAndy Fleming timeout = 4; 1012272cc70bSAndy Fleming while (timeout--) { 1013272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, 1014f781dd38SAnton staaf (u8 *)switch_status); 1015272cc70bSAndy Fleming 1016272cc70bSAndy Fleming if (err) 1017272cc70bSAndy Fleming return err; 1018272cc70bSAndy Fleming 1019272cc70bSAndy Fleming /* The high-speed function is busy. Try again */ 10204e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) 1021272cc70bSAndy Fleming break; 1022272cc70bSAndy Fleming } 1023272cc70bSAndy Fleming 1024272cc70bSAndy Fleming /* If high-speed isn't supported, we return */ 10254e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)) 1026272cc70bSAndy Fleming return 0; 1027272cc70bSAndy Fleming 10282c3fbf4cSMacpaul Lin /* 10292c3fbf4cSMacpaul Lin * If the host doesn't support SD_HIGHSPEED, do not switch card to 10302c3fbf4cSMacpaul Lin * HIGHSPEED mode even if the card support SD_HIGHSPPED. 10312c3fbf4cSMacpaul Lin * This can avoid furthur problem when the card runs in different 10322c3fbf4cSMacpaul Lin * mode between the host. 10332c3fbf4cSMacpaul Lin */ 103493bfd616SPantelis Antoniou if (!((mmc->cfg->host_caps & MMC_MODE_HS_52MHz) && 103593bfd616SPantelis Antoniou (mmc->cfg->host_caps & MMC_MODE_HS))) 10362c3fbf4cSMacpaul Lin return 0; 10372c3fbf4cSMacpaul Lin 1038f781dd38SAnton staaf err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status); 1039272cc70bSAndy Fleming 1040272cc70bSAndy Fleming if (err) 1041272cc70bSAndy Fleming return err; 1042272cc70bSAndy Fleming 10434e3d89baSYauhen Kharuzhy if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000) 1044272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS; 1045272cc70bSAndy Fleming 1046272cc70bSAndy Fleming return 0; 1047272cc70bSAndy Fleming } 1048272cc70bSAndy Fleming 10493697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc) 10503697e599SPeng Fan { 10513697e599SPeng Fan int err, i; 10523697e599SPeng Fan struct mmc_cmd cmd; 10533697e599SPeng Fan ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16); 10543697e599SPeng Fan struct mmc_data data; 10553697e599SPeng Fan int timeout = 3; 10563697e599SPeng Fan unsigned int au, eo, et, es; 10573697e599SPeng Fan 10583697e599SPeng Fan cmd.cmdidx = MMC_CMD_APP_CMD; 10593697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 10603697e599SPeng Fan cmd.cmdarg = mmc->rca << 16; 10613697e599SPeng Fan 10623697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, NULL); 10633697e599SPeng Fan if (err) 10643697e599SPeng Fan return err; 10653697e599SPeng Fan 10663697e599SPeng Fan cmd.cmdidx = SD_CMD_APP_SD_STATUS; 10673697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 10683697e599SPeng Fan cmd.cmdarg = 0; 10693697e599SPeng Fan 10703697e599SPeng Fan retry_ssr: 10713697e599SPeng Fan data.dest = (char *)ssr; 10723697e599SPeng Fan data.blocksize = 64; 10733697e599SPeng Fan data.blocks = 1; 10743697e599SPeng Fan data.flags = MMC_DATA_READ; 10753697e599SPeng Fan 10763697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, &data); 10773697e599SPeng Fan if (err) { 10783697e599SPeng Fan if (timeout--) 10793697e599SPeng Fan goto retry_ssr; 10803697e599SPeng Fan 10813697e599SPeng Fan return err; 10823697e599SPeng Fan } 10833697e599SPeng Fan 10843697e599SPeng Fan for (i = 0; i < 16; i++) 10853697e599SPeng Fan ssr[i] = be32_to_cpu(ssr[i]); 10863697e599SPeng Fan 10873697e599SPeng Fan au = (ssr[2] >> 12) & 0xF; 10883697e599SPeng Fan if ((au <= 9) || (mmc->version == SD_VERSION_3)) { 10893697e599SPeng Fan mmc->ssr.au = sd_au_size[au]; 10903697e599SPeng Fan es = (ssr[3] >> 24) & 0xFF; 10913697e599SPeng Fan es |= (ssr[2] & 0xFF) << 8; 10923697e599SPeng Fan et = (ssr[3] >> 18) & 0x3F; 10933697e599SPeng Fan if (es && et) { 10943697e599SPeng Fan eo = (ssr[3] >> 16) & 0x3; 10953697e599SPeng Fan mmc->ssr.erase_timeout = (et * 1000) / es; 10963697e599SPeng Fan mmc->ssr.erase_offset = eo * 1000; 10973697e599SPeng Fan } 10983697e599SPeng Fan } else { 10993697e599SPeng Fan debug("Invalid Allocation Unit Size.\n"); 11003697e599SPeng Fan } 11013697e599SPeng Fan 11023697e599SPeng Fan return 0; 11033697e599SPeng Fan } 11043697e599SPeng Fan 1105272cc70bSAndy Fleming /* frequency bases */ 1106272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */ 11075f837c2cSMike Frysinger static const int fbase[] = { 1108272cc70bSAndy Fleming 10000, 1109272cc70bSAndy Fleming 100000, 1110272cc70bSAndy Fleming 1000000, 1111272cc70bSAndy Fleming 10000000, 1112272cc70bSAndy Fleming }; 1113272cc70bSAndy Fleming 1114272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice 1115272cc70bSAndy Fleming * to platforms without floating point. 1116272cc70bSAndy Fleming */ 111761fe076fSSimon Glass static const u8 multipliers[] = { 1118272cc70bSAndy Fleming 0, /* reserved */ 1119272cc70bSAndy Fleming 10, 1120272cc70bSAndy Fleming 12, 1121272cc70bSAndy Fleming 13, 1122272cc70bSAndy Fleming 15, 1123272cc70bSAndy Fleming 20, 1124272cc70bSAndy Fleming 25, 1125272cc70bSAndy Fleming 30, 1126272cc70bSAndy Fleming 35, 1127272cc70bSAndy Fleming 40, 1128272cc70bSAndy Fleming 45, 1129272cc70bSAndy Fleming 50, 1130272cc70bSAndy Fleming 55, 1131272cc70bSAndy Fleming 60, 1132272cc70bSAndy Fleming 70, 1133272cc70bSAndy Fleming 80, 1134272cc70bSAndy Fleming }; 1135272cc70bSAndy Fleming 1136e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 1137fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc) 1138272cc70bSAndy Fleming { 113993bfd616SPantelis Antoniou if (mmc->cfg->ops->set_ios) 114093bfd616SPantelis Antoniou mmc->cfg->ops->set_ios(mmc); 1141272cc70bSAndy Fleming } 11428ca51e51SSimon Glass #endif 1143272cc70bSAndy Fleming 1144272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock) 1145272cc70bSAndy Fleming { 114693bfd616SPantelis Antoniou if (clock > mmc->cfg->f_max) 114793bfd616SPantelis Antoniou clock = mmc->cfg->f_max; 1148272cc70bSAndy Fleming 114993bfd616SPantelis Antoniou if (clock < mmc->cfg->f_min) 115093bfd616SPantelis Antoniou clock = mmc->cfg->f_min; 1151272cc70bSAndy Fleming 1152272cc70bSAndy Fleming mmc->clock = clock; 1153272cc70bSAndy Fleming 1154272cc70bSAndy Fleming mmc_set_ios(mmc); 1155272cc70bSAndy Fleming } 1156272cc70bSAndy Fleming 1157fdbb873eSKim Phillips static void mmc_set_bus_width(struct mmc *mmc, uint width) 1158272cc70bSAndy Fleming { 1159272cc70bSAndy Fleming mmc->bus_width = width; 1160272cc70bSAndy Fleming 1161272cc70bSAndy Fleming mmc_set_ios(mmc); 1162272cc70bSAndy Fleming } 1163272cc70bSAndy Fleming 11644c9d2aaaSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG) 11654c9d2aaaSJean-Jacques Hiblot /* 11664c9d2aaaSJean-Jacques Hiblot * helper function to display the capabilities in a human 11674c9d2aaaSJean-Jacques Hiblot * friendly manner. The capabilities include bus width and 11684c9d2aaaSJean-Jacques Hiblot * supported modes. 11694c9d2aaaSJean-Jacques Hiblot */ 11704c9d2aaaSJean-Jacques Hiblot void mmc_dump_capabilities(const char *text, uint caps) 11714c9d2aaaSJean-Jacques Hiblot { 11724c9d2aaaSJean-Jacques Hiblot enum bus_mode mode; 11734c9d2aaaSJean-Jacques Hiblot 11744c9d2aaaSJean-Jacques Hiblot printf("%s: widths [", text); 11754c9d2aaaSJean-Jacques Hiblot if (caps & MMC_MODE_8BIT) 11764c9d2aaaSJean-Jacques Hiblot printf("8, "); 11774c9d2aaaSJean-Jacques Hiblot if (caps & MMC_MODE_4BIT) 11784c9d2aaaSJean-Jacques Hiblot printf("4, "); 11794c9d2aaaSJean-Jacques Hiblot printf("1] modes ["); 11804c9d2aaaSJean-Jacques Hiblot 11814c9d2aaaSJean-Jacques Hiblot for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++) 11824c9d2aaaSJean-Jacques Hiblot if (MMC_CAP(mode) & caps) 11834c9d2aaaSJean-Jacques Hiblot printf("%s, ", mmc_mode_name(mode)); 11844c9d2aaaSJean-Jacques Hiblot printf("\b\b]\n"); 11854c9d2aaaSJean-Jacques Hiblot } 11864c9d2aaaSJean-Jacques Hiblot #endif 11874c9d2aaaSJean-Jacques Hiblot 11888ac8a263SJean-Jacques Hiblot static int sd_select_bus_freq_width(struct mmc *mmc) 11898ac8a263SJean-Jacques Hiblot { 11908ac8a263SJean-Jacques Hiblot int err; 11918ac8a263SJean-Jacques Hiblot struct mmc_cmd cmd; 11928ac8a263SJean-Jacques Hiblot 11938ac8a263SJean-Jacques Hiblot err = sd_change_freq(mmc); 11948ac8a263SJean-Jacques Hiblot if (err) 11958ac8a263SJean-Jacques Hiblot return err; 11968ac8a263SJean-Jacques Hiblot 11978ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */ 11988ac8a263SJean-Jacques Hiblot mmc->card_caps &= mmc->cfg->host_caps; 11998ac8a263SJean-Jacques Hiblot 12008ac8a263SJean-Jacques Hiblot if (mmc->card_caps & MMC_MODE_4BIT) { 12018ac8a263SJean-Jacques Hiblot cmd.cmdidx = MMC_CMD_APP_CMD; 12028ac8a263SJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 12038ac8a263SJean-Jacques Hiblot cmd.cmdarg = mmc->rca << 16; 12048ac8a263SJean-Jacques Hiblot 12058ac8a263SJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 12068ac8a263SJean-Jacques Hiblot if (err) 12078ac8a263SJean-Jacques Hiblot return err; 12088ac8a263SJean-Jacques Hiblot 12098ac8a263SJean-Jacques Hiblot cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; 12108ac8a263SJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 12118ac8a263SJean-Jacques Hiblot cmd.cmdarg = 2; 12128ac8a263SJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 12138ac8a263SJean-Jacques Hiblot if (err) 12148ac8a263SJean-Jacques Hiblot return err; 12158ac8a263SJean-Jacques Hiblot 12168ac8a263SJean-Jacques Hiblot mmc_set_bus_width(mmc, 4); 12178ac8a263SJean-Jacques Hiblot } 12188ac8a263SJean-Jacques Hiblot 12198ac8a263SJean-Jacques Hiblot err = sd_read_ssr(mmc); 12208ac8a263SJean-Jacques Hiblot if (err) 12218ac8a263SJean-Jacques Hiblot return err; 12228ac8a263SJean-Jacques Hiblot 1223*05038576SJean-Jacques Hiblot if (mmc->card_caps & MMC_MODE_HS) 122435f9e196SJean-Jacques Hiblot mmc_select_mode(mmc, SD_HS); 1225*05038576SJean-Jacques Hiblot else 122635f9e196SJean-Jacques Hiblot mmc_select_mode(mmc, SD_LEGACY); 12278ac8a263SJean-Jacques Hiblot 12288ac8a263SJean-Jacques Hiblot return 0; 12298ac8a263SJean-Jacques Hiblot } 12308ac8a263SJean-Jacques Hiblot 12317382e691SJean-Jacques Hiblot /* 12327382e691SJean-Jacques Hiblot * read the compare the part of ext csd that is constant. 12337382e691SJean-Jacques Hiblot * This can be used to check that the transfer is working 12347382e691SJean-Jacques Hiblot * as expected. 12357382e691SJean-Jacques Hiblot */ 12367382e691SJean-Jacques Hiblot static int mmc_read_and_compare_ext_csd(struct mmc *mmc) 12377382e691SJean-Jacques Hiblot { 12387382e691SJean-Jacques Hiblot int err; 12397382e691SJean-Jacques Hiblot const u8 *ext_csd = mmc->ext_csd; 12407382e691SJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 12417382e691SJean-Jacques Hiblot 12427382e691SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, test_csd); 12437382e691SJean-Jacques Hiblot if (err) 12447382e691SJean-Jacques Hiblot return err; 12457382e691SJean-Jacques Hiblot 12467382e691SJean-Jacques Hiblot /* Only compare read only fields */ 12477382e691SJean-Jacques Hiblot if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] 12487382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_PARTITIONING_SUPPORT] && 12497382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_WP_GRP_SIZE] 12507382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_WP_GRP_SIZE] && 12517382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_REV] 12527382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_REV] && 12537382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 12547382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] && 12557382e691SJean-Jacques Hiblot memcmp(&ext_csd[EXT_CSD_SEC_CNT], 12567382e691SJean-Jacques Hiblot &test_csd[EXT_CSD_SEC_CNT], 4) == 0) 12577382e691SJean-Jacques Hiblot return 0; 12587382e691SJean-Jacques Hiblot 12597382e691SJean-Jacques Hiblot return -EBADMSG; 12607382e691SJean-Jacques Hiblot } 12617382e691SJean-Jacques Hiblot 1262dfda9d88SJean-Jacques Hiblot static int mmc_select_bus_freq_width(struct mmc *mmc) 12638ac8a263SJean-Jacques Hiblot { 12648ac8a263SJean-Jacques Hiblot /* An array of possible bus widths in order of preference */ 12658ac8a263SJean-Jacques Hiblot static const unsigned int ext_csd_bits[] = { 12668ac8a263SJean-Jacques Hiblot EXT_CSD_DDR_BUS_WIDTH_8, 12678ac8a263SJean-Jacques Hiblot EXT_CSD_DDR_BUS_WIDTH_4, 12688ac8a263SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH_8, 12698ac8a263SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH_4, 12708ac8a263SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH_1, 12718ac8a263SJean-Jacques Hiblot }; 12728ac8a263SJean-Jacques Hiblot /* An array to map CSD bus widths to host cap bits */ 12738ac8a263SJean-Jacques Hiblot static const unsigned int ext_to_hostcaps[] = { 12748ac8a263SJean-Jacques Hiblot [EXT_CSD_DDR_BUS_WIDTH_4] = 12758ac8a263SJean-Jacques Hiblot MMC_MODE_DDR_52MHz | MMC_MODE_4BIT, 12768ac8a263SJean-Jacques Hiblot [EXT_CSD_DDR_BUS_WIDTH_8] = 12778ac8a263SJean-Jacques Hiblot MMC_MODE_DDR_52MHz | MMC_MODE_8BIT, 12788ac8a263SJean-Jacques Hiblot [EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT, 12798ac8a263SJean-Jacques Hiblot [EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT, 12808ac8a263SJean-Jacques Hiblot }; 12818ac8a263SJean-Jacques Hiblot /* An array to map chosen bus width to an integer */ 12828ac8a263SJean-Jacques Hiblot static const unsigned int widths[] = { 12838ac8a263SJean-Jacques Hiblot 8, 4, 8, 4, 1, 12848ac8a263SJean-Jacques Hiblot }; 12858ac8a263SJean-Jacques Hiblot int err; 12868ac8a263SJean-Jacques Hiblot int idx; 12878ac8a263SJean-Jacques Hiblot 12888ac8a263SJean-Jacques Hiblot err = mmc_change_freq(mmc); 12898ac8a263SJean-Jacques Hiblot if (err) 12908ac8a263SJean-Jacques Hiblot return err; 12918ac8a263SJean-Jacques Hiblot 12928ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */ 12938ac8a263SJean-Jacques Hiblot mmc->card_caps &= mmc->cfg->host_caps; 12948ac8a263SJean-Jacques Hiblot 12958ac8a263SJean-Jacques Hiblot /* Only version 4 of MMC supports wider bus widths */ 12968ac8a263SJean-Jacques Hiblot if (mmc->version < MMC_VERSION_4) 12978ac8a263SJean-Jacques Hiblot return 0; 12988ac8a263SJean-Jacques Hiblot 1299dfda9d88SJean-Jacques Hiblot if (!mmc->ext_csd) { 1300dfda9d88SJean-Jacques Hiblot debug("No ext_csd found!\n"); /* this should enver happen */ 1301dfda9d88SJean-Jacques Hiblot return -ENOTSUPP; 1302dfda9d88SJean-Jacques Hiblot } 1303dfda9d88SJean-Jacques Hiblot 13048ac8a263SJean-Jacques Hiblot for (idx = 0; idx < ARRAY_SIZE(ext_csd_bits); idx++) { 13058ac8a263SJean-Jacques Hiblot unsigned int extw = ext_csd_bits[idx]; 13068ac8a263SJean-Jacques Hiblot unsigned int caps = ext_to_hostcaps[extw]; 13078ac8a263SJean-Jacques Hiblot /* 13088ac8a263SJean-Jacques Hiblot * If the bus width is still not changed, 13098ac8a263SJean-Jacques Hiblot * don't try to set the default again. 13108ac8a263SJean-Jacques Hiblot * Otherwise, recover from switch attempts 13118ac8a263SJean-Jacques Hiblot * by switching to 1-bit bus width. 13128ac8a263SJean-Jacques Hiblot */ 13138ac8a263SJean-Jacques Hiblot if (extw == EXT_CSD_BUS_WIDTH_1 && 13148ac8a263SJean-Jacques Hiblot mmc->bus_width == 1) { 13158ac8a263SJean-Jacques Hiblot err = 0; 13168ac8a263SJean-Jacques Hiblot break; 13178ac8a263SJean-Jacques Hiblot } 13188ac8a263SJean-Jacques Hiblot 13198ac8a263SJean-Jacques Hiblot /* 13208ac8a263SJean-Jacques Hiblot * Check to make sure the card and controller support 13218ac8a263SJean-Jacques Hiblot * these capabilities 13228ac8a263SJean-Jacques Hiblot */ 13238ac8a263SJean-Jacques Hiblot if ((mmc->card_caps & caps) != caps) 13248ac8a263SJean-Jacques Hiblot continue; 13258ac8a263SJean-Jacques Hiblot 13268ac8a263SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 13278ac8a263SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, extw); 13288ac8a263SJean-Jacques Hiblot 13298ac8a263SJean-Jacques Hiblot if (err) 13308ac8a263SJean-Jacques Hiblot continue; 13318ac8a263SJean-Jacques Hiblot 13328ac8a263SJean-Jacques Hiblot mmc->ddr_mode = (caps & MMC_MODE_DDR_52MHz) ? 1 : 0; 13338ac8a263SJean-Jacques Hiblot mmc_set_bus_width(mmc, widths[idx]); 13348ac8a263SJean-Jacques Hiblot 13357382e691SJean-Jacques Hiblot err = mmc_read_and_compare_ext_csd(mmc); 13367382e691SJean-Jacques Hiblot if (!err) 13378ac8a263SJean-Jacques Hiblot break; 13388ac8a263SJean-Jacques Hiblot } 13398ac8a263SJean-Jacques Hiblot 13408ac8a263SJean-Jacques Hiblot if (err) 13418ac8a263SJean-Jacques Hiblot return err; 13428ac8a263SJean-Jacques Hiblot 134335f9e196SJean-Jacques Hiblot if (mmc->card_caps & MMC_MODE_HS_52MHz) { 134435f9e196SJean-Jacques Hiblot if (mmc->ddr_mode) 134535f9e196SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_DDR_52); 13468ac8a263SJean-Jacques Hiblot else 134735f9e196SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_HS_52); 1348*05038576SJean-Jacques Hiblot } else if (mmc->card_caps & MMC_MODE_HS) 134935f9e196SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_HS); 13508ac8a263SJean-Jacques Hiblot 13518ac8a263SJean-Jacques Hiblot return err; 13528ac8a263SJean-Jacques Hiblot } 13538ac8a263SJean-Jacques Hiblot 1354dfda9d88SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc) 1355c744b6f6SJean-Jacques Hiblot { 1356c744b6f6SJean-Jacques Hiblot int err, i; 1357c744b6f6SJean-Jacques Hiblot u64 capacity; 1358c744b6f6SJean-Jacques Hiblot bool has_parts = false; 1359c744b6f6SJean-Jacques Hiblot bool part_completed; 1360dfda9d88SJean-Jacques Hiblot u8 *ext_csd; 1361c744b6f6SJean-Jacques Hiblot 1362c744b6f6SJean-Jacques Hiblot if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4)) 1363c744b6f6SJean-Jacques Hiblot return 0; 1364c744b6f6SJean-Jacques Hiblot 1365dfda9d88SJean-Jacques Hiblot ext_csd = malloc_cache_aligned(MMC_MAX_BLOCK_LEN); 1366dfda9d88SJean-Jacques Hiblot if (!ext_csd) 1367dfda9d88SJean-Jacques Hiblot return -ENOMEM; 1368dfda9d88SJean-Jacques Hiblot 1369dfda9d88SJean-Jacques Hiblot mmc->ext_csd = ext_csd; 1370dfda9d88SJean-Jacques Hiblot 1371c744b6f6SJean-Jacques Hiblot /* check ext_csd version and capacity */ 1372c744b6f6SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, ext_csd); 1373c744b6f6SJean-Jacques Hiblot if (err) 1374c744b6f6SJean-Jacques Hiblot return err; 1375c744b6f6SJean-Jacques Hiblot if (ext_csd[EXT_CSD_REV] >= 2) { 1376c744b6f6SJean-Jacques Hiblot /* 1377c744b6f6SJean-Jacques Hiblot * According to the JEDEC Standard, the value of 1378c744b6f6SJean-Jacques Hiblot * ext_csd's capacity is valid if the value is more 1379c744b6f6SJean-Jacques Hiblot * than 2GB 1380c744b6f6SJean-Jacques Hiblot */ 1381c744b6f6SJean-Jacques Hiblot capacity = ext_csd[EXT_CSD_SEC_CNT] << 0 1382c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 1383c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 1384c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; 1385c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN; 1386c744b6f6SJean-Jacques Hiblot if ((capacity >> 20) > 2 * 1024) 1387c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity; 1388c744b6f6SJean-Jacques Hiblot } 1389c744b6f6SJean-Jacques Hiblot 1390c744b6f6SJean-Jacques Hiblot switch (ext_csd[EXT_CSD_REV]) { 1391c744b6f6SJean-Jacques Hiblot case 1: 1392c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_1; 1393c744b6f6SJean-Jacques Hiblot break; 1394c744b6f6SJean-Jacques Hiblot case 2: 1395c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_2; 1396c744b6f6SJean-Jacques Hiblot break; 1397c744b6f6SJean-Jacques Hiblot case 3: 1398c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_3; 1399c744b6f6SJean-Jacques Hiblot break; 1400c744b6f6SJean-Jacques Hiblot case 5: 1401c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_41; 1402c744b6f6SJean-Jacques Hiblot break; 1403c744b6f6SJean-Jacques Hiblot case 6: 1404c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_5; 1405c744b6f6SJean-Jacques Hiblot break; 1406c744b6f6SJean-Jacques Hiblot case 7: 1407c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_5_0; 1408c744b6f6SJean-Jacques Hiblot break; 1409c744b6f6SJean-Jacques Hiblot case 8: 1410c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_5_1; 1411c744b6f6SJean-Jacques Hiblot break; 1412c744b6f6SJean-Jacques Hiblot } 1413c744b6f6SJean-Jacques Hiblot 1414c744b6f6SJean-Jacques Hiblot /* The partition data may be non-zero but it is only 1415c744b6f6SJean-Jacques Hiblot * effective if PARTITION_SETTING_COMPLETED is set in 1416c744b6f6SJean-Jacques Hiblot * EXT_CSD, so ignore any data if this bit is not set, 1417c744b6f6SJean-Jacques Hiblot * except for enabling the high-capacity group size 1418c744b6f6SJean-Jacques Hiblot * definition (see below). 1419c744b6f6SJean-Jacques Hiblot */ 1420c744b6f6SJean-Jacques Hiblot part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] & 1421c744b6f6SJean-Jacques Hiblot EXT_CSD_PARTITION_SETTING_COMPLETED); 1422c744b6f6SJean-Jacques Hiblot 1423c744b6f6SJean-Jacques Hiblot /* store the partition info of emmc */ 1424c744b6f6SJean-Jacques Hiblot mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT]; 1425c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || 1426c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_BOOT_MULT]) 1427c744b6f6SJean-Jacques Hiblot mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; 1428c744b6f6SJean-Jacques Hiblot if (part_completed && 1429c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT)) 1430c744b6f6SJean-Jacques Hiblot mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]; 1431c744b6f6SJean-Jacques Hiblot 1432c744b6f6SJean-Jacques Hiblot mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17; 1433c744b6f6SJean-Jacques Hiblot 1434c744b6f6SJean-Jacques Hiblot mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17; 1435c744b6f6SJean-Jacques Hiblot 1436c744b6f6SJean-Jacques Hiblot for (i = 0; i < 4; i++) { 1437c744b6f6SJean-Jacques Hiblot int idx = EXT_CSD_GP_SIZE_MULT + i * 3; 1438c744b6f6SJean-Jacques Hiblot uint mult = (ext_csd[idx + 2] << 16) + 1439c744b6f6SJean-Jacques Hiblot (ext_csd[idx + 1] << 8) + ext_csd[idx]; 1440c744b6f6SJean-Jacques Hiblot if (mult) 1441c744b6f6SJean-Jacques Hiblot has_parts = true; 1442c744b6f6SJean-Jacques Hiblot if (!part_completed) 1443c744b6f6SJean-Jacques Hiblot continue; 1444c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] = mult; 1445c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= 1446c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1447c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1448c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] <<= 19; 1449c744b6f6SJean-Jacques Hiblot } 1450c744b6f6SJean-Jacques Hiblot 1451c744b6f6SJean-Jacques Hiblot if (part_completed) { 1452c744b6f6SJean-Jacques Hiblot mmc->enh_user_size = 1453c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) + 1454c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) + 1455c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_SIZE_MULT]; 1456c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1457c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1458c744b6f6SJean-Jacques Hiblot mmc->enh_user_size <<= 19; 1459c744b6f6SJean-Jacques Hiblot mmc->enh_user_start = 1460c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) + 1461c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) + 1462c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) + 1463c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_START_ADDR]; 1464c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity) 1465c744b6f6SJean-Jacques Hiblot mmc->enh_user_start <<= 9; 1466c744b6f6SJean-Jacques Hiblot } 1467c744b6f6SJean-Jacques Hiblot 1468c744b6f6SJean-Jacques Hiblot /* 1469c744b6f6SJean-Jacques Hiblot * Host needs to enable ERASE_GRP_DEF bit if device is 1470c744b6f6SJean-Jacques Hiblot * partitioned. This bit will be lost every time after a reset 1471c744b6f6SJean-Jacques Hiblot * or power off. This will affect erase size. 1472c744b6f6SJean-Jacques Hiblot */ 1473c744b6f6SJean-Jacques Hiblot if (part_completed) 1474c744b6f6SJean-Jacques Hiblot has_parts = true; 1475c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) && 1476c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) 1477c744b6f6SJean-Jacques Hiblot has_parts = true; 1478c744b6f6SJean-Jacques Hiblot if (has_parts) { 1479c744b6f6SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1480c744b6f6SJean-Jacques Hiblot EXT_CSD_ERASE_GROUP_DEF, 1); 1481c744b6f6SJean-Jacques Hiblot 1482c744b6f6SJean-Jacques Hiblot if (err) 1483c744b6f6SJean-Jacques Hiblot return err; 1484c744b6f6SJean-Jacques Hiblot 1485c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 1486c744b6f6SJean-Jacques Hiblot } 1487c744b6f6SJean-Jacques Hiblot 1488c744b6f6SJean-Jacques Hiblot if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) { 1489c744b6f6SJean-Jacques Hiblot /* Read out group size from ext_csd */ 1490c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = 1491c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 1492c744b6f6SJean-Jacques Hiblot /* 1493c744b6f6SJean-Jacques Hiblot * if high capacity and partition setting completed 1494c744b6f6SJean-Jacques Hiblot * SEC_COUNT is valid even if it is smaller than 2 GiB 1495c744b6f6SJean-Jacques Hiblot * JEDEC Standard JESD84-B45, 6.2.4 1496c744b6f6SJean-Jacques Hiblot */ 1497c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity && part_completed) { 1498c744b6f6SJean-Jacques Hiblot capacity = (ext_csd[EXT_CSD_SEC_CNT]) | 1499c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) | 1500c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) | 1501c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 3] << 24); 1502c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN; 1503c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity; 1504c744b6f6SJean-Jacques Hiblot } 1505c744b6f6SJean-Jacques Hiblot } else { 1506c744b6f6SJean-Jacques Hiblot /* Calculate the group size from the csd value. */ 1507c744b6f6SJean-Jacques Hiblot int erase_gsz, erase_gmul; 1508c744b6f6SJean-Jacques Hiblot 1509c744b6f6SJean-Jacques Hiblot erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; 1510c744b6f6SJean-Jacques Hiblot erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; 1511c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = (erase_gsz + 1) 1512c744b6f6SJean-Jacques Hiblot * (erase_gmul + 1); 1513c744b6f6SJean-Jacques Hiblot } 1514c744b6f6SJean-Jacques Hiblot 1515c744b6f6SJean-Jacques Hiblot mmc->hc_wp_grp_size = 1024 1516c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 1517c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1518c744b6f6SJean-Jacques Hiblot 1519c744b6f6SJean-Jacques Hiblot mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 1520c744b6f6SJean-Jacques Hiblot 1521c744b6f6SJean-Jacques Hiblot return 0; 1522c744b6f6SJean-Jacques Hiblot } 1523c744b6f6SJean-Jacques Hiblot 1524fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc) 1525272cc70bSAndy Fleming { 1526f866a46dSStephen Warren int err, i; 1527272cc70bSAndy Fleming uint mult, freq; 1528c744b6f6SJean-Jacques Hiblot u64 cmult, csize; 1529272cc70bSAndy Fleming struct mmc_cmd cmd; 1530c40fdca6SSimon Glass struct blk_desc *bdesc; 1531272cc70bSAndy Fleming 1532d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON 1533d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ 1534d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; 1535d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R1; 1536d52ebf10SThomas Chou cmd.cmdarg = 1; 1537d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 1538d52ebf10SThomas Chou 1539d52ebf10SThomas Chou if (err) 1540d52ebf10SThomas Chou return err; 1541d52ebf10SThomas Chou } 1542d52ebf10SThomas Chou #endif 1543d52ebf10SThomas Chou 1544272cc70bSAndy Fleming /* Put the Card in Identify Mode */ 1545d52ebf10SThomas Chou cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : 1546d52ebf10SThomas Chou MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ 1547272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1548272cc70bSAndy Fleming cmd.cmdarg = 0; 1549272cc70bSAndy Fleming 1550272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1551272cc70bSAndy Fleming 1552272cc70bSAndy Fleming if (err) 1553272cc70bSAndy Fleming return err; 1554272cc70bSAndy Fleming 1555272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16); 1556272cc70bSAndy Fleming 1557272cc70bSAndy Fleming /* 1558272cc70bSAndy Fleming * For MMC cards, set the Relative Address. 1559272cc70bSAndy Fleming * For SD cards, get the Relatvie Address. 1560272cc70bSAndy Fleming * This also puts the cards into Standby State 1561272cc70bSAndy Fleming */ 1562d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1563272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; 1564272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1565272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6; 1566272cc70bSAndy Fleming 1567272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1568272cc70bSAndy Fleming 1569272cc70bSAndy Fleming if (err) 1570272cc70bSAndy Fleming return err; 1571272cc70bSAndy Fleming 1572272cc70bSAndy Fleming if (IS_SD(mmc)) 1573998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff; 1574d52ebf10SThomas Chou } 1575272cc70bSAndy Fleming 1576272cc70bSAndy Fleming /* Get the Card-Specific Data */ 1577272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD; 1578272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1579272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1580272cc70bSAndy Fleming 1581272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1582272cc70bSAndy Fleming 1583272cc70bSAndy Fleming if (err) 1584272cc70bSAndy Fleming return err; 1585272cc70bSAndy Fleming 1586998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0]; 1587998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1]; 1588998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2]; 1589998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3]; 1590272cc70bSAndy Fleming 1591272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) { 15920b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf; 1593272cc70bSAndy Fleming 1594272cc70bSAndy Fleming switch (version) { 1595272cc70bSAndy Fleming case 0: 1596272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1597272cc70bSAndy Fleming break; 1598272cc70bSAndy Fleming case 1: 1599272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4; 1600272cc70bSAndy Fleming break; 1601272cc70bSAndy Fleming case 2: 1602272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2; 1603272cc70bSAndy Fleming break; 1604272cc70bSAndy Fleming case 3: 1605272cc70bSAndy Fleming mmc->version = MMC_VERSION_3; 1606272cc70bSAndy Fleming break; 1607272cc70bSAndy Fleming case 4: 1608272cc70bSAndy Fleming mmc->version = MMC_VERSION_4; 1609272cc70bSAndy Fleming break; 1610272cc70bSAndy Fleming default: 1611272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1612272cc70bSAndy Fleming break; 1613272cc70bSAndy Fleming } 1614272cc70bSAndy Fleming } 1615272cc70bSAndy Fleming 1616272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */ 16170b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)]; 16180b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; 1619272cc70bSAndy Fleming 162035f9e196SJean-Jacques Hiblot mmc->legacy_speed = freq * mult; 162135f9e196SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_LEGACY); 1622272cc70bSAndy Fleming 1623ab71188cSMarkus Niebel mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); 1624998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); 1625272cc70bSAndy Fleming 1626272cc70bSAndy Fleming if (IS_SD(mmc)) 1627272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len; 1628272cc70bSAndy Fleming else 1629998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); 1630272cc70bSAndy Fleming 1631272cc70bSAndy Fleming if (mmc->high_capacity) { 1632272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16 1633272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16; 1634272cc70bSAndy Fleming cmult = 8; 1635272cc70bSAndy Fleming } else { 1636272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2 1637272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30; 1638272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15; 1639272cc70bSAndy Fleming } 1640272cc70bSAndy Fleming 1641f866a46dSStephen Warren mmc->capacity_user = (csize + 1) << (cmult + 2); 1642f866a46dSStephen Warren mmc->capacity_user *= mmc->read_bl_len; 1643f866a46dSStephen Warren mmc->capacity_boot = 0; 1644f866a46dSStephen Warren mmc->capacity_rpmb = 0; 1645f866a46dSStephen Warren for (i = 0; i < 4; i++) 1646f866a46dSStephen Warren mmc->capacity_gp[i] = 0; 1647272cc70bSAndy Fleming 16488bfa195eSSimon Glass if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN) 16498bfa195eSSimon Glass mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 1650272cc70bSAndy Fleming 16518bfa195eSSimon Glass if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) 16528bfa195eSSimon Glass mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 1653272cc70bSAndy Fleming 1654ab71188cSMarkus Niebel if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) { 1655ab71188cSMarkus Niebel cmd.cmdidx = MMC_CMD_SET_DSR; 1656ab71188cSMarkus Niebel cmd.cmdarg = (mmc->dsr & 0xffff) << 16; 1657ab71188cSMarkus Niebel cmd.resp_type = MMC_RSP_NONE; 1658ab71188cSMarkus Niebel if (mmc_send_cmd(mmc, &cmd, NULL)) 1659ab71188cSMarkus Niebel printf("MMC: SET_DSR failed\n"); 1660ab71188cSMarkus Niebel } 1661ab71188cSMarkus Niebel 1662272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */ 1663d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1664272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD; 1665fe8f7066SAjay Bhargav cmd.resp_type = MMC_RSP_R1; 1666272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1667272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1668272cc70bSAndy Fleming 1669272cc70bSAndy Fleming if (err) 1670272cc70bSAndy Fleming return err; 1671d52ebf10SThomas Chou } 1672272cc70bSAndy Fleming 1673e6f99a56SLei Wen /* 1674e6f99a56SLei Wen * For SD, its erase group is always one sector 1675e6f99a56SLei Wen */ 1676e6f99a56SLei Wen mmc->erase_grp_size = 1; 1677bc897b1dSLei Wen mmc->part_config = MMCPART_NOAVAILABLE; 1678c744b6f6SJean-Jacques Hiblot 1679dfda9d88SJean-Jacques Hiblot err = mmc_startup_v4(mmc); 16809cf199ebSDiego Santa Cruz if (err) 16819cf199ebSDiego Santa Cruz return err; 1682f866a46dSStephen Warren 1683c40fdca6SSimon Glass err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart); 1684f866a46dSStephen Warren if (err) 1685f866a46dSStephen Warren return err; 1686d23e2c09SSukumar Ghorai 1687272cc70bSAndy Fleming if (IS_SD(mmc)) 16888ac8a263SJean-Jacques Hiblot err = sd_select_bus_freq_width(mmc); 1689272cc70bSAndy Fleming else 1690dfda9d88SJean-Jacques Hiblot err = mmc_select_bus_freq_width(mmc); 1691272cc70bSAndy Fleming 1692272cc70bSAndy Fleming if (err) 1693272cc70bSAndy Fleming return err; 1694272cc70bSAndy Fleming 1695272cc70bSAndy Fleming 16965af8f45cSAndrew Gabbasov /* Fix the block length for DDR mode */ 16975af8f45cSAndrew Gabbasov if (mmc->ddr_mode) { 16985af8f45cSAndrew Gabbasov mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 16995af8f45cSAndrew Gabbasov mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 17005af8f45cSAndrew Gabbasov } 17015af8f45cSAndrew Gabbasov 1702272cc70bSAndy Fleming /* fill in device description */ 1703c40fdca6SSimon Glass bdesc = mmc_get_blk_desc(mmc); 1704c40fdca6SSimon Glass bdesc->lun = 0; 1705c40fdca6SSimon Glass bdesc->hwpart = 0; 1706c40fdca6SSimon Glass bdesc->type = 0; 1707c40fdca6SSimon Glass bdesc->blksz = mmc->read_bl_len; 1708c40fdca6SSimon Glass bdesc->log2blksz = LOG2(bdesc->blksz); 1709c40fdca6SSimon Glass bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len); 1710fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \ 1711fc011f64SSjoerd Simons (defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \ 1712fc011f64SSjoerd Simons !defined(CONFIG_USE_TINY_PRINTF)) 1713c40fdca6SSimon Glass sprintf(bdesc->vendor, "Man %06x Snr %04x%04x", 1714babce5f6STaylor Hutt mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), 1715babce5f6STaylor Hutt (mmc->cid[3] >> 16) & 0xffff); 1716c40fdca6SSimon Glass sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff, 17170b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 1718babce5f6STaylor Hutt (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff, 1719babce5f6STaylor Hutt (mmc->cid[2] >> 24) & 0xff); 1720c40fdca6SSimon Glass sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf, 1721babce5f6STaylor Hutt (mmc->cid[2] >> 16) & 0xf); 172256196826SPaul Burton #else 1723c40fdca6SSimon Glass bdesc->vendor[0] = 0; 1724c40fdca6SSimon Glass bdesc->product[0] = 0; 1725c40fdca6SSimon Glass bdesc->revision[0] = 0; 172656196826SPaul Burton #endif 1727122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT) 1728c40fdca6SSimon Glass part_init(bdesc); 1729122efd43SMikhail Kshevetskiy #endif 1730272cc70bSAndy Fleming 1731272cc70bSAndy Fleming return 0; 1732272cc70bSAndy Fleming } 1733272cc70bSAndy Fleming 1734fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc) 1735272cc70bSAndy Fleming { 1736272cc70bSAndy Fleming struct mmc_cmd cmd; 1737272cc70bSAndy Fleming int err; 1738272cc70bSAndy Fleming 1739272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND; 1740272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ 174193bfd616SPantelis Antoniou cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa; 1742272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7; 1743272cc70bSAndy Fleming 1744272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1745272cc70bSAndy Fleming 1746272cc70bSAndy Fleming if (err) 1747272cc70bSAndy Fleming return err; 1748272cc70bSAndy Fleming 1749998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa) 1750915ffa52SJaehoon Chung return -EOPNOTSUPP; 1751272cc70bSAndy Fleming else 1752272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 1753272cc70bSAndy Fleming 1754272cc70bSAndy Fleming return 0; 1755272cc70bSAndy Fleming } 1756272cc70bSAndy Fleming 1757c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 175895de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */ 175995de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void) 176095de9ab2SPaul Kocialkowski { 176195de9ab2SPaul Kocialkowski } 176205cbeb7cSSimon Glass #endif 176395de9ab2SPaul Kocialkowski 17642051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc) 17652051aefeSPeng Fan { 1766c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 176706ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR) 17682051aefeSPeng Fan int ret; 17692051aefeSPeng Fan 17702051aefeSPeng Fan ret = device_get_supply_regulator(mmc->dev, "vmmc-supply", 177106ec045fSJean-Jacques Hiblot &mmc->vmmc_supply); 177206ec045fSJean-Jacques Hiblot if (ret) 1773288db7c7SJaehoon Chung debug("%s: No vmmc supply\n", mmc->dev->name); 17742051aefeSPeng Fan 177506ec045fSJean-Jacques Hiblot ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply", 177606ec045fSJean-Jacques Hiblot &mmc->vqmmc_supply); 177706ec045fSJean-Jacques Hiblot if (ret) 177806ec045fSJean-Jacques Hiblot debug("%s: No vqmmc supply\n", mmc->dev->name); 177906ec045fSJean-Jacques Hiblot 178006ec045fSJean-Jacques Hiblot if (mmc->vmmc_supply) { 178106ec045fSJean-Jacques Hiblot ret = regulator_set_enable(mmc->vmmc_supply, true); 17822051aefeSPeng Fan if (ret) { 17832051aefeSPeng Fan puts("Error enabling VMMC supply\n"); 17842051aefeSPeng Fan return ret; 17852051aefeSPeng Fan } 178606ec045fSJean-Jacques Hiblot } 17872051aefeSPeng Fan #endif 178805cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */ 178905cbeb7cSSimon Glass /* 179005cbeb7cSSimon Glass * Driver model should use a regulator, as above, rather than calling 179105cbeb7cSSimon Glass * out to board code. 179205cbeb7cSSimon Glass */ 179305cbeb7cSSimon Glass board_mmc_power_init(); 179405cbeb7cSSimon Glass #endif 17952051aefeSPeng Fan return 0; 17962051aefeSPeng Fan } 17972051aefeSPeng Fan 1798e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc) 1799272cc70bSAndy Fleming { 18008ca51e51SSimon Glass bool no_card; 1801afd5932bSMacpaul Lin int err; 1802272cc70bSAndy Fleming 1803ab769f22SPantelis Antoniou /* we pretend there's no card when init is NULL */ 18048ca51e51SSimon Glass no_card = mmc_getcd(mmc) == 0; 1805e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 18068ca51e51SSimon Glass no_card = no_card || (mmc->cfg->ops->init == NULL); 18078ca51e51SSimon Glass #endif 18088ca51e51SSimon Glass if (no_card) { 180948972d90SThierry Reding mmc->has_init = 0; 181056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 181148972d90SThierry Reding printf("MMC: no card present\n"); 181256196826SPaul Burton #endif 1813915ffa52SJaehoon Chung return -ENOMEDIUM; 181448972d90SThierry Reding } 181548972d90SThierry Reding 1816bc897b1dSLei Wen if (mmc->has_init) 1817bc897b1dSLei Wen return 0; 1818bc897b1dSLei Wen 18195a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 18205a8dbdc6SYangbo Lu mmc_adapter_card_type_ident(); 18215a8dbdc6SYangbo Lu #endif 18222051aefeSPeng Fan err = mmc_power_init(mmc); 18232051aefeSPeng Fan if (err) 18242051aefeSPeng Fan return err; 182595de9ab2SPaul Kocialkowski 1826e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 18278ca51e51SSimon Glass /* The device has already been probed ready for use */ 18288ca51e51SSimon Glass #else 1829ab769f22SPantelis Antoniou /* made sure it's not NULL earlier */ 183093bfd616SPantelis Antoniou err = mmc->cfg->ops->init(mmc); 1831272cc70bSAndy Fleming if (err) 1832272cc70bSAndy Fleming return err; 18338ca51e51SSimon Glass #endif 1834786e8f81SAndrew Gabbasov mmc->ddr_mode = 0; 1835b86b85e2SIlya Yanok mmc_set_bus_width(mmc, 1); 1836b86b85e2SIlya Yanok mmc_set_clock(mmc, 1); 1837b86b85e2SIlya Yanok 1838272cc70bSAndy Fleming /* Reset the Card */ 1839272cc70bSAndy Fleming err = mmc_go_idle(mmc); 1840272cc70bSAndy Fleming 1841272cc70bSAndy Fleming if (err) 1842272cc70bSAndy Fleming return err; 1843272cc70bSAndy Fleming 1844bc897b1dSLei Wen /* The internal partition reset to user partition(0) at every CMD0*/ 1845c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->hwpart = 0; 1846bc897b1dSLei Wen 1847272cc70bSAndy Fleming /* Test for SD version 2 */ 1848272cc70bSAndy Fleming err = mmc_send_if_cond(mmc); 1849272cc70bSAndy Fleming 1850272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */ 1851272cc70bSAndy Fleming err = sd_send_op_cond(mmc); 1852272cc70bSAndy Fleming 1853272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */ 1854915ffa52SJaehoon Chung if (err == -ETIMEDOUT) { 1855272cc70bSAndy Fleming err = mmc_send_op_cond(mmc); 1856272cc70bSAndy Fleming 1857bd47c135SAndrew Gabbasov if (err) { 185856196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 1859272cc70bSAndy Fleming printf("Card did not respond to voltage select!\n"); 186056196826SPaul Burton #endif 1861915ffa52SJaehoon Chung return -EOPNOTSUPP; 1862272cc70bSAndy Fleming } 1863272cc70bSAndy Fleming } 1864272cc70bSAndy Fleming 1865bd47c135SAndrew Gabbasov if (!err) 1866e9550449SChe-Liang Chiou mmc->init_in_progress = 1; 1867e9550449SChe-Liang Chiou 1868e9550449SChe-Liang Chiou return err; 1869e9550449SChe-Liang Chiou } 1870e9550449SChe-Liang Chiou 1871e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc) 1872e9550449SChe-Liang Chiou { 1873e9550449SChe-Liang Chiou int err = 0; 1874e9550449SChe-Liang Chiou 1875bd47c135SAndrew Gabbasov mmc->init_in_progress = 0; 1876e9550449SChe-Liang Chiou if (mmc->op_cond_pending) 1877e9550449SChe-Liang Chiou err = mmc_complete_op_cond(mmc); 1878e9550449SChe-Liang Chiou 1879e9550449SChe-Liang Chiou if (!err) 1880bc897b1dSLei Wen err = mmc_startup(mmc); 1881bc897b1dSLei Wen if (err) 1882bc897b1dSLei Wen mmc->has_init = 0; 1883bc897b1dSLei Wen else 1884bc897b1dSLei Wen mmc->has_init = 1; 1885e9550449SChe-Liang Chiou return err; 1886e9550449SChe-Liang Chiou } 1887e9550449SChe-Liang Chiou 1888e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc) 1889e9550449SChe-Liang Chiou { 1890bd47c135SAndrew Gabbasov int err = 0; 1891ce9eca94SMarek Vasut __maybe_unused unsigned start; 1892c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 189333fb211dSSimon Glass struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev); 1894e9550449SChe-Liang Chiou 189533fb211dSSimon Glass upriv->mmc = mmc; 189633fb211dSSimon Glass #endif 1897e9550449SChe-Liang Chiou if (mmc->has_init) 1898e9550449SChe-Liang Chiou return 0; 1899d803fea5SMateusz Zalega 1900d803fea5SMateusz Zalega start = get_timer(0); 1901d803fea5SMateusz Zalega 1902e9550449SChe-Liang Chiou if (!mmc->init_in_progress) 1903e9550449SChe-Liang Chiou err = mmc_start_init(mmc); 1904e9550449SChe-Liang Chiou 1905bd47c135SAndrew Gabbasov if (!err) 1906e9550449SChe-Liang Chiou err = mmc_complete_init(mmc); 1907919b4858SJagan Teki if (err) 1908919b4858SJagan Teki printf("%s: %d, time %lu\n", __func__, err, get_timer(start)); 1909919b4858SJagan Teki 1910bc897b1dSLei Wen return err; 1911272cc70bSAndy Fleming } 1912272cc70bSAndy Fleming 1913ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val) 1914ab71188cSMarkus Niebel { 1915ab71188cSMarkus Niebel mmc->dsr = val; 1916ab71188cSMarkus Niebel return 0; 1917ab71188cSMarkus Niebel } 1918ab71188cSMarkus Niebel 1919cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */ 1920cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis) 1921272cc70bSAndy Fleming { 1922272cc70bSAndy Fleming return -1; 1923272cc70bSAndy Fleming } 1924272cc70bSAndy Fleming 1925cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */ 1926cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis) 1927cee9ab7cSJeroen Hofstee { 1928cee9ab7cSJeroen Hofstee return -1; 1929cee9ab7cSJeroen Hofstee } 1930272cc70bSAndy Fleming 1931e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit) 1932e9550449SChe-Liang Chiou { 1933e9550449SChe-Liang Chiou mmc->preinit = preinit; 1934e9550449SChe-Liang Chiou } 1935e9550449SChe-Liang Chiou 1936c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD) 19378e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 19388e3332e2SSjoerd Simons { 19398e3332e2SSjoerd Simons return 0; 19408e3332e2SSjoerd Simons } 1941c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC) 19428e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 19438e3332e2SSjoerd Simons { 19444a1db6d8SSimon Glass int ret, i; 19458e3332e2SSjoerd Simons struct uclass *uc; 19464a1db6d8SSimon Glass struct udevice *dev; 19478e3332e2SSjoerd Simons 19488e3332e2SSjoerd Simons ret = uclass_get(UCLASS_MMC, &uc); 19498e3332e2SSjoerd Simons if (ret) 19508e3332e2SSjoerd Simons return ret; 19518e3332e2SSjoerd Simons 19524a1db6d8SSimon Glass /* 19534a1db6d8SSimon Glass * Try to add them in sequence order. Really with driver model we 19544a1db6d8SSimon Glass * should allow holes, but the current MMC list does not allow that. 19554a1db6d8SSimon Glass * So if we request 0, 1, 3 we will get 0, 1, 2. 19564a1db6d8SSimon Glass */ 19574a1db6d8SSimon Glass for (i = 0; ; i++) { 19584a1db6d8SSimon Glass ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev); 19594a1db6d8SSimon Glass if (ret == -ENODEV) 19604a1db6d8SSimon Glass break; 19614a1db6d8SSimon Glass } 19624a1db6d8SSimon Glass uclass_foreach_dev(dev, uc) { 19634a1db6d8SSimon Glass ret = device_probe(dev); 19648e3332e2SSjoerd Simons if (ret) 19654a1db6d8SSimon Glass printf("%s - probe failed: %d\n", dev->name, ret); 19668e3332e2SSjoerd Simons } 19678e3332e2SSjoerd Simons 19688e3332e2SSjoerd Simons return 0; 19698e3332e2SSjoerd Simons } 19708e3332e2SSjoerd Simons #else 19718e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 19728e3332e2SSjoerd Simons { 19738e3332e2SSjoerd Simons if (board_mmc_init(bis) < 0) 19748e3332e2SSjoerd Simons cpu_mmc_init(bis); 19758e3332e2SSjoerd Simons 19768e3332e2SSjoerd Simons return 0; 19778e3332e2SSjoerd Simons } 19788e3332e2SSjoerd Simons #endif 1979e9550449SChe-Liang Chiou 1980272cc70bSAndy Fleming int mmc_initialize(bd_t *bis) 1981272cc70bSAndy Fleming { 19821b26bab1SDaniel Kochmański static int initialized = 0; 19838e3332e2SSjoerd Simons int ret; 19841b26bab1SDaniel Kochmański if (initialized) /* Avoid initializing mmc multiple times */ 19851b26bab1SDaniel Kochmański return 0; 19861b26bab1SDaniel Kochmański initialized = 1; 19871b26bab1SDaniel Kochmański 1988c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK) 1989b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY) 1990c40fdca6SSimon Glass mmc_list_init(); 1991c40fdca6SSimon Glass #endif 1992b5b838f1SMarek Vasut #endif 19938e3332e2SSjoerd Simons ret = mmc_probe(bis); 19948e3332e2SSjoerd Simons if (ret) 19958e3332e2SSjoerd Simons return ret; 1996272cc70bSAndy Fleming 1997bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD 1998272cc70bSAndy Fleming print_mmc_devices(','); 1999bb0dc108SYing Zhang #endif 2000272cc70bSAndy Fleming 2001c40fdca6SSimon Glass mmc_do_preinit(); 2002272cc70bSAndy Fleming return 0; 2003272cc70bSAndy Fleming } 2004cd3d4880STomas Melin 2005cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE 2006cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc) 2007cd3d4880STomas Melin { 2008cd3d4880STomas Melin int err; 2009cd3d4880STomas Melin ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 2010cd3d4880STomas Melin 2011cd3d4880STomas Melin err = mmc_send_ext_csd(mmc, ext_csd); 2012cd3d4880STomas Melin if (err) { 2013cd3d4880STomas Melin puts("Could not get ext_csd register values\n"); 2014cd3d4880STomas Melin return err; 2015cd3d4880STomas Melin } 2016cd3d4880STomas Melin 2017cd3d4880STomas Melin if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) { 2018cd3d4880STomas Melin puts("Background operations not supported on device\n"); 2019cd3d4880STomas Melin return -EMEDIUMTYPE; 2020cd3d4880STomas Melin } 2021cd3d4880STomas Melin 2022cd3d4880STomas Melin if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) { 2023cd3d4880STomas Melin puts("Background operations already enabled\n"); 2024cd3d4880STomas Melin return 0; 2025cd3d4880STomas Melin } 2026cd3d4880STomas Melin 2027cd3d4880STomas Melin err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1); 2028cd3d4880STomas Melin if (err) { 2029cd3d4880STomas Melin puts("Failed to enable manual background operations\n"); 2030cd3d4880STomas Melin return err; 2031cd3d4880STomas Melin } 2032cd3d4880STomas Melin 2033cd3d4880STomas Melin puts("Enabled manual background operations\n"); 2034cd3d4880STomas Melin 2035cd3d4880STomas Melin return 0; 2036cd3d4880STomas Melin } 2037cd3d4880STomas Melin #endif 2038