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 266c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK) 2677dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst) 26833fb211dSSimon Glass #else 2697dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, 2707dba0b93SSimon Glass void *dst) 27133fb211dSSimon Glass #endif 272272cc70bSAndy Fleming { 273c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK) 27433fb211dSSimon Glass struct blk_desc *block_dev = dev_get_uclass_platdata(dev); 27533fb211dSSimon Glass #endif 276bcce53d0SSimon Glass int dev_num = block_dev->devnum; 277873cc1d7SStephen Warren int err; 2784a1a06bcSAlagu Sankar lbaint_t cur, blocks_todo = blkcnt; 279272cc70bSAndy Fleming 2804a1a06bcSAlagu Sankar if (blkcnt == 0) 2814a1a06bcSAlagu Sankar return 0; 2824a1a06bcSAlagu Sankar 2834a1a06bcSAlagu Sankar struct mmc *mmc = find_mmc_device(dev_num); 284272cc70bSAndy Fleming if (!mmc) 285272cc70bSAndy Fleming return 0; 286272cc70bSAndy Fleming 287b5b838f1SMarek Vasut if (CONFIG_IS_ENABLED(MMC_TINY)) 288b5b838f1SMarek Vasut err = mmc_switch_part(mmc, block_dev->hwpart); 289b5b838f1SMarek Vasut else 29069f45cd5SSimon Glass err = blk_dselect_hwpart(block_dev, block_dev->hwpart); 291b5b838f1SMarek Vasut 292873cc1d7SStephen Warren if (err < 0) 293873cc1d7SStephen Warren return 0; 294873cc1d7SStephen Warren 295c40fdca6SSimon Glass if ((start + blkcnt) > block_dev->lba) { 29656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 297ff8fef56SSascha Silbe printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", 298c40fdca6SSimon Glass start + blkcnt, block_dev->lba); 29956196826SPaul Burton #endif 300d2bf29e3SLei Wen return 0; 301d2bf29e3SLei Wen } 302272cc70bSAndy Fleming 30311692991SSimon Glass if (mmc_set_blocklen(mmc, mmc->read_bl_len)) { 30411692991SSimon Glass debug("%s: Failed to set blocklen\n", __func__); 305272cc70bSAndy Fleming return 0; 30611692991SSimon Glass } 307272cc70bSAndy Fleming 3084a1a06bcSAlagu Sankar do { 30993bfd616SPantelis Antoniou cur = (blocks_todo > mmc->cfg->b_max) ? 31093bfd616SPantelis Antoniou mmc->cfg->b_max : blocks_todo; 31111692991SSimon Glass if (mmc_read_blocks(mmc, dst, start, cur) != cur) { 31211692991SSimon Glass debug("%s: Failed to read blocks\n", __func__); 313c30b5115SJason Zhu int timeout = 0; 314c30b5115SJason Zhu re_init_retry: 315c30b5115SJason Zhu timeout++; 316c30b5115SJason Zhu /* 317c30b5115SJason Zhu * Try re-init seven times. 318c30b5115SJason Zhu */ 319c30b5115SJason Zhu if (timeout > 7) { 320c30b5115SJason Zhu printf("Re-init retry timeout\n"); 3214a1a06bcSAlagu Sankar return 0; 32211692991SSimon Glass } 323c30b5115SJason Zhu 324c30b5115SJason Zhu mmc->has_init = 0; 325c30b5115SJason Zhu if (mmc_init(mmc)) 326c30b5115SJason Zhu return 0; 327c30b5115SJason Zhu 328c30b5115SJason Zhu if (mmc_read_blocks(mmc, dst, start, cur) != cur) { 329c30b5115SJason Zhu printf("%s: Re-init mmc_read_blocks error\n", 330c30b5115SJason Zhu __func__); 331c30b5115SJason Zhu goto re_init_retry; 332c30b5115SJason Zhu } 333c30b5115SJason Zhu } 3344a1a06bcSAlagu Sankar blocks_todo -= cur; 3354a1a06bcSAlagu Sankar start += cur; 3364a1a06bcSAlagu Sankar dst += cur * mmc->read_bl_len; 3374a1a06bcSAlagu Sankar } while (blocks_todo > 0); 338272cc70bSAndy Fleming 339272cc70bSAndy Fleming return blkcnt; 340272cc70bSAndy Fleming } 341272cc70bSAndy Fleming 34249dba033SZiyuan Xu void mmc_set_clock(struct mmc *mmc, uint clock) 34349dba033SZiyuan Xu { 34449dba033SZiyuan Xu if (clock > mmc->cfg->f_max) 34549dba033SZiyuan Xu clock = mmc->cfg->f_max; 34649dba033SZiyuan Xu 34749dba033SZiyuan Xu if (clock < mmc->cfg->f_min) 34849dba033SZiyuan Xu clock = mmc->cfg->f_min; 34949dba033SZiyuan Xu 35049dba033SZiyuan Xu mmc->clock = clock; 35149dba033SZiyuan Xu 35249dba033SZiyuan Xu mmc_set_ios(mmc); 35349dba033SZiyuan Xu } 35449dba033SZiyuan Xu 35549dba033SZiyuan Xu static void mmc_set_bus_width(struct mmc *mmc, uint width) 35649dba033SZiyuan Xu { 35749dba033SZiyuan Xu mmc->bus_width = width; 35849dba033SZiyuan Xu 35949dba033SZiyuan Xu mmc_set_ios(mmc); 36049dba033SZiyuan Xu } 36149dba033SZiyuan Xu 36281db2d36SZiyuan Xu static void mmc_set_timing(struct mmc *mmc, uint timing) 36381db2d36SZiyuan Xu { 36481db2d36SZiyuan Xu mmc->timing = timing; 36581db2d36SZiyuan Xu mmc_set_ios(mmc); 36681db2d36SZiyuan Xu } 36781db2d36SZiyuan Xu 368fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc) 369272cc70bSAndy Fleming { 370272cc70bSAndy Fleming struct mmc_cmd cmd; 371272cc70bSAndy Fleming int err; 372272cc70bSAndy Fleming 373272cc70bSAndy Fleming udelay(1000); 374272cc70bSAndy Fleming 375272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_GO_IDLE_STATE; 376272cc70bSAndy Fleming cmd.cmdarg = 0; 377272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_NONE; 378272cc70bSAndy Fleming 379272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 380272cc70bSAndy Fleming 381272cc70bSAndy Fleming if (err) 382272cc70bSAndy Fleming return err; 383272cc70bSAndy Fleming 384272cc70bSAndy Fleming udelay(2000); 385272cc70bSAndy Fleming 386272cc70bSAndy Fleming return 0; 387272cc70bSAndy Fleming } 388272cc70bSAndy Fleming 389*479fbf72SJason Zhu #ifndef CONFIG_MMC_USE_PRE_CONFIG 390fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc) 391272cc70bSAndy Fleming { 392272cc70bSAndy Fleming int timeout = 1000; 393272cc70bSAndy Fleming int err; 394272cc70bSAndy Fleming struct mmc_cmd cmd; 395272cc70bSAndy Fleming 3961677eef4SAndrew Gabbasov while (1) { 397272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 398272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 399272cc70bSAndy Fleming cmd.cmdarg = 0; 400272cc70bSAndy Fleming 401272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 402272cc70bSAndy Fleming 403272cc70bSAndy Fleming if (err) 404272cc70bSAndy Fleming return err; 405272cc70bSAndy Fleming 406272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_OP_COND; 407272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R3; 408250de12bSStefano Babic 409250de12bSStefano Babic /* 410250de12bSStefano Babic * Most cards do not answer if some reserved bits 411250de12bSStefano Babic * in the ocr are set. However, Some controller 412250de12bSStefano Babic * can set bit 7 (reserved for low voltages), but 413250de12bSStefano Babic * how to manage low voltages SD card is not yet 414250de12bSStefano Babic * specified. 415250de12bSStefano Babic */ 416d52ebf10SThomas Chou cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 : 41793bfd616SPantelis Antoniou (mmc->cfg->voltages & 0xff8000); 418272cc70bSAndy Fleming 419272cc70bSAndy Fleming if (mmc->version == SD_VERSION_2) 420272cc70bSAndy Fleming cmd.cmdarg |= OCR_HCS; 421272cc70bSAndy Fleming 422272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 423272cc70bSAndy Fleming 424272cc70bSAndy Fleming if (err) 425272cc70bSAndy Fleming return err; 426272cc70bSAndy Fleming 4271677eef4SAndrew Gabbasov if (cmd.response[0] & OCR_BUSY) 4281677eef4SAndrew Gabbasov break; 429272cc70bSAndy Fleming 4301677eef4SAndrew Gabbasov if (timeout-- <= 0) 431915ffa52SJaehoon Chung return -EOPNOTSUPP; 432272cc70bSAndy Fleming 4331677eef4SAndrew Gabbasov udelay(1000); 4341677eef4SAndrew Gabbasov } 4351677eef4SAndrew Gabbasov 436272cc70bSAndy Fleming if (mmc->version != SD_VERSION_2) 437272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 438272cc70bSAndy Fleming 439d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 440d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 441d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 442d52ebf10SThomas Chou cmd.cmdarg = 0; 443d52ebf10SThomas Chou 444d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 445d52ebf10SThomas Chou 446d52ebf10SThomas Chou if (err) 447d52ebf10SThomas Chou return err; 448d52ebf10SThomas Chou } 449d52ebf10SThomas Chou 450998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 451272cc70bSAndy Fleming 452272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 453272cc70bSAndy Fleming mmc->rca = 0; 454272cc70bSAndy Fleming 455272cc70bSAndy Fleming return 0; 456272cc70bSAndy Fleming } 457*479fbf72SJason Zhu #endif 458272cc70bSAndy Fleming 4595289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg) 460272cc70bSAndy Fleming { 4615289b535SAndrew Gabbasov struct mmc_cmd cmd; 462272cc70bSAndy Fleming int err; 463272cc70bSAndy Fleming 4645289b535SAndrew Gabbasov cmd.cmdidx = MMC_CMD_SEND_OP_COND; 4655289b535SAndrew Gabbasov cmd.resp_type = MMC_RSP_R3; 4665289b535SAndrew Gabbasov cmd.cmdarg = 0; 4675a20397bSRob Herring if (use_arg && !mmc_host_is_spi(mmc)) 4685a20397bSRob Herring cmd.cmdarg = OCR_HCS | 46993bfd616SPantelis Antoniou (mmc->cfg->voltages & 470a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_VOLTAGE_MASK)) | 471a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_ACCESS_MODE); 472e9550449SChe-Liang Chiou 4735289b535SAndrew Gabbasov err = mmc_send_cmd(mmc, &cmd, NULL); 474e9550449SChe-Liang Chiou if (err) 475e9550449SChe-Liang Chiou return err; 4765289b535SAndrew Gabbasov mmc->ocr = cmd.response[0]; 477e9550449SChe-Liang Chiou return 0; 478e9550449SChe-Liang Chiou } 479e9550449SChe-Liang Chiou 480*479fbf72SJason Zhu #ifndef CONFIG_MMC_USE_PRE_CONFIG 481750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc) 482e9550449SChe-Liang Chiou { 483e9550449SChe-Liang Chiou int err, i; 484e9550449SChe-Liang Chiou 485272cc70bSAndy Fleming /* Some cards seem to need this */ 486272cc70bSAndy Fleming mmc_go_idle(mmc); 487272cc70bSAndy Fleming 48831cacbabSRaffaele Recalcati /* Asking to the card its capabilities */ 489e9550449SChe-Liang Chiou for (i = 0; i < 2; i++) { 4905289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, i != 0); 49131cacbabSRaffaele Recalcati if (err) 49231cacbabSRaffaele Recalcati return err; 49331cacbabSRaffaele Recalcati 494e9550449SChe-Liang Chiou /* exit if not busy (flag seems to be inverted) */ 495a626c8d4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 496bd47c135SAndrew Gabbasov break; 497e9550449SChe-Liang Chiou } 498bd47c135SAndrew Gabbasov mmc->op_cond_pending = 1; 499bd47c135SAndrew Gabbasov return 0; 500e9550449SChe-Liang Chiou } 501*479fbf72SJason Zhu #endif 502750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc) 503e9550449SChe-Liang Chiou { 504e9550449SChe-Liang Chiou struct mmc_cmd cmd; 505e9550449SChe-Liang Chiou int timeout = 1000; 506e9550449SChe-Liang Chiou uint start; 507e9550449SChe-Liang Chiou int err; 508e9550449SChe-Liang Chiou 509e9550449SChe-Liang Chiou mmc->op_cond_pending = 0; 510cc17c01fSAndrew Gabbasov if (!(mmc->ocr & OCR_BUSY)) { 511d188b113SYangbo Lu /* Some cards seem to need this */ 512d188b113SYangbo Lu mmc_go_idle(mmc); 513d188b113SYangbo Lu 514e9550449SChe-Liang Chiou start = get_timer(0); 5151677eef4SAndrew Gabbasov while (1) { 5165289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, 1); 517272cc70bSAndy Fleming if (err) 518272cc70bSAndy Fleming return err; 5191677eef4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 5201677eef4SAndrew Gabbasov break; 521e9550449SChe-Liang Chiou if (get_timer(start) > timeout) 522915ffa52SJaehoon Chung return -EOPNOTSUPP; 523e9550449SChe-Liang Chiou udelay(100); 5241677eef4SAndrew Gabbasov } 525cc17c01fSAndrew Gabbasov } 526272cc70bSAndy Fleming 527d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 528d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 529d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 530d52ebf10SThomas Chou cmd.cmdarg = 0; 531d52ebf10SThomas Chou 532d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 533d52ebf10SThomas Chou 534d52ebf10SThomas Chou if (err) 535d52ebf10SThomas Chou return err; 536a626c8d4SAndrew Gabbasov 537a626c8d4SAndrew Gabbasov mmc->ocr = cmd.response[0]; 538d52ebf10SThomas Chou } 539d52ebf10SThomas Chou 540272cc70bSAndy Fleming mmc->version = MMC_VERSION_UNKNOWN; 541272cc70bSAndy Fleming 542272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 543def816a2SStephen Warren mmc->rca = 1; 544272cc70bSAndy Fleming 545272cc70bSAndy Fleming return 0; 546272cc70bSAndy Fleming } 547272cc70bSAndy Fleming 548272cc70bSAndy Fleming 549fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) 550272cc70bSAndy Fleming { 551e531136eSJason Zhu static int initialized; 552272cc70bSAndy Fleming struct mmc_cmd cmd; 553272cc70bSAndy Fleming struct mmc_data data; 554272cc70bSAndy Fleming int err; 555272cc70bSAndy Fleming 556e531136eSJason Zhu if (initialized) { 557e531136eSJason Zhu memcpy(ext_csd, mmc_ext_csd, 512); 558e531136eSJason Zhu return 0; 559e531136eSJason Zhu } 560e531136eSJason Zhu 561e531136eSJason Zhu initialized = 1; 562e531136eSJason Zhu 563272cc70bSAndy Fleming /* Get the Card Status Register */ 564272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_EXT_CSD; 565272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 566272cc70bSAndy Fleming cmd.cmdarg = 0; 567272cc70bSAndy Fleming 568cdfd1ac6SYoshihiro Shimoda data.dest = (char *)ext_csd; 569272cc70bSAndy Fleming data.blocks = 1; 5708bfa195eSSimon Glass data.blocksize = MMC_MAX_BLOCK_LEN; 571272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 572272cc70bSAndy Fleming 573272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 574e531136eSJason Zhu memcpy(mmc_ext_csd, ext_csd, 512); 575272cc70bSAndy Fleming 576272cc70bSAndy Fleming return err; 577272cc70bSAndy Fleming } 578272cc70bSAndy Fleming 5799e8ce816SZiyuan Xu static int mmc_poll_for_busy(struct mmc *mmc, u8 send_status) 580272cc70bSAndy Fleming { 581272cc70bSAndy Fleming struct mmc_cmd cmd; 58255e5defdSZiyuan Xu u8 busy = true; 58355e5defdSZiyuan Xu uint start; 58455e5defdSZiyuan Xu int ret; 5855d4fc8d9SRaffaele Recalcati int timeout = 1000; 58655e5defdSZiyuan Xu 58755e5defdSZiyuan Xu cmd.cmdidx = MMC_CMD_SEND_STATUS; 58855e5defdSZiyuan Xu cmd.resp_type = MMC_RSP_R1; 58955e5defdSZiyuan Xu cmd.cmdarg = mmc->rca << 16; 59055e5defdSZiyuan Xu 59155e5defdSZiyuan Xu start = get_timer(0); 59255e5defdSZiyuan Xu 5939e8ce816SZiyuan Xu if (!send_status && !mmc_can_card_busy(mmc)) { 5949e8ce816SZiyuan Xu mdelay(timeout); 5959e8ce816SZiyuan Xu return 0; 5969e8ce816SZiyuan Xu } 5979e8ce816SZiyuan Xu 59855e5defdSZiyuan Xu do { 5999e8ce816SZiyuan Xu if (!send_status) { 60055e5defdSZiyuan Xu busy = mmc_card_busy(mmc); 60155e5defdSZiyuan Xu } else { 60255e5defdSZiyuan Xu ret = mmc_send_cmd(mmc, &cmd, NULL); 60355e5defdSZiyuan Xu 60455e5defdSZiyuan Xu if (ret) 60555e5defdSZiyuan Xu return ret; 60655e5defdSZiyuan Xu 60755e5defdSZiyuan Xu if (cmd.response[0] & MMC_STATUS_SWITCH_ERROR) 60855e5defdSZiyuan Xu return -EBADMSG; 60955e5defdSZiyuan Xu busy = (cmd.response[0] & MMC_STATUS_CURR_STATE) == 61055e5defdSZiyuan Xu MMC_STATE_PRG; 61155e5defdSZiyuan Xu } 61255e5defdSZiyuan Xu 61355e5defdSZiyuan Xu if (get_timer(start) > timeout && busy) 61455e5defdSZiyuan Xu return -ETIMEDOUT; 61555e5defdSZiyuan Xu } while (busy); 61655e5defdSZiyuan Xu 61755e5defdSZiyuan Xu return 0; 61855e5defdSZiyuan Xu } 61955e5defdSZiyuan Xu 62055e5defdSZiyuan Xu static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value, 62155e5defdSZiyuan Xu u8 send_status) 62255e5defdSZiyuan Xu { 62355e5defdSZiyuan Xu struct mmc_cmd cmd; 624a9003dc6SMaxime Ripard int retries = 3; 6255d4fc8d9SRaffaele Recalcati int ret; 626272cc70bSAndy Fleming 627272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SWITCH; 628272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 629272cc70bSAndy Fleming cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 630272cc70bSAndy Fleming (index << 16) | 631272cc70bSAndy Fleming (value << 8); 632272cc70bSAndy Fleming 63355e5defdSZiyuan Xu do { 6345d4fc8d9SRaffaele Recalcati ret = mmc_send_cmd(mmc, &cmd, NULL); 6355d4fc8d9SRaffaele Recalcati 6369e8ce816SZiyuan Xu if (!ret) 6379e8ce816SZiyuan Xu return mmc_poll_for_busy(mmc, send_status); 63855e5defdSZiyuan Xu } while (--retries > 0 && ret); 63955e5defdSZiyuan Xu 640a9003dc6SMaxime Ripard return ret; 641a9003dc6SMaxime Ripard } 642a9003dc6SMaxime Ripard 64355e5defdSZiyuan Xu int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) 64455e5defdSZiyuan Xu { 64555e5defdSZiyuan Xu return __mmc_switch(mmc, set, index, value, true); 646272cc70bSAndy Fleming } 647272cc70bSAndy Fleming 64849dba033SZiyuan Xu static int mmc_select_bus_width(struct mmc *mmc) 64949dba033SZiyuan Xu { 65049dba033SZiyuan Xu u32 ext_csd_bits[] = { 65149dba033SZiyuan Xu EXT_CSD_BUS_WIDTH_8, 65249dba033SZiyuan Xu EXT_CSD_BUS_WIDTH_4, 65349dba033SZiyuan Xu }; 65449dba033SZiyuan Xu u32 bus_widths[] = { 65549dba033SZiyuan Xu MMC_BUS_WIDTH_8BIT, 65649dba033SZiyuan Xu MMC_BUS_WIDTH_4BIT, 65749dba033SZiyuan Xu }; 65849dba033SZiyuan Xu ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 65949dba033SZiyuan Xu ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 66049dba033SZiyuan Xu u32 idx, bus_width = 0; 66149dba033SZiyuan Xu int err = 0; 66249dba033SZiyuan Xu 66349dba033SZiyuan Xu if (mmc->version < MMC_VERSION_4 || 66449dba033SZiyuan Xu !(mmc->cfg->host_caps & (MMC_MODE_4BIT | MMC_MODE_8BIT))) 66549dba033SZiyuan Xu return 0; 66649dba033SZiyuan Xu 66749dba033SZiyuan Xu err = mmc_send_ext_csd(mmc, ext_csd); 66849dba033SZiyuan Xu 66949dba033SZiyuan Xu if (err) 67049dba033SZiyuan Xu return err; 67149dba033SZiyuan Xu 67249dba033SZiyuan Xu idx = (mmc->cfg->host_caps & MMC_MODE_8BIT) ? 0 : 1; 67349dba033SZiyuan Xu 67449dba033SZiyuan Xu /* 67549dba033SZiyuan Xu * Unlike SD, MMC cards dont have a configuration register to notify 67649dba033SZiyuan Xu * supported bus width. So bus test command should be run to identify 67749dba033SZiyuan Xu * the supported bus width or compare the ext csd values of current 67849dba033SZiyuan Xu * bus width and ext csd values of 1 bit mode read earlier. 67949dba033SZiyuan Xu */ 68049dba033SZiyuan Xu for (; idx < ARRAY_SIZE(bus_widths); idx++) { 68149dba033SZiyuan Xu /* 68249dba033SZiyuan Xu * Host is capable of 8bit transfer, then switch 68349dba033SZiyuan Xu * the device to work in 8bit transfer mode. If the 68449dba033SZiyuan Xu * mmc switch command returns error then switch to 68549dba033SZiyuan Xu * 4bit transfer mode. On success set the corresponding 68649dba033SZiyuan Xu * bus width on the host. 68749dba033SZiyuan Xu */ 68849dba033SZiyuan Xu err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 68949dba033SZiyuan Xu EXT_CSD_BUS_WIDTH, ext_csd_bits[idx]); 69049dba033SZiyuan Xu if (err) 69149dba033SZiyuan Xu continue; 69249dba033SZiyuan Xu 69349dba033SZiyuan Xu bus_width = bus_widths[idx]; 69449dba033SZiyuan Xu mmc_set_bus_width(mmc, bus_width); 69549dba033SZiyuan Xu 69649dba033SZiyuan Xu err = mmc_send_ext_csd(mmc, test_csd); 69749dba033SZiyuan Xu 69849dba033SZiyuan Xu if (err) 69949dba033SZiyuan Xu continue; 70049dba033SZiyuan Xu 70149dba033SZiyuan Xu /* Only compare read only fields */ 70249dba033SZiyuan Xu if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] == 70349dba033SZiyuan Xu test_csd[EXT_CSD_PARTITIONING_SUPPORT]) && 70449dba033SZiyuan Xu (ext_csd[EXT_CSD_HC_WP_GRP_SIZE] == 70549dba033SZiyuan Xu test_csd[EXT_CSD_HC_WP_GRP_SIZE]) && 70649dba033SZiyuan Xu (ext_csd[EXT_CSD_REV] == test_csd[EXT_CSD_REV]) && 70749dba033SZiyuan Xu (ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] == 70849dba033SZiyuan Xu test_csd[EXT_CSD_HC_ERASE_GRP_SIZE]) && 70949dba033SZiyuan Xu !memcmp(&ext_csd[EXT_CSD_SEC_CNT], 71049dba033SZiyuan Xu &test_csd[EXT_CSD_SEC_CNT], 4)) { 71149dba033SZiyuan Xu err = bus_width; 71249dba033SZiyuan Xu break; 71349dba033SZiyuan Xu } else { 71449dba033SZiyuan Xu err = -EBADMSG; 71549dba033SZiyuan Xu } 71649dba033SZiyuan Xu } 71749dba033SZiyuan Xu 71849dba033SZiyuan Xu return err; 71949dba033SZiyuan Xu } 72049dba033SZiyuan Xu 72149dba033SZiyuan Xu static const u8 tuning_blk_pattern_4bit[] = { 72249dba033SZiyuan Xu 0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc, 72349dba033SZiyuan Xu 0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef, 72449dba033SZiyuan Xu 0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb, 72549dba033SZiyuan Xu 0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef, 72649dba033SZiyuan Xu 0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c, 72749dba033SZiyuan Xu 0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee, 72849dba033SZiyuan Xu 0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff, 72949dba033SZiyuan Xu 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde, 73049dba033SZiyuan Xu }; 73149dba033SZiyuan Xu 73249dba033SZiyuan Xu static const u8 tuning_blk_pattern_8bit[] = { 73349dba033SZiyuan Xu 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 73449dba033SZiyuan Xu 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc, 73549dba033SZiyuan Xu 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff, 73649dba033SZiyuan Xu 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff, 73749dba033SZiyuan Xu 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd, 73849dba033SZiyuan Xu 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, 73949dba033SZiyuan Xu 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff, 74049dba033SZiyuan Xu 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff, 74149dba033SZiyuan Xu 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 74249dba033SZiyuan Xu 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 74349dba033SZiyuan Xu 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 74449dba033SZiyuan Xu 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 74549dba033SZiyuan Xu 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 74649dba033SZiyuan Xu 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 74749dba033SZiyuan Xu 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 74849dba033SZiyuan Xu 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 74949dba033SZiyuan Xu }; 75049dba033SZiyuan Xu 75149dba033SZiyuan Xu int mmc_send_tuning(struct mmc *mmc, u32 opcode) 75249dba033SZiyuan Xu { 75349dba033SZiyuan Xu struct mmc_cmd cmd; 75449dba033SZiyuan Xu struct mmc_data data; 75549dba033SZiyuan Xu const u8 *tuning_block_pattern; 75649dba033SZiyuan Xu int size, err = 0; 75749dba033SZiyuan Xu u8 *data_buf; 75849dba033SZiyuan Xu 75949dba033SZiyuan Xu if (mmc->bus_width == MMC_BUS_WIDTH_8BIT) { 76049dba033SZiyuan Xu tuning_block_pattern = tuning_blk_pattern_8bit; 76149dba033SZiyuan Xu size = sizeof(tuning_blk_pattern_8bit); 76249dba033SZiyuan Xu } else if (mmc->bus_width == MMC_BUS_WIDTH_4BIT) { 76349dba033SZiyuan Xu tuning_block_pattern = tuning_blk_pattern_4bit; 76449dba033SZiyuan Xu size = sizeof(tuning_blk_pattern_4bit); 76549dba033SZiyuan Xu } else { 76649dba033SZiyuan Xu return -EINVAL; 76749dba033SZiyuan Xu } 76849dba033SZiyuan Xu 76949dba033SZiyuan Xu data_buf = calloc(1, size); 77049dba033SZiyuan Xu if (!data_buf) 77149dba033SZiyuan Xu return -ENOMEM; 77249dba033SZiyuan Xu 77349dba033SZiyuan Xu cmd.cmdidx = opcode; 77449dba033SZiyuan Xu cmd.resp_type = MMC_RSP_R1; 77549dba033SZiyuan Xu cmd.cmdarg = 0; 77649dba033SZiyuan Xu 77749dba033SZiyuan Xu data.dest = (char *)data_buf; 77849dba033SZiyuan Xu data.blocksize = size; 77949dba033SZiyuan Xu data.blocks = 1; 78049dba033SZiyuan Xu data.flags = MMC_DATA_READ; 78149dba033SZiyuan Xu 78249dba033SZiyuan Xu err = mmc_send_cmd(mmc, &cmd, &data); 78349dba033SZiyuan Xu if (err) 78449dba033SZiyuan Xu goto out; 78549dba033SZiyuan Xu 78649dba033SZiyuan Xu if (memcmp(data_buf, tuning_block_pattern, size)) 78749dba033SZiyuan Xu err = -EIO; 78849dba033SZiyuan Xu out: 78949dba033SZiyuan Xu free(data_buf); 79049dba033SZiyuan Xu return err; 79149dba033SZiyuan Xu } 79249dba033SZiyuan Xu 79349dba033SZiyuan Xu static int mmc_execute_tuning(struct mmc *mmc) 79449dba033SZiyuan Xu { 79549dba033SZiyuan Xu #ifdef CONFIG_DM_MMC 79649dba033SZiyuan Xu struct dm_mmc_ops *ops = mmc_get_ops(mmc->dev); 79749dba033SZiyuan Xu #endif 79849dba033SZiyuan Xu u32 opcode; 79949dba033SZiyuan Xu 80049dba033SZiyuan Xu if (IS_SD(mmc)) 80149dba033SZiyuan Xu opcode = MMC_SEND_TUNING_BLOCK; 80249dba033SZiyuan Xu else 80349dba033SZiyuan Xu opcode = MMC_SEND_TUNING_BLOCK_HS200; 80449dba033SZiyuan Xu 80549dba033SZiyuan Xu #ifndef CONFIG_DM_MMC 80649dba033SZiyuan Xu if (mmc->cfg->ops->execute_tuning) { 80749dba033SZiyuan Xu return mmc->cfg->ops->execute_tuning(mmc, opcode); 80849dba033SZiyuan Xu #else 80949dba033SZiyuan Xu if (ops->execute_tuning) { 81049dba033SZiyuan Xu return ops->execute_tuning(mmc->dev, opcode); 81149dba033SZiyuan Xu #endif 81249dba033SZiyuan Xu } else { 81349dba033SZiyuan Xu debug("Tuning feature required for HS200 mode.\n"); 81449dba033SZiyuan Xu return -EIO; 81549dba033SZiyuan Xu } 81649dba033SZiyuan Xu } 81749dba033SZiyuan Xu 81849dba033SZiyuan Xu static int mmc_hs200_tuning(struct mmc *mmc) 81949dba033SZiyuan Xu { 82049dba033SZiyuan Xu return mmc_execute_tuning(mmc); 82149dba033SZiyuan Xu } 82249dba033SZiyuan Xu 823e61cd3d7SZiyuan Xu static int mmc_select_hs(struct mmc *mmc) 824e61cd3d7SZiyuan Xu { 825e61cd3d7SZiyuan Xu int ret; 826e61cd3d7SZiyuan Xu 827e61cd3d7SZiyuan Xu ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 828e61cd3d7SZiyuan Xu EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS); 829e61cd3d7SZiyuan Xu 830e61cd3d7SZiyuan Xu if (!ret) 831e61cd3d7SZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_MMC_HS); 832e61cd3d7SZiyuan Xu 833e61cd3d7SZiyuan Xu return ret; 834e61cd3d7SZiyuan Xu } 835e61cd3d7SZiyuan Xu 8365545757fSZiyuan Xu static int mmc_select_hs_ddr(struct mmc *mmc) 8375545757fSZiyuan Xu { 8385545757fSZiyuan Xu u32 ext_csd_bits; 8395545757fSZiyuan Xu int err = 0; 8405545757fSZiyuan Xu 8415545757fSZiyuan Xu if (mmc->bus_width == MMC_BUS_WIDTH_1BIT) 8425545757fSZiyuan Xu return 0; 8435545757fSZiyuan Xu 8445545757fSZiyuan Xu ext_csd_bits = (mmc->bus_width == MMC_BUS_WIDTH_8BIT) ? 8455545757fSZiyuan Xu EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4; 8465545757fSZiyuan Xu 8475545757fSZiyuan Xu err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 8485545757fSZiyuan Xu EXT_CSD_BUS_WIDTH, ext_csd_bits); 8495545757fSZiyuan Xu if (err) 8505545757fSZiyuan Xu return err; 8515545757fSZiyuan Xu 8525545757fSZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_MMC_DDR52); 8535545757fSZiyuan Xu 8545545757fSZiyuan Xu return 0; 8555545757fSZiyuan Xu } 8565545757fSZiyuan Xu 85749dba033SZiyuan Xu static int mmc_select_hs200(struct mmc *mmc) 85849dba033SZiyuan Xu { 85949dba033SZiyuan Xu int ret; 86049dba033SZiyuan Xu 86149dba033SZiyuan Xu /* 86249dba033SZiyuan Xu * Set the bus width(4 or 8) with host's support and 86349dba033SZiyuan Xu * switch to HS200 mode if bus width is set successfully. 86449dba033SZiyuan Xu */ 86549dba033SZiyuan Xu ret = mmc_select_bus_width(mmc); 86649dba033SZiyuan Xu 86749dba033SZiyuan Xu if (ret > 0) { 86849dba033SZiyuan Xu ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 86949dba033SZiyuan Xu EXT_CSD_HS_TIMING, 87049dba033SZiyuan Xu EXT_CSD_TIMING_HS200, false); 87149dba033SZiyuan Xu 87249dba033SZiyuan Xu if (ret) 87349dba033SZiyuan Xu return ret; 87449dba033SZiyuan Xu 87549dba033SZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_MMC_HS200); 87649dba033SZiyuan Xu } 87749dba033SZiyuan Xu 87849dba033SZiyuan Xu return ret; 87949dba033SZiyuan Xu } 88049dba033SZiyuan Xu 881b673f29aSZiyuan Xu static int mmc_select_hs400(struct mmc *mmc) 882b673f29aSZiyuan Xu { 883b673f29aSZiyuan Xu int ret; 884b673f29aSZiyuan Xu 885b673f29aSZiyuan Xu /* Switch card to HS mode */ 886b673f29aSZiyuan Xu ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 887b673f29aSZiyuan Xu EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS, false); 888b673f29aSZiyuan Xu if (ret) 889b673f29aSZiyuan Xu return ret; 890b673f29aSZiyuan Xu 891b673f29aSZiyuan Xu /* Set host controller to HS timing */ 892b673f29aSZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_MMC_HS); 893b673f29aSZiyuan Xu 894b673f29aSZiyuan Xu /* Reduce frequency to HS frequency */ 895b673f29aSZiyuan Xu mmc_set_clock(mmc, MMC_HIGH_52_MAX_DTR); 896b673f29aSZiyuan Xu 897b673f29aSZiyuan Xu ret = mmc_send_status(mmc, 1000); 898b673f29aSZiyuan Xu if (ret) 899b673f29aSZiyuan Xu return ret; 900b673f29aSZiyuan Xu 901b673f29aSZiyuan Xu /* Switch card to DDR */ 902b673f29aSZiyuan Xu ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 903b673f29aSZiyuan Xu EXT_CSD_BUS_WIDTH, 904b673f29aSZiyuan Xu EXT_CSD_DDR_BUS_WIDTH_8); 905b673f29aSZiyuan Xu if (ret) 906b673f29aSZiyuan Xu return ret; 907b673f29aSZiyuan Xu 908b673f29aSZiyuan Xu /* Switch card to HS400 */ 909b673f29aSZiyuan Xu ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 910b673f29aSZiyuan Xu EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400, false); 911b673f29aSZiyuan Xu if (ret) 912b673f29aSZiyuan Xu return ret; 913b673f29aSZiyuan Xu 914b673f29aSZiyuan Xu /* Set host controller to HS400 timing and frequency */ 915b673f29aSZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_MMC_HS400); 916b673f29aSZiyuan Xu 917b673f29aSZiyuan Xu return ret; 918b673f29aSZiyuan Xu } 919b673f29aSZiyuan Xu 920227f658eSZiyuan Xu static u32 mmc_select_card_type(struct mmc *mmc, u8 *ext_csd) 921227f658eSZiyuan Xu { 922227f658eSZiyuan Xu u8 card_type; 923227f658eSZiyuan Xu u32 host_caps, avail_type = 0; 924227f658eSZiyuan Xu 925227f658eSZiyuan Xu card_type = ext_csd[EXT_CSD_CARD_TYPE]; 926227f658eSZiyuan Xu host_caps = mmc->cfg->host_caps; 927227f658eSZiyuan Xu 928227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS) && 929227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_26)) 930227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_26; 931227f658eSZiyuan Xu 932227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS) && 933227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_52)) 934227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_52; 935227f658eSZiyuan Xu 936227f658eSZiyuan Xu /* 937227f658eSZiyuan Xu * For the moment, u-boot doesn't support signal voltage 938227f658eSZiyuan Xu * switch, therefor we assume that host support ddr52 939227f658eSZiyuan Xu * at 1.8v or 3.3v I/O(1.2v I/O not supported, hs200 and 940227f658eSZiyuan Xu * hs400 are the same). 941227f658eSZiyuan Xu */ 942227f658eSZiyuan Xu if ((host_caps & MMC_MODE_DDR_52MHz) && 943227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)) 944227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V; 945227f658eSZiyuan Xu 946227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS200) && 947227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_HS200_1_8V)) 948227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V; 949227f658eSZiyuan Xu 950227f658eSZiyuan Xu /* 951227f658eSZiyuan Xu * If host can support HS400, it means that host can also 952227f658eSZiyuan Xu * support HS200. 953227f658eSZiyuan Xu */ 954227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS400) && 955227f658eSZiyuan Xu (host_caps & MMC_MODE_8BIT) && 956227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_HS400_1_8V)) 957227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V | 958227f658eSZiyuan Xu EXT_CSD_CARD_TYPE_HS400_1_8V; 959227f658eSZiyuan Xu 960227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS400ES) && 961227f658eSZiyuan Xu (host_caps & MMC_MODE_8BIT) && 962227f658eSZiyuan Xu ext_csd[EXT_CSD_STROBE_SUPPORT] && 963227f658eSZiyuan Xu (avail_type & EXT_CSD_CARD_TYPE_HS400_1_8V)) 964227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V | 965227f658eSZiyuan Xu EXT_CSD_CARD_TYPE_HS400_1_8V | 966227f658eSZiyuan Xu EXT_CSD_CARD_TYPE_HS400ES; 967227f658eSZiyuan Xu 968227f658eSZiyuan Xu return avail_type; 969227f658eSZiyuan Xu } 970227f658eSZiyuan Xu 97149dba033SZiyuan Xu static void mmc_set_bus_speed(struct mmc *mmc, u8 avail_type) 97249dba033SZiyuan Xu { 97349dba033SZiyuan Xu int clock = 0; 97449dba033SZiyuan Xu 97549dba033SZiyuan Xu if (mmc_card_hs(mmc)) 97649dba033SZiyuan Xu clock = (avail_type & EXT_CSD_CARD_TYPE_52) ? 97749dba033SZiyuan Xu MMC_HIGH_52_MAX_DTR : MMC_HIGH_26_MAX_DTR; 97849dba033SZiyuan Xu else if (mmc_card_hs200(mmc) || 97949dba033SZiyuan Xu mmc_card_hs400(mmc) || 98049dba033SZiyuan Xu mmc_card_hs400es(mmc)) 98149dba033SZiyuan Xu clock = MMC_HS200_MAX_DTR; 98249dba033SZiyuan Xu 98349dba033SZiyuan Xu mmc_set_clock(mmc, clock); 98449dba033SZiyuan Xu } 98549dba033SZiyuan Xu 986fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc) 987272cc70bSAndy Fleming { 9888bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 989227f658eSZiyuan Xu u32 avail_type; 990272cc70bSAndy Fleming int err; 991272cc70bSAndy Fleming 992fc5b32fbSAndrew Gabbasov mmc->card_caps = 0; 993272cc70bSAndy Fleming 994d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 995d52ebf10SThomas Chou return 0; 996d52ebf10SThomas Chou 997272cc70bSAndy Fleming /* Only version 4 supports high-speed */ 998272cc70bSAndy Fleming if (mmc->version < MMC_VERSION_4) 999272cc70bSAndy Fleming return 0; 1000272cc70bSAndy Fleming 1001fc5b32fbSAndrew Gabbasov mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; 1002fc5b32fbSAndrew Gabbasov 1003272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 1004272cc70bSAndy Fleming 1005272cc70bSAndy Fleming if (err) 1006272cc70bSAndy Fleming return err; 1007272cc70bSAndy Fleming 1008227f658eSZiyuan Xu avail_type = mmc_select_card_type(mmc, ext_csd); 1009272cc70bSAndy Fleming 101049dba033SZiyuan Xu if (avail_type & EXT_CSD_CARD_TYPE_HS200) 101149dba033SZiyuan Xu err = mmc_select_hs200(mmc); 10121f250d0aSJason Zhu else if (avail_type & EXT_CSD_CARD_TYPE_HS) 1013e61cd3d7SZiyuan Xu err = mmc_select_hs(mmc); 1014227f658eSZiyuan Xu else 1015227f658eSZiyuan Xu err = -EINVAL; 1016272cc70bSAndy Fleming 1017272cc70bSAndy Fleming if (err) 1018a5e27b41SHeiko Schocher return err; 1019272cc70bSAndy Fleming 102049dba033SZiyuan Xu mmc_set_bus_speed(mmc, avail_type); 1021272cc70bSAndy Fleming 1022b673f29aSZiyuan Xu if (mmc_card_hs200(mmc)) { 102349dba033SZiyuan Xu err = mmc_hs200_tuning(mmc); 1024b673f29aSZiyuan Xu if (avail_type & EXT_CSD_CARD_TYPE_HS400 && 1025b673f29aSZiyuan Xu mmc->bus_width == MMC_BUS_WIDTH_8BIT) { 1026b673f29aSZiyuan Xu err = mmc_select_hs400(mmc); 1027b673f29aSZiyuan Xu mmc_set_bus_speed(mmc, avail_type); 1028b673f29aSZiyuan Xu } 1029b673f29aSZiyuan Xu } else if (!mmc_card_hs400es(mmc)) { 103049dba033SZiyuan Xu err = mmc_select_bus_width(mmc) > 0 ? 0 : err; 10315545757fSZiyuan Xu if (!err && avail_type & EXT_CSD_CARD_TYPE_DDR_52) 10325545757fSZiyuan Xu err = mmc_select_hs_ddr(mmc); 10335545757fSZiyuan Xu } 103449dba033SZiyuan Xu 1035272cc70bSAndy Fleming return err; 1036272cc70bSAndy Fleming } 1037272cc70bSAndy Fleming 1038f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num) 1039f866a46dSStephen Warren { 1040f866a46dSStephen Warren switch (part_num) { 1041f866a46dSStephen Warren case 0: 1042f866a46dSStephen Warren mmc->capacity = mmc->capacity_user; 1043f866a46dSStephen Warren break; 1044f866a46dSStephen Warren case 1: 1045f866a46dSStephen Warren case 2: 1046f866a46dSStephen Warren mmc->capacity = mmc->capacity_boot; 1047f866a46dSStephen Warren break; 1048f866a46dSStephen Warren case 3: 1049f866a46dSStephen Warren mmc->capacity = mmc->capacity_rpmb; 1050f866a46dSStephen Warren break; 1051f866a46dSStephen Warren case 4: 1052f866a46dSStephen Warren case 5: 1053f866a46dSStephen Warren case 6: 1054f866a46dSStephen Warren case 7: 1055f866a46dSStephen Warren mmc->capacity = mmc->capacity_gp[part_num - 4]; 1056f866a46dSStephen Warren break; 1057f866a46dSStephen Warren default: 1058f866a46dSStephen Warren return -1; 1059f866a46dSStephen Warren } 1060f866a46dSStephen Warren 1061c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len); 1062f866a46dSStephen Warren 1063f866a46dSStephen Warren return 0; 1064f866a46dSStephen Warren } 1065f866a46dSStephen Warren 10667dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num) 1067bc897b1dSLei Wen { 1068f866a46dSStephen Warren int ret; 1069bc897b1dSLei Wen 1070f866a46dSStephen Warren ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 1071bc897b1dSLei Wen (mmc->part_config & ~PART_ACCESS_MASK) 1072bc897b1dSLei Wen | (part_num & PART_ACCESS_MASK)); 1073f866a46dSStephen Warren 10746dc93e70SPeter Bigot /* 10756dc93e70SPeter Bigot * Set the capacity if the switch succeeded or was intended 10766dc93e70SPeter Bigot * to return to representing the raw device. 10776dc93e70SPeter Bigot */ 1078873cc1d7SStephen Warren if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) { 10796dc93e70SPeter Bigot ret = mmc_set_capacity(mmc, part_num); 1080fdbb139fSSimon Glass mmc_get_blk_desc(mmc)->hwpart = part_num; 1081873cc1d7SStephen Warren } 10826dc93e70SPeter Bigot 10836dc93e70SPeter Bigot return ret; 1084bc897b1dSLei Wen } 1085bc897b1dSLei Wen 1086ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc, 1087ac9da0e0SDiego Santa Cruz const struct mmc_hwpart_conf *conf, 1088ac9da0e0SDiego Santa Cruz enum mmc_hwpart_conf_mode mode) 1089ac9da0e0SDiego Santa Cruz { 1090ac9da0e0SDiego Santa Cruz u8 part_attrs = 0; 1091ac9da0e0SDiego Santa Cruz u32 enh_size_mult; 1092ac9da0e0SDiego Santa Cruz u32 enh_start_addr; 1093ac9da0e0SDiego Santa Cruz u32 gp_size_mult[4]; 1094ac9da0e0SDiego Santa Cruz u32 max_enh_size_mult; 1095ac9da0e0SDiego Santa Cruz u32 tot_enh_size_mult = 0; 10968dda5b0eSDiego Santa Cruz u8 wr_rel_set; 1097ac9da0e0SDiego Santa Cruz int i, pidx, err; 1098ac9da0e0SDiego Santa Cruz ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 1099ac9da0e0SDiego Santa Cruz 1100ac9da0e0SDiego Santa Cruz if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE) 1101ac9da0e0SDiego Santa Cruz return -EINVAL; 1102ac9da0e0SDiego Santa Cruz 1103ac9da0e0SDiego Santa Cruz if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) { 1104ac9da0e0SDiego Santa Cruz printf("eMMC >= 4.4 required for enhanced user data area\n"); 1105ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1106ac9da0e0SDiego Santa Cruz } 1107ac9da0e0SDiego Santa Cruz 1108ac9da0e0SDiego Santa Cruz if (!(mmc->part_support & PART_SUPPORT)) { 1109ac9da0e0SDiego Santa Cruz printf("Card does not support partitioning\n"); 1110ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1111ac9da0e0SDiego Santa Cruz } 1112ac9da0e0SDiego Santa Cruz 1113ac9da0e0SDiego Santa Cruz if (!mmc->hc_wp_grp_size) { 1114ac9da0e0SDiego Santa Cruz printf("Card does not define HC WP group size\n"); 1115ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1116ac9da0e0SDiego Santa Cruz } 1117ac9da0e0SDiego Santa Cruz 1118ac9da0e0SDiego Santa Cruz /* check partition alignment and total enhanced size */ 1119ac9da0e0SDiego Santa Cruz if (conf->user.enh_size) { 1120ac9da0e0SDiego Santa Cruz if (conf->user.enh_size % mmc->hc_wp_grp_size || 1121ac9da0e0SDiego Santa Cruz conf->user.enh_start % mmc->hc_wp_grp_size) { 1122ac9da0e0SDiego Santa Cruz printf("User data enhanced area not HC WP group " 1123ac9da0e0SDiego Santa Cruz "size aligned\n"); 1124ac9da0e0SDiego Santa Cruz return -EINVAL; 1125ac9da0e0SDiego Santa Cruz } 1126ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_USR; 1127ac9da0e0SDiego Santa Cruz enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size; 1128ac9da0e0SDiego Santa Cruz if (mmc->high_capacity) { 1129ac9da0e0SDiego Santa Cruz enh_start_addr = conf->user.enh_start; 1130ac9da0e0SDiego Santa Cruz } else { 1131ac9da0e0SDiego Santa Cruz enh_start_addr = (conf->user.enh_start << 9); 1132ac9da0e0SDiego Santa Cruz } 1133ac9da0e0SDiego Santa Cruz } else { 1134ac9da0e0SDiego Santa Cruz enh_size_mult = 0; 1135ac9da0e0SDiego Santa Cruz enh_start_addr = 0; 1136ac9da0e0SDiego Santa Cruz } 1137ac9da0e0SDiego Santa Cruz tot_enh_size_mult += enh_size_mult; 1138ac9da0e0SDiego Santa Cruz 1139ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 1140ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) { 1141ac9da0e0SDiego Santa Cruz printf("GP%i partition not HC WP group size " 1142ac9da0e0SDiego Santa Cruz "aligned\n", pidx+1); 1143ac9da0e0SDiego Santa Cruz return -EINVAL; 1144ac9da0e0SDiego Santa Cruz } 1145ac9da0e0SDiego Santa Cruz gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size; 1146ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) { 1147ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_GP(pidx); 1148ac9da0e0SDiego Santa Cruz tot_enh_size_mult += gp_size_mult[pidx]; 1149ac9da0e0SDiego Santa Cruz } 1150ac9da0e0SDiego Santa Cruz } 1151ac9da0e0SDiego Santa Cruz 1152ac9da0e0SDiego Santa Cruz if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) { 1153ac9da0e0SDiego Santa Cruz printf("Card does not support enhanced attribute\n"); 1154ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1155ac9da0e0SDiego Santa Cruz } 1156ac9da0e0SDiego Santa Cruz 1157ac9da0e0SDiego Santa Cruz err = mmc_send_ext_csd(mmc, ext_csd); 1158ac9da0e0SDiego Santa Cruz if (err) 1159ac9da0e0SDiego Santa Cruz return err; 1160ac9da0e0SDiego Santa Cruz 1161ac9da0e0SDiego Santa Cruz max_enh_size_mult = 1162ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) + 1163ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) + 1164ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]; 1165ac9da0e0SDiego Santa Cruz if (tot_enh_size_mult > max_enh_size_mult) { 1166ac9da0e0SDiego Santa Cruz printf("Total enhanced size exceeds maximum (%u > %u)\n", 1167ac9da0e0SDiego Santa Cruz tot_enh_size_mult, max_enh_size_mult); 1168ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1169ac9da0e0SDiego Santa Cruz } 1170ac9da0e0SDiego Santa Cruz 11718dda5b0eSDiego Santa Cruz /* The default value of EXT_CSD_WR_REL_SET is device 11728dda5b0eSDiego Santa Cruz * dependent, the values can only be changed if the 11738dda5b0eSDiego Santa Cruz * EXT_CSD_HS_CTRL_REL bit is set. The values can be 11748dda5b0eSDiego Santa Cruz * changed only once and before partitioning is completed. */ 11758dda5b0eSDiego Santa Cruz wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 11768dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_change) { 11778dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_set) 11788dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_USR; 11798dda5b0eSDiego Santa Cruz else 11808dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR; 11818dda5b0eSDiego Santa Cruz } 11828dda5b0eSDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 11838dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_change) { 11848dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_set) 11858dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx); 11868dda5b0eSDiego Santa Cruz else 11878dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx); 11888dda5b0eSDiego Santa Cruz } 11898dda5b0eSDiego Santa Cruz } 11908dda5b0eSDiego Santa Cruz 11918dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] && 11928dda5b0eSDiego Santa Cruz !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) { 11938dda5b0eSDiego Santa Cruz puts("Card does not support host controlled partition write " 11948dda5b0eSDiego Santa Cruz "reliability settings\n"); 11958dda5b0eSDiego Santa Cruz return -EMEDIUMTYPE; 11968dda5b0eSDiego Santa Cruz } 11978dda5b0eSDiego Santa Cruz 1198ac9da0e0SDiego Santa Cruz if (ext_csd[EXT_CSD_PARTITION_SETTING] & 1199ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED) { 1200ac9da0e0SDiego Santa Cruz printf("Card already partitioned\n"); 1201ac9da0e0SDiego Santa Cruz return -EPERM; 1202ac9da0e0SDiego Santa Cruz } 1203ac9da0e0SDiego Santa Cruz 1204ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_CHECK) 1205ac9da0e0SDiego Santa Cruz return 0; 1206ac9da0e0SDiego Santa Cruz 1207ac9da0e0SDiego Santa Cruz /* Partitioning requires high-capacity size definitions */ 1208ac9da0e0SDiego Santa Cruz if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) { 1209ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1210ac9da0e0SDiego Santa Cruz EXT_CSD_ERASE_GROUP_DEF, 1); 1211ac9da0e0SDiego Santa Cruz 1212ac9da0e0SDiego Santa Cruz if (err) 1213ac9da0e0SDiego Santa Cruz return err; 1214ac9da0e0SDiego Santa Cruz 1215ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 1216ac9da0e0SDiego Santa Cruz 1217ac9da0e0SDiego Santa Cruz /* update erase group size to be high-capacity */ 1218ac9da0e0SDiego Santa Cruz mmc->erase_grp_size = 1219ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 1220ac9da0e0SDiego Santa Cruz 1221ac9da0e0SDiego Santa Cruz } 1222ac9da0e0SDiego Santa Cruz 1223ac9da0e0SDiego Santa Cruz /* all OK, write the configuration */ 1224ac9da0e0SDiego Santa Cruz for (i = 0; i < 4; i++) { 1225ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1226ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_START_ADDR+i, 1227ac9da0e0SDiego Santa Cruz (enh_start_addr >> (i*8)) & 0xFF); 1228ac9da0e0SDiego Santa Cruz if (err) 1229ac9da0e0SDiego Santa Cruz return err; 1230ac9da0e0SDiego Santa Cruz } 1231ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 1232ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1233ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_SIZE_MULT+i, 1234ac9da0e0SDiego Santa Cruz (enh_size_mult >> (i*8)) & 0xFF); 1235ac9da0e0SDiego Santa Cruz if (err) 1236ac9da0e0SDiego Santa Cruz return err; 1237ac9da0e0SDiego Santa Cruz } 1238ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 1239ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 1240ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1241ac9da0e0SDiego Santa Cruz EXT_CSD_GP_SIZE_MULT+pidx*3+i, 1242ac9da0e0SDiego Santa Cruz (gp_size_mult[pidx] >> (i*8)) & 0xFF); 1243ac9da0e0SDiego Santa Cruz if (err) 1244ac9da0e0SDiego Santa Cruz return err; 1245ac9da0e0SDiego Santa Cruz } 1246ac9da0e0SDiego Santa Cruz } 1247ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1248ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs); 1249ac9da0e0SDiego Santa Cruz if (err) 1250ac9da0e0SDiego Santa Cruz return err; 1251ac9da0e0SDiego Santa Cruz 1252ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_SET) 1253ac9da0e0SDiego Santa Cruz return 0; 1254ac9da0e0SDiego Santa Cruz 12558dda5b0eSDiego Santa Cruz /* The WR_REL_SET is a write-once register but shall be 12568dda5b0eSDiego Santa Cruz * written before setting PART_SETTING_COMPLETED. As it is 12578dda5b0eSDiego Santa Cruz * write-once we can only write it when completing the 12588dda5b0eSDiego Santa Cruz * partitioning. */ 12598dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) { 12608dda5b0eSDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 12618dda5b0eSDiego Santa Cruz EXT_CSD_WR_REL_SET, wr_rel_set); 12628dda5b0eSDiego Santa Cruz if (err) 12638dda5b0eSDiego Santa Cruz return err; 12648dda5b0eSDiego Santa Cruz } 12658dda5b0eSDiego Santa Cruz 1266ac9da0e0SDiego Santa Cruz /* Setting PART_SETTING_COMPLETED confirms the partition 1267ac9da0e0SDiego Santa Cruz * configuration but it only becomes effective after power 1268ac9da0e0SDiego Santa Cruz * cycle, so we do not adjust the partition related settings 1269ac9da0e0SDiego Santa Cruz * in the mmc struct. */ 1270ac9da0e0SDiego Santa Cruz 1271ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1272ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING, 1273ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 1274ac9da0e0SDiego Santa Cruz if (err) 1275ac9da0e0SDiego Santa Cruz return err; 1276ac9da0e0SDiego Santa Cruz 1277ac9da0e0SDiego Santa Cruz return 0; 1278ac9da0e0SDiego Santa Cruz } 1279ac9da0e0SDiego Santa Cruz 1280e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 128148972d90SThierry Reding int mmc_getcd(struct mmc *mmc) 128248972d90SThierry Reding { 128348972d90SThierry Reding int cd; 128448972d90SThierry Reding 128548972d90SThierry Reding cd = board_mmc_getcd(mmc); 128648972d90SThierry Reding 1287d4e1da4eSPeter Korsgaard if (cd < 0) { 128893bfd616SPantelis Antoniou if (mmc->cfg->ops->getcd) 128993bfd616SPantelis Antoniou cd = mmc->cfg->ops->getcd(mmc); 1290d4e1da4eSPeter Korsgaard else 1291d4e1da4eSPeter Korsgaard cd = 1; 1292d4e1da4eSPeter Korsgaard } 129348972d90SThierry Reding 129448972d90SThierry Reding return cd; 129548972d90SThierry Reding } 12968ca51e51SSimon Glass #endif 129748972d90SThierry Reding 1298fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) 1299272cc70bSAndy Fleming { 1300272cc70bSAndy Fleming struct mmc_cmd cmd; 1301272cc70bSAndy Fleming struct mmc_data data; 1302272cc70bSAndy Fleming 1303272cc70bSAndy Fleming /* Switch the frequency */ 1304272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC; 1305272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1306272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff; 1307272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4)); 1308272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4); 1309272cc70bSAndy Fleming 1310272cc70bSAndy Fleming data.dest = (char *)resp; 1311272cc70bSAndy Fleming data.blocksize = 64; 1312272cc70bSAndy Fleming data.blocks = 1; 1313272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1314272cc70bSAndy Fleming 1315272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 1316272cc70bSAndy Fleming } 1317272cc70bSAndy Fleming 1318272cc70bSAndy Fleming 1319fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc) 1320272cc70bSAndy Fleming { 1321272cc70bSAndy Fleming int err; 1322272cc70bSAndy Fleming struct mmc_cmd cmd; 1323f781dd38SAnton staaf ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2); 1324f781dd38SAnton staaf ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16); 1325272cc70bSAndy Fleming struct mmc_data data; 1326272cc70bSAndy Fleming int timeout; 1327272cc70bSAndy Fleming 1328272cc70bSAndy Fleming mmc->card_caps = 0; 1329272cc70bSAndy Fleming 1330d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 1331d52ebf10SThomas Chou return 0; 1332d52ebf10SThomas Chou 1333272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */ 1334272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 1335272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1336272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1337272cc70bSAndy Fleming 1338272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1339272cc70bSAndy Fleming 1340272cc70bSAndy Fleming if (err) 1341272cc70bSAndy Fleming return err; 1342272cc70bSAndy Fleming 1343272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR; 1344272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1345272cc70bSAndy Fleming cmd.cmdarg = 0; 1346272cc70bSAndy Fleming 1347272cc70bSAndy Fleming timeout = 3; 1348272cc70bSAndy Fleming 1349272cc70bSAndy Fleming retry_scr: 1350f781dd38SAnton staaf data.dest = (char *)scr; 1351272cc70bSAndy Fleming data.blocksize = 8; 1352272cc70bSAndy Fleming data.blocks = 1; 1353272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1354272cc70bSAndy Fleming 1355272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 1356272cc70bSAndy Fleming 1357272cc70bSAndy Fleming if (err) { 1358272cc70bSAndy Fleming if (timeout--) 1359272cc70bSAndy Fleming goto retry_scr; 1360272cc70bSAndy Fleming 1361272cc70bSAndy Fleming return err; 1362272cc70bSAndy Fleming } 1363272cc70bSAndy Fleming 13644e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]); 13654e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]); 1366272cc70bSAndy Fleming 1367272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) { 1368272cc70bSAndy Fleming case 0: 1369272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1370272cc70bSAndy Fleming break; 1371272cc70bSAndy Fleming case 1: 1372272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10; 1373272cc70bSAndy Fleming break; 1374272cc70bSAndy Fleming case 2: 1375272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 13761741c64dSJaehoon Chung if ((mmc->scr[0] >> 15) & 0x1) 13771741c64dSJaehoon Chung mmc->version = SD_VERSION_3; 1378272cc70bSAndy Fleming break; 1379272cc70bSAndy Fleming default: 1380272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1381272cc70bSAndy Fleming break; 1382272cc70bSAndy Fleming } 1383272cc70bSAndy Fleming 1384b44c7083SAlagu Sankar if (mmc->scr[0] & SD_DATA_4BIT) 1385b44c7083SAlagu Sankar mmc->card_caps |= MMC_MODE_4BIT; 1386b44c7083SAlagu Sankar 1387272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */ 1388272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0) 1389272cc70bSAndy Fleming return 0; 1390272cc70bSAndy Fleming 1391272cc70bSAndy Fleming timeout = 4; 1392272cc70bSAndy Fleming while (timeout--) { 1393272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, 1394f781dd38SAnton staaf (u8 *)switch_status); 1395272cc70bSAndy Fleming 1396272cc70bSAndy Fleming if (err) 1397272cc70bSAndy Fleming return err; 1398272cc70bSAndy Fleming 1399272cc70bSAndy Fleming /* The high-speed function is busy. Try again */ 14004e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) 1401272cc70bSAndy Fleming break; 1402272cc70bSAndy Fleming } 1403272cc70bSAndy Fleming 1404272cc70bSAndy Fleming /* If high-speed isn't supported, we return */ 14054e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)) 1406272cc70bSAndy Fleming return 0; 1407272cc70bSAndy Fleming 14082c3fbf4cSMacpaul Lin /* 14092c3fbf4cSMacpaul Lin * If the host doesn't support SD_HIGHSPEED, do not switch card to 14102c3fbf4cSMacpaul Lin * HIGHSPEED mode even if the card support SD_HIGHSPPED. 14112c3fbf4cSMacpaul Lin * This can avoid furthur problem when the card runs in different 14122c3fbf4cSMacpaul Lin * mode between the host. 14132c3fbf4cSMacpaul Lin */ 141493bfd616SPantelis Antoniou if (!((mmc->cfg->host_caps & MMC_MODE_HS_52MHz) && 141593bfd616SPantelis Antoniou (mmc->cfg->host_caps & MMC_MODE_HS))) 14162c3fbf4cSMacpaul Lin return 0; 14172c3fbf4cSMacpaul Lin 1418f781dd38SAnton staaf err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status); 1419272cc70bSAndy Fleming 1420272cc70bSAndy Fleming if (err) 1421272cc70bSAndy Fleming return err; 1422272cc70bSAndy Fleming 14234e3d89baSYauhen Kharuzhy if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000) 1424272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS; 1425272cc70bSAndy Fleming 1426272cc70bSAndy Fleming return 0; 1427272cc70bSAndy Fleming } 1428272cc70bSAndy Fleming 14293697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc) 14303697e599SPeng Fan { 14313697e599SPeng Fan int err, i; 14323697e599SPeng Fan struct mmc_cmd cmd; 14333697e599SPeng Fan ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16); 14343697e599SPeng Fan struct mmc_data data; 14353697e599SPeng Fan int timeout = 3; 14363697e599SPeng Fan unsigned int au, eo, et, es; 14373697e599SPeng Fan 14383697e599SPeng Fan cmd.cmdidx = MMC_CMD_APP_CMD; 14393697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 14403697e599SPeng Fan cmd.cmdarg = mmc->rca << 16; 14413697e599SPeng Fan 14423697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, NULL); 14433697e599SPeng Fan if (err) 14443697e599SPeng Fan return err; 14453697e599SPeng Fan 14463697e599SPeng Fan cmd.cmdidx = SD_CMD_APP_SD_STATUS; 14473697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 14483697e599SPeng Fan cmd.cmdarg = 0; 14493697e599SPeng Fan 14503697e599SPeng Fan retry_ssr: 14513697e599SPeng Fan data.dest = (char *)ssr; 14523697e599SPeng Fan data.blocksize = 64; 14533697e599SPeng Fan data.blocks = 1; 14543697e599SPeng Fan data.flags = MMC_DATA_READ; 14553697e599SPeng Fan 14563697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, &data); 14573697e599SPeng Fan if (err) { 14583697e599SPeng Fan if (timeout--) 14593697e599SPeng Fan goto retry_ssr; 14603697e599SPeng Fan 14613697e599SPeng Fan return err; 14623697e599SPeng Fan } 14633697e599SPeng Fan 14643697e599SPeng Fan for (i = 0; i < 16; i++) 14653697e599SPeng Fan ssr[i] = be32_to_cpu(ssr[i]); 14663697e599SPeng Fan 14673697e599SPeng Fan au = (ssr[2] >> 12) & 0xF; 14683697e599SPeng Fan if ((au <= 9) || (mmc->version == SD_VERSION_3)) { 14693697e599SPeng Fan mmc->ssr.au = sd_au_size[au]; 14703697e599SPeng Fan es = (ssr[3] >> 24) & 0xFF; 14713697e599SPeng Fan es |= (ssr[2] & 0xFF) << 8; 14723697e599SPeng Fan et = (ssr[3] >> 18) & 0x3F; 14733697e599SPeng Fan if (es && et) { 14743697e599SPeng Fan eo = (ssr[3] >> 16) & 0x3; 14753697e599SPeng Fan mmc->ssr.erase_timeout = (et * 1000) / es; 14763697e599SPeng Fan mmc->ssr.erase_offset = eo * 1000; 14773697e599SPeng Fan } 14783697e599SPeng Fan } else { 14793697e599SPeng Fan debug("Invalid Allocation Unit Size.\n"); 14803697e599SPeng Fan } 14813697e599SPeng Fan 14823697e599SPeng Fan return 0; 14833697e599SPeng Fan } 14843697e599SPeng Fan 1485272cc70bSAndy Fleming /* frequency bases */ 1486272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */ 14875f837c2cSMike Frysinger static const int fbase[] = { 1488272cc70bSAndy Fleming 10000, 1489272cc70bSAndy Fleming 100000, 1490272cc70bSAndy Fleming 1000000, 1491272cc70bSAndy Fleming 10000000, 1492272cc70bSAndy Fleming }; 1493272cc70bSAndy Fleming 1494272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice 1495272cc70bSAndy Fleming * to platforms without floating point. 1496272cc70bSAndy Fleming */ 149761fe076fSSimon Glass static const u8 multipliers[] = { 1498272cc70bSAndy Fleming 0, /* reserved */ 1499272cc70bSAndy Fleming 10, 1500272cc70bSAndy Fleming 12, 1501272cc70bSAndy Fleming 13, 1502272cc70bSAndy Fleming 15, 1503272cc70bSAndy Fleming 20, 1504272cc70bSAndy Fleming 25, 1505272cc70bSAndy Fleming 30, 1506272cc70bSAndy Fleming 35, 1507272cc70bSAndy Fleming 40, 1508272cc70bSAndy Fleming 45, 1509272cc70bSAndy Fleming 50, 1510272cc70bSAndy Fleming 55, 1511272cc70bSAndy Fleming 60, 1512272cc70bSAndy Fleming 70, 1513272cc70bSAndy Fleming 80, 1514272cc70bSAndy Fleming }; 1515272cc70bSAndy Fleming 1516e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 1517fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc) 1518272cc70bSAndy Fleming { 151993bfd616SPantelis Antoniou if (mmc->cfg->ops->set_ios) 152093bfd616SPantelis Antoniou mmc->cfg->ops->set_ios(mmc); 1521272cc70bSAndy Fleming } 1522ad77484aSZiyuan Xu 1523ad77484aSZiyuan Xu static bool mmc_card_busy(struct mmc *mmc) 1524ad77484aSZiyuan Xu { 1525ad77484aSZiyuan Xu if (!mmc->cfg->ops->card_busy) 1526ad77484aSZiyuan Xu return -ENOSYS; 1527ad77484aSZiyuan Xu 1528ad77484aSZiyuan Xu return mmc->cfg->ops->card_busy(mmc); 1529ad77484aSZiyuan Xu } 1530ad77484aSZiyuan Xu 1531ad77484aSZiyuan Xu static bool mmc_can_card_busy(struct mmc *) 1532ad77484aSZiyuan Xu { 1533ad77484aSZiyuan Xu return !!mmc->cfg->ops->card_busy; 1534ad77484aSZiyuan Xu } 15358ca51e51SSimon Glass #endif 1536272cc70bSAndy Fleming 1537fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc) 1538272cc70bSAndy Fleming { 1539f866a46dSStephen Warren int err, i; 15403e3ff0acSZiyuan Xu uint mult, freq, tran_speed; 1541639b7827SYoshihiro Shimoda u64 cmult, csize, capacity; 1542272cc70bSAndy Fleming struct mmc_cmd cmd; 15438bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 15440c453bb7SDiego Santa Cruz bool has_parts = false; 15458a0cf490SDiego Santa Cruz bool part_completed; 1546c40fdca6SSimon Glass struct blk_desc *bdesc; 1547272cc70bSAndy Fleming 1548d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON 1549d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ 1550d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; 1551d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R1; 1552d52ebf10SThomas Chou cmd.cmdarg = 1; 1553d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 1554d52ebf10SThomas Chou 1555d52ebf10SThomas Chou if (err) 1556d52ebf10SThomas Chou return err; 1557d52ebf10SThomas Chou } 1558d52ebf10SThomas Chou #endif 1559*479fbf72SJason Zhu #ifndef CONFIG_MMC_USE_PRE_CONFIG 1560272cc70bSAndy Fleming /* Put the Card in Identify Mode */ 1561d52ebf10SThomas Chou cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : 1562d52ebf10SThomas Chou MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ 1563272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1564272cc70bSAndy Fleming cmd.cmdarg = 0; 1565272cc70bSAndy Fleming 1566272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1567272cc70bSAndy Fleming 1568272cc70bSAndy Fleming if (err) 1569272cc70bSAndy Fleming return err; 1570272cc70bSAndy Fleming 1571272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16); 1572272cc70bSAndy Fleming 1573272cc70bSAndy Fleming /* 1574272cc70bSAndy Fleming * For MMC cards, set the Relative Address. 1575272cc70bSAndy Fleming * For SD cards, get the Relatvie Address. 1576272cc70bSAndy Fleming * This also puts the cards into Standby State 1577272cc70bSAndy Fleming */ 1578d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1579272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; 1580272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1581272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6; 1582272cc70bSAndy Fleming 1583272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1584272cc70bSAndy Fleming 1585272cc70bSAndy Fleming if (err) 1586272cc70bSAndy Fleming return err; 1587272cc70bSAndy Fleming 1588272cc70bSAndy Fleming if (IS_SD(mmc)) 1589998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff; 1590d52ebf10SThomas Chou } 1591*479fbf72SJason Zhu #endif 1592272cc70bSAndy Fleming /* Get the Card-Specific Data */ 1593272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD; 1594272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1595272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1596272cc70bSAndy Fleming 1597272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1598272cc70bSAndy Fleming 1599272cc70bSAndy Fleming if (err) 1600272cc70bSAndy Fleming return err; 1601272cc70bSAndy Fleming 1602998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0]; 1603998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1]; 1604998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2]; 1605998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3]; 1606272cc70bSAndy Fleming 1607272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) { 16080b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf; 1609272cc70bSAndy Fleming 1610272cc70bSAndy Fleming switch (version) { 1611272cc70bSAndy Fleming case 0: 1612272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1613272cc70bSAndy Fleming break; 1614272cc70bSAndy Fleming case 1: 1615272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4; 1616272cc70bSAndy Fleming break; 1617272cc70bSAndy Fleming case 2: 1618272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2; 1619272cc70bSAndy Fleming break; 1620272cc70bSAndy Fleming case 3: 1621272cc70bSAndy Fleming mmc->version = MMC_VERSION_3; 1622272cc70bSAndy Fleming break; 1623272cc70bSAndy Fleming case 4: 1624272cc70bSAndy Fleming mmc->version = MMC_VERSION_4; 1625272cc70bSAndy Fleming break; 1626272cc70bSAndy Fleming default: 1627272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1628272cc70bSAndy Fleming break; 1629272cc70bSAndy Fleming } 1630272cc70bSAndy Fleming } 1631272cc70bSAndy Fleming 1632272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */ 16330b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)]; 16340b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; 1635272cc70bSAndy Fleming 16363e3ff0acSZiyuan Xu tran_speed = freq * mult; 1637272cc70bSAndy Fleming 1638ab71188cSMarkus Niebel mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); 1639998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); 1640272cc70bSAndy Fleming 1641272cc70bSAndy Fleming if (IS_SD(mmc)) 1642272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len; 1643272cc70bSAndy Fleming else 1644998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); 1645272cc70bSAndy Fleming 1646272cc70bSAndy Fleming if (mmc->high_capacity) { 1647272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16 1648272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16; 1649272cc70bSAndy Fleming cmult = 8; 1650272cc70bSAndy Fleming } else { 1651272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2 1652272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30; 1653272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15; 1654272cc70bSAndy Fleming } 1655272cc70bSAndy Fleming 1656f866a46dSStephen Warren mmc->capacity_user = (csize + 1) << (cmult + 2); 1657f866a46dSStephen Warren mmc->capacity_user *= mmc->read_bl_len; 1658f866a46dSStephen Warren mmc->capacity_boot = 0; 1659f866a46dSStephen Warren mmc->capacity_rpmb = 0; 1660f866a46dSStephen Warren for (i = 0; i < 4; i++) 1661f866a46dSStephen Warren mmc->capacity_gp[i] = 0; 1662272cc70bSAndy Fleming 16638bfa195eSSimon Glass if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN) 16648bfa195eSSimon Glass mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 1665272cc70bSAndy Fleming 16668bfa195eSSimon Glass if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) 16678bfa195eSSimon Glass mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 1668272cc70bSAndy Fleming 1669ab71188cSMarkus Niebel if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) { 1670ab71188cSMarkus Niebel cmd.cmdidx = MMC_CMD_SET_DSR; 1671ab71188cSMarkus Niebel cmd.cmdarg = (mmc->dsr & 0xffff) << 16; 1672ab71188cSMarkus Niebel cmd.resp_type = MMC_RSP_NONE; 1673ab71188cSMarkus Niebel if (mmc_send_cmd(mmc, &cmd, NULL)) 1674ab71188cSMarkus Niebel printf("MMC: SET_DSR failed\n"); 1675ab71188cSMarkus Niebel } 1676ab71188cSMarkus Niebel 1677272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */ 1678d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1679272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD; 1680fe8f7066SAjay Bhargav cmd.resp_type = MMC_RSP_R1; 1681272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1682272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1683272cc70bSAndy Fleming 1684272cc70bSAndy Fleming if (err) 1685272cc70bSAndy Fleming return err; 1686d52ebf10SThomas Chou } 1687272cc70bSAndy Fleming 1688e6f99a56SLei Wen /* 1689e6f99a56SLei Wen * For SD, its erase group is always one sector 1690e6f99a56SLei Wen */ 1691e6f99a56SLei Wen mmc->erase_grp_size = 1; 1692bc897b1dSLei Wen mmc->part_config = MMCPART_NOAVAILABLE; 1693d23e2c09SSukumar Ghorai if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) { 1694d23e2c09SSukumar Ghorai /* check ext_csd version and capacity */ 1695d23e2c09SSukumar Ghorai err = mmc_send_ext_csd(mmc, ext_csd); 16969cf199ebSDiego Santa Cruz if (err) 16979cf199ebSDiego Santa Cruz return err; 16989cf199ebSDiego Santa Cruz if (ext_csd[EXT_CSD_REV] >= 2) { 1699639b7827SYoshihiro Shimoda /* 1700639b7827SYoshihiro Shimoda * According to the JEDEC Standard, the value of 1701639b7827SYoshihiro Shimoda * ext_csd's capacity is valid if the value is more 1702639b7827SYoshihiro Shimoda * than 2GB 1703639b7827SYoshihiro Shimoda */ 17040560db18SLei Wen capacity = ext_csd[EXT_CSD_SEC_CNT] << 0 17050560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 17060560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 17070560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; 17088bfa195eSSimon Glass capacity *= MMC_MAX_BLOCK_LEN; 1709b1f1e821SŁukasz Majewski if ((capacity >> 20) > 2 * 1024) 1710f866a46dSStephen Warren mmc->capacity_user = capacity; 1711d23e2c09SSukumar Ghorai } 1712bc897b1dSLei Wen 171364f4a619SJaehoon Chung switch (ext_csd[EXT_CSD_REV]) { 171464f4a619SJaehoon Chung case 1: 171564f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_1; 171664f4a619SJaehoon Chung break; 171764f4a619SJaehoon Chung case 2: 171864f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_2; 171964f4a619SJaehoon Chung break; 172064f4a619SJaehoon Chung case 3: 172164f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_3; 172264f4a619SJaehoon Chung break; 172364f4a619SJaehoon Chung case 5: 172464f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_41; 172564f4a619SJaehoon Chung break; 172664f4a619SJaehoon Chung case 6: 172764f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_5; 172864f4a619SJaehoon Chung break; 1729edab723bSMarkus Niebel case 7: 1730edab723bSMarkus Niebel mmc->version = MMC_VERSION_5_0; 1731edab723bSMarkus Niebel break; 17321a3619cfSStefan Wahren case 8: 17331a3619cfSStefan Wahren mmc->version = MMC_VERSION_5_1; 17341a3619cfSStefan Wahren break; 173564f4a619SJaehoon Chung } 173664f4a619SJaehoon Chung 17378a0cf490SDiego Santa Cruz /* The partition data may be non-zero but it is only 17388a0cf490SDiego Santa Cruz * effective if PARTITION_SETTING_COMPLETED is set in 17398a0cf490SDiego Santa Cruz * EXT_CSD, so ignore any data if this bit is not set, 17408a0cf490SDiego Santa Cruz * except for enabling the high-capacity group size 17418a0cf490SDiego Santa Cruz * definition (see below). */ 17428a0cf490SDiego Santa Cruz part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] & 17438a0cf490SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 17448a0cf490SDiego Santa Cruz 17450c453bb7SDiego Santa Cruz /* store the partition info of emmc */ 17460c453bb7SDiego Santa Cruz mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT]; 17470c453bb7SDiego Santa Cruz if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || 17480c453bb7SDiego Santa Cruz ext_csd[EXT_CSD_BOOT_MULT]) 17490c453bb7SDiego Santa Cruz mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; 17508a0cf490SDiego Santa Cruz if (part_completed && 17518a0cf490SDiego Santa Cruz (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT)) 17520c453bb7SDiego Santa Cruz mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]; 1753a6a1f5f8SJason Zhu if (ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] & EXT_CSD_SEC_GB_CL_EN) 1754a6a1f5f8SJason Zhu mmc->esr.mmc_can_trim = 1; 17550c453bb7SDiego Santa Cruz 17560c453bb7SDiego Santa Cruz mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17; 17570c453bb7SDiego Santa Cruz 17580c453bb7SDiego Santa Cruz mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17; 17590c453bb7SDiego Santa Cruz 17600c453bb7SDiego Santa Cruz for (i = 0; i < 4; i++) { 17610c453bb7SDiego Santa Cruz int idx = EXT_CSD_GP_SIZE_MULT + i * 3; 17628a0cf490SDiego Santa Cruz uint mult = (ext_csd[idx + 2] << 16) + 17630c453bb7SDiego Santa Cruz (ext_csd[idx + 1] << 8) + ext_csd[idx]; 17648a0cf490SDiego Santa Cruz if (mult) 17658a0cf490SDiego Santa Cruz has_parts = true; 17668a0cf490SDiego Santa Cruz if (!part_completed) 17678a0cf490SDiego Santa Cruz continue; 17688a0cf490SDiego Santa Cruz mmc->capacity_gp[i] = mult; 17690c453bb7SDiego Santa Cruz mmc->capacity_gp[i] *= 17700c453bb7SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 17710c453bb7SDiego Santa Cruz mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1772f8e89d67SDiego Santa Cruz mmc->capacity_gp[i] <<= 19; 17730c453bb7SDiego Santa Cruz } 17740c453bb7SDiego Santa Cruz 17758a0cf490SDiego Santa Cruz if (part_completed) { 1776a7f852b6SDiego Santa Cruz mmc->enh_user_size = 1777a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_SIZE_MULT+2] << 16) + 1778a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_SIZE_MULT+1] << 8) + 1779a7f852b6SDiego Santa Cruz ext_csd[EXT_CSD_ENH_SIZE_MULT]; 1780a7f852b6SDiego Santa Cruz mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1781a7f852b6SDiego Santa Cruz mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1782a7f852b6SDiego Santa Cruz mmc->enh_user_size <<= 19; 1783a7f852b6SDiego Santa Cruz mmc->enh_user_start = 1784a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_START_ADDR+3] << 24) + 1785a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_START_ADDR+2] << 16) + 1786a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_START_ADDR+1] << 8) + 1787a7f852b6SDiego Santa Cruz ext_csd[EXT_CSD_ENH_START_ADDR]; 1788a7f852b6SDiego Santa Cruz if (mmc->high_capacity) 1789a7f852b6SDiego Santa Cruz mmc->enh_user_start <<= 9; 17908a0cf490SDiego Santa Cruz } 1791a7f852b6SDiego Santa Cruz 1792e6f99a56SLei Wen /* 17931937e5aaSOliver Metz * Host needs to enable ERASE_GRP_DEF bit if device is 17941937e5aaSOliver Metz * partitioned. This bit will be lost every time after a reset 17951937e5aaSOliver Metz * or power off. This will affect erase size. 1796e6f99a56SLei Wen */ 17978a0cf490SDiego Santa Cruz if (part_completed) 17980c453bb7SDiego Santa Cruz has_parts = true; 17991937e5aaSOliver Metz if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) && 18000c453bb7SDiego Santa Cruz (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) 18010c453bb7SDiego Santa Cruz has_parts = true; 18020c453bb7SDiego Santa Cruz if (has_parts) { 18031937e5aaSOliver Metz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 18041937e5aaSOliver Metz EXT_CSD_ERASE_GROUP_DEF, 1); 18051937e5aaSOliver Metz 18061937e5aaSOliver Metz if (err) 18071937e5aaSOliver Metz return err; 1808021a8055SHannes Petermaier else 1809021a8055SHannes Petermaier ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 1810037dc0abSDiego Santa Cruz } 18111937e5aaSOliver Metz 1812037dc0abSDiego Santa Cruz if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) { 18131937e5aaSOliver Metz /* Read out group size from ext_csd */ 18140560db18SLei Wen mmc->erase_grp_size = 1815a4ff9f83SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 1816d7b29129SMarkus Niebel /* 1817d7b29129SMarkus Niebel * if high capacity and partition setting completed 1818d7b29129SMarkus Niebel * SEC_COUNT is valid even if it is smaller than 2 GiB 1819d7b29129SMarkus Niebel * JEDEC Standard JESD84-B45, 6.2.4 1820d7b29129SMarkus Niebel */ 18218a0cf490SDiego Santa Cruz if (mmc->high_capacity && part_completed) { 1822d7b29129SMarkus Niebel capacity = (ext_csd[EXT_CSD_SEC_CNT]) | 1823d7b29129SMarkus Niebel (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) | 1824d7b29129SMarkus Niebel (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) | 1825d7b29129SMarkus Niebel (ext_csd[EXT_CSD_SEC_CNT + 3] << 24); 1826d7b29129SMarkus Niebel capacity *= MMC_MAX_BLOCK_LEN; 1827d7b29129SMarkus Niebel mmc->capacity_user = capacity; 1828d7b29129SMarkus Niebel } 18298bfa195eSSimon Glass } else { 18301937e5aaSOliver Metz /* Calculate the group size from the csd value. */ 1831e6f99a56SLei Wen int erase_gsz, erase_gmul; 1832e6f99a56SLei Wen erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; 1833e6f99a56SLei Wen erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; 1834e6f99a56SLei Wen mmc->erase_grp_size = (erase_gsz + 1) 1835e6f99a56SLei Wen * (erase_gmul + 1); 1836e6f99a56SLei Wen } 1837037dc0abSDiego Santa Cruz 1838037dc0abSDiego Santa Cruz mmc->hc_wp_grp_size = 1024 1839037dc0abSDiego Santa Cruz * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 1840037dc0abSDiego Santa Cruz * ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 18419e41a00bSDiego Santa Cruz 18429e41a00bSDiego Santa Cruz mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 1843f866a46dSStephen Warren } 1844f866a46dSStephen Warren 1845c40fdca6SSimon Glass err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart); 1846f866a46dSStephen Warren if (err) 1847f866a46dSStephen Warren return err; 1848d23e2c09SSukumar Ghorai 1849272cc70bSAndy Fleming if (IS_SD(mmc)) 1850272cc70bSAndy Fleming err = sd_change_freq(mmc); 1851272cc70bSAndy Fleming else 1852272cc70bSAndy Fleming err = mmc_change_freq(mmc); 1853272cc70bSAndy Fleming 1854272cc70bSAndy Fleming if (err) 1855272cc70bSAndy Fleming return err; 1856272cc70bSAndy Fleming 1857272cc70bSAndy Fleming /* Restrict card's capabilities by what the host can do */ 185893bfd616SPantelis Antoniou mmc->card_caps &= mmc->cfg->host_caps; 1859272cc70bSAndy Fleming 1860272cc70bSAndy Fleming if (IS_SD(mmc)) { 1861272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_4BIT) { 1862272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 1863272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1864272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1865272cc70bSAndy Fleming 1866272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1867272cc70bSAndy Fleming if (err) 1868272cc70bSAndy Fleming return err; 1869272cc70bSAndy Fleming 1870272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; 1871272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1872272cc70bSAndy Fleming cmd.cmdarg = 2; 1873272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1874272cc70bSAndy Fleming if (err) 1875272cc70bSAndy Fleming return err; 1876272cc70bSAndy Fleming 1877272cc70bSAndy Fleming mmc_set_bus_width(mmc, 4); 1878272cc70bSAndy Fleming } 1879272cc70bSAndy Fleming 18803697e599SPeng Fan err = sd_read_ssr(mmc); 18813697e599SPeng Fan if (err) 18823697e599SPeng Fan return err; 18833697e599SPeng Fan 1884272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS) 18853e3ff0acSZiyuan Xu tran_speed = 50000000; 1886272cc70bSAndy Fleming else 18873e3ff0acSZiyuan Xu tran_speed = 25000000; 1888ad5fd922SJaehoon Chung 18893e3ff0acSZiyuan Xu mmc_set_clock(mmc, tran_speed); 189049dba033SZiyuan Xu } 1891272cc70bSAndy Fleming 18925af8f45cSAndrew Gabbasov /* Fix the block length for DDR mode */ 189349dba033SZiyuan Xu if (mmc_card_ddr(mmc)) { 18945af8f45cSAndrew Gabbasov mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 18955af8f45cSAndrew Gabbasov mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 18965af8f45cSAndrew Gabbasov } 18975af8f45cSAndrew Gabbasov 1898272cc70bSAndy Fleming /* fill in device description */ 1899c40fdca6SSimon Glass bdesc = mmc_get_blk_desc(mmc); 1900c40fdca6SSimon Glass bdesc->lun = 0; 1901c40fdca6SSimon Glass bdesc->hwpart = 0; 1902c40fdca6SSimon Glass bdesc->type = 0; 1903c40fdca6SSimon Glass bdesc->blksz = mmc->read_bl_len; 1904c40fdca6SSimon Glass bdesc->log2blksz = LOG2(bdesc->blksz); 1905c40fdca6SSimon Glass bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len); 1906fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \ 1907fc011f64SSjoerd Simons (defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \ 1908fc011f64SSjoerd Simons !defined(CONFIG_USE_TINY_PRINTF)) 1909c40fdca6SSimon Glass sprintf(bdesc->vendor, "Man %06x Snr %04x%04x", 1910babce5f6STaylor Hutt mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), 1911babce5f6STaylor Hutt (mmc->cid[3] >> 16) & 0xffff); 1912c40fdca6SSimon Glass sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff, 19130b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 1914babce5f6STaylor Hutt (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff, 1915babce5f6STaylor Hutt (mmc->cid[2] >> 24) & 0xff); 1916c40fdca6SSimon Glass sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf, 1917babce5f6STaylor Hutt (mmc->cid[2] >> 16) & 0xf); 191856196826SPaul Burton #else 1919c40fdca6SSimon Glass bdesc->vendor[0] = 0; 1920c40fdca6SSimon Glass bdesc->product[0] = 0; 1921c40fdca6SSimon Glass bdesc->revision[0] = 0; 192256196826SPaul Burton #endif 1923122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT) 1924c40fdca6SSimon Glass part_init(bdesc); 1925122efd43SMikhail Kshevetskiy #endif 1926272cc70bSAndy Fleming 1927272cc70bSAndy Fleming return 0; 1928272cc70bSAndy Fleming } 1929272cc70bSAndy Fleming 1930*479fbf72SJason Zhu #ifndef CONFIG_MMC_USE_PRE_CONFIG 1931fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc) 1932272cc70bSAndy Fleming { 1933272cc70bSAndy Fleming struct mmc_cmd cmd; 1934272cc70bSAndy Fleming int err; 1935272cc70bSAndy Fleming 1936272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND; 1937272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ 193893bfd616SPantelis Antoniou cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa; 1939272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7; 1940272cc70bSAndy Fleming 1941272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1942272cc70bSAndy Fleming 1943272cc70bSAndy Fleming if (err) 1944272cc70bSAndy Fleming return err; 1945272cc70bSAndy Fleming 1946998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa) 1947915ffa52SJaehoon Chung return -EOPNOTSUPP; 1948272cc70bSAndy Fleming else 1949272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 1950272cc70bSAndy Fleming 1951272cc70bSAndy Fleming return 0; 1952272cc70bSAndy Fleming } 1953*479fbf72SJason Zhu #endif 1954272cc70bSAndy Fleming 1955c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 195695de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */ 195795de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void) 195895de9ab2SPaul Kocialkowski { 195995de9ab2SPaul Kocialkowski } 196005cbeb7cSSimon Glass #endif 196195de9ab2SPaul Kocialkowski 1962*479fbf72SJason Zhu #ifndef CONFIG_MMC_USE_PRE_CONFIG 19632051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc) 19642051aefeSPeng Fan { 1965c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 196605cbeb7cSSimon Glass #if defined(CONFIG_DM_REGULATOR) && !defined(CONFIG_SPL_BUILD) 19672051aefeSPeng Fan struct udevice *vmmc_supply; 19682051aefeSPeng Fan int ret; 19692051aefeSPeng Fan 19702051aefeSPeng Fan ret = device_get_supply_regulator(mmc->dev, "vmmc-supply", 19712051aefeSPeng Fan &vmmc_supply); 19722051aefeSPeng Fan if (ret) { 1973288db7c7SJaehoon Chung debug("%s: No vmmc supply\n", mmc->dev->name); 19742051aefeSPeng Fan return 0; 19752051aefeSPeng Fan } 19762051aefeSPeng Fan 19772051aefeSPeng Fan ret = regulator_set_enable(vmmc_supply, true); 19782051aefeSPeng Fan if (ret) { 19792051aefeSPeng Fan puts("Error enabling VMMC supply\n"); 19802051aefeSPeng Fan return ret; 19812051aefeSPeng Fan } 19822051aefeSPeng Fan #endif 198305cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */ 198405cbeb7cSSimon Glass /* 198505cbeb7cSSimon Glass * Driver model should use a regulator, as above, rather than calling 198605cbeb7cSSimon Glass * out to board code. 198705cbeb7cSSimon Glass */ 198805cbeb7cSSimon Glass board_mmc_power_init(); 198905cbeb7cSSimon Glass #endif 19902051aefeSPeng Fan return 0; 19912051aefeSPeng Fan } 1992*479fbf72SJason Zhu #endif 1993*479fbf72SJason Zhu #ifdef CONFIG_MMC_USE_PRE_CONFIG 1994*479fbf72SJason Zhu static int mmc_select_card(struct mmc *mmc, int n) 1995*479fbf72SJason Zhu { 1996*479fbf72SJason Zhu struct mmc_cmd cmd; 1997*479fbf72SJason Zhu int err = 0; 19982051aefeSPeng Fan 1999*479fbf72SJason Zhu memset(&cmd, 0, sizeof(struct mmc_cmd)); 2000*479fbf72SJason Zhu if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 2001*479fbf72SJason Zhu mmc->rca = n; 2002*479fbf72SJason Zhu cmd.cmdidx = MMC_CMD_SELECT_CARD; 2003*479fbf72SJason Zhu cmd.resp_type = MMC_RSP_R1; 2004*479fbf72SJason Zhu cmd.cmdarg = mmc->rca << 16; 2005*479fbf72SJason Zhu err = mmc_send_cmd(mmc, &cmd, NULL); 2006*479fbf72SJason Zhu } 2007*479fbf72SJason Zhu 2008*479fbf72SJason Zhu return err; 2009*479fbf72SJason Zhu } 2010*479fbf72SJason Zhu 2011*479fbf72SJason Zhu int mmc_start_init(struct mmc *mmc) 2012*479fbf72SJason Zhu { 2013*479fbf72SJason Zhu /* 2014*479fbf72SJason Zhu * We use the MMC config set by the bootrom. 2015*479fbf72SJason Zhu * So it is no need to reset the eMMC device. 2016*479fbf72SJason Zhu */ 2017*479fbf72SJason Zhu mmc_set_bus_width(mmc, 8); 2018*479fbf72SJason Zhu mmc_set_clock(mmc, 1); 2019*479fbf72SJason Zhu mmc_set_timing(mmc, MMC_TIMING_LEGACY); 2020*479fbf72SJason Zhu /* Send cmd7 to return stand-by state*/ 2021*479fbf72SJason Zhu mmc_select_card(mmc, 0); 2022*479fbf72SJason Zhu mmc->version = MMC_VERSION_UNKNOWN; 2023*479fbf72SJason Zhu mmc->high_capacity = 1; 2024*479fbf72SJason Zhu /* 2025*479fbf72SJason Zhu * The RCA is set to 2 by rockchip bootrom, use the default 2026*479fbf72SJason Zhu * value here. 2027*479fbf72SJason Zhu */ 2028*479fbf72SJason Zhu #ifdef CONFIG_ARCH_ROCKCHIP 2029*479fbf72SJason Zhu mmc->rca = 2; 2030*479fbf72SJason Zhu #else 2031*479fbf72SJason Zhu mmc->rca = 1; 2032*479fbf72SJason Zhu #endif 2033*479fbf72SJason Zhu return 0; 2034*479fbf72SJason Zhu } 2035*479fbf72SJason Zhu #else 2036e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc) 2037272cc70bSAndy Fleming { 20388ca51e51SSimon Glass bool no_card; 2039afd5932bSMacpaul Lin int err; 2040272cc70bSAndy Fleming 2041ab769f22SPantelis Antoniou /* we pretend there's no card when init is NULL */ 20428ca51e51SSimon Glass no_card = mmc_getcd(mmc) == 0; 2043e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 20448ca51e51SSimon Glass no_card = no_card || (mmc->cfg->ops->init == NULL); 20458ca51e51SSimon Glass #endif 20468ca51e51SSimon Glass if (no_card) { 204748972d90SThierry Reding mmc->has_init = 0; 204856196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 204948972d90SThierry Reding printf("MMC: no card present\n"); 205056196826SPaul Burton #endif 2051915ffa52SJaehoon Chung return -ENOMEDIUM; 205248972d90SThierry Reding } 205348972d90SThierry Reding 2054bc897b1dSLei Wen if (mmc->has_init) 2055bc897b1dSLei Wen return 0; 2056bc897b1dSLei Wen 20575a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 20585a8dbdc6SYangbo Lu mmc_adapter_card_type_ident(); 20595a8dbdc6SYangbo Lu #endif 20602051aefeSPeng Fan err = mmc_power_init(mmc); 20612051aefeSPeng Fan if (err) 20622051aefeSPeng Fan return err; 206395de9ab2SPaul Kocialkowski 2064e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 20658ca51e51SSimon Glass /* The device has already been probed ready for use */ 20668ca51e51SSimon Glass #else 2067ab769f22SPantelis Antoniou /* made sure it's not NULL earlier */ 206893bfd616SPantelis Antoniou err = mmc->cfg->ops->init(mmc); 2069272cc70bSAndy Fleming if (err) 2070272cc70bSAndy Fleming return err; 20718ca51e51SSimon Glass #endif 2072b86b85e2SIlya Yanok mmc_set_bus_width(mmc, 1); 2073b86b85e2SIlya Yanok mmc_set_clock(mmc, 1); 207481db2d36SZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_LEGACY); 2075b86b85e2SIlya Yanok 2076272cc70bSAndy Fleming /* Reset the Card */ 2077272cc70bSAndy Fleming err = mmc_go_idle(mmc); 2078272cc70bSAndy Fleming 2079272cc70bSAndy Fleming if (err) 2080272cc70bSAndy Fleming return err; 2081272cc70bSAndy Fleming 2082bc897b1dSLei Wen /* The internal partition reset to user partition(0) at every CMD0*/ 2083c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->hwpart = 0; 2084bc897b1dSLei Wen 2085272cc70bSAndy Fleming /* Test for SD version 2 */ 2086272cc70bSAndy Fleming err = mmc_send_if_cond(mmc); 2087272cc70bSAndy Fleming 2088272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */ 2089272cc70bSAndy Fleming err = sd_send_op_cond(mmc); 2090272cc70bSAndy Fleming 2091272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */ 2092915ffa52SJaehoon Chung if (err == -ETIMEDOUT) { 2093272cc70bSAndy Fleming err = mmc_send_op_cond(mmc); 2094272cc70bSAndy Fleming 2095bd47c135SAndrew Gabbasov if (err) { 209656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2097272cc70bSAndy Fleming printf("Card did not respond to voltage select!\n"); 209856196826SPaul Burton #endif 2099915ffa52SJaehoon Chung return -EOPNOTSUPP; 2100272cc70bSAndy Fleming } 2101272cc70bSAndy Fleming } 2102272cc70bSAndy Fleming 2103bd47c135SAndrew Gabbasov if (!err) 2104e9550449SChe-Liang Chiou mmc->init_in_progress = 1; 2105e9550449SChe-Liang Chiou 2106e9550449SChe-Liang Chiou return err; 2107e9550449SChe-Liang Chiou } 2108*479fbf72SJason Zhu #endif 2109e9550449SChe-Liang Chiou 2110e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc) 2111e9550449SChe-Liang Chiou { 2112e9550449SChe-Liang Chiou int err = 0; 2113e9550449SChe-Liang Chiou 2114bd47c135SAndrew Gabbasov mmc->init_in_progress = 0; 2115e9550449SChe-Liang Chiou if (mmc->op_cond_pending) 2116e9550449SChe-Liang Chiou err = mmc_complete_op_cond(mmc); 2117e9550449SChe-Liang Chiou 2118e9550449SChe-Liang Chiou if (!err) 2119bc897b1dSLei Wen err = mmc_startup(mmc); 2120bc897b1dSLei Wen if (err) 2121bc897b1dSLei Wen mmc->has_init = 0; 2122bc897b1dSLei Wen else 2123bc897b1dSLei Wen mmc->has_init = 1; 2124e9550449SChe-Liang Chiou return err; 2125e9550449SChe-Liang Chiou } 2126e9550449SChe-Liang Chiou 2127e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc) 2128e9550449SChe-Liang Chiou { 2129bd47c135SAndrew Gabbasov int err = 0; 2130ce9eca94SMarek Vasut __maybe_unused unsigned start; 2131c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 213233fb211dSSimon Glass struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev); 2133e9550449SChe-Liang Chiou 213433fb211dSSimon Glass upriv->mmc = mmc; 213533fb211dSSimon Glass #endif 2136e9550449SChe-Liang Chiou if (mmc->has_init) 2137e9550449SChe-Liang Chiou return 0; 2138d803fea5SMateusz Zalega 2139d803fea5SMateusz Zalega start = get_timer(0); 2140d803fea5SMateusz Zalega 2141e9550449SChe-Liang Chiou if (!mmc->init_in_progress) 2142e9550449SChe-Liang Chiou err = mmc_start_init(mmc); 2143e9550449SChe-Liang Chiou 2144bd47c135SAndrew Gabbasov if (!err) 2145e9550449SChe-Liang Chiou err = mmc_complete_init(mmc); 2146919b4858SJagan Teki if (err) 2147919b4858SJagan Teki printf("%s: %d, time %lu\n", __func__, err, get_timer(start)); 2148919b4858SJagan Teki 2149bc897b1dSLei Wen return err; 2150272cc70bSAndy Fleming } 2151272cc70bSAndy Fleming 2152ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val) 2153ab71188cSMarkus Niebel { 2154ab71188cSMarkus Niebel mmc->dsr = val; 2155ab71188cSMarkus Niebel return 0; 2156ab71188cSMarkus Niebel } 2157ab71188cSMarkus Niebel 2158cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */ 2159cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis) 2160272cc70bSAndy Fleming { 2161272cc70bSAndy Fleming return -1; 2162272cc70bSAndy Fleming } 2163272cc70bSAndy Fleming 2164cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */ 2165cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis) 2166cee9ab7cSJeroen Hofstee { 2167cee9ab7cSJeroen Hofstee return -1; 2168cee9ab7cSJeroen Hofstee } 2169272cc70bSAndy Fleming 2170e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit) 2171e9550449SChe-Liang Chiou { 2172e9550449SChe-Liang Chiou mmc->preinit = preinit; 2173e9550449SChe-Liang Chiou } 2174e9550449SChe-Liang Chiou 2175c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD) 21768e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 21778e3332e2SSjoerd Simons { 21788e3332e2SSjoerd Simons return 0; 21798e3332e2SSjoerd Simons } 2180c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC) 21818e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 21828e3332e2SSjoerd Simons { 21834a1db6d8SSimon Glass int ret, i; 21848e3332e2SSjoerd Simons struct uclass *uc; 21854a1db6d8SSimon Glass struct udevice *dev; 21868e3332e2SSjoerd Simons 21878e3332e2SSjoerd Simons ret = uclass_get(UCLASS_MMC, &uc); 21888e3332e2SSjoerd Simons if (ret) 21898e3332e2SSjoerd Simons return ret; 21908e3332e2SSjoerd Simons 21914a1db6d8SSimon Glass /* 21924a1db6d8SSimon Glass * Try to add them in sequence order. Really with driver model we 21934a1db6d8SSimon Glass * should allow holes, but the current MMC list does not allow that. 21944a1db6d8SSimon Glass * So if we request 0, 1, 3 we will get 0, 1, 2. 21954a1db6d8SSimon Glass */ 21964a1db6d8SSimon Glass for (i = 0; ; i++) { 21974a1db6d8SSimon Glass ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev); 21984a1db6d8SSimon Glass if (ret == -ENODEV) 21994a1db6d8SSimon Glass break; 22004a1db6d8SSimon Glass } 22014a1db6d8SSimon Glass uclass_foreach_dev(dev, uc) { 22024a1db6d8SSimon Glass ret = device_probe(dev); 22038e3332e2SSjoerd Simons if (ret) 22044a1db6d8SSimon Glass printf("%s - probe failed: %d\n", dev->name, ret); 22058e3332e2SSjoerd Simons } 22068e3332e2SSjoerd Simons 22078e3332e2SSjoerd Simons return 0; 22088e3332e2SSjoerd Simons } 22098e3332e2SSjoerd Simons #else 22108e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 22118e3332e2SSjoerd Simons { 22128e3332e2SSjoerd Simons if (board_mmc_init(bis) < 0) 22138e3332e2SSjoerd Simons cpu_mmc_init(bis); 22148e3332e2SSjoerd Simons 22158e3332e2SSjoerd Simons return 0; 22168e3332e2SSjoerd Simons } 22178e3332e2SSjoerd Simons #endif 2218e9550449SChe-Liang Chiou 2219272cc70bSAndy Fleming int mmc_initialize(bd_t *bis) 2220272cc70bSAndy Fleming { 22211b26bab1SDaniel Kochmański static int initialized = 0; 22228e3332e2SSjoerd Simons int ret; 22231b26bab1SDaniel Kochmański if (initialized) /* Avoid initializing mmc multiple times */ 22241b26bab1SDaniel Kochmański return 0; 22251b26bab1SDaniel Kochmański initialized = 1; 22261b26bab1SDaniel Kochmański 2227c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK) 2228b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY) 2229c40fdca6SSimon Glass mmc_list_init(); 2230c40fdca6SSimon Glass #endif 2231b5b838f1SMarek Vasut #endif 22328e3332e2SSjoerd Simons ret = mmc_probe(bis); 22338e3332e2SSjoerd Simons if (ret) 22348e3332e2SSjoerd Simons return ret; 2235272cc70bSAndy Fleming 2236bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD 2237272cc70bSAndy Fleming print_mmc_devices(','); 2238bb0dc108SYing Zhang #endif 2239272cc70bSAndy Fleming 2240c40fdca6SSimon Glass mmc_do_preinit(); 2241272cc70bSAndy Fleming return 0; 2242272cc70bSAndy Fleming } 2243cd3d4880STomas Melin 2244cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE 2245cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc) 2246cd3d4880STomas Melin { 2247cd3d4880STomas Melin int err; 2248cd3d4880STomas Melin ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 2249cd3d4880STomas Melin 2250cd3d4880STomas Melin err = mmc_send_ext_csd(mmc, ext_csd); 2251cd3d4880STomas Melin if (err) { 2252cd3d4880STomas Melin puts("Could not get ext_csd register values\n"); 2253cd3d4880STomas Melin return err; 2254cd3d4880STomas Melin } 2255cd3d4880STomas Melin 2256cd3d4880STomas Melin if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) { 2257cd3d4880STomas Melin puts("Background operations not supported on device\n"); 2258cd3d4880STomas Melin return -EMEDIUMTYPE; 2259cd3d4880STomas Melin } 2260cd3d4880STomas Melin 2261cd3d4880STomas Melin if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) { 2262cd3d4880STomas Melin puts("Background operations already enabled\n"); 2263cd3d4880STomas Melin return 0; 2264cd3d4880STomas Melin } 2265cd3d4880STomas Melin 2266cd3d4880STomas Melin err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1); 2267cd3d4880STomas Melin if (err) { 2268cd3d4880STomas Melin puts("Failed to enable manual background operations\n"); 2269cd3d4880STomas Melin return err; 2270cd3d4880STomas Melin } 2271cd3d4880STomas Melin 2272cd3d4880STomas Melin puts("Enabled manual background operations\n"); 2273cd3d4880STomas Melin 2274cd3d4880STomas Melin return 0; 2275cd3d4880STomas Melin } 2276cd3d4880STomas Melin #endif 2277