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 665a95f7caaSJason Zhu #ifdef CONFIG_MMC_USE_PRE_CONFIG 666a95f7caaSJason 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; 673a95f7caaSJason 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); 905*e09ef32eSYifeng Zhao if (err) { 906*e09ef32eSYifeng Zhao cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; 907*e09ef32eSYifeng Zhao cmd.cmdarg = 0; 908*e09ef32eSYifeng Zhao cmd.resp_type = MMC_RSP_R1b; 909*e09ef32eSYifeng Zhao mmc_send_cmd(mmc, &cmd, NULL); 91049dba033SZiyuan Xu goto out; 911*e09ef32eSYifeng Zhao } 91249dba033SZiyuan Xu if (memcmp(data_buf, tuning_block_pattern, size)) 91349dba033SZiyuan Xu err = -EIO; 91449dba033SZiyuan Xu out: 91549dba033SZiyuan Xu free(data_buf); 91649dba033SZiyuan Xu return err; 91749dba033SZiyuan Xu } 91849dba033SZiyuan Xu 91949dba033SZiyuan Xu static int mmc_execute_tuning(struct mmc *mmc) 92049dba033SZiyuan Xu { 92149dba033SZiyuan Xu #ifdef CONFIG_DM_MMC 92249dba033SZiyuan Xu struct dm_mmc_ops *ops = mmc_get_ops(mmc->dev); 92349dba033SZiyuan Xu #endif 92449dba033SZiyuan Xu u32 opcode; 92549dba033SZiyuan Xu 92649dba033SZiyuan Xu if (IS_SD(mmc)) 92749dba033SZiyuan Xu opcode = MMC_SEND_TUNING_BLOCK; 92849dba033SZiyuan Xu else 92949dba033SZiyuan Xu opcode = MMC_SEND_TUNING_BLOCK_HS200; 93049dba033SZiyuan Xu 93149dba033SZiyuan Xu #ifndef CONFIG_DM_MMC 93249dba033SZiyuan Xu if (mmc->cfg->ops->execute_tuning) { 93349dba033SZiyuan Xu return mmc->cfg->ops->execute_tuning(mmc, opcode); 93449dba033SZiyuan Xu #else 93549dba033SZiyuan Xu if (ops->execute_tuning) { 93649dba033SZiyuan Xu return ops->execute_tuning(mmc->dev, opcode); 93749dba033SZiyuan Xu #endif 93849dba033SZiyuan Xu } else { 93949dba033SZiyuan Xu debug("Tuning feature required for HS200 mode.\n"); 94049dba033SZiyuan Xu return -EIO; 94149dba033SZiyuan Xu } 94249dba033SZiyuan Xu } 94349dba033SZiyuan Xu 94449dba033SZiyuan Xu static int mmc_hs200_tuning(struct mmc *mmc) 94549dba033SZiyuan Xu { 94649dba033SZiyuan Xu return mmc_execute_tuning(mmc); 94749dba033SZiyuan Xu } 94849dba033SZiyuan Xu 949699945cbSJason Zhu #else 950699945cbSJason Zhu int mmc_send_tuning(struct mmc *mmc, u32 opcode) { return 0; } 951699945cbSJason Zhu int mmc_execute_tuning(struct mmc *mmc) { return 0; } 952699945cbSJason Zhu static int mmc_hs200_tuning(struct mmc *mmc) { return 0; } 953699945cbSJason Zhu #endif 954699945cbSJason Zhu 955e61cd3d7SZiyuan Xu static int mmc_select_hs(struct mmc *mmc) 956e61cd3d7SZiyuan Xu { 957e61cd3d7SZiyuan Xu int ret; 958e61cd3d7SZiyuan Xu 959e61cd3d7SZiyuan Xu ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 960e61cd3d7SZiyuan Xu EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS); 961e61cd3d7SZiyuan Xu 962e61cd3d7SZiyuan Xu if (!ret) 963e61cd3d7SZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_MMC_HS); 964e61cd3d7SZiyuan Xu 965e61cd3d7SZiyuan Xu return ret; 966e61cd3d7SZiyuan Xu } 967e61cd3d7SZiyuan Xu 9685545757fSZiyuan Xu static int mmc_select_hs_ddr(struct mmc *mmc) 9695545757fSZiyuan Xu { 9705545757fSZiyuan Xu u32 ext_csd_bits; 9715545757fSZiyuan Xu int err = 0; 9725545757fSZiyuan Xu 9735545757fSZiyuan Xu if (mmc->bus_width == MMC_BUS_WIDTH_1BIT) 9745545757fSZiyuan Xu return 0; 9755545757fSZiyuan Xu 9765545757fSZiyuan Xu ext_csd_bits = (mmc->bus_width == MMC_BUS_WIDTH_8BIT) ? 9775545757fSZiyuan Xu EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4; 9785545757fSZiyuan Xu 9795545757fSZiyuan Xu err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 9805545757fSZiyuan Xu EXT_CSD_BUS_WIDTH, ext_csd_bits); 9815545757fSZiyuan Xu if (err) 9825545757fSZiyuan Xu return err; 9835545757fSZiyuan Xu 9845545757fSZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_MMC_DDR52); 9855545757fSZiyuan Xu 9865545757fSZiyuan Xu return 0; 9875545757fSZiyuan Xu } 9885545757fSZiyuan Xu 989699945cbSJason Zhu #ifndef CONFIG_MMC_SIMPLE 99049dba033SZiyuan Xu static int mmc_select_hs200(struct mmc *mmc) 99149dba033SZiyuan Xu { 99249dba033SZiyuan Xu int ret; 99349dba033SZiyuan Xu 99449dba033SZiyuan Xu /* 99549dba033SZiyuan Xu * Set the bus width(4 or 8) with host's support and 99649dba033SZiyuan Xu * switch to HS200 mode if bus width is set successfully. 99749dba033SZiyuan Xu */ 99849dba033SZiyuan Xu ret = mmc_select_bus_width(mmc); 99949dba033SZiyuan Xu 100049dba033SZiyuan Xu if (ret > 0) { 100149dba033SZiyuan Xu ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 100249dba033SZiyuan Xu EXT_CSD_HS_TIMING, 100349dba033SZiyuan Xu EXT_CSD_TIMING_HS200, false); 100449dba033SZiyuan Xu 100549dba033SZiyuan Xu if (ret) 100649dba033SZiyuan Xu return ret; 100749dba033SZiyuan Xu 100849dba033SZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_MMC_HS200); 100949dba033SZiyuan Xu } 101049dba033SZiyuan Xu 101149dba033SZiyuan Xu return ret; 101249dba033SZiyuan Xu } 101349dba033SZiyuan Xu 101499685543SYifeng Zhao static int mmc_switch_to_hs400(struct mmc *mmc) 101599685543SYifeng Zhao { 101699685543SYifeng Zhao u8 val, fixed_drv_type, card_drv_type, drive_strength; 101799685543SYifeng Zhao 101899685543SYifeng Zhao fixed_drv_type = mmc->cfg->fixed_drv_type; 101999685543SYifeng Zhao card_drv_type = mmc->raw_driver_strength | mmc_driver_type_mask(0); 102099685543SYifeng Zhao drive_strength = (card_drv_type & mmc_driver_type_mask(fixed_drv_type)) 102199685543SYifeng Zhao ? fixed_drv_type : 0; 102299685543SYifeng Zhao val = EXT_CSD_TIMING_HS400 | drive_strength << EXT_CSD_DRV_STR_SHIFT; 102399685543SYifeng Zhao 102499685543SYifeng Zhao return __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, val, false); 102599685543SYifeng Zhao } 102699685543SYifeng Zhao 1027b673f29aSZiyuan Xu static int mmc_select_hs400(struct mmc *mmc) 1028b673f29aSZiyuan Xu { 1029b673f29aSZiyuan Xu int ret; 1030b673f29aSZiyuan Xu 1031b673f29aSZiyuan Xu /* Switch card to HS mode */ 1032b673f29aSZiyuan Xu ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1033b673f29aSZiyuan Xu EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS, false); 1034b673f29aSZiyuan Xu if (ret) 1035b673f29aSZiyuan Xu return ret; 1036b673f29aSZiyuan Xu 1037b673f29aSZiyuan Xu /* Set host controller to HS timing */ 1038b673f29aSZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_MMC_HS); 1039b673f29aSZiyuan Xu 104013669fc5SYifeng Zhao /* Reduce frequency to HS frequency */ 104113669fc5SYifeng Zhao mmc_set_clock(mmc, MMC_HIGH_52_MAX_DTR); 104213669fc5SYifeng Zhao 1043b673f29aSZiyuan Xu ret = mmc_send_status(mmc, 1000); 1044b673f29aSZiyuan Xu if (ret) 1045b673f29aSZiyuan Xu return ret; 1046b673f29aSZiyuan Xu 1047b673f29aSZiyuan Xu /* Switch card to DDR */ 1048b673f29aSZiyuan Xu ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1049b673f29aSZiyuan Xu EXT_CSD_BUS_WIDTH, 1050b673f29aSZiyuan Xu EXT_CSD_DDR_BUS_WIDTH_8); 1051b673f29aSZiyuan Xu if (ret) 1052b673f29aSZiyuan Xu return ret; 1053b673f29aSZiyuan Xu 1054b673f29aSZiyuan Xu /* Switch card to HS400 */ 105599685543SYifeng Zhao ret = mmc_switch_to_hs400(mmc); 1056b673f29aSZiyuan Xu if (ret) 1057b673f29aSZiyuan Xu return ret; 1058b673f29aSZiyuan Xu 1059b673f29aSZiyuan Xu /* Set host controller to HS400 timing and frequency */ 1060b673f29aSZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_MMC_HS400); 1061b673f29aSZiyuan Xu 1062b673f29aSZiyuan Xu return ret; 1063b673f29aSZiyuan Xu } 106413669fc5SYifeng Zhao 106513669fc5SYifeng Zhao static int mmc_select_hs400es(struct mmc *mmc) 106613669fc5SYifeng Zhao { 106713669fc5SYifeng Zhao int err; 106813669fc5SYifeng Zhao 106913669fc5SYifeng Zhao /* Switch card to HS mode */ 107013669fc5SYifeng Zhao err = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 107113669fc5SYifeng Zhao EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS, false); 107213669fc5SYifeng Zhao if (err) 107313669fc5SYifeng Zhao return err; 107413669fc5SYifeng Zhao 107513669fc5SYifeng Zhao /* Set host controller to HS timing */ 107613669fc5SYifeng Zhao mmc_set_timing(mmc, MMC_TIMING_MMC_HS); 107713669fc5SYifeng Zhao 107813669fc5SYifeng Zhao err = mmc_send_status(mmc, 1000); 107913669fc5SYifeng Zhao if (err) 108013669fc5SYifeng Zhao return err; 108113669fc5SYifeng Zhao 108213669fc5SYifeng Zhao mmc_set_clock(mmc, MMC_HIGH_52_MAX_DTR); 108313669fc5SYifeng Zhao 108413669fc5SYifeng Zhao err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, 108513669fc5SYifeng Zhao EXT_CSD_DDR_BUS_WIDTH_8 | 108613669fc5SYifeng Zhao EXT_CSD_BUS_WIDTH_STROBE); 108713669fc5SYifeng Zhao if (err) { 108813669fc5SYifeng Zhao printf("switch to bus width for hs400 failed\n"); 108913669fc5SYifeng Zhao return err; 109013669fc5SYifeng Zhao } 109113669fc5SYifeng Zhao 109213669fc5SYifeng Zhao /* Switch card to HS400 */ 109399685543SYifeng Zhao err = mmc_switch_to_hs400(mmc); 109413669fc5SYifeng Zhao if (err) 109513669fc5SYifeng Zhao return err; 109613669fc5SYifeng Zhao 109713669fc5SYifeng Zhao /* Set host controller to HS400 timing and frequency */ 109813669fc5SYifeng Zhao mmc_set_timing(mmc, MMC_TIMING_MMC_HS400ES); 109913669fc5SYifeng Zhao 110013669fc5SYifeng Zhao return mmc_set_enhanced_strobe(mmc); 110113669fc5SYifeng Zhao } 1102699945cbSJason Zhu #else 1103699945cbSJason Zhu static int mmc_select_hs200(struct mmc *mmc) { return 0; } 1104699945cbSJason Zhu static int mmc_select_hs400(struct mmc *mmc) { return 0; } 110513669fc5SYifeng Zhao static int mmc_select_hs400es(struct mmc *mmc) { return 0; } 1106699945cbSJason Zhu #endif 1107b673f29aSZiyuan Xu 1108227f658eSZiyuan Xu static u32 mmc_select_card_type(struct mmc *mmc, u8 *ext_csd) 1109227f658eSZiyuan Xu { 1110227f658eSZiyuan Xu u8 card_type; 1111227f658eSZiyuan Xu u32 host_caps, avail_type = 0; 1112227f658eSZiyuan Xu 1113227f658eSZiyuan Xu card_type = ext_csd[EXT_CSD_CARD_TYPE]; 1114227f658eSZiyuan Xu host_caps = mmc->cfg->host_caps; 1115227f658eSZiyuan Xu 1116227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS) && 1117227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_26)) 1118227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_26; 1119227f658eSZiyuan Xu 1120227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS) && 1121227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_52)) 1122227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_52; 1123227f658eSZiyuan Xu 1124227f658eSZiyuan Xu /* 1125227f658eSZiyuan Xu * For the moment, u-boot doesn't support signal voltage 1126227f658eSZiyuan Xu * switch, therefor we assume that host support ddr52 1127227f658eSZiyuan Xu * at 1.8v or 3.3v I/O(1.2v I/O not supported, hs200 and 1128227f658eSZiyuan Xu * hs400 are the same). 1129227f658eSZiyuan Xu */ 1130227f658eSZiyuan Xu if ((host_caps & MMC_MODE_DDR_52MHz) && 1131227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)) 1132227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V; 1133227f658eSZiyuan Xu 1134227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS200) && 1135227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_HS200_1_8V)) 1136227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V; 1137227f658eSZiyuan Xu 1138227f658eSZiyuan Xu /* 1139227f658eSZiyuan Xu * If host can support HS400, it means that host can also 1140227f658eSZiyuan Xu * support HS200. 1141227f658eSZiyuan Xu */ 1142227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS400) && 1143227f658eSZiyuan Xu (host_caps & MMC_MODE_8BIT) && 1144227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_HS400_1_8V)) 1145227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V | 1146227f658eSZiyuan Xu EXT_CSD_CARD_TYPE_HS400_1_8V; 1147227f658eSZiyuan Xu 1148227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS400ES) && 1149227f658eSZiyuan Xu (host_caps & MMC_MODE_8BIT) && 1150227f658eSZiyuan Xu ext_csd[EXT_CSD_STROBE_SUPPORT] && 1151227f658eSZiyuan Xu (avail_type & EXT_CSD_CARD_TYPE_HS400_1_8V)) 1152227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V | 1153227f658eSZiyuan Xu EXT_CSD_CARD_TYPE_HS400_1_8V | 1154227f658eSZiyuan Xu EXT_CSD_CARD_TYPE_HS400ES; 1155227f658eSZiyuan Xu 1156227f658eSZiyuan Xu return avail_type; 1157227f658eSZiyuan Xu } 1158227f658eSZiyuan Xu 115949dba033SZiyuan Xu static void mmc_set_bus_speed(struct mmc *mmc, u8 avail_type) 116049dba033SZiyuan Xu { 116149dba033SZiyuan Xu int clock = 0; 116249dba033SZiyuan Xu 116349dba033SZiyuan Xu if (mmc_card_hs(mmc)) 116449dba033SZiyuan Xu clock = (avail_type & EXT_CSD_CARD_TYPE_52) ? 116549dba033SZiyuan Xu MMC_HIGH_52_MAX_DTR : MMC_HIGH_26_MAX_DTR; 116649dba033SZiyuan Xu else if (mmc_card_hs200(mmc) || 116749dba033SZiyuan Xu mmc_card_hs400(mmc) || 116849dba033SZiyuan Xu mmc_card_hs400es(mmc)) 116949dba033SZiyuan Xu clock = MMC_HS200_MAX_DTR; 117049dba033SZiyuan Xu 117149dba033SZiyuan Xu mmc_set_clock(mmc, clock); 117249dba033SZiyuan Xu } 117349dba033SZiyuan Xu 1174fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc) 1175272cc70bSAndy Fleming { 11768bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 1177227f658eSZiyuan Xu u32 avail_type; 1178272cc70bSAndy Fleming int err; 1179272cc70bSAndy Fleming 1180fc5b32fbSAndrew Gabbasov mmc->card_caps = 0; 1181272cc70bSAndy Fleming 1182d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 1183d52ebf10SThomas Chou return 0; 1184d52ebf10SThomas Chou 1185272cc70bSAndy Fleming /* Only version 4 supports high-speed */ 1186272cc70bSAndy Fleming if (mmc->version < MMC_VERSION_4) 1187272cc70bSAndy Fleming return 0; 1188272cc70bSAndy Fleming 1189fc5b32fbSAndrew Gabbasov mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; 1190fc5b32fbSAndrew Gabbasov 1191272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 1192272cc70bSAndy Fleming 1193272cc70bSAndy Fleming if (err) 1194272cc70bSAndy Fleming return err; 1195272cc70bSAndy Fleming 1196227f658eSZiyuan Xu avail_type = mmc_select_card_type(mmc, ext_csd); 1197272cc70bSAndy Fleming 119813669fc5SYifeng Zhao if (avail_type & EXT_CSD_CARD_TYPE_HS400ES) { 119913669fc5SYifeng Zhao err = mmc_select_bus_width(mmc); 120013669fc5SYifeng Zhao if (err > 0 && mmc->bus_width == MMC_BUS_WIDTH_8BIT) { 120113669fc5SYifeng Zhao err = mmc_select_hs400es(mmc); 120213669fc5SYifeng Zhao mmc_set_bus_speed(mmc, avail_type); 120313669fc5SYifeng Zhao if (!err) 120413669fc5SYifeng Zhao return err; 120513669fc5SYifeng Zhao } 120613669fc5SYifeng Zhao } 120713669fc5SYifeng Zhao 120849dba033SZiyuan Xu if (avail_type & EXT_CSD_CARD_TYPE_HS200) 120949dba033SZiyuan Xu err = mmc_select_hs200(mmc); 12101f250d0aSJason Zhu else if (avail_type & EXT_CSD_CARD_TYPE_HS) 1211e61cd3d7SZiyuan Xu err = mmc_select_hs(mmc); 1212227f658eSZiyuan Xu else 1213227f658eSZiyuan Xu err = -EINVAL; 1214272cc70bSAndy Fleming 1215272cc70bSAndy Fleming if (err) 1216a5e27b41SHeiko Schocher return err; 1217272cc70bSAndy Fleming 121849dba033SZiyuan Xu mmc_set_bus_speed(mmc, avail_type); 1219272cc70bSAndy Fleming 1220b673f29aSZiyuan Xu if (mmc_card_hs200(mmc)) { 122149dba033SZiyuan Xu err = mmc_hs200_tuning(mmc); 1222b673f29aSZiyuan Xu if (avail_type & EXT_CSD_CARD_TYPE_HS400 && 1223b673f29aSZiyuan Xu mmc->bus_width == MMC_BUS_WIDTH_8BIT) { 1224b673f29aSZiyuan Xu err = mmc_select_hs400(mmc); 1225b673f29aSZiyuan Xu mmc_set_bus_speed(mmc, avail_type); 1226b673f29aSZiyuan Xu } 1227b673f29aSZiyuan Xu } else if (!mmc_card_hs400es(mmc)) { 122849dba033SZiyuan Xu err = mmc_select_bus_width(mmc) > 0 ? 0 : err; 12295545757fSZiyuan Xu if (!err && avail_type & EXT_CSD_CARD_TYPE_DDR_52) 12305545757fSZiyuan Xu err = mmc_select_hs_ddr(mmc); 12315545757fSZiyuan Xu } 123249dba033SZiyuan Xu 1233272cc70bSAndy Fleming return err; 1234272cc70bSAndy Fleming } 1235272cc70bSAndy Fleming 1236f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num) 1237f866a46dSStephen Warren { 1238f866a46dSStephen Warren switch (part_num) { 1239f866a46dSStephen Warren case 0: 1240f866a46dSStephen Warren mmc->capacity = mmc->capacity_user; 1241f866a46dSStephen Warren break; 1242f866a46dSStephen Warren case 1: 1243f866a46dSStephen Warren case 2: 1244f866a46dSStephen Warren mmc->capacity = mmc->capacity_boot; 1245f866a46dSStephen Warren break; 1246f866a46dSStephen Warren case 3: 1247f866a46dSStephen Warren mmc->capacity = mmc->capacity_rpmb; 1248f866a46dSStephen Warren break; 1249f866a46dSStephen Warren case 4: 1250f866a46dSStephen Warren case 5: 1251f866a46dSStephen Warren case 6: 1252f866a46dSStephen Warren case 7: 1253f866a46dSStephen Warren mmc->capacity = mmc->capacity_gp[part_num - 4]; 1254f866a46dSStephen Warren break; 1255f866a46dSStephen Warren default: 1256f866a46dSStephen Warren return -1; 1257f866a46dSStephen Warren } 1258f866a46dSStephen Warren 1259c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len); 1260f866a46dSStephen Warren 1261f866a46dSStephen Warren return 0; 1262f866a46dSStephen Warren } 1263f866a46dSStephen Warren 12647dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num) 1265bc897b1dSLei Wen { 1266f866a46dSStephen Warren int ret; 1267bc897b1dSLei Wen 1268f866a46dSStephen Warren ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 1269bc897b1dSLei Wen (mmc->part_config & ~PART_ACCESS_MASK) 1270bc897b1dSLei Wen | (part_num & PART_ACCESS_MASK)); 1271f866a46dSStephen Warren 12726dc93e70SPeter Bigot /* 12736dc93e70SPeter Bigot * Set the capacity if the switch succeeded or was intended 12746dc93e70SPeter Bigot * to return to representing the raw device. 12756dc93e70SPeter Bigot */ 1276873cc1d7SStephen Warren if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) { 12776dc93e70SPeter Bigot ret = mmc_set_capacity(mmc, part_num); 1278fdbb139fSSimon Glass mmc_get_blk_desc(mmc)->hwpart = part_num; 1279873cc1d7SStephen Warren } 12806dc93e70SPeter Bigot 12816dc93e70SPeter Bigot return ret; 1282bc897b1dSLei Wen } 1283bc897b1dSLei Wen 1284ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc, 1285ac9da0e0SDiego Santa Cruz const struct mmc_hwpart_conf *conf, 1286ac9da0e0SDiego Santa Cruz enum mmc_hwpart_conf_mode mode) 1287ac9da0e0SDiego Santa Cruz { 1288ac9da0e0SDiego Santa Cruz u8 part_attrs = 0; 1289ac9da0e0SDiego Santa Cruz u32 enh_size_mult; 1290ac9da0e0SDiego Santa Cruz u32 enh_start_addr; 1291ac9da0e0SDiego Santa Cruz u32 gp_size_mult[4]; 1292ac9da0e0SDiego Santa Cruz u32 max_enh_size_mult; 1293ac9da0e0SDiego Santa Cruz u32 tot_enh_size_mult = 0; 12948dda5b0eSDiego Santa Cruz u8 wr_rel_set; 1295ac9da0e0SDiego Santa Cruz int i, pidx, err; 1296ac9da0e0SDiego Santa Cruz ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 1297ac9da0e0SDiego Santa Cruz 1298ac9da0e0SDiego Santa Cruz if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE) 1299ac9da0e0SDiego Santa Cruz return -EINVAL; 1300ac9da0e0SDiego Santa Cruz 1301ac9da0e0SDiego Santa Cruz if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) { 1302ac9da0e0SDiego Santa Cruz printf("eMMC >= 4.4 required for enhanced user data area\n"); 1303ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1304ac9da0e0SDiego Santa Cruz } 1305ac9da0e0SDiego Santa Cruz 1306ac9da0e0SDiego Santa Cruz if (!(mmc->part_support & PART_SUPPORT)) { 1307ac9da0e0SDiego Santa Cruz printf("Card does not support partitioning\n"); 1308ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1309ac9da0e0SDiego Santa Cruz } 1310ac9da0e0SDiego Santa Cruz 1311ac9da0e0SDiego Santa Cruz if (!mmc->hc_wp_grp_size) { 1312ac9da0e0SDiego Santa Cruz printf("Card does not define HC WP group size\n"); 1313ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1314ac9da0e0SDiego Santa Cruz } 1315ac9da0e0SDiego Santa Cruz 1316ac9da0e0SDiego Santa Cruz /* check partition alignment and total enhanced size */ 1317ac9da0e0SDiego Santa Cruz if (conf->user.enh_size) { 1318ac9da0e0SDiego Santa Cruz if (conf->user.enh_size % mmc->hc_wp_grp_size || 1319ac9da0e0SDiego Santa Cruz conf->user.enh_start % mmc->hc_wp_grp_size) { 1320ac9da0e0SDiego Santa Cruz printf("User data enhanced area not HC WP group " 1321ac9da0e0SDiego Santa Cruz "size aligned\n"); 1322ac9da0e0SDiego Santa Cruz return -EINVAL; 1323ac9da0e0SDiego Santa Cruz } 1324ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_USR; 1325ac9da0e0SDiego Santa Cruz enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size; 1326ac9da0e0SDiego Santa Cruz if (mmc->high_capacity) { 1327ac9da0e0SDiego Santa Cruz enh_start_addr = conf->user.enh_start; 1328ac9da0e0SDiego Santa Cruz } else { 1329ac9da0e0SDiego Santa Cruz enh_start_addr = (conf->user.enh_start << 9); 1330ac9da0e0SDiego Santa Cruz } 1331ac9da0e0SDiego Santa Cruz } else { 1332ac9da0e0SDiego Santa Cruz enh_size_mult = 0; 1333ac9da0e0SDiego Santa Cruz enh_start_addr = 0; 1334ac9da0e0SDiego Santa Cruz } 1335ac9da0e0SDiego Santa Cruz tot_enh_size_mult += enh_size_mult; 1336ac9da0e0SDiego Santa Cruz 1337ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 1338ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) { 1339ac9da0e0SDiego Santa Cruz printf("GP%i partition not HC WP group size " 1340ac9da0e0SDiego Santa Cruz "aligned\n", pidx+1); 1341ac9da0e0SDiego Santa Cruz return -EINVAL; 1342ac9da0e0SDiego Santa Cruz } 1343ac9da0e0SDiego Santa Cruz gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size; 1344ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) { 1345ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_GP(pidx); 1346ac9da0e0SDiego Santa Cruz tot_enh_size_mult += gp_size_mult[pidx]; 1347ac9da0e0SDiego Santa Cruz } 1348ac9da0e0SDiego Santa Cruz } 1349ac9da0e0SDiego Santa Cruz 1350ac9da0e0SDiego Santa Cruz if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) { 1351ac9da0e0SDiego Santa Cruz printf("Card does not support enhanced attribute\n"); 1352ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1353ac9da0e0SDiego Santa Cruz } 1354ac9da0e0SDiego Santa Cruz 1355ac9da0e0SDiego Santa Cruz err = mmc_send_ext_csd(mmc, ext_csd); 1356ac9da0e0SDiego Santa Cruz if (err) 1357ac9da0e0SDiego Santa Cruz return err; 1358ac9da0e0SDiego Santa Cruz 1359ac9da0e0SDiego Santa Cruz max_enh_size_mult = 1360ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) + 1361ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) + 1362ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]; 1363ac9da0e0SDiego Santa Cruz if (tot_enh_size_mult > max_enh_size_mult) { 1364ac9da0e0SDiego Santa Cruz printf("Total enhanced size exceeds maximum (%u > %u)\n", 1365ac9da0e0SDiego Santa Cruz tot_enh_size_mult, max_enh_size_mult); 1366ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1367ac9da0e0SDiego Santa Cruz } 1368ac9da0e0SDiego Santa Cruz 13698dda5b0eSDiego Santa Cruz /* The default value of EXT_CSD_WR_REL_SET is device 13708dda5b0eSDiego Santa Cruz * dependent, the values can only be changed if the 13718dda5b0eSDiego Santa Cruz * EXT_CSD_HS_CTRL_REL bit is set. The values can be 13728dda5b0eSDiego Santa Cruz * changed only once and before partitioning is completed. */ 13738dda5b0eSDiego Santa Cruz wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 13748dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_change) { 13758dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_set) 13768dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_USR; 13778dda5b0eSDiego Santa Cruz else 13788dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR; 13798dda5b0eSDiego Santa Cruz } 13808dda5b0eSDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 13818dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_change) { 13828dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_set) 13838dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx); 13848dda5b0eSDiego Santa Cruz else 13858dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx); 13868dda5b0eSDiego Santa Cruz } 13878dda5b0eSDiego Santa Cruz } 13888dda5b0eSDiego Santa Cruz 13898dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] && 13908dda5b0eSDiego Santa Cruz !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) { 13918dda5b0eSDiego Santa Cruz puts("Card does not support host controlled partition write " 13928dda5b0eSDiego Santa Cruz "reliability settings\n"); 13938dda5b0eSDiego Santa Cruz return -EMEDIUMTYPE; 13948dda5b0eSDiego Santa Cruz } 13958dda5b0eSDiego Santa Cruz 1396ac9da0e0SDiego Santa Cruz if (ext_csd[EXT_CSD_PARTITION_SETTING] & 1397ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED) { 1398ac9da0e0SDiego Santa Cruz printf("Card already partitioned\n"); 1399ac9da0e0SDiego Santa Cruz return -EPERM; 1400ac9da0e0SDiego Santa Cruz } 1401ac9da0e0SDiego Santa Cruz 1402ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_CHECK) 1403ac9da0e0SDiego Santa Cruz return 0; 1404ac9da0e0SDiego Santa Cruz 1405ac9da0e0SDiego Santa Cruz /* Partitioning requires high-capacity size definitions */ 1406ac9da0e0SDiego Santa Cruz if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) { 1407ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1408ac9da0e0SDiego Santa Cruz EXT_CSD_ERASE_GROUP_DEF, 1); 1409ac9da0e0SDiego Santa Cruz 1410ac9da0e0SDiego Santa Cruz if (err) 1411ac9da0e0SDiego Santa Cruz return err; 1412ac9da0e0SDiego Santa Cruz 1413ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 1414ac9da0e0SDiego Santa Cruz 1415ac9da0e0SDiego Santa Cruz /* update erase group size to be high-capacity */ 1416ac9da0e0SDiego Santa Cruz mmc->erase_grp_size = 1417ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 1418ac9da0e0SDiego Santa Cruz 1419ac9da0e0SDiego Santa Cruz } 1420ac9da0e0SDiego Santa Cruz 1421ac9da0e0SDiego Santa Cruz /* all OK, write the configuration */ 1422ac9da0e0SDiego Santa Cruz for (i = 0; i < 4; i++) { 1423ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1424ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_START_ADDR+i, 1425ac9da0e0SDiego Santa Cruz (enh_start_addr >> (i*8)) & 0xFF); 1426ac9da0e0SDiego Santa Cruz if (err) 1427ac9da0e0SDiego Santa Cruz return err; 1428ac9da0e0SDiego Santa Cruz } 1429ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 1430ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1431ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_SIZE_MULT+i, 1432ac9da0e0SDiego Santa Cruz (enh_size_mult >> (i*8)) & 0xFF); 1433ac9da0e0SDiego Santa Cruz if (err) 1434ac9da0e0SDiego Santa Cruz return err; 1435ac9da0e0SDiego Santa Cruz } 1436ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 1437ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 1438ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1439ac9da0e0SDiego Santa Cruz EXT_CSD_GP_SIZE_MULT+pidx*3+i, 1440ac9da0e0SDiego Santa Cruz (gp_size_mult[pidx] >> (i*8)) & 0xFF); 1441ac9da0e0SDiego Santa Cruz if (err) 1442ac9da0e0SDiego Santa Cruz return err; 1443ac9da0e0SDiego Santa Cruz } 1444ac9da0e0SDiego Santa Cruz } 1445ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1446ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs); 1447ac9da0e0SDiego Santa Cruz if (err) 1448ac9da0e0SDiego Santa Cruz return err; 1449ac9da0e0SDiego Santa Cruz 1450ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_SET) 1451ac9da0e0SDiego Santa Cruz return 0; 1452ac9da0e0SDiego Santa Cruz 14538dda5b0eSDiego Santa Cruz /* The WR_REL_SET is a write-once register but shall be 14548dda5b0eSDiego Santa Cruz * written before setting PART_SETTING_COMPLETED. As it is 14558dda5b0eSDiego Santa Cruz * write-once we can only write it when completing the 14568dda5b0eSDiego Santa Cruz * partitioning. */ 14578dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) { 14588dda5b0eSDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 14598dda5b0eSDiego Santa Cruz EXT_CSD_WR_REL_SET, wr_rel_set); 14608dda5b0eSDiego Santa Cruz if (err) 14618dda5b0eSDiego Santa Cruz return err; 14628dda5b0eSDiego Santa Cruz } 14638dda5b0eSDiego Santa Cruz 1464ac9da0e0SDiego Santa Cruz /* Setting PART_SETTING_COMPLETED confirms the partition 1465ac9da0e0SDiego Santa Cruz * configuration but it only becomes effective after power 1466ac9da0e0SDiego Santa Cruz * cycle, so we do not adjust the partition related settings 1467ac9da0e0SDiego Santa Cruz * in the mmc struct. */ 1468ac9da0e0SDiego Santa Cruz 1469ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1470ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING, 1471ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 1472ac9da0e0SDiego Santa Cruz if (err) 1473ac9da0e0SDiego Santa Cruz return err; 1474ac9da0e0SDiego Santa Cruz 1475ac9da0e0SDiego Santa Cruz return 0; 1476ac9da0e0SDiego Santa Cruz } 1477ac9da0e0SDiego Santa Cruz 1478e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 147948972d90SThierry Reding int mmc_getcd(struct mmc *mmc) 148048972d90SThierry Reding { 148148972d90SThierry Reding int cd; 148248972d90SThierry Reding 148348972d90SThierry Reding cd = board_mmc_getcd(mmc); 148448972d90SThierry Reding 1485d4e1da4eSPeter Korsgaard if (cd < 0) { 148693bfd616SPantelis Antoniou if (mmc->cfg->ops->getcd) 148793bfd616SPantelis Antoniou cd = mmc->cfg->ops->getcd(mmc); 1488d4e1da4eSPeter Korsgaard else 1489d4e1da4eSPeter Korsgaard cd = 1; 1490d4e1da4eSPeter Korsgaard } 149148972d90SThierry Reding 149248972d90SThierry Reding return cd; 149348972d90SThierry Reding } 14948ca51e51SSimon Glass #endif 149548972d90SThierry Reding 1496fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) 1497272cc70bSAndy Fleming { 1498272cc70bSAndy Fleming struct mmc_cmd cmd; 1499272cc70bSAndy Fleming struct mmc_data data; 1500272cc70bSAndy Fleming 1501272cc70bSAndy Fleming /* Switch the frequency */ 1502272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC; 1503272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1504272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff; 1505272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4)); 1506272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4); 1507272cc70bSAndy Fleming 1508272cc70bSAndy Fleming data.dest = (char *)resp; 1509272cc70bSAndy Fleming data.blocksize = 64; 1510272cc70bSAndy Fleming data.blocks = 1; 1511272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1512272cc70bSAndy Fleming 1513272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 1514272cc70bSAndy Fleming } 1515272cc70bSAndy Fleming 1516272cc70bSAndy Fleming 1517fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc) 1518272cc70bSAndy Fleming { 1519272cc70bSAndy Fleming int err; 1520272cc70bSAndy Fleming struct mmc_cmd cmd; 1521f781dd38SAnton staaf ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2); 1522f781dd38SAnton staaf ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16); 1523272cc70bSAndy Fleming struct mmc_data data; 1524272cc70bSAndy Fleming int timeout; 1525272cc70bSAndy Fleming 1526272cc70bSAndy Fleming mmc->card_caps = 0; 1527272cc70bSAndy Fleming 1528d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 1529d52ebf10SThomas Chou return 0; 1530d52ebf10SThomas Chou 1531272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */ 1532272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 1533272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1534272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1535272cc70bSAndy Fleming 1536272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1537272cc70bSAndy Fleming 1538272cc70bSAndy Fleming if (err) 1539272cc70bSAndy Fleming return err; 1540272cc70bSAndy Fleming 1541272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR; 1542272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1543272cc70bSAndy Fleming cmd.cmdarg = 0; 1544272cc70bSAndy Fleming 1545272cc70bSAndy Fleming timeout = 3; 1546272cc70bSAndy Fleming 1547272cc70bSAndy Fleming retry_scr: 1548f781dd38SAnton staaf data.dest = (char *)scr; 1549272cc70bSAndy Fleming data.blocksize = 8; 1550272cc70bSAndy Fleming data.blocks = 1; 1551272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1552272cc70bSAndy Fleming 1553272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 1554272cc70bSAndy Fleming 1555272cc70bSAndy Fleming if (err) { 1556272cc70bSAndy Fleming if (timeout--) 1557272cc70bSAndy Fleming goto retry_scr; 1558272cc70bSAndy Fleming 1559272cc70bSAndy Fleming return err; 1560272cc70bSAndy Fleming } 1561272cc70bSAndy Fleming 15624e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]); 15634e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]); 1564272cc70bSAndy Fleming 1565272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) { 1566272cc70bSAndy Fleming case 0: 1567272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1568272cc70bSAndy Fleming break; 1569272cc70bSAndy Fleming case 1: 1570272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10; 1571272cc70bSAndy Fleming break; 1572272cc70bSAndy Fleming case 2: 1573272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 15741741c64dSJaehoon Chung if ((mmc->scr[0] >> 15) & 0x1) 15751741c64dSJaehoon Chung mmc->version = SD_VERSION_3; 1576272cc70bSAndy Fleming break; 1577272cc70bSAndy Fleming default: 1578272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1579272cc70bSAndy Fleming break; 1580272cc70bSAndy Fleming } 1581272cc70bSAndy Fleming 1582b44c7083SAlagu Sankar if (mmc->scr[0] & SD_DATA_4BIT) 1583b44c7083SAlagu Sankar mmc->card_caps |= MMC_MODE_4BIT; 1584b44c7083SAlagu Sankar 1585272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */ 1586272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0) 1587272cc70bSAndy Fleming return 0; 1588272cc70bSAndy Fleming 1589272cc70bSAndy Fleming timeout = 4; 1590272cc70bSAndy Fleming while (timeout--) { 1591272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, 1592f781dd38SAnton staaf (u8 *)switch_status); 1593272cc70bSAndy Fleming 1594272cc70bSAndy Fleming if (err) 1595272cc70bSAndy Fleming return err; 1596272cc70bSAndy Fleming 1597272cc70bSAndy Fleming /* The high-speed function is busy. Try again */ 15984e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) 1599272cc70bSAndy Fleming break; 1600272cc70bSAndy Fleming } 1601272cc70bSAndy Fleming 1602272cc70bSAndy Fleming /* If high-speed isn't supported, we return */ 16034e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)) 1604272cc70bSAndy Fleming return 0; 1605272cc70bSAndy Fleming 16062c3fbf4cSMacpaul Lin /* 16072c3fbf4cSMacpaul Lin * If the host doesn't support SD_HIGHSPEED, do not switch card to 16082c3fbf4cSMacpaul Lin * HIGHSPEED mode even if the card support SD_HIGHSPPED. 16092c3fbf4cSMacpaul Lin * This can avoid furthur problem when the card runs in different 16102c3fbf4cSMacpaul Lin * mode between the host. 16112c3fbf4cSMacpaul Lin */ 161293bfd616SPantelis Antoniou if (!((mmc->cfg->host_caps & MMC_MODE_HS_52MHz) && 161393bfd616SPantelis Antoniou (mmc->cfg->host_caps & MMC_MODE_HS))) 16142c3fbf4cSMacpaul Lin return 0; 16152c3fbf4cSMacpaul Lin 1616f781dd38SAnton staaf err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status); 1617272cc70bSAndy Fleming 1618272cc70bSAndy Fleming if (err) 1619272cc70bSAndy Fleming return err; 1620272cc70bSAndy Fleming 16214e3d89baSYauhen Kharuzhy if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000) 1622272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS; 1623272cc70bSAndy Fleming 1624272cc70bSAndy Fleming return 0; 1625272cc70bSAndy Fleming } 1626272cc70bSAndy Fleming 16273697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc) 16283697e599SPeng Fan { 16293697e599SPeng Fan int err, i; 16303697e599SPeng Fan struct mmc_cmd cmd; 16313697e599SPeng Fan ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16); 16323697e599SPeng Fan struct mmc_data data; 16333697e599SPeng Fan int timeout = 3; 16343697e599SPeng Fan unsigned int au, eo, et, es; 16353697e599SPeng Fan 16363697e599SPeng Fan cmd.cmdidx = MMC_CMD_APP_CMD; 16373697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 16383697e599SPeng Fan cmd.cmdarg = mmc->rca << 16; 16393697e599SPeng Fan 16403697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, NULL); 16413697e599SPeng Fan if (err) 16423697e599SPeng Fan return err; 16433697e599SPeng Fan 16443697e599SPeng Fan cmd.cmdidx = SD_CMD_APP_SD_STATUS; 16453697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 16463697e599SPeng Fan cmd.cmdarg = 0; 16473697e599SPeng Fan 16483697e599SPeng Fan retry_ssr: 16493697e599SPeng Fan data.dest = (char *)ssr; 16503697e599SPeng Fan data.blocksize = 64; 16513697e599SPeng Fan data.blocks = 1; 16523697e599SPeng Fan data.flags = MMC_DATA_READ; 16533697e599SPeng Fan 16543697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, &data); 16553697e599SPeng Fan if (err) { 16563697e599SPeng Fan if (timeout--) 16573697e599SPeng Fan goto retry_ssr; 16583697e599SPeng Fan 16593697e599SPeng Fan return err; 16603697e599SPeng Fan } 16613697e599SPeng Fan 16623697e599SPeng Fan for (i = 0; i < 16; i++) 16633697e599SPeng Fan ssr[i] = be32_to_cpu(ssr[i]); 16643697e599SPeng Fan 16653697e599SPeng Fan au = (ssr[2] >> 12) & 0xF; 16663697e599SPeng Fan if ((au <= 9) || (mmc->version == SD_VERSION_3)) { 16673697e599SPeng Fan mmc->ssr.au = sd_au_size[au]; 16683697e599SPeng Fan es = (ssr[3] >> 24) & 0xFF; 16693697e599SPeng Fan es |= (ssr[2] & 0xFF) << 8; 16703697e599SPeng Fan et = (ssr[3] >> 18) & 0x3F; 16713697e599SPeng Fan if (es && et) { 16723697e599SPeng Fan eo = (ssr[3] >> 16) & 0x3; 16733697e599SPeng Fan mmc->ssr.erase_timeout = (et * 1000) / es; 16743697e599SPeng Fan mmc->ssr.erase_offset = eo * 1000; 16753697e599SPeng Fan } 16763697e599SPeng Fan } else { 16773697e599SPeng Fan debug("Invalid Allocation Unit Size.\n"); 16783697e599SPeng Fan } 16793697e599SPeng Fan 16803697e599SPeng Fan return 0; 16813697e599SPeng Fan } 16823697e599SPeng Fan 1683272cc70bSAndy Fleming /* frequency bases */ 1684272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */ 16855f837c2cSMike Frysinger static const int fbase[] = { 1686272cc70bSAndy Fleming 10000, 1687272cc70bSAndy Fleming 100000, 1688272cc70bSAndy Fleming 1000000, 1689272cc70bSAndy Fleming 10000000, 1690272cc70bSAndy Fleming }; 1691272cc70bSAndy Fleming 1692272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice 1693272cc70bSAndy Fleming * to platforms without floating point. 1694272cc70bSAndy Fleming */ 169561fe076fSSimon Glass static const u8 multipliers[] = { 1696272cc70bSAndy Fleming 0, /* reserved */ 1697272cc70bSAndy Fleming 10, 1698272cc70bSAndy Fleming 12, 1699272cc70bSAndy Fleming 13, 1700272cc70bSAndy Fleming 15, 1701272cc70bSAndy Fleming 20, 1702272cc70bSAndy Fleming 25, 1703272cc70bSAndy Fleming 30, 1704272cc70bSAndy Fleming 35, 1705272cc70bSAndy Fleming 40, 1706272cc70bSAndy Fleming 45, 1707272cc70bSAndy Fleming 50, 1708272cc70bSAndy Fleming 55, 1709272cc70bSAndy Fleming 60, 1710272cc70bSAndy Fleming 70, 1711272cc70bSAndy Fleming 80, 1712272cc70bSAndy Fleming }; 1713272cc70bSAndy Fleming 1714e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 1715fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc) 1716272cc70bSAndy Fleming { 171793bfd616SPantelis Antoniou if (mmc->cfg->ops->set_ios) 171893bfd616SPantelis Antoniou mmc->cfg->ops->set_ios(mmc); 1719272cc70bSAndy Fleming } 1720ad77484aSZiyuan Xu 1721ad77484aSZiyuan Xu static bool mmc_card_busy(struct mmc *mmc) 1722ad77484aSZiyuan Xu { 1723ad77484aSZiyuan Xu if (!mmc->cfg->ops->card_busy) 1724ad77484aSZiyuan Xu return -ENOSYS; 1725ad77484aSZiyuan Xu 1726ad77484aSZiyuan Xu return mmc->cfg->ops->card_busy(mmc); 1727ad77484aSZiyuan Xu } 1728ad77484aSZiyuan Xu 1729ad77484aSZiyuan Xu static bool mmc_can_card_busy(struct mmc *) 1730ad77484aSZiyuan Xu { 1731ad77484aSZiyuan Xu return !!mmc->cfg->ops->card_busy; 1732ad77484aSZiyuan Xu } 17338ca51e51SSimon Glass #endif 1734272cc70bSAndy Fleming 1735fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc) 1736272cc70bSAndy Fleming { 1737f866a46dSStephen Warren int err, i; 17383e3ff0acSZiyuan Xu uint mult, freq, tran_speed; 1739639b7827SYoshihiro Shimoda u64 cmult, csize, capacity; 1740272cc70bSAndy Fleming struct mmc_cmd cmd; 17418bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 17420c453bb7SDiego Santa Cruz bool has_parts = false; 17438a0cf490SDiego Santa Cruz bool part_completed; 1744c40fdca6SSimon Glass struct blk_desc *bdesc; 1745272cc70bSAndy Fleming 1746d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON 1747d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ 1748d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; 1749d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R1; 1750d52ebf10SThomas Chou cmd.cmdarg = 1; 1751d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 1752d52ebf10SThomas Chou 1753d52ebf10SThomas Chou if (err) 1754d52ebf10SThomas Chou return err; 1755d52ebf10SThomas Chou } 1756d52ebf10SThomas Chou #endif 1757479fbf72SJason Zhu #ifndef CONFIG_MMC_USE_PRE_CONFIG 1758272cc70bSAndy Fleming /* Put the Card in Identify Mode */ 1759d52ebf10SThomas Chou cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : 1760d52ebf10SThomas Chou MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ 1761272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1762272cc70bSAndy Fleming cmd.cmdarg = 0; 1763272cc70bSAndy Fleming 1764272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1765272cc70bSAndy Fleming 1766272cc70bSAndy Fleming if (err) 1767272cc70bSAndy Fleming return err; 1768272cc70bSAndy Fleming 1769272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16); 1770272cc70bSAndy Fleming 1771272cc70bSAndy Fleming /* 1772272cc70bSAndy Fleming * For MMC cards, set the Relative Address. 1773272cc70bSAndy Fleming * For SD cards, get the Relatvie Address. 1774272cc70bSAndy Fleming * This also puts the cards into Standby State 1775272cc70bSAndy Fleming */ 1776d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1777272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; 1778272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1779272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6; 1780272cc70bSAndy Fleming 1781272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1782272cc70bSAndy Fleming 1783272cc70bSAndy Fleming if (err) 1784272cc70bSAndy Fleming return err; 1785272cc70bSAndy Fleming 1786272cc70bSAndy Fleming if (IS_SD(mmc)) 1787998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff; 1788d52ebf10SThomas Chou } 1789479fbf72SJason Zhu #endif 1790272cc70bSAndy Fleming /* Get the Card-Specific Data */ 1791272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD; 1792272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1793272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1794272cc70bSAndy Fleming 1795272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1796272cc70bSAndy Fleming 1797272cc70bSAndy Fleming if (err) 1798272cc70bSAndy Fleming return err; 1799272cc70bSAndy Fleming 1800998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0]; 1801998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1]; 1802998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2]; 1803998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3]; 1804272cc70bSAndy Fleming 1805272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) { 18060b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf; 1807272cc70bSAndy Fleming 1808272cc70bSAndy Fleming switch (version) { 1809272cc70bSAndy Fleming case 0: 1810272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1811272cc70bSAndy Fleming break; 1812272cc70bSAndy Fleming case 1: 1813272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4; 1814272cc70bSAndy Fleming break; 1815272cc70bSAndy Fleming case 2: 1816272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2; 1817272cc70bSAndy Fleming break; 1818272cc70bSAndy Fleming case 3: 1819272cc70bSAndy Fleming mmc->version = MMC_VERSION_3; 1820272cc70bSAndy Fleming break; 1821272cc70bSAndy Fleming case 4: 1822272cc70bSAndy Fleming mmc->version = MMC_VERSION_4; 1823272cc70bSAndy Fleming break; 1824272cc70bSAndy Fleming default: 1825272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1826272cc70bSAndy Fleming break; 1827272cc70bSAndy Fleming } 1828272cc70bSAndy Fleming } 1829272cc70bSAndy Fleming 1830272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */ 18310b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)]; 18320b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; 1833272cc70bSAndy Fleming 18343e3ff0acSZiyuan Xu tran_speed = freq * mult; 1835272cc70bSAndy Fleming 1836ab71188cSMarkus Niebel mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); 1837998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); 1838272cc70bSAndy Fleming 1839272cc70bSAndy Fleming if (IS_SD(mmc)) 1840272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len; 1841272cc70bSAndy Fleming else 1842998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); 1843272cc70bSAndy Fleming 1844272cc70bSAndy Fleming if (mmc->high_capacity) { 1845272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16 1846272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16; 1847272cc70bSAndy Fleming cmult = 8; 1848272cc70bSAndy Fleming } else { 1849272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2 1850272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30; 1851272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15; 1852272cc70bSAndy Fleming } 1853272cc70bSAndy Fleming 1854f866a46dSStephen Warren mmc->capacity_user = (csize + 1) << (cmult + 2); 1855f866a46dSStephen Warren mmc->capacity_user *= mmc->read_bl_len; 1856f866a46dSStephen Warren mmc->capacity_boot = 0; 1857f866a46dSStephen Warren mmc->capacity_rpmb = 0; 1858f866a46dSStephen Warren for (i = 0; i < 4; i++) 1859f866a46dSStephen Warren mmc->capacity_gp[i] = 0; 1860272cc70bSAndy Fleming 18618bfa195eSSimon Glass if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN) 18628bfa195eSSimon Glass mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 1863272cc70bSAndy Fleming 18648bfa195eSSimon Glass if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) 18658bfa195eSSimon Glass mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 1866272cc70bSAndy Fleming 1867ab71188cSMarkus Niebel if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) { 1868ab71188cSMarkus Niebel cmd.cmdidx = MMC_CMD_SET_DSR; 1869ab71188cSMarkus Niebel cmd.cmdarg = (mmc->dsr & 0xffff) << 16; 1870ab71188cSMarkus Niebel cmd.resp_type = MMC_RSP_NONE; 1871ab71188cSMarkus Niebel if (mmc_send_cmd(mmc, &cmd, NULL)) 1872ab71188cSMarkus Niebel printf("MMC: SET_DSR failed\n"); 1873ab71188cSMarkus Niebel } 1874ab71188cSMarkus Niebel 1875272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */ 1876d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1877272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD; 1878fe8f7066SAjay Bhargav cmd.resp_type = MMC_RSP_R1; 1879272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1880272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1881272cc70bSAndy Fleming 1882272cc70bSAndy Fleming if (err) 1883272cc70bSAndy Fleming return err; 1884d52ebf10SThomas Chou } 1885272cc70bSAndy Fleming 1886e6f99a56SLei Wen /* 1887e6f99a56SLei Wen * For SD, its erase group is always one sector 1888e6f99a56SLei Wen */ 1889e6f99a56SLei Wen mmc->erase_grp_size = 1; 1890bc897b1dSLei Wen mmc->part_config = MMCPART_NOAVAILABLE; 1891d23e2c09SSukumar Ghorai if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) { 1892983bba80SYifeng Zhao /* select high speed to reduce initialization time */ 1893983bba80SYifeng Zhao mmc_select_hs(mmc); 1894983bba80SYifeng Zhao mmc_set_clock(mmc, MMC_HIGH_52_MAX_DTR); 1895983bba80SYifeng Zhao 1896d23e2c09SSukumar Ghorai /* check ext_csd version and capacity */ 1897d23e2c09SSukumar Ghorai err = mmc_send_ext_csd(mmc, ext_csd); 18989cf199ebSDiego Santa Cruz if (err) 18999cf199ebSDiego Santa Cruz return err; 19009cf199ebSDiego Santa Cruz if (ext_csd[EXT_CSD_REV] >= 2) { 1901639b7827SYoshihiro Shimoda /* 1902639b7827SYoshihiro Shimoda * According to the JEDEC Standard, the value of 1903639b7827SYoshihiro Shimoda * ext_csd's capacity is valid if the value is more 1904639b7827SYoshihiro Shimoda * than 2GB 1905639b7827SYoshihiro Shimoda */ 19060560db18SLei Wen capacity = ext_csd[EXT_CSD_SEC_CNT] << 0 19070560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 19080560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 19090560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; 19108bfa195eSSimon Glass capacity *= MMC_MAX_BLOCK_LEN; 1911b1f1e821SŁukasz Majewski if ((capacity >> 20) > 2 * 1024) 1912f866a46dSStephen Warren mmc->capacity_user = capacity; 1913d23e2c09SSukumar Ghorai } 1914bc897b1dSLei Wen 191564f4a619SJaehoon Chung switch (ext_csd[EXT_CSD_REV]) { 191664f4a619SJaehoon Chung case 1: 191764f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_1; 191864f4a619SJaehoon Chung break; 191964f4a619SJaehoon Chung case 2: 192064f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_2; 192164f4a619SJaehoon Chung break; 192264f4a619SJaehoon Chung case 3: 192364f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_3; 192464f4a619SJaehoon Chung break; 192564f4a619SJaehoon Chung case 5: 192664f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_41; 192764f4a619SJaehoon Chung break; 192864f4a619SJaehoon Chung case 6: 192964f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_5; 193064f4a619SJaehoon Chung break; 1931edab723bSMarkus Niebel case 7: 1932edab723bSMarkus Niebel mmc->version = MMC_VERSION_5_0; 1933edab723bSMarkus Niebel break; 19341a3619cfSStefan Wahren case 8: 19351a3619cfSStefan Wahren mmc->version = MMC_VERSION_5_1; 19361a3619cfSStefan Wahren break; 193764f4a619SJaehoon Chung } 193864f4a619SJaehoon Chung 19398a0cf490SDiego Santa Cruz /* The partition data may be non-zero but it is only 19408a0cf490SDiego Santa Cruz * effective if PARTITION_SETTING_COMPLETED is set in 19418a0cf490SDiego Santa Cruz * EXT_CSD, so ignore any data if this bit is not set, 19428a0cf490SDiego Santa Cruz * except for enabling the high-capacity group size 19438a0cf490SDiego Santa Cruz * definition (see below). */ 19448a0cf490SDiego Santa Cruz part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] & 19458a0cf490SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 19468a0cf490SDiego Santa Cruz 19470c453bb7SDiego Santa Cruz /* store the partition info of emmc */ 19480c453bb7SDiego Santa Cruz mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT]; 19490c453bb7SDiego Santa Cruz if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || 19500c453bb7SDiego Santa Cruz ext_csd[EXT_CSD_BOOT_MULT]) 19510c453bb7SDiego Santa Cruz mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; 19528a0cf490SDiego Santa Cruz if (part_completed && 19538a0cf490SDiego Santa Cruz (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT)) 19540c453bb7SDiego Santa Cruz mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]; 1955a6a1f5f8SJason Zhu if (ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] & EXT_CSD_SEC_GB_CL_EN) 1956a6a1f5f8SJason Zhu mmc->esr.mmc_can_trim = 1; 19570c453bb7SDiego Santa Cruz 19580c453bb7SDiego Santa Cruz mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17; 19590c453bb7SDiego Santa Cruz 19600c453bb7SDiego Santa Cruz mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17; 19610c453bb7SDiego Santa Cruz 19620c453bb7SDiego Santa Cruz for (i = 0; i < 4; i++) { 19630c453bb7SDiego Santa Cruz int idx = EXT_CSD_GP_SIZE_MULT + i * 3; 19648a0cf490SDiego Santa Cruz uint mult = (ext_csd[idx + 2] << 16) + 19650c453bb7SDiego Santa Cruz (ext_csd[idx + 1] << 8) + ext_csd[idx]; 19668a0cf490SDiego Santa Cruz if (mult) 19678a0cf490SDiego Santa Cruz has_parts = true; 19688a0cf490SDiego Santa Cruz if (!part_completed) 19698a0cf490SDiego Santa Cruz continue; 19708a0cf490SDiego Santa Cruz mmc->capacity_gp[i] = mult; 19710c453bb7SDiego Santa Cruz mmc->capacity_gp[i] *= 19720c453bb7SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 19730c453bb7SDiego Santa Cruz mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1974f8e89d67SDiego Santa Cruz mmc->capacity_gp[i] <<= 19; 19750c453bb7SDiego Santa Cruz } 19760c453bb7SDiego Santa Cruz 19778a0cf490SDiego Santa Cruz if (part_completed) { 1978a7f852b6SDiego Santa Cruz mmc->enh_user_size = 1979a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_SIZE_MULT+2] << 16) + 1980a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_SIZE_MULT+1] << 8) + 1981a7f852b6SDiego Santa Cruz ext_csd[EXT_CSD_ENH_SIZE_MULT]; 1982a7f852b6SDiego Santa Cruz mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1983a7f852b6SDiego Santa Cruz mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1984a7f852b6SDiego Santa Cruz mmc->enh_user_size <<= 19; 1985a7f852b6SDiego Santa Cruz mmc->enh_user_start = 1986a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_START_ADDR+3] << 24) + 1987a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_START_ADDR+2] << 16) + 1988a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_START_ADDR+1] << 8) + 1989a7f852b6SDiego Santa Cruz ext_csd[EXT_CSD_ENH_START_ADDR]; 1990a7f852b6SDiego Santa Cruz if (mmc->high_capacity) 1991a7f852b6SDiego Santa Cruz mmc->enh_user_start <<= 9; 19928a0cf490SDiego Santa Cruz } 1993a7f852b6SDiego Santa Cruz 1994e6f99a56SLei Wen /* 19951937e5aaSOliver Metz * Host needs to enable ERASE_GRP_DEF bit if device is 19961937e5aaSOliver Metz * partitioned. This bit will be lost every time after a reset 19971937e5aaSOliver Metz * or power off. This will affect erase size. 1998e6f99a56SLei Wen */ 19998a0cf490SDiego Santa Cruz if (part_completed) 20000c453bb7SDiego Santa Cruz has_parts = true; 20011937e5aaSOliver Metz if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) && 20020c453bb7SDiego Santa Cruz (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) 20030c453bb7SDiego Santa Cruz has_parts = true; 20040c453bb7SDiego Santa Cruz if (has_parts) { 20051937e5aaSOliver Metz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 20061937e5aaSOliver Metz EXT_CSD_ERASE_GROUP_DEF, 1); 20071937e5aaSOliver Metz 20081937e5aaSOliver Metz if (err) 20091937e5aaSOliver Metz return err; 2010021a8055SHannes Petermaier else 2011021a8055SHannes Petermaier ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 2012037dc0abSDiego Santa Cruz } 20131937e5aaSOliver Metz 2014037dc0abSDiego Santa Cruz if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) { 20151937e5aaSOliver Metz /* Read out group size from ext_csd */ 20160560db18SLei Wen mmc->erase_grp_size = 2017a4ff9f83SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 2018d7b29129SMarkus Niebel /* 2019d7b29129SMarkus Niebel * if high capacity and partition setting completed 2020d7b29129SMarkus Niebel * SEC_COUNT is valid even if it is smaller than 2 GiB 2021d7b29129SMarkus Niebel * JEDEC Standard JESD84-B45, 6.2.4 2022d7b29129SMarkus Niebel */ 20238a0cf490SDiego Santa Cruz if (mmc->high_capacity && part_completed) { 2024d7b29129SMarkus Niebel capacity = (ext_csd[EXT_CSD_SEC_CNT]) | 2025d7b29129SMarkus Niebel (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) | 2026d7b29129SMarkus Niebel (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) | 2027d7b29129SMarkus Niebel (ext_csd[EXT_CSD_SEC_CNT + 3] << 24); 2028d7b29129SMarkus Niebel capacity *= MMC_MAX_BLOCK_LEN; 2029d7b29129SMarkus Niebel mmc->capacity_user = capacity; 2030d7b29129SMarkus Niebel } 20318bfa195eSSimon Glass } else { 20321937e5aaSOliver Metz /* Calculate the group size from the csd value. */ 2033e6f99a56SLei Wen int erase_gsz, erase_gmul; 2034e6f99a56SLei Wen erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; 2035e6f99a56SLei Wen erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; 2036e6f99a56SLei Wen mmc->erase_grp_size = (erase_gsz + 1) 2037e6f99a56SLei Wen * (erase_gmul + 1); 2038e6f99a56SLei Wen } 2039037dc0abSDiego Santa Cruz 2040037dc0abSDiego Santa Cruz mmc->hc_wp_grp_size = 1024 2041037dc0abSDiego Santa Cruz * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 2042037dc0abSDiego Santa Cruz * ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 20439e41a00bSDiego Santa Cruz 20449e41a00bSDiego Santa Cruz mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 20457a9b5d70SYifeng Zhao 20467a9b5d70SYifeng Zhao mmc->raw_driver_strength = ext_csd[EXT_CSD_DRIVER_STRENGTH]; 2047f866a46dSStephen Warren } 2048f866a46dSStephen Warren 2049c40fdca6SSimon Glass err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart); 2050f866a46dSStephen Warren if (err) 2051f866a46dSStephen Warren return err; 2052d23e2c09SSukumar Ghorai 2053272cc70bSAndy Fleming if (IS_SD(mmc)) 2054272cc70bSAndy Fleming err = sd_change_freq(mmc); 2055272cc70bSAndy Fleming else 2056272cc70bSAndy Fleming err = mmc_change_freq(mmc); 2057272cc70bSAndy Fleming 2058272cc70bSAndy Fleming if (err) 2059272cc70bSAndy Fleming return err; 2060272cc70bSAndy Fleming 2061272cc70bSAndy Fleming /* Restrict card's capabilities by what the host can do */ 206293bfd616SPantelis Antoniou mmc->card_caps &= mmc->cfg->host_caps; 2063272cc70bSAndy Fleming 2064272cc70bSAndy Fleming if (IS_SD(mmc)) { 2065272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_4BIT) { 2066272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 2067272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 2068272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 2069272cc70bSAndy Fleming 2070272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2071272cc70bSAndy Fleming if (err) 2072272cc70bSAndy Fleming return err; 2073272cc70bSAndy Fleming 2074272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; 2075272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 2076272cc70bSAndy Fleming cmd.cmdarg = 2; 2077272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2078272cc70bSAndy Fleming if (err) 2079272cc70bSAndy Fleming return err; 2080272cc70bSAndy Fleming 2081272cc70bSAndy Fleming mmc_set_bus_width(mmc, 4); 2082272cc70bSAndy Fleming } 2083272cc70bSAndy Fleming 20843697e599SPeng Fan err = sd_read_ssr(mmc); 20853697e599SPeng Fan if (err) 20863697e599SPeng Fan return err; 20873697e599SPeng Fan 2088272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS) 2089fe414819SJason Zhu tran_speed = MMC_HIGH_52_MAX_DTR; 2090272cc70bSAndy Fleming else 2091fe414819SJason Zhu tran_speed = MMC_HIGH_26_MAX_DTR; 2092ad5fd922SJaehoon Chung 20933e3ff0acSZiyuan Xu mmc_set_clock(mmc, tran_speed); 209449dba033SZiyuan Xu } 2095272cc70bSAndy Fleming 20965af8f45cSAndrew Gabbasov /* Fix the block length for DDR mode */ 209749dba033SZiyuan Xu if (mmc_card_ddr(mmc)) { 20985af8f45cSAndrew Gabbasov mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 20995af8f45cSAndrew Gabbasov mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 21005af8f45cSAndrew Gabbasov } 21015af8f45cSAndrew Gabbasov 2102272cc70bSAndy Fleming /* fill in device description */ 2103c40fdca6SSimon Glass bdesc = mmc_get_blk_desc(mmc); 2104c40fdca6SSimon Glass bdesc->lun = 0; 2105c40fdca6SSimon Glass bdesc->hwpart = 0; 2106c40fdca6SSimon Glass bdesc->type = 0; 2107c40fdca6SSimon Glass bdesc->blksz = mmc->read_bl_len; 2108c40fdca6SSimon Glass bdesc->log2blksz = LOG2(bdesc->blksz); 2109c40fdca6SSimon Glass bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len); 2110fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \ 2111fc011f64SSjoerd Simons (defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \ 2112fc011f64SSjoerd Simons !defined(CONFIG_USE_TINY_PRINTF)) 2113c40fdca6SSimon Glass sprintf(bdesc->vendor, "Man %06x Snr %04x%04x", 2114babce5f6STaylor Hutt mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), 2115babce5f6STaylor Hutt (mmc->cid[3] >> 16) & 0xffff); 2116c40fdca6SSimon Glass sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff, 21170b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 2118babce5f6STaylor Hutt (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff, 2119babce5f6STaylor Hutt (mmc->cid[2] >> 24) & 0xff); 2120c40fdca6SSimon Glass sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf, 2121babce5f6STaylor Hutt (mmc->cid[2] >> 16) & 0xf); 212256196826SPaul Burton #else 2123c40fdca6SSimon Glass bdesc->vendor[0] = 0; 2124c40fdca6SSimon Glass bdesc->product[0] = 0; 2125c40fdca6SSimon Glass bdesc->revision[0] = 0; 212656196826SPaul Burton #endif 2127122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT) 2128c40fdca6SSimon Glass part_init(bdesc); 2129122efd43SMikhail Kshevetskiy #endif 2130272cc70bSAndy Fleming 2131272cc70bSAndy Fleming return 0; 2132272cc70bSAndy Fleming } 2133272cc70bSAndy Fleming 2134479fbf72SJason Zhu #ifndef CONFIG_MMC_USE_PRE_CONFIG 2135fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc) 2136272cc70bSAndy Fleming { 2137272cc70bSAndy Fleming struct mmc_cmd cmd; 2138272cc70bSAndy Fleming int err; 2139272cc70bSAndy Fleming 2140272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND; 2141272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ 214293bfd616SPantelis Antoniou cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa; 2143272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7; 2144272cc70bSAndy Fleming 2145272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2146272cc70bSAndy Fleming 2147272cc70bSAndy Fleming if (err) 2148272cc70bSAndy Fleming return err; 2149272cc70bSAndy Fleming 2150998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa) 2151915ffa52SJaehoon Chung return -EOPNOTSUPP; 2152272cc70bSAndy Fleming else 2153272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 2154272cc70bSAndy Fleming 2155272cc70bSAndy Fleming return 0; 2156272cc70bSAndy Fleming } 2157479fbf72SJason Zhu #endif 2158272cc70bSAndy Fleming 2159c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 216095de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */ 216195de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void) 216295de9ab2SPaul Kocialkowski { 216395de9ab2SPaul Kocialkowski } 216405cbeb7cSSimon Glass #endif 216595de9ab2SPaul Kocialkowski 2166479fbf72SJason Zhu #ifndef CONFIG_MMC_USE_PRE_CONFIG 21672051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc) 21682051aefeSPeng Fan { 2169c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 217005cbeb7cSSimon Glass #if defined(CONFIG_DM_REGULATOR) && !defined(CONFIG_SPL_BUILD) 21712051aefeSPeng Fan struct udevice *vmmc_supply; 21722051aefeSPeng Fan int ret; 21732051aefeSPeng Fan 21742051aefeSPeng Fan ret = device_get_supply_regulator(mmc->dev, "vmmc-supply", 21752051aefeSPeng Fan &vmmc_supply); 21762051aefeSPeng Fan if (ret) { 2177288db7c7SJaehoon Chung debug("%s: No vmmc supply\n", mmc->dev->name); 21782051aefeSPeng Fan return 0; 21792051aefeSPeng Fan } 21802051aefeSPeng Fan 21812051aefeSPeng Fan ret = regulator_set_enable(vmmc_supply, true); 21822051aefeSPeng Fan if (ret) { 21832051aefeSPeng Fan puts("Error enabling VMMC supply\n"); 21842051aefeSPeng Fan return ret; 21852051aefeSPeng Fan } 21862051aefeSPeng Fan #endif 218705cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */ 218805cbeb7cSSimon Glass /* 218905cbeb7cSSimon Glass * Driver model should use a regulator, as above, rather than calling 219005cbeb7cSSimon Glass * out to board code. 219105cbeb7cSSimon Glass */ 219205cbeb7cSSimon Glass board_mmc_power_init(); 219305cbeb7cSSimon Glass #endif 21942051aefeSPeng Fan return 0; 21952051aefeSPeng Fan } 2196479fbf72SJason Zhu #endif 2197479fbf72SJason Zhu #ifdef CONFIG_MMC_USE_PRE_CONFIG 2198479fbf72SJason Zhu static int mmc_select_card(struct mmc *mmc, int n) 2199479fbf72SJason Zhu { 2200479fbf72SJason Zhu struct mmc_cmd cmd; 2201479fbf72SJason Zhu int err = 0; 22022051aefeSPeng Fan 2203479fbf72SJason Zhu memset(&cmd, 0, sizeof(struct mmc_cmd)); 2204479fbf72SJason Zhu if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 2205479fbf72SJason Zhu mmc->rca = n; 2206479fbf72SJason Zhu cmd.cmdidx = MMC_CMD_SELECT_CARD; 2207479fbf72SJason Zhu cmd.resp_type = MMC_RSP_R1; 2208479fbf72SJason Zhu cmd.cmdarg = mmc->rca << 16; 2209479fbf72SJason Zhu err = mmc_send_cmd(mmc, &cmd, NULL); 2210479fbf72SJason Zhu } 2211479fbf72SJason Zhu 2212479fbf72SJason Zhu return err; 2213479fbf72SJason Zhu } 2214479fbf72SJason Zhu 2215479fbf72SJason Zhu int mmc_start_init(struct mmc *mmc) 2216479fbf72SJason Zhu { 2217479fbf72SJason Zhu /* 2218479fbf72SJason Zhu * We use the MMC config set by the bootrom. 2219479fbf72SJason Zhu * So it is no need to reset the eMMC device. 2220479fbf72SJason Zhu */ 2221479fbf72SJason Zhu mmc_set_bus_width(mmc, 8); 2222479fbf72SJason Zhu mmc_set_clock(mmc, 1); 2223479fbf72SJason Zhu mmc_set_timing(mmc, MMC_TIMING_LEGACY); 2224479fbf72SJason Zhu /* Send cmd7 to return stand-by state*/ 2225479fbf72SJason Zhu mmc_select_card(mmc, 0); 2226479fbf72SJason Zhu mmc->version = MMC_VERSION_UNKNOWN; 2227479fbf72SJason Zhu mmc->high_capacity = 1; 2228479fbf72SJason Zhu /* 2229479fbf72SJason Zhu * The RCA is set to 2 by rockchip bootrom, use the default 2230479fbf72SJason Zhu * value here. 2231479fbf72SJason Zhu */ 2232479fbf72SJason Zhu #ifdef CONFIG_ARCH_ROCKCHIP 2233479fbf72SJason Zhu mmc->rca = 2; 2234479fbf72SJason Zhu #else 2235479fbf72SJason Zhu mmc->rca = 1; 2236479fbf72SJason Zhu #endif 2237479fbf72SJason Zhu return 0; 2238479fbf72SJason Zhu } 2239479fbf72SJason Zhu #else 2240e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc) 2241272cc70bSAndy Fleming { 22428ca51e51SSimon Glass bool no_card; 2243afd5932bSMacpaul Lin int err; 2244272cc70bSAndy Fleming 2245ab769f22SPantelis Antoniou /* we pretend there's no card when init is NULL */ 22468ca51e51SSimon Glass no_card = mmc_getcd(mmc) == 0; 2247e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 22488ca51e51SSimon Glass no_card = no_card || (mmc->cfg->ops->init == NULL); 22498ca51e51SSimon Glass #endif 22508ca51e51SSimon Glass if (no_card) { 225148972d90SThierry Reding mmc->has_init = 0; 225256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 225348972d90SThierry Reding printf("MMC: no card present\n"); 225456196826SPaul Burton #endif 2255915ffa52SJaehoon Chung return -ENOMEDIUM; 225648972d90SThierry Reding } 225748972d90SThierry Reding 2258bc897b1dSLei Wen if (mmc->has_init) 2259bc897b1dSLei Wen return 0; 2260bc897b1dSLei Wen 22615a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 22625a8dbdc6SYangbo Lu mmc_adapter_card_type_ident(); 22635a8dbdc6SYangbo Lu #endif 22642051aefeSPeng Fan err = mmc_power_init(mmc); 22652051aefeSPeng Fan if (err) 22662051aefeSPeng Fan return err; 226795de9ab2SPaul Kocialkowski 2268e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 22698ca51e51SSimon Glass /* The device has already been probed ready for use */ 22708ca51e51SSimon Glass #else 2271ab769f22SPantelis Antoniou /* made sure it's not NULL earlier */ 227293bfd616SPantelis Antoniou err = mmc->cfg->ops->init(mmc); 2273272cc70bSAndy Fleming if (err) 2274272cc70bSAndy Fleming return err; 22758ca51e51SSimon Glass #endif 2276b86b85e2SIlya Yanok mmc_set_bus_width(mmc, 1); 2277b86b85e2SIlya Yanok mmc_set_clock(mmc, 1); 227881db2d36SZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_LEGACY); 2279b86b85e2SIlya Yanok 2280272cc70bSAndy Fleming /* Reset the Card */ 2281272cc70bSAndy Fleming err = mmc_go_idle(mmc); 2282272cc70bSAndy Fleming 2283272cc70bSAndy Fleming if (err) 2284272cc70bSAndy Fleming return err; 2285272cc70bSAndy Fleming 2286bc897b1dSLei Wen /* The internal partition reset to user partition(0) at every CMD0*/ 2287c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->hwpart = 0; 2288bc897b1dSLei Wen 2289272cc70bSAndy Fleming /* Test for SD version 2 */ 2290272cc70bSAndy Fleming err = mmc_send_if_cond(mmc); 2291272cc70bSAndy Fleming 2292272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */ 2293272cc70bSAndy Fleming err = sd_send_op_cond(mmc); 2294272cc70bSAndy Fleming 2295272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */ 2296915ffa52SJaehoon Chung if (err == -ETIMEDOUT) { 2297272cc70bSAndy Fleming err = mmc_send_op_cond(mmc); 2298272cc70bSAndy Fleming 2299bd47c135SAndrew Gabbasov if (err) { 230056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2301272cc70bSAndy Fleming printf("Card did not respond to voltage select!\n"); 230256196826SPaul Burton #endif 2303915ffa52SJaehoon Chung return -EOPNOTSUPP; 2304272cc70bSAndy Fleming } 2305272cc70bSAndy Fleming } 2306272cc70bSAndy Fleming 2307bd47c135SAndrew Gabbasov if (!err) 2308e9550449SChe-Liang Chiou mmc->init_in_progress = 1; 2309e9550449SChe-Liang Chiou 2310e9550449SChe-Liang Chiou return err; 2311e9550449SChe-Liang Chiou } 2312479fbf72SJason Zhu #endif 2313e9550449SChe-Liang Chiou 2314e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc) 2315e9550449SChe-Liang Chiou { 2316e9550449SChe-Liang Chiou int err = 0; 2317e9550449SChe-Liang Chiou 2318bd47c135SAndrew Gabbasov mmc->init_in_progress = 0; 2319e9550449SChe-Liang Chiou if (mmc->op_cond_pending) 2320e9550449SChe-Liang Chiou err = mmc_complete_op_cond(mmc); 2321e9550449SChe-Liang Chiou 2322e9550449SChe-Liang Chiou if (!err) 2323bc897b1dSLei Wen err = mmc_startup(mmc); 2324bc897b1dSLei Wen if (err) 2325bc897b1dSLei Wen mmc->has_init = 0; 2326bc897b1dSLei Wen else 2327bc897b1dSLei Wen mmc->has_init = 1; 2328e9550449SChe-Liang Chiou return err; 2329e9550449SChe-Liang Chiou } 2330e9550449SChe-Liang Chiou 2331e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc) 2332e9550449SChe-Liang Chiou { 2333bd47c135SAndrew Gabbasov int err = 0; 2334ce9eca94SMarek Vasut __maybe_unused unsigned start; 2335c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 233633fb211dSSimon Glass struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev); 2337e9550449SChe-Liang Chiou 233833fb211dSSimon Glass upriv->mmc = mmc; 233933fb211dSSimon Glass #endif 2340e9550449SChe-Liang Chiou if (mmc->has_init) 2341e9550449SChe-Liang Chiou return 0; 2342d803fea5SMateusz Zalega 2343d803fea5SMateusz Zalega start = get_timer(0); 2344d803fea5SMateusz Zalega 2345e9550449SChe-Liang Chiou if (!mmc->init_in_progress) 2346e9550449SChe-Liang Chiou err = mmc_start_init(mmc); 2347e9550449SChe-Liang Chiou 2348bd47c135SAndrew Gabbasov if (!err) 2349e9550449SChe-Liang Chiou err = mmc_complete_init(mmc); 2350919b4858SJagan Teki if (err) 2351919b4858SJagan Teki printf("%s: %d, time %lu\n", __func__, err, get_timer(start)); 2352919b4858SJagan Teki 2353bc897b1dSLei Wen return err; 2354272cc70bSAndy Fleming } 2355272cc70bSAndy Fleming 2356ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val) 2357ab71188cSMarkus Niebel { 2358ab71188cSMarkus Niebel mmc->dsr = val; 2359ab71188cSMarkus Niebel return 0; 2360ab71188cSMarkus Niebel } 2361ab71188cSMarkus Niebel 2362cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */ 2363cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis) 2364272cc70bSAndy Fleming { 2365272cc70bSAndy Fleming return -1; 2366272cc70bSAndy Fleming } 2367272cc70bSAndy Fleming 2368cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */ 2369cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis) 2370cee9ab7cSJeroen Hofstee { 2371cee9ab7cSJeroen Hofstee return -1; 2372cee9ab7cSJeroen Hofstee } 2373272cc70bSAndy Fleming 2374e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit) 2375e9550449SChe-Liang Chiou { 2376e9550449SChe-Liang Chiou mmc->preinit = preinit; 2377e9550449SChe-Liang Chiou } 2378e9550449SChe-Liang Chiou 2379c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD) 23808e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 23818e3332e2SSjoerd Simons { 23828e3332e2SSjoerd Simons return 0; 23838e3332e2SSjoerd Simons } 2384c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC) 23858e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 23868e3332e2SSjoerd Simons { 23874a1db6d8SSimon Glass int ret, i; 23888e3332e2SSjoerd Simons struct uclass *uc; 23894a1db6d8SSimon Glass struct udevice *dev; 23908e3332e2SSjoerd Simons 23918e3332e2SSjoerd Simons ret = uclass_get(UCLASS_MMC, &uc); 23928e3332e2SSjoerd Simons if (ret) 23938e3332e2SSjoerd Simons return ret; 23948e3332e2SSjoerd Simons 23954a1db6d8SSimon Glass /* 23964a1db6d8SSimon Glass * Try to add them in sequence order. Really with driver model we 23974a1db6d8SSimon Glass * should allow holes, but the current MMC list does not allow that. 23984a1db6d8SSimon Glass * So if we request 0, 1, 3 we will get 0, 1, 2. 23994a1db6d8SSimon Glass */ 24004a1db6d8SSimon Glass for (i = 0; ; i++) { 24014a1db6d8SSimon Glass ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev); 24024a1db6d8SSimon Glass if (ret == -ENODEV) 24034a1db6d8SSimon Glass break; 24044a1db6d8SSimon Glass } 24054a1db6d8SSimon Glass uclass_foreach_dev(dev, uc) { 24064a1db6d8SSimon Glass ret = device_probe(dev); 24078e3332e2SSjoerd Simons if (ret) 24084a1db6d8SSimon Glass printf("%s - probe failed: %d\n", dev->name, ret); 24098e3332e2SSjoerd Simons } 24108e3332e2SSjoerd Simons 24118e3332e2SSjoerd Simons return 0; 24128e3332e2SSjoerd Simons } 24138e3332e2SSjoerd Simons #else 24148e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 24158e3332e2SSjoerd Simons { 24168e3332e2SSjoerd Simons if (board_mmc_init(bis) < 0) 24178e3332e2SSjoerd Simons cpu_mmc_init(bis); 24188e3332e2SSjoerd Simons 24198e3332e2SSjoerd Simons return 0; 24208e3332e2SSjoerd Simons } 24218e3332e2SSjoerd Simons #endif 2422e9550449SChe-Liang Chiou 2423272cc70bSAndy Fleming int mmc_initialize(bd_t *bis) 2424272cc70bSAndy Fleming { 24251b26bab1SDaniel Kochmański static int initialized = 0; 24268e3332e2SSjoerd Simons int ret; 24271b26bab1SDaniel Kochmański if (initialized) /* Avoid initializing mmc multiple times */ 24281b26bab1SDaniel Kochmański return 0; 24291b26bab1SDaniel Kochmański initialized = 1; 24301b26bab1SDaniel Kochmański 2431c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK) 2432b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY) 2433c40fdca6SSimon Glass mmc_list_init(); 2434c40fdca6SSimon Glass #endif 2435b5b838f1SMarek Vasut #endif 24368e3332e2SSjoerd Simons ret = mmc_probe(bis); 24378e3332e2SSjoerd Simons if (ret) 24388e3332e2SSjoerd Simons return ret; 2439272cc70bSAndy Fleming 2440bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD 2441272cc70bSAndy Fleming print_mmc_devices(','); 2442bb0dc108SYing Zhang #endif 2443272cc70bSAndy Fleming 2444c40fdca6SSimon Glass mmc_do_preinit(); 2445272cc70bSAndy Fleming return 0; 2446272cc70bSAndy Fleming } 2447cd3d4880STomas Melin 2448cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE 2449cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc) 2450cd3d4880STomas Melin { 2451cd3d4880STomas Melin int err; 2452cd3d4880STomas Melin ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 2453cd3d4880STomas Melin 2454cd3d4880STomas Melin err = mmc_send_ext_csd(mmc, ext_csd); 2455cd3d4880STomas Melin if (err) { 2456cd3d4880STomas Melin puts("Could not get ext_csd register values\n"); 2457cd3d4880STomas Melin return err; 2458cd3d4880STomas Melin } 2459cd3d4880STomas Melin 2460cd3d4880STomas Melin if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) { 2461cd3d4880STomas Melin puts("Background operations not supported on device\n"); 2462cd3d4880STomas Melin return -EMEDIUMTYPE; 2463cd3d4880STomas Melin } 2464cd3d4880STomas Melin 2465cd3d4880STomas Melin if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) { 2466cd3d4880STomas Melin puts("Background operations already enabled\n"); 2467cd3d4880STomas Melin return 0; 2468cd3d4880STomas Melin } 2469cd3d4880STomas Melin 2470cd3d4880STomas Melin err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1); 2471cd3d4880STomas Melin if (err) { 2472cd3d4880STomas Melin puts("Failed to enable manual background operations\n"); 2473cd3d4880STomas Melin return err; 2474cd3d4880STomas Melin } 2475cd3d4880STomas Melin 2476cd3d4880STomas Melin puts("Enabled manual background operations\n"); 2477cd3d4880STomas Melin 2478cd3d4880STomas Melin return 0; 2479cd3d4880STomas Melin } 2480cd3d4880STomas Melin #endif 2481