1272cc70bSAndy Fleming /* 2272cc70bSAndy Fleming * Copyright 2008, Freescale Semiconductor, Inc 3272cc70bSAndy Fleming * Andy Fleming 4272cc70bSAndy Fleming * 5272cc70bSAndy Fleming * Based vaguely on the Linux code 6272cc70bSAndy Fleming * 71a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 8272cc70bSAndy Fleming */ 9272cc70bSAndy Fleming 10272cc70bSAndy Fleming #include <config.h> 11272cc70bSAndy Fleming #include <common.h> 12272cc70bSAndy Fleming #include <command.h> 138e3332e2SSjoerd Simons #include <dm.h> 148e3332e2SSjoerd Simons #include <dm/device-internal.h> 15d4622df3SStephen Warren #include <errno.h> 16272cc70bSAndy Fleming #include <mmc.h> 17272cc70bSAndy Fleming #include <part.h> 182051aefeSPeng Fan #include <power/regulator.h> 19272cc70bSAndy Fleming #include <malloc.h> 20cf92e05cSSimon Glass #include <memalign.h> 21272cc70bSAndy Fleming #include <linux/list.h> 229b1f942cSRabin Vincent #include <div64.h> 23da61fa5fSPaul Burton #include "mmc_private.h" 24272cc70bSAndy Fleming 253697e599SPeng Fan static const unsigned int sd_au_size[] = { 263697e599SPeng Fan 0, SZ_16K / 512, SZ_32K / 512, 273697e599SPeng Fan SZ_64K / 512, SZ_128K / 512, SZ_256K / 512, 283697e599SPeng Fan SZ_512K / 512, SZ_1M / 512, SZ_2M / 512, 293697e599SPeng Fan SZ_4M / 512, SZ_8M / 512, (SZ_8M + SZ_4M) / 512, 303697e599SPeng Fan SZ_16M / 512, (SZ_16M + SZ_8M) / 512, SZ_32M / 512, SZ_64M / 512, 313697e599SPeng Fan }; 323697e599SPeng Fan 33b5b838f1SMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY) 34b5b838f1SMarek Vasut static struct mmc mmc_static; 35b5b838f1SMarek Vasut struct mmc *find_mmc_device(int dev_num) 36b5b838f1SMarek Vasut { 37b5b838f1SMarek Vasut return &mmc_static; 38b5b838f1SMarek Vasut } 39b5b838f1SMarek Vasut 40b5b838f1SMarek Vasut void mmc_do_preinit(void) 41b5b838f1SMarek Vasut { 42b5b838f1SMarek Vasut struct mmc *m = &mmc_static; 43b5b838f1SMarek Vasut #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 44b5b838f1SMarek Vasut mmc_set_preinit(m, 1); 45b5b838f1SMarek Vasut #endif 46b5b838f1SMarek Vasut if (m->preinit) 47b5b838f1SMarek Vasut mmc_start_init(m); 48b5b838f1SMarek Vasut } 49b5b838f1SMarek Vasut 50b5b838f1SMarek Vasut struct blk_desc *mmc_get_blk_desc(struct mmc *mmc) 51b5b838f1SMarek Vasut { 52b5b838f1SMarek Vasut return &mmc->block_dev; 53b5b838f1SMarek Vasut } 54b5b838f1SMarek Vasut #endif 55b5b838f1SMarek Vasut 56e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 57750121c3SJeroen Hofstee __weak int board_mmc_getwp(struct mmc *mmc) 58d23d8d7eSNikita Kiryanov { 59d23d8d7eSNikita Kiryanov return -1; 60d23d8d7eSNikita Kiryanov } 61d23d8d7eSNikita Kiryanov 62d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc) 63d23d8d7eSNikita Kiryanov { 64d23d8d7eSNikita Kiryanov int wp; 65d23d8d7eSNikita Kiryanov 66d23d8d7eSNikita Kiryanov wp = board_mmc_getwp(mmc); 67d23d8d7eSNikita Kiryanov 68d4e1da4eSPeter Korsgaard if (wp < 0) { 6993bfd616SPantelis Antoniou if (mmc->cfg->ops->getwp) 7093bfd616SPantelis Antoniou wp = mmc->cfg->ops->getwp(mmc); 71d4e1da4eSPeter Korsgaard else 72d4e1da4eSPeter Korsgaard wp = 0; 73d4e1da4eSPeter Korsgaard } 74d23d8d7eSNikita Kiryanov 75d23d8d7eSNikita Kiryanov return wp; 76d23d8d7eSNikita Kiryanov } 77d23d8d7eSNikita Kiryanov 78cee9ab7cSJeroen Hofstee __weak int board_mmc_getcd(struct mmc *mmc) 79cee9ab7cSJeroen Hofstee { 8011fdade2SStefano Babic return -1; 8111fdade2SStefano Babic } 828ca51e51SSimon Glass #endif 8311fdade2SStefano Babic 848635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE 85c0c76ebaSSimon Glass void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd) 86c0c76ebaSSimon Glass { 87c0c76ebaSSimon Glass printf("CMD_SEND:%d\n", cmd->cmdidx); 88c0c76ebaSSimon Glass printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg); 89c0c76ebaSSimon Glass } 90c0c76ebaSSimon Glass 91c0c76ebaSSimon Glass void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret) 92c0c76ebaSSimon Glass { 935db2fe3aSRaffaele Recalcati int i; 945db2fe3aSRaffaele Recalcati u8 *ptr; 955db2fe3aSRaffaele Recalcati 967863ce58SBin Meng if (ret) { 977863ce58SBin Meng printf("\t\tRET\t\t\t %d\n", ret); 987863ce58SBin Meng } else { 995db2fe3aSRaffaele Recalcati switch (cmd->resp_type) { 1005db2fe3aSRaffaele Recalcati case MMC_RSP_NONE: 1015db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_NONE\n"); 1025db2fe3aSRaffaele Recalcati break; 1035db2fe3aSRaffaele Recalcati case MMC_RSP_R1: 1045db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n", 1055db2fe3aSRaffaele Recalcati cmd->response[0]); 1065db2fe3aSRaffaele Recalcati break; 1075db2fe3aSRaffaele Recalcati case MMC_RSP_R1b: 1085db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n", 1095db2fe3aSRaffaele Recalcati cmd->response[0]); 1105db2fe3aSRaffaele Recalcati break; 1115db2fe3aSRaffaele Recalcati case MMC_RSP_R2: 1125db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R2\t\t 0x%08X \n", 1135db2fe3aSRaffaele Recalcati cmd->response[0]); 1145db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1155db2fe3aSRaffaele Recalcati cmd->response[1]); 1165db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1175db2fe3aSRaffaele Recalcati cmd->response[2]); 1185db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1195db2fe3aSRaffaele Recalcati cmd->response[3]); 1205db2fe3aSRaffaele Recalcati printf("\n"); 1215db2fe3aSRaffaele Recalcati printf("\t\t\t\t\tDUMPING DATA\n"); 1225db2fe3aSRaffaele Recalcati for (i = 0; i < 4; i++) { 1235db2fe3aSRaffaele Recalcati int j; 1245db2fe3aSRaffaele Recalcati printf("\t\t\t\t\t%03d - ", i*4); 125146bec79SDirk Behme ptr = (u8 *)&cmd->response[i]; 1265db2fe3aSRaffaele Recalcati ptr += 3; 1275db2fe3aSRaffaele Recalcati for (j = 0; j < 4; j++) 1285db2fe3aSRaffaele Recalcati printf("%02X ", *ptr--); 1295db2fe3aSRaffaele Recalcati printf("\n"); 1305db2fe3aSRaffaele Recalcati } 1315db2fe3aSRaffaele Recalcati break; 1325db2fe3aSRaffaele Recalcati case MMC_RSP_R3: 1335db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n", 1345db2fe3aSRaffaele Recalcati cmd->response[0]); 1355db2fe3aSRaffaele Recalcati break; 1365db2fe3aSRaffaele Recalcati default: 1375db2fe3aSRaffaele Recalcati printf("\t\tERROR MMC rsp not supported\n"); 1385db2fe3aSRaffaele Recalcati break; 1395db2fe3aSRaffaele Recalcati } 1407863ce58SBin Meng } 141c0c76ebaSSimon Glass } 142c0c76ebaSSimon Glass 143c0c76ebaSSimon Glass void mmc_trace_state(struct mmc *mmc, struct mmc_cmd *cmd) 144c0c76ebaSSimon Glass { 145c0c76ebaSSimon Glass int status; 146c0c76ebaSSimon Glass 147c0c76ebaSSimon Glass status = (cmd->response[0] & MMC_STATUS_CURR_STATE) >> 9; 148c0c76ebaSSimon Glass printf("CURR STATE:%d\n", status); 149c0c76ebaSSimon Glass } 1505db2fe3aSRaffaele Recalcati #endif 151c0c76ebaSSimon Glass 152e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 153c0c76ebaSSimon Glass int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) 154c0c76ebaSSimon Glass { 155c0c76ebaSSimon Glass int ret; 156c0c76ebaSSimon Glass 157c0c76ebaSSimon Glass mmmc_trace_before_send(mmc, cmd); 158c0c76ebaSSimon Glass ret = mmc->cfg->ops->send_cmd(mmc, cmd, data); 159c0c76ebaSSimon Glass mmmc_trace_after_send(mmc, cmd, ret); 160c0c76ebaSSimon Glass 1618635ff9eSMarek Vasut return ret; 162272cc70bSAndy Fleming } 1638ca51e51SSimon Glass #endif 164272cc70bSAndy Fleming 165da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout) 1665d4fc8d9SRaffaele Recalcati { 1675d4fc8d9SRaffaele Recalcati struct mmc_cmd cmd; 168d617c426SJan Kloetzke int err, retries = 5; 1695d4fc8d9SRaffaele Recalcati 1705d4fc8d9SRaffaele Recalcati cmd.cmdidx = MMC_CMD_SEND_STATUS; 1715d4fc8d9SRaffaele Recalcati cmd.resp_type = MMC_RSP_R1; 172aaf3d41aSMarek Vasut if (!mmc_host_is_spi(mmc)) 173aaf3d41aSMarek Vasut cmd.cmdarg = mmc->rca << 16; 1745d4fc8d9SRaffaele Recalcati 1751677eef4SAndrew Gabbasov while (1) { 1765d4fc8d9SRaffaele Recalcati err = mmc_send_cmd(mmc, &cmd, NULL); 177d617c426SJan Kloetzke if (!err) { 178d617c426SJan Kloetzke if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) && 179d617c426SJan Kloetzke (cmd.response[0] & MMC_STATUS_CURR_STATE) != 180d617c426SJan Kloetzke MMC_STATE_PRG) 1815d4fc8d9SRaffaele Recalcati break; 182d617c426SJan Kloetzke else if (cmd.response[0] & MMC_STATUS_MASK) { 18356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 184d617c426SJan Kloetzke printf("Status Error: 0x%08X\n", 185d617c426SJan Kloetzke cmd.response[0]); 18656196826SPaul Burton #endif 187915ffa52SJaehoon Chung return -ECOMM; 188d617c426SJan Kloetzke } 189d617c426SJan Kloetzke } else if (--retries < 0) 190d617c426SJan Kloetzke return err; 1915d4fc8d9SRaffaele Recalcati 1921677eef4SAndrew Gabbasov if (timeout-- <= 0) 1931677eef4SAndrew Gabbasov break; 1945d4fc8d9SRaffaele Recalcati 1951677eef4SAndrew Gabbasov udelay(1000); 1961677eef4SAndrew Gabbasov } 1975d4fc8d9SRaffaele Recalcati 198c0c76ebaSSimon Glass mmc_trace_state(mmc, &cmd); 1995b0c942fSJongman Heo if (timeout <= 0) { 20056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2015d4fc8d9SRaffaele Recalcati printf("Timeout waiting card ready\n"); 20256196826SPaul Burton #endif 203915ffa52SJaehoon Chung return -ETIMEDOUT; 2045d4fc8d9SRaffaele Recalcati } 2055d4fc8d9SRaffaele Recalcati 2065d4fc8d9SRaffaele Recalcati return 0; 2075d4fc8d9SRaffaele Recalcati } 2085d4fc8d9SRaffaele Recalcati 209da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len) 210272cc70bSAndy Fleming { 211272cc70bSAndy Fleming struct mmc_cmd cmd; 212272cc70bSAndy Fleming 213caa21a21SZiyuan Xu if (mmc_card_ddr(mmc)) 214d22e3d46SJaehoon Chung return 0; 215d22e3d46SJaehoon Chung 216272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SET_BLOCKLEN; 217272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 218272cc70bSAndy Fleming cmd.cmdarg = len; 219272cc70bSAndy Fleming 220272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, NULL); 221272cc70bSAndy Fleming } 222272cc70bSAndy Fleming 223ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start, 224fdbb873eSKim Phillips lbaint_t blkcnt) 225272cc70bSAndy Fleming { 226272cc70bSAndy Fleming struct mmc_cmd cmd; 227272cc70bSAndy Fleming struct mmc_data data; 228272cc70bSAndy Fleming 2294a1a06bcSAlagu Sankar if (blkcnt > 1) 2304a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; 2314a1a06bcSAlagu Sankar else 232272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; 233272cc70bSAndy Fleming 234272cc70bSAndy Fleming if (mmc->high_capacity) 2354a1a06bcSAlagu Sankar cmd.cmdarg = start; 236272cc70bSAndy Fleming else 2374a1a06bcSAlagu Sankar cmd.cmdarg = start * mmc->read_bl_len; 238272cc70bSAndy Fleming 239272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 240272cc70bSAndy Fleming 241272cc70bSAndy Fleming data.dest = dst; 2424a1a06bcSAlagu Sankar data.blocks = blkcnt; 243272cc70bSAndy Fleming data.blocksize = mmc->read_bl_len; 244272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 245272cc70bSAndy Fleming 2464a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, &data)) 2474a1a06bcSAlagu Sankar return 0; 2484a1a06bcSAlagu Sankar 2494a1a06bcSAlagu Sankar if (blkcnt > 1) { 2504a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; 2514a1a06bcSAlagu Sankar cmd.cmdarg = 0; 2524a1a06bcSAlagu Sankar cmd.resp_type = MMC_RSP_R1b; 2534a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, NULL)) { 25456196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2554a1a06bcSAlagu Sankar printf("mmc fail to send stop cmd\n"); 25656196826SPaul Burton #endif 2574a1a06bcSAlagu Sankar return 0; 2584a1a06bcSAlagu Sankar } 259272cc70bSAndy Fleming } 260272cc70bSAndy Fleming 2614a1a06bcSAlagu Sankar return blkcnt; 262272cc70bSAndy Fleming } 263272cc70bSAndy Fleming 264c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK) 2657dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst) 26633fb211dSSimon Glass #else 2677dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, 2687dba0b93SSimon Glass void *dst) 26933fb211dSSimon Glass #endif 270272cc70bSAndy Fleming { 271c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK) 27233fb211dSSimon Glass struct blk_desc *block_dev = dev_get_uclass_platdata(dev); 27333fb211dSSimon Glass #endif 274bcce53d0SSimon Glass int dev_num = block_dev->devnum; 275873cc1d7SStephen Warren int err; 2764a1a06bcSAlagu Sankar lbaint_t cur, blocks_todo = blkcnt; 277272cc70bSAndy Fleming 2784a1a06bcSAlagu Sankar if (blkcnt == 0) 2794a1a06bcSAlagu Sankar return 0; 2804a1a06bcSAlagu Sankar 2814a1a06bcSAlagu Sankar struct mmc *mmc = find_mmc_device(dev_num); 282272cc70bSAndy Fleming if (!mmc) 283272cc70bSAndy Fleming return 0; 284272cc70bSAndy Fleming 285b5b838f1SMarek Vasut if (CONFIG_IS_ENABLED(MMC_TINY)) 286b5b838f1SMarek Vasut err = mmc_switch_part(mmc, block_dev->hwpart); 287b5b838f1SMarek Vasut else 28869f45cd5SSimon Glass err = blk_dselect_hwpart(block_dev, block_dev->hwpart); 289b5b838f1SMarek Vasut 290873cc1d7SStephen Warren if (err < 0) 291873cc1d7SStephen Warren return 0; 292873cc1d7SStephen Warren 293c40fdca6SSimon Glass if ((start + blkcnt) > block_dev->lba) { 29456196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 295ff8fef56SSascha Silbe printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", 296c40fdca6SSimon Glass start + blkcnt, block_dev->lba); 29756196826SPaul Burton #endif 298d2bf29e3SLei Wen return 0; 299d2bf29e3SLei Wen } 300272cc70bSAndy Fleming 30111692991SSimon Glass if (mmc_set_blocklen(mmc, mmc->read_bl_len)) { 30211692991SSimon Glass debug("%s: Failed to set blocklen\n", __func__); 303272cc70bSAndy Fleming return 0; 30411692991SSimon Glass } 305272cc70bSAndy Fleming 3064a1a06bcSAlagu Sankar do { 30793bfd616SPantelis Antoniou cur = (blocks_todo > mmc->cfg->b_max) ? 30893bfd616SPantelis Antoniou mmc->cfg->b_max : blocks_todo; 30911692991SSimon Glass if (mmc_read_blocks(mmc, dst, start, cur) != cur) { 31011692991SSimon Glass debug("%s: Failed to read blocks\n", __func__); 311*c30b5115SJason Zhu int timeout = 0; 312*c30b5115SJason Zhu re_init_retry: 313*c30b5115SJason Zhu timeout++; 314*c30b5115SJason Zhu /* 315*c30b5115SJason Zhu * Try re-init seven times. 316*c30b5115SJason Zhu */ 317*c30b5115SJason Zhu if (timeout > 7) { 318*c30b5115SJason Zhu printf("Re-init retry timeout\n"); 3194a1a06bcSAlagu Sankar return 0; 32011692991SSimon Glass } 321*c30b5115SJason Zhu 322*c30b5115SJason Zhu mmc->has_init = 0; 323*c30b5115SJason Zhu if (mmc_init(mmc)) 324*c30b5115SJason Zhu return 0; 325*c30b5115SJason Zhu 326*c30b5115SJason Zhu if (mmc_read_blocks(mmc, dst, start, cur) != cur) { 327*c30b5115SJason Zhu printf("%s: Re-init mmc_read_blocks error\n", 328*c30b5115SJason Zhu __func__); 329*c30b5115SJason Zhu goto re_init_retry; 330*c30b5115SJason Zhu } 331*c30b5115SJason Zhu } 3324a1a06bcSAlagu Sankar blocks_todo -= cur; 3334a1a06bcSAlagu Sankar start += cur; 3344a1a06bcSAlagu Sankar dst += cur * mmc->read_bl_len; 3354a1a06bcSAlagu Sankar } while (blocks_todo > 0); 336272cc70bSAndy Fleming 337272cc70bSAndy Fleming return blkcnt; 338272cc70bSAndy Fleming } 339272cc70bSAndy Fleming 34049dba033SZiyuan Xu void mmc_set_clock(struct mmc *mmc, uint clock) 34149dba033SZiyuan Xu { 34249dba033SZiyuan Xu if (clock > mmc->cfg->f_max) 34349dba033SZiyuan Xu clock = mmc->cfg->f_max; 34449dba033SZiyuan Xu 34549dba033SZiyuan Xu if (clock < mmc->cfg->f_min) 34649dba033SZiyuan Xu clock = mmc->cfg->f_min; 34749dba033SZiyuan Xu 34849dba033SZiyuan Xu mmc->clock = clock; 34949dba033SZiyuan Xu 35049dba033SZiyuan Xu mmc_set_ios(mmc); 35149dba033SZiyuan Xu } 35249dba033SZiyuan Xu 35349dba033SZiyuan Xu static void mmc_set_bus_width(struct mmc *mmc, uint width) 35449dba033SZiyuan Xu { 35549dba033SZiyuan Xu mmc->bus_width = width; 35649dba033SZiyuan Xu 35749dba033SZiyuan Xu mmc_set_ios(mmc); 35849dba033SZiyuan Xu } 35949dba033SZiyuan Xu 36081db2d36SZiyuan Xu static void mmc_set_timing(struct mmc *mmc, uint timing) 36181db2d36SZiyuan Xu { 36281db2d36SZiyuan Xu mmc->timing = timing; 36381db2d36SZiyuan Xu mmc_set_ios(mmc); 36481db2d36SZiyuan Xu } 36581db2d36SZiyuan Xu 366fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc) 367272cc70bSAndy Fleming { 368272cc70bSAndy Fleming struct mmc_cmd cmd; 369272cc70bSAndy Fleming int err; 370272cc70bSAndy Fleming 371272cc70bSAndy Fleming udelay(1000); 372272cc70bSAndy Fleming 373272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_GO_IDLE_STATE; 374272cc70bSAndy Fleming cmd.cmdarg = 0; 375272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_NONE; 376272cc70bSAndy Fleming 377272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 378272cc70bSAndy Fleming 379272cc70bSAndy Fleming if (err) 380272cc70bSAndy Fleming return err; 381272cc70bSAndy Fleming 382272cc70bSAndy Fleming udelay(2000); 383272cc70bSAndy Fleming 384272cc70bSAndy Fleming return 0; 385272cc70bSAndy Fleming } 386272cc70bSAndy Fleming 387fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc) 388272cc70bSAndy Fleming { 389272cc70bSAndy Fleming int timeout = 1000; 390272cc70bSAndy Fleming int err; 391272cc70bSAndy Fleming struct mmc_cmd cmd; 392272cc70bSAndy Fleming 3931677eef4SAndrew Gabbasov while (1) { 394272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 395272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 396272cc70bSAndy Fleming cmd.cmdarg = 0; 397272cc70bSAndy Fleming 398272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 399272cc70bSAndy Fleming 400272cc70bSAndy Fleming if (err) 401272cc70bSAndy Fleming return err; 402272cc70bSAndy Fleming 403272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_OP_COND; 404272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R3; 405250de12bSStefano Babic 406250de12bSStefano Babic /* 407250de12bSStefano Babic * Most cards do not answer if some reserved bits 408250de12bSStefano Babic * in the ocr are set. However, Some controller 409250de12bSStefano Babic * can set bit 7 (reserved for low voltages), but 410250de12bSStefano Babic * how to manage low voltages SD card is not yet 411250de12bSStefano Babic * specified. 412250de12bSStefano Babic */ 413d52ebf10SThomas Chou cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 : 41493bfd616SPantelis Antoniou (mmc->cfg->voltages & 0xff8000); 415272cc70bSAndy Fleming 416272cc70bSAndy Fleming if (mmc->version == SD_VERSION_2) 417272cc70bSAndy Fleming cmd.cmdarg |= OCR_HCS; 418272cc70bSAndy Fleming 419272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 420272cc70bSAndy Fleming 421272cc70bSAndy Fleming if (err) 422272cc70bSAndy Fleming return err; 423272cc70bSAndy Fleming 4241677eef4SAndrew Gabbasov if (cmd.response[0] & OCR_BUSY) 4251677eef4SAndrew Gabbasov break; 426272cc70bSAndy Fleming 4271677eef4SAndrew Gabbasov if (timeout-- <= 0) 428915ffa52SJaehoon Chung return -EOPNOTSUPP; 429272cc70bSAndy Fleming 4301677eef4SAndrew Gabbasov udelay(1000); 4311677eef4SAndrew Gabbasov } 4321677eef4SAndrew Gabbasov 433272cc70bSAndy Fleming if (mmc->version != SD_VERSION_2) 434272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 435272cc70bSAndy Fleming 436d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 437d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 438d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 439d52ebf10SThomas Chou cmd.cmdarg = 0; 440d52ebf10SThomas Chou 441d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 442d52ebf10SThomas Chou 443d52ebf10SThomas Chou if (err) 444d52ebf10SThomas Chou return err; 445d52ebf10SThomas Chou } 446d52ebf10SThomas Chou 447998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 448272cc70bSAndy Fleming 449272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 450272cc70bSAndy Fleming mmc->rca = 0; 451272cc70bSAndy Fleming 452272cc70bSAndy Fleming return 0; 453272cc70bSAndy Fleming } 454272cc70bSAndy Fleming 4555289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg) 456272cc70bSAndy Fleming { 4575289b535SAndrew Gabbasov struct mmc_cmd cmd; 458272cc70bSAndy Fleming int err; 459272cc70bSAndy Fleming 4605289b535SAndrew Gabbasov cmd.cmdidx = MMC_CMD_SEND_OP_COND; 4615289b535SAndrew Gabbasov cmd.resp_type = MMC_RSP_R3; 4625289b535SAndrew Gabbasov cmd.cmdarg = 0; 4635a20397bSRob Herring if (use_arg && !mmc_host_is_spi(mmc)) 4645a20397bSRob Herring cmd.cmdarg = OCR_HCS | 46593bfd616SPantelis Antoniou (mmc->cfg->voltages & 466a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_VOLTAGE_MASK)) | 467a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_ACCESS_MODE); 468e9550449SChe-Liang Chiou 4695289b535SAndrew Gabbasov err = mmc_send_cmd(mmc, &cmd, NULL); 470e9550449SChe-Liang Chiou if (err) 471e9550449SChe-Liang Chiou return err; 4725289b535SAndrew Gabbasov mmc->ocr = cmd.response[0]; 473e9550449SChe-Liang Chiou return 0; 474e9550449SChe-Liang Chiou } 475e9550449SChe-Liang Chiou 476750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc) 477e9550449SChe-Liang Chiou { 478e9550449SChe-Liang Chiou int err, i; 479e9550449SChe-Liang Chiou 480272cc70bSAndy Fleming /* Some cards seem to need this */ 481272cc70bSAndy Fleming mmc_go_idle(mmc); 482272cc70bSAndy Fleming 48331cacbabSRaffaele Recalcati /* Asking to the card its capabilities */ 484e9550449SChe-Liang Chiou for (i = 0; i < 2; i++) { 4855289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, i != 0); 48631cacbabSRaffaele Recalcati if (err) 48731cacbabSRaffaele Recalcati return err; 48831cacbabSRaffaele Recalcati 489e9550449SChe-Liang Chiou /* exit if not busy (flag seems to be inverted) */ 490a626c8d4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 491bd47c135SAndrew Gabbasov break; 492e9550449SChe-Liang Chiou } 493bd47c135SAndrew Gabbasov mmc->op_cond_pending = 1; 494bd47c135SAndrew Gabbasov return 0; 495e9550449SChe-Liang Chiou } 49631cacbabSRaffaele Recalcati 497750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc) 498e9550449SChe-Liang Chiou { 499e9550449SChe-Liang Chiou struct mmc_cmd cmd; 500e9550449SChe-Liang Chiou int timeout = 1000; 501e9550449SChe-Liang Chiou uint start; 502e9550449SChe-Liang Chiou int err; 503e9550449SChe-Liang Chiou 504e9550449SChe-Liang Chiou mmc->op_cond_pending = 0; 505cc17c01fSAndrew Gabbasov if (!(mmc->ocr & OCR_BUSY)) { 506d188b113SYangbo Lu /* Some cards seem to need this */ 507d188b113SYangbo Lu mmc_go_idle(mmc); 508d188b113SYangbo Lu 509e9550449SChe-Liang Chiou start = get_timer(0); 5101677eef4SAndrew Gabbasov while (1) { 5115289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, 1); 512272cc70bSAndy Fleming if (err) 513272cc70bSAndy Fleming return err; 5141677eef4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 5151677eef4SAndrew Gabbasov break; 516e9550449SChe-Liang Chiou if (get_timer(start) > timeout) 517915ffa52SJaehoon Chung return -EOPNOTSUPP; 518e9550449SChe-Liang Chiou udelay(100); 5191677eef4SAndrew Gabbasov } 520cc17c01fSAndrew Gabbasov } 521272cc70bSAndy Fleming 522d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 523d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 524d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 525d52ebf10SThomas Chou cmd.cmdarg = 0; 526d52ebf10SThomas Chou 527d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 528d52ebf10SThomas Chou 529d52ebf10SThomas Chou if (err) 530d52ebf10SThomas Chou return err; 531a626c8d4SAndrew Gabbasov 532a626c8d4SAndrew Gabbasov mmc->ocr = cmd.response[0]; 533d52ebf10SThomas Chou } 534d52ebf10SThomas Chou 535272cc70bSAndy Fleming mmc->version = MMC_VERSION_UNKNOWN; 536272cc70bSAndy Fleming 537272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 538def816a2SStephen Warren mmc->rca = 1; 539272cc70bSAndy Fleming 540272cc70bSAndy Fleming return 0; 541272cc70bSAndy Fleming } 542272cc70bSAndy Fleming 543272cc70bSAndy Fleming 544fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) 545272cc70bSAndy Fleming { 546272cc70bSAndy Fleming struct mmc_cmd cmd; 547272cc70bSAndy Fleming struct mmc_data data; 548272cc70bSAndy Fleming int err; 549272cc70bSAndy Fleming 550272cc70bSAndy Fleming /* Get the Card Status Register */ 551272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_EXT_CSD; 552272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 553272cc70bSAndy Fleming cmd.cmdarg = 0; 554272cc70bSAndy Fleming 555cdfd1ac6SYoshihiro Shimoda data.dest = (char *)ext_csd; 556272cc70bSAndy Fleming data.blocks = 1; 5578bfa195eSSimon Glass data.blocksize = MMC_MAX_BLOCK_LEN; 558272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 559272cc70bSAndy Fleming 560272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 561272cc70bSAndy Fleming 562272cc70bSAndy Fleming return err; 563272cc70bSAndy Fleming } 564272cc70bSAndy Fleming 56555e5defdSZiyuan Xu static int mmc_poll_for_busy(struct mmc *mmc) 566272cc70bSAndy Fleming { 567272cc70bSAndy Fleming struct mmc_cmd cmd; 56855e5defdSZiyuan Xu u8 busy = true; 56955e5defdSZiyuan Xu uint start; 57055e5defdSZiyuan Xu int ret; 5715d4fc8d9SRaffaele Recalcati int timeout = 1000; 57255e5defdSZiyuan Xu 57355e5defdSZiyuan Xu cmd.cmdidx = MMC_CMD_SEND_STATUS; 57455e5defdSZiyuan Xu cmd.resp_type = MMC_RSP_R1; 57555e5defdSZiyuan Xu cmd.cmdarg = mmc->rca << 16; 57655e5defdSZiyuan Xu 57755e5defdSZiyuan Xu start = get_timer(0); 57855e5defdSZiyuan Xu 57955e5defdSZiyuan Xu do { 58055e5defdSZiyuan Xu if (mmc_can_card_busy(mmc)) { 58155e5defdSZiyuan Xu busy = mmc_card_busy(mmc); 58255e5defdSZiyuan Xu } else { 58355e5defdSZiyuan Xu ret = mmc_send_cmd(mmc, &cmd, NULL); 58455e5defdSZiyuan Xu 58555e5defdSZiyuan Xu if (ret) 58655e5defdSZiyuan Xu return ret; 58755e5defdSZiyuan Xu 58855e5defdSZiyuan Xu if (cmd.response[0] & MMC_STATUS_SWITCH_ERROR) 58955e5defdSZiyuan Xu return -EBADMSG; 59055e5defdSZiyuan Xu busy = (cmd.response[0] & MMC_STATUS_CURR_STATE) == 59155e5defdSZiyuan Xu MMC_STATE_PRG; 59255e5defdSZiyuan Xu } 59355e5defdSZiyuan Xu 59455e5defdSZiyuan Xu if (get_timer(start) > timeout && busy) 59555e5defdSZiyuan Xu return -ETIMEDOUT; 59655e5defdSZiyuan Xu } while (busy); 59755e5defdSZiyuan Xu 59855e5defdSZiyuan Xu return 0; 59955e5defdSZiyuan Xu } 60055e5defdSZiyuan Xu 60155e5defdSZiyuan Xu static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value, 60255e5defdSZiyuan Xu u8 send_status) 60355e5defdSZiyuan Xu { 60455e5defdSZiyuan Xu struct mmc_cmd cmd; 605a9003dc6SMaxime Ripard int retries = 3; 6065d4fc8d9SRaffaele Recalcati int ret; 607272cc70bSAndy Fleming 608272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SWITCH; 609272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 610272cc70bSAndy Fleming cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 611272cc70bSAndy Fleming (index << 16) | 612272cc70bSAndy Fleming (value << 8); 613272cc70bSAndy Fleming 61455e5defdSZiyuan Xu do { 6155d4fc8d9SRaffaele Recalcati ret = mmc_send_cmd(mmc, &cmd, NULL); 6165d4fc8d9SRaffaele Recalcati 61755e5defdSZiyuan Xu if (!ret && send_status) 61855e5defdSZiyuan Xu return mmc_poll_for_busy(mmc); 61955e5defdSZiyuan Xu } while (--retries > 0 && ret); 62055e5defdSZiyuan Xu 621a9003dc6SMaxime Ripard return ret; 622a9003dc6SMaxime Ripard } 623a9003dc6SMaxime Ripard 62455e5defdSZiyuan Xu int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) 62555e5defdSZiyuan Xu { 62655e5defdSZiyuan Xu return __mmc_switch(mmc, set, index, value, true); 627272cc70bSAndy Fleming } 628272cc70bSAndy Fleming 62949dba033SZiyuan Xu static int mmc_select_bus_width(struct mmc *mmc) 63049dba033SZiyuan Xu { 63149dba033SZiyuan Xu u32 ext_csd_bits[] = { 63249dba033SZiyuan Xu EXT_CSD_BUS_WIDTH_8, 63349dba033SZiyuan Xu EXT_CSD_BUS_WIDTH_4, 63449dba033SZiyuan Xu }; 63549dba033SZiyuan Xu u32 bus_widths[] = { 63649dba033SZiyuan Xu MMC_BUS_WIDTH_8BIT, 63749dba033SZiyuan Xu MMC_BUS_WIDTH_4BIT, 63849dba033SZiyuan Xu }; 63949dba033SZiyuan Xu ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 64049dba033SZiyuan Xu ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 64149dba033SZiyuan Xu u32 idx, bus_width = 0; 64249dba033SZiyuan Xu int err = 0; 64349dba033SZiyuan Xu 64449dba033SZiyuan Xu if (mmc->version < MMC_VERSION_4 || 64549dba033SZiyuan Xu !(mmc->cfg->host_caps & (MMC_MODE_4BIT | MMC_MODE_8BIT))) 64649dba033SZiyuan Xu return 0; 64749dba033SZiyuan Xu 64849dba033SZiyuan Xu err = mmc_send_ext_csd(mmc, ext_csd); 64949dba033SZiyuan Xu 65049dba033SZiyuan Xu if (err) 65149dba033SZiyuan Xu return err; 65249dba033SZiyuan Xu 65349dba033SZiyuan Xu idx = (mmc->cfg->host_caps & MMC_MODE_8BIT) ? 0 : 1; 65449dba033SZiyuan Xu 65549dba033SZiyuan Xu /* 65649dba033SZiyuan Xu * Unlike SD, MMC cards dont have a configuration register to notify 65749dba033SZiyuan Xu * supported bus width. So bus test command should be run to identify 65849dba033SZiyuan Xu * the supported bus width or compare the ext csd values of current 65949dba033SZiyuan Xu * bus width and ext csd values of 1 bit mode read earlier. 66049dba033SZiyuan Xu */ 66149dba033SZiyuan Xu for (; idx < ARRAY_SIZE(bus_widths); idx++) { 66249dba033SZiyuan Xu /* 66349dba033SZiyuan Xu * Host is capable of 8bit transfer, then switch 66449dba033SZiyuan Xu * the device to work in 8bit transfer mode. If the 66549dba033SZiyuan Xu * mmc switch command returns error then switch to 66649dba033SZiyuan Xu * 4bit transfer mode. On success set the corresponding 66749dba033SZiyuan Xu * bus width on the host. 66849dba033SZiyuan Xu */ 66949dba033SZiyuan Xu err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 67049dba033SZiyuan Xu EXT_CSD_BUS_WIDTH, ext_csd_bits[idx]); 67149dba033SZiyuan Xu if (err) 67249dba033SZiyuan Xu continue; 67349dba033SZiyuan Xu 67449dba033SZiyuan Xu bus_width = bus_widths[idx]; 67549dba033SZiyuan Xu mmc_set_bus_width(mmc, bus_width); 67649dba033SZiyuan Xu 67749dba033SZiyuan Xu err = mmc_send_ext_csd(mmc, test_csd); 67849dba033SZiyuan Xu 67949dba033SZiyuan Xu if (err) 68049dba033SZiyuan Xu continue; 68149dba033SZiyuan Xu 68249dba033SZiyuan Xu /* Only compare read only fields */ 68349dba033SZiyuan Xu if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] == 68449dba033SZiyuan Xu test_csd[EXT_CSD_PARTITIONING_SUPPORT]) && 68549dba033SZiyuan Xu (ext_csd[EXT_CSD_HC_WP_GRP_SIZE] == 68649dba033SZiyuan Xu test_csd[EXT_CSD_HC_WP_GRP_SIZE]) && 68749dba033SZiyuan Xu (ext_csd[EXT_CSD_REV] == test_csd[EXT_CSD_REV]) && 68849dba033SZiyuan Xu (ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] == 68949dba033SZiyuan Xu test_csd[EXT_CSD_HC_ERASE_GRP_SIZE]) && 69049dba033SZiyuan Xu !memcmp(&ext_csd[EXT_CSD_SEC_CNT], 69149dba033SZiyuan Xu &test_csd[EXT_CSD_SEC_CNT], 4)) { 69249dba033SZiyuan Xu err = bus_width; 69349dba033SZiyuan Xu break; 69449dba033SZiyuan Xu } else { 69549dba033SZiyuan Xu err = -EBADMSG; 69649dba033SZiyuan Xu } 69749dba033SZiyuan Xu } 69849dba033SZiyuan Xu 69949dba033SZiyuan Xu return err; 70049dba033SZiyuan Xu } 70149dba033SZiyuan Xu 70249dba033SZiyuan Xu static const u8 tuning_blk_pattern_4bit[] = { 70349dba033SZiyuan Xu 0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc, 70449dba033SZiyuan Xu 0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef, 70549dba033SZiyuan Xu 0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb, 70649dba033SZiyuan Xu 0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef, 70749dba033SZiyuan Xu 0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c, 70849dba033SZiyuan Xu 0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee, 70949dba033SZiyuan Xu 0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff, 71049dba033SZiyuan Xu 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde, 71149dba033SZiyuan Xu }; 71249dba033SZiyuan Xu 71349dba033SZiyuan Xu static const u8 tuning_blk_pattern_8bit[] = { 71449dba033SZiyuan Xu 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 71549dba033SZiyuan Xu 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc, 71649dba033SZiyuan Xu 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff, 71749dba033SZiyuan Xu 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff, 71849dba033SZiyuan Xu 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd, 71949dba033SZiyuan Xu 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, 72049dba033SZiyuan Xu 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff, 72149dba033SZiyuan Xu 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff, 72249dba033SZiyuan Xu 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 72349dba033SZiyuan Xu 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 72449dba033SZiyuan Xu 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 72549dba033SZiyuan Xu 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 72649dba033SZiyuan Xu 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 72749dba033SZiyuan Xu 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 72849dba033SZiyuan Xu 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 72949dba033SZiyuan Xu 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 73049dba033SZiyuan Xu }; 73149dba033SZiyuan Xu 73249dba033SZiyuan Xu int mmc_send_tuning(struct mmc *mmc, u32 opcode) 73349dba033SZiyuan Xu { 73449dba033SZiyuan Xu struct mmc_cmd cmd; 73549dba033SZiyuan Xu struct mmc_data data; 73649dba033SZiyuan Xu const u8 *tuning_block_pattern; 73749dba033SZiyuan Xu int size, err = 0; 73849dba033SZiyuan Xu u8 *data_buf; 73949dba033SZiyuan Xu 74049dba033SZiyuan Xu if (mmc->bus_width == MMC_BUS_WIDTH_8BIT) { 74149dba033SZiyuan Xu tuning_block_pattern = tuning_blk_pattern_8bit; 74249dba033SZiyuan Xu size = sizeof(tuning_blk_pattern_8bit); 74349dba033SZiyuan Xu } else if (mmc->bus_width == MMC_BUS_WIDTH_4BIT) { 74449dba033SZiyuan Xu tuning_block_pattern = tuning_blk_pattern_4bit; 74549dba033SZiyuan Xu size = sizeof(tuning_blk_pattern_4bit); 74649dba033SZiyuan Xu } else { 74749dba033SZiyuan Xu return -EINVAL; 74849dba033SZiyuan Xu } 74949dba033SZiyuan Xu 75049dba033SZiyuan Xu data_buf = calloc(1, size); 75149dba033SZiyuan Xu if (!data_buf) 75249dba033SZiyuan Xu return -ENOMEM; 75349dba033SZiyuan Xu 75449dba033SZiyuan Xu cmd.cmdidx = opcode; 75549dba033SZiyuan Xu cmd.resp_type = MMC_RSP_R1; 75649dba033SZiyuan Xu cmd.cmdarg = 0; 75749dba033SZiyuan Xu 75849dba033SZiyuan Xu data.dest = (char *)data_buf; 75949dba033SZiyuan Xu data.blocksize = size; 76049dba033SZiyuan Xu data.blocks = 1; 76149dba033SZiyuan Xu data.flags = MMC_DATA_READ; 76249dba033SZiyuan Xu 76349dba033SZiyuan Xu err = mmc_send_cmd(mmc, &cmd, &data); 76449dba033SZiyuan Xu if (err) 76549dba033SZiyuan Xu goto out; 76649dba033SZiyuan Xu 76749dba033SZiyuan Xu if (memcmp(data_buf, tuning_block_pattern, size)) 76849dba033SZiyuan Xu err = -EIO; 76949dba033SZiyuan Xu out: 77049dba033SZiyuan Xu free(data_buf); 77149dba033SZiyuan Xu return err; 77249dba033SZiyuan Xu } 77349dba033SZiyuan Xu 77449dba033SZiyuan Xu static int mmc_execute_tuning(struct mmc *mmc) 77549dba033SZiyuan Xu { 77649dba033SZiyuan Xu #ifdef CONFIG_DM_MMC 77749dba033SZiyuan Xu struct dm_mmc_ops *ops = mmc_get_ops(mmc->dev); 77849dba033SZiyuan Xu #endif 77949dba033SZiyuan Xu u32 opcode; 78049dba033SZiyuan Xu 78149dba033SZiyuan Xu if (IS_SD(mmc)) 78249dba033SZiyuan Xu opcode = MMC_SEND_TUNING_BLOCK; 78349dba033SZiyuan Xu else 78449dba033SZiyuan Xu opcode = MMC_SEND_TUNING_BLOCK_HS200; 78549dba033SZiyuan Xu 78649dba033SZiyuan Xu #ifndef CONFIG_DM_MMC 78749dba033SZiyuan Xu if (mmc->cfg->ops->execute_tuning) { 78849dba033SZiyuan Xu return mmc->cfg->ops->execute_tuning(mmc, opcode); 78949dba033SZiyuan Xu #else 79049dba033SZiyuan Xu if (ops->execute_tuning) { 79149dba033SZiyuan Xu return ops->execute_tuning(mmc->dev, opcode); 79249dba033SZiyuan Xu #endif 79349dba033SZiyuan Xu } else { 79449dba033SZiyuan Xu debug("Tuning feature required for HS200 mode.\n"); 79549dba033SZiyuan Xu return -EIO; 79649dba033SZiyuan Xu } 79749dba033SZiyuan Xu } 79849dba033SZiyuan Xu 79949dba033SZiyuan Xu static int mmc_hs200_tuning(struct mmc *mmc) 80049dba033SZiyuan Xu { 80149dba033SZiyuan Xu return mmc_execute_tuning(mmc); 80249dba033SZiyuan Xu } 80349dba033SZiyuan Xu 804e61cd3d7SZiyuan Xu static int mmc_select_hs(struct mmc *mmc) 805e61cd3d7SZiyuan Xu { 806e61cd3d7SZiyuan Xu int ret; 807e61cd3d7SZiyuan Xu 808e61cd3d7SZiyuan Xu ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 809e61cd3d7SZiyuan Xu EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS); 810e61cd3d7SZiyuan Xu 811e61cd3d7SZiyuan Xu if (!ret) 812e61cd3d7SZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_MMC_HS); 813e61cd3d7SZiyuan Xu 814e61cd3d7SZiyuan Xu return ret; 815e61cd3d7SZiyuan Xu } 816e61cd3d7SZiyuan Xu 8175545757fSZiyuan Xu static int mmc_select_hs_ddr(struct mmc *mmc) 8185545757fSZiyuan Xu { 8195545757fSZiyuan Xu u32 ext_csd_bits; 8205545757fSZiyuan Xu int err = 0; 8215545757fSZiyuan Xu 8225545757fSZiyuan Xu if (mmc->bus_width == MMC_BUS_WIDTH_1BIT) 8235545757fSZiyuan Xu return 0; 8245545757fSZiyuan Xu 8255545757fSZiyuan Xu ext_csd_bits = (mmc->bus_width == MMC_BUS_WIDTH_8BIT) ? 8265545757fSZiyuan Xu EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4; 8275545757fSZiyuan Xu 8285545757fSZiyuan Xu err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 8295545757fSZiyuan Xu EXT_CSD_BUS_WIDTH, ext_csd_bits); 8305545757fSZiyuan Xu if (err) 8315545757fSZiyuan Xu return err; 8325545757fSZiyuan Xu 8335545757fSZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_MMC_DDR52); 8345545757fSZiyuan Xu 8355545757fSZiyuan Xu return 0; 8365545757fSZiyuan Xu } 8375545757fSZiyuan Xu 83849dba033SZiyuan Xu #ifndef CONFIG_SPL_BUILD 83949dba033SZiyuan Xu static int mmc_select_hs200(struct mmc *mmc) 84049dba033SZiyuan Xu { 84149dba033SZiyuan Xu int ret; 84249dba033SZiyuan Xu struct mmc_cmd cmd; 84349dba033SZiyuan Xu 84449dba033SZiyuan Xu /* 84549dba033SZiyuan Xu * Set the bus width(4 or 8) with host's support and 84649dba033SZiyuan Xu * switch to HS200 mode if bus width is set successfully. 84749dba033SZiyuan Xu */ 84849dba033SZiyuan Xu ret = mmc_select_bus_width(mmc); 84949dba033SZiyuan Xu 85049dba033SZiyuan Xu if (ret > 0) { 85149dba033SZiyuan Xu ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 85249dba033SZiyuan Xu EXT_CSD_HS_TIMING, 85349dba033SZiyuan Xu EXT_CSD_TIMING_HS200, false); 85449dba033SZiyuan Xu 85549dba033SZiyuan Xu if (ret) 85649dba033SZiyuan Xu return ret; 85749dba033SZiyuan Xu 85849dba033SZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_MMC_HS200); 85949dba033SZiyuan Xu 86049dba033SZiyuan Xu cmd.cmdidx = MMC_CMD_SEND_STATUS; 86149dba033SZiyuan Xu cmd.resp_type = MMC_RSP_R1; 86249dba033SZiyuan Xu cmd.cmdarg = mmc->rca << 16; 86349dba033SZiyuan Xu 86449dba033SZiyuan Xu ret = mmc_send_cmd(mmc, &cmd, NULL); 86549dba033SZiyuan Xu 86649dba033SZiyuan Xu if (ret) 86749dba033SZiyuan Xu return ret; 86849dba033SZiyuan Xu 86949dba033SZiyuan Xu if (cmd.response[0] & MMC_STATUS_SWITCH_ERROR) 87049dba033SZiyuan Xu return -EBADMSG; 87149dba033SZiyuan Xu } 87249dba033SZiyuan Xu 87349dba033SZiyuan Xu return ret; 87449dba033SZiyuan Xu } 87549dba033SZiyuan Xu #endif 87649dba033SZiyuan Xu 877b673f29aSZiyuan Xu static int mmc_select_hs400(struct mmc *mmc) 878b673f29aSZiyuan Xu { 879b673f29aSZiyuan Xu int ret; 880b673f29aSZiyuan Xu 881b673f29aSZiyuan Xu /* Switch card to HS mode */ 882b673f29aSZiyuan Xu ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 883b673f29aSZiyuan Xu EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS, false); 884b673f29aSZiyuan Xu if (ret) 885b673f29aSZiyuan Xu return ret; 886b673f29aSZiyuan Xu 887b673f29aSZiyuan Xu /* Set host controller to HS timing */ 888b673f29aSZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_MMC_HS); 889b673f29aSZiyuan Xu 890b673f29aSZiyuan Xu /* Reduce frequency to HS frequency */ 891b673f29aSZiyuan Xu mmc_set_clock(mmc, MMC_HIGH_52_MAX_DTR); 892b673f29aSZiyuan Xu 893b673f29aSZiyuan Xu ret = mmc_send_status(mmc, 1000); 894b673f29aSZiyuan Xu if (ret) 895b673f29aSZiyuan Xu return ret; 896b673f29aSZiyuan Xu 897b673f29aSZiyuan Xu /* Switch card to DDR */ 898b673f29aSZiyuan Xu ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 899b673f29aSZiyuan Xu EXT_CSD_BUS_WIDTH, 900b673f29aSZiyuan Xu EXT_CSD_DDR_BUS_WIDTH_8); 901b673f29aSZiyuan Xu if (ret) 902b673f29aSZiyuan Xu return ret; 903b673f29aSZiyuan Xu 904b673f29aSZiyuan Xu /* Switch card to HS400 */ 905b673f29aSZiyuan Xu ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 906b673f29aSZiyuan Xu EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400, false); 907b673f29aSZiyuan Xu if (ret) 908b673f29aSZiyuan Xu return ret; 909b673f29aSZiyuan Xu 910b673f29aSZiyuan Xu /* Set host controller to HS400 timing and frequency */ 911b673f29aSZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_MMC_HS400); 912b673f29aSZiyuan Xu 913b673f29aSZiyuan Xu return ret; 914b673f29aSZiyuan Xu } 915b673f29aSZiyuan Xu 916227f658eSZiyuan Xu static u32 mmc_select_card_type(struct mmc *mmc, u8 *ext_csd) 917227f658eSZiyuan Xu { 918227f658eSZiyuan Xu u8 card_type; 919227f658eSZiyuan Xu u32 host_caps, avail_type = 0; 920227f658eSZiyuan Xu 921227f658eSZiyuan Xu card_type = ext_csd[EXT_CSD_CARD_TYPE]; 922227f658eSZiyuan Xu host_caps = mmc->cfg->host_caps; 923227f658eSZiyuan Xu 924227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS) && 925227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_26)) 926227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_26; 927227f658eSZiyuan Xu 928227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS) && 929227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_52)) 930227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_52; 931227f658eSZiyuan Xu 932227f658eSZiyuan Xu /* 933227f658eSZiyuan Xu * For the moment, u-boot doesn't support signal voltage 934227f658eSZiyuan Xu * switch, therefor we assume that host support ddr52 935227f658eSZiyuan Xu * at 1.8v or 3.3v I/O(1.2v I/O not supported, hs200 and 936227f658eSZiyuan Xu * hs400 are the same). 937227f658eSZiyuan Xu */ 938227f658eSZiyuan Xu if ((host_caps & MMC_MODE_DDR_52MHz) && 939227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)) 940227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V; 941227f658eSZiyuan Xu 942227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS200) && 943227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_HS200_1_8V)) 944227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V; 945227f658eSZiyuan Xu 946227f658eSZiyuan Xu /* 947227f658eSZiyuan Xu * If host can support HS400, it means that host can also 948227f658eSZiyuan Xu * support HS200. 949227f658eSZiyuan Xu */ 950227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS400) && 951227f658eSZiyuan Xu (host_caps & MMC_MODE_8BIT) && 952227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_HS400_1_8V)) 953227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V | 954227f658eSZiyuan Xu EXT_CSD_CARD_TYPE_HS400_1_8V; 955227f658eSZiyuan Xu 956227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS400ES) && 957227f658eSZiyuan Xu (host_caps & MMC_MODE_8BIT) && 958227f658eSZiyuan Xu ext_csd[EXT_CSD_STROBE_SUPPORT] && 959227f658eSZiyuan Xu (avail_type & EXT_CSD_CARD_TYPE_HS400_1_8V)) 960227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V | 961227f658eSZiyuan Xu EXT_CSD_CARD_TYPE_HS400_1_8V | 962227f658eSZiyuan Xu EXT_CSD_CARD_TYPE_HS400ES; 963227f658eSZiyuan Xu 964227f658eSZiyuan Xu return avail_type; 965227f658eSZiyuan Xu } 966227f658eSZiyuan Xu 96749dba033SZiyuan Xu static void mmc_set_bus_speed(struct mmc *mmc, u8 avail_type) 96849dba033SZiyuan Xu { 96949dba033SZiyuan Xu int clock = 0; 97049dba033SZiyuan Xu 97149dba033SZiyuan Xu if (mmc_card_hs(mmc)) 97249dba033SZiyuan Xu clock = (avail_type & EXT_CSD_CARD_TYPE_52) ? 97349dba033SZiyuan Xu MMC_HIGH_52_MAX_DTR : MMC_HIGH_26_MAX_DTR; 97449dba033SZiyuan Xu else if (mmc_card_hs200(mmc) || 97549dba033SZiyuan Xu mmc_card_hs400(mmc) || 97649dba033SZiyuan Xu mmc_card_hs400es(mmc)) 97749dba033SZiyuan Xu clock = MMC_HS200_MAX_DTR; 97849dba033SZiyuan Xu 97949dba033SZiyuan Xu mmc_set_clock(mmc, clock); 98049dba033SZiyuan Xu } 98149dba033SZiyuan Xu 982fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc) 983272cc70bSAndy Fleming { 9848bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 985227f658eSZiyuan Xu u32 avail_type; 986272cc70bSAndy Fleming int err; 987272cc70bSAndy Fleming 988fc5b32fbSAndrew Gabbasov mmc->card_caps = 0; 989272cc70bSAndy Fleming 990d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 991d52ebf10SThomas Chou return 0; 992d52ebf10SThomas Chou 993272cc70bSAndy Fleming /* Only version 4 supports high-speed */ 994272cc70bSAndy Fleming if (mmc->version < MMC_VERSION_4) 995272cc70bSAndy Fleming return 0; 996272cc70bSAndy Fleming 997fc5b32fbSAndrew Gabbasov mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; 998fc5b32fbSAndrew Gabbasov 999272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 1000272cc70bSAndy Fleming 1001272cc70bSAndy Fleming if (err) 1002272cc70bSAndy Fleming return err; 1003272cc70bSAndy Fleming 1004227f658eSZiyuan Xu avail_type = mmc_select_card_type(mmc, ext_csd); 1005272cc70bSAndy Fleming 100649dba033SZiyuan Xu #ifndef CONFIG_SPL_BUILD 100749dba033SZiyuan Xu if (avail_type & EXT_CSD_CARD_TYPE_HS200) 100849dba033SZiyuan Xu err = mmc_select_hs200(mmc); 100949dba033SZiyuan Xu else 101049dba033SZiyuan Xu #endif 1011227f658eSZiyuan Xu if (avail_type & EXT_CSD_CARD_TYPE_HS) 1012e61cd3d7SZiyuan Xu err = mmc_select_hs(mmc); 1013227f658eSZiyuan Xu else 1014227f658eSZiyuan Xu err = -EINVAL; 1015272cc70bSAndy Fleming 1016272cc70bSAndy Fleming if (err) 1017a5e27b41SHeiko Schocher return err; 1018272cc70bSAndy Fleming 101949dba033SZiyuan Xu mmc_set_bus_speed(mmc, avail_type); 1020272cc70bSAndy Fleming 1021b673f29aSZiyuan Xu if (mmc_card_hs200(mmc)) { 102249dba033SZiyuan Xu err = mmc_hs200_tuning(mmc); 1023b673f29aSZiyuan Xu if (avail_type & EXT_CSD_CARD_TYPE_HS400 && 1024b673f29aSZiyuan Xu mmc->bus_width == MMC_BUS_WIDTH_8BIT) { 1025b673f29aSZiyuan Xu err = mmc_select_hs400(mmc); 1026b673f29aSZiyuan Xu mmc_set_bus_speed(mmc, avail_type); 1027b673f29aSZiyuan Xu } 1028b673f29aSZiyuan Xu } else if (!mmc_card_hs400es(mmc)) { 102949dba033SZiyuan Xu err = mmc_select_bus_width(mmc) > 0 ? 0 : err; 10305545757fSZiyuan Xu if (!err && avail_type & EXT_CSD_CARD_TYPE_DDR_52) 10315545757fSZiyuan Xu err = mmc_select_hs_ddr(mmc); 10325545757fSZiyuan Xu } 103349dba033SZiyuan Xu 1034272cc70bSAndy Fleming return err; 1035272cc70bSAndy Fleming } 1036272cc70bSAndy Fleming 1037f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num) 1038f866a46dSStephen Warren { 1039f866a46dSStephen Warren switch (part_num) { 1040f866a46dSStephen Warren case 0: 1041f866a46dSStephen Warren mmc->capacity = mmc->capacity_user; 1042f866a46dSStephen Warren break; 1043f866a46dSStephen Warren case 1: 1044f866a46dSStephen Warren case 2: 1045f866a46dSStephen Warren mmc->capacity = mmc->capacity_boot; 1046f866a46dSStephen Warren break; 1047f866a46dSStephen Warren case 3: 1048f866a46dSStephen Warren mmc->capacity = mmc->capacity_rpmb; 1049f866a46dSStephen Warren break; 1050f866a46dSStephen Warren case 4: 1051f866a46dSStephen Warren case 5: 1052f866a46dSStephen Warren case 6: 1053f866a46dSStephen Warren case 7: 1054f866a46dSStephen Warren mmc->capacity = mmc->capacity_gp[part_num - 4]; 1055f866a46dSStephen Warren break; 1056f866a46dSStephen Warren default: 1057f866a46dSStephen Warren return -1; 1058f866a46dSStephen Warren } 1059f866a46dSStephen Warren 1060c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len); 1061f866a46dSStephen Warren 1062f866a46dSStephen Warren return 0; 1063f866a46dSStephen Warren } 1064f866a46dSStephen Warren 10657dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num) 1066bc897b1dSLei Wen { 1067f866a46dSStephen Warren int ret; 1068bc897b1dSLei Wen 1069f866a46dSStephen Warren ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 1070bc897b1dSLei Wen (mmc->part_config & ~PART_ACCESS_MASK) 1071bc897b1dSLei Wen | (part_num & PART_ACCESS_MASK)); 1072f866a46dSStephen Warren 10736dc93e70SPeter Bigot /* 10746dc93e70SPeter Bigot * Set the capacity if the switch succeeded or was intended 10756dc93e70SPeter Bigot * to return to representing the raw device. 10766dc93e70SPeter Bigot */ 1077873cc1d7SStephen Warren if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) { 10786dc93e70SPeter Bigot ret = mmc_set_capacity(mmc, part_num); 1079fdbb139fSSimon Glass mmc_get_blk_desc(mmc)->hwpart = part_num; 1080873cc1d7SStephen Warren } 10816dc93e70SPeter Bigot 10826dc93e70SPeter Bigot return ret; 1083bc897b1dSLei Wen } 1084bc897b1dSLei Wen 1085ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc, 1086ac9da0e0SDiego Santa Cruz const struct mmc_hwpart_conf *conf, 1087ac9da0e0SDiego Santa Cruz enum mmc_hwpart_conf_mode mode) 1088ac9da0e0SDiego Santa Cruz { 1089ac9da0e0SDiego Santa Cruz u8 part_attrs = 0; 1090ac9da0e0SDiego Santa Cruz u32 enh_size_mult; 1091ac9da0e0SDiego Santa Cruz u32 enh_start_addr; 1092ac9da0e0SDiego Santa Cruz u32 gp_size_mult[4]; 1093ac9da0e0SDiego Santa Cruz u32 max_enh_size_mult; 1094ac9da0e0SDiego Santa Cruz u32 tot_enh_size_mult = 0; 10958dda5b0eSDiego Santa Cruz u8 wr_rel_set; 1096ac9da0e0SDiego Santa Cruz int i, pidx, err; 1097ac9da0e0SDiego Santa Cruz ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 1098ac9da0e0SDiego Santa Cruz 1099ac9da0e0SDiego Santa Cruz if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE) 1100ac9da0e0SDiego Santa Cruz return -EINVAL; 1101ac9da0e0SDiego Santa Cruz 1102ac9da0e0SDiego Santa Cruz if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) { 1103ac9da0e0SDiego Santa Cruz printf("eMMC >= 4.4 required for enhanced user data area\n"); 1104ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1105ac9da0e0SDiego Santa Cruz } 1106ac9da0e0SDiego Santa Cruz 1107ac9da0e0SDiego Santa Cruz if (!(mmc->part_support & PART_SUPPORT)) { 1108ac9da0e0SDiego Santa Cruz printf("Card does not support partitioning\n"); 1109ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1110ac9da0e0SDiego Santa Cruz } 1111ac9da0e0SDiego Santa Cruz 1112ac9da0e0SDiego Santa Cruz if (!mmc->hc_wp_grp_size) { 1113ac9da0e0SDiego Santa Cruz printf("Card does not define HC WP group size\n"); 1114ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1115ac9da0e0SDiego Santa Cruz } 1116ac9da0e0SDiego Santa Cruz 1117ac9da0e0SDiego Santa Cruz /* check partition alignment and total enhanced size */ 1118ac9da0e0SDiego Santa Cruz if (conf->user.enh_size) { 1119ac9da0e0SDiego Santa Cruz if (conf->user.enh_size % mmc->hc_wp_grp_size || 1120ac9da0e0SDiego Santa Cruz conf->user.enh_start % mmc->hc_wp_grp_size) { 1121ac9da0e0SDiego Santa Cruz printf("User data enhanced area not HC WP group " 1122ac9da0e0SDiego Santa Cruz "size aligned\n"); 1123ac9da0e0SDiego Santa Cruz return -EINVAL; 1124ac9da0e0SDiego Santa Cruz } 1125ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_USR; 1126ac9da0e0SDiego Santa Cruz enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size; 1127ac9da0e0SDiego Santa Cruz if (mmc->high_capacity) { 1128ac9da0e0SDiego Santa Cruz enh_start_addr = conf->user.enh_start; 1129ac9da0e0SDiego Santa Cruz } else { 1130ac9da0e0SDiego Santa Cruz enh_start_addr = (conf->user.enh_start << 9); 1131ac9da0e0SDiego Santa Cruz } 1132ac9da0e0SDiego Santa Cruz } else { 1133ac9da0e0SDiego Santa Cruz enh_size_mult = 0; 1134ac9da0e0SDiego Santa Cruz enh_start_addr = 0; 1135ac9da0e0SDiego Santa Cruz } 1136ac9da0e0SDiego Santa Cruz tot_enh_size_mult += enh_size_mult; 1137ac9da0e0SDiego Santa Cruz 1138ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 1139ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) { 1140ac9da0e0SDiego Santa Cruz printf("GP%i partition not HC WP group size " 1141ac9da0e0SDiego Santa Cruz "aligned\n", pidx+1); 1142ac9da0e0SDiego Santa Cruz return -EINVAL; 1143ac9da0e0SDiego Santa Cruz } 1144ac9da0e0SDiego Santa Cruz gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size; 1145ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) { 1146ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_GP(pidx); 1147ac9da0e0SDiego Santa Cruz tot_enh_size_mult += gp_size_mult[pidx]; 1148ac9da0e0SDiego Santa Cruz } 1149ac9da0e0SDiego Santa Cruz } 1150ac9da0e0SDiego Santa Cruz 1151ac9da0e0SDiego Santa Cruz if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) { 1152ac9da0e0SDiego Santa Cruz printf("Card does not support enhanced attribute\n"); 1153ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1154ac9da0e0SDiego Santa Cruz } 1155ac9da0e0SDiego Santa Cruz 1156ac9da0e0SDiego Santa Cruz err = mmc_send_ext_csd(mmc, ext_csd); 1157ac9da0e0SDiego Santa Cruz if (err) 1158ac9da0e0SDiego Santa Cruz return err; 1159ac9da0e0SDiego Santa Cruz 1160ac9da0e0SDiego Santa Cruz max_enh_size_mult = 1161ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) + 1162ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) + 1163ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]; 1164ac9da0e0SDiego Santa Cruz if (tot_enh_size_mult > max_enh_size_mult) { 1165ac9da0e0SDiego Santa Cruz printf("Total enhanced size exceeds maximum (%u > %u)\n", 1166ac9da0e0SDiego Santa Cruz tot_enh_size_mult, max_enh_size_mult); 1167ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1168ac9da0e0SDiego Santa Cruz } 1169ac9da0e0SDiego Santa Cruz 11708dda5b0eSDiego Santa Cruz /* The default value of EXT_CSD_WR_REL_SET is device 11718dda5b0eSDiego Santa Cruz * dependent, the values can only be changed if the 11728dda5b0eSDiego Santa Cruz * EXT_CSD_HS_CTRL_REL bit is set. The values can be 11738dda5b0eSDiego Santa Cruz * changed only once and before partitioning is completed. */ 11748dda5b0eSDiego Santa Cruz wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 11758dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_change) { 11768dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_set) 11778dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_USR; 11788dda5b0eSDiego Santa Cruz else 11798dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR; 11808dda5b0eSDiego Santa Cruz } 11818dda5b0eSDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 11828dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_change) { 11838dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_set) 11848dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx); 11858dda5b0eSDiego Santa Cruz else 11868dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx); 11878dda5b0eSDiego Santa Cruz } 11888dda5b0eSDiego Santa Cruz } 11898dda5b0eSDiego Santa Cruz 11908dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] && 11918dda5b0eSDiego Santa Cruz !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) { 11928dda5b0eSDiego Santa Cruz puts("Card does not support host controlled partition write " 11938dda5b0eSDiego Santa Cruz "reliability settings\n"); 11948dda5b0eSDiego Santa Cruz return -EMEDIUMTYPE; 11958dda5b0eSDiego Santa Cruz } 11968dda5b0eSDiego Santa Cruz 1197ac9da0e0SDiego Santa Cruz if (ext_csd[EXT_CSD_PARTITION_SETTING] & 1198ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED) { 1199ac9da0e0SDiego Santa Cruz printf("Card already partitioned\n"); 1200ac9da0e0SDiego Santa Cruz return -EPERM; 1201ac9da0e0SDiego Santa Cruz } 1202ac9da0e0SDiego Santa Cruz 1203ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_CHECK) 1204ac9da0e0SDiego Santa Cruz return 0; 1205ac9da0e0SDiego Santa Cruz 1206ac9da0e0SDiego Santa Cruz /* Partitioning requires high-capacity size definitions */ 1207ac9da0e0SDiego Santa Cruz if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) { 1208ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1209ac9da0e0SDiego Santa Cruz EXT_CSD_ERASE_GROUP_DEF, 1); 1210ac9da0e0SDiego Santa Cruz 1211ac9da0e0SDiego Santa Cruz if (err) 1212ac9da0e0SDiego Santa Cruz return err; 1213ac9da0e0SDiego Santa Cruz 1214ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 1215ac9da0e0SDiego Santa Cruz 1216ac9da0e0SDiego Santa Cruz /* update erase group size to be high-capacity */ 1217ac9da0e0SDiego Santa Cruz mmc->erase_grp_size = 1218ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 1219ac9da0e0SDiego Santa Cruz 1220ac9da0e0SDiego Santa Cruz } 1221ac9da0e0SDiego Santa Cruz 1222ac9da0e0SDiego Santa Cruz /* all OK, write the configuration */ 1223ac9da0e0SDiego Santa Cruz for (i = 0; i < 4; i++) { 1224ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1225ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_START_ADDR+i, 1226ac9da0e0SDiego Santa Cruz (enh_start_addr >> (i*8)) & 0xFF); 1227ac9da0e0SDiego Santa Cruz if (err) 1228ac9da0e0SDiego Santa Cruz return err; 1229ac9da0e0SDiego Santa Cruz } 1230ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 1231ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1232ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_SIZE_MULT+i, 1233ac9da0e0SDiego Santa Cruz (enh_size_mult >> (i*8)) & 0xFF); 1234ac9da0e0SDiego Santa Cruz if (err) 1235ac9da0e0SDiego Santa Cruz return err; 1236ac9da0e0SDiego Santa Cruz } 1237ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 1238ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 1239ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1240ac9da0e0SDiego Santa Cruz EXT_CSD_GP_SIZE_MULT+pidx*3+i, 1241ac9da0e0SDiego Santa Cruz (gp_size_mult[pidx] >> (i*8)) & 0xFF); 1242ac9da0e0SDiego Santa Cruz if (err) 1243ac9da0e0SDiego Santa Cruz return err; 1244ac9da0e0SDiego Santa Cruz } 1245ac9da0e0SDiego Santa Cruz } 1246ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1247ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs); 1248ac9da0e0SDiego Santa Cruz if (err) 1249ac9da0e0SDiego Santa Cruz return err; 1250ac9da0e0SDiego Santa Cruz 1251ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_SET) 1252ac9da0e0SDiego Santa Cruz return 0; 1253ac9da0e0SDiego Santa Cruz 12548dda5b0eSDiego Santa Cruz /* The WR_REL_SET is a write-once register but shall be 12558dda5b0eSDiego Santa Cruz * written before setting PART_SETTING_COMPLETED. As it is 12568dda5b0eSDiego Santa Cruz * write-once we can only write it when completing the 12578dda5b0eSDiego Santa Cruz * partitioning. */ 12588dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) { 12598dda5b0eSDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 12608dda5b0eSDiego Santa Cruz EXT_CSD_WR_REL_SET, wr_rel_set); 12618dda5b0eSDiego Santa Cruz if (err) 12628dda5b0eSDiego Santa Cruz return err; 12638dda5b0eSDiego Santa Cruz } 12648dda5b0eSDiego Santa Cruz 1265ac9da0e0SDiego Santa Cruz /* Setting PART_SETTING_COMPLETED confirms the partition 1266ac9da0e0SDiego Santa Cruz * configuration but it only becomes effective after power 1267ac9da0e0SDiego Santa Cruz * cycle, so we do not adjust the partition related settings 1268ac9da0e0SDiego Santa Cruz * in the mmc struct. */ 1269ac9da0e0SDiego Santa Cruz 1270ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1271ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING, 1272ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 1273ac9da0e0SDiego Santa Cruz if (err) 1274ac9da0e0SDiego Santa Cruz return err; 1275ac9da0e0SDiego Santa Cruz 1276ac9da0e0SDiego Santa Cruz return 0; 1277ac9da0e0SDiego Santa Cruz } 1278ac9da0e0SDiego Santa Cruz 1279e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 128048972d90SThierry Reding int mmc_getcd(struct mmc *mmc) 128148972d90SThierry Reding { 128248972d90SThierry Reding int cd; 128348972d90SThierry Reding 128448972d90SThierry Reding cd = board_mmc_getcd(mmc); 128548972d90SThierry Reding 1286d4e1da4eSPeter Korsgaard if (cd < 0) { 128793bfd616SPantelis Antoniou if (mmc->cfg->ops->getcd) 128893bfd616SPantelis Antoniou cd = mmc->cfg->ops->getcd(mmc); 1289d4e1da4eSPeter Korsgaard else 1290d4e1da4eSPeter Korsgaard cd = 1; 1291d4e1da4eSPeter Korsgaard } 129248972d90SThierry Reding 129348972d90SThierry Reding return cd; 129448972d90SThierry Reding } 12958ca51e51SSimon Glass #endif 129648972d90SThierry Reding 1297fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) 1298272cc70bSAndy Fleming { 1299272cc70bSAndy Fleming struct mmc_cmd cmd; 1300272cc70bSAndy Fleming struct mmc_data data; 1301272cc70bSAndy Fleming 1302272cc70bSAndy Fleming /* Switch the frequency */ 1303272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC; 1304272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1305272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff; 1306272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4)); 1307272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4); 1308272cc70bSAndy Fleming 1309272cc70bSAndy Fleming data.dest = (char *)resp; 1310272cc70bSAndy Fleming data.blocksize = 64; 1311272cc70bSAndy Fleming data.blocks = 1; 1312272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1313272cc70bSAndy Fleming 1314272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 1315272cc70bSAndy Fleming } 1316272cc70bSAndy Fleming 1317272cc70bSAndy Fleming 1318fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc) 1319272cc70bSAndy Fleming { 1320272cc70bSAndy Fleming int err; 1321272cc70bSAndy Fleming struct mmc_cmd cmd; 1322f781dd38SAnton staaf ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2); 1323f781dd38SAnton staaf ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16); 1324272cc70bSAndy Fleming struct mmc_data data; 1325272cc70bSAndy Fleming int timeout; 1326272cc70bSAndy Fleming 1327272cc70bSAndy Fleming mmc->card_caps = 0; 1328272cc70bSAndy Fleming 1329d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 1330d52ebf10SThomas Chou return 0; 1331d52ebf10SThomas Chou 1332272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */ 1333272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 1334272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1335272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1336272cc70bSAndy Fleming 1337272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1338272cc70bSAndy Fleming 1339272cc70bSAndy Fleming if (err) 1340272cc70bSAndy Fleming return err; 1341272cc70bSAndy Fleming 1342272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR; 1343272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1344272cc70bSAndy Fleming cmd.cmdarg = 0; 1345272cc70bSAndy Fleming 1346272cc70bSAndy Fleming timeout = 3; 1347272cc70bSAndy Fleming 1348272cc70bSAndy Fleming retry_scr: 1349f781dd38SAnton staaf data.dest = (char *)scr; 1350272cc70bSAndy Fleming data.blocksize = 8; 1351272cc70bSAndy Fleming data.blocks = 1; 1352272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1353272cc70bSAndy Fleming 1354272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 1355272cc70bSAndy Fleming 1356272cc70bSAndy Fleming if (err) { 1357272cc70bSAndy Fleming if (timeout--) 1358272cc70bSAndy Fleming goto retry_scr; 1359272cc70bSAndy Fleming 1360272cc70bSAndy Fleming return err; 1361272cc70bSAndy Fleming } 1362272cc70bSAndy Fleming 13634e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]); 13644e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]); 1365272cc70bSAndy Fleming 1366272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) { 1367272cc70bSAndy Fleming case 0: 1368272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1369272cc70bSAndy Fleming break; 1370272cc70bSAndy Fleming case 1: 1371272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10; 1372272cc70bSAndy Fleming break; 1373272cc70bSAndy Fleming case 2: 1374272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 13751741c64dSJaehoon Chung if ((mmc->scr[0] >> 15) & 0x1) 13761741c64dSJaehoon Chung mmc->version = SD_VERSION_3; 1377272cc70bSAndy Fleming break; 1378272cc70bSAndy Fleming default: 1379272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1380272cc70bSAndy Fleming break; 1381272cc70bSAndy Fleming } 1382272cc70bSAndy Fleming 1383b44c7083SAlagu Sankar if (mmc->scr[0] & SD_DATA_4BIT) 1384b44c7083SAlagu Sankar mmc->card_caps |= MMC_MODE_4BIT; 1385b44c7083SAlagu Sankar 1386272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */ 1387272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0) 1388272cc70bSAndy Fleming return 0; 1389272cc70bSAndy Fleming 1390272cc70bSAndy Fleming timeout = 4; 1391272cc70bSAndy Fleming while (timeout--) { 1392272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, 1393f781dd38SAnton staaf (u8 *)switch_status); 1394272cc70bSAndy Fleming 1395272cc70bSAndy Fleming if (err) 1396272cc70bSAndy Fleming return err; 1397272cc70bSAndy Fleming 1398272cc70bSAndy Fleming /* The high-speed function is busy. Try again */ 13994e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) 1400272cc70bSAndy Fleming break; 1401272cc70bSAndy Fleming } 1402272cc70bSAndy Fleming 1403272cc70bSAndy Fleming /* If high-speed isn't supported, we return */ 14044e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)) 1405272cc70bSAndy Fleming return 0; 1406272cc70bSAndy Fleming 14072c3fbf4cSMacpaul Lin /* 14082c3fbf4cSMacpaul Lin * If the host doesn't support SD_HIGHSPEED, do not switch card to 14092c3fbf4cSMacpaul Lin * HIGHSPEED mode even if the card support SD_HIGHSPPED. 14102c3fbf4cSMacpaul Lin * This can avoid furthur problem when the card runs in different 14112c3fbf4cSMacpaul Lin * mode between the host. 14122c3fbf4cSMacpaul Lin */ 141393bfd616SPantelis Antoniou if (!((mmc->cfg->host_caps & MMC_MODE_HS_52MHz) && 141493bfd616SPantelis Antoniou (mmc->cfg->host_caps & MMC_MODE_HS))) 14152c3fbf4cSMacpaul Lin return 0; 14162c3fbf4cSMacpaul Lin 1417f781dd38SAnton staaf err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status); 1418272cc70bSAndy Fleming 1419272cc70bSAndy Fleming if (err) 1420272cc70bSAndy Fleming return err; 1421272cc70bSAndy Fleming 14224e3d89baSYauhen Kharuzhy if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000) 1423272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS; 1424272cc70bSAndy Fleming 1425272cc70bSAndy Fleming return 0; 1426272cc70bSAndy Fleming } 1427272cc70bSAndy Fleming 14283697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc) 14293697e599SPeng Fan { 14303697e599SPeng Fan int err, i; 14313697e599SPeng Fan struct mmc_cmd cmd; 14323697e599SPeng Fan ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16); 14333697e599SPeng Fan struct mmc_data data; 14343697e599SPeng Fan int timeout = 3; 14353697e599SPeng Fan unsigned int au, eo, et, es; 14363697e599SPeng Fan 14373697e599SPeng Fan cmd.cmdidx = MMC_CMD_APP_CMD; 14383697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 14393697e599SPeng Fan cmd.cmdarg = mmc->rca << 16; 14403697e599SPeng Fan 14413697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, NULL); 14423697e599SPeng Fan if (err) 14433697e599SPeng Fan return err; 14443697e599SPeng Fan 14453697e599SPeng Fan cmd.cmdidx = SD_CMD_APP_SD_STATUS; 14463697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 14473697e599SPeng Fan cmd.cmdarg = 0; 14483697e599SPeng Fan 14493697e599SPeng Fan retry_ssr: 14503697e599SPeng Fan data.dest = (char *)ssr; 14513697e599SPeng Fan data.blocksize = 64; 14523697e599SPeng Fan data.blocks = 1; 14533697e599SPeng Fan data.flags = MMC_DATA_READ; 14543697e599SPeng Fan 14553697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, &data); 14563697e599SPeng Fan if (err) { 14573697e599SPeng Fan if (timeout--) 14583697e599SPeng Fan goto retry_ssr; 14593697e599SPeng Fan 14603697e599SPeng Fan return err; 14613697e599SPeng Fan } 14623697e599SPeng Fan 14633697e599SPeng Fan for (i = 0; i < 16; i++) 14643697e599SPeng Fan ssr[i] = be32_to_cpu(ssr[i]); 14653697e599SPeng Fan 14663697e599SPeng Fan au = (ssr[2] >> 12) & 0xF; 14673697e599SPeng Fan if ((au <= 9) || (mmc->version == SD_VERSION_3)) { 14683697e599SPeng Fan mmc->ssr.au = sd_au_size[au]; 14693697e599SPeng Fan es = (ssr[3] >> 24) & 0xFF; 14703697e599SPeng Fan es |= (ssr[2] & 0xFF) << 8; 14713697e599SPeng Fan et = (ssr[3] >> 18) & 0x3F; 14723697e599SPeng Fan if (es && et) { 14733697e599SPeng Fan eo = (ssr[3] >> 16) & 0x3; 14743697e599SPeng Fan mmc->ssr.erase_timeout = (et * 1000) / es; 14753697e599SPeng Fan mmc->ssr.erase_offset = eo * 1000; 14763697e599SPeng Fan } 14773697e599SPeng Fan } else { 14783697e599SPeng Fan debug("Invalid Allocation Unit Size.\n"); 14793697e599SPeng Fan } 14803697e599SPeng Fan 14813697e599SPeng Fan return 0; 14823697e599SPeng Fan } 14833697e599SPeng Fan 1484272cc70bSAndy Fleming /* frequency bases */ 1485272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */ 14865f837c2cSMike Frysinger static const int fbase[] = { 1487272cc70bSAndy Fleming 10000, 1488272cc70bSAndy Fleming 100000, 1489272cc70bSAndy Fleming 1000000, 1490272cc70bSAndy Fleming 10000000, 1491272cc70bSAndy Fleming }; 1492272cc70bSAndy Fleming 1493272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice 1494272cc70bSAndy Fleming * to platforms without floating point. 1495272cc70bSAndy Fleming */ 149661fe076fSSimon Glass static const u8 multipliers[] = { 1497272cc70bSAndy Fleming 0, /* reserved */ 1498272cc70bSAndy Fleming 10, 1499272cc70bSAndy Fleming 12, 1500272cc70bSAndy Fleming 13, 1501272cc70bSAndy Fleming 15, 1502272cc70bSAndy Fleming 20, 1503272cc70bSAndy Fleming 25, 1504272cc70bSAndy Fleming 30, 1505272cc70bSAndy Fleming 35, 1506272cc70bSAndy Fleming 40, 1507272cc70bSAndy Fleming 45, 1508272cc70bSAndy Fleming 50, 1509272cc70bSAndy Fleming 55, 1510272cc70bSAndy Fleming 60, 1511272cc70bSAndy Fleming 70, 1512272cc70bSAndy Fleming 80, 1513272cc70bSAndy Fleming }; 1514272cc70bSAndy Fleming 1515e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 1516fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc) 1517272cc70bSAndy Fleming { 151893bfd616SPantelis Antoniou if (mmc->cfg->ops->set_ios) 151993bfd616SPantelis Antoniou mmc->cfg->ops->set_ios(mmc); 1520272cc70bSAndy Fleming } 1521ad77484aSZiyuan Xu 1522ad77484aSZiyuan Xu static bool mmc_card_busy(struct mmc *mmc) 1523ad77484aSZiyuan Xu { 1524ad77484aSZiyuan Xu if (!mmc->cfg->ops->card_busy) 1525ad77484aSZiyuan Xu return -ENOSYS; 1526ad77484aSZiyuan Xu 1527ad77484aSZiyuan Xu return mmc->cfg->ops->card_busy(mmc); 1528ad77484aSZiyuan Xu } 1529ad77484aSZiyuan Xu 1530ad77484aSZiyuan Xu static bool mmc_can_card_busy(struct mmc *) 1531ad77484aSZiyuan Xu { 1532ad77484aSZiyuan Xu return !!mmc->cfg->ops->card_busy; 1533ad77484aSZiyuan Xu } 15348ca51e51SSimon Glass #endif 1535272cc70bSAndy Fleming 1536fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc) 1537272cc70bSAndy Fleming { 1538f866a46dSStephen Warren int err, i; 15393e3ff0acSZiyuan Xu uint mult, freq, tran_speed; 1540639b7827SYoshihiro Shimoda u64 cmult, csize, capacity; 1541272cc70bSAndy Fleming struct mmc_cmd cmd; 15428bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 15430c453bb7SDiego Santa Cruz bool has_parts = false; 15448a0cf490SDiego Santa Cruz bool part_completed; 1545c40fdca6SSimon Glass struct blk_desc *bdesc; 1546272cc70bSAndy Fleming 1547d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON 1548d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ 1549d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; 1550d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R1; 1551d52ebf10SThomas Chou cmd.cmdarg = 1; 1552d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 1553d52ebf10SThomas Chou 1554d52ebf10SThomas Chou if (err) 1555d52ebf10SThomas Chou return err; 1556d52ebf10SThomas Chou } 1557d52ebf10SThomas Chou #endif 1558d52ebf10SThomas Chou 1559272cc70bSAndy Fleming /* Put the Card in Identify Mode */ 1560d52ebf10SThomas Chou cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : 1561d52ebf10SThomas Chou MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ 1562272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1563272cc70bSAndy Fleming cmd.cmdarg = 0; 1564272cc70bSAndy Fleming 1565272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1566272cc70bSAndy Fleming 1567272cc70bSAndy Fleming if (err) 1568272cc70bSAndy Fleming return err; 1569272cc70bSAndy Fleming 1570272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16); 1571272cc70bSAndy Fleming 1572272cc70bSAndy Fleming /* 1573272cc70bSAndy Fleming * For MMC cards, set the Relative Address. 1574272cc70bSAndy Fleming * For SD cards, get the Relatvie Address. 1575272cc70bSAndy Fleming * This also puts the cards into Standby State 1576272cc70bSAndy Fleming */ 1577d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1578272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; 1579272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1580272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6; 1581272cc70bSAndy Fleming 1582272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1583272cc70bSAndy Fleming 1584272cc70bSAndy Fleming if (err) 1585272cc70bSAndy Fleming return err; 1586272cc70bSAndy Fleming 1587272cc70bSAndy Fleming if (IS_SD(mmc)) 1588998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff; 1589d52ebf10SThomas Chou } 1590272cc70bSAndy Fleming 1591272cc70bSAndy Fleming /* Get the Card-Specific Data */ 1592272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD; 1593272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1594272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1595272cc70bSAndy Fleming 1596272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1597272cc70bSAndy Fleming 1598272cc70bSAndy Fleming if (err) 1599272cc70bSAndy Fleming return err; 1600272cc70bSAndy Fleming 1601998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0]; 1602998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1]; 1603998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2]; 1604998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3]; 1605272cc70bSAndy Fleming 1606272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) { 16070b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf; 1608272cc70bSAndy Fleming 1609272cc70bSAndy Fleming switch (version) { 1610272cc70bSAndy Fleming case 0: 1611272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1612272cc70bSAndy Fleming break; 1613272cc70bSAndy Fleming case 1: 1614272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4; 1615272cc70bSAndy Fleming break; 1616272cc70bSAndy Fleming case 2: 1617272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2; 1618272cc70bSAndy Fleming break; 1619272cc70bSAndy Fleming case 3: 1620272cc70bSAndy Fleming mmc->version = MMC_VERSION_3; 1621272cc70bSAndy Fleming break; 1622272cc70bSAndy Fleming case 4: 1623272cc70bSAndy Fleming mmc->version = MMC_VERSION_4; 1624272cc70bSAndy Fleming break; 1625272cc70bSAndy Fleming default: 1626272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1627272cc70bSAndy Fleming break; 1628272cc70bSAndy Fleming } 1629272cc70bSAndy Fleming } 1630272cc70bSAndy Fleming 1631272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */ 16320b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)]; 16330b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; 1634272cc70bSAndy Fleming 16353e3ff0acSZiyuan Xu tran_speed = freq * mult; 1636272cc70bSAndy Fleming 1637ab71188cSMarkus Niebel mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); 1638998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); 1639272cc70bSAndy Fleming 1640272cc70bSAndy Fleming if (IS_SD(mmc)) 1641272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len; 1642272cc70bSAndy Fleming else 1643998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); 1644272cc70bSAndy Fleming 1645272cc70bSAndy Fleming if (mmc->high_capacity) { 1646272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16 1647272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16; 1648272cc70bSAndy Fleming cmult = 8; 1649272cc70bSAndy Fleming } else { 1650272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2 1651272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30; 1652272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15; 1653272cc70bSAndy Fleming } 1654272cc70bSAndy Fleming 1655f866a46dSStephen Warren mmc->capacity_user = (csize + 1) << (cmult + 2); 1656f866a46dSStephen Warren mmc->capacity_user *= mmc->read_bl_len; 1657f866a46dSStephen Warren mmc->capacity_boot = 0; 1658f866a46dSStephen Warren mmc->capacity_rpmb = 0; 1659f866a46dSStephen Warren for (i = 0; i < 4; i++) 1660f866a46dSStephen Warren mmc->capacity_gp[i] = 0; 1661272cc70bSAndy Fleming 16628bfa195eSSimon Glass if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN) 16638bfa195eSSimon Glass mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 1664272cc70bSAndy Fleming 16658bfa195eSSimon Glass if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) 16668bfa195eSSimon Glass mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 1667272cc70bSAndy Fleming 1668ab71188cSMarkus Niebel if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) { 1669ab71188cSMarkus Niebel cmd.cmdidx = MMC_CMD_SET_DSR; 1670ab71188cSMarkus Niebel cmd.cmdarg = (mmc->dsr & 0xffff) << 16; 1671ab71188cSMarkus Niebel cmd.resp_type = MMC_RSP_NONE; 1672ab71188cSMarkus Niebel if (mmc_send_cmd(mmc, &cmd, NULL)) 1673ab71188cSMarkus Niebel printf("MMC: SET_DSR failed\n"); 1674ab71188cSMarkus Niebel } 1675ab71188cSMarkus Niebel 1676272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */ 1677d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1678272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD; 1679fe8f7066SAjay Bhargav cmd.resp_type = MMC_RSP_R1; 1680272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1681272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1682272cc70bSAndy Fleming 1683272cc70bSAndy Fleming if (err) 1684272cc70bSAndy Fleming return err; 1685d52ebf10SThomas Chou } 1686272cc70bSAndy Fleming 1687e6f99a56SLei Wen /* 1688e6f99a56SLei Wen * For SD, its erase group is always one sector 1689e6f99a56SLei Wen */ 1690e6f99a56SLei Wen mmc->erase_grp_size = 1; 1691bc897b1dSLei Wen mmc->part_config = MMCPART_NOAVAILABLE; 1692d23e2c09SSukumar Ghorai if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) { 1693d23e2c09SSukumar Ghorai /* check ext_csd version and capacity */ 1694d23e2c09SSukumar Ghorai err = mmc_send_ext_csd(mmc, ext_csd); 16959cf199ebSDiego Santa Cruz if (err) 16969cf199ebSDiego Santa Cruz return err; 16979cf199ebSDiego Santa Cruz if (ext_csd[EXT_CSD_REV] >= 2) { 1698639b7827SYoshihiro Shimoda /* 1699639b7827SYoshihiro Shimoda * According to the JEDEC Standard, the value of 1700639b7827SYoshihiro Shimoda * ext_csd's capacity is valid if the value is more 1701639b7827SYoshihiro Shimoda * than 2GB 1702639b7827SYoshihiro Shimoda */ 17030560db18SLei Wen capacity = ext_csd[EXT_CSD_SEC_CNT] << 0 17040560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 17050560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 17060560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; 17078bfa195eSSimon Glass capacity *= MMC_MAX_BLOCK_LEN; 1708b1f1e821SŁukasz Majewski if ((capacity >> 20) > 2 * 1024) 1709f866a46dSStephen Warren mmc->capacity_user = capacity; 1710d23e2c09SSukumar Ghorai } 1711bc897b1dSLei Wen 171264f4a619SJaehoon Chung switch (ext_csd[EXT_CSD_REV]) { 171364f4a619SJaehoon Chung case 1: 171464f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_1; 171564f4a619SJaehoon Chung break; 171664f4a619SJaehoon Chung case 2: 171764f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_2; 171864f4a619SJaehoon Chung break; 171964f4a619SJaehoon Chung case 3: 172064f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_3; 172164f4a619SJaehoon Chung break; 172264f4a619SJaehoon Chung case 5: 172364f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_41; 172464f4a619SJaehoon Chung break; 172564f4a619SJaehoon Chung case 6: 172664f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_5; 172764f4a619SJaehoon Chung break; 1728edab723bSMarkus Niebel case 7: 1729edab723bSMarkus Niebel mmc->version = MMC_VERSION_5_0; 1730edab723bSMarkus Niebel break; 17311a3619cfSStefan Wahren case 8: 17321a3619cfSStefan Wahren mmc->version = MMC_VERSION_5_1; 17331a3619cfSStefan Wahren break; 173464f4a619SJaehoon Chung } 173564f4a619SJaehoon Chung 17368a0cf490SDiego Santa Cruz /* The partition data may be non-zero but it is only 17378a0cf490SDiego Santa Cruz * effective if PARTITION_SETTING_COMPLETED is set in 17388a0cf490SDiego Santa Cruz * EXT_CSD, so ignore any data if this bit is not set, 17398a0cf490SDiego Santa Cruz * except for enabling the high-capacity group size 17408a0cf490SDiego Santa Cruz * definition (see below). */ 17418a0cf490SDiego Santa Cruz part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] & 17428a0cf490SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 17438a0cf490SDiego Santa Cruz 17440c453bb7SDiego Santa Cruz /* store the partition info of emmc */ 17450c453bb7SDiego Santa Cruz mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT]; 17460c453bb7SDiego Santa Cruz if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || 17470c453bb7SDiego Santa Cruz ext_csd[EXT_CSD_BOOT_MULT]) 17480c453bb7SDiego Santa Cruz mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; 17498a0cf490SDiego Santa Cruz if (part_completed && 17508a0cf490SDiego Santa Cruz (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT)) 17510c453bb7SDiego Santa Cruz mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]; 1752a6a1f5f8SJason Zhu if (ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] & EXT_CSD_SEC_GB_CL_EN) 1753a6a1f5f8SJason Zhu mmc->esr.mmc_can_trim = 1; 17540c453bb7SDiego Santa Cruz 17550c453bb7SDiego Santa Cruz mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17; 17560c453bb7SDiego Santa Cruz 17570c453bb7SDiego Santa Cruz mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17; 17580c453bb7SDiego Santa Cruz 17590c453bb7SDiego Santa Cruz for (i = 0; i < 4; i++) { 17600c453bb7SDiego Santa Cruz int idx = EXT_CSD_GP_SIZE_MULT + i * 3; 17618a0cf490SDiego Santa Cruz uint mult = (ext_csd[idx + 2] << 16) + 17620c453bb7SDiego Santa Cruz (ext_csd[idx + 1] << 8) + ext_csd[idx]; 17638a0cf490SDiego Santa Cruz if (mult) 17648a0cf490SDiego Santa Cruz has_parts = true; 17658a0cf490SDiego Santa Cruz if (!part_completed) 17668a0cf490SDiego Santa Cruz continue; 17678a0cf490SDiego Santa Cruz mmc->capacity_gp[i] = mult; 17680c453bb7SDiego Santa Cruz mmc->capacity_gp[i] *= 17690c453bb7SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 17700c453bb7SDiego Santa Cruz mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1771f8e89d67SDiego Santa Cruz mmc->capacity_gp[i] <<= 19; 17720c453bb7SDiego Santa Cruz } 17730c453bb7SDiego Santa Cruz 17748a0cf490SDiego Santa Cruz if (part_completed) { 1775a7f852b6SDiego Santa Cruz mmc->enh_user_size = 1776a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_SIZE_MULT+2] << 16) + 1777a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_SIZE_MULT+1] << 8) + 1778a7f852b6SDiego Santa Cruz ext_csd[EXT_CSD_ENH_SIZE_MULT]; 1779a7f852b6SDiego Santa Cruz mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1780a7f852b6SDiego Santa Cruz mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1781a7f852b6SDiego Santa Cruz mmc->enh_user_size <<= 19; 1782a7f852b6SDiego Santa Cruz mmc->enh_user_start = 1783a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_START_ADDR+3] << 24) + 1784a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_START_ADDR+2] << 16) + 1785a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_START_ADDR+1] << 8) + 1786a7f852b6SDiego Santa Cruz ext_csd[EXT_CSD_ENH_START_ADDR]; 1787a7f852b6SDiego Santa Cruz if (mmc->high_capacity) 1788a7f852b6SDiego Santa Cruz mmc->enh_user_start <<= 9; 17898a0cf490SDiego Santa Cruz } 1790a7f852b6SDiego Santa Cruz 1791e6f99a56SLei Wen /* 17921937e5aaSOliver Metz * Host needs to enable ERASE_GRP_DEF bit if device is 17931937e5aaSOliver Metz * partitioned. This bit will be lost every time after a reset 17941937e5aaSOliver Metz * or power off. This will affect erase size. 1795e6f99a56SLei Wen */ 17968a0cf490SDiego Santa Cruz if (part_completed) 17970c453bb7SDiego Santa Cruz has_parts = true; 17981937e5aaSOliver Metz if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) && 17990c453bb7SDiego Santa Cruz (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) 18000c453bb7SDiego Santa Cruz has_parts = true; 18010c453bb7SDiego Santa Cruz if (has_parts) { 18021937e5aaSOliver Metz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 18031937e5aaSOliver Metz EXT_CSD_ERASE_GROUP_DEF, 1); 18041937e5aaSOliver Metz 18051937e5aaSOliver Metz if (err) 18061937e5aaSOliver Metz return err; 1807021a8055SHannes Petermaier else 1808021a8055SHannes Petermaier ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 1809037dc0abSDiego Santa Cruz } 18101937e5aaSOliver Metz 1811037dc0abSDiego Santa Cruz if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) { 18121937e5aaSOliver Metz /* Read out group size from ext_csd */ 18130560db18SLei Wen mmc->erase_grp_size = 1814a4ff9f83SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 1815d7b29129SMarkus Niebel /* 1816d7b29129SMarkus Niebel * if high capacity and partition setting completed 1817d7b29129SMarkus Niebel * SEC_COUNT is valid even if it is smaller than 2 GiB 1818d7b29129SMarkus Niebel * JEDEC Standard JESD84-B45, 6.2.4 1819d7b29129SMarkus Niebel */ 18208a0cf490SDiego Santa Cruz if (mmc->high_capacity && part_completed) { 1821d7b29129SMarkus Niebel capacity = (ext_csd[EXT_CSD_SEC_CNT]) | 1822d7b29129SMarkus Niebel (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) | 1823d7b29129SMarkus Niebel (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) | 1824d7b29129SMarkus Niebel (ext_csd[EXT_CSD_SEC_CNT + 3] << 24); 1825d7b29129SMarkus Niebel capacity *= MMC_MAX_BLOCK_LEN; 1826d7b29129SMarkus Niebel mmc->capacity_user = capacity; 1827d7b29129SMarkus Niebel } 18288bfa195eSSimon Glass } else { 18291937e5aaSOliver Metz /* Calculate the group size from the csd value. */ 1830e6f99a56SLei Wen int erase_gsz, erase_gmul; 1831e6f99a56SLei Wen erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; 1832e6f99a56SLei Wen erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; 1833e6f99a56SLei Wen mmc->erase_grp_size = (erase_gsz + 1) 1834e6f99a56SLei Wen * (erase_gmul + 1); 1835e6f99a56SLei Wen } 1836037dc0abSDiego Santa Cruz 1837037dc0abSDiego Santa Cruz mmc->hc_wp_grp_size = 1024 1838037dc0abSDiego Santa Cruz * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 1839037dc0abSDiego Santa Cruz * ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 18409e41a00bSDiego Santa Cruz 18419e41a00bSDiego Santa Cruz mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 1842f866a46dSStephen Warren } 1843f866a46dSStephen Warren 1844c40fdca6SSimon Glass err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart); 1845f866a46dSStephen Warren if (err) 1846f866a46dSStephen Warren return err; 1847d23e2c09SSukumar Ghorai 1848272cc70bSAndy Fleming if (IS_SD(mmc)) 1849272cc70bSAndy Fleming err = sd_change_freq(mmc); 1850272cc70bSAndy Fleming else 1851272cc70bSAndy Fleming err = mmc_change_freq(mmc); 1852272cc70bSAndy Fleming 1853272cc70bSAndy Fleming if (err) 1854272cc70bSAndy Fleming return err; 1855272cc70bSAndy Fleming 1856272cc70bSAndy Fleming /* Restrict card's capabilities by what the host can do */ 185793bfd616SPantelis Antoniou mmc->card_caps &= mmc->cfg->host_caps; 1858272cc70bSAndy Fleming 1859272cc70bSAndy Fleming if (IS_SD(mmc)) { 1860272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_4BIT) { 1861272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 1862272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1863272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1864272cc70bSAndy Fleming 1865272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1866272cc70bSAndy Fleming if (err) 1867272cc70bSAndy Fleming return err; 1868272cc70bSAndy Fleming 1869272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; 1870272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1871272cc70bSAndy Fleming cmd.cmdarg = 2; 1872272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1873272cc70bSAndy Fleming if (err) 1874272cc70bSAndy Fleming return err; 1875272cc70bSAndy Fleming 1876272cc70bSAndy Fleming mmc_set_bus_width(mmc, 4); 1877272cc70bSAndy Fleming } 1878272cc70bSAndy Fleming 18793697e599SPeng Fan err = sd_read_ssr(mmc); 18803697e599SPeng Fan if (err) 18813697e599SPeng Fan return err; 18823697e599SPeng Fan 1883272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS) 18843e3ff0acSZiyuan Xu tran_speed = 50000000; 1885272cc70bSAndy Fleming else 18863e3ff0acSZiyuan Xu tran_speed = 25000000; 1887ad5fd922SJaehoon Chung 18883e3ff0acSZiyuan Xu mmc_set_clock(mmc, tran_speed); 188949dba033SZiyuan Xu } 1890272cc70bSAndy Fleming 18915af8f45cSAndrew Gabbasov /* Fix the block length for DDR mode */ 189249dba033SZiyuan Xu if (mmc_card_ddr(mmc)) { 18935af8f45cSAndrew Gabbasov mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 18945af8f45cSAndrew Gabbasov mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 18955af8f45cSAndrew Gabbasov } 18965af8f45cSAndrew Gabbasov 1897272cc70bSAndy Fleming /* fill in device description */ 1898c40fdca6SSimon Glass bdesc = mmc_get_blk_desc(mmc); 1899c40fdca6SSimon Glass bdesc->lun = 0; 1900c40fdca6SSimon Glass bdesc->hwpart = 0; 1901c40fdca6SSimon Glass bdesc->type = 0; 1902c40fdca6SSimon Glass bdesc->blksz = mmc->read_bl_len; 1903c40fdca6SSimon Glass bdesc->log2blksz = LOG2(bdesc->blksz); 1904c40fdca6SSimon Glass bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len); 1905fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \ 1906fc011f64SSjoerd Simons (defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \ 1907fc011f64SSjoerd Simons !defined(CONFIG_USE_TINY_PRINTF)) 1908c40fdca6SSimon Glass sprintf(bdesc->vendor, "Man %06x Snr %04x%04x", 1909babce5f6STaylor Hutt mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), 1910babce5f6STaylor Hutt (mmc->cid[3] >> 16) & 0xffff); 1911c40fdca6SSimon Glass sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff, 19120b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 1913babce5f6STaylor Hutt (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff, 1914babce5f6STaylor Hutt (mmc->cid[2] >> 24) & 0xff); 1915c40fdca6SSimon Glass sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf, 1916babce5f6STaylor Hutt (mmc->cid[2] >> 16) & 0xf); 191756196826SPaul Burton #else 1918c40fdca6SSimon Glass bdesc->vendor[0] = 0; 1919c40fdca6SSimon Glass bdesc->product[0] = 0; 1920c40fdca6SSimon Glass bdesc->revision[0] = 0; 192156196826SPaul Burton #endif 1922122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT) 1923c40fdca6SSimon Glass part_init(bdesc); 1924122efd43SMikhail Kshevetskiy #endif 1925272cc70bSAndy Fleming 1926272cc70bSAndy Fleming return 0; 1927272cc70bSAndy Fleming } 1928272cc70bSAndy Fleming 1929fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc) 1930272cc70bSAndy Fleming { 1931272cc70bSAndy Fleming struct mmc_cmd cmd; 1932272cc70bSAndy Fleming int err; 1933272cc70bSAndy Fleming 1934272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND; 1935272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ 193693bfd616SPantelis Antoniou cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa; 1937272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7; 1938272cc70bSAndy Fleming 1939272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1940272cc70bSAndy Fleming 1941272cc70bSAndy Fleming if (err) 1942272cc70bSAndy Fleming return err; 1943272cc70bSAndy Fleming 1944998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa) 1945915ffa52SJaehoon Chung return -EOPNOTSUPP; 1946272cc70bSAndy Fleming else 1947272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 1948272cc70bSAndy Fleming 1949272cc70bSAndy Fleming return 0; 1950272cc70bSAndy Fleming } 1951272cc70bSAndy Fleming 1952c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 195395de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */ 195495de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void) 195595de9ab2SPaul Kocialkowski { 195695de9ab2SPaul Kocialkowski } 195705cbeb7cSSimon Glass #endif 195895de9ab2SPaul Kocialkowski 19592051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc) 19602051aefeSPeng Fan { 1961c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 196205cbeb7cSSimon Glass #if defined(CONFIG_DM_REGULATOR) && !defined(CONFIG_SPL_BUILD) 19632051aefeSPeng Fan struct udevice *vmmc_supply; 19642051aefeSPeng Fan int ret; 19652051aefeSPeng Fan 19662051aefeSPeng Fan ret = device_get_supply_regulator(mmc->dev, "vmmc-supply", 19672051aefeSPeng Fan &vmmc_supply); 19682051aefeSPeng Fan if (ret) { 1969288db7c7SJaehoon Chung debug("%s: No vmmc supply\n", mmc->dev->name); 19702051aefeSPeng Fan return 0; 19712051aefeSPeng Fan } 19722051aefeSPeng Fan 19732051aefeSPeng Fan ret = regulator_set_enable(vmmc_supply, true); 19742051aefeSPeng Fan if (ret) { 19752051aefeSPeng Fan puts("Error enabling VMMC supply\n"); 19762051aefeSPeng Fan return ret; 19772051aefeSPeng Fan } 19782051aefeSPeng Fan #endif 197905cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */ 198005cbeb7cSSimon Glass /* 198105cbeb7cSSimon Glass * Driver model should use a regulator, as above, rather than calling 198205cbeb7cSSimon Glass * out to board code. 198305cbeb7cSSimon Glass */ 198405cbeb7cSSimon Glass board_mmc_power_init(); 198505cbeb7cSSimon Glass #endif 19862051aefeSPeng Fan return 0; 19872051aefeSPeng Fan } 19882051aefeSPeng Fan 1989e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc) 1990272cc70bSAndy Fleming { 19918ca51e51SSimon Glass bool no_card; 1992afd5932bSMacpaul Lin int err; 1993272cc70bSAndy Fleming 1994ab769f22SPantelis Antoniou /* we pretend there's no card when init is NULL */ 19958ca51e51SSimon Glass no_card = mmc_getcd(mmc) == 0; 1996e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 19978ca51e51SSimon Glass no_card = no_card || (mmc->cfg->ops->init == NULL); 19988ca51e51SSimon Glass #endif 19998ca51e51SSimon Glass if (no_card) { 200048972d90SThierry Reding mmc->has_init = 0; 200156196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 200248972d90SThierry Reding printf("MMC: no card present\n"); 200356196826SPaul Burton #endif 2004915ffa52SJaehoon Chung return -ENOMEDIUM; 200548972d90SThierry Reding } 200648972d90SThierry Reding 2007bc897b1dSLei Wen if (mmc->has_init) 2008bc897b1dSLei Wen return 0; 2009bc897b1dSLei Wen 20105a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 20115a8dbdc6SYangbo Lu mmc_adapter_card_type_ident(); 20125a8dbdc6SYangbo Lu #endif 20132051aefeSPeng Fan err = mmc_power_init(mmc); 20142051aefeSPeng Fan if (err) 20152051aefeSPeng Fan return err; 201695de9ab2SPaul Kocialkowski 2017e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 20188ca51e51SSimon Glass /* The device has already been probed ready for use */ 20198ca51e51SSimon Glass #else 2020ab769f22SPantelis Antoniou /* made sure it's not NULL earlier */ 202193bfd616SPantelis Antoniou err = mmc->cfg->ops->init(mmc); 2022272cc70bSAndy Fleming if (err) 2023272cc70bSAndy Fleming return err; 20248ca51e51SSimon Glass #endif 2025b86b85e2SIlya Yanok mmc_set_bus_width(mmc, 1); 2026b86b85e2SIlya Yanok mmc_set_clock(mmc, 1); 202781db2d36SZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_LEGACY); 2028b86b85e2SIlya Yanok 2029272cc70bSAndy Fleming /* Reset the Card */ 2030272cc70bSAndy Fleming err = mmc_go_idle(mmc); 2031272cc70bSAndy Fleming 2032272cc70bSAndy Fleming if (err) 2033272cc70bSAndy Fleming return err; 2034272cc70bSAndy Fleming 2035bc897b1dSLei Wen /* The internal partition reset to user partition(0) at every CMD0*/ 2036c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->hwpart = 0; 2037bc897b1dSLei Wen 2038272cc70bSAndy Fleming /* Test for SD version 2 */ 2039272cc70bSAndy Fleming err = mmc_send_if_cond(mmc); 2040272cc70bSAndy Fleming 2041272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */ 2042272cc70bSAndy Fleming err = sd_send_op_cond(mmc); 2043272cc70bSAndy Fleming 2044272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */ 2045915ffa52SJaehoon Chung if (err == -ETIMEDOUT) { 2046272cc70bSAndy Fleming err = mmc_send_op_cond(mmc); 2047272cc70bSAndy Fleming 2048bd47c135SAndrew Gabbasov if (err) { 204956196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2050272cc70bSAndy Fleming printf("Card did not respond to voltage select!\n"); 205156196826SPaul Burton #endif 2052915ffa52SJaehoon Chung return -EOPNOTSUPP; 2053272cc70bSAndy Fleming } 2054272cc70bSAndy Fleming } 2055272cc70bSAndy Fleming 2056bd47c135SAndrew Gabbasov if (!err) 2057e9550449SChe-Liang Chiou mmc->init_in_progress = 1; 2058e9550449SChe-Liang Chiou 2059e9550449SChe-Liang Chiou return err; 2060e9550449SChe-Liang Chiou } 2061e9550449SChe-Liang Chiou 2062e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc) 2063e9550449SChe-Liang Chiou { 2064e9550449SChe-Liang Chiou int err = 0; 2065e9550449SChe-Liang Chiou 2066bd47c135SAndrew Gabbasov mmc->init_in_progress = 0; 2067e9550449SChe-Liang Chiou if (mmc->op_cond_pending) 2068e9550449SChe-Liang Chiou err = mmc_complete_op_cond(mmc); 2069e9550449SChe-Liang Chiou 2070e9550449SChe-Liang Chiou if (!err) 2071bc897b1dSLei Wen err = mmc_startup(mmc); 2072bc897b1dSLei Wen if (err) 2073bc897b1dSLei Wen mmc->has_init = 0; 2074bc897b1dSLei Wen else 2075bc897b1dSLei Wen mmc->has_init = 1; 2076e9550449SChe-Liang Chiou return err; 2077e9550449SChe-Liang Chiou } 2078e9550449SChe-Liang Chiou 2079e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc) 2080e9550449SChe-Liang Chiou { 2081bd47c135SAndrew Gabbasov int err = 0; 2082ce9eca94SMarek Vasut __maybe_unused unsigned start; 2083c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 208433fb211dSSimon Glass struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev); 2085e9550449SChe-Liang Chiou 208633fb211dSSimon Glass upriv->mmc = mmc; 208733fb211dSSimon Glass #endif 2088e9550449SChe-Liang Chiou if (mmc->has_init) 2089e9550449SChe-Liang Chiou return 0; 2090d803fea5SMateusz Zalega 2091d803fea5SMateusz Zalega start = get_timer(0); 2092d803fea5SMateusz Zalega 2093e9550449SChe-Liang Chiou if (!mmc->init_in_progress) 2094e9550449SChe-Liang Chiou err = mmc_start_init(mmc); 2095e9550449SChe-Liang Chiou 2096bd47c135SAndrew Gabbasov if (!err) 2097e9550449SChe-Liang Chiou err = mmc_complete_init(mmc); 2098919b4858SJagan Teki if (err) 2099919b4858SJagan Teki printf("%s: %d, time %lu\n", __func__, err, get_timer(start)); 2100919b4858SJagan Teki 2101bc897b1dSLei Wen return err; 2102272cc70bSAndy Fleming } 2103272cc70bSAndy Fleming 2104ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val) 2105ab71188cSMarkus Niebel { 2106ab71188cSMarkus Niebel mmc->dsr = val; 2107ab71188cSMarkus Niebel return 0; 2108ab71188cSMarkus Niebel } 2109ab71188cSMarkus Niebel 2110cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */ 2111cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis) 2112272cc70bSAndy Fleming { 2113272cc70bSAndy Fleming return -1; 2114272cc70bSAndy Fleming } 2115272cc70bSAndy Fleming 2116cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */ 2117cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis) 2118cee9ab7cSJeroen Hofstee { 2119cee9ab7cSJeroen Hofstee return -1; 2120cee9ab7cSJeroen Hofstee } 2121272cc70bSAndy Fleming 2122e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit) 2123e9550449SChe-Liang Chiou { 2124e9550449SChe-Liang Chiou mmc->preinit = preinit; 2125e9550449SChe-Liang Chiou } 2126e9550449SChe-Liang Chiou 2127c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD) 21288e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 21298e3332e2SSjoerd Simons { 21308e3332e2SSjoerd Simons return 0; 21318e3332e2SSjoerd Simons } 2132c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC) 21338e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 21348e3332e2SSjoerd Simons { 21354a1db6d8SSimon Glass int ret, i; 21368e3332e2SSjoerd Simons struct uclass *uc; 21374a1db6d8SSimon Glass struct udevice *dev; 21388e3332e2SSjoerd Simons 21398e3332e2SSjoerd Simons ret = uclass_get(UCLASS_MMC, &uc); 21408e3332e2SSjoerd Simons if (ret) 21418e3332e2SSjoerd Simons return ret; 21428e3332e2SSjoerd Simons 21434a1db6d8SSimon Glass /* 21444a1db6d8SSimon Glass * Try to add them in sequence order. Really with driver model we 21454a1db6d8SSimon Glass * should allow holes, but the current MMC list does not allow that. 21464a1db6d8SSimon Glass * So if we request 0, 1, 3 we will get 0, 1, 2. 21474a1db6d8SSimon Glass */ 21484a1db6d8SSimon Glass for (i = 0; ; i++) { 21494a1db6d8SSimon Glass ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev); 21504a1db6d8SSimon Glass if (ret == -ENODEV) 21514a1db6d8SSimon Glass break; 21524a1db6d8SSimon Glass } 21534a1db6d8SSimon Glass uclass_foreach_dev(dev, uc) { 21544a1db6d8SSimon Glass ret = device_probe(dev); 21558e3332e2SSjoerd Simons if (ret) 21564a1db6d8SSimon Glass printf("%s - probe failed: %d\n", dev->name, ret); 21578e3332e2SSjoerd Simons } 21588e3332e2SSjoerd Simons 21598e3332e2SSjoerd Simons return 0; 21608e3332e2SSjoerd Simons } 21618e3332e2SSjoerd Simons #else 21628e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 21638e3332e2SSjoerd Simons { 21648e3332e2SSjoerd Simons if (board_mmc_init(bis) < 0) 21658e3332e2SSjoerd Simons cpu_mmc_init(bis); 21668e3332e2SSjoerd Simons 21678e3332e2SSjoerd Simons return 0; 21688e3332e2SSjoerd Simons } 21698e3332e2SSjoerd Simons #endif 2170e9550449SChe-Liang Chiou 2171272cc70bSAndy Fleming int mmc_initialize(bd_t *bis) 2172272cc70bSAndy Fleming { 21731b26bab1SDaniel Kochmański static int initialized = 0; 21748e3332e2SSjoerd Simons int ret; 21751b26bab1SDaniel Kochmański if (initialized) /* Avoid initializing mmc multiple times */ 21761b26bab1SDaniel Kochmański return 0; 21771b26bab1SDaniel Kochmański initialized = 1; 21781b26bab1SDaniel Kochmański 2179c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK) 2180b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY) 2181c40fdca6SSimon Glass mmc_list_init(); 2182c40fdca6SSimon Glass #endif 2183b5b838f1SMarek Vasut #endif 21848e3332e2SSjoerd Simons ret = mmc_probe(bis); 21858e3332e2SSjoerd Simons if (ret) 21868e3332e2SSjoerd Simons return ret; 2187272cc70bSAndy Fleming 2188bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD 2189272cc70bSAndy Fleming print_mmc_devices(','); 2190bb0dc108SYing Zhang #endif 2191272cc70bSAndy Fleming 2192c40fdca6SSimon Glass mmc_do_preinit(); 2193272cc70bSAndy Fleming return 0; 2194272cc70bSAndy Fleming } 2195cd3d4880STomas Melin 2196cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE 2197cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc) 2198cd3d4880STomas Melin { 2199cd3d4880STomas Melin int err; 2200cd3d4880STomas Melin ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 2201cd3d4880STomas Melin 2202cd3d4880STomas Melin err = mmc_send_ext_csd(mmc, ext_csd); 2203cd3d4880STomas Melin if (err) { 2204cd3d4880STomas Melin puts("Could not get ext_csd register values\n"); 2205cd3d4880STomas Melin return err; 2206cd3d4880STomas Melin } 2207cd3d4880STomas Melin 2208cd3d4880STomas Melin if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) { 2209cd3d4880STomas Melin puts("Background operations not supported on device\n"); 2210cd3d4880STomas Melin return -EMEDIUMTYPE; 2211cd3d4880STomas Melin } 2212cd3d4880STomas Melin 2213cd3d4880STomas Melin if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) { 2214cd3d4880STomas Melin puts("Background operations already enabled\n"); 2215cd3d4880STomas Melin return 0; 2216cd3d4880STomas Melin } 2217cd3d4880STomas Melin 2218cd3d4880STomas Melin err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1); 2219cd3d4880STomas Melin if (err) { 2220cd3d4880STomas Melin puts("Failed to enable manual background operations\n"); 2221cd3d4880STomas Melin return err; 2222cd3d4880STomas Melin } 2223cd3d4880STomas Melin 2224cd3d4880STomas Melin puts("Enabled manual background operations\n"); 2225cd3d4880STomas Melin 2226cd3d4880STomas Melin return 0; 2227cd3d4880STomas Melin } 2228cd3d4880STomas Melin #endif 2229