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 33e531136eSJason Zhu static char mmc_ext_csd[512]; 34e531136eSJason Zhu 35b5b838f1SMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY) 36b5b838f1SMarek Vasut static struct mmc mmc_static; 37b5b838f1SMarek Vasut struct mmc *find_mmc_device(int dev_num) 38b5b838f1SMarek Vasut { 39b5b838f1SMarek Vasut return &mmc_static; 40b5b838f1SMarek Vasut } 41b5b838f1SMarek Vasut 42b5b838f1SMarek Vasut void mmc_do_preinit(void) 43b5b838f1SMarek Vasut { 44b5b838f1SMarek Vasut struct mmc *m = &mmc_static; 45b5b838f1SMarek Vasut #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 46b5b838f1SMarek Vasut mmc_set_preinit(m, 1); 47b5b838f1SMarek Vasut #endif 48b5b838f1SMarek Vasut if (m->preinit) 49b5b838f1SMarek Vasut mmc_start_init(m); 50b5b838f1SMarek Vasut } 51b5b838f1SMarek Vasut 52b5b838f1SMarek Vasut struct blk_desc *mmc_get_blk_desc(struct mmc *mmc) 53b5b838f1SMarek Vasut { 54b5b838f1SMarek Vasut return &mmc->block_dev; 55b5b838f1SMarek Vasut } 56b5b838f1SMarek Vasut #endif 57b5b838f1SMarek Vasut 58e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 59750121c3SJeroen Hofstee __weak int board_mmc_getwp(struct mmc *mmc) 60d23d8d7eSNikita Kiryanov { 61d23d8d7eSNikita Kiryanov return -1; 62d23d8d7eSNikita Kiryanov } 63d23d8d7eSNikita Kiryanov 64d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc) 65d23d8d7eSNikita Kiryanov { 66d23d8d7eSNikita Kiryanov int wp; 67d23d8d7eSNikita Kiryanov 68d23d8d7eSNikita Kiryanov wp = board_mmc_getwp(mmc); 69d23d8d7eSNikita Kiryanov 70d4e1da4eSPeter Korsgaard if (wp < 0) { 7193bfd616SPantelis Antoniou if (mmc->cfg->ops->getwp) 7293bfd616SPantelis Antoniou wp = mmc->cfg->ops->getwp(mmc); 73d4e1da4eSPeter Korsgaard else 74d4e1da4eSPeter Korsgaard wp = 0; 75d4e1da4eSPeter Korsgaard } 76d23d8d7eSNikita Kiryanov 77d23d8d7eSNikita Kiryanov return wp; 78d23d8d7eSNikita Kiryanov } 79d23d8d7eSNikita Kiryanov 80cee9ab7cSJeroen Hofstee __weak int board_mmc_getcd(struct mmc *mmc) 81cee9ab7cSJeroen Hofstee { 8211fdade2SStefano Babic return -1; 8311fdade2SStefano Babic } 848ca51e51SSimon Glass #endif 8511fdade2SStefano Babic 868635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE 87c0c76ebaSSimon Glass void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd) 88c0c76ebaSSimon Glass { 89c0c76ebaSSimon Glass printf("CMD_SEND:%d\n", cmd->cmdidx); 90c0c76ebaSSimon Glass printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg); 91c0c76ebaSSimon Glass } 92c0c76ebaSSimon Glass 93c0c76ebaSSimon Glass void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret) 94c0c76ebaSSimon Glass { 955db2fe3aSRaffaele Recalcati int i; 965db2fe3aSRaffaele Recalcati u8 *ptr; 975db2fe3aSRaffaele Recalcati 987863ce58SBin Meng if (ret) { 997863ce58SBin Meng printf("\t\tRET\t\t\t %d\n", ret); 1007863ce58SBin Meng } else { 1015db2fe3aSRaffaele Recalcati switch (cmd->resp_type) { 1025db2fe3aSRaffaele Recalcati case MMC_RSP_NONE: 1035db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_NONE\n"); 1045db2fe3aSRaffaele Recalcati break; 1055db2fe3aSRaffaele Recalcati case MMC_RSP_R1: 1065db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n", 1075db2fe3aSRaffaele Recalcati cmd->response[0]); 1085db2fe3aSRaffaele Recalcati break; 1095db2fe3aSRaffaele Recalcati case MMC_RSP_R1b: 1105db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n", 1115db2fe3aSRaffaele Recalcati cmd->response[0]); 1125db2fe3aSRaffaele Recalcati break; 1135db2fe3aSRaffaele Recalcati case MMC_RSP_R2: 1145db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R2\t\t 0x%08X \n", 1155db2fe3aSRaffaele Recalcati cmd->response[0]); 1165db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1175db2fe3aSRaffaele Recalcati cmd->response[1]); 1185db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1195db2fe3aSRaffaele Recalcati cmd->response[2]); 1205db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1215db2fe3aSRaffaele Recalcati cmd->response[3]); 1225db2fe3aSRaffaele Recalcati printf("\n"); 1235db2fe3aSRaffaele Recalcati printf("\t\t\t\t\tDUMPING DATA\n"); 1245db2fe3aSRaffaele Recalcati for (i = 0; i < 4; i++) { 1255db2fe3aSRaffaele Recalcati int j; 1265db2fe3aSRaffaele Recalcati printf("\t\t\t\t\t%03d - ", i*4); 127146bec79SDirk Behme ptr = (u8 *)&cmd->response[i]; 1285db2fe3aSRaffaele Recalcati ptr += 3; 1295db2fe3aSRaffaele Recalcati for (j = 0; j < 4; j++) 1305db2fe3aSRaffaele Recalcati printf("%02X ", *ptr--); 1315db2fe3aSRaffaele Recalcati printf("\n"); 1325db2fe3aSRaffaele Recalcati } 1335db2fe3aSRaffaele Recalcati break; 1345db2fe3aSRaffaele Recalcati case MMC_RSP_R3: 1355db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n", 1365db2fe3aSRaffaele Recalcati cmd->response[0]); 1375db2fe3aSRaffaele Recalcati break; 1385db2fe3aSRaffaele Recalcati default: 1395db2fe3aSRaffaele Recalcati printf("\t\tERROR MMC rsp not supported\n"); 1405db2fe3aSRaffaele Recalcati break; 1415db2fe3aSRaffaele Recalcati } 1427863ce58SBin Meng } 143c0c76ebaSSimon Glass } 144c0c76ebaSSimon Glass 145c0c76ebaSSimon Glass void mmc_trace_state(struct mmc *mmc, struct mmc_cmd *cmd) 146c0c76ebaSSimon Glass { 147c0c76ebaSSimon Glass int status; 148c0c76ebaSSimon Glass 149c0c76ebaSSimon Glass status = (cmd->response[0] & MMC_STATUS_CURR_STATE) >> 9; 150c0c76ebaSSimon Glass printf("CURR STATE:%d\n", status); 151c0c76ebaSSimon Glass } 1525db2fe3aSRaffaele Recalcati #endif 153c0c76ebaSSimon Glass 154e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 155c0c76ebaSSimon Glass int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) 156c0c76ebaSSimon Glass { 157c0c76ebaSSimon Glass int ret; 158c0c76ebaSSimon Glass 159c0c76ebaSSimon Glass mmmc_trace_before_send(mmc, cmd); 160c0c76ebaSSimon Glass ret = mmc->cfg->ops->send_cmd(mmc, cmd, data); 161c0c76ebaSSimon Glass mmmc_trace_after_send(mmc, cmd, ret); 162c0c76ebaSSimon Glass 1638635ff9eSMarek Vasut return ret; 164272cc70bSAndy Fleming } 1658ca51e51SSimon Glass #endif 166272cc70bSAndy Fleming 167da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout) 1685d4fc8d9SRaffaele Recalcati { 1695d4fc8d9SRaffaele Recalcati struct mmc_cmd cmd; 170d617c426SJan Kloetzke int err, retries = 5; 1715d4fc8d9SRaffaele Recalcati 1725d4fc8d9SRaffaele Recalcati cmd.cmdidx = MMC_CMD_SEND_STATUS; 1735d4fc8d9SRaffaele Recalcati cmd.resp_type = MMC_RSP_R1; 174aaf3d41aSMarek Vasut if (!mmc_host_is_spi(mmc)) 175aaf3d41aSMarek Vasut cmd.cmdarg = mmc->rca << 16; 1765d4fc8d9SRaffaele Recalcati 1771677eef4SAndrew Gabbasov while (1) { 1785d4fc8d9SRaffaele Recalcati err = mmc_send_cmd(mmc, &cmd, NULL); 179d617c426SJan Kloetzke if (!err) { 180d617c426SJan Kloetzke if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) && 181d617c426SJan Kloetzke (cmd.response[0] & MMC_STATUS_CURR_STATE) != 182d617c426SJan Kloetzke MMC_STATE_PRG) 1835d4fc8d9SRaffaele Recalcati break; 184d617c426SJan Kloetzke else if (cmd.response[0] & MMC_STATUS_MASK) { 18556196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 186d617c426SJan Kloetzke printf("Status Error: 0x%08X\n", 187d617c426SJan Kloetzke cmd.response[0]); 18856196826SPaul Burton #endif 189915ffa52SJaehoon Chung return -ECOMM; 190d617c426SJan Kloetzke } 191d617c426SJan Kloetzke } else if (--retries < 0) 192d617c426SJan Kloetzke return err; 1935d4fc8d9SRaffaele Recalcati 1941677eef4SAndrew Gabbasov if (timeout-- <= 0) 1951677eef4SAndrew Gabbasov break; 1965d4fc8d9SRaffaele Recalcati 1971677eef4SAndrew Gabbasov udelay(1000); 1981677eef4SAndrew Gabbasov } 1995d4fc8d9SRaffaele Recalcati 200c0c76ebaSSimon Glass mmc_trace_state(mmc, &cmd); 2015b0c942fSJongman Heo if (timeout <= 0) { 20256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2035d4fc8d9SRaffaele Recalcati printf("Timeout waiting card ready\n"); 20456196826SPaul Burton #endif 205915ffa52SJaehoon Chung return -ETIMEDOUT; 2065d4fc8d9SRaffaele Recalcati } 2075d4fc8d9SRaffaele Recalcati 2085d4fc8d9SRaffaele Recalcati return 0; 2095d4fc8d9SRaffaele Recalcati } 2105d4fc8d9SRaffaele Recalcati 211da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len) 212272cc70bSAndy Fleming { 213272cc70bSAndy Fleming struct mmc_cmd cmd; 214272cc70bSAndy Fleming 215caa21a21SZiyuan Xu if (mmc_card_ddr(mmc)) 216d22e3d46SJaehoon Chung return 0; 217d22e3d46SJaehoon Chung 218272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SET_BLOCKLEN; 219272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 220272cc70bSAndy Fleming cmd.cmdarg = len; 221272cc70bSAndy Fleming 222272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, NULL); 223272cc70bSAndy Fleming } 224272cc70bSAndy Fleming 225ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start, 226fdbb873eSKim Phillips lbaint_t blkcnt) 227272cc70bSAndy Fleming { 228272cc70bSAndy Fleming struct mmc_cmd cmd; 229272cc70bSAndy Fleming struct mmc_data data; 230272cc70bSAndy Fleming 2314a1a06bcSAlagu Sankar if (blkcnt > 1) 2324a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; 2334a1a06bcSAlagu Sankar else 234272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; 235272cc70bSAndy Fleming 236272cc70bSAndy Fleming if (mmc->high_capacity) 2374a1a06bcSAlagu Sankar cmd.cmdarg = start; 238272cc70bSAndy Fleming else 2394a1a06bcSAlagu Sankar cmd.cmdarg = start * mmc->read_bl_len; 240272cc70bSAndy Fleming 241272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 242272cc70bSAndy Fleming 243272cc70bSAndy Fleming data.dest = dst; 2444a1a06bcSAlagu Sankar data.blocks = blkcnt; 245272cc70bSAndy Fleming data.blocksize = mmc->read_bl_len; 246272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 247272cc70bSAndy Fleming 2484a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, &data)) 2494a1a06bcSAlagu Sankar return 0; 2504a1a06bcSAlagu Sankar 2514a1a06bcSAlagu Sankar if (blkcnt > 1) { 2524a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; 2534a1a06bcSAlagu Sankar cmd.cmdarg = 0; 2544a1a06bcSAlagu Sankar cmd.resp_type = MMC_RSP_R1b; 2554a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, NULL)) { 25656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2574a1a06bcSAlagu Sankar printf("mmc fail to send stop cmd\n"); 25856196826SPaul Burton #endif 2594a1a06bcSAlagu Sankar return 0; 2604a1a06bcSAlagu Sankar } 261272cc70bSAndy Fleming } 262272cc70bSAndy Fleming 2634a1a06bcSAlagu Sankar return blkcnt; 264272cc70bSAndy Fleming } 265272cc70bSAndy Fleming 26647f7fd3aSJason Zhu #ifdef CONFIG_SPL_BLK_READ_PREPARE 26747f7fd3aSJason Zhu static int mmc_read_blocks_prepare(struct mmc *mmc, void *dst, lbaint_t start, 26847f7fd3aSJason Zhu lbaint_t blkcnt) 26947f7fd3aSJason Zhu { 27047f7fd3aSJason Zhu struct mmc_cmd cmd; 27147f7fd3aSJason Zhu struct mmc_data data; 27247f7fd3aSJason Zhu 27347f7fd3aSJason Zhu if (blkcnt > 1) 27447f7fd3aSJason Zhu cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; 27547f7fd3aSJason Zhu else 27647f7fd3aSJason Zhu cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; 27747f7fd3aSJason Zhu 27847f7fd3aSJason Zhu if (mmc->high_capacity) 27947f7fd3aSJason Zhu cmd.cmdarg = start; 28047f7fd3aSJason Zhu else 28147f7fd3aSJason Zhu cmd.cmdarg = start * mmc->read_bl_len; 28247f7fd3aSJason Zhu 28347f7fd3aSJason Zhu cmd.resp_type = MMC_RSP_R1; 28447f7fd3aSJason Zhu 28547f7fd3aSJason Zhu data.dest = dst; 28647f7fd3aSJason Zhu data.blocks = blkcnt; 28747f7fd3aSJason Zhu data.blocksize = mmc->read_bl_len; 28847f7fd3aSJason Zhu data.flags = MMC_DATA_READ; 28947f7fd3aSJason Zhu 29047f7fd3aSJason Zhu if (mmc_send_cmd_prepare(mmc, &cmd, &data)) 29147f7fd3aSJason Zhu return 0; 29247f7fd3aSJason Zhu 29347f7fd3aSJason Zhu return blkcnt; 29447f7fd3aSJason Zhu } 29547f7fd3aSJason Zhu #endif 29647f7fd3aSJason Zhu 29747f7fd3aSJason Zhu #ifdef CONFIG_SPL_BLK_READ_PREPARE 29847f7fd3aSJason Zhu #if CONFIG_IS_ENABLED(BLK) 29947f7fd3aSJason Zhu ulong mmc_bread_prepare(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst) 30047f7fd3aSJason Zhu #else 30147f7fd3aSJason Zhu ulong mmc_bread_prepare(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, 30247f7fd3aSJason Zhu void *dst) 30347f7fd3aSJason Zhu #endif 30447f7fd3aSJason Zhu { 30547f7fd3aSJason Zhu #if CONFIG_IS_ENABLED(BLK) 30647f7fd3aSJason Zhu struct blk_desc *block_dev = dev_get_uclass_platdata(dev); 30747f7fd3aSJason Zhu #endif 30847f7fd3aSJason Zhu int dev_num = block_dev->devnum; 30947f7fd3aSJason Zhu int timeout = 0; 31047f7fd3aSJason Zhu int err; 31147f7fd3aSJason Zhu 31247f7fd3aSJason Zhu if (blkcnt == 0) 31347f7fd3aSJason Zhu return 0; 31447f7fd3aSJason Zhu 31547f7fd3aSJason Zhu struct mmc *mmc = find_mmc_device(dev_num); 31647f7fd3aSJason Zhu 31747f7fd3aSJason Zhu if (!mmc) 31847f7fd3aSJason Zhu return 0; 31947f7fd3aSJason Zhu 32047f7fd3aSJason Zhu if (CONFIG_IS_ENABLED(MMC_TINY)) 32147f7fd3aSJason Zhu err = mmc_switch_part(mmc, block_dev->hwpart); 32247f7fd3aSJason Zhu else 32347f7fd3aSJason Zhu err = blk_dselect_hwpart(block_dev, block_dev->hwpart); 32447f7fd3aSJason Zhu 32547f7fd3aSJason Zhu if (err < 0) 32647f7fd3aSJason Zhu return 0; 32747f7fd3aSJason Zhu 32847f7fd3aSJason Zhu if ((start + blkcnt) > block_dev->lba) { 32947f7fd3aSJason Zhu #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 33047f7fd3aSJason Zhu printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", 33147f7fd3aSJason Zhu start + blkcnt, block_dev->lba); 33247f7fd3aSJason Zhu #endif 33347f7fd3aSJason Zhu return 0; 33447f7fd3aSJason Zhu } 33547f7fd3aSJason Zhu 33647f7fd3aSJason Zhu if (mmc_set_blocklen(mmc, mmc->read_bl_len)) { 33747f7fd3aSJason Zhu debug("%s: Failed to set blocklen\n", __func__); 33847f7fd3aSJason Zhu return 0; 33947f7fd3aSJason Zhu } 34047f7fd3aSJason Zhu 34147f7fd3aSJason Zhu if (mmc_read_blocks_prepare(mmc, dst, start, blkcnt) != blkcnt) { 34247f7fd3aSJason Zhu debug("%s: Failed to read blocks\n", __func__); 34347f7fd3aSJason Zhu re_init_retry: 34447f7fd3aSJason Zhu timeout++; 34547f7fd3aSJason Zhu /* 34647f7fd3aSJason Zhu * Try re-init seven times. 34747f7fd3aSJason Zhu */ 34847f7fd3aSJason Zhu if (timeout > 7) { 34947f7fd3aSJason Zhu printf("Re-init retry timeout\n"); 35047f7fd3aSJason Zhu return 0; 35147f7fd3aSJason Zhu } 35247f7fd3aSJason Zhu 35347f7fd3aSJason Zhu mmc->has_init = 0; 35447f7fd3aSJason Zhu if (mmc_init(mmc)) 35547f7fd3aSJason Zhu return 0; 35647f7fd3aSJason Zhu 35747f7fd3aSJason Zhu if (mmc_read_blocks_prepare(mmc, dst, start, blkcnt) != blkcnt) { 35847f7fd3aSJason Zhu printf("%s: Re-init mmc_read_blocks_prepare error\n", 35947f7fd3aSJason Zhu __func__); 36047f7fd3aSJason Zhu goto re_init_retry; 36147f7fd3aSJason Zhu } 36247f7fd3aSJason Zhu } 36347f7fd3aSJason Zhu 36447f7fd3aSJason Zhu return blkcnt; 36547f7fd3aSJason Zhu } 36647f7fd3aSJason Zhu #endif 36747f7fd3aSJason Zhu 3687863dac1SJason Zhu #if CONFIG_IS_ENABLED(BLK) 3697863dac1SJason Zhu ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst) 3707863dac1SJason Zhu #else 3717863dac1SJason Zhu ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, 3727863dac1SJason Zhu void *dst) 3737863dac1SJason Zhu #endif 3747863dac1SJason Zhu { 3757863dac1SJason Zhu #if CONFIG_IS_ENABLED(BLK) 3767863dac1SJason Zhu struct blk_desc *block_dev = dev_get_uclass_platdata(dev); 3777863dac1SJason Zhu #endif 3787863dac1SJason Zhu int dev_num = block_dev->devnum; 3797863dac1SJason Zhu int err; 3807863dac1SJason Zhu lbaint_t cur, blocks_todo = blkcnt; 3817863dac1SJason Zhu 3827863dac1SJason Zhu #ifdef CONFIG_SPL_BLK_READ_PREPARE 3837863dac1SJason Zhu if (block_dev->op_flag == BLK_PRE_RW) 3847863dac1SJason Zhu #if CONFIG_IS_ENABLED(BLK) 3857863dac1SJason Zhu return mmc_bread_prepare(dev, start, blkcnt, dst); 3867863dac1SJason Zhu #else 3877863dac1SJason Zhu return mmc_bread_prepare(block_dev, start, blkcnt, dst); 3887863dac1SJason Zhu #endif 3897863dac1SJason Zhu #endif 3907863dac1SJason Zhu if (blkcnt == 0) 3917863dac1SJason Zhu return 0; 3927863dac1SJason Zhu 3937863dac1SJason Zhu struct mmc *mmc = find_mmc_device(dev_num); 3947863dac1SJason Zhu if (!mmc) 3957863dac1SJason Zhu return 0; 3967863dac1SJason Zhu 3977863dac1SJason Zhu if (CONFIG_IS_ENABLED(MMC_TINY)) 3987863dac1SJason Zhu err = mmc_switch_part(mmc, block_dev->hwpart); 3997863dac1SJason Zhu else 4007863dac1SJason Zhu err = blk_dselect_hwpart(block_dev, block_dev->hwpart); 4017863dac1SJason Zhu 4027863dac1SJason Zhu if (err < 0) 4037863dac1SJason Zhu return 0; 4047863dac1SJason Zhu 4057863dac1SJason Zhu if ((start + blkcnt) > block_dev->lba) { 4067863dac1SJason Zhu #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 4077863dac1SJason Zhu printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", 4087863dac1SJason Zhu start + blkcnt, block_dev->lba); 4097863dac1SJason Zhu #endif 4107863dac1SJason Zhu return 0; 4117863dac1SJason Zhu } 4127863dac1SJason Zhu 4137863dac1SJason Zhu if (mmc_set_blocklen(mmc, mmc->read_bl_len)) { 4147863dac1SJason Zhu debug("%s: Failed to set blocklen\n", __func__); 4157863dac1SJason Zhu return 0; 4167863dac1SJason Zhu } 4177863dac1SJason Zhu 4187863dac1SJason Zhu do { 4197863dac1SJason Zhu cur = (blocks_todo > mmc->cfg->b_max) ? 4207863dac1SJason Zhu mmc->cfg->b_max : blocks_todo; 4217863dac1SJason Zhu if (mmc_read_blocks(mmc, dst, start, cur) != cur) { 4227863dac1SJason Zhu debug("%s: Failed to read blocks\n", __func__); 4237863dac1SJason Zhu int timeout = 0; 4247863dac1SJason Zhu re_init_retry: 4257863dac1SJason Zhu timeout++; 4267863dac1SJason Zhu /* 4277863dac1SJason Zhu * Try re-init seven times. 4287863dac1SJason Zhu */ 4297863dac1SJason Zhu if (timeout > 7) { 4307863dac1SJason Zhu printf("Re-init retry timeout\n"); 4317863dac1SJason Zhu return 0; 4327863dac1SJason Zhu } 4337863dac1SJason Zhu 4347863dac1SJason Zhu mmc->has_init = 0; 4357863dac1SJason Zhu if (mmc_init(mmc)) 4367863dac1SJason Zhu return 0; 4377863dac1SJason Zhu 4387863dac1SJason Zhu if (mmc_read_blocks(mmc, dst, start, cur) != cur) { 4397863dac1SJason Zhu printf("%s: Re-init mmc_read_blocks error\n", 4407863dac1SJason Zhu __func__); 4417863dac1SJason Zhu goto re_init_retry; 4427863dac1SJason Zhu } 4437863dac1SJason Zhu } 4447863dac1SJason Zhu blocks_todo -= cur; 4457863dac1SJason Zhu start += cur; 4467863dac1SJason Zhu dst += cur * mmc->read_bl_len; 4477863dac1SJason Zhu } while (blocks_todo > 0); 4487863dac1SJason Zhu 4497863dac1SJason Zhu return blkcnt; 4507863dac1SJason Zhu } 4517863dac1SJason Zhu 45249dba033SZiyuan Xu void mmc_set_clock(struct mmc *mmc, uint clock) 45349dba033SZiyuan Xu { 45449dba033SZiyuan Xu if (clock > mmc->cfg->f_max) 45549dba033SZiyuan Xu clock = mmc->cfg->f_max; 45649dba033SZiyuan Xu 45749dba033SZiyuan Xu if (clock < mmc->cfg->f_min) 45849dba033SZiyuan Xu clock = mmc->cfg->f_min; 45949dba033SZiyuan Xu 46049dba033SZiyuan Xu mmc->clock = clock; 46149dba033SZiyuan Xu 46249dba033SZiyuan Xu mmc_set_ios(mmc); 46349dba033SZiyuan Xu } 46449dba033SZiyuan Xu 46549dba033SZiyuan Xu static void mmc_set_bus_width(struct mmc *mmc, uint width) 46649dba033SZiyuan Xu { 46749dba033SZiyuan Xu mmc->bus_width = width; 46849dba033SZiyuan Xu 46949dba033SZiyuan Xu mmc_set_ios(mmc); 47049dba033SZiyuan Xu } 47149dba033SZiyuan Xu 47281db2d36SZiyuan Xu static void mmc_set_timing(struct mmc *mmc, uint timing) 47381db2d36SZiyuan Xu { 47481db2d36SZiyuan Xu mmc->timing = timing; 47581db2d36SZiyuan Xu mmc_set_ios(mmc); 47681db2d36SZiyuan Xu } 47781db2d36SZiyuan Xu 478fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc) 479272cc70bSAndy Fleming { 480272cc70bSAndy Fleming struct mmc_cmd cmd; 481272cc70bSAndy Fleming int err; 482272cc70bSAndy Fleming 483272cc70bSAndy Fleming udelay(1000); 484272cc70bSAndy Fleming 485272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_GO_IDLE_STATE; 486272cc70bSAndy Fleming cmd.cmdarg = 0; 487272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_NONE; 488272cc70bSAndy Fleming 489272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 490272cc70bSAndy Fleming 491272cc70bSAndy Fleming if (err) 492272cc70bSAndy Fleming return err; 493272cc70bSAndy Fleming 494272cc70bSAndy Fleming udelay(2000); 495272cc70bSAndy Fleming 496272cc70bSAndy Fleming return 0; 497272cc70bSAndy Fleming } 498272cc70bSAndy Fleming 499479fbf72SJason Zhu #ifndef CONFIG_MMC_USE_PRE_CONFIG 500fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc) 501272cc70bSAndy Fleming { 502272cc70bSAndy Fleming int timeout = 1000; 503272cc70bSAndy Fleming int err; 504272cc70bSAndy Fleming struct mmc_cmd cmd; 505272cc70bSAndy Fleming 5061677eef4SAndrew Gabbasov while (1) { 507272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 508272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 509272cc70bSAndy Fleming cmd.cmdarg = 0; 510272cc70bSAndy Fleming 511272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 512272cc70bSAndy Fleming 513272cc70bSAndy Fleming if (err) 514272cc70bSAndy Fleming return err; 515272cc70bSAndy Fleming 516272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_OP_COND; 517272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R3; 518250de12bSStefano Babic 519250de12bSStefano Babic /* 520250de12bSStefano Babic * Most cards do not answer if some reserved bits 521250de12bSStefano Babic * in the ocr are set. However, Some controller 522250de12bSStefano Babic * can set bit 7 (reserved for low voltages), but 523250de12bSStefano Babic * how to manage low voltages SD card is not yet 524250de12bSStefano Babic * specified. 525250de12bSStefano Babic */ 526d52ebf10SThomas Chou cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 : 52793bfd616SPantelis Antoniou (mmc->cfg->voltages & 0xff8000); 528272cc70bSAndy Fleming 529272cc70bSAndy Fleming if (mmc->version == SD_VERSION_2) 530272cc70bSAndy Fleming cmd.cmdarg |= OCR_HCS; 531272cc70bSAndy Fleming 532272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 533272cc70bSAndy Fleming 534272cc70bSAndy Fleming if (err) 535272cc70bSAndy Fleming return err; 536272cc70bSAndy Fleming 5371677eef4SAndrew Gabbasov if (cmd.response[0] & OCR_BUSY) 5381677eef4SAndrew Gabbasov break; 539272cc70bSAndy Fleming 5401677eef4SAndrew Gabbasov if (timeout-- <= 0) 541915ffa52SJaehoon Chung return -EOPNOTSUPP; 542272cc70bSAndy Fleming 5431677eef4SAndrew Gabbasov udelay(1000); 5441677eef4SAndrew Gabbasov } 5451677eef4SAndrew Gabbasov 546272cc70bSAndy Fleming if (mmc->version != SD_VERSION_2) 547272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 548272cc70bSAndy Fleming 549d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 550d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 551d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 552d52ebf10SThomas Chou cmd.cmdarg = 0; 553d52ebf10SThomas Chou 554d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 555d52ebf10SThomas Chou 556d52ebf10SThomas Chou if (err) 557d52ebf10SThomas Chou return err; 558d52ebf10SThomas Chou } 559d52ebf10SThomas Chou 560998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 561272cc70bSAndy Fleming 562272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 563272cc70bSAndy Fleming mmc->rca = 0; 564272cc70bSAndy Fleming 565272cc70bSAndy Fleming return 0; 566272cc70bSAndy Fleming } 567479fbf72SJason Zhu #endif 568272cc70bSAndy Fleming 5695289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg) 570272cc70bSAndy Fleming { 5715289b535SAndrew Gabbasov struct mmc_cmd cmd; 572272cc70bSAndy Fleming int err; 573272cc70bSAndy Fleming 5745289b535SAndrew Gabbasov cmd.cmdidx = MMC_CMD_SEND_OP_COND; 5755289b535SAndrew Gabbasov cmd.resp_type = MMC_RSP_R3; 5765289b535SAndrew Gabbasov cmd.cmdarg = 0; 5775a20397bSRob Herring if (use_arg && !mmc_host_is_spi(mmc)) 5785a20397bSRob Herring cmd.cmdarg = OCR_HCS | 57993bfd616SPantelis Antoniou (mmc->cfg->voltages & 580a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_VOLTAGE_MASK)) | 581a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_ACCESS_MODE); 582e9550449SChe-Liang Chiou 5835289b535SAndrew Gabbasov err = mmc_send_cmd(mmc, &cmd, NULL); 584e9550449SChe-Liang Chiou if (err) 585e9550449SChe-Liang Chiou return err; 5865289b535SAndrew Gabbasov mmc->ocr = cmd.response[0]; 587e9550449SChe-Liang Chiou return 0; 588e9550449SChe-Liang Chiou } 589e9550449SChe-Liang Chiou 590479fbf72SJason Zhu #ifndef CONFIG_MMC_USE_PRE_CONFIG 591750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc) 592e9550449SChe-Liang Chiou { 593e9550449SChe-Liang Chiou int err, i; 594e9550449SChe-Liang Chiou 595272cc70bSAndy Fleming /* Some cards seem to need this */ 596272cc70bSAndy Fleming mmc_go_idle(mmc); 597272cc70bSAndy Fleming 59831cacbabSRaffaele Recalcati /* Asking to the card its capabilities */ 599e9550449SChe-Liang Chiou for (i = 0; i < 2; i++) { 6005289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, i != 0); 60131cacbabSRaffaele Recalcati if (err) 60231cacbabSRaffaele Recalcati return err; 60331cacbabSRaffaele Recalcati 604e9550449SChe-Liang Chiou /* exit if not busy (flag seems to be inverted) */ 605a626c8d4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 606bd47c135SAndrew Gabbasov break; 607e9550449SChe-Liang Chiou } 608bd47c135SAndrew Gabbasov mmc->op_cond_pending = 1; 609bd47c135SAndrew Gabbasov return 0; 610e9550449SChe-Liang Chiou } 611479fbf72SJason Zhu #endif 612750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc) 613e9550449SChe-Liang Chiou { 614e9550449SChe-Liang Chiou struct mmc_cmd cmd; 615e9550449SChe-Liang Chiou int timeout = 1000; 616e9550449SChe-Liang Chiou uint start; 617e9550449SChe-Liang Chiou int err; 618e9550449SChe-Liang Chiou 619e9550449SChe-Liang Chiou mmc->op_cond_pending = 0; 620cc17c01fSAndrew Gabbasov if (!(mmc->ocr & OCR_BUSY)) { 621d188b113SYangbo Lu /* Some cards seem to need this */ 622d188b113SYangbo Lu mmc_go_idle(mmc); 623d188b113SYangbo Lu 624e9550449SChe-Liang Chiou start = get_timer(0); 6251677eef4SAndrew Gabbasov while (1) { 6265289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, 1); 627272cc70bSAndy Fleming if (err) 628272cc70bSAndy Fleming return err; 6291677eef4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 6301677eef4SAndrew Gabbasov break; 631e9550449SChe-Liang Chiou if (get_timer(start) > timeout) 632915ffa52SJaehoon Chung return -EOPNOTSUPP; 633e9550449SChe-Liang Chiou udelay(100); 6341677eef4SAndrew Gabbasov } 635cc17c01fSAndrew Gabbasov } 636272cc70bSAndy Fleming 637d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 638d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 639d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 640d52ebf10SThomas Chou cmd.cmdarg = 0; 641d52ebf10SThomas Chou 642d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 643d52ebf10SThomas Chou 644d52ebf10SThomas Chou if (err) 645d52ebf10SThomas Chou return err; 646a626c8d4SAndrew Gabbasov 647a626c8d4SAndrew Gabbasov mmc->ocr = cmd.response[0]; 648d52ebf10SThomas Chou } 649d52ebf10SThomas Chou 650272cc70bSAndy Fleming mmc->version = MMC_VERSION_UNKNOWN; 651272cc70bSAndy Fleming 652272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 653def816a2SStephen Warren mmc->rca = 1; 654272cc70bSAndy Fleming 655272cc70bSAndy Fleming return 0; 656272cc70bSAndy Fleming } 657272cc70bSAndy Fleming 658272cc70bSAndy Fleming 659fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) 660272cc70bSAndy Fleming { 661272cc70bSAndy Fleming struct mmc_cmd cmd; 662272cc70bSAndy Fleming struct mmc_data data; 663272cc70bSAndy Fleming int err; 664272cc70bSAndy Fleming 665*a95f7caaSJason Zhu #ifdef CONFIG_MMC_USE_PRE_CONFIG 666*a95f7caaSJason Zhu static int initialized; 667e531136eSJason Zhu if (initialized) { 668e531136eSJason Zhu memcpy(ext_csd, mmc_ext_csd, 512); 669e531136eSJason Zhu return 0; 670e531136eSJason Zhu } 671e531136eSJason Zhu 672e531136eSJason Zhu initialized = 1; 673*a95f7caaSJason Zhu #endif 674272cc70bSAndy Fleming /* Get the Card Status Register */ 675272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_EXT_CSD; 676272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 677272cc70bSAndy Fleming cmd.cmdarg = 0; 678272cc70bSAndy Fleming 679cdfd1ac6SYoshihiro Shimoda data.dest = (char *)ext_csd; 680272cc70bSAndy Fleming data.blocks = 1; 6818bfa195eSSimon Glass data.blocksize = MMC_MAX_BLOCK_LEN; 682272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 683272cc70bSAndy Fleming 684272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 685e531136eSJason Zhu memcpy(mmc_ext_csd, ext_csd, 512); 6862056aa9fSJason Zhu #if defined(CONFIG_MMC_USE_PRE_CONFIG) && defined(CONFIG_SPL_BUILD) 6872056aa9fSJason Zhu char *mmc_ecsd_base = NULL; 6882056aa9fSJason Zhu ulong mmc_ecsd; 689272cc70bSAndy Fleming 6902056aa9fSJason Zhu mmc_ecsd = dev_read_u32_default(mmc->dev, "mmc-ecsd", 0); 6912056aa9fSJason Zhu mmc_ecsd_base = (char *)mmc_ecsd; 6922056aa9fSJason Zhu if (mmc_ecsd_base) { 6932056aa9fSJason Zhu memcpy(mmc_ecsd_base, ext_csd, 512); 6942056aa9fSJason Zhu *(unsigned int *)(mmc_ecsd_base + 512) = 0x55aa55aa; 6952056aa9fSJason Zhu } 6962056aa9fSJason Zhu #endif 697272cc70bSAndy Fleming return err; 698272cc70bSAndy Fleming } 699272cc70bSAndy Fleming 7009e8ce816SZiyuan Xu static int mmc_poll_for_busy(struct mmc *mmc, u8 send_status) 701272cc70bSAndy Fleming { 702272cc70bSAndy Fleming struct mmc_cmd cmd; 70355e5defdSZiyuan Xu u8 busy = true; 70455e5defdSZiyuan Xu uint start; 70555e5defdSZiyuan Xu int ret; 7065d4fc8d9SRaffaele Recalcati int timeout = 1000; 70755e5defdSZiyuan Xu 70855e5defdSZiyuan Xu cmd.cmdidx = MMC_CMD_SEND_STATUS; 70955e5defdSZiyuan Xu cmd.resp_type = MMC_RSP_R1; 71055e5defdSZiyuan Xu cmd.cmdarg = mmc->rca << 16; 71155e5defdSZiyuan Xu 71255e5defdSZiyuan Xu start = get_timer(0); 71355e5defdSZiyuan Xu 7149e8ce816SZiyuan Xu if (!send_status && !mmc_can_card_busy(mmc)) { 7159e8ce816SZiyuan Xu mdelay(timeout); 7169e8ce816SZiyuan Xu return 0; 7179e8ce816SZiyuan Xu } 7189e8ce816SZiyuan Xu 71955e5defdSZiyuan Xu do { 7209e8ce816SZiyuan Xu if (!send_status) { 72155e5defdSZiyuan Xu busy = mmc_card_busy(mmc); 72255e5defdSZiyuan Xu } else { 72355e5defdSZiyuan Xu ret = mmc_send_cmd(mmc, &cmd, NULL); 72455e5defdSZiyuan Xu 72555e5defdSZiyuan Xu if (ret) 72655e5defdSZiyuan Xu return ret; 72755e5defdSZiyuan Xu 72855e5defdSZiyuan Xu if (cmd.response[0] & MMC_STATUS_SWITCH_ERROR) 72955e5defdSZiyuan Xu return -EBADMSG; 73055e5defdSZiyuan Xu busy = (cmd.response[0] & MMC_STATUS_CURR_STATE) == 73155e5defdSZiyuan Xu MMC_STATE_PRG; 73255e5defdSZiyuan Xu } 73355e5defdSZiyuan Xu 73455e5defdSZiyuan Xu if (get_timer(start) > timeout && busy) 73555e5defdSZiyuan Xu return -ETIMEDOUT; 73655e5defdSZiyuan Xu } while (busy); 73755e5defdSZiyuan Xu 73855e5defdSZiyuan Xu return 0; 73955e5defdSZiyuan Xu } 74055e5defdSZiyuan Xu 74155e5defdSZiyuan Xu static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value, 74255e5defdSZiyuan Xu u8 send_status) 74355e5defdSZiyuan Xu { 74455e5defdSZiyuan Xu struct mmc_cmd cmd; 745a9003dc6SMaxime Ripard int retries = 3; 7465d4fc8d9SRaffaele Recalcati int ret; 747272cc70bSAndy Fleming 748272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SWITCH; 749272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 750272cc70bSAndy Fleming cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 751272cc70bSAndy Fleming (index << 16) | 752272cc70bSAndy Fleming (value << 8); 753272cc70bSAndy Fleming 75455e5defdSZiyuan Xu do { 7555d4fc8d9SRaffaele Recalcati ret = mmc_send_cmd(mmc, &cmd, NULL); 7565d4fc8d9SRaffaele Recalcati 7579e8ce816SZiyuan Xu if (!ret) 7589e8ce816SZiyuan Xu return mmc_poll_for_busy(mmc, send_status); 75955e5defdSZiyuan Xu } while (--retries > 0 && ret); 76055e5defdSZiyuan Xu 761a9003dc6SMaxime Ripard return ret; 762a9003dc6SMaxime Ripard } 763a9003dc6SMaxime Ripard 76455e5defdSZiyuan Xu int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) 76555e5defdSZiyuan Xu { 76655e5defdSZiyuan Xu return __mmc_switch(mmc, set, index, value, true); 767272cc70bSAndy Fleming } 768272cc70bSAndy Fleming 76949dba033SZiyuan Xu static int mmc_select_bus_width(struct mmc *mmc) 77049dba033SZiyuan Xu { 77149dba033SZiyuan Xu u32 ext_csd_bits[] = { 77249dba033SZiyuan Xu EXT_CSD_BUS_WIDTH_8, 77349dba033SZiyuan Xu EXT_CSD_BUS_WIDTH_4, 77449dba033SZiyuan Xu }; 77549dba033SZiyuan Xu u32 bus_widths[] = { 77649dba033SZiyuan Xu MMC_BUS_WIDTH_8BIT, 77749dba033SZiyuan Xu MMC_BUS_WIDTH_4BIT, 77849dba033SZiyuan Xu }; 77949dba033SZiyuan Xu ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 78049dba033SZiyuan Xu ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 78149dba033SZiyuan Xu u32 idx, bus_width = 0; 78249dba033SZiyuan Xu int err = 0; 78349dba033SZiyuan Xu 78449dba033SZiyuan Xu if (mmc->version < MMC_VERSION_4 || 78549dba033SZiyuan Xu !(mmc->cfg->host_caps & (MMC_MODE_4BIT | MMC_MODE_8BIT))) 78649dba033SZiyuan Xu return 0; 78749dba033SZiyuan Xu 78849dba033SZiyuan Xu err = mmc_send_ext_csd(mmc, ext_csd); 78949dba033SZiyuan Xu 79049dba033SZiyuan Xu if (err) 79149dba033SZiyuan Xu return err; 79249dba033SZiyuan Xu 79349dba033SZiyuan Xu idx = (mmc->cfg->host_caps & MMC_MODE_8BIT) ? 0 : 1; 79449dba033SZiyuan Xu 79549dba033SZiyuan Xu /* 79649dba033SZiyuan Xu * Unlike SD, MMC cards dont have a configuration register to notify 79749dba033SZiyuan Xu * supported bus width. So bus test command should be run to identify 79849dba033SZiyuan Xu * the supported bus width or compare the ext csd values of current 79949dba033SZiyuan Xu * bus width and ext csd values of 1 bit mode read earlier. 80049dba033SZiyuan Xu */ 80149dba033SZiyuan Xu for (; idx < ARRAY_SIZE(bus_widths); idx++) { 80249dba033SZiyuan Xu /* 80349dba033SZiyuan Xu * Host is capable of 8bit transfer, then switch 80449dba033SZiyuan Xu * the device to work in 8bit transfer mode. If the 80549dba033SZiyuan Xu * mmc switch command returns error then switch to 80649dba033SZiyuan Xu * 4bit transfer mode. On success set the corresponding 80749dba033SZiyuan Xu * bus width on the host. 80849dba033SZiyuan Xu */ 80949dba033SZiyuan Xu err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 81049dba033SZiyuan Xu EXT_CSD_BUS_WIDTH, ext_csd_bits[idx]); 81149dba033SZiyuan Xu if (err) 81249dba033SZiyuan Xu continue; 81349dba033SZiyuan Xu 81449dba033SZiyuan Xu bus_width = bus_widths[idx]; 81549dba033SZiyuan Xu mmc_set_bus_width(mmc, bus_width); 81649dba033SZiyuan Xu 81749dba033SZiyuan Xu err = mmc_send_ext_csd(mmc, test_csd); 81849dba033SZiyuan Xu 81949dba033SZiyuan Xu if (err) 82049dba033SZiyuan Xu continue; 82149dba033SZiyuan Xu 82249dba033SZiyuan Xu /* Only compare read only fields */ 82349dba033SZiyuan Xu if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] == 82449dba033SZiyuan Xu test_csd[EXT_CSD_PARTITIONING_SUPPORT]) && 82549dba033SZiyuan Xu (ext_csd[EXT_CSD_HC_WP_GRP_SIZE] == 82649dba033SZiyuan Xu test_csd[EXT_CSD_HC_WP_GRP_SIZE]) && 82749dba033SZiyuan Xu (ext_csd[EXT_CSD_REV] == test_csd[EXT_CSD_REV]) && 82849dba033SZiyuan Xu (ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] == 82949dba033SZiyuan Xu test_csd[EXT_CSD_HC_ERASE_GRP_SIZE]) && 83049dba033SZiyuan Xu !memcmp(&ext_csd[EXT_CSD_SEC_CNT], 83149dba033SZiyuan Xu &test_csd[EXT_CSD_SEC_CNT], 4)) { 83249dba033SZiyuan Xu err = bus_width; 83349dba033SZiyuan Xu break; 83449dba033SZiyuan Xu } else { 83549dba033SZiyuan Xu err = -EBADMSG; 83649dba033SZiyuan Xu } 83749dba033SZiyuan Xu } 83849dba033SZiyuan Xu 83949dba033SZiyuan Xu return err; 84049dba033SZiyuan Xu } 84149dba033SZiyuan Xu 842699945cbSJason Zhu #ifndef CONFIG_MMC_SIMPLE 84349dba033SZiyuan Xu static const u8 tuning_blk_pattern_4bit[] = { 84449dba033SZiyuan Xu 0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc, 84549dba033SZiyuan Xu 0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef, 84649dba033SZiyuan Xu 0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb, 84749dba033SZiyuan Xu 0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef, 84849dba033SZiyuan Xu 0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c, 84949dba033SZiyuan Xu 0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee, 85049dba033SZiyuan Xu 0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff, 85149dba033SZiyuan Xu 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde, 85249dba033SZiyuan Xu }; 85349dba033SZiyuan Xu 85449dba033SZiyuan Xu static const u8 tuning_blk_pattern_8bit[] = { 85549dba033SZiyuan Xu 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 85649dba033SZiyuan Xu 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc, 85749dba033SZiyuan Xu 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff, 85849dba033SZiyuan Xu 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff, 85949dba033SZiyuan Xu 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd, 86049dba033SZiyuan Xu 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, 86149dba033SZiyuan Xu 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff, 86249dba033SZiyuan Xu 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff, 86349dba033SZiyuan Xu 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 86449dba033SZiyuan Xu 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 86549dba033SZiyuan Xu 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 86649dba033SZiyuan Xu 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 86749dba033SZiyuan Xu 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 86849dba033SZiyuan Xu 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 86949dba033SZiyuan Xu 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 87049dba033SZiyuan Xu 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 87149dba033SZiyuan Xu }; 87249dba033SZiyuan Xu 87349dba033SZiyuan Xu int mmc_send_tuning(struct mmc *mmc, u32 opcode) 87449dba033SZiyuan Xu { 87549dba033SZiyuan Xu struct mmc_cmd cmd; 87649dba033SZiyuan Xu struct mmc_data data; 87749dba033SZiyuan Xu const u8 *tuning_block_pattern; 87849dba033SZiyuan Xu int size, err = 0; 87949dba033SZiyuan Xu u8 *data_buf; 88049dba033SZiyuan Xu 88149dba033SZiyuan Xu if (mmc->bus_width == MMC_BUS_WIDTH_8BIT) { 88249dba033SZiyuan Xu tuning_block_pattern = tuning_blk_pattern_8bit; 88349dba033SZiyuan Xu size = sizeof(tuning_blk_pattern_8bit); 88449dba033SZiyuan Xu } else if (mmc->bus_width == MMC_BUS_WIDTH_4BIT) { 88549dba033SZiyuan Xu tuning_block_pattern = tuning_blk_pattern_4bit; 88649dba033SZiyuan Xu size = sizeof(tuning_blk_pattern_4bit); 88749dba033SZiyuan Xu } else { 88849dba033SZiyuan Xu return -EINVAL; 88949dba033SZiyuan Xu } 89049dba033SZiyuan Xu 89149dba033SZiyuan Xu data_buf = calloc(1, size); 89249dba033SZiyuan Xu if (!data_buf) 89349dba033SZiyuan Xu return -ENOMEM; 89449dba033SZiyuan Xu 89549dba033SZiyuan Xu cmd.cmdidx = opcode; 89649dba033SZiyuan Xu cmd.resp_type = MMC_RSP_R1; 89749dba033SZiyuan Xu cmd.cmdarg = 0; 89849dba033SZiyuan Xu 89949dba033SZiyuan Xu data.dest = (char *)data_buf; 90049dba033SZiyuan Xu data.blocksize = size; 90149dba033SZiyuan Xu data.blocks = 1; 90249dba033SZiyuan Xu data.flags = MMC_DATA_READ; 90349dba033SZiyuan Xu 90449dba033SZiyuan Xu err = mmc_send_cmd(mmc, &cmd, &data); 90549dba033SZiyuan Xu if (err) 90649dba033SZiyuan Xu goto out; 90749dba033SZiyuan Xu 90849dba033SZiyuan Xu if (memcmp(data_buf, tuning_block_pattern, size)) 90949dba033SZiyuan Xu err = -EIO; 91049dba033SZiyuan Xu out: 91149dba033SZiyuan Xu free(data_buf); 91249dba033SZiyuan Xu return err; 91349dba033SZiyuan Xu } 91449dba033SZiyuan Xu 91549dba033SZiyuan Xu static int mmc_execute_tuning(struct mmc *mmc) 91649dba033SZiyuan Xu { 91749dba033SZiyuan Xu #ifdef CONFIG_DM_MMC 91849dba033SZiyuan Xu struct dm_mmc_ops *ops = mmc_get_ops(mmc->dev); 91949dba033SZiyuan Xu #endif 92049dba033SZiyuan Xu u32 opcode; 92149dba033SZiyuan Xu 92249dba033SZiyuan Xu if (IS_SD(mmc)) 92349dba033SZiyuan Xu opcode = MMC_SEND_TUNING_BLOCK; 92449dba033SZiyuan Xu else 92549dba033SZiyuan Xu opcode = MMC_SEND_TUNING_BLOCK_HS200; 92649dba033SZiyuan Xu 92749dba033SZiyuan Xu #ifndef CONFIG_DM_MMC 92849dba033SZiyuan Xu if (mmc->cfg->ops->execute_tuning) { 92949dba033SZiyuan Xu return mmc->cfg->ops->execute_tuning(mmc, opcode); 93049dba033SZiyuan Xu #else 93149dba033SZiyuan Xu if (ops->execute_tuning) { 93249dba033SZiyuan Xu return ops->execute_tuning(mmc->dev, opcode); 93349dba033SZiyuan Xu #endif 93449dba033SZiyuan Xu } else { 93549dba033SZiyuan Xu debug("Tuning feature required for HS200 mode.\n"); 93649dba033SZiyuan Xu return -EIO; 93749dba033SZiyuan Xu } 93849dba033SZiyuan Xu } 93949dba033SZiyuan Xu 94049dba033SZiyuan Xu static int mmc_hs200_tuning(struct mmc *mmc) 94149dba033SZiyuan Xu { 94249dba033SZiyuan Xu return mmc_execute_tuning(mmc); 94349dba033SZiyuan Xu } 94449dba033SZiyuan Xu 945699945cbSJason Zhu #else 946699945cbSJason Zhu int mmc_send_tuning(struct mmc *mmc, u32 opcode) { return 0; } 947699945cbSJason Zhu int mmc_execute_tuning(struct mmc *mmc) { return 0; } 948699945cbSJason Zhu static int mmc_hs200_tuning(struct mmc *mmc) { return 0; } 949699945cbSJason Zhu #endif 950699945cbSJason Zhu 951e61cd3d7SZiyuan Xu static int mmc_select_hs(struct mmc *mmc) 952e61cd3d7SZiyuan Xu { 953e61cd3d7SZiyuan Xu int ret; 954e61cd3d7SZiyuan Xu 955e61cd3d7SZiyuan Xu ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 956e61cd3d7SZiyuan Xu EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS); 957e61cd3d7SZiyuan Xu 958e61cd3d7SZiyuan Xu if (!ret) 959e61cd3d7SZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_MMC_HS); 960e61cd3d7SZiyuan Xu 961e61cd3d7SZiyuan Xu return ret; 962e61cd3d7SZiyuan Xu } 963e61cd3d7SZiyuan Xu 9645545757fSZiyuan Xu static int mmc_select_hs_ddr(struct mmc *mmc) 9655545757fSZiyuan Xu { 9665545757fSZiyuan Xu u32 ext_csd_bits; 9675545757fSZiyuan Xu int err = 0; 9685545757fSZiyuan Xu 9695545757fSZiyuan Xu if (mmc->bus_width == MMC_BUS_WIDTH_1BIT) 9705545757fSZiyuan Xu return 0; 9715545757fSZiyuan Xu 9725545757fSZiyuan Xu ext_csd_bits = (mmc->bus_width == MMC_BUS_WIDTH_8BIT) ? 9735545757fSZiyuan Xu EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4; 9745545757fSZiyuan Xu 9755545757fSZiyuan Xu err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 9765545757fSZiyuan Xu EXT_CSD_BUS_WIDTH, ext_csd_bits); 9775545757fSZiyuan Xu if (err) 9785545757fSZiyuan Xu return err; 9795545757fSZiyuan Xu 9805545757fSZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_MMC_DDR52); 9815545757fSZiyuan Xu 9825545757fSZiyuan Xu return 0; 9835545757fSZiyuan Xu } 9845545757fSZiyuan Xu 985699945cbSJason Zhu #ifndef CONFIG_MMC_SIMPLE 98649dba033SZiyuan Xu static int mmc_select_hs200(struct mmc *mmc) 98749dba033SZiyuan Xu { 98849dba033SZiyuan Xu int ret; 98949dba033SZiyuan Xu 99049dba033SZiyuan Xu /* 99149dba033SZiyuan Xu * Set the bus width(4 or 8) with host's support and 99249dba033SZiyuan Xu * switch to HS200 mode if bus width is set successfully. 99349dba033SZiyuan Xu */ 99449dba033SZiyuan Xu ret = mmc_select_bus_width(mmc); 99549dba033SZiyuan Xu 99649dba033SZiyuan Xu if (ret > 0) { 99749dba033SZiyuan Xu ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 99849dba033SZiyuan Xu EXT_CSD_HS_TIMING, 99949dba033SZiyuan Xu EXT_CSD_TIMING_HS200, false); 100049dba033SZiyuan Xu 100149dba033SZiyuan Xu if (ret) 100249dba033SZiyuan Xu return ret; 100349dba033SZiyuan Xu 100449dba033SZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_MMC_HS200); 100549dba033SZiyuan Xu } 100649dba033SZiyuan Xu 100749dba033SZiyuan Xu return ret; 100849dba033SZiyuan Xu } 100949dba033SZiyuan Xu 1010b673f29aSZiyuan Xu static int mmc_select_hs400(struct mmc *mmc) 1011b673f29aSZiyuan Xu { 1012b673f29aSZiyuan Xu int ret; 1013b673f29aSZiyuan Xu 1014e56bff5bSJason Zhu /* Reduce frequency to HS frequency */ 1015e56bff5bSJason Zhu mmc_set_clock(mmc, MMC_HIGH_52_MAX_DTR); 1016e56bff5bSJason Zhu 1017b673f29aSZiyuan Xu /* Switch card to HS mode */ 1018b673f29aSZiyuan Xu ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1019b673f29aSZiyuan Xu EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS, false); 1020b673f29aSZiyuan Xu if (ret) 1021b673f29aSZiyuan Xu return ret; 1022b673f29aSZiyuan Xu 1023b673f29aSZiyuan Xu /* Set host controller to HS timing */ 1024b673f29aSZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_MMC_HS); 1025b673f29aSZiyuan Xu 1026b673f29aSZiyuan Xu ret = mmc_send_status(mmc, 1000); 1027b673f29aSZiyuan Xu if (ret) 1028b673f29aSZiyuan Xu return ret; 1029b673f29aSZiyuan Xu 1030b673f29aSZiyuan Xu /* Switch card to DDR */ 1031b673f29aSZiyuan Xu ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1032b673f29aSZiyuan Xu EXT_CSD_BUS_WIDTH, 1033b673f29aSZiyuan Xu EXT_CSD_DDR_BUS_WIDTH_8); 1034b673f29aSZiyuan Xu if (ret) 1035b673f29aSZiyuan Xu return ret; 1036b673f29aSZiyuan Xu 1037b673f29aSZiyuan Xu /* Switch card to HS400 */ 1038b673f29aSZiyuan Xu ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1039b673f29aSZiyuan Xu EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400, false); 1040b673f29aSZiyuan Xu if (ret) 1041b673f29aSZiyuan Xu return ret; 1042b673f29aSZiyuan Xu 1043b673f29aSZiyuan Xu /* Set host controller to HS400 timing and frequency */ 1044b673f29aSZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_MMC_HS400); 1045b673f29aSZiyuan Xu 1046b673f29aSZiyuan Xu return ret; 1047b673f29aSZiyuan Xu } 1048699945cbSJason Zhu #else 1049699945cbSJason Zhu static int mmc_select_hs200(struct mmc *mmc) { return 0; } 1050699945cbSJason Zhu static int mmc_select_hs400(struct mmc *mmc) { return 0; } 1051699945cbSJason Zhu #endif 1052b673f29aSZiyuan Xu 1053227f658eSZiyuan Xu static u32 mmc_select_card_type(struct mmc *mmc, u8 *ext_csd) 1054227f658eSZiyuan Xu { 1055227f658eSZiyuan Xu u8 card_type; 1056227f658eSZiyuan Xu u32 host_caps, avail_type = 0; 1057227f658eSZiyuan Xu 1058227f658eSZiyuan Xu card_type = ext_csd[EXT_CSD_CARD_TYPE]; 1059227f658eSZiyuan Xu host_caps = mmc->cfg->host_caps; 1060227f658eSZiyuan Xu 1061227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS) && 1062227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_26)) 1063227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_26; 1064227f658eSZiyuan Xu 1065227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS) && 1066227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_52)) 1067227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_52; 1068227f658eSZiyuan Xu 1069227f658eSZiyuan Xu /* 1070227f658eSZiyuan Xu * For the moment, u-boot doesn't support signal voltage 1071227f658eSZiyuan Xu * switch, therefor we assume that host support ddr52 1072227f658eSZiyuan Xu * at 1.8v or 3.3v I/O(1.2v I/O not supported, hs200 and 1073227f658eSZiyuan Xu * hs400 are the same). 1074227f658eSZiyuan Xu */ 1075227f658eSZiyuan Xu if ((host_caps & MMC_MODE_DDR_52MHz) && 1076227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)) 1077227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V; 1078227f658eSZiyuan Xu 1079227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS200) && 1080227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_HS200_1_8V)) 1081227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V; 1082227f658eSZiyuan Xu 1083227f658eSZiyuan Xu /* 1084227f658eSZiyuan Xu * If host can support HS400, it means that host can also 1085227f658eSZiyuan Xu * support HS200. 1086227f658eSZiyuan Xu */ 1087227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS400) && 1088227f658eSZiyuan Xu (host_caps & MMC_MODE_8BIT) && 1089227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_HS400_1_8V)) 1090227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V | 1091227f658eSZiyuan Xu EXT_CSD_CARD_TYPE_HS400_1_8V; 1092227f658eSZiyuan Xu 1093227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS400ES) && 1094227f658eSZiyuan Xu (host_caps & MMC_MODE_8BIT) && 1095227f658eSZiyuan Xu ext_csd[EXT_CSD_STROBE_SUPPORT] && 1096227f658eSZiyuan Xu (avail_type & EXT_CSD_CARD_TYPE_HS400_1_8V)) 1097227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V | 1098227f658eSZiyuan Xu EXT_CSD_CARD_TYPE_HS400_1_8V | 1099227f658eSZiyuan Xu EXT_CSD_CARD_TYPE_HS400ES; 1100227f658eSZiyuan Xu 1101227f658eSZiyuan Xu return avail_type; 1102227f658eSZiyuan Xu } 1103227f658eSZiyuan Xu 110449dba033SZiyuan Xu static void mmc_set_bus_speed(struct mmc *mmc, u8 avail_type) 110549dba033SZiyuan Xu { 110649dba033SZiyuan Xu int clock = 0; 110749dba033SZiyuan Xu 110849dba033SZiyuan Xu if (mmc_card_hs(mmc)) 110949dba033SZiyuan Xu clock = (avail_type & EXT_CSD_CARD_TYPE_52) ? 111049dba033SZiyuan Xu MMC_HIGH_52_MAX_DTR : MMC_HIGH_26_MAX_DTR; 111149dba033SZiyuan Xu else if (mmc_card_hs200(mmc) || 111249dba033SZiyuan Xu mmc_card_hs400(mmc) || 111349dba033SZiyuan Xu mmc_card_hs400es(mmc)) 111449dba033SZiyuan Xu clock = MMC_HS200_MAX_DTR; 111549dba033SZiyuan Xu 111649dba033SZiyuan Xu mmc_set_clock(mmc, clock); 111749dba033SZiyuan Xu } 111849dba033SZiyuan Xu 1119fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc) 1120272cc70bSAndy Fleming { 11218bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 1122227f658eSZiyuan Xu u32 avail_type; 1123272cc70bSAndy Fleming int err; 1124272cc70bSAndy Fleming 1125fc5b32fbSAndrew Gabbasov mmc->card_caps = 0; 1126272cc70bSAndy Fleming 1127d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 1128d52ebf10SThomas Chou return 0; 1129d52ebf10SThomas Chou 1130272cc70bSAndy Fleming /* Only version 4 supports high-speed */ 1131272cc70bSAndy Fleming if (mmc->version < MMC_VERSION_4) 1132272cc70bSAndy Fleming return 0; 1133272cc70bSAndy Fleming 1134fc5b32fbSAndrew Gabbasov mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; 1135fc5b32fbSAndrew Gabbasov 1136272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 1137272cc70bSAndy Fleming 1138272cc70bSAndy Fleming if (err) 1139272cc70bSAndy Fleming return err; 1140272cc70bSAndy Fleming 1141227f658eSZiyuan Xu avail_type = mmc_select_card_type(mmc, ext_csd); 1142272cc70bSAndy Fleming 114349dba033SZiyuan Xu if (avail_type & EXT_CSD_CARD_TYPE_HS200) 114449dba033SZiyuan Xu err = mmc_select_hs200(mmc); 11451f250d0aSJason Zhu else if (avail_type & EXT_CSD_CARD_TYPE_HS) 1146e61cd3d7SZiyuan Xu err = mmc_select_hs(mmc); 1147227f658eSZiyuan Xu else 1148227f658eSZiyuan Xu err = -EINVAL; 1149272cc70bSAndy Fleming 1150272cc70bSAndy Fleming if (err) 1151a5e27b41SHeiko Schocher return err; 1152272cc70bSAndy Fleming 115349dba033SZiyuan Xu mmc_set_bus_speed(mmc, avail_type); 1154272cc70bSAndy Fleming 1155b673f29aSZiyuan Xu if (mmc_card_hs200(mmc)) { 115649dba033SZiyuan Xu err = mmc_hs200_tuning(mmc); 1157b673f29aSZiyuan Xu if (avail_type & EXT_CSD_CARD_TYPE_HS400 && 1158b673f29aSZiyuan Xu mmc->bus_width == MMC_BUS_WIDTH_8BIT) { 1159b673f29aSZiyuan Xu err = mmc_select_hs400(mmc); 1160b673f29aSZiyuan Xu mmc_set_bus_speed(mmc, avail_type); 1161b673f29aSZiyuan Xu } 1162b673f29aSZiyuan Xu } else if (!mmc_card_hs400es(mmc)) { 116349dba033SZiyuan Xu err = mmc_select_bus_width(mmc) > 0 ? 0 : err; 11645545757fSZiyuan Xu if (!err && avail_type & EXT_CSD_CARD_TYPE_DDR_52) 11655545757fSZiyuan Xu err = mmc_select_hs_ddr(mmc); 11665545757fSZiyuan Xu } 116749dba033SZiyuan Xu 1168272cc70bSAndy Fleming return err; 1169272cc70bSAndy Fleming } 1170272cc70bSAndy Fleming 1171f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num) 1172f866a46dSStephen Warren { 1173f866a46dSStephen Warren switch (part_num) { 1174f866a46dSStephen Warren case 0: 1175f866a46dSStephen Warren mmc->capacity = mmc->capacity_user; 1176f866a46dSStephen Warren break; 1177f866a46dSStephen Warren case 1: 1178f866a46dSStephen Warren case 2: 1179f866a46dSStephen Warren mmc->capacity = mmc->capacity_boot; 1180f866a46dSStephen Warren break; 1181f866a46dSStephen Warren case 3: 1182f866a46dSStephen Warren mmc->capacity = mmc->capacity_rpmb; 1183f866a46dSStephen Warren break; 1184f866a46dSStephen Warren case 4: 1185f866a46dSStephen Warren case 5: 1186f866a46dSStephen Warren case 6: 1187f866a46dSStephen Warren case 7: 1188f866a46dSStephen Warren mmc->capacity = mmc->capacity_gp[part_num - 4]; 1189f866a46dSStephen Warren break; 1190f866a46dSStephen Warren default: 1191f866a46dSStephen Warren return -1; 1192f866a46dSStephen Warren } 1193f866a46dSStephen Warren 1194c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len); 1195f866a46dSStephen Warren 1196f866a46dSStephen Warren return 0; 1197f866a46dSStephen Warren } 1198f866a46dSStephen Warren 11997dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num) 1200bc897b1dSLei Wen { 1201f866a46dSStephen Warren int ret; 1202bc897b1dSLei Wen 1203f866a46dSStephen Warren ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 1204bc897b1dSLei Wen (mmc->part_config & ~PART_ACCESS_MASK) 1205bc897b1dSLei Wen | (part_num & PART_ACCESS_MASK)); 1206f866a46dSStephen Warren 12076dc93e70SPeter Bigot /* 12086dc93e70SPeter Bigot * Set the capacity if the switch succeeded or was intended 12096dc93e70SPeter Bigot * to return to representing the raw device. 12106dc93e70SPeter Bigot */ 1211873cc1d7SStephen Warren if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) { 12126dc93e70SPeter Bigot ret = mmc_set_capacity(mmc, part_num); 1213fdbb139fSSimon Glass mmc_get_blk_desc(mmc)->hwpart = part_num; 1214873cc1d7SStephen Warren } 12156dc93e70SPeter Bigot 12166dc93e70SPeter Bigot return ret; 1217bc897b1dSLei Wen } 1218bc897b1dSLei Wen 1219ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc, 1220ac9da0e0SDiego Santa Cruz const struct mmc_hwpart_conf *conf, 1221ac9da0e0SDiego Santa Cruz enum mmc_hwpart_conf_mode mode) 1222ac9da0e0SDiego Santa Cruz { 1223ac9da0e0SDiego Santa Cruz u8 part_attrs = 0; 1224ac9da0e0SDiego Santa Cruz u32 enh_size_mult; 1225ac9da0e0SDiego Santa Cruz u32 enh_start_addr; 1226ac9da0e0SDiego Santa Cruz u32 gp_size_mult[4]; 1227ac9da0e0SDiego Santa Cruz u32 max_enh_size_mult; 1228ac9da0e0SDiego Santa Cruz u32 tot_enh_size_mult = 0; 12298dda5b0eSDiego Santa Cruz u8 wr_rel_set; 1230ac9da0e0SDiego Santa Cruz int i, pidx, err; 1231ac9da0e0SDiego Santa Cruz ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 1232ac9da0e0SDiego Santa Cruz 1233ac9da0e0SDiego Santa Cruz if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE) 1234ac9da0e0SDiego Santa Cruz return -EINVAL; 1235ac9da0e0SDiego Santa Cruz 1236ac9da0e0SDiego Santa Cruz if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) { 1237ac9da0e0SDiego Santa Cruz printf("eMMC >= 4.4 required for enhanced user data area\n"); 1238ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1239ac9da0e0SDiego Santa Cruz } 1240ac9da0e0SDiego Santa Cruz 1241ac9da0e0SDiego Santa Cruz if (!(mmc->part_support & PART_SUPPORT)) { 1242ac9da0e0SDiego Santa Cruz printf("Card does not support partitioning\n"); 1243ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1244ac9da0e0SDiego Santa Cruz } 1245ac9da0e0SDiego Santa Cruz 1246ac9da0e0SDiego Santa Cruz if (!mmc->hc_wp_grp_size) { 1247ac9da0e0SDiego Santa Cruz printf("Card does not define HC WP group size\n"); 1248ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1249ac9da0e0SDiego Santa Cruz } 1250ac9da0e0SDiego Santa Cruz 1251ac9da0e0SDiego Santa Cruz /* check partition alignment and total enhanced size */ 1252ac9da0e0SDiego Santa Cruz if (conf->user.enh_size) { 1253ac9da0e0SDiego Santa Cruz if (conf->user.enh_size % mmc->hc_wp_grp_size || 1254ac9da0e0SDiego Santa Cruz conf->user.enh_start % mmc->hc_wp_grp_size) { 1255ac9da0e0SDiego Santa Cruz printf("User data enhanced area not HC WP group " 1256ac9da0e0SDiego Santa Cruz "size aligned\n"); 1257ac9da0e0SDiego Santa Cruz return -EINVAL; 1258ac9da0e0SDiego Santa Cruz } 1259ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_USR; 1260ac9da0e0SDiego Santa Cruz enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size; 1261ac9da0e0SDiego Santa Cruz if (mmc->high_capacity) { 1262ac9da0e0SDiego Santa Cruz enh_start_addr = conf->user.enh_start; 1263ac9da0e0SDiego Santa Cruz } else { 1264ac9da0e0SDiego Santa Cruz enh_start_addr = (conf->user.enh_start << 9); 1265ac9da0e0SDiego Santa Cruz } 1266ac9da0e0SDiego Santa Cruz } else { 1267ac9da0e0SDiego Santa Cruz enh_size_mult = 0; 1268ac9da0e0SDiego Santa Cruz enh_start_addr = 0; 1269ac9da0e0SDiego Santa Cruz } 1270ac9da0e0SDiego Santa Cruz tot_enh_size_mult += enh_size_mult; 1271ac9da0e0SDiego Santa Cruz 1272ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 1273ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) { 1274ac9da0e0SDiego Santa Cruz printf("GP%i partition not HC WP group size " 1275ac9da0e0SDiego Santa Cruz "aligned\n", pidx+1); 1276ac9da0e0SDiego Santa Cruz return -EINVAL; 1277ac9da0e0SDiego Santa Cruz } 1278ac9da0e0SDiego Santa Cruz gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size; 1279ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) { 1280ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_GP(pidx); 1281ac9da0e0SDiego Santa Cruz tot_enh_size_mult += gp_size_mult[pidx]; 1282ac9da0e0SDiego Santa Cruz } 1283ac9da0e0SDiego Santa Cruz } 1284ac9da0e0SDiego Santa Cruz 1285ac9da0e0SDiego Santa Cruz if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) { 1286ac9da0e0SDiego Santa Cruz printf("Card does not support enhanced attribute\n"); 1287ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1288ac9da0e0SDiego Santa Cruz } 1289ac9da0e0SDiego Santa Cruz 1290ac9da0e0SDiego Santa Cruz err = mmc_send_ext_csd(mmc, ext_csd); 1291ac9da0e0SDiego Santa Cruz if (err) 1292ac9da0e0SDiego Santa Cruz return err; 1293ac9da0e0SDiego Santa Cruz 1294ac9da0e0SDiego Santa Cruz max_enh_size_mult = 1295ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) + 1296ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) + 1297ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]; 1298ac9da0e0SDiego Santa Cruz if (tot_enh_size_mult > max_enh_size_mult) { 1299ac9da0e0SDiego Santa Cruz printf("Total enhanced size exceeds maximum (%u > %u)\n", 1300ac9da0e0SDiego Santa Cruz tot_enh_size_mult, max_enh_size_mult); 1301ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1302ac9da0e0SDiego Santa Cruz } 1303ac9da0e0SDiego Santa Cruz 13048dda5b0eSDiego Santa Cruz /* The default value of EXT_CSD_WR_REL_SET is device 13058dda5b0eSDiego Santa Cruz * dependent, the values can only be changed if the 13068dda5b0eSDiego Santa Cruz * EXT_CSD_HS_CTRL_REL bit is set. The values can be 13078dda5b0eSDiego Santa Cruz * changed only once and before partitioning is completed. */ 13088dda5b0eSDiego Santa Cruz wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 13098dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_change) { 13108dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_set) 13118dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_USR; 13128dda5b0eSDiego Santa Cruz else 13138dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR; 13148dda5b0eSDiego Santa Cruz } 13158dda5b0eSDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 13168dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_change) { 13178dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_set) 13188dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx); 13198dda5b0eSDiego Santa Cruz else 13208dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx); 13218dda5b0eSDiego Santa Cruz } 13228dda5b0eSDiego Santa Cruz } 13238dda5b0eSDiego Santa Cruz 13248dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] && 13258dda5b0eSDiego Santa Cruz !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) { 13268dda5b0eSDiego Santa Cruz puts("Card does not support host controlled partition write " 13278dda5b0eSDiego Santa Cruz "reliability settings\n"); 13288dda5b0eSDiego Santa Cruz return -EMEDIUMTYPE; 13298dda5b0eSDiego Santa Cruz } 13308dda5b0eSDiego Santa Cruz 1331ac9da0e0SDiego Santa Cruz if (ext_csd[EXT_CSD_PARTITION_SETTING] & 1332ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED) { 1333ac9da0e0SDiego Santa Cruz printf("Card already partitioned\n"); 1334ac9da0e0SDiego Santa Cruz return -EPERM; 1335ac9da0e0SDiego Santa Cruz } 1336ac9da0e0SDiego Santa Cruz 1337ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_CHECK) 1338ac9da0e0SDiego Santa Cruz return 0; 1339ac9da0e0SDiego Santa Cruz 1340ac9da0e0SDiego Santa Cruz /* Partitioning requires high-capacity size definitions */ 1341ac9da0e0SDiego Santa Cruz if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) { 1342ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1343ac9da0e0SDiego Santa Cruz EXT_CSD_ERASE_GROUP_DEF, 1); 1344ac9da0e0SDiego Santa Cruz 1345ac9da0e0SDiego Santa Cruz if (err) 1346ac9da0e0SDiego Santa Cruz return err; 1347ac9da0e0SDiego Santa Cruz 1348ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 1349ac9da0e0SDiego Santa Cruz 1350ac9da0e0SDiego Santa Cruz /* update erase group size to be high-capacity */ 1351ac9da0e0SDiego Santa Cruz mmc->erase_grp_size = 1352ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 1353ac9da0e0SDiego Santa Cruz 1354ac9da0e0SDiego Santa Cruz } 1355ac9da0e0SDiego Santa Cruz 1356ac9da0e0SDiego Santa Cruz /* all OK, write the configuration */ 1357ac9da0e0SDiego Santa Cruz for (i = 0; i < 4; i++) { 1358ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1359ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_START_ADDR+i, 1360ac9da0e0SDiego Santa Cruz (enh_start_addr >> (i*8)) & 0xFF); 1361ac9da0e0SDiego Santa Cruz if (err) 1362ac9da0e0SDiego Santa Cruz return err; 1363ac9da0e0SDiego Santa Cruz } 1364ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 1365ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1366ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_SIZE_MULT+i, 1367ac9da0e0SDiego Santa Cruz (enh_size_mult >> (i*8)) & 0xFF); 1368ac9da0e0SDiego Santa Cruz if (err) 1369ac9da0e0SDiego Santa Cruz return err; 1370ac9da0e0SDiego Santa Cruz } 1371ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 1372ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 1373ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1374ac9da0e0SDiego Santa Cruz EXT_CSD_GP_SIZE_MULT+pidx*3+i, 1375ac9da0e0SDiego Santa Cruz (gp_size_mult[pidx] >> (i*8)) & 0xFF); 1376ac9da0e0SDiego Santa Cruz if (err) 1377ac9da0e0SDiego Santa Cruz return err; 1378ac9da0e0SDiego Santa Cruz } 1379ac9da0e0SDiego Santa Cruz } 1380ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1381ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs); 1382ac9da0e0SDiego Santa Cruz if (err) 1383ac9da0e0SDiego Santa Cruz return err; 1384ac9da0e0SDiego Santa Cruz 1385ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_SET) 1386ac9da0e0SDiego Santa Cruz return 0; 1387ac9da0e0SDiego Santa Cruz 13888dda5b0eSDiego Santa Cruz /* The WR_REL_SET is a write-once register but shall be 13898dda5b0eSDiego Santa Cruz * written before setting PART_SETTING_COMPLETED. As it is 13908dda5b0eSDiego Santa Cruz * write-once we can only write it when completing the 13918dda5b0eSDiego Santa Cruz * partitioning. */ 13928dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) { 13938dda5b0eSDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 13948dda5b0eSDiego Santa Cruz EXT_CSD_WR_REL_SET, wr_rel_set); 13958dda5b0eSDiego Santa Cruz if (err) 13968dda5b0eSDiego Santa Cruz return err; 13978dda5b0eSDiego Santa Cruz } 13988dda5b0eSDiego Santa Cruz 1399ac9da0e0SDiego Santa Cruz /* Setting PART_SETTING_COMPLETED confirms the partition 1400ac9da0e0SDiego Santa Cruz * configuration but it only becomes effective after power 1401ac9da0e0SDiego Santa Cruz * cycle, so we do not adjust the partition related settings 1402ac9da0e0SDiego Santa Cruz * in the mmc struct. */ 1403ac9da0e0SDiego Santa Cruz 1404ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1405ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING, 1406ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 1407ac9da0e0SDiego Santa Cruz if (err) 1408ac9da0e0SDiego Santa Cruz return err; 1409ac9da0e0SDiego Santa Cruz 1410ac9da0e0SDiego Santa Cruz return 0; 1411ac9da0e0SDiego Santa Cruz } 1412ac9da0e0SDiego Santa Cruz 1413e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 141448972d90SThierry Reding int mmc_getcd(struct mmc *mmc) 141548972d90SThierry Reding { 141648972d90SThierry Reding int cd; 141748972d90SThierry Reding 141848972d90SThierry Reding cd = board_mmc_getcd(mmc); 141948972d90SThierry Reding 1420d4e1da4eSPeter Korsgaard if (cd < 0) { 142193bfd616SPantelis Antoniou if (mmc->cfg->ops->getcd) 142293bfd616SPantelis Antoniou cd = mmc->cfg->ops->getcd(mmc); 1423d4e1da4eSPeter Korsgaard else 1424d4e1da4eSPeter Korsgaard cd = 1; 1425d4e1da4eSPeter Korsgaard } 142648972d90SThierry Reding 142748972d90SThierry Reding return cd; 142848972d90SThierry Reding } 14298ca51e51SSimon Glass #endif 143048972d90SThierry Reding 1431fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) 1432272cc70bSAndy Fleming { 1433272cc70bSAndy Fleming struct mmc_cmd cmd; 1434272cc70bSAndy Fleming struct mmc_data data; 1435272cc70bSAndy Fleming 1436272cc70bSAndy Fleming /* Switch the frequency */ 1437272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC; 1438272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1439272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff; 1440272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4)); 1441272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4); 1442272cc70bSAndy Fleming 1443272cc70bSAndy Fleming data.dest = (char *)resp; 1444272cc70bSAndy Fleming data.blocksize = 64; 1445272cc70bSAndy Fleming data.blocks = 1; 1446272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1447272cc70bSAndy Fleming 1448272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 1449272cc70bSAndy Fleming } 1450272cc70bSAndy Fleming 1451272cc70bSAndy Fleming 1452fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc) 1453272cc70bSAndy Fleming { 1454272cc70bSAndy Fleming int err; 1455272cc70bSAndy Fleming struct mmc_cmd cmd; 1456f781dd38SAnton staaf ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2); 1457f781dd38SAnton staaf ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16); 1458272cc70bSAndy Fleming struct mmc_data data; 1459272cc70bSAndy Fleming int timeout; 1460272cc70bSAndy Fleming 1461272cc70bSAndy Fleming mmc->card_caps = 0; 1462272cc70bSAndy Fleming 1463d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 1464d52ebf10SThomas Chou return 0; 1465d52ebf10SThomas Chou 1466272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */ 1467272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 1468272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1469272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1470272cc70bSAndy Fleming 1471272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1472272cc70bSAndy Fleming 1473272cc70bSAndy Fleming if (err) 1474272cc70bSAndy Fleming return err; 1475272cc70bSAndy Fleming 1476272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR; 1477272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1478272cc70bSAndy Fleming cmd.cmdarg = 0; 1479272cc70bSAndy Fleming 1480272cc70bSAndy Fleming timeout = 3; 1481272cc70bSAndy Fleming 1482272cc70bSAndy Fleming retry_scr: 1483f781dd38SAnton staaf data.dest = (char *)scr; 1484272cc70bSAndy Fleming data.blocksize = 8; 1485272cc70bSAndy Fleming data.blocks = 1; 1486272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1487272cc70bSAndy Fleming 1488272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 1489272cc70bSAndy Fleming 1490272cc70bSAndy Fleming if (err) { 1491272cc70bSAndy Fleming if (timeout--) 1492272cc70bSAndy Fleming goto retry_scr; 1493272cc70bSAndy Fleming 1494272cc70bSAndy Fleming return err; 1495272cc70bSAndy Fleming } 1496272cc70bSAndy Fleming 14974e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]); 14984e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]); 1499272cc70bSAndy Fleming 1500272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) { 1501272cc70bSAndy Fleming case 0: 1502272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1503272cc70bSAndy Fleming break; 1504272cc70bSAndy Fleming case 1: 1505272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10; 1506272cc70bSAndy Fleming break; 1507272cc70bSAndy Fleming case 2: 1508272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 15091741c64dSJaehoon Chung if ((mmc->scr[0] >> 15) & 0x1) 15101741c64dSJaehoon Chung mmc->version = SD_VERSION_3; 1511272cc70bSAndy Fleming break; 1512272cc70bSAndy Fleming default: 1513272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1514272cc70bSAndy Fleming break; 1515272cc70bSAndy Fleming } 1516272cc70bSAndy Fleming 1517b44c7083SAlagu Sankar if (mmc->scr[0] & SD_DATA_4BIT) 1518b44c7083SAlagu Sankar mmc->card_caps |= MMC_MODE_4BIT; 1519b44c7083SAlagu Sankar 1520272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */ 1521272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0) 1522272cc70bSAndy Fleming return 0; 1523272cc70bSAndy Fleming 1524272cc70bSAndy Fleming timeout = 4; 1525272cc70bSAndy Fleming while (timeout--) { 1526272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, 1527f781dd38SAnton staaf (u8 *)switch_status); 1528272cc70bSAndy Fleming 1529272cc70bSAndy Fleming if (err) 1530272cc70bSAndy Fleming return err; 1531272cc70bSAndy Fleming 1532272cc70bSAndy Fleming /* The high-speed function is busy. Try again */ 15334e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) 1534272cc70bSAndy Fleming break; 1535272cc70bSAndy Fleming } 1536272cc70bSAndy Fleming 1537272cc70bSAndy Fleming /* If high-speed isn't supported, we return */ 15384e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)) 1539272cc70bSAndy Fleming return 0; 1540272cc70bSAndy Fleming 15412c3fbf4cSMacpaul Lin /* 15422c3fbf4cSMacpaul Lin * If the host doesn't support SD_HIGHSPEED, do not switch card to 15432c3fbf4cSMacpaul Lin * HIGHSPEED mode even if the card support SD_HIGHSPPED. 15442c3fbf4cSMacpaul Lin * This can avoid furthur problem when the card runs in different 15452c3fbf4cSMacpaul Lin * mode between the host. 15462c3fbf4cSMacpaul Lin */ 154793bfd616SPantelis Antoniou if (!((mmc->cfg->host_caps & MMC_MODE_HS_52MHz) && 154893bfd616SPantelis Antoniou (mmc->cfg->host_caps & MMC_MODE_HS))) 15492c3fbf4cSMacpaul Lin return 0; 15502c3fbf4cSMacpaul Lin 1551f781dd38SAnton staaf err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status); 1552272cc70bSAndy Fleming 1553272cc70bSAndy Fleming if (err) 1554272cc70bSAndy Fleming return err; 1555272cc70bSAndy Fleming 15564e3d89baSYauhen Kharuzhy if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000) 1557272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS; 1558272cc70bSAndy Fleming 1559272cc70bSAndy Fleming return 0; 1560272cc70bSAndy Fleming } 1561272cc70bSAndy Fleming 15623697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc) 15633697e599SPeng Fan { 15643697e599SPeng Fan int err, i; 15653697e599SPeng Fan struct mmc_cmd cmd; 15663697e599SPeng Fan ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16); 15673697e599SPeng Fan struct mmc_data data; 15683697e599SPeng Fan int timeout = 3; 15693697e599SPeng Fan unsigned int au, eo, et, es; 15703697e599SPeng Fan 15713697e599SPeng Fan cmd.cmdidx = MMC_CMD_APP_CMD; 15723697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 15733697e599SPeng Fan cmd.cmdarg = mmc->rca << 16; 15743697e599SPeng Fan 15753697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, NULL); 15763697e599SPeng Fan if (err) 15773697e599SPeng Fan return err; 15783697e599SPeng Fan 15793697e599SPeng Fan cmd.cmdidx = SD_CMD_APP_SD_STATUS; 15803697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 15813697e599SPeng Fan cmd.cmdarg = 0; 15823697e599SPeng Fan 15833697e599SPeng Fan retry_ssr: 15843697e599SPeng Fan data.dest = (char *)ssr; 15853697e599SPeng Fan data.blocksize = 64; 15863697e599SPeng Fan data.blocks = 1; 15873697e599SPeng Fan data.flags = MMC_DATA_READ; 15883697e599SPeng Fan 15893697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, &data); 15903697e599SPeng Fan if (err) { 15913697e599SPeng Fan if (timeout--) 15923697e599SPeng Fan goto retry_ssr; 15933697e599SPeng Fan 15943697e599SPeng Fan return err; 15953697e599SPeng Fan } 15963697e599SPeng Fan 15973697e599SPeng Fan for (i = 0; i < 16; i++) 15983697e599SPeng Fan ssr[i] = be32_to_cpu(ssr[i]); 15993697e599SPeng Fan 16003697e599SPeng Fan au = (ssr[2] >> 12) & 0xF; 16013697e599SPeng Fan if ((au <= 9) || (mmc->version == SD_VERSION_3)) { 16023697e599SPeng Fan mmc->ssr.au = sd_au_size[au]; 16033697e599SPeng Fan es = (ssr[3] >> 24) & 0xFF; 16043697e599SPeng Fan es |= (ssr[2] & 0xFF) << 8; 16053697e599SPeng Fan et = (ssr[3] >> 18) & 0x3F; 16063697e599SPeng Fan if (es && et) { 16073697e599SPeng Fan eo = (ssr[3] >> 16) & 0x3; 16083697e599SPeng Fan mmc->ssr.erase_timeout = (et * 1000) / es; 16093697e599SPeng Fan mmc->ssr.erase_offset = eo * 1000; 16103697e599SPeng Fan } 16113697e599SPeng Fan } else { 16123697e599SPeng Fan debug("Invalid Allocation Unit Size.\n"); 16133697e599SPeng Fan } 16143697e599SPeng Fan 16153697e599SPeng Fan return 0; 16163697e599SPeng Fan } 16173697e599SPeng Fan 1618272cc70bSAndy Fleming /* frequency bases */ 1619272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */ 16205f837c2cSMike Frysinger static const int fbase[] = { 1621272cc70bSAndy Fleming 10000, 1622272cc70bSAndy Fleming 100000, 1623272cc70bSAndy Fleming 1000000, 1624272cc70bSAndy Fleming 10000000, 1625272cc70bSAndy Fleming }; 1626272cc70bSAndy Fleming 1627272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice 1628272cc70bSAndy Fleming * to platforms without floating point. 1629272cc70bSAndy Fleming */ 163061fe076fSSimon Glass static const u8 multipliers[] = { 1631272cc70bSAndy Fleming 0, /* reserved */ 1632272cc70bSAndy Fleming 10, 1633272cc70bSAndy Fleming 12, 1634272cc70bSAndy Fleming 13, 1635272cc70bSAndy Fleming 15, 1636272cc70bSAndy Fleming 20, 1637272cc70bSAndy Fleming 25, 1638272cc70bSAndy Fleming 30, 1639272cc70bSAndy Fleming 35, 1640272cc70bSAndy Fleming 40, 1641272cc70bSAndy Fleming 45, 1642272cc70bSAndy Fleming 50, 1643272cc70bSAndy Fleming 55, 1644272cc70bSAndy Fleming 60, 1645272cc70bSAndy Fleming 70, 1646272cc70bSAndy Fleming 80, 1647272cc70bSAndy Fleming }; 1648272cc70bSAndy Fleming 1649e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 1650fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc) 1651272cc70bSAndy Fleming { 165293bfd616SPantelis Antoniou if (mmc->cfg->ops->set_ios) 165393bfd616SPantelis Antoniou mmc->cfg->ops->set_ios(mmc); 1654272cc70bSAndy Fleming } 1655ad77484aSZiyuan Xu 1656ad77484aSZiyuan Xu static bool mmc_card_busy(struct mmc *mmc) 1657ad77484aSZiyuan Xu { 1658ad77484aSZiyuan Xu if (!mmc->cfg->ops->card_busy) 1659ad77484aSZiyuan Xu return -ENOSYS; 1660ad77484aSZiyuan Xu 1661ad77484aSZiyuan Xu return mmc->cfg->ops->card_busy(mmc); 1662ad77484aSZiyuan Xu } 1663ad77484aSZiyuan Xu 1664ad77484aSZiyuan Xu static bool mmc_can_card_busy(struct mmc *) 1665ad77484aSZiyuan Xu { 1666ad77484aSZiyuan Xu return !!mmc->cfg->ops->card_busy; 1667ad77484aSZiyuan Xu } 16688ca51e51SSimon Glass #endif 1669272cc70bSAndy Fleming 1670fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc) 1671272cc70bSAndy Fleming { 1672f866a46dSStephen Warren int err, i; 16733e3ff0acSZiyuan Xu uint mult, freq, tran_speed; 1674639b7827SYoshihiro Shimoda u64 cmult, csize, capacity; 1675272cc70bSAndy Fleming struct mmc_cmd cmd; 16768bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 16770c453bb7SDiego Santa Cruz bool has_parts = false; 16788a0cf490SDiego Santa Cruz bool part_completed; 1679c40fdca6SSimon Glass struct blk_desc *bdesc; 1680272cc70bSAndy Fleming 1681d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON 1682d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ 1683d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; 1684d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R1; 1685d52ebf10SThomas Chou cmd.cmdarg = 1; 1686d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 1687d52ebf10SThomas Chou 1688d52ebf10SThomas Chou if (err) 1689d52ebf10SThomas Chou return err; 1690d52ebf10SThomas Chou } 1691d52ebf10SThomas Chou #endif 1692479fbf72SJason Zhu #ifndef CONFIG_MMC_USE_PRE_CONFIG 1693272cc70bSAndy Fleming /* Put the Card in Identify Mode */ 1694d52ebf10SThomas Chou cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : 1695d52ebf10SThomas Chou MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ 1696272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1697272cc70bSAndy Fleming cmd.cmdarg = 0; 1698272cc70bSAndy Fleming 1699272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1700272cc70bSAndy Fleming 1701272cc70bSAndy Fleming if (err) 1702272cc70bSAndy Fleming return err; 1703272cc70bSAndy Fleming 1704272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16); 1705272cc70bSAndy Fleming 1706272cc70bSAndy Fleming /* 1707272cc70bSAndy Fleming * For MMC cards, set the Relative Address. 1708272cc70bSAndy Fleming * For SD cards, get the Relatvie Address. 1709272cc70bSAndy Fleming * This also puts the cards into Standby State 1710272cc70bSAndy Fleming */ 1711d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1712272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; 1713272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1714272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6; 1715272cc70bSAndy Fleming 1716272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1717272cc70bSAndy Fleming 1718272cc70bSAndy Fleming if (err) 1719272cc70bSAndy Fleming return err; 1720272cc70bSAndy Fleming 1721272cc70bSAndy Fleming if (IS_SD(mmc)) 1722998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff; 1723d52ebf10SThomas Chou } 1724479fbf72SJason Zhu #endif 1725272cc70bSAndy Fleming /* Get the Card-Specific Data */ 1726272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD; 1727272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1728272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1729272cc70bSAndy Fleming 1730272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1731272cc70bSAndy Fleming 1732272cc70bSAndy Fleming if (err) 1733272cc70bSAndy Fleming return err; 1734272cc70bSAndy Fleming 1735998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0]; 1736998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1]; 1737998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2]; 1738998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3]; 1739272cc70bSAndy Fleming 1740272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) { 17410b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf; 1742272cc70bSAndy Fleming 1743272cc70bSAndy Fleming switch (version) { 1744272cc70bSAndy Fleming case 0: 1745272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1746272cc70bSAndy Fleming break; 1747272cc70bSAndy Fleming case 1: 1748272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4; 1749272cc70bSAndy Fleming break; 1750272cc70bSAndy Fleming case 2: 1751272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2; 1752272cc70bSAndy Fleming break; 1753272cc70bSAndy Fleming case 3: 1754272cc70bSAndy Fleming mmc->version = MMC_VERSION_3; 1755272cc70bSAndy Fleming break; 1756272cc70bSAndy Fleming case 4: 1757272cc70bSAndy Fleming mmc->version = MMC_VERSION_4; 1758272cc70bSAndy Fleming break; 1759272cc70bSAndy Fleming default: 1760272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1761272cc70bSAndy Fleming break; 1762272cc70bSAndy Fleming } 1763272cc70bSAndy Fleming } 1764272cc70bSAndy Fleming 1765272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */ 17660b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)]; 17670b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; 1768272cc70bSAndy Fleming 17693e3ff0acSZiyuan Xu tran_speed = freq * mult; 1770272cc70bSAndy Fleming 1771ab71188cSMarkus Niebel mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); 1772998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); 1773272cc70bSAndy Fleming 1774272cc70bSAndy Fleming if (IS_SD(mmc)) 1775272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len; 1776272cc70bSAndy Fleming else 1777998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); 1778272cc70bSAndy Fleming 1779272cc70bSAndy Fleming if (mmc->high_capacity) { 1780272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16 1781272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16; 1782272cc70bSAndy Fleming cmult = 8; 1783272cc70bSAndy Fleming } else { 1784272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2 1785272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30; 1786272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15; 1787272cc70bSAndy Fleming } 1788272cc70bSAndy Fleming 1789f866a46dSStephen Warren mmc->capacity_user = (csize + 1) << (cmult + 2); 1790f866a46dSStephen Warren mmc->capacity_user *= mmc->read_bl_len; 1791f866a46dSStephen Warren mmc->capacity_boot = 0; 1792f866a46dSStephen Warren mmc->capacity_rpmb = 0; 1793f866a46dSStephen Warren for (i = 0; i < 4; i++) 1794f866a46dSStephen Warren mmc->capacity_gp[i] = 0; 1795272cc70bSAndy Fleming 17968bfa195eSSimon Glass if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN) 17978bfa195eSSimon Glass mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 1798272cc70bSAndy Fleming 17998bfa195eSSimon Glass if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) 18008bfa195eSSimon Glass mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 1801272cc70bSAndy Fleming 1802ab71188cSMarkus Niebel if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) { 1803ab71188cSMarkus Niebel cmd.cmdidx = MMC_CMD_SET_DSR; 1804ab71188cSMarkus Niebel cmd.cmdarg = (mmc->dsr & 0xffff) << 16; 1805ab71188cSMarkus Niebel cmd.resp_type = MMC_RSP_NONE; 1806ab71188cSMarkus Niebel if (mmc_send_cmd(mmc, &cmd, NULL)) 1807ab71188cSMarkus Niebel printf("MMC: SET_DSR failed\n"); 1808ab71188cSMarkus Niebel } 1809ab71188cSMarkus Niebel 1810272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */ 1811d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1812272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD; 1813fe8f7066SAjay Bhargav cmd.resp_type = MMC_RSP_R1; 1814272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1815272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1816272cc70bSAndy Fleming 1817272cc70bSAndy Fleming if (err) 1818272cc70bSAndy Fleming return err; 1819d52ebf10SThomas Chou } 1820272cc70bSAndy Fleming 1821e6f99a56SLei Wen /* 1822e6f99a56SLei Wen * For SD, its erase group is always one sector 1823e6f99a56SLei Wen */ 1824e6f99a56SLei Wen mmc->erase_grp_size = 1; 1825bc897b1dSLei Wen mmc->part_config = MMCPART_NOAVAILABLE; 1826d23e2c09SSukumar Ghorai if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) { 1827d23e2c09SSukumar Ghorai /* check ext_csd version and capacity */ 1828d23e2c09SSukumar Ghorai err = mmc_send_ext_csd(mmc, ext_csd); 18299cf199ebSDiego Santa Cruz if (err) 18309cf199ebSDiego Santa Cruz return err; 18319cf199ebSDiego Santa Cruz if (ext_csd[EXT_CSD_REV] >= 2) { 1832639b7827SYoshihiro Shimoda /* 1833639b7827SYoshihiro Shimoda * According to the JEDEC Standard, the value of 1834639b7827SYoshihiro Shimoda * ext_csd's capacity is valid if the value is more 1835639b7827SYoshihiro Shimoda * than 2GB 1836639b7827SYoshihiro Shimoda */ 18370560db18SLei Wen capacity = ext_csd[EXT_CSD_SEC_CNT] << 0 18380560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 18390560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 18400560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; 18418bfa195eSSimon Glass capacity *= MMC_MAX_BLOCK_LEN; 1842b1f1e821SŁukasz Majewski if ((capacity >> 20) > 2 * 1024) 1843f866a46dSStephen Warren mmc->capacity_user = capacity; 1844d23e2c09SSukumar Ghorai } 1845bc897b1dSLei Wen 184664f4a619SJaehoon Chung switch (ext_csd[EXT_CSD_REV]) { 184764f4a619SJaehoon Chung case 1: 184864f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_1; 184964f4a619SJaehoon Chung break; 185064f4a619SJaehoon Chung case 2: 185164f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_2; 185264f4a619SJaehoon Chung break; 185364f4a619SJaehoon Chung case 3: 185464f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_3; 185564f4a619SJaehoon Chung break; 185664f4a619SJaehoon Chung case 5: 185764f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_41; 185864f4a619SJaehoon Chung break; 185964f4a619SJaehoon Chung case 6: 186064f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_5; 186164f4a619SJaehoon Chung break; 1862edab723bSMarkus Niebel case 7: 1863edab723bSMarkus Niebel mmc->version = MMC_VERSION_5_0; 1864edab723bSMarkus Niebel break; 18651a3619cfSStefan Wahren case 8: 18661a3619cfSStefan Wahren mmc->version = MMC_VERSION_5_1; 18671a3619cfSStefan Wahren break; 186864f4a619SJaehoon Chung } 186964f4a619SJaehoon Chung 18708a0cf490SDiego Santa Cruz /* The partition data may be non-zero but it is only 18718a0cf490SDiego Santa Cruz * effective if PARTITION_SETTING_COMPLETED is set in 18728a0cf490SDiego Santa Cruz * EXT_CSD, so ignore any data if this bit is not set, 18738a0cf490SDiego Santa Cruz * except for enabling the high-capacity group size 18748a0cf490SDiego Santa Cruz * definition (see below). */ 18758a0cf490SDiego Santa Cruz part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] & 18768a0cf490SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 18778a0cf490SDiego Santa Cruz 18780c453bb7SDiego Santa Cruz /* store the partition info of emmc */ 18790c453bb7SDiego Santa Cruz mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT]; 18800c453bb7SDiego Santa Cruz if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || 18810c453bb7SDiego Santa Cruz ext_csd[EXT_CSD_BOOT_MULT]) 18820c453bb7SDiego Santa Cruz mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; 18838a0cf490SDiego Santa Cruz if (part_completed && 18848a0cf490SDiego Santa Cruz (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT)) 18850c453bb7SDiego Santa Cruz mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]; 1886a6a1f5f8SJason Zhu if (ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] & EXT_CSD_SEC_GB_CL_EN) 1887a6a1f5f8SJason Zhu mmc->esr.mmc_can_trim = 1; 18880c453bb7SDiego Santa Cruz 18890c453bb7SDiego Santa Cruz mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17; 18900c453bb7SDiego Santa Cruz 18910c453bb7SDiego Santa Cruz mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17; 18920c453bb7SDiego Santa Cruz 18930c453bb7SDiego Santa Cruz for (i = 0; i < 4; i++) { 18940c453bb7SDiego Santa Cruz int idx = EXT_CSD_GP_SIZE_MULT + i * 3; 18958a0cf490SDiego Santa Cruz uint mult = (ext_csd[idx + 2] << 16) + 18960c453bb7SDiego Santa Cruz (ext_csd[idx + 1] << 8) + ext_csd[idx]; 18978a0cf490SDiego Santa Cruz if (mult) 18988a0cf490SDiego Santa Cruz has_parts = true; 18998a0cf490SDiego Santa Cruz if (!part_completed) 19008a0cf490SDiego Santa Cruz continue; 19018a0cf490SDiego Santa Cruz mmc->capacity_gp[i] = mult; 19020c453bb7SDiego Santa Cruz mmc->capacity_gp[i] *= 19030c453bb7SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 19040c453bb7SDiego Santa Cruz mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1905f8e89d67SDiego Santa Cruz mmc->capacity_gp[i] <<= 19; 19060c453bb7SDiego Santa Cruz } 19070c453bb7SDiego Santa Cruz 19088a0cf490SDiego Santa Cruz if (part_completed) { 1909a7f852b6SDiego Santa Cruz mmc->enh_user_size = 1910a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_SIZE_MULT+2] << 16) + 1911a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_SIZE_MULT+1] << 8) + 1912a7f852b6SDiego Santa Cruz ext_csd[EXT_CSD_ENH_SIZE_MULT]; 1913a7f852b6SDiego Santa Cruz mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1914a7f852b6SDiego Santa Cruz mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1915a7f852b6SDiego Santa Cruz mmc->enh_user_size <<= 19; 1916a7f852b6SDiego Santa Cruz mmc->enh_user_start = 1917a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_START_ADDR+3] << 24) + 1918a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_START_ADDR+2] << 16) + 1919a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_START_ADDR+1] << 8) + 1920a7f852b6SDiego Santa Cruz ext_csd[EXT_CSD_ENH_START_ADDR]; 1921a7f852b6SDiego Santa Cruz if (mmc->high_capacity) 1922a7f852b6SDiego Santa Cruz mmc->enh_user_start <<= 9; 19238a0cf490SDiego Santa Cruz } 1924a7f852b6SDiego Santa Cruz 1925e6f99a56SLei Wen /* 19261937e5aaSOliver Metz * Host needs to enable ERASE_GRP_DEF bit if device is 19271937e5aaSOliver Metz * partitioned. This bit will be lost every time after a reset 19281937e5aaSOliver Metz * or power off. This will affect erase size. 1929e6f99a56SLei Wen */ 19308a0cf490SDiego Santa Cruz if (part_completed) 19310c453bb7SDiego Santa Cruz has_parts = true; 19321937e5aaSOliver Metz if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) && 19330c453bb7SDiego Santa Cruz (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) 19340c453bb7SDiego Santa Cruz has_parts = true; 19350c453bb7SDiego Santa Cruz if (has_parts) { 19361937e5aaSOliver Metz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 19371937e5aaSOliver Metz EXT_CSD_ERASE_GROUP_DEF, 1); 19381937e5aaSOliver Metz 19391937e5aaSOliver Metz if (err) 19401937e5aaSOliver Metz return err; 1941021a8055SHannes Petermaier else 1942021a8055SHannes Petermaier ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 1943037dc0abSDiego Santa Cruz } 19441937e5aaSOliver Metz 1945037dc0abSDiego Santa Cruz if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) { 19461937e5aaSOliver Metz /* Read out group size from ext_csd */ 19470560db18SLei Wen mmc->erase_grp_size = 1948a4ff9f83SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 1949d7b29129SMarkus Niebel /* 1950d7b29129SMarkus Niebel * if high capacity and partition setting completed 1951d7b29129SMarkus Niebel * SEC_COUNT is valid even if it is smaller than 2 GiB 1952d7b29129SMarkus Niebel * JEDEC Standard JESD84-B45, 6.2.4 1953d7b29129SMarkus Niebel */ 19548a0cf490SDiego Santa Cruz if (mmc->high_capacity && part_completed) { 1955d7b29129SMarkus Niebel capacity = (ext_csd[EXT_CSD_SEC_CNT]) | 1956d7b29129SMarkus Niebel (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) | 1957d7b29129SMarkus Niebel (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) | 1958d7b29129SMarkus Niebel (ext_csd[EXT_CSD_SEC_CNT + 3] << 24); 1959d7b29129SMarkus Niebel capacity *= MMC_MAX_BLOCK_LEN; 1960d7b29129SMarkus Niebel mmc->capacity_user = capacity; 1961d7b29129SMarkus Niebel } 19628bfa195eSSimon Glass } else { 19631937e5aaSOliver Metz /* Calculate the group size from the csd value. */ 1964e6f99a56SLei Wen int erase_gsz, erase_gmul; 1965e6f99a56SLei Wen erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; 1966e6f99a56SLei Wen erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; 1967e6f99a56SLei Wen mmc->erase_grp_size = (erase_gsz + 1) 1968e6f99a56SLei Wen * (erase_gmul + 1); 1969e6f99a56SLei Wen } 1970037dc0abSDiego Santa Cruz 1971037dc0abSDiego Santa Cruz mmc->hc_wp_grp_size = 1024 1972037dc0abSDiego Santa Cruz * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 1973037dc0abSDiego Santa Cruz * ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 19749e41a00bSDiego Santa Cruz 19759e41a00bSDiego Santa Cruz mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 1976f866a46dSStephen Warren } 1977f866a46dSStephen Warren 1978c40fdca6SSimon Glass err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart); 1979f866a46dSStephen Warren if (err) 1980f866a46dSStephen Warren return err; 1981d23e2c09SSukumar Ghorai 1982272cc70bSAndy Fleming if (IS_SD(mmc)) 1983272cc70bSAndy Fleming err = sd_change_freq(mmc); 1984272cc70bSAndy Fleming else 1985272cc70bSAndy Fleming err = mmc_change_freq(mmc); 1986272cc70bSAndy Fleming 1987272cc70bSAndy Fleming if (err) 1988272cc70bSAndy Fleming return err; 1989272cc70bSAndy Fleming 1990272cc70bSAndy Fleming /* Restrict card's capabilities by what the host can do */ 199193bfd616SPantelis Antoniou mmc->card_caps &= mmc->cfg->host_caps; 1992272cc70bSAndy Fleming 1993272cc70bSAndy Fleming if (IS_SD(mmc)) { 1994272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_4BIT) { 1995272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 1996272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1997272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1998272cc70bSAndy Fleming 1999272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2000272cc70bSAndy Fleming if (err) 2001272cc70bSAndy Fleming return err; 2002272cc70bSAndy Fleming 2003272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; 2004272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 2005272cc70bSAndy Fleming cmd.cmdarg = 2; 2006272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2007272cc70bSAndy Fleming if (err) 2008272cc70bSAndy Fleming return err; 2009272cc70bSAndy Fleming 2010272cc70bSAndy Fleming mmc_set_bus_width(mmc, 4); 2011272cc70bSAndy Fleming } 2012272cc70bSAndy Fleming 20133697e599SPeng Fan err = sd_read_ssr(mmc); 20143697e599SPeng Fan if (err) 20153697e599SPeng Fan return err; 20163697e599SPeng Fan 2017272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS) 2018fe414819SJason Zhu tran_speed = MMC_HIGH_52_MAX_DTR; 2019272cc70bSAndy Fleming else 2020fe414819SJason Zhu tran_speed = MMC_HIGH_26_MAX_DTR; 2021ad5fd922SJaehoon Chung 20223e3ff0acSZiyuan Xu mmc_set_clock(mmc, tran_speed); 202349dba033SZiyuan Xu } 2024272cc70bSAndy Fleming 20255af8f45cSAndrew Gabbasov /* Fix the block length for DDR mode */ 202649dba033SZiyuan Xu if (mmc_card_ddr(mmc)) { 20275af8f45cSAndrew Gabbasov mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 20285af8f45cSAndrew Gabbasov mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 20295af8f45cSAndrew Gabbasov } 20305af8f45cSAndrew Gabbasov 2031272cc70bSAndy Fleming /* fill in device description */ 2032c40fdca6SSimon Glass bdesc = mmc_get_blk_desc(mmc); 2033c40fdca6SSimon Glass bdesc->lun = 0; 2034c40fdca6SSimon Glass bdesc->hwpart = 0; 2035c40fdca6SSimon Glass bdesc->type = 0; 2036c40fdca6SSimon Glass bdesc->blksz = mmc->read_bl_len; 2037c40fdca6SSimon Glass bdesc->log2blksz = LOG2(bdesc->blksz); 2038c40fdca6SSimon Glass bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len); 2039fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \ 2040fc011f64SSjoerd Simons (defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \ 2041fc011f64SSjoerd Simons !defined(CONFIG_USE_TINY_PRINTF)) 2042c40fdca6SSimon Glass sprintf(bdesc->vendor, "Man %06x Snr %04x%04x", 2043babce5f6STaylor Hutt mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), 2044babce5f6STaylor Hutt (mmc->cid[3] >> 16) & 0xffff); 2045c40fdca6SSimon Glass sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff, 20460b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 2047babce5f6STaylor Hutt (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff, 2048babce5f6STaylor Hutt (mmc->cid[2] >> 24) & 0xff); 2049c40fdca6SSimon Glass sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf, 2050babce5f6STaylor Hutt (mmc->cid[2] >> 16) & 0xf); 205156196826SPaul Burton #else 2052c40fdca6SSimon Glass bdesc->vendor[0] = 0; 2053c40fdca6SSimon Glass bdesc->product[0] = 0; 2054c40fdca6SSimon Glass bdesc->revision[0] = 0; 205556196826SPaul Burton #endif 2056122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT) 2057c40fdca6SSimon Glass part_init(bdesc); 2058122efd43SMikhail Kshevetskiy #endif 2059272cc70bSAndy Fleming 2060272cc70bSAndy Fleming return 0; 2061272cc70bSAndy Fleming } 2062272cc70bSAndy Fleming 2063479fbf72SJason Zhu #ifndef CONFIG_MMC_USE_PRE_CONFIG 2064fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc) 2065272cc70bSAndy Fleming { 2066272cc70bSAndy Fleming struct mmc_cmd cmd; 2067272cc70bSAndy Fleming int err; 2068272cc70bSAndy Fleming 2069272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND; 2070272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ 207193bfd616SPantelis Antoniou cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa; 2072272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7; 2073272cc70bSAndy Fleming 2074272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2075272cc70bSAndy Fleming 2076272cc70bSAndy Fleming if (err) 2077272cc70bSAndy Fleming return err; 2078272cc70bSAndy Fleming 2079998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa) 2080915ffa52SJaehoon Chung return -EOPNOTSUPP; 2081272cc70bSAndy Fleming else 2082272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 2083272cc70bSAndy Fleming 2084272cc70bSAndy Fleming return 0; 2085272cc70bSAndy Fleming } 2086479fbf72SJason Zhu #endif 2087272cc70bSAndy Fleming 2088c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 208995de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */ 209095de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void) 209195de9ab2SPaul Kocialkowski { 209295de9ab2SPaul Kocialkowski } 209305cbeb7cSSimon Glass #endif 209495de9ab2SPaul Kocialkowski 2095479fbf72SJason Zhu #ifndef CONFIG_MMC_USE_PRE_CONFIG 20962051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc) 20972051aefeSPeng Fan { 2098c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 209905cbeb7cSSimon Glass #if defined(CONFIG_DM_REGULATOR) && !defined(CONFIG_SPL_BUILD) 21002051aefeSPeng Fan struct udevice *vmmc_supply; 21012051aefeSPeng Fan int ret; 21022051aefeSPeng Fan 21032051aefeSPeng Fan ret = device_get_supply_regulator(mmc->dev, "vmmc-supply", 21042051aefeSPeng Fan &vmmc_supply); 21052051aefeSPeng Fan if (ret) { 2106288db7c7SJaehoon Chung debug("%s: No vmmc supply\n", mmc->dev->name); 21072051aefeSPeng Fan return 0; 21082051aefeSPeng Fan } 21092051aefeSPeng Fan 21102051aefeSPeng Fan ret = regulator_set_enable(vmmc_supply, true); 21112051aefeSPeng Fan if (ret) { 21122051aefeSPeng Fan puts("Error enabling VMMC supply\n"); 21132051aefeSPeng Fan return ret; 21142051aefeSPeng Fan } 21152051aefeSPeng Fan #endif 211605cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */ 211705cbeb7cSSimon Glass /* 211805cbeb7cSSimon Glass * Driver model should use a regulator, as above, rather than calling 211905cbeb7cSSimon Glass * out to board code. 212005cbeb7cSSimon Glass */ 212105cbeb7cSSimon Glass board_mmc_power_init(); 212205cbeb7cSSimon Glass #endif 21232051aefeSPeng Fan return 0; 21242051aefeSPeng Fan } 2125479fbf72SJason Zhu #endif 2126479fbf72SJason Zhu #ifdef CONFIG_MMC_USE_PRE_CONFIG 2127479fbf72SJason Zhu static int mmc_select_card(struct mmc *mmc, int n) 2128479fbf72SJason Zhu { 2129479fbf72SJason Zhu struct mmc_cmd cmd; 2130479fbf72SJason Zhu int err = 0; 21312051aefeSPeng Fan 2132479fbf72SJason Zhu memset(&cmd, 0, sizeof(struct mmc_cmd)); 2133479fbf72SJason Zhu if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 2134479fbf72SJason Zhu mmc->rca = n; 2135479fbf72SJason Zhu cmd.cmdidx = MMC_CMD_SELECT_CARD; 2136479fbf72SJason Zhu cmd.resp_type = MMC_RSP_R1; 2137479fbf72SJason Zhu cmd.cmdarg = mmc->rca << 16; 2138479fbf72SJason Zhu err = mmc_send_cmd(mmc, &cmd, NULL); 2139479fbf72SJason Zhu } 2140479fbf72SJason Zhu 2141479fbf72SJason Zhu return err; 2142479fbf72SJason Zhu } 2143479fbf72SJason Zhu 2144479fbf72SJason Zhu int mmc_start_init(struct mmc *mmc) 2145479fbf72SJason Zhu { 2146479fbf72SJason Zhu /* 2147479fbf72SJason Zhu * We use the MMC config set by the bootrom. 2148479fbf72SJason Zhu * So it is no need to reset the eMMC device. 2149479fbf72SJason Zhu */ 2150479fbf72SJason Zhu mmc_set_bus_width(mmc, 8); 2151479fbf72SJason Zhu mmc_set_clock(mmc, 1); 2152479fbf72SJason Zhu mmc_set_timing(mmc, MMC_TIMING_LEGACY); 2153479fbf72SJason Zhu /* Send cmd7 to return stand-by state*/ 2154479fbf72SJason Zhu mmc_select_card(mmc, 0); 2155479fbf72SJason Zhu mmc->version = MMC_VERSION_UNKNOWN; 2156479fbf72SJason Zhu mmc->high_capacity = 1; 2157479fbf72SJason Zhu /* 2158479fbf72SJason Zhu * The RCA is set to 2 by rockchip bootrom, use the default 2159479fbf72SJason Zhu * value here. 2160479fbf72SJason Zhu */ 2161479fbf72SJason Zhu #ifdef CONFIG_ARCH_ROCKCHIP 2162479fbf72SJason Zhu mmc->rca = 2; 2163479fbf72SJason Zhu #else 2164479fbf72SJason Zhu mmc->rca = 1; 2165479fbf72SJason Zhu #endif 2166479fbf72SJason Zhu return 0; 2167479fbf72SJason Zhu } 2168479fbf72SJason Zhu #else 2169e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc) 2170272cc70bSAndy Fleming { 21718ca51e51SSimon Glass bool no_card; 2172afd5932bSMacpaul Lin int err; 2173272cc70bSAndy Fleming 2174ab769f22SPantelis Antoniou /* we pretend there's no card when init is NULL */ 21758ca51e51SSimon Glass no_card = mmc_getcd(mmc) == 0; 2176e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 21778ca51e51SSimon Glass no_card = no_card || (mmc->cfg->ops->init == NULL); 21788ca51e51SSimon Glass #endif 21798ca51e51SSimon Glass if (no_card) { 218048972d90SThierry Reding mmc->has_init = 0; 218156196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 218248972d90SThierry Reding printf("MMC: no card present\n"); 218356196826SPaul Burton #endif 2184915ffa52SJaehoon Chung return -ENOMEDIUM; 218548972d90SThierry Reding } 218648972d90SThierry Reding 2187bc897b1dSLei Wen if (mmc->has_init) 2188bc897b1dSLei Wen return 0; 2189bc897b1dSLei Wen 21905a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 21915a8dbdc6SYangbo Lu mmc_adapter_card_type_ident(); 21925a8dbdc6SYangbo Lu #endif 21932051aefeSPeng Fan err = mmc_power_init(mmc); 21942051aefeSPeng Fan if (err) 21952051aefeSPeng Fan return err; 219695de9ab2SPaul Kocialkowski 2197e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 21988ca51e51SSimon Glass /* The device has already been probed ready for use */ 21998ca51e51SSimon Glass #else 2200ab769f22SPantelis Antoniou /* made sure it's not NULL earlier */ 220193bfd616SPantelis Antoniou err = mmc->cfg->ops->init(mmc); 2202272cc70bSAndy Fleming if (err) 2203272cc70bSAndy Fleming return err; 22048ca51e51SSimon Glass #endif 2205b86b85e2SIlya Yanok mmc_set_bus_width(mmc, 1); 2206b86b85e2SIlya Yanok mmc_set_clock(mmc, 1); 220781db2d36SZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_LEGACY); 2208b86b85e2SIlya Yanok 2209272cc70bSAndy Fleming /* Reset the Card */ 2210272cc70bSAndy Fleming err = mmc_go_idle(mmc); 2211272cc70bSAndy Fleming 2212272cc70bSAndy Fleming if (err) 2213272cc70bSAndy Fleming return err; 2214272cc70bSAndy Fleming 2215bc897b1dSLei Wen /* The internal partition reset to user partition(0) at every CMD0*/ 2216c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->hwpart = 0; 2217bc897b1dSLei Wen 2218272cc70bSAndy Fleming /* Test for SD version 2 */ 2219272cc70bSAndy Fleming err = mmc_send_if_cond(mmc); 2220272cc70bSAndy Fleming 2221272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */ 2222272cc70bSAndy Fleming err = sd_send_op_cond(mmc); 2223272cc70bSAndy Fleming 2224272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */ 2225915ffa52SJaehoon Chung if (err == -ETIMEDOUT) { 2226272cc70bSAndy Fleming err = mmc_send_op_cond(mmc); 2227272cc70bSAndy Fleming 2228bd47c135SAndrew Gabbasov if (err) { 222956196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2230272cc70bSAndy Fleming printf("Card did not respond to voltage select!\n"); 223156196826SPaul Burton #endif 2232915ffa52SJaehoon Chung return -EOPNOTSUPP; 2233272cc70bSAndy Fleming } 2234272cc70bSAndy Fleming } 2235272cc70bSAndy Fleming 2236bd47c135SAndrew Gabbasov if (!err) 2237e9550449SChe-Liang Chiou mmc->init_in_progress = 1; 2238e9550449SChe-Liang Chiou 2239e9550449SChe-Liang Chiou return err; 2240e9550449SChe-Liang Chiou } 2241479fbf72SJason Zhu #endif 2242e9550449SChe-Liang Chiou 2243e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc) 2244e9550449SChe-Liang Chiou { 2245e9550449SChe-Liang Chiou int err = 0; 2246e9550449SChe-Liang Chiou 2247bd47c135SAndrew Gabbasov mmc->init_in_progress = 0; 2248e9550449SChe-Liang Chiou if (mmc->op_cond_pending) 2249e9550449SChe-Liang Chiou err = mmc_complete_op_cond(mmc); 2250e9550449SChe-Liang Chiou 2251e9550449SChe-Liang Chiou if (!err) 2252bc897b1dSLei Wen err = mmc_startup(mmc); 2253bc897b1dSLei Wen if (err) 2254bc897b1dSLei Wen mmc->has_init = 0; 2255bc897b1dSLei Wen else 2256bc897b1dSLei Wen mmc->has_init = 1; 2257e9550449SChe-Liang Chiou return err; 2258e9550449SChe-Liang Chiou } 2259e9550449SChe-Liang Chiou 2260e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc) 2261e9550449SChe-Liang Chiou { 2262bd47c135SAndrew Gabbasov int err = 0; 2263ce9eca94SMarek Vasut __maybe_unused unsigned start; 2264c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 226533fb211dSSimon Glass struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev); 2266e9550449SChe-Liang Chiou 226733fb211dSSimon Glass upriv->mmc = mmc; 226833fb211dSSimon Glass #endif 2269e9550449SChe-Liang Chiou if (mmc->has_init) 2270e9550449SChe-Liang Chiou return 0; 2271d803fea5SMateusz Zalega 2272d803fea5SMateusz Zalega start = get_timer(0); 2273d803fea5SMateusz Zalega 2274e9550449SChe-Liang Chiou if (!mmc->init_in_progress) 2275e9550449SChe-Liang Chiou err = mmc_start_init(mmc); 2276e9550449SChe-Liang Chiou 2277bd47c135SAndrew Gabbasov if (!err) 2278e9550449SChe-Liang Chiou err = mmc_complete_init(mmc); 2279919b4858SJagan Teki if (err) 2280919b4858SJagan Teki printf("%s: %d, time %lu\n", __func__, err, get_timer(start)); 2281919b4858SJagan Teki 2282bc897b1dSLei Wen return err; 2283272cc70bSAndy Fleming } 2284272cc70bSAndy Fleming 2285ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val) 2286ab71188cSMarkus Niebel { 2287ab71188cSMarkus Niebel mmc->dsr = val; 2288ab71188cSMarkus Niebel return 0; 2289ab71188cSMarkus Niebel } 2290ab71188cSMarkus Niebel 2291cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */ 2292cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis) 2293272cc70bSAndy Fleming { 2294272cc70bSAndy Fleming return -1; 2295272cc70bSAndy Fleming } 2296272cc70bSAndy Fleming 2297cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */ 2298cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis) 2299cee9ab7cSJeroen Hofstee { 2300cee9ab7cSJeroen Hofstee return -1; 2301cee9ab7cSJeroen Hofstee } 2302272cc70bSAndy Fleming 2303e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit) 2304e9550449SChe-Liang Chiou { 2305e9550449SChe-Liang Chiou mmc->preinit = preinit; 2306e9550449SChe-Liang Chiou } 2307e9550449SChe-Liang Chiou 2308c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD) 23098e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 23108e3332e2SSjoerd Simons { 23118e3332e2SSjoerd Simons return 0; 23128e3332e2SSjoerd Simons } 2313c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC) 23148e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 23158e3332e2SSjoerd Simons { 23164a1db6d8SSimon Glass int ret, i; 23178e3332e2SSjoerd Simons struct uclass *uc; 23184a1db6d8SSimon Glass struct udevice *dev; 23198e3332e2SSjoerd Simons 23208e3332e2SSjoerd Simons ret = uclass_get(UCLASS_MMC, &uc); 23218e3332e2SSjoerd Simons if (ret) 23228e3332e2SSjoerd Simons return ret; 23238e3332e2SSjoerd Simons 23244a1db6d8SSimon Glass /* 23254a1db6d8SSimon Glass * Try to add them in sequence order. Really with driver model we 23264a1db6d8SSimon Glass * should allow holes, but the current MMC list does not allow that. 23274a1db6d8SSimon Glass * So if we request 0, 1, 3 we will get 0, 1, 2. 23284a1db6d8SSimon Glass */ 23294a1db6d8SSimon Glass for (i = 0; ; i++) { 23304a1db6d8SSimon Glass ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev); 23314a1db6d8SSimon Glass if (ret == -ENODEV) 23324a1db6d8SSimon Glass break; 23334a1db6d8SSimon Glass } 23344a1db6d8SSimon Glass uclass_foreach_dev(dev, uc) { 23354a1db6d8SSimon Glass ret = device_probe(dev); 23368e3332e2SSjoerd Simons if (ret) 23374a1db6d8SSimon Glass printf("%s - probe failed: %d\n", dev->name, ret); 23388e3332e2SSjoerd Simons } 23398e3332e2SSjoerd Simons 23408e3332e2SSjoerd Simons return 0; 23418e3332e2SSjoerd Simons } 23428e3332e2SSjoerd Simons #else 23438e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 23448e3332e2SSjoerd Simons { 23458e3332e2SSjoerd Simons if (board_mmc_init(bis) < 0) 23468e3332e2SSjoerd Simons cpu_mmc_init(bis); 23478e3332e2SSjoerd Simons 23488e3332e2SSjoerd Simons return 0; 23498e3332e2SSjoerd Simons } 23508e3332e2SSjoerd Simons #endif 2351e9550449SChe-Liang Chiou 2352272cc70bSAndy Fleming int mmc_initialize(bd_t *bis) 2353272cc70bSAndy Fleming { 23541b26bab1SDaniel Kochmański static int initialized = 0; 23558e3332e2SSjoerd Simons int ret; 23561b26bab1SDaniel Kochmański if (initialized) /* Avoid initializing mmc multiple times */ 23571b26bab1SDaniel Kochmański return 0; 23581b26bab1SDaniel Kochmański initialized = 1; 23591b26bab1SDaniel Kochmański 2360c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK) 2361b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY) 2362c40fdca6SSimon Glass mmc_list_init(); 2363c40fdca6SSimon Glass #endif 2364b5b838f1SMarek Vasut #endif 23658e3332e2SSjoerd Simons ret = mmc_probe(bis); 23668e3332e2SSjoerd Simons if (ret) 23678e3332e2SSjoerd Simons return ret; 2368272cc70bSAndy Fleming 2369bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD 2370272cc70bSAndy Fleming print_mmc_devices(','); 2371bb0dc108SYing Zhang #endif 2372272cc70bSAndy Fleming 2373c40fdca6SSimon Glass mmc_do_preinit(); 2374272cc70bSAndy Fleming return 0; 2375272cc70bSAndy Fleming } 2376cd3d4880STomas Melin 2377cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE 2378cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc) 2379cd3d4880STomas Melin { 2380cd3d4880STomas Melin int err; 2381cd3d4880STomas Melin ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 2382cd3d4880STomas Melin 2383cd3d4880STomas Melin err = mmc_send_ext_csd(mmc, ext_csd); 2384cd3d4880STomas Melin if (err) { 2385cd3d4880STomas Melin puts("Could not get ext_csd register values\n"); 2386cd3d4880STomas Melin return err; 2387cd3d4880STomas Melin } 2388cd3d4880STomas Melin 2389cd3d4880STomas Melin if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) { 2390cd3d4880STomas Melin puts("Background operations not supported on device\n"); 2391cd3d4880STomas Melin return -EMEDIUMTYPE; 2392cd3d4880STomas Melin } 2393cd3d4880STomas Melin 2394cd3d4880STomas Melin if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) { 2395cd3d4880STomas Melin puts("Background operations already enabled\n"); 2396cd3d4880STomas Melin return 0; 2397cd3d4880STomas Melin } 2398cd3d4880STomas Melin 2399cd3d4880STomas Melin err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1); 2400cd3d4880STomas Melin if (err) { 2401cd3d4880STomas Melin puts("Failed to enable manual background operations\n"); 2402cd3d4880STomas Melin return err; 2403cd3d4880STomas Melin } 2404cd3d4880STomas Melin 2405cd3d4880STomas Melin puts("Enabled manual background operations\n"); 2406cd3d4880STomas Melin 2407cd3d4880STomas Melin return 0; 2408cd3d4880STomas Melin } 2409cd3d4880STomas Melin #endif 2410