1272cc70bSAndy Fleming /* 2272cc70bSAndy Fleming * Copyright 2008, Freescale Semiconductor, Inc 3272cc70bSAndy Fleming * Andy Fleming 4272cc70bSAndy Fleming * 5272cc70bSAndy Fleming * Based vaguely on the Linux code 6272cc70bSAndy Fleming * 71a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 8272cc70bSAndy Fleming */ 9272cc70bSAndy Fleming 10272cc70bSAndy Fleming #include <config.h> 11272cc70bSAndy Fleming #include <common.h> 12272cc70bSAndy Fleming #include <command.h> 138e3332e2SSjoerd Simons #include <dm.h> 148e3332e2SSjoerd Simons #include <dm/device-internal.h> 15d4622df3SStephen Warren #include <errno.h> 16272cc70bSAndy Fleming #include <mmc.h> 17272cc70bSAndy Fleming #include <part.h> 182051aefeSPeng Fan #include <power/regulator.h> 19272cc70bSAndy Fleming #include <malloc.h> 20cf92e05cSSimon Glass #include <memalign.h> 21272cc70bSAndy Fleming #include <linux/list.h> 229b1f942cSRabin Vincent #include <div64.h> 23da61fa5fSPaul Burton #include "mmc_private.h" 24272cc70bSAndy Fleming 253697e599SPeng Fan static const unsigned int sd_au_size[] = { 263697e599SPeng Fan 0, SZ_16K / 512, SZ_32K / 512, 273697e599SPeng Fan SZ_64K / 512, SZ_128K / 512, SZ_256K / 512, 283697e599SPeng Fan SZ_512K / 512, SZ_1M / 512, SZ_2M / 512, 293697e599SPeng Fan SZ_4M / 512, SZ_8M / 512, (SZ_8M + SZ_4M) / 512, 303697e599SPeng Fan SZ_16M / 512, (SZ_16M + SZ_8M) / 512, SZ_32M / 512, SZ_64M / 512, 313697e599SPeng Fan }; 323697e599SPeng Fan 33b5b838f1SMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY) 34b5b838f1SMarek Vasut static struct mmc mmc_static; 35b5b838f1SMarek Vasut struct mmc *find_mmc_device(int dev_num) 36b5b838f1SMarek Vasut { 37b5b838f1SMarek Vasut return &mmc_static; 38b5b838f1SMarek Vasut } 39b5b838f1SMarek Vasut 40b5b838f1SMarek Vasut void mmc_do_preinit(void) 41b5b838f1SMarek Vasut { 42b5b838f1SMarek Vasut struct mmc *m = &mmc_static; 43b5b838f1SMarek Vasut #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 44b5b838f1SMarek Vasut mmc_set_preinit(m, 1); 45b5b838f1SMarek Vasut #endif 46b5b838f1SMarek Vasut if (m->preinit) 47b5b838f1SMarek Vasut mmc_start_init(m); 48b5b838f1SMarek Vasut } 49b5b838f1SMarek Vasut 50b5b838f1SMarek Vasut struct blk_desc *mmc_get_blk_desc(struct mmc *mmc) 51b5b838f1SMarek Vasut { 52b5b838f1SMarek Vasut return &mmc->block_dev; 53b5b838f1SMarek Vasut } 54b5b838f1SMarek Vasut #endif 55b5b838f1SMarek Vasut 56e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 57750121c3SJeroen Hofstee __weak int board_mmc_getwp(struct mmc *mmc) 58d23d8d7eSNikita Kiryanov { 59d23d8d7eSNikita Kiryanov return -1; 60d23d8d7eSNikita Kiryanov } 61d23d8d7eSNikita Kiryanov 62d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc) 63d23d8d7eSNikita Kiryanov { 64d23d8d7eSNikita Kiryanov int wp; 65d23d8d7eSNikita Kiryanov 66d23d8d7eSNikita Kiryanov wp = board_mmc_getwp(mmc); 67d23d8d7eSNikita Kiryanov 68d4e1da4eSPeter Korsgaard if (wp < 0) { 6993bfd616SPantelis Antoniou if (mmc->cfg->ops->getwp) 7093bfd616SPantelis Antoniou wp = mmc->cfg->ops->getwp(mmc); 71d4e1da4eSPeter Korsgaard else 72d4e1da4eSPeter Korsgaard wp = 0; 73d4e1da4eSPeter Korsgaard } 74d23d8d7eSNikita Kiryanov 75d23d8d7eSNikita Kiryanov return wp; 76d23d8d7eSNikita Kiryanov } 77d23d8d7eSNikita Kiryanov 78cee9ab7cSJeroen Hofstee __weak int board_mmc_getcd(struct mmc *mmc) 79cee9ab7cSJeroen Hofstee { 8011fdade2SStefano Babic return -1; 8111fdade2SStefano Babic } 828ca51e51SSimon Glass #endif 8311fdade2SStefano Babic 848635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE 85c0c76ebaSSimon Glass void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd) 86c0c76ebaSSimon Glass { 87c0c76ebaSSimon Glass printf("CMD_SEND:%d\n", cmd->cmdidx); 88c0c76ebaSSimon Glass printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg); 89c0c76ebaSSimon Glass } 90c0c76ebaSSimon Glass 91c0c76ebaSSimon Glass void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret) 92c0c76ebaSSimon Glass { 935db2fe3aSRaffaele Recalcati int i; 945db2fe3aSRaffaele Recalcati u8 *ptr; 955db2fe3aSRaffaele Recalcati 967863ce58SBin Meng if (ret) { 977863ce58SBin Meng printf("\t\tRET\t\t\t %d\n", ret); 987863ce58SBin Meng } else { 995db2fe3aSRaffaele Recalcati switch (cmd->resp_type) { 1005db2fe3aSRaffaele Recalcati case MMC_RSP_NONE: 1015db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_NONE\n"); 1025db2fe3aSRaffaele Recalcati break; 1035db2fe3aSRaffaele Recalcati case MMC_RSP_R1: 1045db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n", 1055db2fe3aSRaffaele Recalcati cmd->response[0]); 1065db2fe3aSRaffaele Recalcati break; 1075db2fe3aSRaffaele Recalcati case MMC_RSP_R1b: 1085db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n", 1095db2fe3aSRaffaele Recalcati cmd->response[0]); 1105db2fe3aSRaffaele Recalcati break; 1115db2fe3aSRaffaele Recalcati case MMC_RSP_R2: 1125db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R2\t\t 0x%08X \n", 1135db2fe3aSRaffaele Recalcati cmd->response[0]); 1145db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1155db2fe3aSRaffaele Recalcati cmd->response[1]); 1165db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1175db2fe3aSRaffaele Recalcati cmd->response[2]); 1185db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1195db2fe3aSRaffaele Recalcati cmd->response[3]); 1205db2fe3aSRaffaele Recalcati printf("\n"); 1215db2fe3aSRaffaele Recalcati printf("\t\t\t\t\tDUMPING DATA\n"); 1225db2fe3aSRaffaele Recalcati for (i = 0; i < 4; i++) { 1235db2fe3aSRaffaele Recalcati int j; 1245db2fe3aSRaffaele Recalcati printf("\t\t\t\t\t%03d - ", i*4); 125146bec79SDirk Behme ptr = (u8 *)&cmd->response[i]; 1265db2fe3aSRaffaele Recalcati ptr += 3; 1275db2fe3aSRaffaele Recalcati for (j = 0; j < 4; j++) 1285db2fe3aSRaffaele Recalcati printf("%02X ", *ptr--); 1295db2fe3aSRaffaele Recalcati printf("\n"); 1305db2fe3aSRaffaele Recalcati } 1315db2fe3aSRaffaele Recalcati break; 1325db2fe3aSRaffaele Recalcati case MMC_RSP_R3: 1335db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n", 1345db2fe3aSRaffaele Recalcati cmd->response[0]); 1355db2fe3aSRaffaele Recalcati break; 1365db2fe3aSRaffaele Recalcati default: 1375db2fe3aSRaffaele Recalcati printf("\t\tERROR MMC rsp not supported\n"); 1385db2fe3aSRaffaele Recalcati break; 1395db2fe3aSRaffaele Recalcati } 1407863ce58SBin Meng } 141c0c76ebaSSimon Glass } 142c0c76ebaSSimon Glass 143c0c76ebaSSimon Glass void mmc_trace_state(struct mmc *mmc, struct mmc_cmd *cmd) 144c0c76ebaSSimon Glass { 145c0c76ebaSSimon Glass int status; 146c0c76ebaSSimon Glass 147c0c76ebaSSimon Glass status = (cmd->response[0] & MMC_STATUS_CURR_STATE) >> 9; 148c0c76ebaSSimon Glass printf("CURR STATE:%d\n", status); 149c0c76ebaSSimon Glass } 1505db2fe3aSRaffaele Recalcati #endif 151c0c76ebaSSimon Glass 152e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 153c0c76ebaSSimon Glass int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) 154c0c76ebaSSimon Glass { 155c0c76ebaSSimon Glass int ret; 156c0c76ebaSSimon Glass 157c0c76ebaSSimon Glass mmmc_trace_before_send(mmc, cmd); 158c0c76ebaSSimon Glass ret = mmc->cfg->ops->send_cmd(mmc, cmd, data); 159c0c76ebaSSimon Glass mmmc_trace_after_send(mmc, cmd, ret); 160c0c76ebaSSimon Glass 1618635ff9eSMarek Vasut return ret; 162272cc70bSAndy Fleming } 1638ca51e51SSimon Glass #endif 164272cc70bSAndy Fleming 165da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout) 1665d4fc8d9SRaffaele Recalcati { 1675d4fc8d9SRaffaele Recalcati struct mmc_cmd cmd; 168d617c426SJan Kloetzke int err, retries = 5; 1695d4fc8d9SRaffaele Recalcati 1705d4fc8d9SRaffaele Recalcati cmd.cmdidx = MMC_CMD_SEND_STATUS; 1715d4fc8d9SRaffaele Recalcati cmd.resp_type = MMC_RSP_R1; 172aaf3d41aSMarek Vasut if (!mmc_host_is_spi(mmc)) 173aaf3d41aSMarek Vasut cmd.cmdarg = mmc->rca << 16; 1745d4fc8d9SRaffaele Recalcati 1751677eef4SAndrew Gabbasov while (1) { 1765d4fc8d9SRaffaele Recalcati err = mmc_send_cmd(mmc, &cmd, NULL); 177d617c426SJan Kloetzke if (!err) { 178d617c426SJan Kloetzke if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) && 179d617c426SJan Kloetzke (cmd.response[0] & MMC_STATUS_CURR_STATE) != 180d617c426SJan Kloetzke MMC_STATE_PRG) 1815d4fc8d9SRaffaele Recalcati break; 182d617c426SJan Kloetzke else if (cmd.response[0] & MMC_STATUS_MASK) { 18356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 184d617c426SJan Kloetzke printf("Status Error: 0x%08X\n", 185d617c426SJan Kloetzke cmd.response[0]); 18656196826SPaul Burton #endif 187915ffa52SJaehoon Chung return -ECOMM; 188d617c426SJan Kloetzke } 189d617c426SJan Kloetzke } else if (--retries < 0) 190d617c426SJan Kloetzke return err; 1915d4fc8d9SRaffaele Recalcati 1921677eef4SAndrew Gabbasov if (timeout-- <= 0) 1931677eef4SAndrew Gabbasov break; 1945d4fc8d9SRaffaele Recalcati 1951677eef4SAndrew Gabbasov udelay(1000); 1961677eef4SAndrew Gabbasov } 1975d4fc8d9SRaffaele Recalcati 198c0c76ebaSSimon Glass mmc_trace_state(mmc, &cmd); 1995b0c942fSJongman Heo if (timeout <= 0) { 20056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2015d4fc8d9SRaffaele Recalcati printf("Timeout waiting card ready\n"); 20256196826SPaul Burton #endif 203915ffa52SJaehoon Chung return -ETIMEDOUT; 2045d4fc8d9SRaffaele Recalcati } 2055d4fc8d9SRaffaele Recalcati 2065d4fc8d9SRaffaele Recalcati return 0; 2075d4fc8d9SRaffaele Recalcati } 2085d4fc8d9SRaffaele Recalcati 209da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len) 210272cc70bSAndy Fleming { 211272cc70bSAndy Fleming struct mmc_cmd cmd; 212272cc70bSAndy Fleming 213caa21a21SZiyuan Xu if (mmc_card_ddr(mmc)) 214d22e3d46SJaehoon Chung return 0; 215d22e3d46SJaehoon Chung 216272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SET_BLOCKLEN; 217272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 218272cc70bSAndy Fleming cmd.cmdarg = len; 219272cc70bSAndy Fleming 220272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, NULL); 221272cc70bSAndy Fleming } 222272cc70bSAndy Fleming 223ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start, 224fdbb873eSKim Phillips lbaint_t blkcnt) 225272cc70bSAndy Fleming { 226272cc70bSAndy Fleming struct mmc_cmd cmd; 227272cc70bSAndy Fleming struct mmc_data data; 228272cc70bSAndy Fleming 2294a1a06bcSAlagu Sankar if (blkcnt > 1) 2304a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; 2314a1a06bcSAlagu Sankar else 232272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; 233272cc70bSAndy Fleming 234272cc70bSAndy Fleming if (mmc->high_capacity) 2354a1a06bcSAlagu Sankar cmd.cmdarg = start; 236272cc70bSAndy Fleming else 2374a1a06bcSAlagu Sankar cmd.cmdarg = start * mmc->read_bl_len; 238272cc70bSAndy Fleming 239272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 240272cc70bSAndy Fleming 241272cc70bSAndy Fleming data.dest = dst; 2424a1a06bcSAlagu Sankar data.blocks = blkcnt; 243272cc70bSAndy Fleming data.blocksize = mmc->read_bl_len; 244272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 245272cc70bSAndy Fleming 2464a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, &data)) 2474a1a06bcSAlagu Sankar return 0; 2484a1a06bcSAlagu Sankar 2494a1a06bcSAlagu Sankar if (blkcnt > 1) { 2504a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; 2514a1a06bcSAlagu Sankar cmd.cmdarg = 0; 2524a1a06bcSAlagu Sankar cmd.resp_type = MMC_RSP_R1b; 2534a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, NULL)) { 25456196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2554a1a06bcSAlagu Sankar printf("mmc fail to send stop cmd\n"); 25656196826SPaul Burton #endif 2574a1a06bcSAlagu Sankar return 0; 2584a1a06bcSAlagu Sankar } 259272cc70bSAndy Fleming } 260272cc70bSAndy Fleming 2614a1a06bcSAlagu Sankar return blkcnt; 262272cc70bSAndy Fleming } 263272cc70bSAndy Fleming 264c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK) 2657dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst) 26633fb211dSSimon Glass #else 2677dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, 2687dba0b93SSimon Glass void *dst) 26933fb211dSSimon Glass #endif 270272cc70bSAndy Fleming { 271c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK) 27233fb211dSSimon Glass struct blk_desc *block_dev = dev_get_uclass_platdata(dev); 27333fb211dSSimon Glass #endif 274bcce53d0SSimon Glass int dev_num = block_dev->devnum; 275873cc1d7SStephen Warren int err; 2764a1a06bcSAlagu Sankar lbaint_t cur, blocks_todo = blkcnt; 277272cc70bSAndy Fleming 2784a1a06bcSAlagu Sankar if (blkcnt == 0) 2794a1a06bcSAlagu Sankar return 0; 2804a1a06bcSAlagu Sankar 2814a1a06bcSAlagu Sankar struct mmc *mmc = find_mmc_device(dev_num); 282272cc70bSAndy Fleming if (!mmc) 283272cc70bSAndy Fleming return 0; 284272cc70bSAndy Fleming 285b5b838f1SMarek Vasut if (CONFIG_IS_ENABLED(MMC_TINY)) 286b5b838f1SMarek Vasut err = mmc_switch_part(mmc, block_dev->hwpart); 287b5b838f1SMarek Vasut else 28869f45cd5SSimon Glass err = blk_dselect_hwpart(block_dev, block_dev->hwpart); 289b5b838f1SMarek Vasut 290873cc1d7SStephen Warren if (err < 0) 291873cc1d7SStephen Warren return 0; 292873cc1d7SStephen Warren 293c40fdca6SSimon Glass if ((start + blkcnt) > block_dev->lba) { 29456196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 295ff8fef56SSascha Silbe printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", 296c40fdca6SSimon Glass start + blkcnt, block_dev->lba); 29756196826SPaul Burton #endif 298d2bf29e3SLei Wen return 0; 299d2bf29e3SLei Wen } 300272cc70bSAndy Fleming 30111692991SSimon Glass if (mmc_set_blocklen(mmc, mmc->read_bl_len)) { 30211692991SSimon Glass debug("%s: Failed to set blocklen\n", __func__); 303272cc70bSAndy Fleming return 0; 30411692991SSimon Glass } 305272cc70bSAndy Fleming 3064a1a06bcSAlagu Sankar do { 30793bfd616SPantelis Antoniou cur = (blocks_todo > mmc->cfg->b_max) ? 30893bfd616SPantelis Antoniou mmc->cfg->b_max : blocks_todo; 30911692991SSimon Glass if (mmc_read_blocks(mmc, dst, start, cur) != cur) { 31011692991SSimon Glass debug("%s: Failed to read blocks\n", __func__); 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 7985545757fSZiyuan Xu static int mmc_select_hs_ddr(struct mmc *mmc) 7995545757fSZiyuan Xu { 8005545757fSZiyuan Xu u32 ext_csd_bits; 8015545757fSZiyuan Xu int err = 0; 8025545757fSZiyuan Xu 8035545757fSZiyuan Xu if (mmc->bus_width == MMC_BUS_WIDTH_1BIT) 8045545757fSZiyuan Xu return 0; 8055545757fSZiyuan Xu 8065545757fSZiyuan Xu ext_csd_bits = (mmc->bus_width == MMC_BUS_WIDTH_8BIT) ? 8075545757fSZiyuan Xu EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4; 8085545757fSZiyuan Xu 8095545757fSZiyuan Xu err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 8105545757fSZiyuan Xu EXT_CSD_BUS_WIDTH, ext_csd_bits); 8115545757fSZiyuan Xu if (err) 8125545757fSZiyuan Xu return err; 8135545757fSZiyuan Xu 8145545757fSZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_MMC_DDR52); 8155545757fSZiyuan Xu 8165545757fSZiyuan Xu return 0; 8175545757fSZiyuan Xu } 8185545757fSZiyuan Xu 81949dba033SZiyuan Xu #ifndef CONFIG_SPL_BUILD 82049dba033SZiyuan Xu static int mmc_select_hs200(struct mmc *mmc) 82149dba033SZiyuan Xu { 82249dba033SZiyuan Xu int ret; 82349dba033SZiyuan Xu struct mmc_cmd cmd; 82449dba033SZiyuan Xu 82549dba033SZiyuan Xu /* 82649dba033SZiyuan Xu * Set the bus width(4 or 8) with host's support and 82749dba033SZiyuan Xu * switch to HS200 mode if bus width is set successfully. 82849dba033SZiyuan Xu */ 82949dba033SZiyuan Xu ret = mmc_select_bus_width(mmc); 83049dba033SZiyuan Xu 83149dba033SZiyuan Xu if (ret > 0) { 83249dba033SZiyuan Xu ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 83349dba033SZiyuan Xu EXT_CSD_HS_TIMING, 83449dba033SZiyuan Xu EXT_CSD_TIMING_HS200, false); 83549dba033SZiyuan Xu 83649dba033SZiyuan Xu if (ret) 83749dba033SZiyuan Xu return ret; 83849dba033SZiyuan Xu 83949dba033SZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_MMC_HS200); 84049dba033SZiyuan Xu 84149dba033SZiyuan Xu cmd.cmdidx = MMC_CMD_SEND_STATUS; 84249dba033SZiyuan Xu cmd.resp_type = MMC_RSP_R1; 84349dba033SZiyuan Xu cmd.cmdarg = mmc->rca << 16; 84449dba033SZiyuan Xu 84549dba033SZiyuan Xu ret = mmc_send_cmd(mmc, &cmd, NULL); 84649dba033SZiyuan Xu 84749dba033SZiyuan Xu if (ret) 84849dba033SZiyuan Xu return ret; 84949dba033SZiyuan Xu 85049dba033SZiyuan Xu if (cmd.response[0] & MMC_STATUS_SWITCH_ERROR) 85149dba033SZiyuan Xu return -EBADMSG; 85249dba033SZiyuan Xu } 85349dba033SZiyuan Xu 85449dba033SZiyuan Xu return ret; 85549dba033SZiyuan Xu } 85649dba033SZiyuan Xu #endif 85749dba033SZiyuan Xu 858b673f29aSZiyuan Xu static int mmc_select_hs400(struct mmc *mmc) 859b673f29aSZiyuan Xu { 860b673f29aSZiyuan Xu int ret; 861b673f29aSZiyuan Xu 862b673f29aSZiyuan Xu /* Switch card to HS mode */ 863b673f29aSZiyuan Xu ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 864b673f29aSZiyuan Xu EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS, false); 865b673f29aSZiyuan Xu if (ret) 866b673f29aSZiyuan Xu return ret; 867b673f29aSZiyuan Xu 868b673f29aSZiyuan Xu /* Set host controller to HS timing */ 869b673f29aSZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_MMC_HS); 870b673f29aSZiyuan Xu 871b673f29aSZiyuan Xu /* Reduce frequency to HS frequency */ 872b673f29aSZiyuan Xu mmc_set_clock(mmc, MMC_HIGH_52_MAX_DTR); 873b673f29aSZiyuan Xu 874b673f29aSZiyuan Xu ret = mmc_send_status(mmc, 1000); 875b673f29aSZiyuan Xu if (ret) 876b673f29aSZiyuan Xu return ret; 877b673f29aSZiyuan Xu 878b673f29aSZiyuan Xu /* Switch card to DDR */ 879b673f29aSZiyuan Xu ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 880b673f29aSZiyuan Xu EXT_CSD_BUS_WIDTH, 881b673f29aSZiyuan Xu EXT_CSD_DDR_BUS_WIDTH_8); 882b673f29aSZiyuan Xu if (ret) 883b673f29aSZiyuan Xu return ret; 884b673f29aSZiyuan Xu 885b673f29aSZiyuan Xu /* Switch card to HS400 */ 886b673f29aSZiyuan Xu ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 887b673f29aSZiyuan Xu EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400, false); 888b673f29aSZiyuan Xu if (ret) 889b673f29aSZiyuan Xu return ret; 890b673f29aSZiyuan Xu 891b673f29aSZiyuan Xu /* Set host controller to HS400 timing and frequency */ 892b673f29aSZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_MMC_HS400); 893b673f29aSZiyuan Xu 894b673f29aSZiyuan Xu return ret; 895b673f29aSZiyuan Xu } 896b673f29aSZiyuan Xu 897227f658eSZiyuan Xu static u32 mmc_select_card_type(struct mmc *mmc, u8 *ext_csd) 898227f658eSZiyuan Xu { 899227f658eSZiyuan Xu u8 card_type; 900227f658eSZiyuan Xu u32 host_caps, avail_type = 0; 901227f658eSZiyuan Xu 902227f658eSZiyuan Xu card_type = ext_csd[EXT_CSD_CARD_TYPE]; 903227f658eSZiyuan Xu host_caps = mmc->cfg->host_caps; 904227f658eSZiyuan Xu 905227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS) && 906227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_26)) 907227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_26; 908227f658eSZiyuan Xu 909227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS) && 910227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_52)) 911227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_52; 912227f658eSZiyuan Xu 913227f658eSZiyuan Xu /* 914227f658eSZiyuan Xu * For the moment, u-boot doesn't support signal voltage 915227f658eSZiyuan Xu * switch, therefor we assume that host support ddr52 916227f658eSZiyuan Xu * at 1.8v or 3.3v I/O(1.2v I/O not supported, hs200 and 917227f658eSZiyuan Xu * hs400 are the same). 918227f658eSZiyuan Xu */ 919227f658eSZiyuan Xu if ((host_caps & MMC_MODE_DDR_52MHz) && 920227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_DDR_1_8V)) 921227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V; 922227f658eSZiyuan Xu 923227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS200) && 924227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_HS200_1_8V)) 925227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V; 926227f658eSZiyuan Xu 927227f658eSZiyuan Xu /* 928227f658eSZiyuan Xu * If host can support HS400, it means that host can also 929227f658eSZiyuan Xu * support HS200. 930227f658eSZiyuan Xu */ 931227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS400) && 932227f658eSZiyuan Xu (host_caps & MMC_MODE_8BIT) && 933227f658eSZiyuan Xu (card_type & EXT_CSD_CARD_TYPE_HS400_1_8V)) 934227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V | 935227f658eSZiyuan Xu EXT_CSD_CARD_TYPE_HS400_1_8V; 936227f658eSZiyuan Xu 937227f658eSZiyuan Xu if ((host_caps & MMC_MODE_HS400ES) && 938227f658eSZiyuan Xu (host_caps & MMC_MODE_8BIT) && 939227f658eSZiyuan Xu ext_csd[EXT_CSD_STROBE_SUPPORT] && 940227f658eSZiyuan Xu (avail_type & EXT_CSD_CARD_TYPE_HS400_1_8V)) 941227f658eSZiyuan Xu avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V | 942227f658eSZiyuan Xu EXT_CSD_CARD_TYPE_HS400_1_8V | 943227f658eSZiyuan Xu EXT_CSD_CARD_TYPE_HS400ES; 944227f658eSZiyuan Xu 945227f658eSZiyuan Xu return avail_type; 946227f658eSZiyuan Xu } 947227f658eSZiyuan Xu 94849dba033SZiyuan Xu static void mmc_set_bus_speed(struct mmc *mmc, u8 avail_type) 94949dba033SZiyuan Xu { 95049dba033SZiyuan Xu int clock = 0; 95149dba033SZiyuan Xu 95249dba033SZiyuan Xu if (mmc_card_hs(mmc)) 95349dba033SZiyuan Xu clock = (avail_type & EXT_CSD_CARD_TYPE_52) ? 95449dba033SZiyuan Xu MMC_HIGH_52_MAX_DTR : MMC_HIGH_26_MAX_DTR; 95549dba033SZiyuan Xu else if (mmc_card_hs200(mmc) || 95649dba033SZiyuan Xu mmc_card_hs400(mmc) || 95749dba033SZiyuan Xu mmc_card_hs400es(mmc)) 95849dba033SZiyuan Xu clock = MMC_HS200_MAX_DTR; 95949dba033SZiyuan Xu 96049dba033SZiyuan Xu mmc_set_clock(mmc, clock); 96149dba033SZiyuan Xu } 96249dba033SZiyuan Xu 963fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc) 964272cc70bSAndy Fleming { 9658bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 966227f658eSZiyuan Xu u32 avail_type; 967272cc70bSAndy Fleming int err; 968272cc70bSAndy Fleming 969fc5b32fbSAndrew Gabbasov mmc->card_caps = 0; 970272cc70bSAndy Fleming 971d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 972d52ebf10SThomas Chou return 0; 973d52ebf10SThomas Chou 974272cc70bSAndy Fleming /* Only version 4 supports high-speed */ 975272cc70bSAndy Fleming if (mmc->version < MMC_VERSION_4) 976272cc70bSAndy Fleming return 0; 977272cc70bSAndy Fleming 978fc5b32fbSAndrew Gabbasov mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; 979fc5b32fbSAndrew Gabbasov 980272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 981272cc70bSAndy Fleming 982272cc70bSAndy Fleming if (err) 983272cc70bSAndy Fleming return err; 984272cc70bSAndy Fleming 985227f658eSZiyuan Xu avail_type = mmc_select_card_type(mmc, ext_csd); 986272cc70bSAndy Fleming 98749dba033SZiyuan Xu #ifndef CONFIG_SPL_BUILD 98849dba033SZiyuan Xu if (avail_type & EXT_CSD_CARD_TYPE_HS200) 98949dba033SZiyuan Xu err = mmc_select_hs200(mmc); 99049dba033SZiyuan Xu else 99149dba033SZiyuan Xu #endif 992227f658eSZiyuan Xu if (avail_type & EXT_CSD_CARD_TYPE_HS) 993e61cd3d7SZiyuan Xu err = mmc_select_hs(mmc); 994227f658eSZiyuan Xu else 995227f658eSZiyuan Xu err = -EINVAL; 996272cc70bSAndy Fleming 997272cc70bSAndy Fleming if (err) 998a5e27b41SHeiko Schocher return err; 999272cc70bSAndy Fleming 100049dba033SZiyuan Xu mmc_set_bus_speed(mmc, avail_type); 1001272cc70bSAndy Fleming 1002b673f29aSZiyuan Xu if (mmc_card_hs200(mmc)) { 100349dba033SZiyuan Xu err = mmc_hs200_tuning(mmc); 1004b673f29aSZiyuan Xu if (avail_type & EXT_CSD_CARD_TYPE_HS400 && 1005b673f29aSZiyuan Xu mmc->bus_width == MMC_BUS_WIDTH_8BIT) { 1006b673f29aSZiyuan Xu err = mmc_select_hs400(mmc); 1007b673f29aSZiyuan Xu mmc_set_bus_speed(mmc, avail_type); 1008b673f29aSZiyuan Xu } 1009b673f29aSZiyuan Xu } else if (!mmc_card_hs400es(mmc)) { 101049dba033SZiyuan Xu err = mmc_select_bus_width(mmc) > 0 ? 0 : err; 10115545757fSZiyuan Xu if (!err && avail_type & EXT_CSD_CARD_TYPE_DDR_52) 10125545757fSZiyuan Xu err = mmc_select_hs_ddr(mmc); 10135545757fSZiyuan Xu } 101449dba033SZiyuan Xu 1015272cc70bSAndy Fleming return err; 1016272cc70bSAndy Fleming } 1017272cc70bSAndy Fleming 1018f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num) 1019f866a46dSStephen Warren { 1020f866a46dSStephen Warren switch (part_num) { 1021f866a46dSStephen Warren case 0: 1022f866a46dSStephen Warren mmc->capacity = mmc->capacity_user; 1023f866a46dSStephen Warren break; 1024f866a46dSStephen Warren case 1: 1025f866a46dSStephen Warren case 2: 1026f866a46dSStephen Warren mmc->capacity = mmc->capacity_boot; 1027f866a46dSStephen Warren break; 1028f866a46dSStephen Warren case 3: 1029f866a46dSStephen Warren mmc->capacity = mmc->capacity_rpmb; 1030f866a46dSStephen Warren break; 1031f866a46dSStephen Warren case 4: 1032f866a46dSStephen Warren case 5: 1033f866a46dSStephen Warren case 6: 1034f866a46dSStephen Warren case 7: 1035f866a46dSStephen Warren mmc->capacity = mmc->capacity_gp[part_num - 4]; 1036f866a46dSStephen Warren break; 1037f866a46dSStephen Warren default: 1038f866a46dSStephen Warren return -1; 1039f866a46dSStephen Warren } 1040f866a46dSStephen Warren 1041c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len); 1042f866a46dSStephen Warren 1043f866a46dSStephen Warren return 0; 1044f866a46dSStephen Warren } 1045f866a46dSStephen Warren 10467dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num) 1047bc897b1dSLei Wen { 1048f866a46dSStephen Warren int ret; 1049bc897b1dSLei Wen 1050f866a46dSStephen Warren ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 1051bc897b1dSLei Wen (mmc->part_config & ~PART_ACCESS_MASK) 1052bc897b1dSLei Wen | (part_num & PART_ACCESS_MASK)); 1053f866a46dSStephen Warren 10546dc93e70SPeter Bigot /* 10556dc93e70SPeter Bigot * Set the capacity if the switch succeeded or was intended 10566dc93e70SPeter Bigot * to return to representing the raw device. 10576dc93e70SPeter Bigot */ 1058873cc1d7SStephen Warren if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) { 10596dc93e70SPeter Bigot ret = mmc_set_capacity(mmc, part_num); 1060fdbb139fSSimon Glass mmc_get_blk_desc(mmc)->hwpart = part_num; 1061873cc1d7SStephen Warren } 10626dc93e70SPeter Bigot 10636dc93e70SPeter Bigot return ret; 1064bc897b1dSLei Wen } 1065bc897b1dSLei Wen 1066ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc, 1067ac9da0e0SDiego Santa Cruz const struct mmc_hwpart_conf *conf, 1068ac9da0e0SDiego Santa Cruz enum mmc_hwpart_conf_mode mode) 1069ac9da0e0SDiego Santa Cruz { 1070ac9da0e0SDiego Santa Cruz u8 part_attrs = 0; 1071ac9da0e0SDiego Santa Cruz u32 enh_size_mult; 1072ac9da0e0SDiego Santa Cruz u32 enh_start_addr; 1073ac9da0e0SDiego Santa Cruz u32 gp_size_mult[4]; 1074ac9da0e0SDiego Santa Cruz u32 max_enh_size_mult; 1075ac9da0e0SDiego Santa Cruz u32 tot_enh_size_mult = 0; 10768dda5b0eSDiego Santa Cruz u8 wr_rel_set; 1077ac9da0e0SDiego Santa Cruz int i, pidx, err; 1078ac9da0e0SDiego Santa Cruz ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 1079ac9da0e0SDiego Santa Cruz 1080ac9da0e0SDiego Santa Cruz if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE) 1081ac9da0e0SDiego Santa Cruz return -EINVAL; 1082ac9da0e0SDiego Santa Cruz 1083ac9da0e0SDiego Santa Cruz if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) { 1084ac9da0e0SDiego Santa Cruz printf("eMMC >= 4.4 required for enhanced user data area\n"); 1085ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1086ac9da0e0SDiego Santa Cruz } 1087ac9da0e0SDiego Santa Cruz 1088ac9da0e0SDiego Santa Cruz if (!(mmc->part_support & PART_SUPPORT)) { 1089ac9da0e0SDiego Santa Cruz printf("Card does not support partitioning\n"); 1090ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1091ac9da0e0SDiego Santa Cruz } 1092ac9da0e0SDiego Santa Cruz 1093ac9da0e0SDiego Santa Cruz if (!mmc->hc_wp_grp_size) { 1094ac9da0e0SDiego Santa Cruz printf("Card does not define HC WP group size\n"); 1095ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1096ac9da0e0SDiego Santa Cruz } 1097ac9da0e0SDiego Santa Cruz 1098ac9da0e0SDiego Santa Cruz /* check partition alignment and total enhanced size */ 1099ac9da0e0SDiego Santa Cruz if (conf->user.enh_size) { 1100ac9da0e0SDiego Santa Cruz if (conf->user.enh_size % mmc->hc_wp_grp_size || 1101ac9da0e0SDiego Santa Cruz conf->user.enh_start % mmc->hc_wp_grp_size) { 1102ac9da0e0SDiego Santa Cruz printf("User data enhanced area not HC WP group " 1103ac9da0e0SDiego Santa Cruz "size aligned\n"); 1104ac9da0e0SDiego Santa Cruz return -EINVAL; 1105ac9da0e0SDiego Santa Cruz } 1106ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_USR; 1107ac9da0e0SDiego Santa Cruz enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size; 1108ac9da0e0SDiego Santa Cruz if (mmc->high_capacity) { 1109ac9da0e0SDiego Santa Cruz enh_start_addr = conf->user.enh_start; 1110ac9da0e0SDiego Santa Cruz } else { 1111ac9da0e0SDiego Santa Cruz enh_start_addr = (conf->user.enh_start << 9); 1112ac9da0e0SDiego Santa Cruz } 1113ac9da0e0SDiego Santa Cruz } else { 1114ac9da0e0SDiego Santa Cruz enh_size_mult = 0; 1115ac9da0e0SDiego Santa Cruz enh_start_addr = 0; 1116ac9da0e0SDiego Santa Cruz } 1117ac9da0e0SDiego Santa Cruz tot_enh_size_mult += enh_size_mult; 1118ac9da0e0SDiego Santa Cruz 1119ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 1120ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) { 1121ac9da0e0SDiego Santa Cruz printf("GP%i partition not HC WP group size " 1122ac9da0e0SDiego Santa Cruz "aligned\n", pidx+1); 1123ac9da0e0SDiego Santa Cruz return -EINVAL; 1124ac9da0e0SDiego Santa Cruz } 1125ac9da0e0SDiego Santa Cruz gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size; 1126ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) { 1127ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_GP(pidx); 1128ac9da0e0SDiego Santa Cruz tot_enh_size_mult += gp_size_mult[pidx]; 1129ac9da0e0SDiego Santa Cruz } 1130ac9da0e0SDiego Santa Cruz } 1131ac9da0e0SDiego Santa Cruz 1132ac9da0e0SDiego Santa Cruz if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) { 1133ac9da0e0SDiego Santa Cruz printf("Card does not support enhanced attribute\n"); 1134ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1135ac9da0e0SDiego Santa Cruz } 1136ac9da0e0SDiego Santa Cruz 1137ac9da0e0SDiego Santa Cruz err = mmc_send_ext_csd(mmc, ext_csd); 1138ac9da0e0SDiego Santa Cruz if (err) 1139ac9da0e0SDiego Santa Cruz return err; 1140ac9da0e0SDiego Santa Cruz 1141ac9da0e0SDiego Santa Cruz max_enh_size_mult = 1142ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) + 1143ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) + 1144ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]; 1145ac9da0e0SDiego Santa Cruz if (tot_enh_size_mult > max_enh_size_mult) { 1146ac9da0e0SDiego Santa Cruz printf("Total enhanced size exceeds maximum (%u > %u)\n", 1147ac9da0e0SDiego Santa Cruz tot_enh_size_mult, max_enh_size_mult); 1148ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1149ac9da0e0SDiego Santa Cruz } 1150ac9da0e0SDiego Santa Cruz 11518dda5b0eSDiego Santa Cruz /* The default value of EXT_CSD_WR_REL_SET is device 11528dda5b0eSDiego Santa Cruz * dependent, the values can only be changed if the 11538dda5b0eSDiego Santa Cruz * EXT_CSD_HS_CTRL_REL bit is set. The values can be 11548dda5b0eSDiego Santa Cruz * changed only once and before partitioning is completed. */ 11558dda5b0eSDiego Santa Cruz wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 11568dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_change) { 11578dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_set) 11588dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_USR; 11598dda5b0eSDiego Santa Cruz else 11608dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR; 11618dda5b0eSDiego Santa Cruz } 11628dda5b0eSDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 11638dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_change) { 11648dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_set) 11658dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx); 11668dda5b0eSDiego Santa Cruz else 11678dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx); 11688dda5b0eSDiego Santa Cruz } 11698dda5b0eSDiego Santa Cruz } 11708dda5b0eSDiego Santa Cruz 11718dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] && 11728dda5b0eSDiego Santa Cruz !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) { 11738dda5b0eSDiego Santa Cruz puts("Card does not support host controlled partition write " 11748dda5b0eSDiego Santa Cruz "reliability settings\n"); 11758dda5b0eSDiego Santa Cruz return -EMEDIUMTYPE; 11768dda5b0eSDiego Santa Cruz } 11778dda5b0eSDiego Santa Cruz 1178ac9da0e0SDiego Santa Cruz if (ext_csd[EXT_CSD_PARTITION_SETTING] & 1179ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED) { 1180ac9da0e0SDiego Santa Cruz printf("Card already partitioned\n"); 1181ac9da0e0SDiego Santa Cruz return -EPERM; 1182ac9da0e0SDiego Santa Cruz } 1183ac9da0e0SDiego Santa Cruz 1184ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_CHECK) 1185ac9da0e0SDiego Santa Cruz return 0; 1186ac9da0e0SDiego Santa Cruz 1187ac9da0e0SDiego Santa Cruz /* Partitioning requires high-capacity size definitions */ 1188ac9da0e0SDiego Santa Cruz if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) { 1189ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1190ac9da0e0SDiego Santa Cruz EXT_CSD_ERASE_GROUP_DEF, 1); 1191ac9da0e0SDiego Santa Cruz 1192ac9da0e0SDiego Santa Cruz if (err) 1193ac9da0e0SDiego Santa Cruz return err; 1194ac9da0e0SDiego Santa Cruz 1195ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 1196ac9da0e0SDiego Santa Cruz 1197ac9da0e0SDiego Santa Cruz /* update erase group size to be high-capacity */ 1198ac9da0e0SDiego Santa Cruz mmc->erase_grp_size = 1199ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 1200ac9da0e0SDiego Santa Cruz 1201ac9da0e0SDiego Santa Cruz } 1202ac9da0e0SDiego Santa Cruz 1203ac9da0e0SDiego Santa Cruz /* all OK, write the configuration */ 1204ac9da0e0SDiego Santa Cruz for (i = 0; i < 4; i++) { 1205ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1206ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_START_ADDR+i, 1207ac9da0e0SDiego Santa Cruz (enh_start_addr >> (i*8)) & 0xFF); 1208ac9da0e0SDiego Santa Cruz if (err) 1209ac9da0e0SDiego Santa Cruz return err; 1210ac9da0e0SDiego Santa Cruz } 1211ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 1212ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1213ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_SIZE_MULT+i, 1214ac9da0e0SDiego Santa Cruz (enh_size_mult >> (i*8)) & 0xFF); 1215ac9da0e0SDiego Santa Cruz if (err) 1216ac9da0e0SDiego Santa Cruz return err; 1217ac9da0e0SDiego Santa Cruz } 1218ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 1219ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 1220ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1221ac9da0e0SDiego Santa Cruz EXT_CSD_GP_SIZE_MULT+pidx*3+i, 1222ac9da0e0SDiego Santa Cruz (gp_size_mult[pidx] >> (i*8)) & 0xFF); 1223ac9da0e0SDiego Santa Cruz if (err) 1224ac9da0e0SDiego Santa Cruz return err; 1225ac9da0e0SDiego Santa Cruz } 1226ac9da0e0SDiego Santa Cruz } 1227ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1228ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs); 1229ac9da0e0SDiego Santa Cruz if (err) 1230ac9da0e0SDiego Santa Cruz return err; 1231ac9da0e0SDiego Santa Cruz 1232ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_SET) 1233ac9da0e0SDiego Santa Cruz return 0; 1234ac9da0e0SDiego Santa Cruz 12358dda5b0eSDiego Santa Cruz /* The WR_REL_SET is a write-once register but shall be 12368dda5b0eSDiego Santa Cruz * written before setting PART_SETTING_COMPLETED. As it is 12378dda5b0eSDiego Santa Cruz * write-once we can only write it when completing the 12388dda5b0eSDiego Santa Cruz * partitioning. */ 12398dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) { 12408dda5b0eSDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 12418dda5b0eSDiego Santa Cruz EXT_CSD_WR_REL_SET, wr_rel_set); 12428dda5b0eSDiego Santa Cruz if (err) 12438dda5b0eSDiego Santa Cruz return err; 12448dda5b0eSDiego Santa Cruz } 12458dda5b0eSDiego Santa Cruz 1246ac9da0e0SDiego Santa Cruz /* Setting PART_SETTING_COMPLETED confirms the partition 1247ac9da0e0SDiego Santa Cruz * configuration but it only becomes effective after power 1248ac9da0e0SDiego Santa Cruz * cycle, so we do not adjust the partition related settings 1249ac9da0e0SDiego Santa Cruz * in the mmc struct. */ 1250ac9da0e0SDiego Santa Cruz 1251ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1252ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING, 1253ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 1254ac9da0e0SDiego Santa Cruz if (err) 1255ac9da0e0SDiego Santa Cruz return err; 1256ac9da0e0SDiego Santa Cruz 1257ac9da0e0SDiego Santa Cruz return 0; 1258ac9da0e0SDiego Santa Cruz } 1259ac9da0e0SDiego Santa Cruz 1260e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 126148972d90SThierry Reding int mmc_getcd(struct mmc *mmc) 126248972d90SThierry Reding { 126348972d90SThierry Reding int cd; 126448972d90SThierry Reding 126548972d90SThierry Reding cd = board_mmc_getcd(mmc); 126648972d90SThierry Reding 1267d4e1da4eSPeter Korsgaard if (cd < 0) { 126893bfd616SPantelis Antoniou if (mmc->cfg->ops->getcd) 126993bfd616SPantelis Antoniou cd = mmc->cfg->ops->getcd(mmc); 1270d4e1da4eSPeter Korsgaard else 1271d4e1da4eSPeter Korsgaard cd = 1; 1272d4e1da4eSPeter Korsgaard } 127348972d90SThierry Reding 127448972d90SThierry Reding return cd; 127548972d90SThierry Reding } 12768ca51e51SSimon Glass #endif 127748972d90SThierry Reding 1278fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) 1279272cc70bSAndy Fleming { 1280272cc70bSAndy Fleming struct mmc_cmd cmd; 1281272cc70bSAndy Fleming struct mmc_data data; 1282272cc70bSAndy Fleming 1283272cc70bSAndy Fleming /* Switch the frequency */ 1284272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC; 1285272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1286272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff; 1287272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4)); 1288272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4); 1289272cc70bSAndy Fleming 1290272cc70bSAndy Fleming data.dest = (char *)resp; 1291272cc70bSAndy Fleming data.blocksize = 64; 1292272cc70bSAndy Fleming data.blocks = 1; 1293272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1294272cc70bSAndy Fleming 1295272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 1296272cc70bSAndy Fleming } 1297272cc70bSAndy Fleming 1298272cc70bSAndy Fleming 1299fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc) 1300272cc70bSAndy Fleming { 1301272cc70bSAndy Fleming int err; 1302272cc70bSAndy Fleming struct mmc_cmd cmd; 1303f781dd38SAnton staaf ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2); 1304f781dd38SAnton staaf ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16); 1305272cc70bSAndy Fleming struct mmc_data data; 1306272cc70bSAndy Fleming int timeout; 1307272cc70bSAndy Fleming 1308272cc70bSAndy Fleming mmc->card_caps = 0; 1309272cc70bSAndy Fleming 1310d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 1311d52ebf10SThomas Chou return 0; 1312d52ebf10SThomas Chou 1313272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */ 1314272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 1315272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1316272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1317272cc70bSAndy Fleming 1318272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1319272cc70bSAndy Fleming 1320272cc70bSAndy Fleming if (err) 1321272cc70bSAndy Fleming return err; 1322272cc70bSAndy Fleming 1323272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR; 1324272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1325272cc70bSAndy Fleming cmd.cmdarg = 0; 1326272cc70bSAndy Fleming 1327272cc70bSAndy Fleming timeout = 3; 1328272cc70bSAndy Fleming 1329272cc70bSAndy Fleming retry_scr: 1330f781dd38SAnton staaf data.dest = (char *)scr; 1331272cc70bSAndy Fleming data.blocksize = 8; 1332272cc70bSAndy Fleming data.blocks = 1; 1333272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1334272cc70bSAndy Fleming 1335272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 1336272cc70bSAndy Fleming 1337272cc70bSAndy Fleming if (err) { 1338272cc70bSAndy Fleming if (timeout--) 1339272cc70bSAndy Fleming goto retry_scr; 1340272cc70bSAndy Fleming 1341272cc70bSAndy Fleming return err; 1342272cc70bSAndy Fleming } 1343272cc70bSAndy Fleming 13444e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]); 13454e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]); 1346272cc70bSAndy Fleming 1347272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) { 1348272cc70bSAndy Fleming case 0: 1349272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1350272cc70bSAndy Fleming break; 1351272cc70bSAndy Fleming case 1: 1352272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10; 1353272cc70bSAndy Fleming break; 1354272cc70bSAndy Fleming case 2: 1355272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 13561741c64dSJaehoon Chung if ((mmc->scr[0] >> 15) & 0x1) 13571741c64dSJaehoon Chung mmc->version = SD_VERSION_3; 1358272cc70bSAndy Fleming break; 1359272cc70bSAndy Fleming default: 1360272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1361272cc70bSAndy Fleming break; 1362272cc70bSAndy Fleming } 1363272cc70bSAndy Fleming 1364b44c7083SAlagu Sankar if (mmc->scr[0] & SD_DATA_4BIT) 1365b44c7083SAlagu Sankar mmc->card_caps |= MMC_MODE_4BIT; 1366b44c7083SAlagu Sankar 1367272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */ 1368272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0) 1369272cc70bSAndy Fleming return 0; 1370272cc70bSAndy Fleming 1371272cc70bSAndy Fleming timeout = 4; 1372272cc70bSAndy Fleming while (timeout--) { 1373272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, 1374f781dd38SAnton staaf (u8 *)switch_status); 1375272cc70bSAndy Fleming 1376272cc70bSAndy Fleming if (err) 1377272cc70bSAndy Fleming return err; 1378272cc70bSAndy Fleming 1379272cc70bSAndy Fleming /* The high-speed function is busy. Try again */ 13804e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) 1381272cc70bSAndy Fleming break; 1382272cc70bSAndy Fleming } 1383272cc70bSAndy Fleming 1384272cc70bSAndy Fleming /* If high-speed isn't supported, we return */ 13854e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)) 1386272cc70bSAndy Fleming return 0; 1387272cc70bSAndy Fleming 13882c3fbf4cSMacpaul Lin /* 13892c3fbf4cSMacpaul Lin * If the host doesn't support SD_HIGHSPEED, do not switch card to 13902c3fbf4cSMacpaul Lin * HIGHSPEED mode even if the card support SD_HIGHSPPED. 13912c3fbf4cSMacpaul Lin * This can avoid furthur problem when the card runs in different 13922c3fbf4cSMacpaul Lin * mode between the host. 13932c3fbf4cSMacpaul Lin */ 139493bfd616SPantelis Antoniou if (!((mmc->cfg->host_caps & MMC_MODE_HS_52MHz) && 139593bfd616SPantelis Antoniou (mmc->cfg->host_caps & MMC_MODE_HS))) 13962c3fbf4cSMacpaul Lin return 0; 13972c3fbf4cSMacpaul Lin 1398f781dd38SAnton staaf err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status); 1399272cc70bSAndy Fleming 1400272cc70bSAndy Fleming if (err) 1401272cc70bSAndy Fleming return err; 1402272cc70bSAndy Fleming 14034e3d89baSYauhen Kharuzhy if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000) 1404272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS; 1405272cc70bSAndy Fleming 1406272cc70bSAndy Fleming return 0; 1407272cc70bSAndy Fleming } 1408272cc70bSAndy Fleming 14093697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc) 14103697e599SPeng Fan { 14113697e599SPeng Fan int err, i; 14123697e599SPeng Fan struct mmc_cmd cmd; 14133697e599SPeng Fan ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16); 14143697e599SPeng Fan struct mmc_data data; 14153697e599SPeng Fan int timeout = 3; 14163697e599SPeng Fan unsigned int au, eo, et, es; 14173697e599SPeng Fan 14183697e599SPeng Fan cmd.cmdidx = MMC_CMD_APP_CMD; 14193697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 14203697e599SPeng Fan cmd.cmdarg = mmc->rca << 16; 14213697e599SPeng Fan 14223697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, NULL); 14233697e599SPeng Fan if (err) 14243697e599SPeng Fan return err; 14253697e599SPeng Fan 14263697e599SPeng Fan cmd.cmdidx = SD_CMD_APP_SD_STATUS; 14273697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 14283697e599SPeng Fan cmd.cmdarg = 0; 14293697e599SPeng Fan 14303697e599SPeng Fan retry_ssr: 14313697e599SPeng Fan data.dest = (char *)ssr; 14323697e599SPeng Fan data.blocksize = 64; 14333697e599SPeng Fan data.blocks = 1; 14343697e599SPeng Fan data.flags = MMC_DATA_READ; 14353697e599SPeng Fan 14363697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, &data); 14373697e599SPeng Fan if (err) { 14383697e599SPeng Fan if (timeout--) 14393697e599SPeng Fan goto retry_ssr; 14403697e599SPeng Fan 14413697e599SPeng Fan return err; 14423697e599SPeng Fan } 14433697e599SPeng Fan 14443697e599SPeng Fan for (i = 0; i < 16; i++) 14453697e599SPeng Fan ssr[i] = be32_to_cpu(ssr[i]); 14463697e599SPeng Fan 14473697e599SPeng Fan au = (ssr[2] >> 12) & 0xF; 14483697e599SPeng Fan if ((au <= 9) || (mmc->version == SD_VERSION_3)) { 14493697e599SPeng Fan mmc->ssr.au = sd_au_size[au]; 14503697e599SPeng Fan es = (ssr[3] >> 24) & 0xFF; 14513697e599SPeng Fan es |= (ssr[2] & 0xFF) << 8; 14523697e599SPeng Fan et = (ssr[3] >> 18) & 0x3F; 14533697e599SPeng Fan if (es && et) { 14543697e599SPeng Fan eo = (ssr[3] >> 16) & 0x3; 14553697e599SPeng Fan mmc->ssr.erase_timeout = (et * 1000) / es; 14563697e599SPeng Fan mmc->ssr.erase_offset = eo * 1000; 14573697e599SPeng Fan } 14583697e599SPeng Fan } else { 14593697e599SPeng Fan debug("Invalid Allocation Unit Size.\n"); 14603697e599SPeng Fan } 14613697e599SPeng Fan 14623697e599SPeng Fan return 0; 14633697e599SPeng Fan } 14643697e599SPeng Fan 1465272cc70bSAndy Fleming /* frequency bases */ 1466272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */ 14675f837c2cSMike Frysinger static const int fbase[] = { 1468272cc70bSAndy Fleming 10000, 1469272cc70bSAndy Fleming 100000, 1470272cc70bSAndy Fleming 1000000, 1471272cc70bSAndy Fleming 10000000, 1472272cc70bSAndy Fleming }; 1473272cc70bSAndy Fleming 1474272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice 1475272cc70bSAndy Fleming * to platforms without floating point. 1476272cc70bSAndy Fleming */ 147761fe076fSSimon Glass static const u8 multipliers[] = { 1478272cc70bSAndy Fleming 0, /* reserved */ 1479272cc70bSAndy Fleming 10, 1480272cc70bSAndy Fleming 12, 1481272cc70bSAndy Fleming 13, 1482272cc70bSAndy Fleming 15, 1483272cc70bSAndy Fleming 20, 1484272cc70bSAndy Fleming 25, 1485272cc70bSAndy Fleming 30, 1486272cc70bSAndy Fleming 35, 1487272cc70bSAndy Fleming 40, 1488272cc70bSAndy Fleming 45, 1489272cc70bSAndy Fleming 50, 1490272cc70bSAndy Fleming 55, 1491272cc70bSAndy Fleming 60, 1492272cc70bSAndy Fleming 70, 1493272cc70bSAndy Fleming 80, 1494272cc70bSAndy Fleming }; 1495272cc70bSAndy Fleming 1496e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 1497fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc) 1498272cc70bSAndy Fleming { 149993bfd616SPantelis Antoniou if (mmc->cfg->ops->set_ios) 150093bfd616SPantelis Antoniou mmc->cfg->ops->set_ios(mmc); 1501272cc70bSAndy Fleming } 1502ad77484aSZiyuan Xu 1503ad77484aSZiyuan Xu static bool mmc_card_busy(struct mmc *mmc) 1504ad77484aSZiyuan Xu { 1505ad77484aSZiyuan Xu if (!mmc->cfg->ops->card_busy) 1506ad77484aSZiyuan Xu return -ENOSYS; 1507ad77484aSZiyuan Xu 1508ad77484aSZiyuan Xu return mmc->cfg->ops->card_busy(mmc); 1509ad77484aSZiyuan Xu } 1510ad77484aSZiyuan Xu 1511ad77484aSZiyuan Xu static bool mmc_can_card_busy(struct mmc *) 1512ad77484aSZiyuan Xu { 1513ad77484aSZiyuan Xu return !!mmc->cfg->ops->card_busy; 1514ad77484aSZiyuan Xu } 15158ca51e51SSimon Glass #endif 1516272cc70bSAndy Fleming 1517fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc) 1518272cc70bSAndy Fleming { 1519f866a46dSStephen Warren int err, i; 15203e3ff0acSZiyuan Xu uint mult, freq, tran_speed; 1521639b7827SYoshihiro Shimoda u64 cmult, csize, capacity; 1522272cc70bSAndy Fleming struct mmc_cmd cmd; 15238bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 15240c453bb7SDiego Santa Cruz bool has_parts = false; 15258a0cf490SDiego Santa Cruz bool part_completed; 1526c40fdca6SSimon Glass struct blk_desc *bdesc; 1527272cc70bSAndy Fleming 1528d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON 1529d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ 1530d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; 1531d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R1; 1532d52ebf10SThomas Chou cmd.cmdarg = 1; 1533d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 1534d52ebf10SThomas Chou 1535d52ebf10SThomas Chou if (err) 1536d52ebf10SThomas Chou return err; 1537d52ebf10SThomas Chou } 1538d52ebf10SThomas Chou #endif 1539d52ebf10SThomas Chou 1540272cc70bSAndy Fleming /* Put the Card in Identify Mode */ 1541d52ebf10SThomas Chou cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : 1542d52ebf10SThomas Chou MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ 1543272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1544272cc70bSAndy Fleming cmd.cmdarg = 0; 1545272cc70bSAndy Fleming 1546272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1547272cc70bSAndy Fleming 1548272cc70bSAndy Fleming if (err) 1549272cc70bSAndy Fleming return err; 1550272cc70bSAndy Fleming 1551272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16); 1552272cc70bSAndy Fleming 1553272cc70bSAndy Fleming /* 1554272cc70bSAndy Fleming * For MMC cards, set the Relative Address. 1555272cc70bSAndy Fleming * For SD cards, get the Relatvie Address. 1556272cc70bSAndy Fleming * This also puts the cards into Standby State 1557272cc70bSAndy Fleming */ 1558d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1559272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; 1560272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1561272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6; 1562272cc70bSAndy Fleming 1563272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1564272cc70bSAndy Fleming 1565272cc70bSAndy Fleming if (err) 1566272cc70bSAndy Fleming return err; 1567272cc70bSAndy Fleming 1568272cc70bSAndy Fleming if (IS_SD(mmc)) 1569998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff; 1570d52ebf10SThomas Chou } 1571272cc70bSAndy Fleming 1572272cc70bSAndy Fleming /* Get the Card-Specific Data */ 1573272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD; 1574272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1575272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1576272cc70bSAndy Fleming 1577272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1578272cc70bSAndy Fleming 1579272cc70bSAndy Fleming if (err) 1580272cc70bSAndy Fleming return err; 1581272cc70bSAndy Fleming 1582998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0]; 1583998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1]; 1584998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2]; 1585998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3]; 1586272cc70bSAndy Fleming 1587272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) { 15880b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf; 1589272cc70bSAndy Fleming 1590272cc70bSAndy Fleming switch (version) { 1591272cc70bSAndy Fleming case 0: 1592272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1593272cc70bSAndy Fleming break; 1594272cc70bSAndy Fleming case 1: 1595272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4; 1596272cc70bSAndy Fleming break; 1597272cc70bSAndy Fleming case 2: 1598272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2; 1599272cc70bSAndy Fleming break; 1600272cc70bSAndy Fleming case 3: 1601272cc70bSAndy Fleming mmc->version = MMC_VERSION_3; 1602272cc70bSAndy Fleming break; 1603272cc70bSAndy Fleming case 4: 1604272cc70bSAndy Fleming mmc->version = MMC_VERSION_4; 1605272cc70bSAndy Fleming break; 1606272cc70bSAndy Fleming default: 1607272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1608272cc70bSAndy Fleming break; 1609272cc70bSAndy Fleming } 1610272cc70bSAndy Fleming } 1611272cc70bSAndy Fleming 1612272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */ 16130b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)]; 16140b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; 1615272cc70bSAndy Fleming 16163e3ff0acSZiyuan Xu tran_speed = freq * mult; 1617272cc70bSAndy Fleming 1618ab71188cSMarkus Niebel mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); 1619998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); 1620272cc70bSAndy Fleming 1621272cc70bSAndy Fleming if (IS_SD(mmc)) 1622272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len; 1623272cc70bSAndy Fleming else 1624998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); 1625272cc70bSAndy Fleming 1626272cc70bSAndy Fleming if (mmc->high_capacity) { 1627272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16 1628272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16; 1629272cc70bSAndy Fleming cmult = 8; 1630272cc70bSAndy Fleming } else { 1631272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2 1632272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30; 1633272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15; 1634272cc70bSAndy Fleming } 1635272cc70bSAndy Fleming 1636f866a46dSStephen Warren mmc->capacity_user = (csize + 1) << (cmult + 2); 1637f866a46dSStephen Warren mmc->capacity_user *= mmc->read_bl_len; 1638f866a46dSStephen Warren mmc->capacity_boot = 0; 1639f866a46dSStephen Warren mmc->capacity_rpmb = 0; 1640f866a46dSStephen Warren for (i = 0; i < 4; i++) 1641f866a46dSStephen Warren mmc->capacity_gp[i] = 0; 1642272cc70bSAndy Fleming 16438bfa195eSSimon Glass if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN) 16448bfa195eSSimon Glass mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 1645272cc70bSAndy Fleming 16468bfa195eSSimon Glass if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) 16478bfa195eSSimon Glass mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 1648272cc70bSAndy Fleming 1649ab71188cSMarkus Niebel if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) { 1650ab71188cSMarkus Niebel cmd.cmdidx = MMC_CMD_SET_DSR; 1651ab71188cSMarkus Niebel cmd.cmdarg = (mmc->dsr & 0xffff) << 16; 1652ab71188cSMarkus Niebel cmd.resp_type = MMC_RSP_NONE; 1653ab71188cSMarkus Niebel if (mmc_send_cmd(mmc, &cmd, NULL)) 1654ab71188cSMarkus Niebel printf("MMC: SET_DSR failed\n"); 1655ab71188cSMarkus Niebel } 1656ab71188cSMarkus Niebel 1657272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */ 1658d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1659272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD; 1660fe8f7066SAjay Bhargav cmd.resp_type = MMC_RSP_R1; 1661272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1662272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1663272cc70bSAndy Fleming 1664272cc70bSAndy Fleming if (err) 1665272cc70bSAndy Fleming return err; 1666d52ebf10SThomas Chou } 1667272cc70bSAndy Fleming 1668e6f99a56SLei Wen /* 1669e6f99a56SLei Wen * For SD, its erase group is always one sector 1670e6f99a56SLei Wen */ 1671e6f99a56SLei Wen mmc->erase_grp_size = 1; 1672bc897b1dSLei Wen mmc->part_config = MMCPART_NOAVAILABLE; 1673d23e2c09SSukumar Ghorai if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) { 1674d23e2c09SSukumar Ghorai /* check ext_csd version and capacity */ 1675d23e2c09SSukumar Ghorai err = mmc_send_ext_csd(mmc, ext_csd); 16769cf199ebSDiego Santa Cruz if (err) 16779cf199ebSDiego Santa Cruz return err; 16789cf199ebSDiego Santa Cruz if (ext_csd[EXT_CSD_REV] >= 2) { 1679639b7827SYoshihiro Shimoda /* 1680639b7827SYoshihiro Shimoda * According to the JEDEC Standard, the value of 1681639b7827SYoshihiro Shimoda * ext_csd's capacity is valid if the value is more 1682639b7827SYoshihiro Shimoda * than 2GB 1683639b7827SYoshihiro Shimoda */ 16840560db18SLei Wen capacity = ext_csd[EXT_CSD_SEC_CNT] << 0 16850560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 16860560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 16870560db18SLei Wen | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; 16888bfa195eSSimon Glass capacity *= MMC_MAX_BLOCK_LEN; 1689b1f1e821SŁukasz Majewski if ((capacity >> 20) > 2 * 1024) 1690f866a46dSStephen Warren mmc->capacity_user = capacity; 1691d23e2c09SSukumar Ghorai } 1692bc897b1dSLei Wen 169364f4a619SJaehoon Chung switch (ext_csd[EXT_CSD_REV]) { 169464f4a619SJaehoon Chung case 1: 169564f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_1; 169664f4a619SJaehoon Chung break; 169764f4a619SJaehoon Chung case 2: 169864f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_2; 169964f4a619SJaehoon Chung break; 170064f4a619SJaehoon Chung case 3: 170164f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_3; 170264f4a619SJaehoon Chung break; 170364f4a619SJaehoon Chung case 5: 170464f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_41; 170564f4a619SJaehoon Chung break; 170664f4a619SJaehoon Chung case 6: 170764f4a619SJaehoon Chung mmc->version = MMC_VERSION_4_5; 170864f4a619SJaehoon Chung break; 1709edab723bSMarkus Niebel case 7: 1710edab723bSMarkus Niebel mmc->version = MMC_VERSION_5_0; 1711edab723bSMarkus Niebel break; 17121a3619cfSStefan Wahren case 8: 17131a3619cfSStefan Wahren mmc->version = MMC_VERSION_5_1; 17141a3619cfSStefan Wahren break; 171564f4a619SJaehoon Chung } 171664f4a619SJaehoon Chung 17178a0cf490SDiego Santa Cruz /* The partition data may be non-zero but it is only 17188a0cf490SDiego Santa Cruz * effective if PARTITION_SETTING_COMPLETED is set in 17198a0cf490SDiego Santa Cruz * EXT_CSD, so ignore any data if this bit is not set, 17208a0cf490SDiego Santa Cruz * except for enabling the high-capacity group size 17218a0cf490SDiego Santa Cruz * definition (see below). */ 17228a0cf490SDiego Santa Cruz part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] & 17238a0cf490SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 17248a0cf490SDiego Santa Cruz 17250c453bb7SDiego Santa Cruz /* store the partition info of emmc */ 17260c453bb7SDiego Santa Cruz mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT]; 17270c453bb7SDiego Santa Cruz if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || 17280c453bb7SDiego Santa Cruz ext_csd[EXT_CSD_BOOT_MULT]) 17290c453bb7SDiego Santa Cruz mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; 17308a0cf490SDiego Santa Cruz if (part_completed && 17318a0cf490SDiego Santa Cruz (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT)) 17320c453bb7SDiego Santa Cruz mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]; 1733*a6a1f5f8SJason Zhu if (ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] & EXT_CSD_SEC_GB_CL_EN) 1734*a6a1f5f8SJason Zhu mmc->esr.mmc_can_trim = 1; 17350c453bb7SDiego Santa Cruz 17360c453bb7SDiego Santa Cruz mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17; 17370c453bb7SDiego Santa Cruz 17380c453bb7SDiego Santa Cruz mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17; 17390c453bb7SDiego Santa Cruz 17400c453bb7SDiego Santa Cruz for (i = 0; i < 4; i++) { 17410c453bb7SDiego Santa Cruz int idx = EXT_CSD_GP_SIZE_MULT + i * 3; 17428a0cf490SDiego Santa Cruz uint mult = (ext_csd[idx + 2] << 16) + 17430c453bb7SDiego Santa Cruz (ext_csd[idx + 1] << 8) + ext_csd[idx]; 17448a0cf490SDiego Santa Cruz if (mult) 17458a0cf490SDiego Santa Cruz has_parts = true; 17468a0cf490SDiego Santa Cruz if (!part_completed) 17478a0cf490SDiego Santa Cruz continue; 17488a0cf490SDiego Santa Cruz mmc->capacity_gp[i] = mult; 17490c453bb7SDiego Santa Cruz mmc->capacity_gp[i] *= 17500c453bb7SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 17510c453bb7SDiego Santa Cruz mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1752f8e89d67SDiego Santa Cruz mmc->capacity_gp[i] <<= 19; 17530c453bb7SDiego Santa Cruz } 17540c453bb7SDiego Santa Cruz 17558a0cf490SDiego Santa Cruz if (part_completed) { 1756a7f852b6SDiego Santa Cruz mmc->enh_user_size = 1757a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_SIZE_MULT+2] << 16) + 1758a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_SIZE_MULT+1] << 8) + 1759a7f852b6SDiego Santa Cruz ext_csd[EXT_CSD_ENH_SIZE_MULT]; 1760a7f852b6SDiego Santa Cruz mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1761a7f852b6SDiego Santa Cruz mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1762a7f852b6SDiego Santa Cruz mmc->enh_user_size <<= 19; 1763a7f852b6SDiego Santa Cruz mmc->enh_user_start = 1764a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_START_ADDR+3] << 24) + 1765a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_START_ADDR+2] << 16) + 1766a7f852b6SDiego Santa Cruz (ext_csd[EXT_CSD_ENH_START_ADDR+1] << 8) + 1767a7f852b6SDiego Santa Cruz ext_csd[EXT_CSD_ENH_START_ADDR]; 1768a7f852b6SDiego Santa Cruz if (mmc->high_capacity) 1769a7f852b6SDiego Santa Cruz mmc->enh_user_start <<= 9; 17708a0cf490SDiego Santa Cruz } 1771a7f852b6SDiego Santa Cruz 1772e6f99a56SLei Wen /* 17731937e5aaSOliver Metz * Host needs to enable ERASE_GRP_DEF bit if device is 17741937e5aaSOliver Metz * partitioned. This bit will be lost every time after a reset 17751937e5aaSOliver Metz * or power off. This will affect erase size. 1776e6f99a56SLei Wen */ 17778a0cf490SDiego Santa Cruz if (part_completed) 17780c453bb7SDiego Santa Cruz has_parts = true; 17791937e5aaSOliver Metz if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) && 17800c453bb7SDiego Santa Cruz (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) 17810c453bb7SDiego Santa Cruz has_parts = true; 17820c453bb7SDiego Santa Cruz if (has_parts) { 17831937e5aaSOliver Metz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 17841937e5aaSOliver Metz EXT_CSD_ERASE_GROUP_DEF, 1); 17851937e5aaSOliver Metz 17861937e5aaSOliver Metz if (err) 17871937e5aaSOliver Metz return err; 1788021a8055SHannes Petermaier else 1789021a8055SHannes Petermaier ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 1790037dc0abSDiego Santa Cruz } 17911937e5aaSOliver Metz 1792037dc0abSDiego Santa Cruz if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) { 17931937e5aaSOliver Metz /* Read out group size from ext_csd */ 17940560db18SLei Wen mmc->erase_grp_size = 1795a4ff9f83SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 1796d7b29129SMarkus Niebel /* 1797d7b29129SMarkus Niebel * if high capacity and partition setting completed 1798d7b29129SMarkus Niebel * SEC_COUNT is valid even if it is smaller than 2 GiB 1799d7b29129SMarkus Niebel * JEDEC Standard JESD84-B45, 6.2.4 1800d7b29129SMarkus Niebel */ 18018a0cf490SDiego Santa Cruz if (mmc->high_capacity && part_completed) { 1802d7b29129SMarkus Niebel capacity = (ext_csd[EXT_CSD_SEC_CNT]) | 1803d7b29129SMarkus Niebel (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) | 1804d7b29129SMarkus Niebel (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) | 1805d7b29129SMarkus Niebel (ext_csd[EXT_CSD_SEC_CNT + 3] << 24); 1806d7b29129SMarkus Niebel capacity *= MMC_MAX_BLOCK_LEN; 1807d7b29129SMarkus Niebel mmc->capacity_user = capacity; 1808d7b29129SMarkus Niebel } 18098bfa195eSSimon Glass } else { 18101937e5aaSOliver Metz /* Calculate the group size from the csd value. */ 1811e6f99a56SLei Wen int erase_gsz, erase_gmul; 1812e6f99a56SLei Wen erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; 1813e6f99a56SLei Wen erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; 1814e6f99a56SLei Wen mmc->erase_grp_size = (erase_gsz + 1) 1815e6f99a56SLei Wen * (erase_gmul + 1); 1816e6f99a56SLei Wen } 1817037dc0abSDiego Santa Cruz 1818037dc0abSDiego Santa Cruz mmc->hc_wp_grp_size = 1024 1819037dc0abSDiego Santa Cruz * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 1820037dc0abSDiego Santa Cruz * ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 18219e41a00bSDiego Santa Cruz 18229e41a00bSDiego Santa Cruz mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 1823f866a46dSStephen Warren } 1824f866a46dSStephen Warren 1825c40fdca6SSimon Glass err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart); 1826f866a46dSStephen Warren if (err) 1827f866a46dSStephen Warren return err; 1828d23e2c09SSukumar Ghorai 1829272cc70bSAndy Fleming if (IS_SD(mmc)) 1830272cc70bSAndy Fleming err = sd_change_freq(mmc); 1831272cc70bSAndy Fleming else 1832272cc70bSAndy Fleming err = mmc_change_freq(mmc); 1833272cc70bSAndy Fleming 1834272cc70bSAndy Fleming if (err) 1835272cc70bSAndy Fleming return err; 1836272cc70bSAndy Fleming 1837272cc70bSAndy Fleming /* Restrict card's capabilities by what the host can do */ 183893bfd616SPantelis Antoniou mmc->card_caps &= mmc->cfg->host_caps; 1839272cc70bSAndy Fleming 1840272cc70bSAndy Fleming if (IS_SD(mmc)) { 1841272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_4BIT) { 1842272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 1843272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1844272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1845272cc70bSAndy Fleming 1846272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1847272cc70bSAndy Fleming if (err) 1848272cc70bSAndy Fleming return err; 1849272cc70bSAndy Fleming 1850272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; 1851272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1852272cc70bSAndy Fleming cmd.cmdarg = 2; 1853272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1854272cc70bSAndy Fleming if (err) 1855272cc70bSAndy Fleming return err; 1856272cc70bSAndy Fleming 1857272cc70bSAndy Fleming mmc_set_bus_width(mmc, 4); 1858272cc70bSAndy Fleming } 1859272cc70bSAndy Fleming 18603697e599SPeng Fan err = sd_read_ssr(mmc); 18613697e599SPeng Fan if (err) 18623697e599SPeng Fan return err; 18633697e599SPeng Fan 1864272cc70bSAndy Fleming if (mmc->card_caps & MMC_MODE_HS) 18653e3ff0acSZiyuan Xu tran_speed = 50000000; 1866272cc70bSAndy Fleming else 18673e3ff0acSZiyuan Xu tran_speed = 25000000; 1868ad5fd922SJaehoon Chung 18693e3ff0acSZiyuan Xu mmc_set_clock(mmc, tran_speed); 187049dba033SZiyuan Xu } 1871272cc70bSAndy Fleming 18725af8f45cSAndrew Gabbasov /* Fix the block length for DDR mode */ 187349dba033SZiyuan Xu if (mmc_card_ddr(mmc)) { 18745af8f45cSAndrew Gabbasov mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 18755af8f45cSAndrew Gabbasov mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 18765af8f45cSAndrew Gabbasov } 18775af8f45cSAndrew Gabbasov 1878272cc70bSAndy Fleming /* fill in device description */ 1879c40fdca6SSimon Glass bdesc = mmc_get_blk_desc(mmc); 1880c40fdca6SSimon Glass bdesc->lun = 0; 1881c40fdca6SSimon Glass bdesc->hwpart = 0; 1882c40fdca6SSimon Glass bdesc->type = 0; 1883c40fdca6SSimon Glass bdesc->blksz = mmc->read_bl_len; 1884c40fdca6SSimon Glass bdesc->log2blksz = LOG2(bdesc->blksz); 1885c40fdca6SSimon Glass bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len); 1886fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \ 1887fc011f64SSjoerd Simons (defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \ 1888fc011f64SSjoerd Simons !defined(CONFIG_USE_TINY_PRINTF)) 1889c40fdca6SSimon Glass sprintf(bdesc->vendor, "Man %06x Snr %04x%04x", 1890babce5f6STaylor Hutt mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), 1891babce5f6STaylor Hutt (mmc->cid[3] >> 16) & 0xffff); 1892c40fdca6SSimon Glass sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff, 18930b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 1894babce5f6STaylor Hutt (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff, 1895babce5f6STaylor Hutt (mmc->cid[2] >> 24) & 0xff); 1896c40fdca6SSimon Glass sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf, 1897babce5f6STaylor Hutt (mmc->cid[2] >> 16) & 0xf); 189856196826SPaul Burton #else 1899c40fdca6SSimon Glass bdesc->vendor[0] = 0; 1900c40fdca6SSimon Glass bdesc->product[0] = 0; 1901c40fdca6SSimon Glass bdesc->revision[0] = 0; 190256196826SPaul Burton #endif 1903122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT) 1904c40fdca6SSimon Glass part_init(bdesc); 1905122efd43SMikhail Kshevetskiy #endif 1906272cc70bSAndy Fleming 1907272cc70bSAndy Fleming return 0; 1908272cc70bSAndy Fleming } 1909272cc70bSAndy Fleming 1910fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc) 1911272cc70bSAndy Fleming { 1912272cc70bSAndy Fleming struct mmc_cmd cmd; 1913272cc70bSAndy Fleming int err; 1914272cc70bSAndy Fleming 1915272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND; 1916272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ 191793bfd616SPantelis Antoniou cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa; 1918272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7; 1919272cc70bSAndy Fleming 1920272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1921272cc70bSAndy Fleming 1922272cc70bSAndy Fleming if (err) 1923272cc70bSAndy Fleming return err; 1924272cc70bSAndy Fleming 1925998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa) 1926915ffa52SJaehoon Chung return -EOPNOTSUPP; 1927272cc70bSAndy Fleming else 1928272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 1929272cc70bSAndy Fleming 1930272cc70bSAndy Fleming return 0; 1931272cc70bSAndy Fleming } 1932272cc70bSAndy Fleming 1933c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 193495de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */ 193595de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void) 193695de9ab2SPaul Kocialkowski { 193795de9ab2SPaul Kocialkowski } 193805cbeb7cSSimon Glass #endif 193995de9ab2SPaul Kocialkowski 19402051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc) 19412051aefeSPeng Fan { 1942c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 194305cbeb7cSSimon Glass #if defined(CONFIG_DM_REGULATOR) && !defined(CONFIG_SPL_BUILD) 19442051aefeSPeng Fan struct udevice *vmmc_supply; 19452051aefeSPeng Fan int ret; 19462051aefeSPeng Fan 19472051aefeSPeng Fan ret = device_get_supply_regulator(mmc->dev, "vmmc-supply", 19482051aefeSPeng Fan &vmmc_supply); 19492051aefeSPeng Fan if (ret) { 1950288db7c7SJaehoon Chung debug("%s: No vmmc supply\n", mmc->dev->name); 19512051aefeSPeng Fan return 0; 19522051aefeSPeng Fan } 19532051aefeSPeng Fan 19542051aefeSPeng Fan ret = regulator_set_enable(vmmc_supply, true); 19552051aefeSPeng Fan if (ret) { 19562051aefeSPeng Fan puts("Error enabling VMMC supply\n"); 19572051aefeSPeng Fan return ret; 19582051aefeSPeng Fan } 19592051aefeSPeng Fan #endif 196005cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */ 196105cbeb7cSSimon Glass /* 196205cbeb7cSSimon Glass * Driver model should use a regulator, as above, rather than calling 196305cbeb7cSSimon Glass * out to board code. 196405cbeb7cSSimon Glass */ 196505cbeb7cSSimon Glass board_mmc_power_init(); 196605cbeb7cSSimon Glass #endif 19672051aefeSPeng Fan return 0; 19682051aefeSPeng Fan } 19692051aefeSPeng Fan 1970e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc) 1971272cc70bSAndy Fleming { 19728ca51e51SSimon Glass bool no_card; 1973afd5932bSMacpaul Lin int err; 1974272cc70bSAndy Fleming 1975ab769f22SPantelis Antoniou /* we pretend there's no card when init is NULL */ 19768ca51e51SSimon Glass no_card = mmc_getcd(mmc) == 0; 1977e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 19788ca51e51SSimon Glass no_card = no_card || (mmc->cfg->ops->init == NULL); 19798ca51e51SSimon Glass #endif 19808ca51e51SSimon Glass if (no_card) { 198148972d90SThierry Reding mmc->has_init = 0; 198256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 198348972d90SThierry Reding printf("MMC: no card present\n"); 198456196826SPaul Burton #endif 1985915ffa52SJaehoon Chung return -ENOMEDIUM; 198648972d90SThierry Reding } 198748972d90SThierry Reding 1988bc897b1dSLei Wen if (mmc->has_init) 1989bc897b1dSLei Wen return 0; 1990bc897b1dSLei Wen 19915a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 19925a8dbdc6SYangbo Lu mmc_adapter_card_type_ident(); 19935a8dbdc6SYangbo Lu #endif 19942051aefeSPeng Fan err = mmc_power_init(mmc); 19952051aefeSPeng Fan if (err) 19962051aefeSPeng Fan return err; 199795de9ab2SPaul Kocialkowski 1998e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 19998ca51e51SSimon Glass /* The device has already been probed ready for use */ 20008ca51e51SSimon Glass #else 2001ab769f22SPantelis Antoniou /* made sure it's not NULL earlier */ 200293bfd616SPantelis Antoniou err = mmc->cfg->ops->init(mmc); 2003272cc70bSAndy Fleming if (err) 2004272cc70bSAndy Fleming return err; 20058ca51e51SSimon Glass #endif 2006b86b85e2SIlya Yanok mmc_set_bus_width(mmc, 1); 2007b86b85e2SIlya Yanok mmc_set_clock(mmc, 1); 200881db2d36SZiyuan Xu mmc_set_timing(mmc, MMC_TIMING_LEGACY); 2009b86b85e2SIlya Yanok 2010272cc70bSAndy Fleming /* Reset the Card */ 2011272cc70bSAndy Fleming err = mmc_go_idle(mmc); 2012272cc70bSAndy Fleming 2013272cc70bSAndy Fleming if (err) 2014272cc70bSAndy Fleming return err; 2015272cc70bSAndy Fleming 2016bc897b1dSLei Wen /* The internal partition reset to user partition(0) at every CMD0*/ 2017c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->hwpart = 0; 2018bc897b1dSLei Wen 2019272cc70bSAndy Fleming /* Test for SD version 2 */ 2020272cc70bSAndy Fleming err = mmc_send_if_cond(mmc); 2021272cc70bSAndy Fleming 2022272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */ 2023272cc70bSAndy Fleming err = sd_send_op_cond(mmc); 2024272cc70bSAndy Fleming 2025272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */ 2026915ffa52SJaehoon Chung if (err == -ETIMEDOUT) { 2027272cc70bSAndy Fleming err = mmc_send_op_cond(mmc); 2028272cc70bSAndy Fleming 2029bd47c135SAndrew Gabbasov if (err) { 203056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2031272cc70bSAndy Fleming printf("Card did not respond to voltage select!\n"); 203256196826SPaul Burton #endif 2033915ffa52SJaehoon Chung return -EOPNOTSUPP; 2034272cc70bSAndy Fleming } 2035272cc70bSAndy Fleming } 2036272cc70bSAndy Fleming 2037bd47c135SAndrew Gabbasov if (!err) 2038e9550449SChe-Liang Chiou mmc->init_in_progress = 1; 2039e9550449SChe-Liang Chiou 2040e9550449SChe-Liang Chiou return err; 2041e9550449SChe-Liang Chiou } 2042e9550449SChe-Liang Chiou 2043e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc) 2044e9550449SChe-Liang Chiou { 2045e9550449SChe-Liang Chiou int err = 0; 2046e9550449SChe-Liang Chiou 2047bd47c135SAndrew Gabbasov mmc->init_in_progress = 0; 2048e9550449SChe-Liang Chiou if (mmc->op_cond_pending) 2049e9550449SChe-Liang Chiou err = mmc_complete_op_cond(mmc); 2050e9550449SChe-Liang Chiou 2051e9550449SChe-Liang Chiou if (!err) 2052bc897b1dSLei Wen err = mmc_startup(mmc); 2053bc897b1dSLei Wen if (err) 2054bc897b1dSLei Wen mmc->has_init = 0; 2055bc897b1dSLei Wen else 2056bc897b1dSLei Wen mmc->has_init = 1; 2057e9550449SChe-Liang Chiou return err; 2058e9550449SChe-Liang Chiou } 2059e9550449SChe-Liang Chiou 2060e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc) 2061e9550449SChe-Liang Chiou { 2062bd47c135SAndrew Gabbasov int err = 0; 2063ce9eca94SMarek Vasut __maybe_unused unsigned start; 2064c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 206533fb211dSSimon Glass struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev); 2066e9550449SChe-Liang Chiou 206733fb211dSSimon Glass upriv->mmc = mmc; 206833fb211dSSimon Glass #endif 2069e9550449SChe-Liang Chiou if (mmc->has_init) 2070e9550449SChe-Liang Chiou return 0; 2071d803fea5SMateusz Zalega 2072d803fea5SMateusz Zalega start = get_timer(0); 2073d803fea5SMateusz Zalega 2074e9550449SChe-Liang Chiou if (!mmc->init_in_progress) 2075e9550449SChe-Liang Chiou err = mmc_start_init(mmc); 2076e9550449SChe-Liang Chiou 2077bd47c135SAndrew Gabbasov if (!err) 2078e9550449SChe-Liang Chiou err = mmc_complete_init(mmc); 2079919b4858SJagan Teki if (err) 2080919b4858SJagan Teki printf("%s: %d, time %lu\n", __func__, err, get_timer(start)); 2081919b4858SJagan Teki 2082bc897b1dSLei Wen return err; 2083272cc70bSAndy Fleming } 2084272cc70bSAndy Fleming 2085ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val) 2086ab71188cSMarkus Niebel { 2087ab71188cSMarkus Niebel mmc->dsr = val; 2088ab71188cSMarkus Niebel return 0; 2089ab71188cSMarkus Niebel } 2090ab71188cSMarkus Niebel 2091cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */ 2092cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis) 2093272cc70bSAndy Fleming { 2094272cc70bSAndy Fleming return -1; 2095272cc70bSAndy Fleming } 2096272cc70bSAndy Fleming 2097cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */ 2098cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis) 2099cee9ab7cSJeroen Hofstee { 2100cee9ab7cSJeroen Hofstee return -1; 2101cee9ab7cSJeroen Hofstee } 2102272cc70bSAndy Fleming 2103e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit) 2104e9550449SChe-Liang Chiou { 2105e9550449SChe-Liang Chiou mmc->preinit = preinit; 2106e9550449SChe-Liang Chiou } 2107e9550449SChe-Liang Chiou 2108c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD) 21098e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 21108e3332e2SSjoerd Simons { 21118e3332e2SSjoerd Simons return 0; 21128e3332e2SSjoerd Simons } 2113c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC) 21148e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 21158e3332e2SSjoerd Simons { 21164a1db6d8SSimon Glass int ret, i; 21178e3332e2SSjoerd Simons struct uclass *uc; 21184a1db6d8SSimon Glass struct udevice *dev; 21198e3332e2SSjoerd Simons 21208e3332e2SSjoerd Simons ret = uclass_get(UCLASS_MMC, &uc); 21218e3332e2SSjoerd Simons if (ret) 21228e3332e2SSjoerd Simons return ret; 21238e3332e2SSjoerd Simons 21244a1db6d8SSimon Glass /* 21254a1db6d8SSimon Glass * Try to add them in sequence order. Really with driver model we 21264a1db6d8SSimon Glass * should allow holes, but the current MMC list does not allow that. 21274a1db6d8SSimon Glass * So if we request 0, 1, 3 we will get 0, 1, 2. 21284a1db6d8SSimon Glass */ 21294a1db6d8SSimon Glass for (i = 0; ; i++) { 21304a1db6d8SSimon Glass ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev); 21314a1db6d8SSimon Glass if (ret == -ENODEV) 21324a1db6d8SSimon Glass break; 21334a1db6d8SSimon Glass } 21344a1db6d8SSimon Glass uclass_foreach_dev(dev, uc) { 21354a1db6d8SSimon Glass ret = device_probe(dev); 21368e3332e2SSjoerd Simons if (ret) 21374a1db6d8SSimon Glass printf("%s - probe failed: %d\n", dev->name, ret); 21388e3332e2SSjoerd Simons } 21398e3332e2SSjoerd Simons 21408e3332e2SSjoerd Simons return 0; 21418e3332e2SSjoerd Simons } 21428e3332e2SSjoerd Simons #else 21438e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 21448e3332e2SSjoerd Simons { 21458e3332e2SSjoerd Simons if (board_mmc_init(bis) < 0) 21468e3332e2SSjoerd Simons cpu_mmc_init(bis); 21478e3332e2SSjoerd Simons 21488e3332e2SSjoerd Simons return 0; 21498e3332e2SSjoerd Simons } 21508e3332e2SSjoerd Simons #endif 2151e9550449SChe-Liang Chiou 2152272cc70bSAndy Fleming int mmc_initialize(bd_t *bis) 2153272cc70bSAndy Fleming { 21541b26bab1SDaniel Kochmański static int initialized = 0; 21558e3332e2SSjoerd Simons int ret; 21561b26bab1SDaniel Kochmański if (initialized) /* Avoid initializing mmc multiple times */ 21571b26bab1SDaniel Kochmański return 0; 21581b26bab1SDaniel Kochmański initialized = 1; 21591b26bab1SDaniel Kochmański 2160c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK) 2161b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY) 2162c40fdca6SSimon Glass mmc_list_init(); 2163c40fdca6SSimon Glass #endif 2164b5b838f1SMarek Vasut #endif 21658e3332e2SSjoerd Simons ret = mmc_probe(bis); 21668e3332e2SSjoerd Simons if (ret) 21678e3332e2SSjoerd Simons return ret; 2168272cc70bSAndy Fleming 2169bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD 2170272cc70bSAndy Fleming print_mmc_devices(','); 2171bb0dc108SYing Zhang #endif 2172272cc70bSAndy Fleming 2173c40fdca6SSimon Glass mmc_do_preinit(); 2174272cc70bSAndy Fleming return 0; 2175272cc70bSAndy Fleming } 2176cd3d4880STomas Melin 2177cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE 2178cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc) 2179cd3d4880STomas Melin { 2180cd3d4880STomas Melin int err; 2181cd3d4880STomas Melin ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 2182cd3d4880STomas Melin 2183cd3d4880STomas Melin err = mmc_send_ext_csd(mmc, ext_csd); 2184cd3d4880STomas Melin if (err) { 2185cd3d4880STomas Melin puts("Could not get ext_csd register values\n"); 2186cd3d4880STomas Melin return err; 2187cd3d4880STomas Melin } 2188cd3d4880STomas Melin 2189cd3d4880STomas Melin if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) { 2190cd3d4880STomas Melin puts("Background operations not supported on device\n"); 2191cd3d4880STomas Melin return -EMEDIUMTYPE; 2192cd3d4880STomas Melin } 2193cd3d4880STomas Melin 2194cd3d4880STomas Melin if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) { 2195cd3d4880STomas Melin puts("Background operations already enabled\n"); 2196cd3d4880STomas Melin return 0; 2197cd3d4880STomas Melin } 2198cd3d4880STomas Melin 2199cd3d4880STomas Melin err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1); 2200cd3d4880STomas Melin if (err) { 2201cd3d4880STomas Melin puts("Failed to enable manual background operations\n"); 2202cd3d4880STomas Melin return err; 2203cd3d4880STomas Melin } 2204cd3d4880STomas Melin 2205cd3d4880STomas Melin puts("Enabled manual background operations\n"); 2206cd3d4880STomas Melin 2207cd3d4880STomas Melin return 0; 2208cd3d4880STomas Melin } 2209cd3d4880STomas Melin #endif 2210