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 213*caa21a21SZiyuan 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__); 3114a1a06bcSAlagu Sankar return 0; 31211692991SSimon Glass } 3134a1a06bcSAlagu Sankar blocks_todo -= cur; 3144a1a06bcSAlagu Sankar start += cur; 3154a1a06bcSAlagu Sankar dst += cur * mmc->read_bl_len; 3164a1a06bcSAlagu Sankar } while (blocks_todo > 0); 317272cc70bSAndy Fleming 318272cc70bSAndy Fleming return blkcnt; 319272cc70bSAndy Fleming } 320272cc70bSAndy Fleming 32149dba033SZiyuan Xu void mmc_set_clock(struct mmc *mmc, uint clock) 32249dba033SZiyuan Xu { 32349dba033SZiyuan Xu if (clock > mmc->cfg->f_max) 32449dba033SZiyuan Xu clock = mmc->cfg->f_max; 32549dba033SZiyuan Xu 32649dba033SZiyuan Xu if (clock < mmc->cfg->f_min) 32749dba033SZiyuan Xu clock = mmc->cfg->f_min; 32849dba033SZiyuan Xu 32949dba033SZiyuan Xu mmc->clock = clock; 33049dba033SZiyuan Xu 33149dba033SZiyuan Xu mmc_set_ios(mmc); 33249dba033SZiyuan Xu } 33349dba033SZiyuan Xu 33449dba033SZiyuan Xu static void mmc_set_bus_width(struct mmc *mmc, uint width) 33549dba033SZiyuan Xu { 33649dba033SZiyuan Xu mmc->bus_width = width; 33749dba033SZiyuan Xu 33849dba033SZiyuan Xu mmc_set_ios(mmc); 33949dba033SZiyuan Xu } 34049dba033SZiyuan Xu 34181db2d36SZiyuan Xu static void mmc_set_timing(struct mmc *mmc, uint timing) 34281db2d36SZiyuan Xu { 34381db2d36SZiyuan Xu mmc->timing = timing; 34481db2d36SZiyuan Xu mmc_set_ios(mmc); 34581db2d36SZiyuan Xu } 34681db2d36SZiyuan Xu 347fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc) 348272cc70bSAndy Fleming { 349272cc70bSAndy Fleming struct mmc_cmd cmd; 350272cc70bSAndy Fleming int err; 351272cc70bSAndy Fleming 352272cc70bSAndy Fleming udelay(1000); 353272cc70bSAndy Fleming 354272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_GO_IDLE_STATE; 355272cc70bSAndy Fleming cmd.cmdarg = 0; 356272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_NONE; 357272cc70bSAndy Fleming 358272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 359272cc70bSAndy Fleming 360272cc70bSAndy Fleming if (err) 361272cc70bSAndy Fleming return err; 362272cc70bSAndy Fleming 363272cc70bSAndy Fleming udelay(2000); 364272cc70bSAndy Fleming 365272cc70bSAndy Fleming return 0; 366272cc70bSAndy Fleming } 367272cc70bSAndy Fleming 368fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc) 369272cc70bSAndy Fleming { 370272cc70bSAndy Fleming int timeout = 1000; 371272cc70bSAndy Fleming int err; 372272cc70bSAndy Fleming struct mmc_cmd cmd; 373272cc70bSAndy Fleming 3741677eef4SAndrew Gabbasov while (1) { 375272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 376272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 377272cc70bSAndy Fleming cmd.cmdarg = 0; 378272cc70bSAndy Fleming 379272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 380272cc70bSAndy Fleming 381272cc70bSAndy Fleming if (err) 382272cc70bSAndy Fleming return err; 383272cc70bSAndy Fleming 384272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_OP_COND; 385272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R3; 386250de12bSStefano Babic 387250de12bSStefano Babic /* 388250de12bSStefano Babic * Most cards do not answer if some reserved bits 389250de12bSStefano Babic * in the ocr are set. However, Some controller 390250de12bSStefano Babic * can set bit 7 (reserved for low voltages), but 391250de12bSStefano Babic * how to manage low voltages SD card is not yet 392250de12bSStefano Babic * specified. 393250de12bSStefano Babic */ 394d52ebf10SThomas Chou cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 : 39593bfd616SPantelis Antoniou (mmc->cfg->voltages & 0xff8000); 396272cc70bSAndy Fleming 397272cc70bSAndy Fleming if (mmc->version == SD_VERSION_2) 398272cc70bSAndy Fleming cmd.cmdarg |= OCR_HCS; 399272cc70bSAndy Fleming 400272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 401272cc70bSAndy Fleming 402272cc70bSAndy Fleming if (err) 403272cc70bSAndy Fleming return err; 404272cc70bSAndy Fleming 4051677eef4SAndrew Gabbasov if (cmd.response[0] & OCR_BUSY) 4061677eef4SAndrew Gabbasov break; 407272cc70bSAndy Fleming 4081677eef4SAndrew Gabbasov if (timeout-- <= 0) 409915ffa52SJaehoon Chung return -EOPNOTSUPP; 410272cc70bSAndy Fleming 4111677eef4SAndrew Gabbasov udelay(1000); 4121677eef4SAndrew Gabbasov } 4131677eef4SAndrew Gabbasov 414272cc70bSAndy Fleming if (mmc->version != SD_VERSION_2) 415272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 416272cc70bSAndy Fleming 417d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 418d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 419d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 420d52ebf10SThomas Chou cmd.cmdarg = 0; 421d52ebf10SThomas Chou 422d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 423d52ebf10SThomas Chou 424d52ebf10SThomas Chou if (err) 425d52ebf10SThomas Chou return err; 426d52ebf10SThomas Chou } 427d52ebf10SThomas Chou 428998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 429272cc70bSAndy Fleming 430272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 431272cc70bSAndy Fleming mmc->rca = 0; 432272cc70bSAndy Fleming 433272cc70bSAndy Fleming return 0; 434272cc70bSAndy Fleming } 435272cc70bSAndy Fleming 4365289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg) 437272cc70bSAndy Fleming { 4385289b535SAndrew Gabbasov struct mmc_cmd cmd; 439272cc70bSAndy Fleming int err; 440272cc70bSAndy Fleming 4415289b535SAndrew Gabbasov cmd.cmdidx = MMC_CMD_SEND_OP_COND; 4425289b535SAndrew Gabbasov cmd.resp_type = MMC_RSP_R3; 4435289b535SAndrew Gabbasov cmd.cmdarg = 0; 4445a20397bSRob Herring if (use_arg && !mmc_host_is_spi(mmc)) 4455a20397bSRob Herring cmd.cmdarg = OCR_HCS | 44693bfd616SPantelis Antoniou (mmc->cfg->voltages & 447a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_VOLTAGE_MASK)) | 448a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_ACCESS_MODE); 449e9550449SChe-Liang Chiou 4505289b535SAndrew Gabbasov err = mmc_send_cmd(mmc, &cmd, NULL); 451e9550449SChe-Liang Chiou if (err) 452e9550449SChe-Liang Chiou return err; 4535289b535SAndrew Gabbasov mmc->ocr = cmd.response[0]; 454e9550449SChe-Liang Chiou return 0; 455e9550449SChe-Liang Chiou } 456e9550449SChe-Liang Chiou 457750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc) 458e9550449SChe-Liang Chiou { 459e9550449SChe-Liang Chiou int err, i; 460e9550449SChe-Liang Chiou 461272cc70bSAndy Fleming /* Some cards seem to need this */ 462272cc70bSAndy Fleming mmc_go_idle(mmc); 463272cc70bSAndy Fleming 46431cacbabSRaffaele Recalcati /* Asking to the card its capabilities */ 465e9550449SChe-Liang Chiou for (i = 0; i < 2; i++) { 4665289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, i != 0); 46731cacbabSRaffaele Recalcati if (err) 46831cacbabSRaffaele Recalcati return err; 46931cacbabSRaffaele Recalcati 470e9550449SChe-Liang Chiou /* exit if not busy (flag seems to be inverted) */ 471a626c8d4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 472bd47c135SAndrew Gabbasov break; 473e9550449SChe-Liang Chiou } 474bd47c135SAndrew Gabbasov mmc->op_cond_pending = 1; 475bd47c135SAndrew Gabbasov return 0; 476e9550449SChe-Liang Chiou } 47731cacbabSRaffaele Recalcati 478750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc) 479e9550449SChe-Liang Chiou { 480e9550449SChe-Liang Chiou struct mmc_cmd cmd; 481e9550449SChe-Liang Chiou int timeout = 1000; 482e9550449SChe-Liang Chiou uint start; 483e9550449SChe-Liang Chiou int err; 484e9550449SChe-Liang Chiou 485e9550449SChe-Liang Chiou mmc->op_cond_pending = 0; 486cc17c01fSAndrew Gabbasov if (!(mmc->ocr & OCR_BUSY)) { 487d188b113SYangbo Lu /* Some cards seem to need this */ 488d188b113SYangbo Lu mmc_go_idle(mmc); 489d188b113SYangbo Lu 490e9550449SChe-Liang Chiou start = get_timer(0); 4911677eef4SAndrew Gabbasov while (1) { 4925289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, 1); 493272cc70bSAndy Fleming if (err) 494272cc70bSAndy Fleming return err; 4951677eef4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 4961677eef4SAndrew Gabbasov break; 497e9550449SChe-Liang Chiou if (get_timer(start) > timeout) 498915ffa52SJaehoon Chung return -EOPNOTSUPP; 499e9550449SChe-Liang Chiou udelay(100); 5001677eef4SAndrew Gabbasov } 501cc17c01fSAndrew Gabbasov } 502272cc70bSAndy Fleming 503d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 504d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 505d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 506d52ebf10SThomas Chou cmd.cmdarg = 0; 507d52ebf10SThomas Chou 508d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 509d52ebf10SThomas Chou 510d52ebf10SThomas Chou if (err) 511d52ebf10SThomas Chou return err; 512a626c8d4SAndrew Gabbasov 513a626c8d4SAndrew Gabbasov mmc->ocr = cmd.response[0]; 514d52ebf10SThomas Chou } 515d52ebf10SThomas Chou 516272cc70bSAndy Fleming mmc->version = MMC_VERSION_UNKNOWN; 517272cc70bSAndy Fleming 518272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 519def816a2SStephen Warren mmc->rca = 1; 520272cc70bSAndy Fleming 521272cc70bSAndy Fleming return 0; 522272cc70bSAndy Fleming } 523272cc70bSAndy Fleming 524272cc70bSAndy Fleming 525fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) 526272cc70bSAndy Fleming { 527272cc70bSAndy Fleming struct mmc_cmd cmd; 528272cc70bSAndy Fleming struct mmc_data data; 529272cc70bSAndy Fleming int err; 530272cc70bSAndy Fleming 531272cc70bSAndy Fleming /* Get the Card Status Register */ 532272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_EXT_CSD; 533272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 534272cc70bSAndy Fleming cmd.cmdarg = 0; 535272cc70bSAndy Fleming 536cdfd1ac6SYoshihiro Shimoda data.dest = (char *)ext_csd; 537272cc70bSAndy Fleming data.blocks = 1; 5388bfa195eSSimon Glass data.blocksize = MMC_MAX_BLOCK_LEN; 539272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 540272cc70bSAndy Fleming 541272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 542272cc70bSAndy Fleming 543272cc70bSAndy Fleming return err; 544272cc70bSAndy Fleming } 545272cc70bSAndy Fleming 54655e5defdSZiyuan Xu static int mmc_poll_for_busy(struct mmc *mmc) 547272cc70bSAndy Fleming { 548272cc70bSAndy Fleming struct mmc_cmd cmd; 54955e5defdSZiyuan Xu u8 busy = true; 55055e5defdSZiyuan Xu uint start; 55155e5defdSZiyuan Xu int ret; 5525d4fc8d9SRaffaele Recalcati int timeout = 1000; 55355e5defdSZiyuan Xu 55455e5defdSZiyuan Xu cmd.cmdidx = MMC_CMD_SEND_STATUS; 55555e5defdSZiyuan Xu cmd.resp_type = MMC_RSP_R1; 55655e5defdSZiyuan Xu cmd.cmdarg = mmc->rca << 16; 55755e5defdSZiyuan Xu 55855e5defdSZiyuan Xu start = get_timer(0); 55955e5defdSZiyuan Xu 56055e5defdSZiyuan Xu do { 56155e5defdSZiyuan Xu if (mmc_can_card_busy(mmc)) { 56255e5defdSZiyuan Xu busy = mmc_card_busy(mmc); 56355e5defdSZiyuan Xu } else { 56455e5defdSZiyuan Xu ret = mmc_send_cmd(mmc, &cmd, NULL); 56555e5defdSZiyuan Xu 56655e5defdSZiyuan Xu if (ret) 56755e5defdSZiyuan Xu return ret; 56855e5defdSZiyuan Xu 56955e5defdSZiyuan Xu if (cmd.response[0] & MMC_STATUS_SWITCH_ERROR) 57055e5defdSZiyuan Xu return -EBADMSG; 57155e5defdSZiyuan Xu busy = (cmd.response[0] & MMC_STATUS_CURR_STATE) == 57255e5defdSZiyuan Xu MMC_STATE_PRG; 57355e5defdSZiyuan Xu } 57455e5defdSZiyuan Xu 57555e5defdSZiyuan Xu if (get_timer(start) > timeout && busy) 57655e5defdSZiyuan Xu return -ETIMEDOUT; 57755e5defdSZiyuan Xu } while (busy); 57855e5defdSZiyuan Xu 57955e5defdSZiyuan Xu return 0; 58055e5defdSZiyuan Xu } 58155e5defdSZiyuan Xu 58255e5defdSZiyuan Xu static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value, 58355e5defdSZiyuan Xu u8 send_status) 58455e5defdSZiyuan Xu { 58555e5defdSZiyuan Xu struct mmc_cmd cmd; 586a9003dc6SMaxime Ripard int retries = 3; 5875d4fc8d9SRaffaele Recalcati int ret; 588272cc70bSAndy Fleming 589272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SWITCH; 590272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 591272cc70bSAndy Fleming cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 592272cc70bSAndy Fleming (index << 16) | 593272cc70bSAndy Fleming (value << 8); 594272cc70bSAndy Fleming 59555e5defdSZiyuan Xu do { 5965d4fc8d9SRaffaele Recalcati ret = mmc_send_cmd(mmc, &cmd, NULL); 5975d4fc8d9SRaffaele Recalcati 59855e5defdSZiyuan Xu if (!ret && send_status) 59955e5defdSZiyuan Xu return mmc_poll_for_busy(mmc); 60055e5defdSZiyuan Xu } while (--retries > 0 && ret); 60155e5defdSZiyuan Xu 602a9003dc6SMaxime Ripard return ret; 603a9003dc6SMaxime Ripard } 604a9003dc6SMaxime Ripard 60555e5defdSZiyuan Xu int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) 60655e5defdSZiyuan Xu { 60755e5defdSZiyuan Xu return __mmc_switch(mmc, set, index, value, true); 608272cc70bSAndy Fleming } 609272cc70bSAndy Fleming 61049dba033SZiyuan Xu static int mmc_select_bus_width(struct mmc *mmc) 61149dba033SZiyuan Xu { 61249dba033SZiyuan Xu u32 ext_csd_bits[] = { 61349dba033SZiyuan Xu EXT_CSD_BUS_WIDTH_8, 61449dba033SZiyuan Xu EXT_CSD_BUS_WIDTH_4, 61549dba033SZiyuan Xu }; 61649dba033SZiyuan Xu u32 bus_widths[] = { 61749dba033SZiyuan Xu MMC_BUS_WIDTH_8BIT, 61849dba033SZiyuan Xu MMC_BUS_WIDTH_4BIT, 61949dba033SZiyuan Xu }; 62049dba033SZiyuan Xu ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 62149dba033SZiyuan Xu ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 62249dba033SZiyuan Xu u32 idx, bus_width = 0; 62349dba033SZiyuan Xu int err = 0; 62449dba033SZiyuan Xu 62549dba033SZiyuan Xu if (mmc->version < MMC_VERSION_4 || 62649dba033SZiyuan Xu !(mmc->cfg->host_caps & (MMC_MODE_4BIT | MMC_MODE_8BIT))) 62749dba033SZiyuan Xu return 0; 62849dba033SZiyuan Xu 62949dba033SZiyuan Xu err = mmc_send_ext_csd(mmc, ext_csd); 63049dba033SZiyuan Xu 63149dba033SZiyuan Xu if (err) 63249dba033SZiyuan Xu return err; 63349dba033SZiyuan Xu 63449dba033SZiyuan Xu idx = (mmc->cfg->host_caps & MMC_MODE_8BIT) ? 0 : 1; 63549dba033SZiyuan Xu 63649dba033SZiyuan Xu /* 63749dba033SZiyuan Xu * Unlike SD, MMC cards dont have a configuration register to notify 63849dba033SZiyuan Xu * supported bus width. So bus test command should be run to identify 63949dba033SZiyuan Xu * the supported bus width or compare the ext csd values of current 64049dba033SZiyuan Xu * bus width and ext csd values of 1 bit mode read earlier. 64149dba033SZiyuan Xu */ 64249dba033SZiyuan Xu for (; idx < ARRAY_SIZE(bus_widths); idx++) { 64349dba033SZiyuan Xu /* 64449dba033SZiyuan Xu * Host is capable of 8bit transfer, then switch 64549dba033SZiyuan Xu * the device to work in 8bit transfer mode. If the 64649dba033SZiyuan Xu * mmc switch command returns error then switch to 64749dba033SZiyuan Xu * 4bit transfer mode. On success set the corresponding 64849dba033SZiyuan Xu * bus width on the host. 64949dba033SZiyuan Xu */ 65049dba033SZiyuan Xu err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 65149dba033SZiyuan Xu EXT_CSD_BUS_WIDTH, ext_csd_bits[idx]); 65249dba033SZiyuan Xu if (err) 65349dba033SZiyuan Xu continue; 65449dba033SZiyuan Xu 65549dba033SZiyuan Xu bus_width = bus_widths[idx]; 65649dba033SZiyuan Xu mmc_set_bus_width(mmc, bus_width); 65749dba033SZiyuan Xu 65849dba033SZiyuan Xu err = mmc_send_ext_csd(mmc, test_csd); 65949dba033SZiyuan Xu 66049dba033SZiyuan Xu if (err) 66149dba033SZiyuan Xu continue; 66249dba033SZiyuan Xu 66349dba033SZiyuan Xu /* Only compare read only fields */ 66449dba033SZiyuan Xu if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] == 66549dba033SZiyuan Xu test_csd[EXT_CSD_PARTITIONING_SUPPORT]) && 66649dba033SZiyuan Xu (ext_csd[EXT_CSD_HC_WP_GRP_SIZE] == 66749dba033SZiyuan Xu test_csd[EXT_CSD_HC_WP_GRP_SIZE]) && 66849dba033SZiyuan Xu (ext_csd[EXT_CSD_REV] == test_csd[EXT_CSD_REV]) && 66949dba033SZiyuan Xu (ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] == 67049dba033SZiyuan Xu test_csd[EXT_CSD_HC_ERASE_GRP_SIZE]) && 67149dba033SZiyuan Xu !memcmp(&ext_csd[EXT_CSD_SEC_CNT], 67249dba033SZiyuan Xu &test_csd[EXT_CSD_SEC_CNT], 4)) { 67349dba033SZiyuan Xu err = bus_width; 67449dba033SZiyuan Xu break; 67549dba033SZiyuan Xu } else { 67649dba033SZiyuan Xu err = -EBADMSG; 67749dba033SZiyuan Xu } 67849dba033SZiyuan Xu } 67949dba033SZiyuan Xu 68049dba033SZiyuan Xu return err; 68149dba033SZiyuan Xu } 68249dba033SZiyuan Xu 68349dba033SZiyuan Xu static const u8 tuning_blk_pattern_4bit[] = { 68449dba033SZiyuan Xu 0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc, 68549dba033SZiyuan Xu 0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef, 68649dba033SZiyuan Xu 0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb, 68749dba033SZiyuan Xu 0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef, 68849dba033SZiyuan Xu 0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c, 68949dba033SZiyuan Xu 0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee, 69049dba033SZiyuan Xu 0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff, 69149dba033SZiyuan Xu 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde, 69249dba033SZiyuan Xu }; 69349dba033SZiyuan Xu 69449dba033SZiyuan Xu static const u8 tuning_blk_pattern_8bit[] = { 69549dba033SZiyuan Xu 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 69649dba033SZiyuan Xu 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc, 69749dba033SZiyuan Xu 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff, 69849dba033SZiyuan Xu 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff, 69949dba033SZiyuan Xu 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd, 70049dba033SZiyuan Xu 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, 70149dba033SZiyuan Xu 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff, 70249dba033SZiyuan Xu 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff, 70349dba033SZiyuan Xu 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 70449dba033SZiyuan Xu 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 70549dba033SZiyuan Xu 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 70649dba033SZiyuan Xu 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 70749dba033SZiyuan Xu 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 70849dba033SZiyuan Xu 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 70949dba033SZiyuan Xu 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 71049dba033SZiyuan Xu 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 71149dba033SZiyuan Xu }; 71249dba033SZiyuan Xu 71349dba033SZiyuan Xu int mmc_send_tuning(struct mmc *mmc, u32 opcode) 71449dba033SZiyuan Xu { 71549dba033SZiyuan Xu struct mmc_cmd cmd; 71649dba033SZiyuan Xu struct mmc_data data; 71749dba033SZiyuan Xu const u8 *tuning_block_pattern; 71849dba033SZiyuan Xu int size, err = 0; 71949dba033SZiyuan Xu u8 *data_buf; 72049dba033SZiyuan Xu 72149dba033SZiyuan Xu if (mmc->bus_width == MMC_BUS_WIDTH_8BIT) { 72249dba033SZiyuan Xu tuning_block_pattern = tuning_blk_pattern_8bit; 72349dba033SZiyuan Xu size = sizeof(tuning_blk_pattern_8bit); 72449dba033SZiyuan Xu } else if (mmc->bus_width == MMC_BUS_WIDTH_4BIT) { 72549dba033SZiyuan Xu tuning_block_pattern = tuning_blk_pattern_4bit; 72649dba033SZiyuan Xu size = sizeof(tuning_blk_pattern_4bit); 72749dba033SZiyuan Xu } else { 72849dba033SZiyuan Xu return -EINVAL; 72949dba033SZiyuan Xu } 73049dba033SZiyuan Xu 73149dba033SZiyuan Xu data_buf = calloc(1, size); 73249dba033SZiyuan Xu if (!data_buf) 73349dba033SZiyuan Xu return -ENOMEM; 73449dba033SZiyuan Xu 73549dba033SZiyuan Xu cmd.cmdidx = opcode; 73649dba033SZiyuan Xu cmd.resp_type = MMC_RSP_R1; 73749dba033SZiyuan Xu cmd.cmdarg = 0; 73849dba033SZiyuan Xu 73949dba033SZiyuan Xu data.dest = (char *)data_buf; 74049dba033SZiyuan Xu data.blocksize = size; 74149dba033SZiyuan Xu data.blocks = 1; 74249dba033SZiyuan Xu data.flags = MMC_DATA_READ; 74349dba033SZiyuan Xu 74449dba033SZiyuan Xu err = mmc_send_cmd(mmc, &cmd, &data); 74549dba033SZiyuan Xu if (err) 74649dba033SZiyuan Xu goto out; 74749dba033SZiyuan Xu 74849dba033SZiyuan Xu if (memcmp(data_buf, tuning_block_pattern, size)) 74949dba033SZiyuan Xu err = -EIO; 75049dba033SZiyuan Xu out: 75149dba033SZiyuan Xu free(data_buf); 75249dba033SZiyuan Xu return err; 75349dba033SZiyuan Xu } 75449dba033SZiyuan Xu 75549dba033SZiyuan Xu static int mmc_execute_tuning(struct mmc *mmc) 75649dba033SZiyuan Xu { 75749dba033SZiyuan Xu #ifdef CONFIG_DM_MMC 75849dba033SZiyuan Xu struct dm_mmc_ops *ops = mmc_get_ops(mmc->dev); 75949dba033SZiyuan Xu #endif 76049dba033SZiyuan Xu u32 opcode; 76149dba033SZiyuan Xu 76249dba033SZiyuan Xu if (IS_SD(mmc)) 76349dba033SZiyuan Xu opcode = MMC_SEND_TUNING_BLOCK; 76449dba033SZiyuan Xu else 76549dba033SZiyuan Xu opcode = MMC_SEND_TUNING_BLOCK_HS200; 76649dba033SZiyuan Xu 76749dba033SZiyuan Xu #ifndef CONFIG_DM_MMC 76849dba033SZiyuan Xu if (mmc->cfg->ops->execute_tuning) { 76949dba033SZiyuan Xu return mmc->cfg->ops->execute_tuning(mmc, opcode); 77049dba033SZiyuan Xu #else 77149dba033SZiyuan Xu if (ops->execute_tuning) { 77249dba033SZiyuan Xu return ops->execute_tuning(mmc->dev, opcode); 77349dba033SZiyuan Xu #endif 77449dba033SZiyuan Xu } else { 77549dba033SZiyuan Xu debug("Tuning feature required for HS200 mode.\n"); 77649dba033SZiyuan Xu return -EIO; 77749dba033SZiyuan Xu } 77849dba033SZiyuan Xu } 77949dba033SZiyuan Xu 78049dba033SZiyuan Xu static int mmc_hs200_tuning(struct mmc *mmc) 78149dba033SZiyuan Xu { 78249dba033SZiyuan Xu return mmc_execute_tuning(mmc); 78349dba033SZiyuan Xu } 78449dba033SZiyuan Xu 785e61cd3d7SZiyuan Xu static int mmc_select_hs(struct mmc *mmc) 786e61cd3d7SZiyuan Xu { 787e61cd3d7SZiyuan Xu int ret; 788e61cd3d7SZiyuan Xu 789e61cd3d7SZiyuan Xu ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 790e61cd3d7SZiyuan Xu EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS); 791e61cd3d7SZiyuan Xu 792e61cd3d7SZiyuan Xu if (!ret) 793e61cd3d7SZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_MMC_HS); 794e61cd3d7SZiyuan Xu 795e61cd3d7SZiyuan Xu return ret; 796e61cd3d7SZiyuan Xu } 797e61cd3d7SZiyuan Xu 79849dba033SZiyuan Xu #ifndef CONFIG_SPL_BUILD 79949dba033SZiyuan Xu static int mmc_select_hs200(struct mmc *mmc) 80049dba033SZiyuan Xu { 80149dba033SZiyuan Xu int ret; 80249dba033SZiyuan Xu struct mmc_cmd cmd; 80349dba033SZiyuan Xu 80449dba033SZiyuan Xu /* 80549dba033SZiyuan Xu * Set the bus width(4 or 8) with host's support and 80649dba033SZiyuan Xu * switch to HS200 mode if bus width is set successfully. 80749dba033SZiyuan Xu */ 80849dba033SZiyuan Xu ret = mmc_select_bus_width(mmc); 80949dba033SZiyuan Xu 81049dba033SZiyuan Xu if (ret > 0) { 81149dba033SZiyuan Xu ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 81249dba033SZiyuan Xu EXT_CSD_HS_TIMING, 81349dba033SZiyuan Xu EXT_CSD_TIMING_HS200, false); 81449dba033SZiyuan Xu 81549dba033SZiyuan Xu if (ret) 81649dba033SZiyuan Xu return ret; 81749dba033SZiyuan Xu 81849dba033SZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_MMC_HS200); 81949dba033SZiyuan Xu 82049dba033SZiyuan Xu cmd.cmdidx = MMC_CMD_SEND_STATUS; 82149dba033SZiyuan Xu cmd.resp_type = MMC_RSP_R1; 82249dba033SZiyuan Xu cmd.cmdarg = mmc->rca << 16; 82349dba033SZiyuan Xu 82449dba033SZiyuan Xu ret = mmc_send_cmd(mmc, &cmd, NULL); 82549dba033SZiyuan Xu 82649dba033SZiyuan Xu if (ret) 82749dba033SZiyuan Xu return ret; 82849dba033SZiyuan Xu 82949dba033SZiyuan Xu if (cmd.response[0] & MMC_STATUS_SWITCH_ERROR) 83049dba033SZiyuan Xu return -EBADMSG; 83149dba033SZiyuan Xu } 83249dba033SZiyuan Xu 83349dba033SZiyuan Xu return ret; 83449dba033SZiyuan Xu } 83549dba033SZiyuan Xu #endif 83649dba033SZiyuan Xu 837227f658eSZiyuan Xu static u32 mmc_select_card_type(struct mmc *mmc, u8 *ext_csd) 838227f658eSZiyuan Xu { 839227f658eSZiyuan Xu u8 card_type; 840227f658eSZiyuan Xu u32 host_caps, avail_type = 0; 841227f658eSZiyuan Xu 842227f658eSZiyuan Xu card_type = ext_csd[EXT_CSD_CARD_TYPE]; 843227f658eSZiyuan Xu host_caps = mmc->cfg->host_caps; 844227f658eSZiyuan Xu 845227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS) && 846227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_26)) 847227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_26; 848227f658eSZiyuan Xu 849227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS) && 850227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_52)) 851227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_52; 852227f658eSZiyuan Xu 853227f658eSZiyuan Xu /* 854227f658eSZiyuan Xu * For the moment, u-boot doesn't support signal voltage 855227f658eSZiyuan Xu * switch, therefor we assume that host support ddr52 856227f658eSZiyuan Xu * at 1.8v or 3.3v I/O(1.2v I/O not supported, hs200 and 857227f658eSZiyuan Xu * hs400 are the same). 858227f658eSZiyuan Xu */ 859227f658eSZiyuan Xu if ((host_caps & MMC_MODE_DDR_52MHz) && 860227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)) 861227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V; 862227f658eSZiyuan Xu 863227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS200) && 864227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_HS200_1_8V)) 865227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V; 866227f658eSZiyuan Xu 867227f658eSZiyuan Xu /* 868227f658eSZiyuan Xu * If host can support HS400, it means that host can also 869227f658eSZiyuan Xu * support HS200. 870227f658eSZiyuan Xu */ 871227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS400) && 872227f658eSZiyuan Xu (host_caps & MMC_MODE_8BIT) && 873227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_HS400_1_8V)) 874227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V | 875227f658eSZiyuan Xu EXT_CSD_CARD_TYPE_HS400_1_8V; 876227f658eSZiyuan Xu 877227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS400ES) && 878227f658eSZiyuan Xu (host_caps & MMC_MODE_8BIT) && 879227f658eSZiyuan Xu ext_csd[EXT_CSD_STROBE_SUPPORT] && 880227f658eSZiyuan Xu (avail_type & EXT_CSD_CARD_TYPE_HS400_1_8V)) 881227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V | 882227f658eSZiyuan Xu EXT_CSD_CARD_TYPE_HS400_1_8V | 883227f658eSZiyuan Xu EXT_CSD_CARD_TYPE_HS400ES; 884227f658eSZiyuan Xu 885227f658eSZiyuan Xu return avail_type; 886227f658eSZiyuan Xu } 887227f658eSZiyuan Xu 88849dba033SZiyuan Xu static void mmc_set_bus_speed(struct mmc *mmc, u8 avail_type) 88949dba033SZiyuan Xu { 89049dba033SZiyuan Xu int clock = 0; 89149dba033SZiyuan Xu 89249dba033SZiyuan Xu if (mmc_card_hs(mmc)) 89349dba033SZiyuan Xu clock = (avail_type & EXT_CSD_CARD_TYPE_52) ? 89449dba033SZiyuan Xu MMC_HIGH_52_MAX_DTR : MMC_HIGH_26_MAX_DTR; 89549dba033SZiyuan Xu else if (mmc_card_hs200(mmc) || 89649dba033SZiyuan Xu mmc_card_hs400(mmc) || 89749dba033SZiyuan Xu mmc_card_hs400es(mmc)) 89849dba033SZiyuan Xu clock = MMC_HS200_MAX_DTR; 89949dba033SZiyuan Xu 90049dba033SZiyuan Xu mmc_set_clock(mmc, clock); 90149dba033SZiyuan Xu } 90249dba033SZiyuan Xu 903fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc) 904272cc70bSAndy Fleming { 9058bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 906227f658eSZiyuan Xu u32 avail_type; 907272cc70bSAndy Fleming int err; 908272cc70bSAndy Fleming 909fc5b32fbSAndrew Gabbasov mmc->card_caps = 0; 910272cc70bSAndy Fleming 911d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 912d52ebf10SThomas Chou return 0; 913d52ebf10SThomas Chou 914272cc70bSAndy Fleming /* Only version 4 supports high-speed */ 915272cc70bSAndy Fleming if (mmc->version < MMC_VERSION_4) 916272cc70bSAndy Fleming return 0; 917272cc70bSAndy Fleming 918fc5b32fbSAndrew Gabbasov mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; 919fc5b32fbSAndrew Gabbasov 920272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 921272cc70bSAndy Fleming 922272cc70bSAndy Fleming if (err) 923272cc70bSAndy Fleming return err; 924272cc70bSAndy Fleming 925227f658eSZiyuan Xu avail_type = mmc_select_card_type(mmc, ext_csd); 926272cc70bSAndy Fleming 92749dba033SZiyuan Xu #ifndef CONFIG_SPL_BUILD 92849dba033SZiyuan Xu if (avail_type & EXT_CSD_CARD_TYPE_HS200) 92949dba033SZiyuan Xu err = mmc_select_hs200(mmc); 93049dba033SZiyuan Xu else 93149dba033SZiyuan Xu #endif 932227f658eSZiyuan Xu if (avail_type & EXT_CSD_CARD_TYPE_HS) 933e61cd3d7SZiyuan Xu err = mmc_select_hs(mmc); 934227f658eSZiyuan Xu else 935227f658eSZiyuan Xu err = -EINVAL; 936272cc70bSAndy Fleming 937272cc70bSAndy Fleming if (err) 938a5e27b41SHeiko Schocher return err; 939272cc70bSAndy Fleming 94049dba033SZiyuan Xu mmc_set_bus_speed(mmc, avail_type); 941272cc70bSAndy Fleming 94249dba033SZiyuan Xu if (mmc_card_hs200(mmc)) 94349dba033SZiyuan Xu err = mmc_hs200_tuning(mmc); 94449dba033SZiyuan Xu else 94549dba033SZiyuan Xu err = mmc_select_bus_width(mmc) > 0 ? 0 : err; 94649dba033SZiyuan Xu 947272cc70bSAndy Fleming return err; 948272cc70bSAndy Fleming } 949272cc70bSAndy Fleming 950f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num) 951f866a46dSStephen Warren { 952f866a46dSStephen Warren switch (part_num) { 953f866a46dSStephen Warren case 0: 954f866a46dSStephen Warren mmc->capacity = mmc->capacity_user; 955f866a46dSStephen Warren break; 956f866a46dSStephen Warren case 1: 957f866a46dSStephen Warren case 2: 958f866a46dSStephen Warren mmc->capacity = mmc->capacity_boot; 959f866a46dSStephen Warren break; 960f866a46dSStephen Warren case 3: 961f866a46dSStephen Warren mmc->capacity = mmc->capacity_rpmb; 962f866a46dSStephen Warren break; 963f866a46dSStephen Warren case 4: 964f866a46dSStephen Warren case 5: 965f866a46dSStephen Warren case 6: 966f866a46dSStephen Warren case 7: 967f866a46dSStephen Warren mmc->capacity = mmc->capacity_gp[part_num - 4]; 968f866a46dSStephen Warren break; 969f866a46dSStephen Warren default: 970f866a46dSStephen Warren return -1; 971f866a46dSStephen Warren } 972f866a46dSStephen Warren 973c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len); 974f866a46dSStephen Warren 975f866a46dSStephen Warren return 0; 976f866a46dSStephen Warren } 977f866a46dSStephen Warren 9787dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num) 979bc897b1dSLei Wen { 980f866a46dSStephen Warren int ret; 981bc897b1dSLei Wen 982f866a46dSStephen Warren ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 983bc897b1dSLei Wen (mmc->part_config & ~PART_ACCESS_MASK) 984bc897b1dSLei Wen | (part_num & PART_ACCESS_MASK)); 985f866a46dSStephen Warren 9866dc93e70SPeter Bigot /* 9876dc93e70SPeter Bigot * Set the capacity if the switch succeeded or was intended 9886dc93e70SPeter Bigot * to return to representing the raw device. 9896dc93e70SPeter Bigot */ 990873cc1d7SStephen Warren if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) { 9916dc93e70SPeter Bigot ret = mmc_set_capacity(mmc, part_num); 992fdbb139fSSimon Glass mmc_get_blk_desc(mmc)->hwpart = part_num; 993873cc1d7SStephen Warren } 9946dc93e70SPeter Bigot 9956dc93e70SPeter Bigot return ret; 996bc897b1dSLei Wen } 997bc897b1dSLei Wen 998ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc, 999ac9da0e0SDiego Santa Cruz const struct mmc_hwpart_conf *conf, 1000ac9da0e0SDiego Santa Cruz enum mmc_hwpart_conf_mode mode) 1001ac9da0e0SDiego Santa Cruz { 1002ac9da0e0SDiego Santa Cruz u8 part_attrs = 0; 1003ac9da0e0SDiego Santa Cruz u32 enh_size_mult; 1004ac9da0e0SDiego Santa Cruz u32 enh_start_addr; 1005ac9da0e0SDiego Santa Cruz u32 gp_size_mult[4]; 1006ac9da0e0SDiego Santa Cruz u32 max_enh_size_mult; 1007ac9da0e0SDiego Santa Cruz u32 tot_enh_size_mult = 0; 10088dda5b0eSDiego Santa Cruz u8 wr_rel_set; 1009ac9da0e0SDiego Santa Cruz int i, pidx, err; 1010ac9da0e0SDiego Santa Cruz ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 1011ac9da0e0SDiego Santa Cruz 1012ac9da0e0SDiego Santa Cruz if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE) 1013ac9da0e0SDiego Santa Cruz return -EINVAL; 1014ac9da0e0SDiego Santa Cruz 1015ac9da0e0SDiego Santa Cruz if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) { 1016ac9da0e0SDiego Santa Cruz printf("eMMC >= 4.4 required for enhanced user data area\n"); 1017ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1018ac9da0e0SDiego Santa Cruz } 1019ac9da0e0SDiego Santa Cruz 1020ac9da0e0SDiego Santa Cruz if (!(mmc->part_support & PART_SUPPORT)) { 1021ac9da0e0SDiego Santa Cruz printf("Card does not support partitioning\n"); 1022ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1023ac9da0e0SDiego Santa Cruz } 1024ac9da0e0SDiego Santa Cruz 1025ac9da0e0SDiego Santa Cruz if (!mmc->hc_wp_grp_size) { 1026ac9da0e0SDiego Santa Cruz printf("Card does not define HC WP group size\n"); 1027ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1028ac9da0e0SDiego Santa Cruz } 1029ac9da0e0SDiego Santa Cruz 1030ac9da0e0SDiego Santa Cruz /* check partition alignment and total enhanced size */ 1031ac9da0e0SDiego Santa Cruz if (conf->user.enh_size) { 1032ac9da0e0SDiego Santa Cruz if (conf->user.enh_size % mmc->hc_wp_grp_size || 1033ac9da0e0SDiego Santa Cruz conf->user.enh_start % mmc->hc_wp_grp_size) { 1034ac9da0e0SDiego Santa Cruz printf("User data enhanced area not HC WP group " 1035ac9da0e0SDiego Santa Cruz "size aligned\n"); 1036ac9da0e0SDiego Santa Cruz return -EINVAL; 1037ac9da0e0SDiego Santa Cruz } 1038ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_USR; 1039ac9da0e0SDiego Santa Cruz enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size; 1040ac9da0e0SDiego Santa Cruz if (mmc->high_capacity) { 1041ac9da0e0SDiego Santa Cruz enh_start_addr = conf->user.enh_start; 1042ac9da0e0SDiego Santa Cruz } else { 1043ac9da0e0SDiego Santa Cruz enh_start_addr = (conf->user.enh_start << 9); 1044ac9da0e0SDiego Santa Cruz } 1045ac9da0e0SDiego Santa Cruz } else { 1046ac9da0e0SDiego Santa Cruz enh_size_mult = 0; 1047ac9da0e0SDiego Santa Cruz enh_start_addr = 0; 1048ac9da0e0SDiego Santa Cruz } 1049ac9da0e0SDiego Santa Cruz tot_enh_size_mult += enh_size_mult; 1050ac9da0e0SDiego Santa Cruz 1051ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 1052ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) { 1053ac9da0e0SDiego Santa Cruz printf("GP%i partition not HC WP group size " 1054ac9da0e0SDiego Santa Cruz "aligned\n", pidx+1); 1055ac9da0e0SDiego Santa Cruz return -EINVAL; 1056ac9da0e0SDiego Santa Cruz } 1057ac9da0e0SDiego Santa Cruz gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size; 1058ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) { 1059ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_GP(pidx); 1060ac9da0e0SDiego Santa Cruz tot_enh_size_mult += gp_size_mult[pidx]; 1061ac9da0e0SDiego Santa Cruz } 1062ac9da0e0SDiego Santa Cruz } 1063ac9da0e0SDiego Santa Cruz 1064ac9da0e0SDiego Santa Cruz if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) { 1065ac9da0e0SDiego Santa Cruz printf("Card does not support enhanced attribute\n"); 1066ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1067ac9da0e0SDiego Santa Cruz } 1068ac9da0e0SDiego Santa Cruz 1069ac9da0e0SDiego Santa Cruz err = mmc_send_ext_csd(mmc, ext_csd); 1070ac9da0e0SDiego Santa Cruz if (err) 1071ac9da0e0SDiego Santa Cruz return err; 1072ac9da0e0SDiego Santa Cruz 1073ac9da0e0SDiego Santa Cruz max_enh_size_mult = 1074ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) + 1075ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) + 1076ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]; 1077ac9da0e0SDiego Santa Cruz if (tot_enh_size_mult > max_enh_size_mult) { 1078ac9da0e0SDiego Santa Cruz printf("Total enhanced size exceeds maximum (%u > %u)\n", 1079ac9da0e0SDiego Santa Cruz tot_enh_size_mult, max_enh_size_mult); 1080ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1081ac9da0e0SDiego Santa Cruz } 1082ac9da0e0SDiego Santa Cruz 10838dda5b0eSDiego Santa Cruz /* The default value of EXT_CSD_WR_REL_SET is device 10848dda5b0eSDiego Santa Cruz * dependent, the values can only be changed if the 10858dda5b0eSDiego Santa Cruz * EXT_CSD_HS_CTRL_REL bit is set. The values can be 10868dda5b0eSDiego Santa Cruz * changed only once and before partitioning is completed. */ 10878dda5b0eSDiego Santa Cruz wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 10888dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_change) { 10898dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_set) 10908dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_USR; 10918dda5b0eSDiego Santa Cruz else 10928dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR; 10938dda5b0eSDiego Santa Cruz } 10948dda5b0eSDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 10958dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_change) { 10968dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_set) 10978dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx); 10988dda5b0eSDiego Santa Cruz else 10998dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx); 11008dda5b0eSDiego Santa Cruz } 11018dda5b0eSDiego Santa Cruz } 11028dda5b0eSDiego Santa Cruz 11038dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] && 11048dda5b0eSDiego Santa Cruz !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) { 11058dda5b0eSDiego Santa Cruz puts("Card does not support host controlled partition write " 11068dda5b0eSDiego Santa Cruz "reliability settings\n"); 11078dda5b0eSDiego Santa Cruz return -EMEDIUMTYPE; 11088dda5b0eSDiego Santa Cruz } 11098dda5b0eSDiego Santa Cruz 1110ac9da0e0SDiego Santa Cruz if (ext_csd[EXT_CSD_PARTITION_SETTING] & 1111ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED) { 1112ac9da0e0SDiego Santa Cruz printf("Card already partitioned\n"); 1113ac9da0e0SDiego Santa Cruz return -EPERM; 1114ac9da0e0SDiego Santa Cruz } 1115ac9da0e0SDiego Santa Cruz 1116ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_CHECK) 1117ac9da0e0SDiego Santa Cruz return 0; 1118ac9da0e0SDiego Santa Cruz 1119ac9da0e0SDiego Santa Cruz /* Partitioning requires high-capacity size definitions */ 1120ac9da0e0SDiego Santa Cruz if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) { 1121ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1122ac9da0e0SDiego Santa Cruz EXT_CSD_ERASE_GROUP_DEF, 1); 1123ac9da0e0SDiego Santa Cruz 1124ac9da0e0SDiego Santa Cruz if (err) 1125ac9da0e0SDiego Santa Cruz return err; 1126ac9da0e0SDiego Santa Cruz 1127ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 1128ac9da0e0SDiego Santa Cruz 1129ac9da0e0SDiego Santa Cruz /* update erase group size to be high-capacity */ 1130ac9da0e0SDiego Santa Cruz mmc->erase_grp_size = 1131ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 1132ac9da0e0SDiego Santa Cruz 1133ac9da0e0SDiego Santa Cruz } 1134ac9da0e0SDiego Santa Cruz 1135ac9da0e0SDiego Santa Cruz /* all OK, write the configuration */ 1136ac9da0e0SDiego Santa Cruz for (i = 0; i < 4; i++) { 1137ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1138ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_START_ADDR+i, 1139ac9da0e0SDiego Santa Cruz (enh_start_addr >> (i*8)) & 0xFF); 1140ac9da0e0SDiego Santa Cruz if (err) 1141ac9da0e0SDiego Santa Cruz return err; 1142ac9da0e0SDiego Santa Cruz } 1143ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 1144ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1145ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_SIZE_MULT+i, 1146ac9da0e0SDiego Santa Cruz (enh_size_mult >> (i*8)) & 0xFF); 1147ac9da0e0SDiego Santa Cruz if (err) 1148ac9da0e0SDiego Santa Cruz return err; 1149ac9da0e0SDiego Santa Cruz } 1150ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 1151ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 1152ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1153ac9da0e0SDiego Santa Cruz EXT_CSD_GP_SIZE_MULT+pidx*3+i, 1154ac9da0e0SDiego Santa Cruz (gp_size_mult[pidx] >> (i*8)) & 0xFF); 1155ac9da0e0SDiego Santa Cruz if (err) 1156ac9da0e0SDiego Santa Cruz return err; 1157ac9da0e0SDiego Santa Cruz } 1158ac9da0e0SDiego Santa Cruz } 1159ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1160ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs); 1161ac9da0e0SDiego Santa Cruz if (err) 1162ac9da0e0SDiego Santa Cruz return err; 1163ac9da0e0SDiego Santa Cruz 1164ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_SET) 1165ac9da0e0SDiego Santa Cruz return 0; 1166ac9da0e0SDiego Santa Cruz 11678dda5b0eSDiego Santa Cruz /* The WR_REL_SET is a write-once register but shall be 11688dda5b0eSDiego Santa Cruz * written before setting PART_SETTING_COMPLETED. As it is 11698dda5b0eSDiego Santa Cruz * write-once we can only write it when completing the 11708dda5b0eSDiego Santa Cruz * partitioning. */ 11718dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) { 11728dda5b0eSDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 11738dda5b0eSDiego Santa Cruz EXT_CSD_WR_REL_SET, wr_rel_set); 11748dda5b0eSDiego Santa Cruz if (err) 11758dda5b0eSDiego Santa Cruz return err; 11768dda5b0eSDiego Santa Cruz } 11778dda5b0eSDiego Santa Cruz 1178ac9da0e0SDiego Santa Cruz /* Setting PART_SETTING_COMPLETED confirms the partition 1179ac9da0e0SDiego Santa Cruz * configuration but it only becomes effective after power 1180ac9da0e0SDiego Santa Cruz * cycle, so we do not adjust the partition related settings 1181ac9da0e0SDiego Santa Cruz * in the mmc struct. */ 1182ac9da0e0SDiego Santa Cruz 1183ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1184ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING, 1185ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 1186ac9da0e0SDiego Santa Cruz if (err) 1187ac9da0e0SDiego Santa Cruz return err; 1188ac9da0e0SDiego Santa Cruz 1189ac9da0e0SDiego Santa Cruz return 0; 1190ac9da0e0SDiego Santa Cruz } 1191ac9da0e0SDiego Santa Cruz 1192e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 119348972d90SThierry Reding int mmc_getcd(struct mmc *mmc) 119448972d90SThierry Reding { 119548972d90SThierry Reding int cd; 119648972d90SThierry Reding 119748972d90SThierry Reding cd = board_mmc_getcd(mmc); 119848972d90SThierry Reding 1199d4e1da4eSPeter Korsgaard if (cd < 0) { 120093bfd616SPantelis Antoniou if (mmc->cfg->ops->getcd) 120193bfd616SPantelis Antoniou cd = mmc->cfg->ops->getcd(mmc); 1202d4e1da4eSPeter Korsgaard else 1203d4e1da4eSPeter Korsgaard cd = 1; 1204d4e1da4eSPeter Korsgaard } 120548972d90SThierry Reding 120648972d90SThierry Reding return cd; 120748972d90SThierry Reding } 12088ca51e51SSimon Glass #endif 120948972d90SThierry Reding 1210fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) 1211272cc70bSAndy Fleming { 1212272cc70bSAndy Fleming struct mmc_cmd cmd; 1213272cc70bSAndy Fleming struct mmc_data data; 1214272cc70bSAndy Fleming 1215272cc70bSAndy Fleming /* Switch the frequency */ 1216272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC; 1217272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1218272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff; 1219272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4)); 1220272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4); 1221272cc70bSAndy Fleming 1222272cc70bSAndy Fleming data.dest = (char *)resp; 1223272cc70bSAndy Fleming data.blocksize = 64; 1224272cc70bSAndy Fleming data.blocks = 1; 1225272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1226272cc70bSAndy Fleming 1227272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 1228272cc70bSAndy Fleming } 1229272cc70bSAndy Fleming 1230272cc70bSAndy Fleming 1231fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc) 1232272cc70bSAndy Fleming { 1233272cc70bSAndy Fleming int err; 1234272cc70bSAndy Fleming struct mmc_cmd cmd; 1235f781dd38SAnton staaf ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2); 1236f781dd38SAnton staaf ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16); 1237272cc70bSAndy Fleming struct mmc_data data; 1238272cc70bSAndy Fleming int timeout; 1239272cc70bSAndy Fleming 1240272cc70bSAndy Fleming mmc->card_caps = 0; 1241272cc70bSAndy Fleming 1242d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 1243d52ebf10SThomas Chou return 0; 1244d52ebf10SThomas Chou 1245272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */ 1246272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 1247272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1248272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1249272cc70bSAndy Fleming 1250272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1251272cc70bSAndy Fleming 1252272cc70bSAndy Fleming if (err) 1253272cc70bSAndy Fleming return err; 1254272cc70bSAndy Fleming 1255272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR; 1256272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1257272cc70bSAndy Fleming cmd.cmdarg = 0; 1258272cc70bSAndy Fleming 1259272cc70bSAndy Fleming timeout = 3; 1260272cc70bSAndy Fleming 1261272cc70bSAndy Fleming retry_scr: 1262f781dd38SAnton staaf data.dest = (char *)scr; 1263272cc70bSAndy Fleming data.blocksize = 8; 1264272cc70bSAndy Fleming data.blocks = 1; 1265272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1266272cc70bSAndy Fleming 1267272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 1268272cc70bSAndy Fleming 1269272cc70bSAndy Fleming if (err) { 1270272cc70bSAndy Fleming if (timeout--) 1271272cc70bSAndy Fleming goto retry_scr; 1272272cc70bSAndy Fleming 1273272cc70bSAndy Fleming return err; 1274272cc70bSAndy Fleming } 1275272cc70bSAndy Fleming 12764e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]); 12774e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]); 1278272cc70bSAndy Fleming 1279272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) { 1280272cc70bSAndy Fleming case 0: 1281272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1282272cc70bSAndy Fleming break; 1283272cc70bSAndy Fleming case 1: 1284272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10; 1285272cc70bSAndy Fleming break; 1286272cc70bSAndy Fleming case 2: 1287272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 12881741c64dSJaehoon Chung if ((mmc->scr[0] >> 15) & 0x1) 12891741c64dSJaehoon Chung mmc->version = SD_VERSION_3; 1290272cc70bSAndy Fleming break; 1291272cc70bSAndy Fleming default: 1292272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1293272cc70bSAndy Fleming break; 1294272cc70bSAndy Fleming } 1295272cc70bSAndy Fleming 1296b44c7083SAlagu Sankar if (mmc->scr[0] & SD_DATA_4BIT) 1297b44c7083SAlagu Sankar mmc->card_caps |= MMC_MODE_4BIT; 1298b44c7083SAlagu Sankar 1299272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */ 1300272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0) 1301272cc70bSAndy Fleming return 0; 1302272cc70bSAndy Fleming 1303272cc70bSAndy Fleming timeout = 4; 1304272cc70bSAndy Fleming while (timeout--) { 1305272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, 1306f781dd38SAnton staaf (u8 *)switch_status); 1307272cc70bSAndy Fleming 1308272cc70bSAndy Fleming if (err) 1309272cc70bSAndy Fleming return err; 1310272cc70bSAndy Fleming 1311272cc70bSAndy Fleming /* The high-speed function is busy. Try again */ 13124e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) 1313272cc70bSAndy Fleming break; 1314272cc70bSAndy Fleming } 1315272cc70bSAndy Fleming 1316272cc70bSAndy Fleming /* If high-speed isn't supported, we return */ 13174e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)) 1318272cc70bSAndy Fleming return 0; 1319272cc70bSAndy Fleming 13202c3fbf4cSMacpaul Lin /* 13212c3fbf4cSMacpaul Lin * If the host doesn't support SD_HIGHSPEED, do not switch card to 13222c3fbf4cSMacpaul Lin * HIGHSPEED mode even if the card support SD_HIGHSPPED. 13232c3fbf4cSMacpaul Lin * This can avoid furthur problem when the card runs in different 13242c3fbf4cSMacpaul Lin * mode between the host. 13252c3fbf4cSMacpaul Lin */ 132693bfd616SPantelis Antoniou if (!((mmc->cfg->host_caps & MMC_MODE_HS_52MHz) && 132793bfd616SPantelis Antoniou (mmc->cfg->host_caps & MMC_MODE_HS))) 13282c3fbf4cSMacpaul Lin return 0; 13292c3fbf4cSMacpaul Lin 1330f781dd38SAnton staaf err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status); 1331272cc70bSAndy Fleming 1332272cc70bSAndy Fleming if (err) 1333272cc70bSAndy Fleming return err; 1334272cc70bSAndy Fleming 13354e3d89baSYauhen Kharuzhy if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000) 1336272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS; 1337272cc70bSAndy Fleming 1338272cc70bSAndy Fleming return 0; 1339272cc70bSAndy Fleming } 1340272cc70bSAndy Fleming 13413697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc) 13423697e599SPeng Fan { 13433697e599SPeng Fan int err, i; 13443697e599SPeng Fan struct mmc_cmd cmd; 13453697e599SPeng Fan ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16); 13463697e599SPeng Fan struct mmc_data data; 13473697e599SPeng Fan int timeout = 3; 13483697e599SPeng Fan unsigned int au, eo, et, es; 13493697e599SPeng Fan 13503697e599SPeng Fan cmd.cmdidx = MMC_CMD_APP_CMD; 13513697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 13523697e599SPeng Fan cmd.cmdarg = mmc->rca << 16; 13533697e599SPeng Fan 13543697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, NULL); 13553697e599SPeng Fan if (err) 13563697e599SPeng Fan return err; 13573697e599SPeng Fan 13583697e599SPeng Fan cmd.cmdidx = SD_CMD_APP_SD_STATUS; 13593697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 13603697e599SPeng Fan cmd.cmdarg = 0; 13613697e599SPeng Fan 13623697e599SPeng Fan retry_ssr: 13633697e599SPeng Fan data.dest = (char *)ssr; 13643697e599SPeng Fan data.blocksize = 64; 13653697e599SPeng Fan data.blocks = 1; 13663697e599SPeng Fan data.flags = MMC_DATA_READ; 13673697e599SPeng Fan 13683697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, &data); 13693697e599SPeng Fan if (err) { 13703697e599SPeng Fan if (timeout--) 13713697e599SPeng Fan goto retry_ssr; 13723697e599SPeng Fan 13733697e599SPeng Fan return err; 13743697e599SPeng Fan } 13753697e599SPeng Fan 13763697e599SPeng Fan for (i = 0; i < 16; i++) 13773697e599SPeng Fan ssr[i] = be32_to_cpu(ssr[i]); 13783697e599SPeng Fan 13793697e599SPeng Fan au = (ssr[2] >> 12) & 0xF; 13803697e599SPeng Fan if ((au <= 9) || (mmc->version == SD_VERSION_3)) { 13813697e599SPeng Fan mmc->ssr.au = sd_au_size[au]; 13823697e599SPeng Fan es = (ssr[3] >> 24) & 0xFF; 13833697e599SPeng Fan es |= (ssr[2] & 0xFF) << 8; 13843697e599SPeng Fan et = (ssr[3] >> 18) & 0x3F; 13853697e599SPeng Fan if (es && et) { 13863697e599SPeng Fan eo = (ssr[3] >> 16) & 0x3; 13873697e599SPeng Fan mmc->ssr.erase_timeout = (et * 1000) / es; 13883697e599SPeng Fan mmc->ssr.erase_offset = eo * 1000; 13893697e599SPeng Fan } 13903697e599SPeng Fan } else { 13913697e599SPeng Fan debug("Invalid Allocation Unit Size.\n"); 13923697e599SPeng Fan } 13933697e599SPeng Fan 13943697e599SPeng Fan return 0; 13953697e599SPeng Fan } 13963697e599SPeng Fan 1397272cc70bSAndy Fleming /* frequency bases */ 1398272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */ 13995f837c2cSMike Frysinger static const int fbase[] = { 1400272cc70bSAndy Fleming 10000, 1401272cc70bSAndy Fleming 100000, 1402272cc70bSAndy Fleming 1000000, 1403272cc70bSAndy Fleming 10000000, 1404272cc70bSAndy Fleming }; 1405272cc70bSAndy Fleming 1406272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice 1407272cc70bSAndy Fleming * to platforms without floating point. 1408272cc70bSAndy Fleming */ 140961fe076fSSimon Glass static const u8 multipliers[] = { 1410272cc70bSAndy Fleming 0, /* reserved */ 1411272cc70bSAndy Fleming 10, 1412272cc70bSAndy Fleming 12, 1413272cc70bSAndy Fleming 13, 1414272cc70bSAndy Fleming 15, 1415272cc70bSAndy Fleming 20, 1416272cc70bSAndy Fleming 25, 1417272cc70bSAndy Fleming 30, 1418272cc70bSAndy Fleming 35, 1419272cc70bSAndy Fleming 40, 1420272cc70bSAndy Fleming 45, 1421272cc70bSAndy Fleming 50, 1422272cc70bSAndy Fleming 55, 1423272cc70bSAndy Fleming 60, 1424272cc70bSAndy Fleming 70, 1425272cc70bSAndy Fleming 80, 1426272cc70bSAndy Fleming }; 1427272cc70bSAndy Fleming 1428e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 1429fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc) 1430272cc70bSAndy Fleming { 143193bfd616SPantelis Antoniou if (mmc->cfg->ops->set_ios) 143293bfd616SPantelis Antoniou mmc->cfg->ops->set_ios(mmc); 1433272cc70bSAndy Fleming } 1434ad77484aSZiyuan Xu 1435ad77484aSZiyuan Xu static bool mmc_card_busy(struct mmc *mmc) 1436ad77484aSZiyuan Xu { 1437ad77484aSZiyuan Xu if (!mmc->cfg->ops->card_busy) 1438ad77484aSZiyuan Xu return -ENOSYS; 1439ad77484aSZiyuan Xu 1440ad77484aSZiyuan Xu return mmc->cfg->ops->card_busy(mmc); 1441ad77484aSZiyuan Xu } 1442ad77484aSZiyuan Xu 1443ad77484aSZiyuan Xu static bool mmc_can_card_busy(struct mmc *) 1444ad77484aSZiyuan Xu { 1445ad77484aSZiyuan Xu return !!mmc->cfg->ops->card_busy; 1446ad77484aSZiyuan Xu } 14478ca51e51SSimon Glass #endif 1448272cc70bSAndy Fleming 1449fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc) 1450272cc70bSAndy Fleming { 1451f866a46dSStephen Warren int err, i; 1452272cc70bSAndy Fleming uint mult, freq; 1453639b7827SYoshihiro Shimoda u64 cmult, csize, capacity; 1454272cc70bSAndy Fleming struct mmc_cmd cmd; 14558bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 14560c453bb7SDiego Santa Cruz bool has_parts = false; 14578a0cf490SDiego Santa Cruz bool part_completed; 1458c40fdca6SSimon Glass struct blk_desc *bdesc; 1459272cc70bSAndy Fleming 1460d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON 1461d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ 1462d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; 1463d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R1; 1464d52ebf10SThomas Chou cmd.cmdarg = 1; 1465d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 1466d52ebf10SThomas Chou 1467d52ebf10SThomas Chou if (err) 1468d52ebf10SThomas Chou return err; 1469d52ebf10SThomas Chou } 1470d52ebf10SThomas Chou #endif 1471d52ebf10SThomas Chou 1472272cc70bSAndy Fleming /* Put the Card in Identify Mode */ 1473d52ebf10SThomas Chou cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : 1474d52ebf10SThomas Chou MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ 1475272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1476272cc70bSAndy Fleming cmd.cmdarg = 0; 1477272cc70bSAndy Fleming 1478272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1479272cc70bSAndy Fleming 1480272cc70bSAndy Fleming if (err) 1481272cc70bSAndy Fleming return err; 1482272cc70bSAndy Fleming 1483272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16); 1484272cc70bSAndy Fleming 1485272cc70bSAndy Fleming /* 1486272cc70bSAndy Fleming * For MMC cards, set the Relative Address. 1487272cc70bSAndy Fleming * For SD cards, get the Relatvie Address. 1488272cc70bSAndy Fleming * This also puts the cards into Standby State 1489272cc70bSAndy Fleming */ 1490d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1491272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; 1492272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1493272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6; 1494272cc70bSAndy Fleming 1495272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1496272cc70bSAndy Fleming 1497272cc70bSAndy Fleming if (err) 1498272cc70bSAndy Fleming return err; 1499272cc70bSAndy Fleming 1500272cc70bSAndy Fleming if (IS_SD(mmc)) 1501998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff; 1502d52ebf10SThomas Chou } 1503272cc70bSAndy Fleming 1504272cc70bSAndy Fleming /* Get the Card-Specific Data */ 1505272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD; 1506272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1507272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1508272cc70bSAndy Fleming 1509272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1510272cc70bSAndy Fleming 1511272cc70bSAndy Fleming if (err) 1512272cc70bSAndy Fleming return err; 1513272cc70bSAndy Fleming 1514998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0]; 1515998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1]; 1516998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2]; 1517998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3]; 1518272cc70bSAndy Fleming 1519272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) { 15200b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf; 1521272cc70bSAndy Fleming 1522272cc70bSAndy Fleming switch (version) { 1523272cc70bSAndy Fleming case 0: 1524272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1525272cc70bSAndy Fleming break; 1526272cc70bSAndy Fleming case 1: 1527272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4; 1528272cc70bSAndy Fleming break; 1529272cc70bSAndy Fleming case 2: 1530272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2; 1531272cc70bSAndy Fleming break; 1532272cc70bSAndy Fleming case 3: 1533272cc70bSAndy Fleming mmc->version = MMC_VERSION_3; 1534272cc70bSAndy Fleming break; 1535272cc70bSAndy Fleming case 4: 1536272cc70bSAndy Fleming mmc->version = MMC_VERSION_4; 1537272cc70bSAndy Fleming break; 1538272cc70bSAndy Fleming default: 1539272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1540272cc70bSAndy Fleming break; 1541272cc70bSAndy Fleming } 1542272cc70bSAndy Fleming } 1543272cc70bSAndy Fleming 1544272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */ 15450b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)]; 15460b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; 1547272cc70bSAndy Fleming 1548272cc70bSAndy Fleming mmc->tran_speed = freq * mult; 1549272cc70bSAndy Fleming 1550ab71188cSMarkus Niebel mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); 1551998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); 1552272cc70bSAndy Fleming 1553272cc70bSAndy Fleming if (IS_SD(mmc)) 1554272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len; 1555272cc70bSAndy Fleming else 1556998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); 1557272cc70bSAndy Fleming 1558272cc70bSAndy Fleming if (mmc->high_capacity) { 1559272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16 1560272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16; 1561272cc70bSAndy Fleming cmult = 8; 1562272cc70bSAndy Fleming } else { 1563272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2 1564272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30; 1565272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15; 1566272cc70bSAndy Fleming } 1567272cc70bSAndy Fleming 1568f866a46dSStephen Warren mmc->capacity_user = (csize + 1) << (cmult + 2); 1569f866a46dSStephen Warren mmc->capacity_user *= mmc->read_bl_len; 1570f866a46dSStephen Warren mmc->capacity_boot = 0; 1571f866a46dSStephen Warren mmc->capacity_rpmb = 0; 1572f866a46dSStephen Warren for (i = 0; i < 4; i++) 1573f866a46dSStephen Warren mmc->capacity_gp[i] = 0; 1574272cc70bSAndy Fleming 15758bfa195eSSimon Glass if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN) 15768bfa195eSSimon Glass mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 1577272cc70bSAndy Fleming 15788bfa195eSSimon Glass if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) 15798bfa195eSSimon Glass mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 1580272cc70bSAndy Fleming 1581ab71188cSMarkus Niebel if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) { 1582ab71188cSMarkus Niebel cmd.cmdidx = MMC_CMD_SET_DSR; 1583ab71188cSMarkus Niebel cmd.cmdarg = (mmc->dsr & 0xffff) << 16; 1584ab71188cSMarkus Niebel cmd.resp_type = MMC_RSP_NONE; 1585ab71188cSMarkus Niebel if (mmc_send_cmd(mmc, &cmd, NULL)) 1586ab71188cSMarkus Niebel printf("MMC: SET_DSR failed\n"); 1587ab71188cSMarkus Niebel } 1588ab71188cSMarkus Niebel 1589272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */ 1590d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1591272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD; 1592fe8f7066SAjay Bhargav cmd.resp_type = MMC_RSP_R1; 1593272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1594272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1595272cc70bSAndy Fleming 1596272cc70bSAndy Fleming if (err) 1597272cc70bSAndy Fleming return err; 1598d52ebf10SThomas Chou } 1599272cc70bSAndy Fleming 1600e6f99a56SLei Wen /* 1601e6f99a56SLei Wen * For SD, its erase group is always one sector 1602e6f99a56SLei Wen */ 1603e6f99a56SLei Wen mmc->erase_grp_size = 1; 1604bc897b1dSLei Wen mmc->part_config = MMCPART_NOAVAILABLE; 1605d23e2c09SSukumar Ghorai if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) { 1606d23e2c09SSukumar Ghorai /* check ext_csd version and capacity */ 1607d23e2c09SSukumar Ghorai err = mmc_send_ext_csd(mmc, ext_csd); 16089cf199ebSDiego Santa Cruz if (err) 16099cf199ebSDiego Santa Cruz return err; 16109cf199ebSDiego Santa Cruz if (ext_csd[EXT_CSD_REV] >= 2) { 1611639b7827SYoshihiro Shimoda /* 1612639b7827SYoshihiro Shimoda * According to the JEDEC Standard, the value of 1613639b7827SYoshihiro Shimoda * ext_csd's capacity is valid if the value is more 1614639b7827SYoshihiro Shimoda * than 2GB 1615639b7827SYoshihiro Shimoda */ 16160560db18SLei Wen capacity = ext_csd[EXT_CSD_SEC_CNT] << 0 16170560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 16180560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 16190560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; 16208bfa195eSSimon Glass capacity *= MMC_MAX_BLOCK_LEN; 1621b1f1e821SŁukasz Majewski if ((capacity >> 20) > 2 * 1024) 1622f866a46dSStephen Warren mmc->capacity_user = capacity; 1623d23e2c09SSukumar Ghorai } 1624bc897b1dSLei Wen 162564f4a619SJaehoon Chung switch (ext_csd[EXT_CSD_REV]) { 162664f4a619SJaehoon Chung case 1: 162764f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_1; 162864f4a619SJaehoon Chung break; 162964f4a619SJaehoon Chung case 2: 163064f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_2; 163164f4a619SJaehoon Chung break; 163264f4a619SJaehoon Chung case 3: 163364f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_3; 163464f4a619SJaehoon Chung break; 163564f4a619SJaehoon Chung case 5: 163664f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_41; 163764f4a619SJaehoon Chung break; 163864f4a619SJaehoon Chung case 6: 163964f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_5; 164064f4a619SJaehoon Chung break; 1641edab723bSMarkus Niebel case 7: 1642edab723bSMarkus Niebel mmc->version = MMC_VERSION_5_0; 1643edab723bSMarkus Niebel break; 16441a3619cfSStefan Wahren case 8: 16451a3619cfSStefan Wahren mmc->version = MMC_VERSION_5_1; 16461a3619cfSStefan Wahren break; 164764f4a619SJaehoon Chung } 164864f4a619SJaehoon Chung 16498a0cf490SDiego Santa Cruz /* The partition data may be non-zero but it is only 16508a0cf490SDiego Santa Cruz * effective if PARTITION_SETTING_COMPLETED is set in 16518a0cf490SDiego Santa Cruz * EXT_CSD, so ignore any data if this bit is not set, 16528a0cf490SDiego Santa Cruz * except for enabling the high-capacity group size 16538a0cf490SDiego Santa Cruz * definition (see below). */ 16548a0cf490SDiego Santa Cruz part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] & 16558a0cf490SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 16568a0cf490SDiego Santa Cruz 16570c453bb7SDiego Santa Cruz /* store the partition info of emmc */ 16580c453bb7SDiego Santa Cruz mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT]; 16590c453bb7SDiego Santa Cruz if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || 16600c453bb7SDiego Santa Cruz ext_csd[EXT_CSD_BOOT_MULT]) 16610c453bb7SDiego Santa Cruz mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; 16628a0cf490SDiego Santa Cruz if (part_completed && 16638a0cf490SDiego Santa Cruz (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT)) 16640c453bb7SDiego Santa Cruz mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]; 16650c453bb7SDiego Santa Cruz 16660c453bb7SDiego Santa Cruz mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17; 16670c453bb7SDiego Santa Cruz 16680c453bb7SDiego Santa Cruz mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17; 16690c453bb7SDiego Santa Cruz 16700c453bb7SDiego Santa Cruz for (i = 0; i < 4; i++) { 16710c453bb7SDiego Santa Cruz int idx = EXT_CSD_GP_SIZE_MULT + i * 3; 16728a0cf490SDiego Santa Cruz uint mult = (ext_csd[idx + 2] << 16) + 16730c453bb7SDiego Santa Cruz (ext_csd[idx + 1] << 8) + ext_csd[idx]; 16748a0cf490SDiego Santa Cruz if (mult) 16758a0cf490SDiego Santa Cruz has_parts = true; 16768a0cf490SDiego Santa Cruz if (!part_completed) 16778a0cf490SDiego Santa Cruz continue; 16788a0cf490SDiego Santa Cruz mmc->capacity_gp[i] = mult; 16790c453bb7SDiego Santa Cruz mmc->capacity_gp[i] *= 16800c453bb7SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 16810c453bb7SDiego Santa Cruz mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1682f8e89d67SDiego Santa Cruz mmc->capacity_gp[i] <<= 19; 16830c453bb7SDiego Santa Cruz } 16840c453bb7SDiego Santa Cruz 16858a0cf490SDiego Santa Cruz if (part_completed) { 1686a7f852b6SDiego Santa Cruz mmc->enh_user_size = 1687a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_SIZE_MULT+2] << 16) + 1688a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_SIZE_MULT+1] << 8) + 1689a7f852b6SDiego Santa Cruz ext_csd[EXT_CSD_ENH_SIZE_MULT]; 1690a7f852b6SDiego Santa Cruz mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1691a7f852b6SDiego Santa Cruz mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1692a7f852b6SDiego Santa Cruz mmc->enh_user_size <<= 19; 1693a7f852b6SDiego Santa Cruz mmc->enh_user_start = 1694a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_START_ADDR+3] << 24) + 1695a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_START_ADDR+2] << 16) + 1696a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_START_ADDR+1] << 8) + 1697a7f852b6SDiego Santa Cruz ext_csd[EXT_CSD_ENH_START_ADDR]; 1698a7f852b6SDiego Santa Cruz if (mmc->high_capacity) 1699a7f852b6SDiego Santa Cruz mmc->enh_user_start <<= 9; 17008a0cf490SDiego Santa Cruz } 1701a7f852b6SDiego Santa Cruz 1702e6f99a56SLei Wen /* 17031937e5aaSOliver Metz * Host needs to enable ERASE_GRP_DEF bit if device is 17041937e5aaSOliver Metz * partitioned. This bit will be lost every time after a reset 17051937e5aaSOliver Metz * or power off. This will affect erase size. 1706e6f99a56SLei Wen */ 17078a0cf490SDiego Santa Cruz if (part_completed) 17080c453bb7SDiego Santa Cruz has_parts = true; 17091937e5aaSOliver Metz if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) && 17100c453bb7SDiego Santa Cruz (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) 17110c453bb7SDiego Santa Cruz has_parts = true; 17120c453bb7SDiego Santa Cruz if (has_parts) { 17131937e5aaSOliver Metz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 17141937e5aaSOliver Metz EXT_CSD_ERASE_GROUP_DEF, 1); 17151937e5aaSOliver Metz 17161937e5aaSOliver Metz if (err) 17171937e5aaSOliver Metz return err; 1718021a8055SHannes Petermaier else 1719021a8055SHannes Petermaier ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 1720037dc0abSDiego Santa Cruz } 17211937e5aaSOliver Metz 1722037dc0abSDiego Santa Cruz if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) { 17231937e5aaSOliver Metz /* Read out group size from ext_csd */ 17240560db18SLei Wen mmc->erase_grp_size = 1725a4ff9f83SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 1726d7b29129SMarkus Niebel /* 1727d7b29129SMarkus Niebel * if high capacity and partition setting completed 1728d7b29129SMarkus Niebel * SEC_COUNT is valid even if it is smaller than 2 GiB 1729d7b29129SMarkus Niebel * JEDEC Standard JESD84-B45, 6.2.4 1730d7b29129SMarkus Niebel */ 17318a0cf490SDiego Santa Cruz if (mmc->high_capacity && part_completed) { 1732d7b29129SMarkus Niebel capacity = (ext_csd[EXT_CSD_SEC_CNT]) | 1733d7b29129SMarkus Niebel (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) | 1734d7b29129SMarkus Niebel (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) | 1735d7b29129SMarkus Niebel (ext_csd[EXT_CSD_SEC_CNT + 3] << 24); 1736d7b29129SMarkus Niebel capacity *= MMC_MAX_BLOCK_LEN; 1737d7b29129SMarkus Niebel mmc->capacity_user = capacity; 1738d7b29129SMarkus Niebel } 17398bfa195eSSimon Glass } else { 17401937e5aaSOliver Metz /* Calculate the group size from the csd value. */ 1741e6f99a56SLei Wen int erase_gsz, erase_gmul; 1742e6f99a56SLei Wen erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; 1743e6f99a56SLei Wen erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; 1744e6f99a56SLei Wen mmc->erase_grp_size = (erase_gsz + 1) 1745e6f99a56SLei Wen * (erase_gmul + 1); 1746e6f99a56SLei Wen } 1747037dc0abSDiego Santa Cruz 1748037dc0abSDiego Santa Cruz mmc->hc_wp_grp_size = 1024 1749037dc0abSDiego Santa Cruz * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 1750037dc0abSDiego Santa Cruz * ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 17519e41a00bSDiego Santa Cruz 17529e41a00bSDiego Santa Cruz mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 1753f866a46dSStephen Warren } 1754f866a46dSStephen Warren 1755c40fdca6SSimon Glass err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart); 1756f866a46dSStephen Warren if (err) 1757f866a46dSStephen Warren return err; 1758d23e2c09SSukumar Ghorai 1759272cc70bSAndy Fleming if (IS_SD(mmc)) 1760272cc70bSAndy Fleming err = sd_change_freq(mmc); 1761272cc70bSAndy Fleming else 1762272cc70bSAndy Fleming err = mmc_change_freq(mmc); 1763272cc70bSAndy Fleming 1764272cc70bSAndy Fleming if (err) 1765272cc70bSAndy Fleming return err; 1766272cc70bSAndy Fleming 1767272cc70bSAndy Fleming /* Restrict card's capabilities by what the host can do */ 176893bfd616SPantelis Antoniou mmc->card_caps &= mmc->cfg->host_caps; 1769272cc70bSAndy Fleming 1770272cc70bSAndy Fleming if (IS_SD(mmc)) { 1771272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_4BIT) { 1772272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 1773272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1774272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1775272cc70bSAndy Fleming 1776272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1777272cc70bSAndy Fleming if (err) 1778272cc70bSAndy Fleming return err; 1779272cc70bSAndy Fleming 1780272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; 1781272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1782272cc70bSAndy Fleming cmd.cmdarg = 2; 1783272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1784272cc70bSAndy Fleming if (err) 1785272cc70bSAndy Fleming return err; 1786272cc70bSAndy Fleming 1787272cc70bSAndy Fleming mmc_set_bus_width(mmc, 4); 1788272cc70bSAndy Fleming } 1789272cc70bSAndy Fleming 17903697e599SPeng Fan err = sd_read_ssr(mmc); 17913697e599SPeng Fan if (err) 17923697e599SPeng Fan return err; 17933697e599SPeng Fan 1794272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS) 1795ad5fd922SJaehoon Chung mmc->tran_speed = 50000000; 1796272cc70bSAndy Fleming else 1797ad5fd922SJaehoon Chung mmc->tran_speed = 25000000; 1798ad5fd922SJaehoon Chung 1799ad5fd922SJaehoon Chung mmc_set_clock(mmc, mmc->tran_speed); 180049dba033SZiyuan Xu } 1801272cc70bSAndy Fleming 18025af8f45cSAndrew Gabbasov /* Fix the block length for DDR mode */ 180349dba033SZiyuan Xu if (mmc_card_ddr(mmc)) { 18045af8f45cSAndrew Gabbasov mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 18055af8f45cSAndrew Gabbasov mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 18065af8f45cSAndrew Gabbasov } 18075af8f45cSAndrew Gabbasov 1808272cc70bSAndy Fleming /* fill in device description */ 1809c40fdca6SSimon Glass bdesc = mmc_get_blk_desc(mmc); 1810c40fdca6SSimon Glass bdesc->lun = 0; 1811c40fdca6SSimon Glass bdesc->hwpart = 0; 1812c40fdca6SSimon Glass bdesc->type = 0; 1813c40fdca6SSimon Glass bdesc->blksz = mmc->read_bl_len; 1814c40fdca6SSimon Glass bdesc->log2blksz = LOG2(bdesc->blksz); 1815c40fdca6SSimon Glass bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len); 1816fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \ 1817fc011f64SSjoerd Simons (defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \ 1818fc011f64SSjoerd Simons !defined(CONFIG_USE_TINY_PRINTF)) 1819c40fdca6SSimon Glass sprintf(bdesc->vendor, "Man %06x Snr %04x%04x", 1820babce5f6STaylor Hutt mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), 1821babce5f6STaylor Hutt (mmc->cid[3] >> 16) & 0xffff); 1822c40fdca6SSimon Glass sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff, 18230b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 1824babce5f6STaylor Hutt (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff, 1825babce5f6STaylor Hutt (mmc->cid[2] >> 24) & 0xff); 1826c40fdca6SSimon Glass sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf, 1827babce5f6STaylor Hutt (mmc->cid[2] >> 16) & 0xf); 182856196826SPaul Burton #else 1829c40fdca6SSimon Glass bdesc->vendor[0] = 0; 1830c40fdca6SSimon Glass bdesc->product[0] = 0; 1831c40fdca6SSimon Glass bdesc->revision[0] = 0; 183256196826SPaul Burton #endif 1833122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT) 1834c40fdca6SSimon Glass part_init(bdesc); 1835122efd43SMikhail Kshevetskiy #endif 1836272cc70bSAndy Fleming 1837272cc70bSAndy Fleming return 0; 1838272cc70bSAndy Fleming } 1839272cc70bSAndy Fleming 1840fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc) 1841272cc70bSAndy Fleming { 1842272cc70bSAndy Fleming struct mmc_cmd cmd; 1843272cc70bSAndy Fleming int err; 1844272cc70bSAndy Fleming 1845272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND; 1846272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ 184793bfd616SPantelis Antoniou cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa; 1848272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7; 1849272cc70bSAndy Fleming 1850272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1851272cc70bSAndy Fleming 1852272cc70bSAndy Fleming if (err) 1853272cc70bSAndy Fleming return err; 1854272cc70bSAndy Fleming 1855998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa) 1856915ffa52SJaehoon Chung return -EOPNOTSUPP; 1857272cc70bSAndy Fleming else 1858272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 1859272cc70bSAndy Fleming 1860272cc70bSAndy Fleming return 0; 1861272cc70bSAndy Fleming } 1862272cc70bSAndy Fleming 1863c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 186495de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */ 186595de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void) 186695de9ab2SPaul Kocialkowski { 186795de9ab2SPaul Kocialkowski } 186805cbeb7cSSimon Glass #endif 186995de9ab2SPaul Kocialkowski 18702051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc) 18712051aefeSPeng Fan { 1872c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 187305cbeb7cSSimon Glass #if defined(CONFIG_DM_REGULATOR) && !defined(CONFIG_SPL_BUILD) 18742051aefeSPeng Fan struct udevice *vmmc_supply; 18752051aefeSPeng Fan int ret; 18762051aefeSPeng Fan 18772051aefeSPeng Fan ret = device_get_supply_regulator(mmc->dev, "vmmc-supply", 18782051aefeSPeng Fan &vmmc_supply); 18792051aefeSPeng Fan if (ret) { 1880288db7c7SJaehoon Chung debug("%s: No vmmc supply\n", mmc->dev->name); 18812051aefeSPeng Fan return 0; 18822051aefeSPeng Fan } 18832051aefeSPeng Fan 18842051aefeSPeng Fan ret = regulator_set_enable(vmmc_supply, true); 18852051aefeSPeng Fan if (ret) { 18862051aefeSPeng Fan puts("Error enabling VMMC supply\n"); 18872051aefeSPeng Fan return ret; 18882051aefeSPeng Fan } 18892051aefeSPeng Fan #endif 189005cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */ 189105cbeb7cSSimon Glass /* 189205cbeb7cSSimon Glass * Driver model should use a regulator, as above, rather than calling 189305cbeb7cSSimon Glass * out to board code. 189405cbeb7cSSimon Glass */ 189505cbeb7cSSimon Glass board_mmc_power_init(); 189605cbeb7cSSimon Glass #endif 18972051aefeSPeng Fan return 0; 18982051aefeSPeng Fan } 18992051aefeSPeng Fan 1900e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc) 1901272cc70bSAndy Fleming { 19028ca51e51SSimon Glass bool no_card; 1903afd5932bSMacpaul Lin int err; 1904272cc70bSAndy Fleming 1905ab769f22SPantelis Antoniou /* we pretend there's no card when init is NULL */ 19068ca51e51SSimon Glass no_card = mmc_getcd(mmc) == 0; 1907e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 19088ca51e51SSimon Glass no_card = no_card || (mmc->cfg->ops->init == NULL); 19098ca51e51SSimon Glass #endif 19108ca51e51SSimon Glass if (no_card) { 191148972d90SThierry Reding mmc->has_init = 0; 191256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 191348972d90SThierry Reding printf("MMC: no card present\n"); 191456196826SPaul Burton #endif 1915915ffa52SJaehoon Chung return -ENOMEDIUM; 191648972d90SThierry Reding } 191748972d90SThierry Reding 1918bc897b1dSLei Wen if (mmc->has_init) 1919bc897b1dSLei Wen return 0; 1920bc897b1dSLei Wen 19215a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 19225a8dbdc6SYangbo Lu mmc_adapter_card_type_ident(); 19235a8dbdc6SYangbo Lu #endif 19242051aefeSPeng Fan err = mmc_power_init(mmc); 19252051aefeSPeng Fan if (err) 19262051aefeSPeng Fan return err; 192795de9ab2SPaul Kocialkowski 1928e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 19298ca51e51SSimon Glass /* The device has already been probed ready for use */ 19308ca51e51SSimon Glass #else 1931ab769f22SPantelis Antoniou /* made sure it's not NULL earlier */ 193293bfd616SPantelis Antoniou err = mmc->cfg->ops->init(mmc); 1933272cc70bSAndy Fleming if (err) 1934272cc70bSAndy Fleming return err; 19358ca51e51SSimon Glass #endif 1936b86b85e2SIlya Yanok mmc_set_bus_width(mmc, 1); 1937b86b85e2SIlya Yanok mmc_set_clock(mmc, 1); 193881db2d36SZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_LEGACY); 1939b86b85e2SIlya Yanok 1940272cc70bSAndy Fleming /* Reset the Card */ 1941272cc70bSAndy Fleming err = mmc_go_idle(mmc); 1942272cc70bSAndy Fleming 1943272cc70bSAndy Fleming if (err) 1944272cc70bSAndy Fleming return err; 1945272cc70bSAndy Fleming 1946bc897b1dSLei Wen /* The internal partition reset to user partition(0) at every CMD0*/ 1947c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->hwpart = 0; 1948bc897b1dSLei Wen 1949272cc70bSAndy Fleming /* Test for SD version 2 */ 1950272cc70bSAndy Fleming err = mmc_send_if_cond(mmc); 1951272cc70bSAndy Fleming 1952272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */ 1953272cc70bSAndy Fleming err = sd_send_op_cond(mmc); 1954272cc70bSAndy Fleming 1955272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */ 1956915ffa52SJaehoon Chung if (err == -ETIMEDOUT) { 1957272cc70bSAndy Fleming err = mmc_send_op_cond(mmc); 1958272cc70bSAndy Fleming 1959bd47c135SAndrew Gabbasov if (err) { 196056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 1961272cc70bSAndy Fleming printf("Card did not respond to voltage select!\n"); 196256196826SPaul Burton #endif 1963915ffa52SJaehoon Chung return -EOPNOTSUPP; 1964272cc70bSAndy Fleming } 1965272cc70bSAndy Fleming } 1966272cc70bSAndy Fleming 1967bd47c135SAndrew Gabbasov if (!err) 1968e9550449SChe-Liang Chiou mmc->init_in_progress = 1; 1969e9550449SChe-Liang Chiou 1970e9550449SChe-Liang Chiou return err; 1971e9550449SChe-Liang Chiou } 1972e9550449SChe-Liang Chiou 1973e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc) 1974e9550449SChe-Liang Chiou { 1975e9550449SChe-Liang Chiou int err = 0; 1976e9550449SChe-Liang Chiou 1977bd47c135SAndrew Gabbasov mmc->init_in_progress = 0; 1978e9550449SChe-Liang Chiou if (mmc->op_cond_pending) 1979e9550449SChe-Liang Chiou err = mmc_complete_op_cond(mmc); 1980e9550449SChe-Liang Chiou 1981e9550449SChe-Liang Chiou if (!err) 1982bc897b1dSLei Wen err = mmc_startup(mmc); 1983bc897b1dSLei Wen if (err) 1984bc897b1dSLei Wen mmc->has_init = 0; 1985bc897b1dSLei Wen else 1986bc897b1dSLei Wen mmc->has_init = 1; 1987e9550449SChe-Liang Chiou return err; 1988e9550449SChe-Liang Chiou } 1989e9550449SChe-Liang Chiou 1990e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc) 1991e9550449SChe-Liang Chiou { 1992bd47c135SAndrew Gabbasov int err = 0; 1993ce9eca94SMarek Vasut __maybe_unused unsigned start; 1994c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 199533fb211dSSimon Glass struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev); 1996e9550449SChe-Liang Chiou 199733fb211dSSimon Glass upriv->mmc = mmc; 199833fb211dSSimon Glass #endif 1999e9550449SChe-Liang Chiou if (mmc->has_init) 2000e9550449SChe-Liang Chiou return 0; 2001d803fea5SMateusz Zalega 2002d803fea5SMateusz Zalega start = get_timer(0); 2003d803fea5SMateusz Zalega 2004e9550449SChe-Liang Chiou if (!mmc->init_in_progress) 2005e9550449SChe-Liang Chiou err = mmc_start_init(mmc); 2006e9550449SChe-Liang Chiou 2007bd47c135SAndrew Gabbasov if (!err) 2008e9550449SChe-Liang Chiou err = mmc_complete_init(mmc); 2009919b4858SJagan Teki if (err) 2010919b4858SJagan Teki printf("%s: %d, time %lu\n", __func__, err, get_timer(start)); 2011919b4858SJagan Teki 2012bc897b1dSLei Wen return err; 2013272cc70bSAndy Fleming } 2014272cc70bSAndy Fleming 2015ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val) 2016ab71188cSMarkus Niebel { 2017ab71188cSMarkus Niebel mmc->dsr = val; 2018ab71188cSMarkus Niebel return 0; 2019ab71188cSMarkus Niebel } 2020ab71188cSMarkus Niebel 2021cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */ 2022cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis) 2023272cc70bSAndy Fleming { 2024272cc70bSAndy Fleming return -1; 2025272cc70bSAndy Fleming } 2026272cc70bSAndy Fleming 2027cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */ 2028cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis) 2029cee9ab7cSJeroen Hofstee { 2030cee9ab7cSJeroen Hofstee return -1; 2031cee9ab7cSJeroen Hofstee } 2032272cc70bSAndy Fleming 2033e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit) 2034e9550449SChe-Liang Chiou { 2035e9550449SChe-Liang Chiou mmc->preinit = preinit; 2036e9550449SChe-Liang Chiou } 2037e9550449SChe-Liang Chiou 2038c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD) 20398e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 20408e3332e2SSjoerd Simons { 20418e3332e2SSjoerd Simons return 0; 20428e3332e2SSjoerd Simons } 2043c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC) 20448e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 20458e3332e2SSjoerd Simons { 20464a1db6d8SSimon Glass int ret, i; 20478e3332e2SSjoerd Simons struct uclass *uc; 20484a1db6d8SSimon Glass struct udevice *dev; 20498e3332e2SSjoerd Simons 20508e3332e2SSjoerd Simons ret = uclass_get(UCLASS_MMC, &uc); 20518e3332e2SSjoerd Simons if (ret) 20528e3332e2SSjoerd Simons return ret; 20538e3332e2SSjoerd Simons 20544a1db6d8SSimon Glass /* 20554a1db6d8SSimon Glass * Try to add them in sequence order. Really with driver model we 20564a1db6d8SSimon Glass * should allow holes, but the current MMC list does not allow that. 20574a1db6d8SSimon Glass * So if we request 0, 1, 3 we will get 0, 1, 2. 20584a1db6d8SSimon Glass */ 20594a1db6d8SSimon Glass for (i = 0; ; i++) { 20604a1db6d8SSimon Glass ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev); 20614a1db6d8SSimon Glass if (ret == -ENODEV) 20624a1db6d8SSimon Glass break; 20634a1db6d8SSimon Glass } 20644a1db6d8SSimon Glass uclass_foreach_dev(dev, uc) { 20654a1db6d8SSimon Glass ret = device_probe(dev); 20668e3332e2SSjoerd Simons if (ret) 20674a1db6d8SSimon Glass printf("%s - probe failed: %d\n", dev->name, ret); 20688e3332e2SSjoerd Simons } 20698e3332e2SSjoerd Simons 20708e3332e2SSjoerd Simons return 0; 20718e3332e2SSjoerd Simons } 20728e3332e2SSjoerd Simons #else 20738e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 20748e3332e2SSjoerd Simons { 20758e3332e2SSjoerd Simons if (board_mmc_init(bis) < 0) 20768e3332e2SSjoerd Simons cpu_mmc_init(bis); 20778e3332e2SSjoerd Simons 20788e3332e2SSjoerd Simons return 0; 20798e3332e2SSjoerd Simons } 20808e3332e2SSjoerd Simons #endif 2081e9550449SChe-Liang Chiou 2082272cc70bSAndy Fleming int mmc_initialize(bd_t *bis) 2083272cc70bSAndy Fleming { 20841b26bab1SDaniel Kochmański static int initialized = 0; 20858e3332e2SSjoerd Simons int ret; 20861b26bab1SDaniel Kochmański if (initialized) /* Avoid initializing mmc multiple times */ 20871b26bab1SDaniel Kochmański return 0; 20881b26bab1SDaniel Kochmański initialized = 1; 20891b26bab1SDaniel Kochmański 2090c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK) 2091b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY) 2092c40fdca6SSimon Glass mmc_list_init(); 2093c40fdca6SSimon Glass #endif 2094b5b838f1SMarek Vasut #endif 20958e3332e2SSjoerd Simons ret = mmc_probe(bis); 20968e3332e2SSjoerd Simons if (ret) 20978e3332e2SSjoerd Simons return ret; 2098272cc70bSAndy Fleming 2099bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD 2100272cc70bSAndy Fleming print_mmc_devices(','); 2101bb0dc108SYing Zhang #endif 2102272cc70bSAndy Fleming 2103c40fdca6SSimon Glass mmc_do_preinit(); 2104272cc70bSAndy Fleming return 0; 2105272cc70bSAndy Fleming } 2106cd3d4880STomas Melin 2107cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE 2108cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc) 2109cd3d4880STomas Melin { 2110cd3d4880STomas Melin int err; 2111cd3d4880STomas Melin ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 2112cd3d4880STomas Melin 2113cd3d4880STomas Melin err = mmc_send_ext_csd(mmc, ext_csd); 2114cd3d4880STomas Melin if (err) { 2115cd3d4880STomas Melin puts("Could not get ext_csd register values\n"); 2116cd3d4880STomas Melin return err; 2117cd3d4880STomas Melin } 2118cd3d4880STomas Melin 2119cd3d4880STomas Melin if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) { 2120cd3d4880STomas Melin puts("Background operations not supported on device\n"); 2121cd3d4880STomas Melin return -EMEDIUMTYPE; 2122cd3d4880STomas Melin } 2123cd3d4880STomas Melin 2124cd3d4880STomas Melin if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) { 2125cd3d4880STomas Melin puts("Background operations already enabled\n"); 2126cd3d4880STomas Melin return 0; 2127cd3d4880STomas Melin } 2128cd3d4880STomas Melin 2129cd3d4880STomas Melin err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1); 2130cd3d4880STomas Melin if (err) { 2131cd3d4880STomas Melin puts("Failed to enable manual background operations\n"); 2132cd3d4880STomas Melin return err; 2133cd3d4880STomas Melin } 2134cd3d4880STomas Melin 2135cd3d4880STomas Melin puts("Enabled manual background operations\n"); 2136cd3d4880STomas Melin 2137cd3d4880STomas Melin return 0; 2138cd3d4880STomas Melin } 2139cd3d4880STomas Melin #endif 2140