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 17705038576SJean-Jacques Hiblot static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode) 17805038576SJean-Jacques Hiblot { 17905038576SJean-Jacques Hiblot static const int freqs[] = { 18005038576SJean-Jacques Hiblot [SD_LEGACY] = 25000000, 18105038576SJean-Jacques Hiblot [MMC_HS] = 26000000, 18205038576SJean-Jacques Hiblot [SD_HS] = 50000000, 18305038576SJean-Jacques Hiblot [UHS_SDR12] = 25000000, 18405038576SJean-Jacques Hiblot [UHS_SDR25] = 50000000, 18505038576SJean-Jacques Hiblot [UHS_SDR50] = 100000000, 18605038576SJean-Jacques Hiblot [UHS_SDR104] = 208000000, 18705038576SJean-Jacques Hiblot [UHS_DDR50] = 50000000, 18805038576SJean-Jacques Hiblot [MMC_HS_52] = 52000000, 18905038576SJean-Jacques Hiblot [MMC_DDR_52] = 52000000, 19005038576SJean-Jacques Hiblot [MMC_HS_200] = 200000000, 19105038576SJean-Jacques Hiblot }; 19205038576SJean-Jacques Hiblot 19305038576SJean-Jacques Hiblot if (mode == MMC_LEGACY) 19405038576SJean-Jacques Hiblot return mmc->legacy_speed; 19505038576SJean-Jacques Hiblot else if (mode >= MMC_MODES_END) 19605038576SJean-Jacques Hiblot return 0; 19705038576SJean-Jacques Hiblot else 19805038576SJean-Jacques Hiblot return freqs[mode]; 19905038576SJean-Jacques Hiblot } 20005038576SJean-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; 20405038576SJean-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; 240*d0c221feSJean-Jacques Hiblot 241*d0c221feSJean-Jacques Hiblot if (cmd.response[0] & MMC_STATUS_MASK) { 24256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 243d617c426SJan Kloetzke printf("Status Error: 0x%08X\n", 244d617c426SJan Kloetzke cmd.response[0]); 24556196826SPaul Burton #endif 246915ffa52SJaehoon Chung return -ECOMM; 247d617c426SJan Kloetzke } 248d617c426SJan Kloetzke } else if (--retries < 0) 249d617c426SJan Kloetzke return err; 2505d4fc8d9SRaffaele Recalcati 2511677eef4SAndrew Gabbasov if (timeout-- <= 0) 2521677eef4SAndrew Gabbasov break; 2535d4fc8d9SRaffaele Recalcati 2541677eef4SAndrew Gabbasov udelay(1000); 2551677eef4SAndrew Gabbasov } 2565d4fc8d9SRaffaele Recalcati 257c0c76ebaSSimon Glass mmc_trace_state(mmc, &cmd); 2585b0c942fSJongman Heo if (timeout <= 0) { 25956196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2605d4fc8d9SRaffaele Recalcati printf("Timeout waiting card ready\n"); 26156196826SPaul Burton #endif 262915ffa52SJaehoon Chung return -ETIMEDOUT; 2635d4fc8d9SRaffaele Recalcati } 2645d4fc8d9SRaffaele Recalcati 2655d4fc8d9SRaffaele Recalcati return 0; 2665d4fc8d9SRaffaele Recalcati } 2675d4fc8d9SRaffaele Recalcati 268da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len) 269272cc70bSAndy Fleming { 270272cc70bSAndy Fleming struct mmc_cmd cmd; 271272cc70bSAndy Fleming 272786e8f81SAndrew Gabbasov if (mmc->ddr_mode) 273d22e3d46SJaehoon Chung return 0; 274d22e3d46SJaehoon Chung 275272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SET_BLOCKLEN; 276272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 277272cc70bSAndy Fleming cmd.cmdarg = len; 278272cc70bSAndy Fleming 279272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, NULL); 280272cc70bSAndy Fleming } 281272cc70bSAndy Fleming 282ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start, 283fdbb873eSKim Phillips lbaint_t blkcnt) 284272cc70bSAndy Fleming { 285272cc70bSAndy Fleming struct mmc_cmd cmd; 286272cc70bSAndy Fleming struct mmc_data data; 287272cc70bSAndy Fleming 2884a1a06bcSAlagu Sankar if (blkcnt > 1) 2894a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; 2904a1a06bcSAlagu Sankar else 291272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; 292272cc70bSAndy Fleming 293272cc70bSAndy Fleming if (mmc->high_capacity) 2944a1a06bcSAlagu Sankar cmd.cmdarg = start; 295272cc70bSAndy Fleming else 2964a1a06bcSAlagu Sankar cmd.cmdarg = start * mmc->read_bl_len; 297272cc70bSAndy Fleming 298272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 299272cc70bSAndy Fleming 300272cc70bSAndy Fleming data.dest = dst; 3014a1a06bcSAlagu Sankar data.blocks = blkcnt; 302272cc70bSAndy Fleming data.blocksize = mmc->read_bl_len; 303272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 304272cc70bSAndy Fleming 3054a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, &data)) 3064a1a06bcSAlagu Sankar return 0; 3074a1a06bcSAlagu Sankar 3084a1a06bcSAlagu Sankar if (blkcnt > 1) { 3094a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; 3104a1a06bcSAlagu Sankar cmd.cmdarg = 0; 3114a1a06bcSAlagu Sankar cmd.resp_type = MMC_RSP_R1b; 3124a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, NULL)) { 31356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 3144a1a06bcSAlagu Sankar printf("mmc fail to send stop cmd\n"); 31556196826SPaul Burton #endif 3164a1a06bcSAlagu Sankar return 0; 3174a1a06bcSAlagu Sankar } 318272cc70bSAndy Fleming } 319272cc70bSAndy Fleming 3204a1a06bcSAlagu Sankar return blkcnt; 321272cc70bSAndy Fleming } 322272cc70bSAndy Fleming 323c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK) 3247dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst) 32533fb211dSSimon Glass #else 3267dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, 3277dba0b93SSimon Glass void *dst) 32833fb211dSSimon Glass #endif 329272cc70bSAndy Fleming { 330c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK) 33133fb211dSSimon Glass struct blk_desc *block_dev = dev_get_uclass_platdata(dev); 33233fb211dSSimon Glass #endif 333bcce53d0SSimon Glass int dev_num = block_dev->devnum; 334873cc1d7SStephen Warren int err; 3354a1a06bcSAlagu Sankar lbaint_t cur, blocks_todo = blkcnt; 336272cc70bSAndy Fleming 3374a1a06bcSAlagu Sankar if (blkcnt == 0) 3384a1a06bcSAlagu Sankar return 0; 3394a1a06bcSAlagu Sankar 3404a1a06bcSAlagu Sankar struct mmc *mmc = find_mmc_device(dev_num); 341272cc70bSAndy Fleming if (!mmc) 342272cc70bSAndy Fleming return 0; 343272cc70bSAndy Fleming 344b5b838f1SMarek Vasut if (CONFIG_IS_ENABLED(MMC_TINY)) 345b5b838f1SMarek Vasut err = mmc_switch_part(mmc, block_dev->hwpart); 346b5b838f1SMarek Vasut else 34769f45cd5SSimon Glass err = blk_dselect_hwpart(block_dev, block_dev->hwpart); 348b5b838f1SMarek Vasut 349873cc1d7SStephen Warren if (err < 0) 350873cc1d7SStephen Warren return 0; 351873cc1d7SStephen Warren 352c40fdca6SSimon Glass if ((start + blkcnt) > block_dev->lba) { 35356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 354ff8fef56SSascha Silbe printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", 355c40fdca6SSimon Glass start + blkcnt, block_dev->lba); 35656196826SPaul Burton #endif 357d2bf29e3SLei Wen return 0; 358d2bf29e3SLei Wen } 359272cc70bSAndy Fleming 36011692991SSimon Glass if (mmc_set_blocklen(mmc, mmc->read_bl_len)) { 36111692991SSimon Glass debug("%s: Failed to set blocklen\n", __func__); 362272cc70bSAndy Fleming return 0; 36311692991SSimon Glass } 364272cc70bSAndy Fleming 3654a1a06bcSAlagu Sankar do { 36693bfd616SPantelis Antoniou cur = (blocks_todo > mmc->cfg->b_max) ? 36793bfd616SPantelis Antoniou mmc->cfg->b_max : blocks_todo; 36811692991SSimon Glass if (mmc_read_blocks(mmc, dst, start, cur) != cur) { 36911692991SSimon Glass debug("%s: Failed to read blocks\n", __func__); 3704a1a06bcSAlagu Sankar return 0; 37111692991SSimon Glass } 3724a1a06bcSAlagu Sankar blocks_todo -= cur; 3734a1a06bcSAlagu Sankar start += cur; 3744a1a06bcSAlagu Sankar dst += cur * mmc->read_bl_len; 3754a1a06bcSAlagu Sankar } while (blocks_todo > 0); 376272cc70bSAndy Fleming 377272cc70bSAndy Fleming return blkcnt; 378272cc70bSAndy Fleming } 379272cc70bSAndy Fleming 380fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc) 381272cc70bSAndy Fleming { 382272cc70bSAndy Fleming struct mmc_cmd cmd; 383272cc70bSAndy Fleming int err; 384272cc70bSAndy Fleming 385272cc70bSAndy Fleming udelay(1000); 386272cc70bSAndy Fleming 387272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_GO_IDLE_STATE; 388272cc70bSAndy Fleming cmd.cmdarg = 0; 389272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_NONE; 390272cc70bSAndy Fleming 391272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 392272cc70bSAndy Fleming 393272cc70bSAndy Fleming if (err) 394272cc70bSAndy Fleming return err; 395272cc70bSAndy Fleming 396272cc70bSAndy Fleming udelay(2000); 397272cc70bSAndy Fleming 398272cc70bSAndy Fleming return 0; 399272cc70bSAndy Fleming } 400272cc70bSAndy Fleming 401fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc) 402272cc70bSAndy Fleming { 403272cc70bSAndy Fleming int timeout = 1000; 404272cc70bSAndy Fleming int err; 405272cc70bSAndy Fleming struct mmc_cmd cmd; 406272cc70bSAndy Fleming 4071677eef4SAndrew Gabbasov while (1) { 408272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 409272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 410272cc70bSAndy Fleming cmd.cmdarg = 0; 411272cc70bSAndy Fleming 412272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 413272cc70bSAndy Fleming 414272cc70bSAndy Fleming if (err) 415272cc70bSAndy Fleming return err; 416272cc70bSAndy Fleming 417272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_OP_COND; 418272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R3; 419250de12bSStefano Babic 420250de12bSStefano Babic /* 421250de12bSStefano Babic * Most cards do not answer if some reserved bits 422250de12bSStefano Babic * in the ocr are set. However, Some controller 423250de12bSStefano Babic * can set bit 7 (reserved for low voltages), but 424250de12bSStefano Babic * how to manage low voltages SD card is not yet 425250de12bSStefano Babic * specified. 426250de12bSStefano Babic */ 427d52ebf10SThomas Chou cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 : 42893bfd616SPantelis Antoniou (mmc->cfg->voltages & 0xff8000); 429272cc70bSAndy Fleming 430272cc70bSAndy Fleming if (mmc->version == SD_VERSION_2) 431272cc70bSAndy Fleming cmd.cmdarg |= OCR_HCS; 432272cc70bSAndy Fleming 433272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 434272cc70bSAndy Fleming 435272cc70bSAndy Fleming if (err) 436272cc70bSAndy Fleming return err; 437272cc70bSAndy Fleming 4381677eef4SAndrew Gabbasov if (cmd.response[0] & OCR_BUSY) 4391677eef4SAndrew Gabbasov break; 440272cc70bSAndy Fleming 4411677eef4SAndrew Gabbasov if (timeout-- <= 0) 442915ffa52SJaehoon Chung return -EOPNOTSUPP; 443272cc70bSAndy Fleming 4441677eef4SAndrew Gabbasov udelay(1000); 4451677eef4SAndrew Gabbasov } 4461677eef4SAndrew Gabbasov 447272cc70bSAndy Fleming if (mmc->version != SD_VERSION_2) 448272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 449272cc70bSAndy Fleming 450d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 451d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 452d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 453d52ebf10SThomas Chou cmd.cmdarg = 0; 454d52ebf10SThomas Chou 455d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 456d52ebf10SThomas Chou 457d52ebf10SThomas Chou if (err) 458d52ebf10SThomas Chou return err; 459d52ebf10SThomas Chou } 460d52ebf10SThomas Chou 461998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 462272cc70bSAndy Fleming 463272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 464272cc70bSAndy Fleming mmc->rca = 0; 465272cc70bSAndy Fleming 466272cc70bSAndy Fleming return 0; 467272cc70bSAndy Fleming } 468272cc70bSAndy Fleming 4695289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg) 470272cc70bSAndy Fleming { 4715289b535SAndrew Gabbasov struct mmc_cmd cmd; 472272cc70bSAndy Fleming int err; 473272cc70bSAndy Fleming 4745289b535SAndrew Gabbasov cmd.cmdidx = MMC_CMD_SEND_OP_COND; 4755289b535SAndrew Gabbasov cmd.resp_type = MMC_RSP_R3; 4765289b535SAndrew Gabbasov cmd.cmdarg = 0; 4775a20397bSRob Herring if (use_arg && !mmc_host_is_spi(mmc)) 4785a20397bSRob Herring cmd.cmdarg = OCR_HCS | 47993bfd616SPantelis Antoniou (mmc->cfg->voltages & 480a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_VOLTAGE_MASK)) | 481a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_ACCESS_MODE); 482e9550449SChe-Liang Chiou 4835289b535SAndrew Gabbasov err = mmc_send_cmd(mmc, &cmd, NULL); 484e9550449SChe-Liang Chiou if (err) 485e9550449SChe-Liang Chiou return err; 4865289b535SAndrew Gabbasov mmc->ocr = cmd.response[0]; 487e9550449SChe-Liang Chiou return 0; 488e9550449SChe-Liang Chiou } 489e9550449SChe-Liang Chiou 490750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc) 491e9550449SChe-Liang Chiou { 492e9550449SChe-Liang Chiou int err, i; 493e9550449SChe-Liang Chiou 494272cc70bSAndy Fleming /* Some cards seem to need this */ 495272cc70bSAndy Fleming mmc_go_idle(mmc); 496272cc70bSAndy Fleming 49731cacbabSRaffaele Recalcati /* Asking to the card its capabilities */ 498e9550449SChe-Liang Chiou for (i = 0; i < 2; i++) { 4995289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, i != 0); 50031cacbabSRaffaele Recalcati if (err) 50131cacbabSRaffaele Recalcati return err; 50231cacbabSRaffaele Recalcati 503e9550449SChe-Liang Chiou /* exit if not busy (flag seems to be inverted) */ 504a626c8d4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 505bd47c135SAndrew Gabbasov break; 506e9550449SChe-Liang Chiou } 507bd47c135SAndrew Gabbasov mmc->op_cond_pending = 1; 508bd47c135SAndrew Gabbasov return 0; 509e9550449SChe-Liang Chiou } 51031cacbabSRaffaele Recalcati 511750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc) 512e9550449SChe-Liang Chiou { 513e9550449SChe-Liang Chiou struct mmc_cmd cmd; 514e9550449SChe-Liang Chiou int timeout = 1000; 515e9550449SChe-Liang Chiou uint start; 516e9550449SChe-Liang Chiou int err; 517e9550449SChe-Liang Chiou 518e9550449SChe-Liang Chiou mmc->op_cond_pending = 0; 519cc17c01fSAndrew Gabbasov if (!(mmc->ocr & OCR_BUSY)) { 520d188b113SYangbo Lu /* Some cards seem to need this */ 521d188b113SYangbo Lu mmc_go_idle(mmc); 522d188b113SYangbo Lu 523e9550449SChe-Liang Chiou start = get_timer(0); 5241677eef4SAndrew Gabbasov while (1) { 5255289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, 1); 526272cc70bSAndy Fleming if (err) 527272cc70bSAndy Fleming return err; 5281677eef4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 5291677eef4SAndrew Gabbasov break; 530e9550449SChe-Liang Chiou if (get_timer(start) > timeout) 531915ffa52SJaehoon Chung return -EOPNOTSUPP; 532e9550449SChe-Liang Chiou udelay(100); 5331677eef4SAndrew Gabbasov } 534cc17c01fSAndrew Gabbasov } 535272cc70bSAndy Fleming 536d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 537d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 538d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 539d52ebf10SThomas Chou cmd.cmdarg = 0; 540d52ebf10SThomas Chou 541d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 542d52ebf10SThomas Chou 543d52ebf10SThomas Chou if (err) 544d52ebf10SThomas Chou return err; 545a626c8d4SAndrew Gabbasov 546a626c8d4SAndrew Gabbasov mmc->ocr = cmd.response[0]; 547d52ebf10SThomas Chou } 548d52ebf10SThomas Chou 549272cc70bSAndy Fleming mmc->version = MMC_VERSION_UNKNOWN; 550272cc70bSAndy Fleming 551272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 552def816a2SStephen Warren mmc->rca = 1; 553272cc70bSAndy Fleming 554272cc70bSAndy Fleming return 0; 555272cc70bSAndy Fleming } 556272cc70bSAndy Fleming 557272cc70bSAndy Fleming 558fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) 559272cc70bSAndy Fleming { 560272cc70bSAndy Fleming struct mmc_cmd cmd; 561272cc70bSAndy Fleming struct mmc_data data; 562272cc70bSAndy Fleming int err; 563272cc70bSAndy Fleming 564272cc70bSAndy Fleming /* Get the Card Status Register */ 565272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_EXT_CSD; 566272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 567272cc70bSAndy Fleming cmd.cmdarg = 0; 568272cc70bSAndy Fleming 569cdfd1ac6SYoshihiro Shimoda data.dest = (char *)ext_csd; 570272cc70bSAndy Fleming data.blocks = 1; 5718bfa195eSSimon Glass data.blocksize = MMC_MAX_BLOCK_LEN; 572272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 573272cc70bSAndy Fleming 574272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 575272cc70bSAndy Fleming 576272cc70bSAndy Fleming return err; 577272cc70bSAndy Fleming } 578272cc70bSAndy Fleming 579c40704f4SSimon Glass int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) 580272cc70bSAndy Fleming { 581272cc70bSAndy Fleming struct mmc_cmd cmd; 5825d4fc8d9SRaffaele Recalcati int timeout = 1000; 583a9003dc6SMaxime Ripard int retries = 3; 5845d4fc8d9SRaffaele Recalcati int ret; 585272cc70bSAndy Fleming 586272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SWITCH; 587272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 588272cc70bSAndy Fleming cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 589272cc70bSAndy Fleming (index << 16) | 590272cc70bSAndy Fleming (value << 8); 591272cc70bSAndy Fleming 592a9003dc6SMaxime Ripard while (retries > 0) { 5935d4fc8d9SRaffaele Recalcati ret = mmc_send_cmd(mmc, &cmd, NULL); 5945d4fc8d9SRaffaele Recalcati 5955d4fc8d9SRaffaele Recalcati /* Waiting for the ready status */ 596a9003dc6SMaxime Ripard if (!ret) { 59793ad0d18SJan Kloetzke ret = mmc_send_status(mmc, timeout); 598a9003dc6SMaxime Ripard return ret; 599a9003dc6SMaxime Ripard } 600a9003dc6SMaxime Ripard 601a9003dc6SMaxime Ripard retries--; 602a9003dc6SMaxime Ripard } 6035d4fc8d9SRaffaele Recalcati 6045d4fc8d9SRaffaele Recalcati return ret; 6055d4fc8d9SRaffaele Recalcati 606272cc70bSAndy Fleming } 607272cc70bSAndy Fleming 608fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc) 609272cc70bSAndy Fleming { 6108bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 611272cc70bSAndy Fleming char cardtype; 612272cc70bSAndy Fleming int err; 613272cc70bSAndy Fleming 614*d0c221feSJean-Jacques Hiblot mmc->card_caps = MMC_MODE_1BIT; 615272cc70bSAndy Fleming 616d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 617d52ebf10SThomas Chou return 0; 618d52ebf10SThomas Chou 619272cc70bSAndy Fleming /* Only version 4 supports high-speed */ 620272cc70bSAndy Fleming if (mmc->version < MMC_VERSION_4) 621272cc70bSAndy Fleming return 0; 622272cc70bSAndy Fleming 623fc5b32fbSAndrew Gabbasov mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; 624fc5b32fbSAndrew Gabbasov 625272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 626272cc70bSAndy Fleming 627272cc70bSAndy Fleming if (err) 628272cc70bSAndy Fleming return err; 629272cc70bSAndy Fleming 6300560db18SLei Wen cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf; 631272cc70bSAndy Fleming 632272cc70bSAndy Fleming err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1); 633272cc70bSAndy Fleming 634272cc70bSAndy Fleming if (err) 635a5e27b41SHeiko Schocher return err; 636272cc70bSAndy Fleming 637272cc70bSAndy Fleming /* Now check to see that it worked */ 638272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 639272cc70bSAndy Fleming 640272cc70bSAndy Fleming if (err) 641272cc70bSAndy Fleming return err; 642272cc70bSAndy Fleming 643272cc70bSAndy Fleming /* No high-speed support */ 6440560db18SLei Wen if (!ext_csd[EXT_CSD_HS_TIMING]) 645272cc70bSAndy Fleming return 0; 646272cc70bSAndy Fleming 647272cc70bSAndy Fleming /* High Speed is set, there are two types: 52MHz and 26MHz */ 648d22e3d46SJaehoon Chung if (cardtype & EXT_CSD_CARD_TYPE_52) { 649201d5ac4SAndrew Gabbasov if (cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V) 650d22e3d46SJaehoon Chung mmc->card_caps |= MMC_MODE_DDR_52MHz; 651272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; 652d22e3d46SJaehoon Chung } else { 653272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS; 654d22e3d46SJaehoon Chung } 655272cc70bSAndy Fleming 656272cc70bSAndy Fleming return 0; 657272cc70bSAndy Fleming } 658272cc70bSAndy Fleming 659f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num) 660f866a46dSStephen Warren { 661f866a46dSStephen Warren switch (part_num) { 662f866a46dSStephen Warren case 0: 663f866a46dSStephen Warren mmc->capacity = mmc->capacity_user; 664f866a46dSStephen Warren break; 665f866a46dSStephen Warren case 1: 666f866a46dSStephen Warren case 2: 667f866a46dSStephen Warren mmc->capacity = mmc->capacity_boot; 668f866a46dSStephen Warren break; 669f866a46dSStephen Warren case 3: 670f866a46dSStephen Warren mmc->capacity = mmc->capacity_rpmb; 671f866a46dSStephen Warren break; 672f866a46dSStephen Warren case 4: 673f866a46dSStephen Warren case 5: 674f866a46dSStephen Warren case 6: 675f866a46dSStephen Warren case 7: 676f866a46dSStephen Warren mmc->capacity = mmc->capacity_gp[part_num - 4]; 677f866a46dSStephen Warren break; 678f866a46dSStephen Warren default: 679f866a46dSStephen Warren return -1; 680f866a46dSStephen Warren } 681f866a46dSStephen Warren 682c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len); 683f866a46dSStephen Warren 684f866a46dSStephen Warren return 0; 685f866a46dSStephen Warren } 686f866a46dSStephen Warren 6877dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num) 688bc897b1dSLei Wen { 689f866a46dSStephen Warren int ret; 690bc897b1dSLei Wen 691f866a46dSStephen Warren ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 692bc897b1dSLei Wen (mmc->part_config & ~PART_ACCESS_MASK) 693bc897b1dSLei Wen | (part_num & PART_ACCESS_MASK)); 694f866a46dSStephen Warren 6956dc93e70SPeter Bigot /* 6966dc93e70SPeter Bigot * Set the capacity if the switch succeeded or was intended 6976dc93e70SPeter Bigot * to return to representing the raw device. 6986dc93e70SPeter Bigot */ 699873cc1d7SStephen Warren if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) { 7006dc93e70SPeter Bigot ret = mmc_set_capacity(mmc, part_num); 701fdbb139fSSimon Glass mmc_get_blk_desc(mmc)->hwpart = part_num; 702873cc1d7SStephen Warren } 7036dc93e70SPeter Bigot 7046dc93e70SPeter Bigot return ret; 705bc897b1dSLei Wen } 706bc897b1dSLei Wen 707ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc, 708ac9da0e0SDiego Santa Cruz const struct mmc_hwpart_conf *conf, 709ac9da0e0SDiego Santa Cruz enum mmc_hwpart_conf_mode mode) 710ac9da0e0SDiego Santa Cruz { 711ac9da0e0SDiego Santa Cruz u8 part_attrs = 0; 712ac9da0e0SDiego Santa Cruz u32 enh_size_mult; 713ac9da0e0SDiego Santa Cruz u32 enh_start_addr; 714ac9da0e0SDiego Santa Cruz u32 gp_size_mult[4]; 715ac9da0e0SDiego Santa Cruz u32 max_enh_size_mult; 716ac9da0e0SDiego Santa Cruz u32 tot_enh_size_mult = 0; 7178dda5b0eSDiego Santa Cruz u8 wr_rel_set; 718ac9da0e0SDiego Santa Cruz int i, pidx, err; 719ac9da0e0SDiego Santa Cruz ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 720ac9da0e0SDiego Santa Cruz 721ac9da0e0SDiego Santa Cruz if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE) 722ac9da0e0SDiego Santa Cruz return -EINVAL; 723ac9da0e0SDiego Santa Cruz 724ac9da0e0SDiego Santa Cruz if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) { 725ac9da0e0SDiego Santa Cruz printf("eMMC >= 4.4 required for enhanced user data area\n"); 726ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 727ac9da0e0SDiego Santa Cruz } 728ac9da0e0SDiego Santa Cruz 729ac9da0e0SDiego Santa Cruz if (!(mmc->part_support & PART_SUPPORT)) { 730ac9da0e0SDiego Santa Cruz printf("Card does not support partitioning\n"); 731ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 732ac9da0e0SDiego Santa Cruz } 733ac9da0e0SDiego Santa Cruz 734ac9da0e0SDiego Santa Cruz if (!mmc->hc_wp_grp_size) { 735ac9da0e0SDiego Santa Cruz printf("Card does not define HC WP group size\n"); 736ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 737ac9da0e0SDiego Santa Cruz } 738ac9da0e0SDiego Santa Cruz 739ac9da0e0SDiego Santa Cruz /* check partition alignment and total enhanced size */ 740ac9da0e0SDiego Santa Cruz if (conf->user.enh_size) { 741ac9da0e0SDiego Santa Cruz if (conf->user.enh_size % mmc->hc_wp_grp_size || 742ac9da0e0SDiego Santa Cruz conf->user.enh_start % mmc->hc_wp_grp_size) { 743ac9da0e0SDiego Santa Cruz printf("User data enhanced area not HC WP group " 744ac9da0e0SDiego Santa Cruz "size aligned\n"); 745ac9da0e0SDiego Santa Cruz return -EINVAL; 746ac9da0e0SDiego Santa Cruz } 747ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_USR; 748ac9da0e0SDiego Santa Cruz enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size; 749ac9da0e0SDiego Santa Cruz if (mmc->high_capacity) { 750ac9da0e0SDiego Santa Cruz enh_start_addr = conf->user.enh_start; 751ac9da0e0SDiego Santa Cruz } else { 752ac9da0e0SDiego Santa Cruz enh_start_addr = (conf->user.enh_start << 9); 753ac9da0e0SDiego Santa Cruz } 754ac9da0e0SDiego Santa Cruz } else { 755ac9da0e0SDiego Santa Cruz enh_size_mult = 0; 756ac9da0e0SDiego Santa Cruz enh_start_addr = 0; 757ac9da0e0SDiego Santa Cruz } 758ac9da0e0SDiego Santa Cruz tot_enh_size_mult += enh_size_mult; 759ac9da0e0SDiego Santa Cruz 760ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 761ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) { 762ac9da0e0SDiego Santa Cruz printf("GP%i partition not HC WP group size " 763ac9da0e0SDiego Santa Cruz "aligned\n", pidx+1); 764ac9da0e0SDiego Santa Cruz return -EINVAL; 765ac9da0e0SDiego Santa Cruz } 766ac9da0e0SDiego Santa Cruz gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size; 767ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) { 768ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_GP(pidx); 769ac9da0e0SDiego Santa Cruz tot_enh_size_mult += gp_size_mult[pidx]; 770ac9da0e0SDiego Santa Cruz } 771ac9da0e0SDiego Santa Cruz } 772ac9da0e0SDiego Santa Cruz 773ac9da0e0SDiego Santa Cruz if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) { 774ac9da0e0SDiego Santa Cruz printf("Card does not support enhanced attribute\n"); 775ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 776ac9da0e0SDiego Santa Cruz } 777ac9da0e0SDiego Santa Cruz 778ac9da0e0SDiego Santa Cruz err = mmc_send_ext_csd(mmc, ext_csd); 779ac9da0e0SDiego Santa Cruz if (err) 780ac9da0e0SDiego Santa Cruz return err; 781ac9da0e0SDiego Santa Cruz 782ac9da0e0SDiego Santa Cruz max_enh_size_mult = 783ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) + 784ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) + 785ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]; 786ac9da0e0SDiego Santa Cruz if (tot_enh_size_mult > max_enh_size_mult) { 787ac9da0e0SDiego Santa Cruz printf("Total enhanced size exceeds maximum (%u > %u)\n", 788ac9da0e0SDiego Santa Cruz tot_enh_size_mult, max_enh_size_mult); 789ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 790ac9da0e0SDiego Santa Cruz } 791ac9da0e0SDiego Santa Cruz 7928dda5b0eSDiego Santa Cruz /* The default value of EXT_CSD_WR_REL_SET is device 7938dda5b0eSDiego Santa Cruz * dependent, the values can only be changed if the 7948dda5b0eSDiego Santa Cruz * EXT_CSD_HS_CTRL_REL bit is set. The values can be 7958dda5b0eSDiego Santa Cruz * changed only once and before partitioning is completed. */ 7968dda5b0eSDiego Santa Cruz wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 7978dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_change) { 7988dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_set) 7998dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_USR; 8008dda5b0eSDiego Santa Cruz else 8018dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR; 8028dda5b0eSDiego Santa Cruz } 8038dda5b0eSDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 8048dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_change) { 8058dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_set) 8068dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx); 8078dda5b0eSDiego Santa Cruz else 8088dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx); 8098dda5b0eSDiego Santa Cruz } 8108dda5b0eSDiego Santa Cruz } 8118dda5b0eSDiego Santa Cruz 8128dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] && 8138dda5b0eSDiego Santa Cruz !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) { 8148dda5b0eSDiego Santa Cruz puts("Card does not support host controlled partition write " 8158dda5b0eSDiego Santa Cruz "reliability settings\n"); 8168dda5b0eSDiego Santa Cruz return -EMEDIUMTYPE; 8178dda5b0eSDiego Santa Cruz } 8188dda5b0eSDiego Santa Cruz 819ac9da0e0SDiego Santa Cruz if (ext_csd[EXT_CSD_PARTITION_SETTING] & 820ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED) { 821ac9da0e0SDiego Santa Cruz printf("Card already partitioned\n"); 822ac9da0e0SDiego Santa Cruz return -EPERM; 823ac9da0e0SDiego Santa Cruz } 824ac9da0e0SDiego Santa Cruz 825ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_CHECK) 826ac9da0e0SDiego Santa Cruz return 0; 827ac9da0e0SDiego Santa Cruz 828ac9da0e0SDiego Santa Cruz /* Partitioning requires high-capacity size definitions */ 829ac9da0e0SDiego Santa Cruz if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) { 830ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 831ac9da0e0SDiego Santa Cruz EXT_CSD_ERASE_GROUP_DEF, 1); 832ac9da0e0SDiego Santa Cruz 833ac9da0e0SDiego Santa Cruz if (err) 834ac9da0e0SDiego Santa Cruz return err; 835ac9da0e0SDiego Santa Cruz 836ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 837ac9da0e0SDiego Santa Cruz 838ac9da0e0SDiego Santa Cruz /* update erase group size to be high-capacity */ 839ac9da0e0SDiego Santa Cruz mmc->erase_grp_size = 840ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 841ac9da0e0SDiego Santa Cruz 842ac9da0e0SDiego Santa Cruz } 843ac9da0e0SDiego Santa Cruz 844ac9da0e0SDiego Santa Cruz /* all OK, write the configuration */ 845ac9da0e0SDiego Santa Cruz for (i = 0; i < 4; i++) { 846ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 847ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_START_ADDR+i, 848ac9da0e0SDiego Santa Cruz (enh_start_addr >> (i*8)) & 0xFF); 849ac9da0e0SDiego Santa Cruz if (err) 850ac9da0e0SDiego Santa Cruz return err; 851ac9da0e0SDiego Santa Cruz } 852ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 853ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 854ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_SIZE_MULT+i, 855ac9da0e0SDiego Santa Cruz (enh_size_mult >> (i*8)) & 0xFF); 856ac9da0e0SDiego Santa Cruz if (err) 857ac9da0e0SDiego Santa Cruz return err; 858ac9da0e0SDiego Santa Cruz } 859ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 860ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 861ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 862ac9da0e0SDiego Santa Cruz EXT_CSD_GP_SIZE_MULT+pidx*3+i, 863ac9da0e0SDiego Santa Cruz (gp_size_mult[pidx] >> (i*8)) & 0xFF); 864ac9da0e0SDiego Santa Cruz if (err) 865ac9da0e0SDiego Santa Cruz return err; 866ac9da0e0SDiego Santa Cruz } 867ac9da0e0SDiego Santa Cruz } 868ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 869ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs); 870ac9da0e0SDiego Santa Cruz if (err) 871ac9da0e0SDiego Santa Cruz return err; 872ac9da0e0SDiego Santa Cruz 873ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_SET) 874ac9da0e0SDiego Santa Cruz return 0; 875ac9da0e0SDiego Santa Cruz 8768dda5b0eSDiego Santa Cruz /* The WR_REL_SET is a write-once register but shall be 8778dda5b0eSDiego Santa Cruz * written before setting PART_SETTING_COMPLETED. As it is 8788dda5b0eSDiego Santa Cruz * write-once we can only write it when completing the 8798dda5b0eSDiego Santa Cruz * partitioning. */ 8808dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) { 8818dda5b0eSDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 8828dda5b0eSDiego Santa Cruz EXT_CSD_WR_REL_SET, wr_rel_set); 8838dda5b0eSDiego Santa Cruz if (err) 8848dda5b0eSDiego Santa Cruz return err; 8858dda5b0eSDiego Santa Cruz } 8868dda5b0eSDiego Santa Cruz 887ac9da0e0SDiego Santa Cruz /* Setting PART_SETTING_COMPLETED confirms the partition 888ac9da0e0SDiego Santa Cruz * configuration but it only becomes effective after power 889ac9da0e0SDiego Santa Cruz * cycle, so we do not adjust the partition related settings 890ac9da0e0SDiego Santa Cruz * in the mmc struct. */ 891ac9da0e0SDiego Santa Cruz 892ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 893ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING, 894ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 895ac9da0e0SDiego Santa Cruz if (err) 896ac9da0e0SDiego Santa Cruz return err; 897ac9da0e0SDiego Santa Cruz 898ac9da0e0SDiego Santa Cruz return 0; 899ac9da0e0SDiego Santa Cruz } 900ac9da0e0SDiego Santa Cruz 901e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 90248972d90SThierry Reding int mmc_getcd(struct mmc *mmc) 90348972d90SThierry Reding { 90448972d90SThierry Reding int cd; 90548972d90SThierry Reding 90648972d90SThierry Reding cd = board_mmc_getcd(mmc); 90748972d90SThierry Reding 908d4e1da4eSPeter Korsgaard if (cd < 0) { 90993bfd616SPantelis Antoniou if (mmc->cfg->ops->getcd) 91093bfd616SPantelis Antoniou cd = mmc->cfg->ops->getcd(mmc); 911d4e1da4eSPeter Korsgaard else 912d4e1da4eSPeter Korsgaard cd = 1; 913d4e1da4eSPeter Korsgaard } 91448972d90SThierry Reding 91548972d90SThierry Reding return cd; 91648972d90SThierry Reding } 9178ca51e51SSimon Glass #endif 91848972d90SThierry Reding 919fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) 920272cc70bSAndy Fleming { 921272cc70bSAndy Fleming struct mmc_cmd cmd; 922272cc70bSAndy Fleming struct mmc_data data; 923272cc70bSAndy Fleming 924272cc70bSAndy Fleming /* Switch the frequency */ 925272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC; 926272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 927272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff; 928272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4)); 929272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4); 930272cc70bSAndy Fleming 931272cc70bSAndy Fleming data.dest = (char *)resp; 932272cc70bSAndy Fleming data.blocksize = 64; 933272cc70bSAndy Fleming data.blocks = 1; 934272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 935272cc70bSAndy Fleming 936272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 937272cc70bSAndy Fleming } 938272cc70bSAndy Fleming 939272cc70bSAndy Fleming 940*d0c221feSJean-Jacques Hiblot static int sd_get_capabilities(struct mmc *mmc) 941272cc70bSAndy Fleming { 942272cc70bSAndy Fleming int err; 943272cc70bSAndy Fleming struct mmc_cmd cmd; 94418e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2); 94518e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16); 946272cc70bSAndy Fleming struct mmc_data data; 947272cc70bSAndy Fleming int timeout; 948272cc70bSAndy Fleming 949*d0c221feSJean-Jacques Hiblot mmc->card_caps = MMC_MODE_1BIT; 950272cc70bSAndy Fleming 951d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 952d52ebf10SThomas Chou return 0; 953d52ebf10SThomas Chou 954272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */ 955272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 956272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 957272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 958272cc70bSAndy Fleming 959272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 960272cc70bSAndy Fleming 961272cc70bSAndy Fleming if (err) 962272cc70bSAndy Fleming return err; 963272cc70bSAndy Fleming 964272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR; 965272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 966272cc70bSAndy Fleming cmd.cmdarg = 0; 967272cc70bSAndy Fleming 968272cc70bSAndy Fleming timeout = 3; 969272cc70bSAndy Fleming 970272cc70bSAndy Fleming retry_scr: 971f781dd38SAnton staaf data.dest = (char *)scr; 972272cc70bSAndy Fleming data.blocksize = 8; 973272cc70bSAndy Fleming data.blocks = 1; 974272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 975272cc70bSAndy Fleming 976272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 977272cc70bSAndy Fleming 978272cc70bSAndy Fleming if (err) { 979272cc70bSAndy Fleming if (timeout--) 980272cc70bSAndy Fleming goto retry_scr; 981272cc70bSAndy Fleming 982272cc70bSAndy Fleming return err; 983272cc70bSAndy Fleming } 984272cc70bSAndy Fleming 9854e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]); 9864e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]); 987272cc70bSAndy Fleming 988272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) { 989272cc70bSAndy Fleming case 0: 990272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 991272cc70bSAndy Fleming break; 992272cc70bSAndy Fleming case 1: 993272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10; 994272cc70bSAndy Fleming break; 995272cc70bSAndy Fleming case 2: 996272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 9971741c64dSJaehoon Chung if ((mmc->scr[0] >> 15) & 0x1) 9981741c64dSJaehoon Chung mmc->version = SD_VERSION_3; 999272cc70bSAndy Fleming break; 1000272cc70bSAndy Fleming default: 1001272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1002272cc70bSAndy Fleming break; 1003272cc70bSAndy Fleming } 1004272cc70bSAndy Fleming 1005b44c7083SAlagu Sankar if (mmc->scr[0] & SD_DATA_4BIT) 1006b44c7083SAlagu Sankar mmc->card_caps |= MMC_MODE_4BIT; 1007b44c7083SAlagu Sankar 1008272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */ 1009272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0) 1010272cc70bSAndy Fleming return 0; 1011272cc70bSAndy Fleming 1012272cc70bSAndy Fleming timeout = 4; 1013272cc70bSAndy Fleming while (timeout--) { 1014272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, 1015f781dd38SAnton staaf (u8 *)switch_status); 1016272cc70bSAndy Fleming 1017272cc70bSAndy Fleming if (err) 1018272cc70bSAndy Fleming return err; 1019272cc70bSAndy Fleming 1020272cc70bSAndy Fleming /* The high-speed function is busy. Try again */ 10214e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) 1022272cc70bSAndy Fleming break; 1023272cc70bSAndy Fleming } 1024272cc70bSAndy Fleming 1025272cc70bSAndy Fleming /* If high-speed isn't supported, we return */ 1026*d0c221feSJean-Jacques Hiblot if (__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED) 1027*d0c221feSJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(SD_HS); 1028272cc70bSAndy Fleming 10292c3fbf4cSMacpaul Lin return 0; 1030*d0c221feSJean-Jacques Hiblot } 1031*d0c221feSJean-Jacques Hiblot 1032*d0c221feSJean-Jacques Hiblot static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode) 1033*d0c221feSJean-Jacques Hiblot { 1034*d0c221feSJean-Jacques Hiblot int err; 1035*d0c221feSJean-Jacques Hiblot 1036*d0c221feSJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16); 10372c3fbf4cSMacpaul Lin 1038f781dd38SAnton staaf err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status); 1039272cc70bSAndy Fleming if (err) 1040272cc70bSAndy Fleming return err; 1041272cc70bSAndy Fleming 1042*d0c221feSJean-Jacques Hiblot if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) != 0x01000000) 1043*d0c221feSJean-Jacques Hiblot return -ENOTSUPP; 1044*d0c221feSJean-Jacques Hiblot 1045*d0c221feSJean-Jacques Hiblot return 0; 1046*d0c221feSJean-Jacques Hiblot } 1047*d0c221feSJean-Jacques Hiblot 1048*d0c221feSJean-Jacques Hiblot int sd_select_bus_width(struct mmc *mmc, int w) 1049*d0c221feSJean-Jacques Hiblot { 1050*d0c221feSJean-Jacques Hiblot int err; 1051*d0c221feSJean-Jacques Hiblot struct mmc_cmd cmd; 1052*d0c221feSJean-Jacques Hiblot 1053*d0c221feSJean-Jacques Hiblot if ((w != 4) && (w != 1)) 1054*d0c221feSJean-Jacques Hiblot return -EINVAL; 1055*d0c221feSJean-Jacques Hiblot 1056*d0c221feSJean-Jacques Hiblot cmd.cmdidx = MMC_CMD_APP_CMD; 1057*d0c221feSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 1058*d0c221feSJean-Jacques Hiblot cmd.cmdarg = mmc->rca << 16; 1059*d0c221feSJean-Jacques Hiblot 1060*d0c221feSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 1061*d0c221feSJean-Jacques Hiblot if (err) 1062*d0c221feSJean-Jacques Hiblot return err; 1063*d0c221feSJean-Jacques Hiblot 1064*d0c221feSJean-Jacques Hiblot cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; 1065*d0c221feSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 1066*d0c221feSJean-Jacques Hiblot if (w == 4) 1067*d0c221feSJean-Jacques Hiblot cmd.cmdarg = 2; 1068*d0c221feSJean-Jacques Hiblot else if (w == 1) 1069*d0c221feSJean-Jacques Hiblot cmd.cmdarg = 0; 1070*d0c221feSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 1071*d0c221feSJean-Jacques Hiblot if (err) 1072*d0c221feSJean-Jacques Hiblot return err; 1073272cc70bSAndy Fleming 1074272cc70bSAndy Fleming return 0; 1075272cc70bSAndy Fleming } 1076272cc70bSAndy Fleming 10773697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc) 10783697e599SPeng Fan { 10793697e599SPeng Fan int err, i; 10803697e599SPeng Fan struct mmc_cmd cmd; 10813697e599SPeng Fan ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16); 10823697e599SPeng Fan struct mmc_data data; 10833697e599SPeng Fan int timeout = 3; 10843697e599SPeng Fan unsigned int au, eo, et, es; 10853697e599SPeng Fan 10863697e599SPeng Fan cmd.cmdidx = MMC_CMD_APP_CMD; 10873697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 10883697e599SPeng Fan cmd.cmdarg = mmc->rca << 16; 10893697e599SPeng Fan 10903697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, NULL); 10913697e599SPeng Fan if (err) 10923697e599SPeng Fan return err; 10933697e599SPeng Fan 10943697e599SPeng Fan cmd.cmdidx = SD_CMD_APP_SD_STATUS; 10953697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 10963697e599SPeng Fan cmd.cmdarg = 0; 10973697e599SPeng Fan 10983697e599SPeng Fan retry_ssr: 10993697e599SPeng Fan data.dest = (char *)ssr; 11003697e599SPeng Fan data.blocksize = 64; 11013697e599SPeng Fan data.blocks = 1; 11023697e599SPeng Fan data.flags = MMC_DATA_READ; 11033697e599SPeng Fan 11043697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, &data); 11053697e599SPeng Fan if (err) { 11063697e599SPeng Fan if (timeout--) 11073697e599SPeng Fan goto retry_ssr; 11083697e599SPeng Fan 11093697e599SPeng Fan return err; 11103697e599SPeng Fan } 11113697e599SPeng Fan 11123697e599SPeng Fan for (i = 0; i < 16; i++) 11133697e599SPeng Fan ssr[i] = be32_to_cpu(ssr[i]); 11143697e599SPeng Fan 11153697e599SPeng Fan au = (ssr[2] >> 12) & 0xF; 11163697e599SPeng Fan if ((au <= 9) || (mmc->version == SD_VERSION_3)) { 11173697e599SPeng Fan mmc->ssr.au = sd_au_size[au]; 11183697e599SPeng Fan es = (ssr[3] >> 24) & 0xFF; 11193697e599SPeng Fan es |= (ssr[2] & 0xFF) << 8; 11203697e599SPeng Fan et = (ssr[3] >> 18) & 0x3F; 11213697e599SPeng Fan if (es && et) { 11223697e599SPeng Fan eo = (ssr[3] >> 16) & 0x3; 11233697e599SPeng Fan mmc->ssr.erase_timeout = (et * 1000) / es; 11243697e599SPeng Fan mmc->ssr.erase_offset = eo * 1000; 11253697e599SPeng Fan } 11263697e599SPeng Fan } else { 11273697e599SPeng Fan debug("Invalid Allocation Unit Size.\n"); 11283697e599SPeng Fan } 11293697e599SPeng Fan 11303697e599SPeng Fan return 0; 11313697e599SPeng Fan } 11323697e599SPeng Fan 1133272cc70bSAndy Fleming /* frequency bases */ 1134272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */ 11355f837c2cSMike Frysinger static const int fbase[] = { 1136272cc70bSAndy Fleming 10000, 1137272cc70bSAndy Fleming 100000, 1138272cc70bSAndy Fleming 1000000, 1139272cc70bSAndy Fleming 10000000, 1140272cc70bSAndy Fleming }; 1141272cc70bSAndy Fleming 1142272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice 1143272cc70bSAndy Fleming * to platforms without floating point. 1144272cc70bSAndy Fleming */ 114561fe076fSSimon Glass static const u8 multipliers[] = { 1146272cc70bSAndy Fleming 0, /* reserved */ 1147272cc70bSAndy Fleming 10, 1148272cc70bSAndy Fleming 12, 1149272cc70bSAndy Fleming 13, 1150272cc70bSAndy Fleming 15, 1151272cc70bSAndy Fleming 20, 1152272cc70bSAndy Fleming 25, 1153272cc70bSAndy Fleming 30, 1154272cc70bSAndy Fleming 35, 1155272cc70bSAndy Fleming 40, 1156272cc70bSAndy Fleming 45, 1157272cc70bSAndy Fleming 50, 1158272cc70bSAndy Fleming 55, 1159272cc70bSAndy Fleming 60, 1160272cc70bSAndy Fleming 70, 1161272cc70bSAndy Fleming 80, 1162272cc70bSAndy Fleming }; 1163272cc70bSAndy Fleming 1164*d0c221feSJean-Jacques Hiblot static inline int bus_width(uint cap) 1165*d0c221feSJean-Jacques Hiblot { 1166*d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_8BIT) 1167*d0c221feSJean-Jacques Hiblot return 8; 1168*d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_4BIT) 1169*d0c221feSJean-Jacques Hiblot return 4; 1170*d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_1BIT) 1171*d0c221feSJean-Jacques Hiblot return 1; 1172*d0c221feSJean-Jacques Hiblot printf("invalid bus witdh capability 0x%x\n", cap); 1173*d0c221feSJean-Jacques Hiblot return 0; 1174*d0c221feSJean-Jacques Hiblot } 1175*d0c221feSJean-Jacques Hiblot 1176e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 1177fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc) 1178272cc70bSAndy Fleming { 117993bfd616SPantelis Antoniou if (mmc->cfg->ops->set_ios) 118093bfd616SPantelis Antoniou mmc->cfg->ops->set_ios(mmc); 1181272cc70bSAndy Fleming } 11828ca51e51SSimon Glass #endif 1183272cc70bSAndy Fleming 1184272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock) 1185272cc70bSAndy Fleming { 118693bfd616SPantelis Antoniou if (clock > mmc->cfg->f_max) 118793bfd616SPantelis Antoniou clock = mmc->cfg->f_max; 1188272cc70bSAndy Fleming 118993bfd616SPantelis Antoniou if (clock < mmc->cfg->f_min) 119093bfd616SPantelis Antoniou clock = mmc->cfg->f_min; 1191272cc70bSAndy Fleming 1192272cc70bSAndy Fleming mmc->clock = clock; 1193272cc70bSAndy Fleming 1194272cc70bSAndy Fleming mmc_set_ios(mmc); 1195272cc70bSAndy Fleming } 1196272cc70bSAndy Fleming 1197fdbb873eSKim Phillips static void mmc_set_bus_width(struct mmc *mmc, uint width) 1198272cc70bSAndy Fleming { 1199272cc70bSAndy Fleming mmc->bus_width = width; 1200272cc70bSAndy Fleming 1201272cc70bSAndy Fleming mmc_set_ios(mmc); 1202272cc70bSAndy Fleming } 1203272cc70bSAndy Fleming 12044c9d2aaaSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG) 12054c9d2aaaSJean-Jacques Hiblot /* 12064c9d2aaaSJean-Jacques Hiblot * helper function to display the capabilities in a human 12074c9d2aaaSJean-Jacques Hiblot * friendly manner. The capabilities include bus width and 12084c9d2aaaSJean-Jacques Hiblot * supported modes. 12094c9d2aaaSJean-Jacques Hiblot */ 12104c9d2aaaSJean-Jacques Hiblot void mmc_dump_capabilities(const char *text, uint caps) 12114c9d2aaaSJean-Jacques Hiblot { 12124c9d2aaaSJean-Jacques Hiblot enum bus_mode mode; 12134c9d2aaaSJean-Jacques Hiblot 12144c9d2aaaSJean-Jacques Hiblot printf("%s: widths [", text); 12154c9d2aaaSJean-Jacques Hiblot if (caps & MMC_MODE_8BIT) 12164c9d2aaaSJean-Jacques Hiblot printf("8, "); 12174c9d2aaaSJean-Jacques Hiblot if (caps & MMC_MODE_4BIT) 12184c9d2aaaSJean-Jacques Hiblot printf("4, "); 1219*d0c221feSJean-Jacques Hiblot if (caps & MMC_MODE_1BIT) 1220*d0c221feSJean-Jacques Hiblot printf("1, "); 1221*d0c221feSJean-Jacques Hiblot printf("\b\b] modes ["); 12224c9d2aaaSJean-Jacques Hiblot for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++) 12234c9d2aaaSJean-Jacques Hiblot if (MMC_CAP(mode) & caps) 12244c9d2aaaSJean-Jacques Hiblot printf("%s, ", mmc_mode_name(mode)); 12254c9d2aaaSJean-Jacques Hiblot printf("\b\b]\n"); 12264c9d2aaaSJean-Jacques Hiblot } 12274c9d2aaaSJean-Jacques Hiblot #endif 12284c9d2aaaSJean-Jacques Hiblot 1229*d0c221feSJean-Jacques Hiblot struct mode_width_tuning { 1230*d0c221feSJean-Jacques Hiblot enum bus_mode mode; 1231*d0c221feSJean-Jacques Hiblot uint widths; 1232*d0c221feSJean-Jacques Hiblot }; 1233*d0c221feSJean-Jacques Hiblot 1234*d0c221feSJean-Jacques Hiblot static const struct mode_width_tuning sd_modes_by_pref[] = { 1235*d0c221feSJean-Jacques Hiblot { 1236*d0c221feSJean-Jacques Hiblot .mode = SD_HS, 1237*d0c221feSJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1238*d0c221feSJean-Jacques Hiblot }, 1239*d0c221feSJean-Jacques Hiblot { 1240*d0c221feSJean-Jacques Hiblot .mode = SD_LEGACY, 1241*d0c221feSJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1242*d0c221feSJean-Jacques Hiblot } 1243*d0c221feSJean-Jacques Hiblot }; 1244*d0c221feSJean-Jacques Hiblot 1245*d0c221feSJean-Jacques Hiblot #define for_each_sd_mode_by_pref(caps, mwt) \ 1246*d0c221feSJean-Jacques Hiblot for (mwt = sd_modes_by_pref;\ 1247*d0c221feSJean-Jacques Hiblot mwt < sd_modes_by_pref + ARRAY_SIZE(sd_modes_by_pref);\ 1248*d0c221feSJean-Jacques Hiblot mwt++) \ 1249*d0c221feSJean-Jacques Hiblot if (caps & MMC_CAP(mwt->mode)) 1250*d0c221feSJean-Jacques Hiblot 1251*d0c221feSJean-Jacques Hiblot static int sd_select_mode_and_width(struct mmc *mmc) 12528ac8a263SJean-Jacques Hiblot { 12538ac8a263SJean-Jacques Hiblot int err; 1254*d0c221feSJean-Jacques Hiblot uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT}; 1255*d0c221feSJean-Jacques Hiblot const struct mode_width_tuning *mwt; 12568ac8a263SJean-Jacques Hiblot 1257*d0c221feSJean-Jacques Hiblot err = sd_get_capabilities(mmc); 12588ac8a263SJean-Jacques Hiblot if (err) 12598ac8a263SJean-Jacques Hiblot return err; 12608ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */ 1261*d0c221feSJean-Jacques Hiblot mmc->card_caps &= (mmc->cfg->host_caps | MMC_MODE_1BIT); 12628ac8a263SJean-Jacques Hiblot 1263*d0c221feSJean-Jacques Hiblot for_each_sd_mode_by_pref(mmc->card_caps, mwt) { 1264*d0c221feSJean-Jacques Hiblot uint *w; 12658ac8a263SJean-Jacques Hiblot 1266*d0c221feSJean-Jacques Hiblot for (w = widths; w < widths + ARRAY_SIZE(widths); w++) { 1267*d0c221feSJean-Jacques Hiblot if (*w & mmc->card_caps & mwt->widths) { 1268*d0c221feSJean-Jacques Hiblot debug("trying mode %s width %d (at %d MHz)\n", 1269*d0c221feSJean-Jacques Hiblot mmc_mode_name(mwt->mode), 1270*d0c221feSJean-Jacques Hiblot bus_width(*w), 1271*d0c221feSJean-Jacques Hiblot mmc_mode2freq(mmc, mwt->mode) / 1000000); 1272*d0c221feSJean-Jacques Hiblot 1273*d0c221feSJean-Jacques Hiblot /* configure the bus width (card + host) */ 1274*d0c221feSJean-Jacques Hiblot err = sd_select_bus_width(mmc, bus_width(*w)); 12758ac8a263SJean-Jacques Hiblot if (err) 1276*d0c221feSJean-Jacques Hiblot goto error; 1277*d0c221feSJean-Jacques Hiblot mmc_set_bus_width(mmc, bus_width(*w)); 12788ac8a263SJean-Jacques Hiblot 1279*d0c221feSJean-Jacques Hiblot /* configure the bus mode (card) */ 1280*d0c221feSJean-Jacques Hiblot err = sd_set_card_speed(mmc, mwt->mode); 12818ac8a263SJean-Jacques Hiblot if (err) 1282*d0c221feSJean-Jacques Hiblot goto error; 12838ac8a263SJean-Jacques Hiblot 1284*d0c221feSJean-Jacques Hiblot /* configure the bus mode (host) */ 1285*d0c221feSJean-Jacques Hiblot mmc_select_mode(mmc, mwt->mode); 1286*d0c221feSJean-Jacques Hiblot mmc_set_clock(mmc, mmc->tran_speed); 12878ac8a263SJean-Jacques Hiblot 12888ac8a263SJean-Jacques Hiblot err = sd_read_ssr(mmc); 1289*d0c221feSJean-Jacques Hiblot if (!err) 12908ac8a263SJean-Jacques Hiblot return 0; 1291*d0c221feSJean-Jacques Hiblot 1292*d0c221feSJean-Jacques Hiblot printf("bad ssr\n"); 1293*d0c221feSJean-Jacques Hiblot 1294*d0c221feSJean-Jacques Hiblot error: 1295*d0c221feSJean-Jacques Hiblot /* revert to a safer bus speed */ 1296*d0c221feSJean-Jacques Hiblot mmc_select_mode(mmc, SD_LEGACY); 1297*d0c221feSJean-Jacques Hiblot mmc_set_clock(mmc, mmc->tran_speed); 1298*d0c221feSJean-Jacques Hiblot } 1299*d0c221feSJean-Jacques Hiblot } 1300*d0c221feSJean-Jacques Hiblot } 1301*d0c221feSJean-Jacques Hiblot 1302*d0c221feSJean-Jacques Hiblot printf("unable to select a mode\n"); 1303*d0c221feSJean-Jacques Hiblot return -ENOTSUPP; 13048ac8a263SJean-Jacques Hiblot } 13058ac8a263SJean-Jacques Hiblot 13067382e691SJean-Jacques Hiblot /* 13077382e691SJean-Jacques Hiblot * read the compare the part of ext csd that is constant. 13087382e691SJean-Jacques Hiblot * This can be used to check that the transfer is working 13097382e691SJean-Jacques Hiblot * as expected. 13107382e691SJean-Jacques Hiblot */ 13117382e691SJean-Jacques Hiblot static int mmc_read_and_compare_ext_csd(struct mmc *mmc) 13127382e691SJean-Jacques Hiblot { 13137382e691SJean-Jacques Hiblot int err; 13147382e691SJean-Jacques Hiblot const u8 *ext_csd = mmc->ext_csd; 13157382e691SJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 13167382e691SJean-Jacques Hiblot 13177382e691SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, test_csd); 13187382e691SJean-Jacques Hiblot if (err) 13197382e691SJean-Jacques Hiblot return err; 13207382e691SJean-Jacques Hiblot 13217382e691SJean-Jacques Hiblot /* Only compare read only fields */ 13227382e691SJean-Jacques Hiblot if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] 13237382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_PARTITIONING_SUPPORT] && 13247382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_WP_GRP_SIZE] 13257382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_WP_GRP_SIZE] && 13267382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_REV] 13277382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_REV] && 13287382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 13297382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] && 13307382e691SJean-Jacques Hiblot memcmp(&ext_csd[EXT_CSD_SEC_CNT], 13317382e691SJean-Jacques Hiblot &test_csd[EXT_CSD_SEC_CNT], 4) == 0) 13327382e691SJean-Jacques Hiblot return 0; 13337382e691SJean-Jacques Hiblot 13347382e691SJean-Jacques Hiblot return -EBADMSG; 13357382e691SJean-Jacques Hiblot } 13367382e691SJean-Jacques Hiblot 1337dfda9d88SJean-Jacques Hiblot static int mmc_select_bus_freq_width(struct mmc *mmc) 13388ac8a263SJean-Jacques Hiblot { 13398ac8a263SJean-Jacques Hiblot /* An array of possible bus widths in order of preference */ 13408ac8a263SJean-Jacques Hiblot static const unsigned int ext_csd_bits[] = { 13418ac8a263SJean-Jacques Hiblot EXT_CSD_DDR_BUS_WIDTH_8, 13428ac8a263SJean-Jacques Hiblot EXT_CSD_DDR_BUS_WIDTH_4, 13438ac8a263SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH_8, 13448ac8a263SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH_4, 13458ac8a263SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH_1, 13468ac8a263SJean-Jacques Hiblot }; 13478ac8a263SJean-Jacques Hiblot /* An array to map CSD bus widths to host cap bits */ 13488ac8a263SJean-Jacques Hiblot static const unsigned int ext_to_hostcaps[] = { 13498ac8a263SJean-Jacques Hiblot [EXT_CSD_DDR_BUS_WIDTH_4] = 13508ac8a263SJean-Jacques Hiblot MMC_MODE_DDR_52MHz | MMC_MODE_4BIT, 13518ac8a263SJean-Jacques Hiblot [EXT_CSD_DDR_BUS_WIDTH_8] = 13528ac8a263SJean-Jacques Hiblot MMC_MODE_DDR_52MHz | MMC_MODE_8BIT, 13538ac8a263SJean-Jacques Hiblot [EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT, 13548ac8a263SJean-Jacques Hiblot [EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT, 13558ac8a263SJean-Jacques Hiblot }; 13568ac8a263SJean-Jacques Hiblot /* An array to map chosen bus width to an integer */ 13578ac8a263SJean-Jacques Hiblot static const unsigned int widths[] = { 13588ac8a263SJean-Jacques Hiblot 8, 4, 8, 4, 1, 13598ac8a263SJean-Jacques Hiblot }; 13608ac8a263SJean-Jacques Hiblot int err; 13618ac8a263SJean-Jacques Hiblot int idx; 13628ac8a263SJean-Jacques Hiblot 13638ac8a263SJean-Jacques Hiblot err = mmc_change_freq(mmc); 13648ac8a263SJean-Jacques Hiblot if (err) 13658ac8a263SJean-Jacques Hiblot return err; 13668ac8a263SJean-Jacques Hiblot 13678ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */ 1368*d0c221feSJean-Jacques Hiblot mmc->card_caps &= (mmc->cfg->host_caps | MMC_MODE_1BIT); 13698ac8a263SJean-Jacques Hiblot 13708ac8a263SJean-Jacques Hiblot /* Only version 4 of MMC supports wider bus widths */ 13718ac8a263SJean-Jacques Hiblot if (mmc->version < MMC_VERSION_4) 13728ac8a263SJean-Jacques Hiblot return 0; 13738ac8a263SJean-Jacques Hiblot 1374dfda9d88SJean-Jacques Hiblot if (!mmc->ext_csd) { 1375dfda9d88SJean-Jacques Hiblot debug("No ext_csd found!\n"); /* this should enver happen */ 1376dfda9d88SJean-Jacques Hiblot return -ENOTSUPP; 1377dfda9d88SJean-Jacques Hiblot } 1378dfda9d88SJean-Jacques Hiblot 13798ac8a263SJean-Jacques Hiblot for (idx = 0; idx < ARRAY_SIZE(ext_csd_bits); idx++) { 13808ac8a263SJean-Jacques Hiblot unsigned int extw = ext_csd_bits[idx]; 13818ac8a263SJean-Jacques Hiblot unsigned int caps = ext_to_hostcaps[extw]; 13828ac8a263SJean-Jacques Hiblot /* 13838ac8a263SJean-Jacques Hiblot * If the bus width is still not changed, 13848ac8a263SJean-Jacques Hiblot * don't try to set the default again. 13858ac8a263SJean-Jacques Hiblot * Otherwise, recover from switch attempts 13868ac8a263SJean-Jacques Hiblot * by switching to 1-bit bus width. 13878ac8a263SJean-Jacques Hiblot */ 13888ac8a263SJean-Jacques Hiblot if (extw == EXT_CSD_BUS_WIDTH_1 && 13898ac8a263SJean-Jacques Hiblot mmc->bus_width == 1) { 13908ac8a263SJean-Jacques Hiblot err = 0; 13918ac8a263SJean-Jacques Hiblot break; 13928ac8a263SJean-Jacques Hiblot } 13938ac8a263SJean-Jacques Hiblot 13948ac8a263SJean-Jacques Hiblot /* 13958ac8a263SJean-Jacques Hiblot * Check to make sure the card and controller support 13968ac8a263SJean-Jacques Hiblot * these capabilities 13978ac8a263SJean-Jacques Hiblot */ 13988ac8a263SJean-Jacques Hiblot if ((mmc->card_caps & caps) != caps) 13998ac8a263SJean-Jacques Hiblot continue; 14008ac8a263SJean-Jacques Hiblot 14018ac8a263SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 14028ac8a263SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, extw); 14038ac8a263SJean-Jacques Hiblot 14048ac8a263SJean-Jacques Hiblot if (err) 14058ac8a263SJean-Jacques Hiblot continue; 14068ac8a263SJean-Jacques Hiblot 14078ac8a263SJean-Jacques Hiblot mmc->ddr_mode = (caps & MMC_MODE_DDR_52MHz) ? 1 : 0; 14088ac8a263SJean-Jacques Hiblot mmc_set_bus_width(mmc, widths[idx]); 14098ac8a263SJean-Jacques Hiblot 14107382e691SJean-Jacques Hiblot err = mmc_read_and_compare_ext_csd(mmc); 14117382e691SJean-Jacques Hiblot if (!err) 14128ac8a263SJean-Jacques Hiblot break; 14138ac8a263SJean-Jacques Hiblot } 14148ac8a263SJean-Jacques Hiblot 14158ac8a263SJean-Jacques Hiblot if (err) 14168ac8a263SJean-Jacques Hiblot return err; 14178ac8a263SJean-Jacques Hiblot 141835f9e196SJean-Jacques Hiblot if (mmc->card_caps & MMC_MODE_HS_52MHz) { 141935f9e196SJean-Jacques Hiblot if (mmc->ddr_mode) 142035f9e196SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_DDR_52); 14218ac8a263SJean-Jacques Hiblot else 142235f9e196SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_HS_52); 142305038576SJean-Jacques Hiblot } else if (mmc->card_caps & MMC_MODE_HS) 142435f9e196SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_HS); 14258ac8a263SJean-Jacques Hiblot 14268ac8a263SJean-Jacques Hiblot return err; 14278ac8a263SJean-Jacques Hiblot } 14288ac8a263SJean-Jacques Hiblot 1429dfda9d88SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc) 1430c744b6f6SJean-Jacques Hiblot { 1431c744b6f6SJean-Jacques Hiblot int err, i; 1432c744b6f6SJean-Jacques Hiblot u64 capacity; 1433c744b6f6SJean-Jacques Hiblot bool has_parts = false; 1434c744b6f6SJean-Jacques Hiblot bool part_completed; 1435dfda9d88SJean-Jacques Hiblot u8 *ext_csd; 1436c744b6f6SJean-Jacques Hiblot 1437c744b6f6SJean-Jacques Hiblot if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4)) 1438c744b6f6SJean-Jacques Hiblot return 0; 1439c744b6f6SJean-Jacques Hiblot 1440dfda9d88SJean-Jacques Hiblot ext_csd = malloc_cache_aligned(MMC_MAX_BLOCK_LEN); 1441dfda9d88SJean-Jacques Hiblot if (!ext_csd) 1442dfda9d88SJean-Jacques Hiblot return -ENOMEM; 1443dfda9d88SJean-Jacques Hiblot 1444dfda9d88SJean-Jacques Hiblot mmc->ext_csd = ext_csd; 1445dfda9d88SJean-Jacques Hiblot 1446c744b6f6SJean-Jacques Hiblot /* check ext_csd version and capacity */ 1447c744b6f6SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, ext_csd); 1448c744b6f6SJean-Jacques Hiblot if (err) 1449c744b6f6SJean-Jacques Hiblot return err; 1450c744b6f6SJean-Jacques Hiblot if (ext_csd[EXT_CSD_REV] >= 2) { 1451c744b6f6SJean-Jacques Hiblot /* 1452c744b6f6SJean-Jacques Hiblot * According to the JEDEC Standard, the value of 1453c744b6f6SJean-Jacques Hiblot * ext_csd's capacity is valid if the value is more 1454c744b6f6SJean-Jacques Hiblot * than 2GB 1455c744b6f6SJean-Jacques Hiblot */ 1456c744b6f6SJean-Jacques Hiblot capacity = ext_csd[EXT_CSD_SEC_CNT] << 0 1457c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 1458c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 1459c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; 1460c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN; 1461c744b6f6SJean-Jacques Hiblot if ((capacity >> 20) > 2 * 1024) 1462c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity; 1463c744b6f6SJean-Jacques Hiblot } 1464c744b6f6SJean-Jacques Hiblot 1465c744b6f6SJean-Jacques Hiblot switch (ext_csd[EXT_CSD_REV]) { 1466c744b6f6SJean-Jacques Hiblot case 1: 1467c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_1; 1468c744b6f6SJean-Jacques Hiblot break; 1469c744b6f6SJean-Jacques Hiblot case 2: 1470c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_2; 1471c744b6f6SJean-Jacques Hiblot break; 1472c744b6f6SJean-Jacques Hiblot case 3: 1473c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_3; 1474c744b6f6SJean-Jacques Hiblot break; 1475c744b6f6SJean-Jacques Hiblot case 5: 1476c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_41; 1477c744b6f6SJean-Jacques Hiblot break; 1478c744b6f6SJean-Jacques Hiblot case 6: 1479c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_5; 1480c744b6f6SJean-Jacques Hiblot break; 1481c744b6f6SJean-Jacques Hiblot case 7: 1482c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_5_0; 1483c744b6f6SJean-Jacques Hiblot break; 1484c744b6f6SJean-Jacques Hiblot case 8: 1485c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_5_1; 1486c744b6f6SJean-Jacques Hiblot break; 1487c744b6f6SJean-Jacques Hiblot } 1488c744b6f6SJean-Jacques Hiblot 1489c744b6f6SJean-Jacques Hiblot /* The partition data may be non-zero but it is only 1490c744b6f6SJean-Jacques Hiblot * effective if PARTITION_SETTING_COMPLETED is set in 1491c744b6f6SJean-Jacques Hiblot * EXT_CSD, so ignore any data if this bit is not set, 1492c744b6f6SJean-Jacques Hiblot * except for enabling the high-capacity group size 1493c744b6f6SJean-Jacques Hiblot * definition (see below). 1494c744b6f6SJean-Jacques Hiblot */ 1495c744b6f6SJean-Jacques Hiblot part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] & 1496c744b6f6SJean-Jacques Hiblot EXT_CSD_PARTITION_SETTING_COMPLETED); 1497c744b6f6SJean-Jacques Hiblot 1498c744b6f6SJean-Jacques Hiblot /* store the partition info of emmc */ 1499c744b6f6SJean-Jacques Hiblot mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT]; 1500c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || 1501c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_BOOT_MULT]) 1502c744b6f6SJean-Jacques Hiblot mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; 1503c744b6f6SJean-Jacques Hiblot if (part_completed && 1504c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT)) 1505c744b6f6SJean-Jacques Hiblot mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]; 1506c744b6f6SJean-Jacques Hiblot 1507c744b6f6SJean-Jacques Hiblot mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17; 1508c744b6f6SJean-Jacques Hiblot 1509c744b6f6SJean-Jacques Hiblot mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17; 1510c744b6f6SJean-Jacques Hiblot 1511c744b6f6SJean-Jacques Hiblot for (i = 0; i < 4; i++) { 1512c744b6f6SJean-Jacques Hiblot int idx = EXT_CSD_GP_SIZE_MULT + i * 3; 1513c744b6f6SJean-Jacques Hiblot uint mult = (ext_csd[idx + 2] << 16) + 1514c744b6f6SJean-Jacques Hiblot (ext_csd[idx + 1] << 8) + ext_csd[idx]; 1515c744b6f6SJean-Jacques Hiblot if (mult) 1516c744b6f6SJean-Jacques Hiblot has_parts = true; 1517c744b6f6SJean-Jacques Hiblot if (!part_completed) 1518c744b6f6SJean-Jacques Hiblot continue; 1519c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] = mult; 1520c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= 1521c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1522c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1523c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] <<= 19; 1524c744b6f6SJean-Jacques Hiblot } 1525c744b6f6SJean-Jacques Hiblot 1526c744b6f6SJean-Jacques Hiblot if (part_completed) { 1527c744b6f6SJean-Jacques Hiblot mmc->enh_user_size = 1528c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) + 1529c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) + 1530c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_SIZE_MULT]; 1531c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1532c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1533c744b6f6SJean-Jacques Hiblot mmc->enh_user_size <<= 19; 1534c744b6f6SJean-Jacques Hiblot mmc->enh_user_start = 1535c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) + 1536c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) + 1537c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) + 1538c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_START_ADDR]; 1539c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity) 1540c744b6f6SJean-Jacques Hiblot mmc->enh_user_start <<= 9; 1541c744b6f6SJean-Jacques Hiblot } 1542c744b6f6SJean-Jacques Hiblot 1543c744b6f6SJean-Jacques Hiblot /* 1544c744b6f6SJean-Jacques Hiblot * Host needs to enable ERASE_GRP_DEF bit if device is 1545c744b6f6SJean-Jacques Hiblot * partitioned. This bit will be lost every time after a reset 1546c744b6f6SJean-Jacques Hiblot * or power off. This will affect erase size. 1547c744b6f6SJean-Jacques Hiblot */ 1548c744b6f6SJean-Jacques Hiblot if (part_completed) 1549c744b6f6SJean-Jacques Hiblot has_parts = true; 1550c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) && 1551c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) 1552c744b6f6SJean-Jacques Hiblot has_parts = true; 1553c744b6f6SJean-Jacques Hiblot if (has_parts) { 1554c744b6f6SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1555c744b6f6SJean-Jacques Hiblot EXT_CSD_ERASE_GROUP_DEF, 1); 1556c744b6f6SJean-Jacques Hiblot 1557c744b6f6SJean-Jacques Hiblot if (err) 1558c744b6f6SJean-Jacques Hiblot return err; 1559c744b6f6SJean-Jacques Hiblot 1560c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 1561c744b6f6SJean-Jacques Hiblot } 1562c744b6f6SJean-Jacques Hiblot 1563c744b6f6SJean-Jacques Hiblot if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) { 1564c744b6f6SJean-Jacques Hiblot /* Read out group size from ext_csd */ 1565c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = 1566c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 1567c744b6f6SJean-Jacques Hiblot /* 1568c744b6f6SJean-Jacques Hiblot * if high capacity and partition setting completed 1569c744b6f6SJean-Jacques Hiblot * SEC_COUNT is valid even if it is smaller than 2 GiB 1570c744b6f6SJean-Jacques Hiblot * JEDEC Standard JESD84-B45, 6.2.4 1571c744b6f6SJean-Jacques Hiblot */ 1572c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity && part_completed) { 1573c744b6f6SJean-Jacques Hiblot capacity = (ext_csd[EXT_CSD_SEC_CNT]) | 1574c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) | 1575c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) | 1576c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 3] << 24); 1577c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN; 1578c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity; 1579c744b6f6SJean-Jacques Hiblot } 1580c744b6f6SJean-Jacques Hiblot } else { 1581c744b6f6SJean-Jacques Hiblot /* Calculate the group size from the csd value. */ 1582c744b6f6SJean-Jacques Hiblot int erase_gsz, erase_gmul; 1583c744b6f6SJean-Jacques Hiblot 1584c744b6f6SJean-Jacques Hiblot erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; 1585c744b6f6SJean-Jacques Hiblot erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; 1586c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = (erase_gsz + 1) 1587c744b6f6SJean-Jacques Hiblot * (erase_gmul + 1); 1588c744b6f6SJean-Jacques Hiblot } 1589c744b6f6SJean-Jacques Hiblot 1590c744b6f6SJean-Jacques Hiblot mmc->hc_wp_grp_size = 1024 1591c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 1592c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1593c744b6f6SJean-Jacques Hiblot 1594c744b6f6SJean-Jacques Hiblot mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 1595c744b6f6SJean-Jacques Hiblot 1596c744b6f6SJean-Jacques Hiblot return 0; 1597c744b6f6SJean-Jacques Hiblot } 1598c744b6f6SJean-Jacques Hiblot 1599fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc) 1600272cc70bSAndy Fleming { 1601f866a46dSStephen Warren int err, i; 1602272cc70bSAndy Fleming uint mult, freq; 1603c744b6f6SJean-Jacques Hiblot u64 cmult, csize; 1604272cc70bSAndy Fleming struct mmc_cmd cmd; 1605c40fdca6SSimon Glass struct blk_desc *bdesc; 1606272cc70bSAndy Fleming 1607d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON 1608d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ 1609d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; 1610d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R1; 1611d52ebf10SThomas Chou cmd.cmdarg = 1; 1612d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 1613d52ebf10SThomas Chou 1614d52ebf10SThomas Chou if (err) 1615d52ebf10SThomas Chou return err; 1616d52ebf10SThomas Chou } 1617d52ebf10SThomas Chou #endif 1618d52ebf10SThomas Chou 1619272cc70bSAndy Fleming /* Put the Card in Identify Mode */ 1620d52ebf10SThomas Chou cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : 1621d52ebf10SThomas Chou MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ 1622272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1623272cc70bSAndy Fleming cmd.cmdarg = 0; 1624272cc70bSAndy Fleming 1625272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1626272cc70bSAndy Fleming 1627272cc70bSAndy Fleming if (err) 1628272cc70bSAndy Fleming return err; 1629272cc70bSAndy Fleming 1630272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16); 1631272cc70bSAndy Fleming 1632272cc70bSAndy Fleming /* 1633272cc70bSAndy Fleming * For MMC cards, set the Relative Address. 1634272cc70bSAndy Fleming * For SD cards, get the Relatvie Address. 1635272cc70bSAndy Fleming * This also puts the cards into Standby State 1636272cc70bSAndy Fleming */ 1637d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1638272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; 1639272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1640272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6; 1641272cc70bSAndy Fleming 1642272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1643272cc70bSAndy Fleming 1644272cc70bSAndy Fleming if (err) 1645272cc70bSAndy Fleming return err; 1646272cc70bSAndy Fleming 1647272cc70bSAndy Fleming if (IS_SD(mmc)) 1648998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff; 1649d52ebf10SThomas Chou } 1650272cc70bSAndy Fleming 1651272cc70bSAndy Fleming /* Get the Card-Specific Data */ 1652272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD; 1653272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1654272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1655272cc70bSAndy Fleming 1656272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1657272cc70bSAndy Fleming 1658272cc70bSAndy Fleming if (err) 1659272cc70bSAndy Fleming return err; 1660272cc70bSAndy Fleming 1661998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0]; 1662998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1]; 1663998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2]; 1664998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3]; 1665272cc70bSAndy Fleming 1666272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) { 16670b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf; 1668272cc70bSAndy Fleming 1669272cc70bSAndy Fleming switch (version) { 1670272cc70bSAndy Fleming case 0: 1671272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1672272cc70bSAndy Fleming break; 1673272cc70bSAndy Fleming case 1: 1674272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4; 1675272cc70bSAndy Fleming break; 1676272cc70bSAndy Fleming case 2: 1677272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2; 1678272cc70bSAndy Fleming break; 1679272cc70bSAndy Fleming case 3: 1680272cc70bSAndy Fleming mmc->version = MMC_VERSION_3; 1681272cc70bSAndy Fleming break; 1682272cc70bSAndy Fleming case 4: 1683272cc70bSAndy Fleming mmc->version = MMC_VERSION_4; 1684272cc70bSAndy Fleming break; 1685272cc70bSAndy Fleming default: 1686272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1687272cc70bSAndy Fleming break; 1688272cc70bSAndy Fleming } 1689272cc70bSAndy Fleming } 1690272cc70bSAndy Fleming 1691272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */ 16920b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)]; 16930b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; 1694272cc70bSAndy Fleming 169535f9e196SJean-Jacques Hiblot mmc->legacy_speed = freq * mult; 169635f9e196SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_LEGACY); 1697272cc70bSAndy Fleming 1698ab71188cSMarkus Niebel mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); 1699998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); 1700272cc70bSAndy Fleming 1701272cc70bSAndy Fleming if (IS_SD(mmc)) 1702272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len; 1703272cc70bSAndy Fleming else 1704998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); 1705272cc70bSAndy Fleming 1706272cc70bSAndy Fleming if (mmc->high_capacity) { 1707272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16 1708272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16; 1709272cc70bSAndy Fleming cmult = 8; 1710272cc70bSAndy Fleming } else { 1711272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2 1712272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30; 1713272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15; 1714272cc70bSAndy Fleming } 1715272cc70bSAndy Fleming 1716f866a46dSStephen Warren mmc->capacity_user = (csize + 1) << (cmult + 2); 1717f866a46dSStephen Warren mmc->capacity_user *= mmc->read_bl_len; 1718f866a46dSStephen Warren mmc->capacity_boot = 0; 1719f866a46dSStephen Warren mmc->capacity_rpmb = 0; 1720f866a46dSStephen Warren for (i = 0; i < 4; i++) 1721f866a46dSStephen Warren mmc->capacity_gp[i] = 0; 1722272cc70bSAndy Fleming 17238bfa195eSSimon Glass if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN) 17248bfa195eSSimon Glass mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 1725272cc70bSAndy Fleming 17268bfa195eSSimon Glass if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) 17278bfa195eSSimon Glass mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 1728272cc70bSAndy Fleming 1729ab71188cSMarkus Niebel if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) { 1730ab71188cSMarkus Niebel cmd.cmdidx = MMC_CMD_SET_DSR; 1731ab71188cSMarkus Niebel cmd.cmdarg = (mmc->dsr & 0xffff) << 16; 1732ab71188cSMarkus Niebel cmd.resp_type = MMC_RSP_NONE; 1733ab71188cSMarkus Niebel if (mmc_send_cmd(mmc, &cmd, NULL)) 1734ab71188cSMarkus Niebel printf("MMC: SET_DSR failed\n"); 1735ab71188cSMarkus Niebel } 1736ab71188cSMarkus Niebel 1737272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */ 1738d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1739272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD; 1740fe8f7066SAjay Bhargav cmd.resp_type = MMC_RSP_R1; 1741272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1742272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1743272cc70bSAndy Fleming 1744272cc70bSAndy Fleming if (err) 1745272cc70bSAndy Fleming return err; 1746d52ebf10SThomas Chou } 1747272cc70bSAndy Fleming 1748e6f99a56SLei Wen /* 1749e6f99a56SLei Wen * For SD, its erase group is always one sector 1750e6f99a56SLei Wen */ 1751e6f99a56SLei Wen mmc->erase_grp_size = 1; 1752bc897b1dSLei Wen mmc->part_config = MMCPART_NOAVAILABLE; 1753c744b6f6SJean-Jacques Hiblot 1754dfda9d88SJean-Jacques Hiblot err = mmc_startup_v4(mmc); 17559cf199ebSDiego Santa Cruz if (err) 17569cf199ebSDiego Santa Cruz return err; 1757f866a46dSStephen Warren 1758c40fdca6SSimon Glass err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart); 1759f866a46dSStephen Warren if (err) 1760f866a46dSStephen Warren return err; 1761d23e2c09SSukumar Ghorai 1762272cc70bSAndy Fleming if (IS_SD(mmc)) 1763*d0c221feSJean-Jacques Hiblot err = sd_select_mode_and_width(mmc); 1764272cc70bSAndy Fleming else 1765dfda9d88SJean-Jacques Hiblot err = mmc_select_bus_freq_width(mmc); 1766272cc70bSAndy Fleming 1767272cc70bSAndy Fleming if (err) 1768272cc70bSAndy Fleming return err; 1769272cc70bSAndy Fleming 1770272cc70bSAndy Fleming 17715af8f45cSAndrew Gabbasov /* Fix the block length for DDR mode */ 17725af8f45cSAndrew Gabbasov if (mmc->ddr_mode) { 17735af8f45cSAndrew Gabbasov mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 17745af8f45cSAndrew Gabbasov mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 17755af8f45cSAndrew Gabbasov } 17765af8f45cSAndrew Gabbasov 1777272cc70bSAndy Fleming /* fill in device description */ 1778c40fdca6SSimon Glass bdesc = mmc_get_blk_desc(mmc); 1779c40fdca6SSimon Glass bdesc->lun = 0; 1780c40fdca6SSimon Glass bdesc->hwpart = 0; 1781c40fdca6SSimon Glass bdesc->type = 0; 1782c40fdca6SSimon Glass bdesc->blksz = mmc->read_bl_len; 1783c40fdca6SSimon Glass bdesc->log2blksz = LOG2(bdesc->blksz); 1784c40fdca6SSimon Glass bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len); 1785fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \ 1786fc011f64SSjoerd Simons (defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \ 1787fc011f64SSjoerd Simons !defined(CONFIG_USE_TINY_PRINTF)) 1788c40fdca6SSimon Glass sprintf(bdesc->vendor, "Man %06x Snr %04x%04x", 1789babce5f6STaylor Hutt mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), 1790babce5f6STaylor Hutt (mmc->cid[3] >> 16) & 0xffff); 1791c40fdca6SSimon Glass sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff, 17920b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 1793babce5f6STaylor Hutt (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff, 1794babce5f6STaylor Hutt (mmc->cid[2] >> 24) & 0xff); 1795c40fdca6SSimon Glass sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf, 1796babce5f6STaylor Hutt (mmc->cid[2] >> 16) & 0xf); 179756196826SPaul Burton #else 1798c40fdca6SSimon Glass bdesc->vendor[0] = 0; 1799c40fdca6SSimon Glass bdesc->product[0] = 0; 1800c40fdca6SSimon Glass bdesc->revision[0] = 0; 180156196826SPaul Burton #endif 1802122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT) 1803c40fdca6SSimon Glass part_init(bdesc); 1804122efd43SMikhail Kshevetskiy #endif 1805272cc70bSAndy Fleming 1806272cc70bSAndy Fleming return 0; 1807272cc70bSAndy Fleming } 1808272cc70bSAndy Fleming 1809fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc) 1810272cc70bSAndy Fleming { 1811272cc70bSAndy Fleming struct mmc_cmd cmd; 1812272cc70bSAndy Fleming int err; 1813272cc70bSAndy Fleming 1814272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND; 1815272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ 181693bfd616SPantelis Antoniou cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa; 1817272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7; 1818272cc70bSAndy Fleming 1819272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1820272cc70bSAndy Fleming 1821272cc70bSAndy Fleming if (err) 1822272cc70bSAndy Fleming return err; 1823272cc70bSAndy Fleming 1824998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa) 1825915ffa52SJaehoon Chung return -EOPNOTSUPP; 1826272cc70bSAndy Fleming else 1827272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 1828272cc70bSAndy Fleming 1829272cc70bSAndy Fleming return 0; 1830272cc70bSAndy Fleming } 1831272cc70bSAndy Fleming 1832c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 183395de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */ 183495de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void) 183595de9ab2SPaul Kocialkowski { 183695de9ab2SPaul Kocialkowski } 183705cbeb7cSSimon Glass #endif 183895de9ab2SPaul Kocialkowski 18392051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc) 18402051aefeSPeng Fan { 1841c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 184206ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR) 18432051aefeSPeng Fan int ret; 18442051aefeSPeng Fan 18452051aefeSPeng Fan ret = device_get_supply_regulator(mmc->dev, "vmmc-supply", 184606ec045fSJean-Jacques Hiblot &mmc->vmmc_supply); 184706ec045fSJean-Jacques Hiblot if (ret) 1848288db7c7SJaehoon Chung debug("%s: No vmmc supply\n", mmc->dev->name); 18492051aefeSPeng Fan 185006ec045fSJean-Jacques Hiblot ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply", 185106ec045fSJean-Jacques Hiblot &mmc->vqmmc_supply); 185206ec045fSJean-Jacques Hiblot if (ret) 185306ec045fSJean-Jacques Hiblot debug("%s: No vqmmc supply\n", mmc->dev->name); 185406ec045fSJean-Jacques Hiblot 185506ec045fSJean-Jacques Hiblot if (mmc->vmmc_supply) { 185606ec045fSJean-Jacques Hiblot ret = regulator_set_enable(mmc->vmmc_supply, true); 18572051aefeSPeng Fan if (ret) { 18582051aefeSPeng Fan puts("Error enabling VMMC supply\n"); 18592051aefeSPeng Fan return ret; 18602051aefeSPeng Fan } 186106ec045fSJean-Jacques Hiblot } 18622051aefeSPeng Fan #endif 186305cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */ 186405cbeb7cSSimon Glass /* 186505cbeb7cSSimon Glass * Driver model should use a regulator, as above, rather than calling 186605cbeb7cSSimon Glass * out to board code. 186705cbeb7cSSimon Glass */ 186805cbeb7cSSimon Glass board_mmc_power_init(); 186905cbeb7cSSimon Glass #endif 18702051aefeSPeng Fan return 0; 18712051aefeSPeng Fan } 18722051aefeSPeng Fan 1873e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc) 1874272cc70bSAndy Fleming { 18758ca51e51SSimon Glass bool no_card; 1876afd5932bSMacpaul Lin int err; 1877272cc70bSAndy Fleming 1878ab769f22SPantelis Antoniou /* we pretend there's no card when init is NULL */ 18798ca51e51SSimon Glass no_card = mmc_getcd(mmc) == 0; 1880e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 18818ca51e51SSimon Glass no_card = no_card || (mmc->cfg->ops->init == NULL); 18828ca51e51SSimon Glass #endif 18838ca51e51SSimon Glass if (no_card) { 188448972d90SThierry Reding mmc->has_init = 0; 188556196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 188648972d90SThierry Reding printf("MMC: no card present\n"); 188756196826SPaul Burton #endif 1888915ffa52SJaehoon Chung return -ENOMEDIUM; 188948972d90SThierry Reding } 189048972d90SThierry Reding 1891bc897b1dSLei Wen if (mmc->has_init) 1892bc897b1dSLei Wen return 0; 1893bc897b1dSLei Wen 18945a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 18955a8dbdc6SYangbo Lu mmc_adapter_card_type_ident(); 18965a8dbdc6SYangbo Lu #endif 18972051aefeSPeng Fan err = mmc_power_init(mmc); 18982051aefeSPeng Fan if (err) 18992051aefeSPeng Fan return err; 190095de9ab2SPaul Kocialkowski 1901e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 19028ca51e51SSimon Glass /* The device has already been probed ready for use */ 19038ca51e51SSimon Glass #else 1904ab769f22SPantelis Antoniou /* made sure it's not NULL earlier */ 190593bfd616SPantelis Antoniou err = mmc->cfg->ops->init(mmc); 1906272cc70bSAndy Fleming if (err) 1907272cc70bSAndy Fleming return err; 19088ca51e51SSimon Glass #endif 1909786e8f81SAndrew Gabbasov mmc->ddr_mode = 0; 1910b86b85e2SIlya Yanok mmc_set_bus_width(mmc, 1); 1911b86b85e2SIlya Yanok mmc_set_clock(mmc, 1); 1912b86b85e2SIlya Yanok 1913272cc70bSAndy Fleming /* Reset the Card */ 1914272cc70bSAndy Fleming err = mmc_go_idle(mmc); 1915272cc70bSAndy Fleming 1916272cc70bSAndy Fleming if (err) 1917272cc70bSAndy Fleming return err; 1918272cc70bSAndy Fleming 1919bc897b1dSLei Wen /* The internal partition reset to user partition(0) at every CMD0*/ 1920c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->hwpart = 0; 1921bc897b1dSLei Wen 1922272cc70bSAndy Fleming /* Test for SD version 2 */ 1923272cc70bSAndy Fleming err = mmc_send_if_cond(mmc); 1924272cc70bSAndy Fleming 1925272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */ 1926272cc70bSAndy Fleming err = sd_send_op_cond(mmc); 1927272cc70bSAndy Fleming 1928272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */ 1929915ffa52SJaehoon Chung if (err == -ETIMEDOUT) { 1930272cc70bSAndy Fleming err = mmc_send_op_cond(mmc); 1931272cc70bSAndy Fleming 1932bd47c135SAndrew Gabbasov if (err) { 193356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 1934272cc70bSAndy Fleming printf("Card did not respond to voltage select!\n"); 193556196826SPaul Burton #endif 1936915ffa52SJaehoon Chung return -EOPNOTSUPP; 1937272cc70bSAndy Fleming } 1938272cc70bSAndy Fleming } 1939272cc70bSAndy Fleming 1940bd47c135SAndrew Gabbasov if (!err) 1941e9550449SChe-Liang Chiou mmc->init_in_progress = 1; 1942e9550449SChe-Liang Chiou 1943e9550449SChe-Liang Chiou return err; 1944e9550449SChe-Liang Chiou } 1945e9550449SChe-Liang Chiou 1946e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc) 1947e9550449SChe-Liang Chiou { 1948e9550449SChe-Liang Chiou int err = 0; 1949e9550449SChe-Liang Chiou 1950bd47c135SAndrew Gabbasov mmc->init_in_progress = 0; 1951e9550449SChe-Liang Chiou if (mmc->op_cond_pending) 1952e9550449SChe-Liang Chiou err = mmc_complete_op_cond(mmc); 1953e9550449SChe-Liang Chiou 1954e9550449SChe-Liang Chiou if (!err) 1955bc897b1dSLei Wen err = mmc_startup(mmc); 1956bc897b1dSLei Wen if (err) 1957bc897b1dSLei Wen mmc->has_init = 0; 1958bc897b1dSLei Wen else 1959bc897b1dSLei Wen mmc->has_init = 1; 1960e9550449SChe-Liang Chiou return err; 1961e9550449SChe-Liang Chiou } 1962e9550449SChe-Liang Chiou 1963e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc) 1964e9550449SChe-Liang Chiou { 1965bd47c135SAndrew Gabbasov int err = 0; 1966ce9eca94SMarek Vasut __maybe_unused unsigned start; 1967c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 196833fb211dSSimon Glass struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev); 1969e9550449SChe-Liang Chiou 197033fb211dSSimon Glass upriv->mmc = mmc; 197133fb211dSSimon Glass #endif 1972e9550449SChe-Liang Chiou if (mmc->has_init) 1973e9550449SChe-Liang Chiou return 0; 1974d803fea5SMateusz Zalega 1975d803fea5SMateusz Zalega start = get_timer(0); 1976d803fea5SMateusz Zalega 1977e9550449SChe-Liang Chiou if (!mmc->init_in_progress) 1978e9550449SChe-Liang Chiou err = mmc_start_init(mmc); 1979e9550449SChe-Liang Chiou 1980bd47c135SAndrew Gabbasov if (!err) 1981e9550449SChe-Liang Chiou err = mmc_complete_init(mmc); 1982919b4858SJagan Teki if (err) 1983919b4858SJagan Teki printf("%s: %d, time %lu\n", __func__, err, get_timer(start)); 1984919b4858SJagan Teki 1985bc897b1dSLei Wen return err; 1986272cc70bSAndy Fleming } 1987272cc70bSAndy Fleming 1988ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val) 1989ab71188cSMarkus Niebel { 1990ab71188cSMarkus Niebel mmc->dsr = val; 1991ab71188cSMarkus Niebel return 0; 1992ab71188cSMarkus Niebel } 1993ab71188cSMarkus Niebel 1994cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */ 1995cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis) 1996272cc70bSAndy Fleming { 1997272cc70bSAndy Fleming return -1; 1998272cc70bSAndy Fleming } 1999272cc70bSAndy Fleming 2000cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */ 2001cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis) 2002cee9ab7cSJeroen Hofstee { 2003cee9ab7cSJeroen Hofstee return -1; 2004cee9ab7cSJeroen Hofstee } 2005272cc70bSAndy Fleming 2006e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit) 2007e9550449SChe-Liang Chiou { 2008e9550449SChe-Liang Chiou mmc->preinit = preinit; 2009e9550449SChe-Liang Chiou } 2010e9550449SChe-Liang Chiou 2011c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD) 20128e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 20138e3332e2SSjoerd Simons { 20148e3332e2SSjoerd Simons return 0; 20158e3332e2SSjoerd Simons } 2016c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC) 20178e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 20188e3332e2SSjoerd Simons { 20194a1db6d8SSimon Glass int ret, i; 20208e3332e2SSjoerd Simons struct uclass *uc; 20214a1db6d8SSimon Glass struct udevice *dev; 20228e3332e2SSjoerd Simons 20238e3332e2SSjoerd Simons ret = uclass_get(UCLASS_MMC, &uc); 20248e3332e2SSjoerd Simons if (ret) 20258e3332e2SSjoerd Simons return ret; 20268e3332e2SSjoerd Simons 20274a1db6d8SSimon Glass /* 20284a1db6d8SSimon Glass * Try to add them in sequence order. Really with driver model we 20294a1db6d8SSimon Glass * should allow holes, but the current MMC list does not allow that. 20304a1db6d8SSimon Glass * So if we request 0, 1, 3 we will get 0, 1, 2. 20314a1db6d8SSimon Glass */ 20324a1db6d8SSimon Glass for (i = 0; ; i++) { 20334a1db6d8SSimon Glass ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev); 20344a1db6d8SSimon Glass if (ret == -ENODEV) 20354a1db6d8SSimon Glass break; 20364a1db6d8SSimon Glass } 20374a1db6d8SSimon Glass uclass_foreach_dev(dev, uc) { 20384a1db6d8SSimon Glass ret = device_probe(dev); 20398e3332e2SSjoerd Simons if (ret) 20404a1db6d8SSimon Glass printf("%s - probe failed: %d\n", dev->name, ret); 20418e3332e2SSjoerd Simons } 20428e3332e2SSjoerd Simons 20438e3332e2SSjoerd Simons return 0; 20448e3332e2SSjoerd Simons } 20458e3332e2SSjoerd Simons #else 20468e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 20478e3332e2SSjoerd Simons { 20488e3332e2SSjoerd Simons if (board_mmc_init(bis) < 0) 20498e3332e2SSjoerd Simons cpu_mmc_init(bis); 20508e3332e2SSjoerd Simons 20518e3332e2SSjoerd Simons return 0; 20528e3332e2SSjoerd Simons } 20538e3332e2SSjoerd Simons #endif 2054e9550449SChe-Liang Chiou 2055272cc70bSAndy Fleming int mmc_initialize(bd_t *bis) 2056272cc70bSAndy Fleming { 20571b26bab1SDaniel Kochmański static int initialized = 0; 20588e3332e2SSjoerd Simons int ret; 20591b26bab1SDaniel Kochmański if (initialized) /* Avoid initializing mmc multiple times */ 20601b26bab1SDaniel Kochmański return 0; 20611b26bab1SDaniel Kochmański initialized = 1; 20621b26bab1SDaniel Kochmański 2063c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK) 2064b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY) 2065c40fdca6SSimon Glass mmc_list_init(); 2066c40fdca6SSimon Glass #endif 2067b5b838f1SMarek Vasut #endif 20688e3332e2SSjoerd Simons ret = mmc_probe(bis); 20698e3332e2SSjoerd Simons if (ret) 20708e3332e2SSjoerd Simons return ret; 2071272cc70bSAndy Fleming 2072bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD 2073272cc70bSAndy Fleming print_mmc_devices(','); 2074bb0dc108SYing Zhang #endif 2075272cc70bSAndy Fleming 2076c40fdca6SSimon Glass mmc_do_preinit(); 2077272cc70bSAndy Fleming return 0; 2078272cc70bSAndy Fleming } 2079cd3d4880STomas Melin 2080cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE 2081cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc) 2082cd3d4880STomas Melin { 2083cd3d4880STomas Melin int err; 2084cd3d4880STomas Melin ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 2085cd3d4880STomas Melin 2086cd3d4880STomas Melin err = mmc_send_ext_csd(mmc, ext_csd); 2087cd3d4880STomas Melin if (err) { 2088cd3d4880STomas Melin puts("Could not get ext_csd register values\n"); 2089cd3d4880STomas Melin return err; 2090cd3d4880STomas Melin } 2091cd3d4880STomas Melin 2092cd3d4880STomas Melin if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) { 2093cd3d4880STomas Melin puts("Background operations not supported on device\n"); 2094cd3d4880STomas Melin return -EMEDIUMTYPE; 2095cd3d4880STomas Melin } 2096cd3d4880STomas Melin 2097cd3d4880STomas Melin if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) { 2098cd3d4880STomas Melin puts("Background operations already enabled\n"); 2099cd3d4880STomas Melin return 0; 2100cd3d4880STomas Melin } 2101cd3d4880STomas Melin 2102cd3d4880STomas Melin err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1); 2103cd3d4880STomas Melin if (err) { 2104cd3d4880STomas Melin puts("Failed to enable manual background operations\n"); 2105cd3d4880STomas Melin return err; 2106cd3d4880STomas Melin } 2107cd3d4880STomas Melin 2108cd3d4880STomas Melin puts("Enabled manual background operations\n"); 2109cd3d4880STomas Melin 2110cd3d4880STomas Melin return 0; 2111cd3d4880STomas Melin } 2112cd3d4880STomas Melin #endif 2113