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 { 661e531136eSJason Zhu static int initialized; 662272cc70bSAndy Fleming struct mmc_cmd cmd; 663272cc70bSAndy Fleming struct mmc_data data; 664272cc70bSAndy Fleming int err; 665272cc70bSAndy Fleming 666e531136eSJason Zhu if (initialized) { 667e531136eSJason Zhu memcpy(ext_csd, mmc_ext_csd, 512); 668e531136eSJason Zhu return 0; 669e531136eSJason Zhu } 670e531136eSJason Zhu 671e531136eSJason Zhu initialized = 1; 672e531136eSJason Zhu 673272cc70bSAndy Fleming /* Get the Card Status Register */ 674272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_EXT_CSD; 675272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 676272cc70bSAndy Fleming cmd.cmdarg = 0; 677272cc70bSAndy Fleming 678cdfd1ac6SYoshihiro Shimoda data.dest = (char *)ext_csd; 679272cc70bSAndy Fleming data.blocks = 1; 6808bfa195eSSimon Glass data.blocksize = MMC_MAX_BLOCK_LEN; 681272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 682272cc70bSAndy Fleming 683272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 684e531136eSJason Zhu memcpy(mmc_ext_csd, ext_csd, 512); 6852056aa9fSJason Zhu #if defined(CONFIG_MMC_USE_PRE_CONFIG) && defined(CONFIG_SPL_BUILD) 6862056aa9fSJason Zhu char *mmc_ecsd_base = NULL; 6872056aa9fSJason Zhu ulong mmc_ecsd; 688272cc70bSAndy Fleming 6892056aa9fSJason Zhu mmc_ecsd = dev_read_u32_default(mmc->dev, "mmc-ecsd", 0); 6902056aa9fSJason Zhu mmc_ecsd_base = (char *)mmc_ecsd; 6912056aa9fSJason Zhu if (mmc_ecsd_base) { 6922056aa9fSJason Zhu memcpy(mmc_ecsd_base, ext_csd, 512); 6932056aa9fSJason Zhu *(unsigned int *)(mmc_ecsd_base + 512) = 0x55aa55aa; 6942056aa9fSJason Zhu } 6952056aa9fSJason Zhu #endif 696272cc70bSAndy Fleming return err; 697272cc70bSAndy Fleming } 698272cc70bSAndy Fleming 6999e8ce816SZiyuan Xu static int mmc_poll_for_busy(struct mmc *mmc, u8 send_status) 700272cc70bSAndy Fleming { 701272cc70bSAndy Fleming struct mmc_cmd cmd; 70255e5defdSZiyuan Xu u8 busy = true; 70355e5defdSZiyuan Xu uint start; 70455e5defdSZiyuan Xu int ret; 7055d4fc8d9SRaffaele Recalcati int timeout = 1000; 70655e5defdSZiyuan Xu 70755e5defdSZiyuan Xu cmd.cmdidx = MMC_CMD_SEND_STATUS; 70855e5defdSZiyuan Xu cmd.resp_type = MMC_RSP_R1; 70955e5defdSZiyuan Xu cmd.cmdarg = mmc->rca << 16; 71055e5defdSZiyuan Xu 71155e5defdSZiyuan Xu start = get_timer(0); 71255e5defdSZiyuan Xu 7139e8ce816SZiyuan Xu if (!send_status && !mmc_can_card_busy(mmc)) { 7149e8ce816SZiyuan Xu mdelay(timeout); 7159e8ce816SZiyuan Xu return 0; 7169e8ce816SZiyuan Xu } 7179e8ce816SZiyuan Xu 71855e5defdSZiyuan Xu do { 7199e8ce816SZiyuan Xu if (!send_status) { 72055e5defdSZiyuan Xu busy = mmc_card_busy(mmc); 72155e5defdSZiyuan Xu } else { 72255e5defdSZiyuan Xu ret = mmc_send_cmd(mmc, &cmd, NULL); 72355e5defdSZiyuan Xu 72455e5defdSZiyuan Xu if (ret) 72555e5defdSZiyuan Xu return ret; 72655e5defdSZiyuan Xu 72755e5defdSZiyuan Xu if (cmd.response[0] & MMC_STATUS_SWITCH_ERROR) 72855e5defdSZiyuan Xu return -EBADMSG; 72955e5defdSZiyuan Xu busy = (cmd.response[0] & MMC_STATUS_CURR_STATE) == 73055e5defdSZiyuan Xu MMC_STATE_PRG; 73155e5defdSZiyuan Xu } 73255e5defdSZiyuan Xu 73355e5defdSZiyuan Xu if (get_timer(start) > timeout && busy) 73455e5defdSZiyuan Xu return -ETIMEDOUT; 73555e5defdSZiyuan Xu } while (busy); 73655e5defdSZiyuan Xu 73755e5defdSZiyuan Xu return 0; 73855e5defdSZiyuan Xu } 73955e5defdSZiyuan Xu 74055e5defdSZiyuan Xu static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value, 74155e5defdSZiyuan Xu u8 send_status) 74255e5defdSZiyuan Xu { 74355e5defdSZiyuan Xu struct mmc_cmd cmd; 744a9003dc6SMaxime Ripard int retries = 3; 7455d4fc8d9SRaffaele Recalcati int ret; 746272cc70bSAndy Fleming 747272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SWITCH; 748272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 749272cc70bSAndy Fleming cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 750272cc70bSAndy Fleming (index << 16) | 751272cc70bSAndy Fleming (value << 8); 752272cc70bSAndy Fleming 75355e5defdSZiyuan Xu do { 7545d4fc8d9SRaffaele Recalcati ret = mmc_send_cmd(mmc, &cmd, NULL); 7555d4fc8d9SRaffaele Recalcati 7569e8ce816SZiyuan Xu if (!ret) 7579e8ce816SZiyuan Xu return mmc_poll_for_busy(mmc, send_status); 75855e5defdSZiyuan Xu } while (--retries > 0 && ret); 75955e5defdSZiyuan Xu 760a9003dc6SMaxime Ripard return ret; 761a9003dc6SMaxime Ripard } 762a9003dc6SMaxime Ripard 76355e5defdSZiyuan Xu int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) 76455e5defdSZiyuan Xu { 76555e5defdSZiyuan Xu return __mmc_switch(mmc, set, index, value, true); 766272cc70bSAndy Fleming } 767272cc70bSAndy Fleming 76849dba033SZiyuan Xu static int mmc_select_bus_width(struct mmc *mmc) 76949dba033SZiyuan Xu { 77049dba033SZiyuan Xu u32 ext_csd_bits[] = { 77149dba033SZiyuan Xu EXT_CSD_BUS_WIDTH_8, 77249dba033SZiyuan Xu EXT_CSD_BUS_WIDTH_4, 77349dba033SZiyuan Xu }; 77449dba033SZiyuan Xu u32 bus_widths[] = { 77549dba033SZiyuan Xu MMC_BUS_WIDTH_8BIT, 77649dba033SZiyuan Xu MMC_BUS_WIDTH_4BIT, 77749dba033SZiyuan Xu }; 77849dba033SZiyuan Xu ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 77949dba033SZiyuan Xu ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 78049dba033SZiyuan Xu u32 idx, bus_width = 0; 78149dba033SZiyuan Xu int err = 0; 78249dba033SZiyuan Xu 78349dba033SZiyuan Xu if (mmc->version < MMC_VERSION_4 || 78449dba033SZiyuan Xu !(mmc->cfg->host_caps & (MMC_MODE_4BIT | MMC_MODE_8BIT))) 78549dba033SZiyuan Xu return 0; 78649dba033SZiyuan Xu 78749dba033SZiyuan Xu err = mmc_send_ext_csd(mmc, ext_csd); 78849dba033SZiyuan Xu 78949dba033SZiyuan Xu if (err) 79049dba033SZiyuan Xu return err; 79149dba033SZiyuan Xu 79249dba033SZiyuan Xu idx = (mmc->cfg->host_caps & MMC_MODE_8BIT) ? 0 : 1; 79349dba033SZiyuan Xu 79449dba033SZiyuan Xu /* 79549dba033SZiyuan Xu * Unlike SD, MMC cards dont have a configuration register to notify 79649dba033SZiyuan Xu * supported bus width. So bus test command should be run to identify 79749dba033SZiyuan Xu * the supported bus width or compare the ext csd values of current 79849dba033SZiyuan Xu * bus width and ext csd values of 1 bit mode read earlier. 79949dba033SZiyuan Xu */ 80049dba033SZiyuan Xu for (; idx < ARRAY_SIZE(bus_widths); idx++) { 80149dba033SZiyuan Xu /* 80249dba033SZiyuan Xu * Host is capable of 8bit transfer, then switch 80349dba033SZiyuan Xu * the device to work in 8bit transfer mode. If the 80449dba033SZiyuan Xu * mmc switch command returns error then switch to 80549dba033SZiyuan Xu * 4bit transfer mode. On success set the corresponding 80649dba033SZiyuan Xu * bus width on the host. 80749dba033SZiyuan Xu */ 80849dba033SZiyuan Xu err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 80949dba033SZiyuan Xu EXT_CSD_BUS_WIDTH, ext_csd_bits[idx]); 81049dba033SZiyuan Xu if (err) 81149dba033SZiyuan Xu continue; 81249dba033SZiyuan Xu 81349dba033SZiyuan Xu bus_width = bus_widths[idx]; 81449dba033SZiyuan Xu mmc_set_bus_width(mmc, bus_width); 81549dba033SZiyuan Xu 81649dba033SZiyuan Xu err = mmc_send_ext_csd(mmc, test_csd); 81749dba033SZiyuan Xu 81849dba033SZiyuan Xu if (err) 81949dba033SZiyuan Xu continue; 82049dba033SZiyuan Xu 82149dba033SZiyuan Xu /* Only compare read only fields */ 82249dba033SZiyuan Xu if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] == 82349dba033SZiyuan Xu test_csd[EXT_CSD_PARTITIONING_SUPPORT]) && 82449dba033SZiyuan Xu (ext_csd[EXT_CSD_HC_WP_GRP_SIZE] == 82549dba033SZiyuan Xu test_csd[EXT_CSD_HC_WP_GRP_SIZE]) && 82649dba033SZiyuan Xu (ext_csd[EXT_CSD_REV] == test_csd[EXT_CSD_REV]) && 82749dba033SZiyuan Xu (ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] == 82849dba033SZiyuan Xu test_csd[EXT_CSD_HC_ERASE_GRP_SIZE]) && 82949dba033SZiyuan Xu !memcmp(&ext_csd[EXT_CSD_SEC_CNT], 83049dba033SZiyuan Xu &test_csd[EXT_CSD_SEC_CNT], 4)) { 83149dba033SZiyuan Xu err = bus_width; 83249dba033SZiyuan Xu break; 83349dba033SZiyuan Xu } else { 83449dba033SZiyuan Xu err = -EBADMSG; 83549dba033SZiyuan Xu } 83649dba033SZiyuan Xu } 83749dba033SZiyuan Xu 83849dba033SZiyuan Xu return err; 83949dba033SZiyuan Xu } 84049dba033SZiyuan Xu 84149dba033SZiyuan Xu static const u8 tuning_blk_pattern_4bit[] = { 84249dba033SZiyuan Xu 0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc, 84349dba033SZiyuan Xu 0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef, 84449dba033SZiyuan Xu 0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb, 84549dba033SZiyuan Xu 0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef, 84649dba033SZiyuan Xu 0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c, 84749dba033SZiyuan Xu 0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee, 84849dba033SZiyuan Xu 0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff, 84949dba033SZiyuan Xu 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde, 85049dba033SZiyuan Xu }; 85149dba033SZiyuan Xu 85249dba033SZiyuan Xu static const u8 tuning_blk_pattern_8bit[] = { 85349dba033SZiyuan Xu 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 85449dba033SZiyuan Xu 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc, 85549dba033SZiyuan Xu 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff, 85649dba033SZiyuan Xu 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff, 85749dba033SZiyuan Xu 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd, 85849dba033SZiyuan Xu 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, 85949dba033SZiyuan Xu 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff, 86049dba033SZiyuan Xu 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff, 86149dba033SZiyuan Xu 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 86249dba033SZiyuan Xu 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 86349dba033SZiyuan Xu 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 86449dba033SZiyuan Xu 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 86549dba033SZiyuan Xu 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 86649dba033SZiyuan Xu 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 86749dba033SZiyuan Xu 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 86849dba033SZiyuan Xu 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 86949dba033SZiyuan Xu }; 87049dba033SZiyuan Xu 87149dba033SZiyuan Xu int mmc_send_tuning(struct mmc *mmc, u32 opcode) 87249dba033SZiyuan Xu { 87349dba033SZiyuan Xu struct mmc_cmd cmd; 87449dba033SZiyuan Xu struct mmc_data data; 87549dba033SZiyuan Xu const u8 *tuning_block_pattern; 87649dba033SZiyuan Xu int size, err = 0; 87749dba033SZiyuan Xu u8 *data_buf; 87849dba033SZiyuan Xu 87949dba033SZiyuan Xu if (mmc->bus_width == MMC_BUS_WIDTH_8BIT) { 88049dba033SZiyuan Xu tuning_block_pattern = tuning_blk_pattern_8bit; 88149dba033SZiyuan Xu size = sizeof(tuning_blk_pattern_8bit); 88249dba033SZiyuan Xu } else if (mmc->bus_width == MMC_BUS_WIDTH_4BIT) { 88349dba033SZiyuan Xu tuning_block_pattern = tuning_blk_pattern_4bit; 88449dba033SZiyuan Xu size = sizeof(tuning_blk_pattern_4bit); 88549dba033SZiyuan Xu } else { 88649dba033SZiyuan Xu return -EINVAL; 88749dba033SZiyuan Xu } 88849dba033SZiyuan Xu 88949dba033SZiyuan Xu data_buf = calloc(1, size); 89049dba033SZiyuan Xu if (!data_buf) 89149dba033SZiyuan Xu return -ENOMEM; 89249dba033SZiyuan Xu 89349dba033SZiyuan Xu cmd.cmdidx = opcode; 89449dba033SZiyuan Xu cmd.resp_type = MMC_RSP_R1; 89549dba033SZiyuan Xu cmd.cmdarg = 0; 89649dba033SZiyuan Xu 89749dba033SZiyuan Xu data.dest = (char *)data_buf; 89849dba033SZiyuan Xu data.blocksize = size; 89949dba033SZiyuan Xu data.blocks = 1; 90049dba033SZiyuan Xu data.flags = MMC_DATA_READ; 90149dba033SZiyuan Xu 90249dba033SZiyuan Xu err = mmc_send_cmd(mmc, &cmd, &data); 90349dba033SZiyuan Xu if (err) 90449dba033SZiyuan Xu goto out; 90549dba033SZiyuan Xu 90649dba033SZiyuan Xu if (memcmp(data_buf, tuning_block_pattern, size)) 90749dba033SZiyuan Xu err = -EIO; 90849dba033SZiyuan Xu out: 90949dba033SZiyuan Xu free(data_buf); 91049dba033SZiyuan Xu return err; 91149dba033SZiyuan Xu } 91249dba033SZiyuan Xu 91349dba033SZiyuan Xu static int mmc_execute_tuning(struct mmc *mmc) 91449dba033SZiyuan Xu { 91549dba033SZiyuan Xu #ifdef CONFIG_DM_MMC 91649dba033SZiyuan Xu struct dm_mmc_ops *ops = mmc_get_ops(mmc->dev); 91749dba033SZiyuan Xu #endif 91849dba033SZiyuan Xu u32 opcode; 91949dba033SZiyuan Xu 92049dba033SZiyuan Xu if (IS_SD(mmc)) 92149dba033SZiyuan Xu opcode = MMC_SEND_TUNING_BLOCK; 92249dba033SZiyuan Xu else 92349dba033SZiyuan Xu opcode = MMC_SEND_TUNING_BLOCK_HS200; 92449dba033SZiyuan Xu 92549dba033SZiyuan Xu #ifndef CONFIG_DM_MMC 92649dba033SZiyuan Xu if (mmc->cfg->ops->execute_tuning) { 92749dba033SZiyuan Xu return mmc->cfg->ops->execute_tuning(mmc, opcode); 92849dba033SZiyuan Xu #else 92949dba033SZiyuan Xu if (ops->execute_tuning) { 93049dba033SZiyuan Xu return ops->execute_tuning(mmc->dev, opcode); 93149dba033SZiyuan Xu #endif 93249dba033SZiyuan Xu } else { 93349dba033SZiyuan Xu debug("Tuning feature required for HS200 mode.\n"); 93449dba033SZiyuan Xu return -EIO; 93549dba033SZiyuan Xu } 93649dba033SZiyuan Xu } 93749dba033SZiyuan Xu 93849dba033SZiyuan Xu static int mmc_hs200_tuning(struct mmc *mmc) 93949dba033SZiyuan Xu { 94049dba033SZiyuan Xu return mmc_execute_tuning(mmc); 94149dba033SZiyuan Xu } 94249dba033SZiyuan Xu 943e61cd3d7SZiyuan Xu static int mmc_select_hs(struct mmc *mmc) 944e61cd3d7SZiyuan Xu { 945e61cd3d7SZiyuan Xu int ret; 946e61cd3d7SZiyuan Xu 947e61cd3d7SZiyuan Xu ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 948e61cd3d7SZiyuan Xu EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS); 949e61cd3d7SZiyuan Xu 950e61cd3d7SZiyuan Xu if (!ret) 951e61cd3d7SZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_MMC_HS); 952e61cd3d7SZiyuan Xu 953e61cd3d7SZiyuan Xu return ret; 954e61cd3d7SZiyuan Xu } 955e61cd3d7SZiyuan Xu 9565545757fSZiyuan Xu static int mmc_select_hs_ddr(struct mmc *mmc) 9575545757fSZiyuan Xu { 9585545757fSZiyuan Xu u32 ext_csd_bits; 9595545757fSZiyuan Xu int err = 0; 9605545757fSZiyuan Xu 9615545757fSZiyuan Xu if (mmc->bus_width == MMC_BUS_WIDTH_1BIT) 9625545757fSZiyuan Xu return 0; 9635545757fSZiyuan Xu 9645545757fSZiyuan Xu ext_csd_bits = (mmc->bus_width == MMC_BUS_WIDTH_8BIT) ? 9655545757fSZiyuan Xu EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4; 9665545757fSZiyuan Xu 9675545757fSZiyuan Xu err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 9685545757fSZiyuan Xu EXT_CSD_BUS_WIDTH, ext_csd_bits); 9695545757fSZiyuan Xu if (err) 9705545757fSZiyuan Xu return err; 9715545757fSZiyuan Xu 9725545757fSZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_MMC_DDR52); 9735545757fSZiyuan Xu 9745545757fSZiyuan Xu return 0; 9755545757fSZiyuan Xu } 9765545757fSZiyuan Xu 97749dba033SZiyuan Xu static int mmc_select_hs200(struct mmc *mmc) 97849dba033SZiyuan Xu { 97949dba033SZiyuan Xu int ret; 98049dba033SZiyuan Xu 98149dba033SZiyuan Xu /* 98249dba033SZiyuan Xu * Set the bus width(4 or 8) with host's support and 98349dba033SZiyuan Xu * switch to HS200 mode if bus width is set successfully. 98449dba033SZiyuan Xu */ 98549dba033SZiyuan Xu ret = mmc_select_bus_width(mmc); 98649dba033SZiyuan Xu 98749dba033SZiyuan Xu if (ret > 0) { 98849dba033SZiyuan Xu ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 98949dba033SZiyuan Xu EXT_CSD_HS_TIMING, 99049dba033SZiyuan Xu EXT_CSD_TIMING_HS200, false); 99149dba033SZiyuan Xu 99249dba033SZiyuan Xu if (ret) 99349dba033SZiyuan Xu return ret; 99449dba033SZiyuan Xu 99549dba033SZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_MMC_HS200); 99649dba033SZiyuan Xu } 99749dba033SZiyuan Xu 99849dba033SZiyuan Xu return ret; 99949dba033SZiyuan Xu } 100049dba033SZiyuan Xu 1001b673f29aSZiyuan Xu static int mmc_select_hs400(struct mmc *mmc) 1002b673f29aSZiyuan Xu { 1003b673f29aSZiyuan Xu int ret; 1004b673f29aSZiyuan Xu 1005*e56bff5bSJason Zhu /* Reduce frequency to HS frequency */ 1006*e56bff5bSJason Zhu mmc_set_clock(mmc, MMC_HIGH_52_MAX_DTR); 1007*e56bff5bSJason Zhu 1008b673f29aSZiyuan Xu /* Switch card to HS mode */ 1009b673f29aSZiyuan Xu ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1010b673f29aSZiyuan Xu EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS, false); 1011b673f29aSZiyuan Xu if (ret) 1012b673f29aSZiyuan Xu return ret; 1013b673f29aSZiyuan Xu 1014b673f29aSZiyuan Xu /* Set host controller to HS timing */ 1015b673f29aSZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_MMC_HS); 1016b673f29aSZiyuan Xu 1017b673f29aSZiyuan Xu ret = mmc_send_status(mmc, 1000); 1018b673f29aSZiyuan Xu if (ret) 1019b673f29aSZiyuan Xu return ret; 1020b673f29aSZiyuan Xu 1021b673f29aSZiyuan Xu /* Switch card to DDR */ 1022b673f29aSZiyuan Xu ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1023b673f29aSZiyuan Xu EXT_CSD_BUS_WIDTH, 1024b673f29aSZiyuan Xu EXT_CSD_DDR_BUS_WIDTH_8); 1025b673f29aSZiyuan Xu if (ret) 1026b673f29aSZiyuan Xu return ret; 1027b673f29aSZiyuan Xu 1028b673f29aSZiyuan Xu /* Switch card to HS400 */ 1029b673f29aSZiyuan Xu ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1030b673f29aSZiyuan Xu EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400, false); 1031b673f29aSZiyuan Xu if (ret) 1032b673f29aSZiyuan Xu return ret; 1033b673f29aSZiyuan Xu 1034b673f29aSZiyuan Xu /* Set host controller to HS400 timing and frequency */ 1035b673f29aSZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_MMC_HS400); 1036b673f29aSZiyuan Xu 1037b673f29aSZiyuan Xu return ret; 1038b673f29aSZiyuan Xu } 1039b673f29aSZiyuan Xu 1040227f658eSZiyuan Xu static u32 mmc_select_card_type(struct mmc *mmc, u8 *ext_csd) 1041227f658eSZiyuan Xu { 1042227f658eSZiyuan Xu u8 card_type; 1043227f658eSZiyuan Xu u32 host_caps, avail_type = 0; 1044227f658eSZiyuan Xu 1045227f658eSZiyuan Xu card_type = ext_csd[EXT_CSD_CARD_TYPE]; 1046227f658eSZiyuan Xu host_caps = mmc->cfg->host_caps; 1047227f658eSZiyuan Xu 1048227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS) && 1049227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_26)) 1050227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_26; 1051227f658eSZiyuan Xu 1052227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS) && 1053227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_52)) 1054227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_52; 1055227f658eSZiyuan Xu 1056227f658eSZiyuan Xu /* 1057227f658eSZiyuan Xu * For the moment, u-boot doesn't support signal voltage 1058227f658eSZiyuan Xu * switch, therefor we assume that host support ddr52 1059227f658eSZiyuan Xu * at 1.8v or 3.3v I/O(1.2v I/O not supported, hs200 and 1060227f658eSZiyuan Xu * hs400 are the same). 1061227f658eSZiyuan Xu */ 1062227f658eSZiyuan Xu if ((host_caps & MMC_MODE_DDR_52MHz) && 1063227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)) 1064227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V; 1065227f658eSZiyuan Xu 1066227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS200) && 1067227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_HS200_1_8V)) 1068227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V; 1069227f658eSZiyuan Xu 1070227f658eSZiyuan Xu /* 1071227f658eSZiyuan Xu * If host can support HS400, it means that host can also 1072227f658eSZiyuan Xu * support HS200. 1073227f658eSZiyuan Xu */ 1074227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS400) && 1075227f658eSZiyuan Xu (host_caps & MMC_MODE_8BIT) && 1076227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_HS400_1_8V)) 1077227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V | 1078227f658eSZiyuan Xu EXT_CSD_CARD_TYPE_HS400_1_8V; 1079227f658eSZiyuan Xu 1080227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS400ES) && 1081227f658eSZiyuan Xu (host_caps & MMC_MODE_8BIT) && 1082227f658eSZiyuan Xu ext_csd[EXT_CSD_STROBE_SUPPORT] && 1083227f658eSZiyuan Xu (avail_type & EXT_CSD_CARD_TYPE_HS400_1_8V)) 1084227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V | 1085227f658eSZiyuan Xu EXT_CSD_CARD_TYPE_HS400_1_8V | 1086227f658eSZiyuan Xu EXT_CSD_CARD_TYPE_HS400ES; 1087227f658eSZiyuan Xu 1088227f658eSZiyuan Xu return avail_type; 1089227f658eSZiyuan Xu } 1090227f658eSZiyuan Xu 109149dba033SZiyuan Xu static void mmc_set_bus_speed(struct mmc *mmc, u8 avail_type) 109249dba033SZiyuan Xu { 109349dba033SZiyuan Xu int clock = 0; 109449dba033SZiyuan Xu 109549dba033SZiyuan Xu if (mmc_card_hs(mmc)) 109649dba033SZiyuan Xu clock = (avail_type & EXT_CSD_CARD_TYPE_52) ? 109749dba033SZiyuan Xu MMC_HIGH_52_MAX_DTR : MMC_HIGH_26_MAX_DTR; 109849dba033SZiyuan Xu else if (mmc_card_hs200(mmc) || 109949dba033SZiyuan Xu mmc_card_hs400(mmc) || 110049dba033SZiyuan Xu mmc_card_hs400es(mmc)) 110149dba033SZiyuan Xu clock = MMC_HS200_MAX_DTR; 110249dba033SZiyuan Xu 110349dba033SZiyuan Xu mmc_set_clock(mmc, clock); 110449dba033SZiyuan Xu } 110549dba033SZiyuan Xu 1106fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc) 1107272cc70bSAndy Fleming { 11088bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 1109227f658eSZiyuan Xu u32 avail_type; 1110272cc70bSAndy Fleming int err; 1111272cc70bSAndy Fleming 1112fc5b32fbSAndrew Gabbasov mmc->card_caps = 0; 1113272cc70bSAndy Fleming 1114d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 1115d52ebf10SThomas Chou return 0; 1116d52ebf10SThomas Chou 1117272cc70bSAndy Fleming /* Only version 4 supports high-speed */ 1118272cc70bSAndy Fleming if (mmc->version < MMC_VERSION_4) 1119272cc70bSAndy Fleming return 0; 1120272cc70bSAndy Fleming 1121fc5b32fbSAndrew Gabbasov mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; 1122fc5b32fbSAndrew Gabbasov 1123272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 1124272cc70bSAndy Fleming 1125272cc70bSAndy Fleming if (err) 1126272cc70bSAndy Fleming return err; 1127272cc70bSAndy Fleming 1128227f658eSZiyuan Xu avail_type = mmc_select_card_type(mmc, ext_csd); 1129272cc70bSAndy Fleming 113049dba033SZiyuan Xu if (avail_type & EXT_CSD_CARD_TYPE_HS200) 113149dba033SZiyuan Xu err = mmc_select_hs200(mmc); 11321f250d0aSJason Zhu else if (avail_type & EXT_CSD_CARD_TYPE_HS) 1133e61cd3d7SZiyuan Xu err = mmc_select_hs(mmc); 1134227f658eSZiyuan Xu else 1135227f658eSZiyuan Xu err = -EINVAL; 1136272cc70bSAndy Fleming 1137272cc70bSAndy Fleming if (err) 1138a5e27b41SHeiko Schocher return err; 1139272cc70bSAndy Fleming 114049dba033SZiyuan Xu mmc_set_bus_speed(mmc, avail_type); 1141272cc70bSAndy Fleming 1142b673f29aSZiyuan Xu if (mmc_card_hs200(mmc)) { 114349dba033SZiyuan Xu err = mmc_hs200_tuning(mmc); 1144b673f29aSZiyuan Xu if (avail_type & EXT_CSD_CARD_TYPE_HS400 && 1145b673f29aSZiyuan Xu mmc->bus_width == MMC_BUS_WIDTH_8BIT) { 1146b673f29aSZiyuan Xu err = mmc_select_hs400(mmc); 1147b673f29aSZiyuan Xu mmc_set_bus_speed(mmc, avail_type); 1148b673f29aSZiyuan Xu } 1149b673f29aSZiyuan Xu } else if (!mmc_card_hs400es(mmc)) { 115049dba033SZiyuan Xu err = mmc_select_bus_width(mmc) > 0 ? 0 : err; 11515545757fSZiyuan Xu if (!err && avail_type & EXT_CSD_CARD_TYPE_DDR_52) 11525545757fSZiyuan Xu err = mmc_select_hs_ddr(mmc); 11535545757fSZiyuan Xu } 115449dba033SZiyuan Xu 1155272cc70bSAndy Fleming return err; 1156272cc70bSAndy Fleming } 1157272cc70bSAndy Fleming 1158f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num) 1159f866a46dSStephen Warren { 1160f866a46dSStephen Warren switch (part_num) { 1161f866a46dSStephen Warren case 0: 1162f866a46dSStephen Warren mmc->capacity = mmc->capacity_user; 1163f866a46dSStephen Warren break; 1164f866a46dSStephen Warren case 1: 1165f866a46dSStephen Warren case 2: 1166f866a46dSStephen Warren mmc->capacity = mmc->capacity_boot; 1167f866a46dSStephen Warren break; 1168f866a46dSStephen Warren case 3: 1169f866a46dSStephen Warren mmc->capacity = mmc->capacity_rpmb; 1170f866a46dSStephen Warren break; 1171f866a46dSStephen Warren case 4: 1172f866a46dSStephen Warren case 5: 1173f866a46dSStephen Warren case 6: 1174f866a46dSStephen Warren case 7: 1175f866a46dSStephen Warren mmc->capacity = mmc->capacity_gp[part_num - 4]; 1176f866a46dSStephen Warren break; 1177f866a46dSStephen Warren default: 1178f866a46dSStephen Warren return -1; 1179f866a46dSStephen Warren } 1180f866a46dSStephen Warren 1181c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len); 1182f866a46dSStephen Warren 1183f866a46dSStephen Warren return 0; 1184f866a46dSStephen Warren } 1185f866a46dSStephen Warren 11867dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num) 1187bc897b1dSLei Wen { 1188f866a46dSStephen Warren int ret; 1189bc897b1dSLei Wen 1190f866a46dSStephen Warren ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 1191bc897b1dSLei Wen (mmc->part_config & ~PART_ACCESS_MASK) 1192bc897b1dSLei Wen | (part_num & PART_ACCESS_MASK)); 1193f866a46dSStephen Warren 11946dc93e70SPeter Bigot /* 11956dc93e70SPeter Bigot * Set the capacity if the switch succeeded or was intended 11966dc93e70SPeter Bigot * to return to representing the raw device. 11976dc93e70SPeter Bigot */ 1198873cc1d7SStephen Warren if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) { 11996dc93e70SPeter Bigot ret = mmc_set_capacity(mmc, part_num); 1200fdbb139fSSimon Glass mmc_get_blk_desc(mmc)->hwpart = part_num; 1201873cc1d7SStephen Warren } 12026dc93e70SPeter Bigot 12036dc93e70SPeter Bigot return ret; 1204bc897b1dSLei Wen } 1205bc897b1dSLei Wen 1206ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc, 1207ac9da0e0SDiego Santa Cruz const struct mmc_hwpart_conf *conf, 1208ac9da0e0SDiego Santa Cruz enum mmc_hwpart_conf_mode mode) 1209ac9da0e0SDiego Santa Cruz { 1210ac9da0e0SDiego Santa Cruz u8 part_attrs = 0; 1211ac9da0e0SDiego Santa Cruz u32 enh_size_mult; 1212ac9da0e0SDiego Santa Cruz u32 enh_start_addr; 1213ac9da0e0SDiego Santa Cruz u32 gp_size_mult[4]; 1214ac9da0e0SDiego Santa Cruz u32 max_enh_size_mult; 1215ac9da0e0SDiego Santa Cruz u32 tot_enh_size_mult = 0; 12168dda5b0eSDiego Santa Cruz u8 wr_rel_set; 1217ac9da0e0SDiego Santa Cruz int i, pidx, err; 1218ac9da0e0SDiego Santa Cruz ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 1219ac9da0e0SDiego Santa Cruz 1220ac9da0e0SDiego Santa Cruz if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE) 1221ac9da0e0SDiego Santa Cruz return -EINVAL; 1222ac9da0e0SDiego Santa Cruz 1223ac9da0e0SDiego Santa Cruz if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) { 1224ac9da0e0SDiego Santa Cruz printf("eMMC >= 4.4 required for enhanced user data area\n"); 1225ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1226ac9da0e0SDiego Santa Cruz } 1227ac9da0e0SDiego Santa Cruz 1228ac9da0e0SDiego Santa Cruz if (!(mmc->part_support & PART_SUPPORT)) { 1229ac9da0e0SDiego Santa Cruz printf("Card does not support partitioning\n"); 1230ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1231ac9da0e0SDiego Santa Cruz } 1232ac9da0e0SDiego Santa Cruz 1233ac9da0e0SDiego Santa Cruz if (!mmc->hc_wp_grp_size) { 1234ac9da0e0SDiego Santa Cruz printf("Card does not define HC WP group size\n"); 1235ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1236ac9da0e0SDiego Santa Cruz } 1237ac9da0e0SDiego Santa Cruz 1238ac9da0e0SDiego Santa Cruz /* check partition alignment and total enhanced size */ 1239ac9da0e0SDiego Santa Cruz if (conf->user.enh_size) { 1240ac9da0e0SDiego Santa Cruz if (conf->user.enh_size % mmc->hc_wp_grp_size || 1241ac9da0e0SDiego Santa Cruz conf->user.enh_start % mmc->hc_wp_grp_size) { 1242ac9da0e0SDiego Santa Cruz printf("User data enhanced area not HC WP group " 1243ac9da0e0SDiego Santa Cruz "size aligned\n"); 1244ac9da0e0SDiego Santa Cruz return -EINVAL; 1245ac9da0e0SDiego Santa Cruz } 1246ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_USR; 1247ac9da0e0SDiego Santa Cruz enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size; 1248ac9da0e0SDiego Santa Cruz if (mmc->high_capacity) { 1249ac9da0e0SDiego Santa Cruz enh_start_addr = conf->user.enh_start; 1250ac9da0e0SDiego Santa Cruz } else { 1251ac9da0e0SDiego Santa Cruz enh_start_addr = (conf->user.enh_start << 9); 1252ac9da0e0SDiego Santa Cruz } 1253ac9da0e0SDiego Santa Cruz } else { 1254ac9da0e0SDiego Santa Cruz enh_size_mult = 0; 1255ac9da0e0SDiego Santa Cruz enh_start_addr = 0; 1256ac9da0e0SDiego Santa Cruz } 1257ac9da0e0SDiego Santa Cruz tot_enh_size_mult += enh_size_mult; 1258ac9da0e0SDiego Santa Cruz 1259ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 1260ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) { 1261ac9da0e0SDiego Santa Cruz printf("GP%i partition not HC WP group size " 1262ac9da0e0SDiego Santa Cruz "aligned\n", pidx+1); 1263ac9da0e0SDiego Santa Cruz return -EINVAL; 1264ac9da0e0SDiego Santa Cruz } 1265ac9da0e0SDiego Santa Cruz gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size; 1266ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) { 1267ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_GP(pidx); 1268ac9da0e0SDiego Santa Cruz tot_enh_size_mult += gp_size_mult[pidx]; 1269ac9da0e0SDiego Santa Cruz } 1270ac9da0e0SDiego Santa Cruz } 1271ac9da0e0SDiego Santa Cruz 1272ac9da0e0SDiego Santa Cruz if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) { 1273ac9da0e0SDiego Santa Cruz printf("Card does not support enhanced attribute\n"); 1274ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1275ac9da0e0SDiego Santa Cruz } 1276ac9da0e0SDiego Santa Cruz 1277ac9da0e0SDiego Santa Cruz err = mmc_send_ext_csd(mmc, ext_csd); 1278ac9da0e0SDiego Santa Cruz if (err) 1279ac9da0e0SDiego Santa Cruz return err; 1280ac9da0e0SDiego Santa Cruz 1281ac9da0e0SDiego Santa Cruz max_enh_size_mult = 1282ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) + 1283ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) + 1284ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]; 1285ac9da0e0SDiego Santa Cruz if (tot_enh_size_mult > max_enh_size_mult) { 1286ac9da0e0SDiego Santa Cruz printf("Total enhanced size exceeds maximum (%u > %u)\n", 1287ac9da0e0SDiego Santa Cruz tot_enh_size_mult, max_enh_size_mult); 1288ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1289ac9da0e0SDiego Santa Cruz } 1290ac9da0e0SDiego Santa Cruz 12918dda5b0eSDiego Santa Cruz /* The default value of EXT_CSD_WR_REL_SET is device 12928dda5b0eSDiego Santa Cruz * dependent, the values can only be changed if the 12938dda5b0eSDiego Santa Cruz * EXT_CSD_HS_CTRL_REL bit is set. The values can be 12948dda5b0eSDiego Santa Cruz * changed only once and before partitioning is completed. */ 12958dda5b0eSDiego Santa Cruz wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 12968dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_change) { 12978dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_set) 12988dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_USR; 12998dda5b0eSDiego Santa Cruz else 13008dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR; 13018dda5b0eSDiego Santa Cruz } 13028dda5b0eSDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 13038dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_change) { 13048dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_set) 13058dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx); 13068dda5b0eSDiego Santa Cruz else 13078dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx); 13088dda5b0eSDiego Santa Cruz } 13098dda5b0eSDiego Santa Cruz } 13108dda5b0eSDiego Santa Cruz 13118dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] && 13128dda5b0eSDiego Santa Cruz !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) { 13138dda5b0eSDiego Santa Cruz puts("Card does not support host controlled partition write " 13148dda5b0eSDiego Santa Cruz "reliability settings\n"); 13158dda5b0eSDiego Santa Cruz return -EMEDIUMTYPE; 13168dda5b0eSDiego Santa Cruz } 13178dda5b0eSDiego Santa Cruz 1318ac9da0e0SDiego Santa Cruz if (ext_csd[EXT_CSD_PARTITION_SETTING] & 1319ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED) { 1320ac9da0e0SDiego Santa Cruz printf("Card already partitioned\n"); 1321ac9da0e0SDiego Santa Cruz return -EPERM; 1322ac9da0e0SDiego Santa Cruz } 1323ac9da0e0SDiego Santa Cruz 1324ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_CHECK) 1325ac9da0e0SDiego Santa Cruz return 0; 1326ac9da0e0SDiego Santa Cruz 1327ac9da0e0SDiego Santa Cruz /* Partitioning requires high-capacity size definitions */ 1328ac9da0e0SDiego Santa Cruz if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) { 1329ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1330ac9da0e0SDiego Santa Cruz EXT_CSD_ERASE_GROUP_DEF, 1); 1331ac9da0e0SDiego Santa Cruz 1332ac9da0e0SDiego Santa Cruz if (err) 1333ac9da0e0SDiego Santa Cruz return err; 1334ac9da0e0SDiego Santa Cruz 1335ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 1336ac9da0e0SDiego Santa Cruz 1337ac9da0e0SDiego Santa Cruz /* update erase group size to be high-capacity */ 1338ac9da0e0SDiego Santa Cruz mmc->erase_grp_size = 1339ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 1340ac9da0e0SDiego Santa Cruz 1341ac9da0e0SDiego Santa Cruz } 1342ac9da0e0SDiego Santa Cruz 1343ac9da0e0SDiego Santa Cruz /* all OK, write the configuration */ 1344ac9da0e0SDiego Santa Cruz for (i = 0; i < 4; i++) { 1345ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1346ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_START_ADDR+i, 1347ac9da0e0SDiego Santa Cruz (enh_start_addr >> (i*8)) & 0xFF); 1348ac9da0e0SDiego Santa Cruz if (err) 1349ac9da0e0SDiego Santa Cruz return err; 1350ac9da0e0SDiego Santa Cruz } 1351ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 1352ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1353ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_SIZE_MULT+i, 1354ac9da0e0SDiego Santa Cruz (enh_size_mult >> (i*8)) & 0xFF); 1355ac9da0e0SDiego Santa Cruz if (err) 1356ac9da0e0SDiego Santa Cruz return err; 1357ac9da0e0SDiego Santa Cruz } 1358ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 1359ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 1360ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1361ac9da0e0SDiego Santa Cruz EXT_CSD_GP_SIZE_MULT+pidx*3+i, 1362ac9da0e0SDiego Santa Cruz (gp_size_mult[pidx] >> (i*8)) & 0xFF); 1363ac9da0e0SDiego Santa Cruz if (err) 1364ac9da0e0SDiego Santa Cruz return err; 1365ac9da0e0SDiego Santa Cruz } 1366ac9da0e0SDiego Santa Cruz } 1367ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1368ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs); 1369ac9da0e0SDiego Santa Cruz if (err) 1370ac9da0e0SDiego Santa Cruz return err; 1371ac9da0e0SDiego Santa Cruz 1372ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_SET) 1373ac9da0e0SDiego Santa Cruz return 0; 1374ac9da0e0SDiego Santa Cruz 13758dda5b0eSDiego Santa Cruz /* The WR_REL_SET is a write-once register but shall be 13768dda5b0eSDiego Santa Cruz * written before setting PART_SETTING_COMPLETED. As it is 13778dda5b0eSDiego Santa Cruz * write-once we can only write it when completing the 13788dda5b0eSDiego Santa Cruz * partitioning. */ 13798dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) { 13808dda5b0eSDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 13818dda5b0eSDiego Santa Cruz EXT_CSD_WR_REL_SET, wr_rel_set); 13828dda5b0eSDiego Santa Cruz if (err) 13838dda5b0eSDiego Santa Cruz return err; 13848dda5b0eSDiego Santa Cruz } 13858dda5b0eSDiego Santa Cruz 1386ac9da0e0SDiego Santa Cruz /* Setting PART_SETTING_COMPLETED confirms the partition 1387ac9da0e0SDiego Santa Cruz * configuration but it only becomes effective after power 1388ac9da0e0SDiego Santa Cruz * cycle, so we do not adjust the partition related settings 1389ac9da0e0SDiego Santa Cruz * in the mmc struct. */ 1390ac9da0e0SDiego Santa Cruz 1391ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1392ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING, 1393ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 1394ac9da0e0SDiego Santa Cruz if (err) 1395ac9da0e0SDiego Santa Cruz return err; 1396ac9da0e0SDiego Santa Cruz 1397ac9da0e0SDiego Santa Cruz return 0; 1398ac9da0e0SDiego Santa Cruz } 1399ac9da0e0SDiego Santa Cruz 1400e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 140148972d90SThierry Reding int mmc_getcd(struct mmc *mmc) 140248972d90SThierry Reding { 140348972d90SThierry Reding int cd; 140448972d90SThierry Reding 140548972d90SThierry Reding cd = board_mmc_getcd(mmc); 140648972d90SThierry Reding 1407d4e1da4eSPeter Korsgaard if (cd < 0) { 140893bfd616SPantelis Antoniou if (mmc->cfg->ops->getcd) 140993bfd616SPantelis Antoniou cd = mmc->cfg->ops->getcd(mmc); 1410d4e1da4eSPeter Korsgaard else 1411d4e1da4eSPeter Korsgaard cd = 1; 1412d4e1da4eSPeter Korsgaard } 141348972d90SThierry Reding 141448972d90SThierry Reding return cd; 141548972d90SThierry Reding } 14168ca51e51SSimon Glass #endif 141748972d90SThierry Reding 1418fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) 1419272cc70bSAndy Fleming { 1420272cc70bSAndy Fleming struct mmc_cmd cmd; 1421272cc70bSAndy Fleming struct mmc_data data; 1422272cc70bSAndy Fleming 1423272cc70bSAndy Fleming /* Switch the frequency */ 1424272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC; 1425272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1426272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff; 1427272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4)); 1428272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4); 1429272cc70bSAndy Fleming 1430272cc70bSAndy Fleming data.dest = (char *)resp; 1431272cc70bSAndy Fleming data.blocksize = 64; 1432272cc70bSAndy Fleming data.blocks = 1; 1433272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1434272cc70bSAndy Fleming 1435272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 1436272cc70bSAndy Fleming } 1437272cc70bSAndy Fleming 1438272cc70bSAndy Fleming 1439fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc) 1440272cc70bSAndy Fleming { 1441272cc70bSAndy Fleming int err; 1442272cc70bSAndy Fleming struct mmc_cmd cmd; 1443f781dd38SAnton staaf ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2); 1444f781dd38SAnton staaf ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16); 1445272cc70bSAndy Fleming struct mmc_data data; 1446272cc70bSAndy Fleming int timeout; 1447272cc70bSAndy Fleming 1448272cc70bSAndy Fleming mmc->card_caps = 0; 1449272cc70bSAndy Fleming 1450d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 1451d52ebf10SThomas Chou return 0; 1452d52ebf10SThomas Chou 1453272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */ 1454272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 1455272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1456272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1457272cc70bSAndy Fleming 1458272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1459272cc70bSAndy Fleming 1460272cc70bSAndy Fleming if (err) 1461272cc70bSAndy Fleming return err; 1462272cc70bSAndy Fleming 1463272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR; 1464272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1465272cc70bSAndy Fleming cmd.cmdarg = 0; 1466272cc70bSAndy Fleming 1467272cc70bSAndy Fleming timeout = 3; 1468272cc70bSAndy Fleming 1469272cc70bSAndy Fleming retry_scr: 1470f781dd38SAnton staaf data.dest = (char *)scr; 1471272cc70bSAndy Fleming data.blocksize = 8; 1472272cc70bSAndy Fleming data.blocks = 1; 1473272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1474272cc70bSAndy Fleming 1475272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 1476272cc70bSAndy Fleming 1477272cc70bSAndy Fleming if (err) { 1478272cc70bSAndy Fleming if (timeout--) 1479272cc70bSAndy Fleming goto retry_scr; 1480272cc70bSAndy Fleming 1481272cc70bSAndy Fleming return err; 1482272cc70bSAndy Fleming } 1483272cc70bSAndy Fleming 14844e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]); 14854e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]); 1486272cc70bSAndy Fleming 1487272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) { 1488272cc70bSAndy Fleming case 0: 1489272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1490272cc70bSAndy Fleming break; 1491272cc70bSAndy Fleming case 1: 1492272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10; 1493272cc70bSAndy Fleming break; 1494272cc70bSAndy Fleming case 2: 1495272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 14961741c64dSJaehoon Chung if ((mmc->scr[0] >> 15) & 0x1) 14971741c64dSJaehoon Chung mmc->version = SD_VERSION_3; 1498272cc70bSAndy Fleming break; 1499272cc70bSAndy Fleming default: 1500272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1501272cc70bSAndy Fleming break; 1502272cc70bSAndy Fleming } 1503272cc70bSAndy Fleming 1504b44c7083SAlagu Sankar if (mmc->scr[0] & SD_DATA_4BIT) 1505b44c7083SAlagu Sankar mmc->card_caps |= MMC_MODE_4BIT; 1506b44c7083SAlagu Sankar 1507272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */ 1508272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0) 1509272cc70bSAndy Fleming return 0; 1510272cc70bSAndy Fleming 1511272cc70bSAndy Fleming timeout = 4; 1512272cc70bSAndy Fleming while (timeout--) { 1513272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, 1514f781dd38SAnton staaf (u8 *)switch_status); 1515272cc70bSAndy Fleming 1516272cc70bSAndy Fleming if (err) 1517272cc70bSAndy Fleming return err; 1518272cc70bSAndy Fleming 1519272cc70bSAndy Fleming /* The high-speed function is busy. Try again */ 15204e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) 1521272cc70bSAndy Fleming break; 1522272cc70bSAndy Fleming } 1523272cc70bSAndy Fleming 1524272cc70bSAndy Fleming /* If high-speed isn't supported, we return */ 15254e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)) 1526272cc70bSAndy Fleming return 0; 1527272cc70bSAndy Fleming 15282c3fbf4cSMacpaul Lin /* 15292c3fbf4cSMacpaul Lin * If the host doesn't support SD_HIGHSPEED, do not switch card to 15302c3fbf4cSMacpaul Lin * HIGHSPEED mode even if the card support SD_HIGHSPPED. 15312c3fbf4cSMacpaul Lin * This can avoid furthur problem when the card runs in different 15322c3fbf4cSMacpaul Lin * mode between the host. 15332c3fbf4cSMacpaul Lin */ 153493bfd616SPantelis Antoniou if (!((mmc->cfg->host_caps & MMC_MODE_HS_52MHz) && 153593bfd616SPantelis Antoniou (mmc->cfg->host_caps & MMC_MODE_HS))) 15362c3fbf4cSMacpaul Lin return 0; 15372c3fbf4cSMacpaul Lin 1538f781dd38SAnton staaf err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status); 1539272cc70bSAndy Fleming 1540272cc70bSAndy Fleming if (err) 1541272cc70bSAndy Fleming return err; 1542272cc70bSAndy Fleming 15434e3d89baSYauhen Kharuzhy if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000) 1544272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS; 1545272cc70bSAndy Fleming 1546272cc70bSAndy Fleming return 0; 1547272cc70bSAndy Fleming } 1548272cc70bSAndy Fleming 15493697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc) 15503697e599SPeng Fan { 15513697e599SPeng Fan int err, i; 15523697e599SPeng Fan struct mmc_cmd cmd; 15533697e599SPeng Fan ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16); 15543697e599SPeng Fan struct mmc_data data; 15553697e599SPeng Fan int timeout = 3; 15563697e599SPeng Fan unsigned int au, eo, et, es; 15573697e599SPeng Fan 15583697e599SPeng Fan cmd.cmdidx = MMC_CMD_APP_CMD; 15593697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 15603697e599SPeng Fan cmd.cmdarg = mmc->rca << 16; 15613697e599SPeng Fan 15623697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, NULL); 15633697e599SPeng Fan if (err) 15643697e599SPeng Fan return err; 15653697e599SPeng Fan 15663697e599SPeng Fan cmd.cmdidx = SD_CMD_APP_SD_STATUS; 15673697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 15683697e599SPeng Fan cmd.cmdarg = 0; 15693697e599SPeng Fan 15703697e599SPeng Fan retry_ssr: 15713697e599SPeng Fan data.dest = (char *)ssr; 15723697e599SPeng Fan data.blocksize = 64; 15733697e599SPeng Fan data.blocks = 1; 15743697e599SPeng Fan data.flags = MMC_DATA_READ; 15753697e599SPeng Fan 15763697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, &data); 15773697e599SPeng Fan if (err) { 15783697e599SPeng Fan if (timeout--) 15793697e599SPeng Fan goto retry_ssr; 15803697e599SPeng Fan 15813697e599SPeng Fan return err; 15823697e599SPeng Fan } 15833697e599SPeng Fan 15843697e599SPeng Fan for (i = 0; i < 16; i++) 15853697e599SPeng Fan ssr[i] = be32_to_cpu(ssr[i]); 15863697e599SPeng Fan 15873697e599SPeng Fan au = (ssr[2] >> 12) & 0xF; 15883697e599SPeng Fan if ((au <= 9) || (mmc->version == SD_VERSION_3)) { 15893697e599SPeng Fan mmc->ssr.au = sd_au_size[au]; 15903697e599SPeng Fan es = (ssr[3] >> 24) & 0xFF; 15913697e599SPeng Fan es |= (ssr[2] & 0xFF) << 8; 15923697e599SPeng Fan et = (ssr[3] >> 18) & 0x3F; 15933697e599SPeng Fan if (es && et) { 15943697e599SPeng Fan eo = (ssr[3] >> 16) & 0x3; 15953697e599SPeng Fan mmc->ssr.erase_timeout = (et * 1000) / es; 15963697e599SPeng Fan mmc->ssr.erase_offset = eo * 1000; 15973697e599SPeng Fan } 15983697e599SPeng Fan } else { 15993697e599SPeng Fan debug("Invalid Allocation Unit Size.\n"); 16003697e599SPeng Fan } 16013697e599SPeng Fan 16023697e599SPeng Fan return 0; 16033697e599SPeng Fan } 16043697e599SPeng Fan 1605272cc70bSAndy Fleming /* frequency bases */ 1606272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */ 16075f837c2cSMike Frysinger static const int fbase[] = { 1608272cc70bSAndy Fleming 10000, 1609272cc70bSAndy Fleming 100000, 1610272cc70bSAndy Fleming 1000000, 1611272cc70bSAndy Fleming 10000000, 1612272cc70bSAndy Fleming }; 1613272cc70bSAndy Fleming 1614272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice 1615272cc70bSAndy Fleming * to platforms without floating point. 1616272cc70bSAndy Fleming */ 161761fe076fSSimon Glass static const u8 multipliers[] = { 1618272cc70bSAndy Fleming 0, /* reserved */ 1619272cc70bSAndy Fleming 10, 1620272cc70bSAndy Fleming 12, 1621272cc70bSAndy Fleming 13, 1622272cc70bSAndy Fleming 15, 1623272cc70bSAndy Fleming 20, 1624272cc70bSAndy Fleming 25, 1625272cc70bSAndy Fleming 30, 1626272cc70bSAndy Fleming 35, 1627272cc70bSAndy Fleming 40, 1628272cc70bSAndy Fleming 45, 1629272cc70bSAndy Fleming 50, 1630272cc70bSAndy Fleming 55, 1631272cc70bSAndy Fleming 60, 1632272cc70bSAndy Fleming 70, 1633272cc70bSAndy Fleming 80, 1634272cc70bSAndy Fleming }; 1635272cc70bSAndy Fleming 1636e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 1637fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc) 1638272cc70bSAndy Fleming { 163993bfd616SPantelis Antoniou if (mmc->cfg->ops->set_ios) 164093bfd616SPantelis Antoniou mmc->cfg->ops->set_ios(mmc); 1641272cc70bSAndy Fleming } 1642ad77484aSZiyuan Xu 1643ad77484aSZiyuan Xu static bool mmc_card_busy(struct mmc *mmc) 1644ad77484aSZiyuan Xu { 1645ad77484aSZiyuan Xu if (!mmc->cfg->ops->card_busy) 1646ad77484aSZiyuan Xu return -ENOSYS; 1647ad77484aSZiyuan Xu 1648ad77484aSZiyuan Xu return mmc->cfg->ops->card_busy(mmc); 1649ad77484aSZiyuan Xu } 1650ad77484aSZiyuan Xu 1651ad77484aSZiyuan Xu static bool mmc_can_card_busy(struct mmc *) 1652ad77484aSZiyuan Xu { 1653ad77484aSZiyuan Xu return !!mmc->cfg->ops->card_busy; 1654ad77484aSZiyuan Xu } 16558ca51e51SSimon Glass #endif 1656272cc70bSAndy Fleming 1657fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc) 1658272cc70bSAndy Fleming { 1659f866a46dSStephen Warren int err, i; 16603e3ff0acSZiyuan Xu uint mult, freq, tran_speed; 1661639b7827SYoshihiro Shimoda u64 cmult, csize, capacity; 1662272cc70bSAndy Fleming struct mmc_cmd cmd; 16638bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 16640c453bb7SDiego Santa Cruz bool has_parts = false; 16658a0cf490SDiego Santa Cruz bool part_completed; 1666c40fdca6SSimon Glass struct blk_desc *bdesc; 1667272cc70bSAndy Fleming 1668d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON 1669d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ 1670d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; 1671d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R1; 1672d52ebf10SThomas Chou cmd.cmdarg = 1; 1673d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 1674d52ebf10SThomas Chou 1675d52ebf10SThomas Chou if (err) 1676d52ebf10SThomas Chou return err; 1677d52ebf10SThomas Chou } 1678d52ebf10SThomas Chou #endif 1679479fbf72SJason Zhu #ifndef CONFIG_MMC_USE_PRE_CONFIG 1680272cc70bSAndy Fleming /* Put the Card in Identify Mode */ 1681d52ebf10SThomas Chou cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : 1682d52ebf10SThomas Chou MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ 1683272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1684272cc70bSAndy Fleming cmd.cmdarg = 0; 1685272cc70bSAndy Fleming 1686272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1687272cc70bSAndy Fleming 1688272cc70bSAndy Fleming if (err) 1689272cc70bSAndy Fleming return err; 1690272cc70bSAndy Fleming 1691272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16); 1692272cc70bSAndy Fleming 1693272cc70bSAndy Fleming /* 1694272cc70bSAndy Fleming * For MMC cards, set the Relative Address. 1695272cc70bSAndy Fleming * For SD cards, get the Relatvie Address. 1696272cc70bSAndy Fleming * This also puts the cards into Standby State 1697272cc70bSAndy Fleming */ 1698d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1699272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; 1700272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1701272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6; 1702272cc70bSAndy Fleming 1703272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1704272cc70bSAndy Fleming 1705272cc70bSAndy Fleming if (err) 1706272cc70bSAndy Fleming return err; 1707272cc70bSAndy Fleming 1708272cc70bSAndy Fleming if (IS_SD(mmc)) 1709998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff; 1710d52ebf10SThomas Chou } 1711479fbf72SJason Zhu #endif 1712272cc70bSAndy Fleming /* Get the Card-Specific Data */ 1713272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD; 1714272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1715272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1716272cc70bSAndy Fleming 1717272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1718272cc70bSAndy Fleming 1719272cc70bSAndy Fleming if (err) 1720272cc70bSAndy Fleming return err; 1721272cc70bSAndy Fleming 1722998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0]; 1723998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1]; 1724998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2]; 1725998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3]; 1726272cc70bSAndy Fleming 1727272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) { 17280b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf; 1729272cc70bSAndy Fleming 1730272cc70bSAndy Fleming switch (version) { 1731272cc70bSAndy Fleming case 0: 1732272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1733272cc70bSAndy Fleming break; 1734272cc70bSAndy Fleming case 1: 1735272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4; 1736272cc70bSAndy Fleming break; 1737272cc70bSAndy Fleming case 2: 1738272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2; 1739272cc70bSAndy Fleming break; 1740272cc70bSAndy Fleming case 3: 1741272cc70bSAndy Fleming mmc->version = MMC_VERSION_3; 1742272cc70bSAndy Fleming break; 1743272cc70bSAndy Fleming case 4: 1744272cc70bSAndy Fleming mmc->version = MMC_VERSION_4; 1745272cc70bSAndy Fleming break; 1746272cc70bSAndy Fleming default: 1747272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1748272cc70bSAndy Fleming break; 1749272cc70bSAndy Fleming } 1750272cc70bSAndy Fleming } 1751272cc70bSAndy Fleming 1752272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */ 17530b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)]; 17540b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; 1755272cc70bSAndy Fleming 17563e3ff0acSZiyuan Xu tran_speed = freq * mult; 1757272cc70bSAndy Fleming 1758ab71188cSMarkus Niebel mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); 1759998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); 1760272cc70bSAndy Fleming 1761272cc70bSAndy Fleming if (IS_SD(mmc)) 1762272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len; 1763272cc70bSAndy Fleming else 1764998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); 1765272cc70bSAndy Fleming 1766272cc70bSAndy Fleming if (mmc->high_capacity) { 1767272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16 1768272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16; 1769272cc70bSAndy Fleming cmult = 8; 1770272cc70bSAndy Fleming } else { 1771272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2 1772272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30; 1773272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15; 1774272cc70bSAndy Fleming } 1775272cc70bSAndy Fleming 1776f866a46dSStephen Warren mmc->capacity_user = (csize + 1) << (cmult + 2); 1777f866a46dSStephen Warren mmc->capacity_user *= mmc->read_bl_len; 1778f866a46dSStephen Warren mmc->capacity_boot = 0; 1779f866a46dSStephen Warren mmc->capacity_rpmb = 0; 1780f866a46dSStephen Warren for (i = 0; i < 4; i++) 1781f866a46dSStephen Warren mmc->capacity_gp[i] = 0; 1782272cc70bSAndy Fleming 17838bfa195eSSimon Glass if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN) 17848bfa195eSSimon Glass mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 1785272cc70bSAndy Fleming 17868bfa195eSSimon Glass if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) 17878bfa195eSSimon Glass mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 1788272cc70bSAndy Fleming 1789ab71188cSMarkus Niebel if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) { 1790ab71188cSMarkus Niebel cmd.cmdidx = MMC_CMD_SET_DSR; 1791ab71188cSMarkus Niebel cmd.cmdarg = (mmc->dsr & 0xffff) << 16; 1792ab71188cSMarkus Niebel cmd.resp_type = MMC_RSP_NONE; 1793ab71188cSMarkus Niebel if (mmc_send_cmd(mmc, &cmd, NULL)) 1794ab71188cSMarkus Niebel printf("MMC: SET_DSR failed\n"); 1795ab71188cSMarkus Niebel } 1796ab71188cSMarkus Niebel 1797272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */ 1798d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1799272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD; 1800fe8f7066SAjay Bhargav cmd.resp_type = MMC_RSP_R1; 1801272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1802272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1803272cc70bSAndy Fleming 1804272cc70bSAndy Fleming if (err) 1805272cc70bSAndy Fleming return err; 1806d52ebf10SThomas Chou } 1807272cc70bSAndy Fleming 1808e6f99a56SLei Wen /* 1809e6f99a56SLei Wen * For SD, its erase group is always one sector 1810e6f99a56SLei Wen */ 1811e6f99a56SLei Wen mmc->erase_grp_size = 1; 1812bc897b1dSLei Wen mmc->part_config = MMCPART_NOAVAILABLE; 1813d23e2c09SSukumar Ghorai if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) { 1814d23e2c09SSukumar Ghorai /* check ext_csd version and capacity */ 1815d23e2c09SSukumar Ghorai err = mmc_send_ext_csd(mmc, ext_csd); 18169cf199ebSDiego Santa Cruz if (err) 18179cf199ebSDiego Santa Cruz return err; 18189cf199ebSDiego Santa Cruz if (ext_csd[EXT_CSD_REV] >= 2) { 1819639b7827SYoshihiro Shimoda /* 1820639b7827SYoshihiro Shimoda * According to the JEDEC Standard, the value of 1821639b7827SYoshihiro Shimoda * ext_csd's capacity is valid if the value is more 1822639b7827SYoshihiro Shimoda * than 2GB 1823639b7827SYoshihiro Shimoda */ 18240560db18SLei Wen capacity = ext_csd[EXT_CSD_SEC_CNT] << 0 18250560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 18260560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 18270560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; 18288bfa195eSSimon Glass capacity *= MMC_MAX_BLOCK_LEN; 1829b1f1e821SŁukasz Majewski if ((capacity >> 20) > 2 * 1024) 1830f866a46dSStephen Warren mmc->capacity_user = capacity; 1831d23e2c09SSukumar Ghorai } 1832bc897b1dSLei Wen 183364f4a619SJaehoon Chung switch (ext_csd[EXT_CSD_REV]) { 183464f4a619SJaehoon Chung case 1: 183564f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_1; 183664f4a619SJaehoon Chung break; 183764f4a619SJaehoon Chung case 2: 183864f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_2; 183964f4a619SJaehoon Chung break; 184064f4a619SJaehoon Chung case 3: 184164f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_3; 184264f4a619SJaehoon Chung break; 184364f4a619SJaehoon Chung case 5: 184464f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_41; 184564f4a619SJaehoon Chung break; 184664f4a619SJaehoon Chung case 6: 184764f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_5; 184864f4a619SJaehoon Chung break; 1849edab723bSMarkus Niebel case 7: 1850edab723bSMarkus Niebel mmc->version = MMC_VERSION_5_0; 1851edab723bSMarkus Niebel break; 18521a3619cfSStefan Wahren case 8: 18531a3619cfSStefan Wahren mmc->version = MMC_VERSION_5_1; 18541a3619cfSStefan Wahren break; 185564f4a619SJaehoon Chung } 185664f4a619SJaehoon Chung 18578a0cf490SDiego Santa Cruz /* The partition data may be non-zero but it is only 18588a0cf490SDiego Santa Cruz * effective if PARTITION_SETTING_COMPLETED is set in 18598a0cf490SDiego Santa Cruz * EXT_CSD, so ignore any data if this bit is not set, 18608a0cf490SDiego Santa Cruz * except for enabling the high-capacity group size 18618a0cf490SDiego Santa Cruz * definition (see below). */ 18628a0cf490SDiego Santa Cruz part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] & 18638a0cf490SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 18648a0cf490SDiego Santa Cruz 18650c453bb7SDiego Santa Cruz /* store the partition info of emmc */ 18660c453bb7SDiego Santa Cruz mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT]; 18670c453bb7SDiego Santa Cruz if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || 18680c453bb7SDiego Santa Cruz ext_csd[EXT_CSD_BOOT_MULT]) 18690c453bb7SDiego Santa Cruz mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; 18708a0cf490SDiego Santa Cruz if (part_completed && 18718a0cf490SDiego Santa Cruz (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT)) 18720c453bb7SDiego Santa Cruz mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]; 1873a6a1f5f8SJason Zhu if (ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] & EXT_CSD_SEC_GB_CL_EN) 1874a6a1f5f8SJason Zhu mmc->esr.mmc_can_trim = 1; 18750c453bb7SDiego Santa Cruz 18760c453bb7SDiego Santa Cruz mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17; 18770c453bb7SDiego Santa Cruz 18780c453bb7SDiego Santa Cruz mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17; 18790c453bb7SDiego Santa Cruz 18800c453bb7SDiego Santa Cruz for (i = 0; i < 4; i++) { 18810c453bb7SDiego Santa Cruz int idx = EXT_CSD_GP_SIZE_MULT + i * 3; 18828a0cf490SDiego Santa Cruz uint mult = (ext_csd[idx + 2] << 16) + 18830c453bb7SDiego Santa Cruz (ext_csd[idx + 1] << 8) + ext_csd[idx]; 18848a0cf490SDiego Santa Cruz if (mult) 18858a0cf490SDiego Santa Cruz has_parts = true; 18868a0cf490SDiego Santa Cruz if (!part_completed) 18878a0cf490SDiego Santa Cruz continue; 18888a0cf490SDiego Santa Cruz mmc->capacity_gp[i] = mult; 18890c453bb7SDiego Santa Cruz mmc->capacity_gp[i] *= 18900c453bb7SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 18910c453bb7SDiego Santa Cruz mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1892f8e89d67SDiego Santa Cruz mmc->capacity_gp[i] <<= 19; 18930c453bb7SDiego Santa Cruz } 18940c453bb7SDiego Santa Cruz 18958a0cf490SDiego Santa Cruz if (part_completed) { 1896a7f852b6SDiego Santa Cruz mmc->enh_user_size = 1897a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_SIZE_MULT+2] << 16) + 1898a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_SIZE_MULT+1] << 8) + 1899a7f852b6SDiego Santa Cruz ext_csd[EXT_CSD_ENH_SIZE_MULT]; 1900a7f852b6SDiego Santa Cruz mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1901a7f852b6SDiego Santa Cruz mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1902a7f852b6SDiego Santa Cruz mmc->enh_user_size <<= 19; 1903a7f852b6SDiego Santa Cruz mmc->enh_user_start = 1904a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_START_ADDR+3] << 24) + 1905a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_START_ADDR+2] << 16) + 1906a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_START_ADDR+1] << 8) + 1907a7f852b6SDiego Santa Cruz ext_csd[EXT_CSD_ENH_START_ADDR]; 1908a7f852b6SDiego Santa Cruz if (mmc->high_capacity) 1909a7f852b6SDiego Santa Cruz mmc->enh_user_start <<= 9; 19108a0cf490SDiego Santa Cruz } 1911a7f852b6SDiego Santa Cruz 1912e6f99a56SLei Wen /* 19131937e5aaSOliver Metz * Host needs to enable ERASE_GRP_DEF bit if device is 19141937e5aaSOliver Metz * partitioned. This bit will be lost every time after a reset 19151937e5aaSOliver Metz * or power off. This will affect erase size. 1916e6f99a56SLei Wen */ 19178a0cf490SDiego Santa Cruz if (part_completed) 19180c453bb7SDiego Santa Cruz has_parts = true; 19191937e5aaSOliver Metz if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) && 19200c453bb7SDiego Santa Cruz (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) 19210c453bb7SDiego Santa Cruz has_parts = true; 19220c453bb7SDiego Santa Cruz if (has_parts) { 19231937e5aaSOliver Metz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 19241937e5aaSOliver Metz EXT_CSD_ERASE_GROUP_DEF, 1); 19251937e5aaSOliver Metz 19261937e5aaSOliver Metz if (err) 19271937e5aaSOliver Metz return err; 1928021a8055SHannes Petermaier else 1929021a8055SHannes Petermaier ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 1930037dc0abSDiego Santa Cruz } 19311937e5aaSOliver Metz 1932037dc0abSDiego Santa Cruz if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) { 19331937e5aaSOliver Metz /* Read out group size from ext_csd */ 19340560db18SLei Wen mmc->erase_grp_size = 1935a4ff9f83SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 1936d7b29129SMarkus Niebel /* 1937d7b29129SMarkus Niebel * if high capacity and partition setting completed 1938d7b29129SMarkus Niebel * SEC_COUNT is valid even if it is smaller than 2 GiB 1939d7b29129SMarkus Niebel * JEDEC Standard JESD84-B45, 6.2.4 1940d7b29129SMarkus Niebel */ 19418a0cf490SDiego Santa Cruz if (mmc->high_capacity && part_completed) { 1942d7b29129SMarkus Niebel capacity = (ext_csd[EXT_CSD_SEC_CNT]) | 1943d7b29129SMarkus Niebel (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) | 1944d7b29129SMarkus Niebel (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) | 1945d7b29129SMarkus Niebel (ext_csd[EXT_CSD_SEC_CNT + 3] << 24); 1946d7b29129SMarkus Niebel capacity *= MMC_MAX_BLOCK_LEN; 1947d7b29129SMarkus Niebel mmc->capacity_user = capacity; 1948d7b29129SMarkus Niebel } 19498bfa195eSSimon Glass } else { 19501937e5aaSOliver Metz /* Calculate the group size from the csd value. */ 1951e6f99a56SLei Wen int erase_gsz, erase_gmul; 1952e6f99a56SLei Wen erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; 1953e6f99a56SLei Wen erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; 1954e6f99a56SLei Wen mmc->erase_grp_size = (erase_gsz + 1) 1955e6f99a56SLei Wen * (erase_gmul + 1); 1956e6f99a56SLei Wen } 1957037dc0abSDiego Santa Cruz 1958037dc0abSDiego Santa Cruz mmc->hc_wp_grp_size = 1024 1959037dc0abSDiego Santa Cruz * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 1960037dc0abSDiego Santa Cruz * ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 19619e41a00bSDiego Santa Cruz 19629e41a00bSDiego Santa Cruz mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 1963f866a46dSStephen Warren } 1964f866a46dSStephen Warren 1965c40fdca6SSimon Glass err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart); 1966f866a46dSStephen Warren if (err) 1967f866a46dSStephen Warren return err; 1968d23e2c09SSukumar Ghorai 1969272cc70bSAndy Fleming if (IS_SD(mmc)) 1970272cc70bSAndy Fleming err = sd_change_freq(mmc); 1971272cc70bSAndy Fleming else 1972272cc70bSAndy Fleming err = mmc_change_freq(mmc); 1973272cc70bSAndy Fleming 1974272cc70bSAndy Fleming if (err) 1975272cc70bSAndy Fleming return err; 1976272cc70bSAndy Fleming 1977272cc70bSAndy Fleming /* Restrict card's capabilities by what the host can do */ 197893bfd616SPantelis Antoniou mmc->card_caps &= mmc->cfg->host_caps; 1979272cc70bSAndy Fleming 1980272cc70bSAndy Fleming if (IS_SD(mmc)) { 1981272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_4BIT) { 1982272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 1983272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1984272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1985272cc70bSAndy Fleming 1986272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1987272cc70bSAndy Fleming if (err) 1988272cc70bSAndy Fleming return err; 1989272cc70bSAndy Fleming 1990272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; 1991272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1992272cc70bSAndy Fleming cmd.cmdarg = 2; 1993272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1994272cc70bSAndy Fleming if (err) 1995272cc70bSAndy Fleming return err; 1996272cc70bSAndy Fleming 1997272cc70bSAndy Fleming mmc_set_bus_width(mmc, 4); 1998272cc70bSAndy Fleming } 1999272cc70bSAndy Fleming 20003697e599SPeng Fan err = sd_read_ssr(mmc); 20013697e599SPeng Fan if (err) 20023697e599SPeng Fan return err; 20033697e599SPeng Fan 2004272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS) 2005fe414819SJason Zhu tran_speed = MMC_HIGH_52_MAX_DTR; 2006272cc70bSAndy Fleming else 2007fe414819SJason Zhu tran_speed = MMC_HIGH_26_MAX_DTR; 2008ad5fd922SJaehoon Chung 20093e3ff0acSZiyuan Xu mmc_set_clock(mmc, tran_speed); 201049dba033SZiyuan Xu } 2011272cc70bSAndy Fleming 20125af8f45cSAndrew Gabbasov /* Fix the block length for DDR mode */ 201349dba033SZiyuan Xu if (mmc_card_ddr(mmc)) { 20145af8f45cSAndrew Gabbasov mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 20155af8f45cSAndrew Gabbasov mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 20165af8f45cSAndrew Gabbasov } 20175af8f45cSAndrew Gabbasov 2018272cc70bSAndy Fleming /* fill in device description */ 2019c40fdca6SSimon Glass bdesc = mmc_get_blk_desc(mmc); 2020c40fdca6SSimon Glass bdesc->lun = 0; 2021c40fdca6SSimon Glass bdesc->hwpart = 0; 2022c40fdca6SSimon Glass bdesc->type = 0; 2023c40fdca6SSimon Glass bdesc->blksz = mmc->read_bl_len; 2024c40fdca6SSimon Glass bdesc->log2blksz = LOG2(bdesc->blksz); 2025c40fdca6SSimon Glass bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len); 2026fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \ 2027fc011f64SSjoerd Simons (defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \ 2028fc011f64SSjoerd Simons !defined(CONFIG_USE_TINY_PRINTF)) 2029c40fdca6SSimon Glass sprintf(bdesc->vendor, "Man %06x Snr %04x%04x", 2030babce5f6STaylor Hutt mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), 2031babce5f6STaylor Hutt (mmc->cid[3] >> 16) & 0xffff); 2032c40fdca6SSimon Glass sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff, 20330b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 2034babce5f6STaylor Hutt (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff, 2035babce5f6STaylor Hutt (mmc->cid[2] >> 24) & 0xff); 2036c40fdca6SSimon Glass sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf, 2037babce5f6STaylor Hutt (mmc->cid[2] >> 16) & 0xf); 203856196826SPaul Burton #else 2039c40fdca6SSimon Glass bdesc->vendor[0] = 0; 2040c40fdca6SSimon Glass bdesc->product[0] = 0; 2041c40fdca6SSimon Glass bdesc->revision[0] = 0; 204256196826SPaul Burton #endif 2043122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT) 2044c40fdca6SSimon Glass part_init(bdesc); 2045122efd43SMikhail Kshevetskiy #endif 2046272cc70bSAndy Fleming 2047272cc70bSAndy Fleming return 0; 2048272cc70bSAndy Fleming } 2049272cc70bSAndy Fleming 2050479fbf72SJason Zhu #ifndef CONFIG_MMC_USE_PRE_CONFIG 2051fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc) 2052272cc70bSAndy Fleming { 2053272cc70bSAndy Fleming struct mmc_cmd cmd; 2054272cc70bSAndy Fleming int err; 2055272cc70bSAndy Fleming 2056272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND; 2057272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ 205893bfd616SPantelis Antoniou cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa; 2059272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7; 2060272cc70bSAndy Fleming 2061272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2062272cc70bSAndy Fleming 2063272cc70bSAndy Fleming if (err) 2064272cc70bSAndy Fleming return err; 2065272cc70bSAndy Fleming 2066998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa) 2067915ffa52SJaehoon Chung return -EOPNOTSUPP; 2068272cc70bSAndy Fleming else 2069272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 2070272cc70bSAndy Fleming 2071272cc70bSAndy Fleming return 0; 2072272cc70bSAndy Fleming } 2073479fbf72SJason Zhu #endif 2074272cc70bSAndy Fleming 2075c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 207695de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */ 207795de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void) 207895de9ab2SPaul Kocialkowski { 207995de9ab2SPaul Kocialkowski } 208005cbeb7cSSimon Glass #endif 208195de9ab2SPaul Kocialkowski 2082479fbf72SJason Zhu #ifndef CONFIG_MMC_USE_PRE_CONFIG 20832051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc) 20842051aefeSPeng Fan { 2085c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 208605cbeb7cSSimon Glass #if defined(CONFIG_DM_REGULATOR) && !defined(CONFIG_SPL_BUILD) 20872051aefeSPeng Fan struct udevice *vmmc_supply; 20882051aefeSPeng Fan int ret; 20892051aefeSPeng Fan 20902051aefeSPeng Fan ret = device_get_supply_regulator(mmc->dev, "vmmc-supply", 20912051aefeSPeng Fan &vmmc_supply); 20922051aefeSPeng Fan if (ret) { 2093288db7c7SJaehoon Chung debug("%s: No vmmc supply\n", mmc->dev->name); 20942051aefeSPeng Fan return 0; 20952051aefeSPeng Fan } 20962051aefeSPeng Fan 20972051aefeSPeng Fan ret = regulator_set_enable(vmmc_supply, true); 20982051aefeSPeng Fan if (ret) { 20992051aefeSPeng Fan puts("Error enabling VMMC supply\n"); 21002051aefeSPeng Fan return ret; 21012051aefeSPeng Fan } 21022051aefeSPeng Fan #endif 210305cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */ 210405cbeb7cSSimon Glass /* 210505cbeb7cSSimon Glass * Driver model should use a regulator, as above, rather than calling 210605cbeb7cSSimon Glass * out to board code. 210705cbeb7cSSimon Glass */ 210805cbeb7cSSimon Glass board_mmc_power_init(); 210905cbeb7cSSimon Glass #endif 21102051aefeSPeng Fan return 0; 21112051aefeSPeng Fan } 2112479fbf72SJason Zhu #endif 2113479fbf72SJason Zhu #ifdef CONFIG_MMC_USE_PRE_CONFIG 2114479fbf72SJason Zhu static int mmc_select_card(struct mmc *mmc, int n) 2115479fbf72SJason Zhu { 2116479fbf72SJason Zhu struct mmc_cmd cmd; 2117479fbf72SJason Zhu int err = 0; 21182051aefeSPeng Fan 2119479fbf72SJason Zhu memset(&cmd, 0, sizeof(struct mmc_cmd)); 2120479fbf72SJason Zhu if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 2121479fbf72SJason Zhu mmc->rca = n; 2122479fbf72SJason Zhu cmd.cmdidx = MMC_CMD_SELECT_CARD; 2123479fbf72SJason Zhu cmd.resp_type = MMC_RSP_R1; 2124479fbf72SJason Zhu cmd.cmdarg = mmc->rca << 16; 2125479fbf72SJason Zhu err = mmc_send_cmd(mmc, &cmd, NULL); 2126479fbf72SJason Zhu } 2127479fbf72SJason Zhu 2128479fbf72SJason Zhu return err; 2129479fbf72SJason Zhu } 2130479fbf72SJason Zhu 2131479fbf72SJason Zhu int mmc_start_init(struct mmc *mmc) 2132479fbf72SJason Zhu { 2133479fbf72SJason Zhu /* 2134479fbf72SJason Zhu * We use the MMC config set by the bootrom. 2135479fbf72SJason Zhu * So it is no need to reset the eMMC device. 2136479fbf72SJason Zhu */ 2137479fbf72SJason Zhu mmc_set_bus_width(mmc, 8); 2138479fbf72SJason Zhu mmc_set_clock(mmc, 1); 2139479fbf72SJason Zhu mmc_set_timing(mmc, MMC_TIMING_LEGACY); 2140479fbf72SJason Zhu /* Send cmd7 to return stand-by state*/ 2141479fbf72SJason Zhu mmc_select_card(mmc, 0); 2142479fbf72SJason Zhu mmc->version = MMC_VERSION_UNKNOWN; 2143479fbf72SJason Zhu mmc->high_capacity = 1; 2144479fbf72SJason Zhu /* 2145479fbf72SJason Zhu * The RCA is set to 2 by rockchip bootrom, use the default 2146479fbf72SJason Zhu * value here. 2147479fbf72SJason Zhu */ 2148479fbf72SJason Zhu #ifdef CONFIG_ARCH_ROCKCHIP 2149479fbf72SJason Zhu mmc->rca = 2; 2150479fbf72SJason Zhu #else 2151479fbf72SJason Zhu mmc->rca = 1; 2152479fbf72SJason Zhu #endif 2153479fbf72SJason Zhu return 0; 2154479fbf72SJason Zhu } 2155479fbf72SJason Zhu #else 2156e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc) 2157272cc70bSAndy Fleming { 21588ca51e51SSimon Glass bool no_card; 2159afd5932bSMacpaul Lin int err; 2160272cc70bSAndy Fleming 2161ab769f22SPantelis Antoniou /* we pretend there's no card when init is NULL */ 21628ca51e51SSimon Glass no_card = mmc_getcd(mmc) == 0; 2163e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 21648ca51e51SSimon Glass no_card = no_card || (mmc->cfg->ops->init == NULL); 21658ca51e51SSimon Glass #endif 21668ca51e51SSimon Glass if (no_card) { 216748972d90SThierry Reding mmc->has_init = 0; 216856196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 216948972d90SThierry Reding printf("MMC: no card present\n"); 217056196826SPaul Burton #endif 2171915ffa52SJaehoon Chung return -ENOMEDIUM; 217248972d90SThierry Reding } 217348972d90SThierry Reding 2174bc897b1dSLei Wen if (mmc->has_init) 2175bc897b1dSLei Wen return 0; 2176bc897b1dSLei Wen 21775a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 21785a8dbdc6SYangbo Lu mmc_adapter_card_type_ident(); 21795a8dbdc6SYangbo Lu #endif 21802051aefeSPeng Fan err = mmc_power_init(mmc); 21812051aefeSPeng Fan if (err) 21822051aefeSPeng Fan return err; 218395de9ab2SPaul Kocialkowski 2184e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 21858ca51e51SSimon Glass /* The device has already been probed ready for use */ 21868ca51e51SSimon Glass #else 2187ab769f22SPantelis Antoniou /* made sure it's not NULL earlier */ 218893bfd616SPantelis Antoniou err = mmc->cfg->ops->init(mmc); 2189272cc70bSAndy Fleming if (err) 2190272cc70bSAndy Fleming return err; 21918ca51e51SSimon Glass #endif 2192b86b85e2SIlya Yanok mmc_set_bus_width(mmc, 1); 2193b86b85e2SIlya Yanok mmc_set_clock(mmc, 1); 219481db2d36SZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_LEGACY); 2195b86b85e2SIlya Yanok 2196272cc70bSAndy Fleming /* Reset the Card */ 2197272cc70bSAndy Fleming err = mmc_go_idle(mmc); 2198272cc70bSAndy Fleming 2199272cc70bSAndy Fleming if (err) 2200272cc70bSAndy Fleming return err; 2201272cc70bSAndy Fleming 2202bc897b1dSLei Wen /* The internal partition reset to user partition(0) at every CMD0*/ 2203c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->hwpart = 0; 2204bc897b1dSLei Wen 2205272cc70bSAndy Fleming /* Test for SD version 2 */ 2206272cc70bSAndy Fleming err = mmc_send_if_cond(mmc); 2207272cc70bSAndy Fleming 2208272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */ 2209272cc70bSAndy Fleming err = sd_send_op_cond(mmc); 2210272cc70bSAndy Fleming 2211272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */ 2212915ffa52SJaehoon Chung if (err == -ETIMEDOUT) { 2213272cc70bSAndy Fleming err = mmc_send_op_cond(mmc); 2214272cc70bSAndy Fleming 2215bd47c135SAndrew Gabbasov if (err) { 221656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2217272cc70bSAndy Fleming printf("Card did not respond to voltage select!\n"); 221856196826SPaul Burton #endif 2219915ffa52SJaehoon Chung return -EOPNOTSUPP; 2220272cc70bSAndy Fleming } 2221272cc70bSAndy Fleming } 2222272cc70bSAndy Fleming 2223bd47c135SAndrew Gabbasov if (!err) 2224e9550449SChe-Liang Chiou mmc->init_in_progress = 1; 2225e9550449SChe-Liang Chiou 2226e9550449SChe-Liang Chiou return err; 2227e9550449SChe-Liang Chiou } 2228479fbf72SJason Zhu #endif 2229e9550449SChe-Liang Chiou 2230e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc) 2231e9550449SChe-Liang Chiou { 2232e9550449SChe-Liang Chiou int err = 0; 2233e9550449SChe-Liang Chiou 2234bd47c135SAndrew Gabbasov mmc->init_in_progress = 0; 2235e9550449SChe-Liang Chiou if (mmc->op_cond_pending) 2236e9550449SChe-Liang Chiou err = mmc_complete_op_cond(mmc); 2237e9550449SChe-Liang Chiou 2238e9550449SChe-Liang Chiou if (!err) 2239bc897b1dSLei Wen err = mmc_startup(mmc); 2240bc897b1dSLei Wen if (err) 2241bc897b1dSLei Wen mmc->has_init = 0; 2242bc897b1dSLei Wen else 2243bc897b1dSLei Wen mmc->has_init = 1; 2244e9550449SChe-Liang Chiou return err; 2245e9550449SChe-Liang Chiou } 2246e9550449SChe-Liang Chiou 2247e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc) 2248e9550449SChe-Liang Chiou { 2249bd47c135SAndrew Gabbasov int err = 0; 2250ce9eca94SMarek Vasut __maybe_unused unsigned start; 2251c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 225233fb211dSSimon Glass struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev); 2253e9550449SChe-Liang Chiou 225433fb211dSSimon Glass upriv->mmc = mmc; 225533fb211dSSimon Glass #endif 2256e9550449SChe-Liang Chiou if (mmc->has_init) 2257e9550449SChe-Liang Chiou return 0; 2258d803fea5SMateusz Zalega 2259d803fea5SMateusz Zalega start = get_timer(0); 2260d803fea5SMateusz Zalega 2261e9550449SChe-Liang Chiou if (!mmc->init_in_progress) 2262e9550449SChe-Liang Chiou err = mmc_start_init(mmc); 2263e9550449SChe-Liang Chiou 2264bd47c135SAndrew Gabbasov if (!err) 2265e9550449SChe-Liang Chiou err = mmc_complete_init(mmc); 2266919b4858SJagan Teki if (err) 2267919b4858SJagan Teki printf("%s: %d, time %lu\n", __func__, err, get_timer(start)); 2268919b4858SJagan Teki 2269bc897b1dSLei Wen return err; 2270272cc70bSAndy Fleming } 2271272cc70bSAndy Fleming 2272ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val) 2273ab71188cSMarkus Niebel { 2274ab71188cSMarkus Niebel mmc->dsr = val; 2275ab71188cSMarkus Niebel return 0; 2276ab71188cSMarkus Niebel } 2277ab71188cSMarkus Niebel 2278cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */ 2279cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis) 2280272cc70bSAndy Fleming { 2281272cc70bSAndy Fleming return -1; 2282272cc70bSAndy Fleming } 2283272cc70bSAndy Fleming 2284cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */ 2285cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis) 2286cee9ab7cSJeroen Hofstee { 2287cee9ab7cSJeroen Hofstee return -1; 2288cee9ab7cSJeroen Hofstee } 2289272cc70bSAndy Fleming 2290e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit) 2291e9550449SChe-Liang Chiou { 2292e9550449SChe-Liang Chiou mmc->preinit = preinit; 2293e9550449SChe-Liang Chiou } 2294e9550449SChe-Liang Chiou 2295c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD) 22968e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 22978e3332e2SSjoerd Simons { 22988e3332e2SSjoerd Simons return 0; 22998e3332e2SSjoerd Simons } 2300c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC) 23018e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 23028e3332e2SSjoerd Simons { 23034a1db6d8SSimon Glass int ret, i; 23048e3332e2SSjoerd Simons struct uclass *uc; 23054a1db6d8SSimon Glass struct udevice *dev; 23068e3332e2SSjoerd Simons 23078e3332e2SSjoerd Simons ret = uclass_get(UCLASS_MMC, &uc); 23088e3332e2SSjoerd Simons if (ret) 23098e3332e2SSjoerd Simons return ret; 23108e3332e2SSjoerd Simons 23114a1db6d8SSimon Glass /* 23124a1db6d8SSimon Glass * Try to add them in sequence order. Really with driver model we 23134a1db6d8SSimon Glass * should allow holes, but the current MMC list does not allow that. 23144a1db6d8SSimon Glass * So if we request 0, 1, 3 we will get 0, 1, 2. 23154a1db6d8SSimon Glass */ 23164a1db6d8SSimon Glass for (i = 0; ; i++) { 23174a1db6d8SSimon Glass ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev); 23184a1db6d8SSimon Glass if (ret == -ENODEV) 23194a1db6d8SSimon Glass break; 23204a1db6d8SSimon Glass } 23214a1db6d8SSimon Glass uclass_foreach_dev(dev, uc) { 23224a1db6d8SSimon Glass ret = device_probe(dev); 23238e3332e2SSjoerd Simons if (ret) 23244a1db6d8SSimon Glass printf("%s - probe failed: %d\n", dev->name, ret); 23258e3332e2SSjoerd Simons } 23268e3332e2SSjoerd Simons 23278e3332e2SSjoerd Simons return 0; 23288e3332e2SSjoerd Simons } 23298e3332e2SSjoerd Simons #else 23308e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 23318e3332e2SSjoerd Simons { 23328e3332e2SSjoerd Simons if (board_mmc_init(bis) < 0) 23338e3332e2SSjoerd Simons cpu_mmc_init(bis); 23348e3332e2SSjoerd Simons 23358e3332e2SSjoerd Simons return 0; 23368e3332e2SSjoerd Simons } 23378e3332e2SSjoerd Simons #endif 2338e9550449SChe-Liang Chiou 2339272cc70bSAndy Fleming int mmc_initialize(bd_t *bis) 2340272cc70bSAndy Fleming { 23411b26bab1SDaniel Kochmański static int initialized = 0; 23428e3332e2SSjoerd Simons int ret; 23431b26bab1SDaniel Kochmański if (initialized) /* Avoid initializing mmc multiple times */ 23441b26bab1SDaniel Kochmański return 0; 23451b26bab1SDaniel Kochmański initialized = 1; 23461b26bab1SDaniel Kochmański 2347c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK) 2348b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY) 2349c40fdca6SSimon Glass mmc_list_init(); 2350c40fdca6SSimon Glass #endif 2351b5b838f1SMarek Vasut #endif 23528e3332e2SSjoerd Simons ret = mmc_probe(bis); 23538e3332e2SSjoerd Simons if (ret) 23548e3332e2SSjoerd Simons return ret; 2355272cc70bSAndy Fleming 2356bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD 2357272cc70bSAndy Fleming print_mmc_devices(','); 2358bb0dc108SYing Zhang #endif 2359272cc70bSAndy Fleming 2360c40fdca6SSimon Glass mmc_do_preinit(); 2361272cc70bSAndy Fleming return 0; 2362272cc70bSAndy Fleming } 2363cd3d4880STomas Melin 2364cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE 2365cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc) 2366cd3d4880STomas Melin { 2367cd3d4880STomas Melin int err; 2368cd3d4880STomas Melin ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 2369cd3d4880STomas Melin 2370cd3d4880STomas Melin err = mmc_send_ext_csd(mmc, ext_csd); 2371cd3d4880STomas Melin if (err) { 2372cd3d4880STomas Melin puts("Could not get ext_csd register values\n"); 2373cd3d4880STomas Melin return err; 2374cd3d4880STomas Melin } 2375cd3d4880STomas Melin 2376cd3d4880STomas Melin if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) { 2377cd3d4880STomas Melin puts("Background operations not supported on device\n"); 2378cd3d4880STomas Melin return -EMEDIUMTYPE; 2379cd3d4880STomas Melin } 2380cd3d4880STomas Melin 2381cd3d4880STomas Melin if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) { 2382cd3d4880STomas Melin puts("Background operations already enabled\n"); 2383cd3d4880STomas Melin return 0; 2384cd3d4880STomas Melin } 2385cd3d4880STomas Melin 2386cd3d4880STomas Melin err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1); 2387cd3d4880STomas Melin if (err) { 2388cd3d4880STomas Melin puts("Failed to enable manual background operations\n"); 2389cd3d4880STomas Melin return err; 2390cd3d4880STomas Melin } 2391cd3d4880STomas Melin 2392cd3d4880STomas Melin puts("Enabled manual background operations\n"); 2393cd3d4880STomas Melin 2394cd3d4880STomas Melin return 0; 2395cd3d4880STomas Melin } 2396cd3d4880STomas Melin #endif 2397