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 213786e8f81SAndrew Gabbasov if (mmc->ddr_mode) 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 321fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc) 322272cc70bSAndy Fleming { 323272cc70bSAndy Fleming struct mmc_cmd cmd; 324272cc70bSAndy Fleming int err; 325272cc70bSAndy Fleming 326272cc70bSAndy Fleming udelay(1000); 327272cc70bSAndy Fleming 328272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_GO_IDLE_STATE; 329272cc70bSAndy Fleming cmd.cmdarg = 0; 330272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_NONE; 331272cc70bSAndy Fleming 332272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 333272cc70bSAndy Fleming 334272cc70bSAndy Fleming if (err) 335272cc70bSAndy Fleming return err; 336272cc70bSAndy Fleming 337272cc70bSAndy Fleming udelay(2000); 338272cc70bSAndy Fleming 339272cc70bSAndy Fleming return 0; 340272cc70bSAndy Fleming } 341272cc70bSAndy Fleming 342fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc) 343272cc70bSAndy Fleming { 344272cc70bSAndy Fleming int timeout = 1000; 345272cc70bSAndy Fleming int err; 346272cc70bSAndy Fleming struct mmc_cmd cmd; 347272cc70bSAndy Fleming 3481677eef4SAndrew Gabbasov while (1) { 349272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 350272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 351272cc70bSAndy Fleming cmd.cmdarg = 0; 352272cc70bSAndy Fleming 353272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 354272cc70bSAndy Fleming 355272cc70bSAndy Fleming if (err) 356272cc70bSAndy Fleming return err; 357272cc70bSAndy Fleming 358272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_OP_COND; 359272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R3; 360250de12bSStefano Babic 361250de12bSStefano Babic /* 362250de12bSStefano Babic * Most cards do not answer if some reserved bits 363250de12bSStefano Babic * in the ocr are set. However, Some controller 364250de12bSStefano Babic * can set bit 7 (reserved for low voltages), but 365250de12bSStefano Babic * how to manage low voltages SD card is not yet 366250de12bSStefano Babic * specified. 367250de12bSStefano Babic */ 368d52ebf10SThomas Chou cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 : 36993bfd616SPantelis Antoniou (mmc->cfg->voltages & 0xff8000); 370272cc70bSAndy Fleming 371272cc70bSAndy Fleming if (mmc->version == SD_VERSION_2) 372272cc70bSAndy Fleming cmd.cmdarg |= OCR_HCS; 373272cc70bSAndy Fleming 374272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 375272cc70bSAndy Fleming 376272cc70bSAndy Fleming if (err) 377272cc70bSAndy Fleming return err; 378272cc70bSAndy Fleming 3791677eef4SAndrew Gabbasov if (cmd.response[0] & OCR_BUSY) 3801677eef4SAndrew Gabbasov break; 381272cc70bSAndy Fleming 3821677eef4SAndrew Gabbasov if (timeout-- <= 0) 383915ffa52SJaehoon Chung return -EOPNOTSUPP; 384272cc70bSAndy Fleming 3851677eef4SAndrew Gabbasov udelay(1000); 3861677eef4SAndrew Gabbasov } 3871677eef4SAndrew Gabbasov 388272cc70bSAndy Fleming if (mmc->version != SD_VERSION_2) 389272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 390272cc70bSAndy Fleming 391d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 392d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 393d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 394d52ebf10SThomas Chou cmd.cmdarg = 0; 395d52ebf10SThomas Chou 396d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 397d52ebf10SThomas Chou 398d52ebf10SThomas Chou if (err) 399d52ebf10SThomas Chou return err; 400d52ebf10SThomas Chou } 401d52ebf10SThomas Chou 402998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 403272cc70bSAndy Fleming 404272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 405272cc70bSAndy Fleming mmc->rca = 0; 406272cc70bSAndy Fleming 407272cc70bSAndy Fleming return 0; 408272cc70bSAndy Fleming } 409272cc70bSAndy Fleming 4105289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg) 411272cc70bSAndy Fleming { 4125289b535SAndrew Gabbasov struct mmc_cmd cmd; 413272cc70bSAndy Fleming int err; 414272cc70bSAndy Fleming 4155289b535SAndrew Gabbasov cmd.cmdidx = MMC_CMD_SEND_OP_COND; 4165289b535SAndrew Gabbasov cmd.resp_type = MMC_RSP_R3; 4175289b535SAndrew Gabbasov cmd.cmdarg = 0; 4185a20397bSRob Herring if (use_arg && !mmc_host_is_spi(mmc)) 4195a20397bSRob Herring cmd.cmdarg = OCR_HCS | 42093bfd616SPantelis Antoniou (mmc->cfg->voltages & 421a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_VOLTAGE_MASK)) | 422a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_ACCESS_MODE); 423e9550449SChe-Liang Chiou 4245289b535SAndrew Gabbasov err = mmc_send_cmd(mmc, &cmd, NULL); 425e9550449SChe-Liang Chiou if (err) 426e9550449SChe-Liang Chiou return err; 4275289b535SAndrew Gabbasov mmc->ocr = cmd.response[0]; 428e9550449SChe-Liang Chiou return 0; 429e9550449SChe-Liang Chiou } 430e9550449SChe-Liang Chiou 431750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc) 432e9550449SChe-Liang Chiou { 433e9550449SChe-Liang Chiou int err, i; 434e9550449SChe-Liang Chiou 435272cc70bSAndy Fleming /* Some cards seem to need this */ 436272cc70bSAndy Fleming mmc_go_idle(mmc); 437272cc70bSAndy Fleming 43831cacbabSRaffaele Recalcati /* Asking to the card its capabilities */ 439e9550449SChe-Liang Chiou for (i = 0; i < 2; i++) { 4405289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, i != 0); 44131cacbabSRaffaele Recalcati if (err) 44231cacbabSRaffaele Recalcati return err; 44331cacbabSRaffaele Recalcati 444e9550449SChe-Liang Chiou /* exit if not busy (flag seems to be inverted) */ 445a626c8d4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 446bd47c135SAndrew Gabbasov break; 447e9550449SChe-Liang Chiou } 448bd47c135SAndrew Gabbasov mmc->op_cond_pending = 1; 449bd47c135SAndrew Gabbasov return 0; 450e9550449SChe-Liang Chiou } 45131cacbabSRaffaele Recalcati 452750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc) 453e9550449SChe-Liang Chiou { 454e9550449SChe-Liang Chiou struct mmc_cmd cmd; 455e9550449SChe-Liang Chiou int timeout = 1000; 456e9550449SChe-Liang Chiou uint start; 457e9550449SChe-Liang Chiou int err; 458e9550449SChe-Liang Chiou 459e9550449SChe-Liang Chiou mmc->op_cond_pending = 0; 460cc17c01fSAndrew Gabbasov if (!(mmc->ocr & OCR_BUSY)) { 461d188b113SYangbo Lu /* Some cards seem to need this */ 462d188b113SYangbo Lu mmc_go_idle(mmc); 463d188b113SYangbo Lu 464e9550449SChe-Liang Chiou start = get_timer(0); 4651677eef4SAndrew Gabbasov while (1) { 4665289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, 1); 467272cc70bSAndy Fleming if (err) 468272cc70bSAndy Fleming return err; 4691677eef4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 4701677eef4SAndrew Gabbasov break; 471e9550449SChe-Liang Chiou if (get_timer(start) > timeout) 472915ffa52SJaehoon Chung return -EOPNOTSUPP; 473e9550449SChe-Liang Chiou udelay(100); 4741677eef4SAndrew Gabbasov } 475cc17c01fSAndrew Gabbasov } 476272cc70bSAndy Fleming 477d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 478d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 479d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 480d52ebf10SThomas Chou cmd.cmdarg = 0; 481d52ebf10SThomas Chou 482d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 483d52ebf10SThomas Chou 484d52ebf10SThomas Chou if (err) 485d52ebf10SThomas Chou return err; 486a626c8d4SAndrew Gabbasov 487a626c8d4SAndrew Gabbasov mmc->ocr = cmd.response[0]; 488d52ebf10SThomas Chou } 489d52ebf10SThomas Chou 490272cc70bSAndy Fleming mmc->version = MMC_VERSION_UNKNOWN; 491272cc70bSAndy Fleming 492272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 493def816a2SStephen Warren mmc->rca = 1; 494272cc70bSAndy Fleming 495272cc70bSAndy Fleming return 0; 496272cc70bSAndy Fleming } 497272cc70bSAndy Fleming 498272cc70bSAndy Fleming 499fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) 500272cc70bSAndy Fleming { 501272cc70bSAndy Fleming struct mmc_cmd cmd; 502272cc70bSAndy Fleming struct mmc_data data; 503272cc70bSAndy Fleming int err; 504272cc70bSAndy Fleming 505272cc70bSAndy Fleming /* Get the Card Status Register */ 506272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_EXT_CSD; 507272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 508272cc70bSAndy Fleming cmd.cmdarg = 0; 509272cc70bSAndy Fleming 510cdfd1ac6SYoshihiro Shimoda data.dest = (char *)ext_csd; 511272cc70bSAndy Fleming data.blocks = 1; 5128bfa195eSSimon Glass data.blocksize = MMC_MAX_BLOCK_LEN; 513272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 514272cc70bSAndy Fleming 515272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 516272cc70bSAndy Fleming 517272cc70bSAndy Fleming return err; 518272cc70bSAndy Fleming } 519272cc70bSAndy Fleming 520c40704f4SSimon Glass int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) 521272cc70bSAndy Fleming { 522272cc70bSAndy Fleming struct mmc_cmd cmd; 5235d4fc8d9SRaffaele Recalcati int timeout = 1000; 524a9003dc6SMaxime Ripard int retries = 3; 5255d4fc8d9SRaffaele Recalcati int ret; 526272cc70bSAndy Fleming 527272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SWITCH; 528272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 529272cc70bSAndy Fleming cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 530272cc70bSAndy Fleming (index << 16) | 531272cc70bSAndy Fleming (value << 8); 532272cc70bSAndy Fleming 533a9003dc6SMaxime Ripard while (retries > 0) { 5345d4fc8d9SRaffaele Recalcati ret = mmc_send_cmd(mmc, &cmd, NULL); 5355d4fc8d9SRaffaele Recalcati 5365d4fc8d9SRaffaele Recalcati /* Waiting for the ready status */ 537a9003dc6SMaxime Ripard if (!ret) { 53893ad0d18SJan Kloetzke ret = mmc_send_status(mmc, timeout); 539a9003dc6SMaxime Ripard return ret; 540a9003dc6SMaxime Ripard } 541a9003dc6SMaxime Ripard 542a9003dc6SMaxime Ripard retries--; 543a9003dc6SMaxime Ripard } 5445d4fc8d9SRaffaele Recalcati 5455d4fc8d9SRaffaele Recalcati return ret; 5465d4fc8d9SRaffaele Recalcati 547272cc70bSAndy Fleming } 548272cc70bSAndy Fleming 549fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc) 550272cc70bSAndy Fleming { 5518bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 552272cc70bSAndy Fleming char cardtype; 553272cc70bSAndy Fleming int err; 554272cc70bSAndy Fleming 555fc5b32fbSAndrew Gabbasov mmc->card_caps = 0; 556272cc70bSAndy Fleming 557d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 558d52ebf10SThomas Chou return 0; 559d52ebf10SThomas Chou 560272cc70bSAndy Fleming /* Only version 4 supports high-speed */ 561272cc70bSAndy Fleming if (mmc->version < MMC_VERSION_4) 562272cc70bSAndy Fleming return 0; 563272cc70bSAndy Fleming 564fc5b32fbSAndrew Gabbasov mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; 565fc5b32fbSAndrew Gabbasov 566272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 567272cc70bSAndy Fleming 568272cc70bSAndy Fleming if (err) 569272cc70bSAndy Fleming return err; 570272cc70bSAndy Fleming 5710560db18SLei Wen cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf; 572272cc70bSAndy Fleming 573272cc70bSAndy Fleming err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1); 574272cc70bSAndy Fleming 575272cc70bSAndy Fleming if (err) 576a5e27b41SHeiko Schocher return err; 577272cc70bSAndy Fleming 578272cc70bSAndy Fleming /* Now check to see that it worked */ 579272cc70bSAndy Fleming err = mmc_send_ext_csd(mmc, ext_csd); 580272cc70bSAndy Fleming 581272cc70bSAndy Fleming if (err) 582272cc70bSAndy Fleming return err; 583272cc70bSAndy Fleming 584272cc70bSAndy Fleming /* No high-speed support */ 5850560db18SLei Wen if (!ext_csd[EXT_CSD_HS_TIMING]) 586272cc70bSAndy Fleming return 0; 587272cc70bSAndy Fleming 588272cc70bSAndy Fleming /* High Speed is set, there are two types: 52MHz and 26MHz */ 589d22e3d46SJaehoon Chung if (cardtype & EXT_CSD_CARD_TYPE_52) { 590201d5ac4SAndrew Gabbasov if (cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V) 591d22e3d46SJaehoon Chung mmc->card_caps |= MMC_MODE_DDR_52MHz; 592272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; 593d22e3d46SJaehoon Chung } else { 594272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS; 595d22e3d46SJaehoon Chung } 596272cc70bSAndy Fleming 597272cc70bSAndy Fleming return 0; 598272cc70bSAndy Fleming } 599272cc70bSAndy Fleming 600f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num) 601f866a46dSStephen Warren { 602f866a46dSStephen Warren switch (part_num) { 603f866a46dSStephen Warren case 0: 604f866a46dSStephen Warren mmc->capacity = mmc->capacity_user; 605f866a46dSStephen Warren break; 606f866a46dSStephen Warren case 1: 607f866a46dSStephen Warren case 2: 608f866a46dSStephen Warren mmc->capacity = mmc->capacity_boot; 609f866a46dSStephen Warren break; 610f866a46dSStephen Warren case 3: 611f866a46dSStephen Warren mmc->capacity = mmc->capacity_rpmb; 612f866a46dSStephen Warren break; 613f866a46dSStephen Warren case 4: 614f866a46dSStephen Warren case 5: 615f866a46dSStephen Warren case 6: 616f866a46dSStephen Warren case 7: 617f866a46dSStephen Warren mmc->capacity = mmc->capacity_gp[part_num - 4]; 618f866a46dSStephen Warren break; 619f866a46dSStephen Warren default: 620f866a46dSStephen Warren return -1; 621f866a46dSStephen Warren } 622f866a46dSStephen Warren 623c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len); 624f866a46dSStephen Warren 625f866a46dSStephen Warren return 0; 626f866a46dSStephen Warren } 627f866a46dSStephen Warren 6287dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num) 629bc897b1dSLei Wen { 630f866a46dSStephen Warren int ret; 631bc897b1dSLei Wen 632f866a46dSStephen Warren ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 633bc897b1dSLei Wen (mmc->part_config & ~PART_ACCESS_MASK) 634bc897b1dSLei Wen | (part_num & PART_ACCESS_MASK)); 635f866a46dSStephen Warren 6366dc93e70SPeter Bigot /* 6376dc93e70SPeter Bigot * Set the capacity if the switch succeeded or was intended 6386dc93e70SPeter Bigot * to return to representing the raw device. 6396dc93e70SPeter Bigot */ 640873cc1d7SStephen Warren if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) { 6416dc93e70SPeter Bigot ret = mmc_set_capacity(mmc, part_num); 642fdbb139fSSimon Glass mmc_get_blk_desc(mmc)->hwpart = part_num; 643873cc1d7SStephen Warren } 6446dc93e70SPeter Bigot 6456dc93e70SPeter Bigot return ret; 646bc897b1dSLei Wen } 647bc897b1dSLei Wen 648ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc, 649ac9da0e0SDiego Santa Cruz const struct mmc_hwpart_conf *conf, 650ac9da0e0SDiego Santa Cruz enum mmc_hwpart_conf_mode mode) 651ac9da0e0SDiego Santa Cruz { 652ac9da0e0SDiego Santa Cruz u8 part_attrs = 0; 653ac9da0e0SDiego Santa Cruz u32 enh_size_mult; 654ac9da0e0SDiego Santa Cruz u32 enh_start_addr; 655ac9da0e0SDiego Santa Cruz u32 gp_size_mult[4]; 656ac9da0e0SDiego Santa Cruz u32 max_enh_size_mult; 657ac9da0e0SDiego Santa Cruz u32 tot_enh_size_mult = 0; 6588dda5b0eSDiego Santa Cruz u8 wr_rel_set; 659ac9da0e0SDiego Santa Cruz int i, pidx, err; 660ac9da0e0SDiego Santa Cruz ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 661ac9da0e0SDiego Santa Cruz 662ac9da0e0SDiego Santa Cruz if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE) 663ac9da0e0SDiego Santa Cruz return -EINVAL; 664ac9da0e0SDiego Santa Cruz 665ac9da0e0SDiego Santa Cruz if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) { 666ac9da0e0SDiego Santa Cruz printf("eMMC >= 4.4 required for enhanced user data area\n"); 667ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 668ac9da0e0SDiego Santa Cruz } 669ac9da0e0SDiego Santa Cruz 670ac9da0e0SDiego Santa Cruz if (!(mmc->part_support & PART_SUPPORT)) { 671ac9da0e0SDiego Santa Cruz printf("Card does not support partitioning\n"); 672ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 673ac9da0e0SDiego Santa Cruz } 674ac9da0e0SDiego Santa Cruz 675ac9da0e0SDiego Santa Cruz if (!mmc->hc_wp_grp_size) { 676ac9da0e0SDiego Santa Cruz printf("Card does not define HC WP group size\n"); 677ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 678ac9da0e0SDiego Santa Cruz } 679ac9da0e0SDiego Santa Cruz 680ac9da0e0SDiego Santa Cruz /* check partition alignment and total enhanced size */ 681ac9da0e0SDiego Santa Cruz if (conf->user.enh_size) { 682ac9da0e0SDiego Santa Cruz if (conf->user.enh_size % mmc->hc_wp_grp_size || 683ac9da0e0SDiego Santa Cruz conf->user.enh_start % mmc->hc_wp_grp_size) { 684ac9da0e0SDiego Santa Cruz printf("User data enhanced area not HC WP group " 685ac9da0e0SDiego Santa Cruz "size aligned\n"); 686ac9da0e0SDiego Santa Cruz return -EINVAL; 687ac9da0e0SDiego Santa Cruz } 688ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_USR; 689ac9da0e0SDiego Santa Cruz enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size; 690ac9da0e0SDiego Santa Cruz if (mmc->high_capacity) { 691ac9da0e0SDiego Santa Cruz enh_start_addr = conf->user.enh_start; 692ac9da0e0SDiego Santa Cruz } else { 693ac9da0e0SDiego Santa Cruz enh_start_addr = (conf->user.enh_start << 9); 694ac9da0e0SDiego Santa Cruz } 695ac9da0e0SDiego Santa Cruz } else { 696ac9da0e0SDiego Santa Cruz enh_size_mult = 0; 697ac9da0e0SDiego Santa Cruz enh_start_addr = 0; 698ac9da0e0SDiego Santa Cruz } 699ac9da0e0SDiego Santa Cruz tot_enh_size_mult += enh_size_mult; 700ac9da0e0SDiego Santa Cruz 701ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 702ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) { 703ac9da0e0SDiego Santa Cruz printf("GP%i partition not HC WP group size " 704ac9da0e0SDiego Santa Cruz "aligned\n", pidx+1); 705ac9da0e0SDiego Santa Cruz return -EINVAL; 706ac9da0e0SDiego Santa Cruz } 707ac9da0e0SDiego Santa Cruz gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size; 708ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) { 709ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_GP(pidx); 710ac9da0e0SDiego Santa Cruz tot_enh_size_mult += gp_size_mult[pidx]; 711ac9da0e0SDiego Santa Cruz } 712ac9da0e0SDiego Santa Cruz } 713ac9da0e0SDiego Santa Cruz 714ac9da0e0SDiego Santa Cruz if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) { 715ac9da0e0SDiego Santa Cruz printf("Card does not support enhanced attribute\n"); 716ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 717ac9da0e0SDiego Santa Cruz } 718ac9da0e0SDiego Santa Cruz 719ac9da0e0SDiego Santa Cruz err = mmc_send_ext_csd(mmc, ext_csd); 720ac9da0e0SDiego Santa Cruz if (err) 721ac9da0e0SDiego Santa Cruz return err; 722ac9da0e0SDiego Santa Cruz 723ac9da0e0SDiego Santa Cruz max_enh_size_mult = 724ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) + 725ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) + 726ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]; 727ac9da0e0SDiego Santa Cruz if (tot_enh_size_mult > max_enh_size_mult) { 728ac9da0e0SDiego Santa Cruz printf("Total enhanced size exceeds maximum (%u > %u)\n", 729ac9da0e0SDiego Santa Cruz tot_enh_size_mult, max_enh_size_mult); 730ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 731ac9da0e0SDiego Santa Cruz } 732ac9da0e0SDiego Santa Cruz 7338dda5b0eSDiego Santa Cruz /* The default value of EXT_CSD_WR_REL_SET is device 7348dda5b0eSDiego Santa Cruz * dependent, the values can only be changed if the 7358dda5b0eSDiego Santa Cruz * EXT_CSD_HS_CTRL_REL bit is set. The values can be 7368dda5b0eSDiego Santa Cruz * changed only once and before partitioning is completed. */ 7378dda5b0eSDiego Santa Cruz wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 7388dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_change) { 7398dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_set) 7408dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_USR; 7418dda5b0eSDiego Santa Cruz else 7428dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR; 7438dda5b0eSDiego Santa Cruz } 7448dda5b0eSDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 7458dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_change) { 7468dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_set) 7478dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx); 7488dda5b0eSDiego Santa Cruz else 7498dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx); 7508dda5b0eSDiego Santa Cruz } 7518dda5b0eSDiego Santa Cruz } 7528dda5b0eSDiego Santa Cruz 7538dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] && 7548dda5b0eSDiego Santa Cruz !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) { 7558dda5b0eSDiego Santa Cruz puts("Card does not support host controlled partition write " 7568dda5b0eSDiego Santa Cruz "reliability settings\n"); 7578dda5b0eSDiego Santa Cruz return -EMEDIUMTYPE; 7588dda5b0eSDiego Santa Cruz } 7598dda5b0eSDiego Santa Cruz 760ac9da0e0SDiego Santa Cruz if (ext_csd[EXT_CSD_PARTITION_SETTING] & 761ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED) { 762ac9da0e0SDiego Santa Cruz printf("Card already partitioned\n"); 763ac9da0e0SDiego Santa Cruz return -EPERM; 764ac9da0e0SDiego Santa Cruz } 765ac9da0e0SDiego Santa Cruz 766ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_CHECK) 767ac9da0e0SDiego Santa Cruz return 0; 768ac9da0e0SDiego Santa Cruz 769ac9da0e0SDiego Santa Cruz /* Partitioning requires high-capacity size definitions */ 770ac9da0e0SDiego Santa Cruz if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) { 771ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 772ac9da0e0SDiego Santa Cruz EXT_CSD_ERASE_GROUP_DEF, 1); 773ac9da0e0SDiego Santa Cruz 774ac9da0e0SDiego Santa Cruz if (err) 775ac9da0e0SDiego Santa Cruz return err; 776ac9da0e0SDiego Santa Cruz 777ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 778ac9da0e0SDiego Santa Cruz 779ac9da0e0SDiego Santa Cruz /* update erase group size to be high-capacity */ 780ac9da0e0SDiego Santa Cruz mmc->erase_grp_size = 781ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 782ac9da0e0SDiego Santa Cruz 783ac9da0e0SDiego Santa Cruz } 784ac9da0e0SDiego Santa Cruz 785ac9da0e0SDiego Santa Cruz /* all OK, write the configuration */ 786ac9da0e0SDiego Santa Cruz for (i = 0; i < 4; i++) { 787ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 788ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_START_ADDR+i, 789ac9da0e0SDiego Santa Cruz (enh_start_addr >> (i*8)) & 0xFF); 790ac9da0e0SDiego Santa Cruz if (err) 791ac9da0e0SDiego Santa Cruz return err; 792ac9da0e0SDiego Santa Cruz } 793ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 794ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 795ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_SIZE_MULT+i, 796ac9da0e0SDiego Santa Cruz (enh_size_mult >> (i*8)) & 0xFF); 797ac9da0e0SDiego Santa Cruz if (err) 798ac9da0e0SDiego Santa Cruz return err; 799ac9da0e0SDiego Santa Cruz } 800ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 801ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 802ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 803ac9da0e0SDiego Santa Cruz EXT_CSD_GP_SIZE_MULT+pidx*3+i, 804ac9da0e0SDiego Santa Cruz (gp_size_mult[pidx] >> (i*8)) & 0xFF); 805ac9da0e0SDiego Santa Cruz if (err) 806ac9da0e0SDiego Santa Cruz return err; 807ac9da0e0SDiego Santa Cruz } 808ac9da0e0SDiego Santa Cruz } 809ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 810ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs); 811ac9da0e0SDiego Santa Cruz if (err) 812ac9da0e0SDiego Santa Cruz return err; 813ac9da0e0SDiego Santa Cruz 814ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_SET) 815ac9da0e0SDiego Santa Cruz return 0; 816ac9da0e0SDiego Santa Cruz 8178dda5b0eSDiego Santa Cruz /* The WR_REL_SET is a write-once register but shall be 8188dda5b0eSDiego Santa Cruz * written before setting PART_SETTING_COMPLETED. As it is 8198dda5b0eSDiego Santa Cruz * write-once we can only write it when completing the 8208dda5b0eSDiego Santa Cruz * partitioning. */ 8218dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) { 8228dda5b0eSDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 8238dda5b0eSDiego Santa Cruz EXT_CSD_WR_REL_SET, wr_rel_set); 8248dda5b0eSDiego Santa Cruz if (err) 8258dda5b0eSDiego Santa Cruz return err; 8268dda5b0eSDiego Santa Cruz } 8278dda5b0eSDiego Santa Cruz 828ac9da0e0SDiego Santa Cruz /* Setting PART_SETTING_COMPLETED confirms the partition 829ac9da0e0SDiego Santa Cruz * configuration but it only becomes effective after power 830ac9da0e0SDiego Santa Cruz * cycle, so we do not adjust the partition related settings 831ac9da0e0SDiego Santa Cruz * in the mmc struct. */ 832ac9da0e0SDiego Santa Cruz 833ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 834ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING, 835ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 836ac9da0e0SDiego Santa Cruz if (err) 837ac9da0e0SDiego Santa Cruz return err; 838ac9da0e0SDiego Santa Cruz 839ac9da0e0SDiego Santa Cruz return 0; 840ac9da0e0SDiego Santa Cruz } 841ac9da0e0SDiego Santa Cruz 842e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 84348972d90SThierry Reding int mmc_getcd(struct mmc *mmc) 84448972d90SThierry Reding { 84548972d90SThierry Reding int cd; 84648972d90SThierry Reding 84748972d90SThierry Reding cd = board_mmc_getcd(mmc); 84848972d90SThierry Reding 849d4e1da4eSPeter Korsgaard if (cd < 0) { 85093bfd616SPantelis Antoniou if (mmc->cfg->ops->getcd) 85193bfd616SPantelis Antoniou cd = mmc->cfg->ops->getcd(mmc); 852d4e1da4eSPeter Korsgaard else 853d4e1da4eSPeter Korsgaard cd = 1; 854d4e1da4eSPeter Korsgaard } 85548972d90SThierry Reding 85648972d90SThierry Reding return cd; 85748972d90SThierry Reding } 8588ca51e51SSimon Glass #endif 85948972d90SThierry Reding 860fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) 861272cc70bSAndy Fleming { 862272cc70bSAndy Fleming struct mmc_cmd cmd; 863272cc70bSAndy Fleming struct mmc_data data; 864272cc70bSAndy Fleming 865272cc70bSAndy Fleming /* Switch the frequency */ 866272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC; 867272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 868272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff; 869272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4)); 870272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4); 871272cc70bSAndy Fleming 872272cc70bSAndy Fleming data.dest = (char *)resp; 873272cc70bSAndy Fleming data.blocksize = 64; 874272cc70bSAndy Fleming data.blocks = 1; 875272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 876272cc70bSAndy Fleming 877272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 878272cc70bSAndy Fleming } 879272cc70bSAndy Fleming 880272cc70bSAndy Fleming 881fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc) 882272cc70bSAndy Fleming { 883272cc70bSAndy Fleming int err; 884272cc70bSAndy Fleming struct mmc_cmd cmd; 88518e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2); 88618e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16); 887272cc70bSAndy Fleming struct mmc_data data; 888272cc70bSAndy Fleming int timeout; 889272cc70bSAndy Fleming 890272cc70bSAndy Fleming mmc->card_caps = 0; 891272cc70bSAndy Fleming 892d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 893d52ebf10SThomas Chou return 0; 894d52ebf10SThomas Chou 895272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */ 896272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 897272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 898272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 899272cc70bSAndy Fleming 900272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 901272cc70bSAndy Fleming 902272cc70bSAndy Fleming if (err) 903272cc70bSAndy Fleming return err; 904272cc70bSAndy Fleming 905272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR; 906272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 907272cc70bSAndy Fleming cmd.cmdarg = 0; 908272cc70bSAndy Fleming 909272cc70bSAndy Fleming timeout = 3; 910272cc70bSAndy Fleming 911272cc70bSAndy Fleming retry_scr: 912f781dd38SAnton staaf data.dest = (char *)scr; 913272cc70bSAndy Fleming data.blocksize = 8; 914272cc70bSAndy Fleming data.blocks = 1; 915272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 916272cc70bSAndy Fleming 917272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 918272cc70bSAndy Fleming 919272cc70bSAndy Fleming if (err) { 920272cc70bSAndy Fleming if (timeout--) 921272cc70bSAndy Fleming goto retry_scr; 922272cc70bSAndy Fleming 923272cc70bSAndy Fleming return err; 924272cc70bSAndy Fleming } 925272cc70bSAndy Fleming 9264e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]); 9274e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]); 928272cc70bSAndy Fleming 929272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) { 930272cc70bSAndy Fleming case 0: 931272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 932272cc70bSAndy Fleming break; 933272cc70bSAndy Fleming case 1: 934272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10; 935272cc70bSAndy Fleming break; 936272cc70bSAndy Fleming case 2: 937272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 9381741c64dSJaehoon Chung if ((mmc->scr[0] >> 15) & 0x1) 9391741c64dSJaehoon Chung mmc->version = SD_VERSION_3; 940272cc70bSAndy Fleming break; 941272cc70bSAndy Fleming default: 942272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 943272cc70bSAndy Fleming break; 944272cc70bSAndy Fleming } 945272cc70bSAndy Fleming 946b44c7083SAlagu Sankar if (mmc->scr[0] & SD_DATA_4BIT) 947b44c7083SAlagu Sankar mmc->card_caps |= MMC_MODE_4BIT; 948b44c7083SAlagu Sankar 949272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */ 950272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0) 951272cc70bSAndy Fleming return 0; 952272cc70bSAndy Fleming 953272cc70bSAndy Fleming timeout = 4; 954272cc70bSAndy Fleming while (timeout--) { 955272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, 956f781dd38SAnton staaf (u8 *)switch_status); 957272cc70bSAndy Fleming 958272cc70bSAndy Fleming if (err) 959272cc70bSAndy Fleming return err; 960272cc70bSAndy Fleming 961272cc70bSAndy Fleming /* The high-speed function is busy. Try again */ 9624e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) 963272cc70bSAndy Fleming break; 964272cc70bSAndy Fleming } 965272cc70bSAndy Fleming 966272cc70bSAndy Fleming /* If high-speed isn't supported, we return */ 9674e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)) 968272cc70bSAndy Fleming return 0; 969272cc70bSAndy Fleming 9702c3fbf4cSMacpaul Lin /* 9712c3fbf4cSMacpaul Lin * If the host doesn't support SD_HIGHSPEED, do not switch card to 9722c3fbf4cSMacpaul Lin * HIGHSPEED mode even if the card support SD_HIGHSPPED. 9732c3fbf4cSMacpaul Lin * This can avoid furthur problem when the card runs in different 9742c3fbf4cSMacpaul Lin * mode between the host. 9752c3fbf4cSMacpaul Lin */ 97693bfd616SPantelis Antoniou if (!((mmc->cfg->host_caps & MMC_MODE_HS_52MHz) && 97793bfd616SPantelis Antoniou (mmc->cfg->host_caps & MMC_MODE_HS))) 9782c3fbf4cSMacpaul Lin return 0; 9792c3fbf4cSMacpaul Lin 980f781dd38SAnton staaf err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status); 981272cc70bSAndy Fleming 982272cc70bSAndy Fleming if (err) 983272cc70bSAndy Fleming return err; 984272cc70bSAndy Fleming 9854e3d89baSYauhen Kharuzhy if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000) 986272cc70bSAndy Fleming mmc->card_caps |= MMC_MODE_HS; 987272cc70bSAndy Fleming 988272cc70bSAndy Fleming return 0; 989272cc70bSAndy Fleming } 990272cc70bSAndy Fleming 9913697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc) 9923697e599SPeng Fan { 9933697e599SPeng Fan int err, i; 9943697e599SPeng Fan struct mmc_cmd cmd; 9953697e599SPeng Fan ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16); 9963697e599SPeng Fan struct mmc_data data; 9973697e599SPeng Fan int timeout = 3; 9983697e599SPeng Fan unsigned int au, eo, et, es; 9993697e599SPeng Fan 10003697e599SPeng Fan cmd.cmdidx = MMC_CMD_APP_CMD; 10013697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 10023697e599SPeng Fan cmd.cmdarg = mmc->rca << 16; 10033697e599SPeng Fan 10043697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, NULL); 10053697e599SPeng Fan if (err) 10063697e599SPeng Fan return err; 10073697e599SPeng Fan 10083697e599SPeng Fan cmd.cmdidx = SD_CMD_APP_SD_STATUS; 10093697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 10103697e599SPeng Fan cmd.cmdarg = 0; 10113697e599SPeng Fan 10123697e599SPeng Fan retry_ssr: 10133697e599SPeng Fan data.dest = (char *)ssr; 10143697e599SPeng Fan data.blocksize = 64; 10153697e599SPeng Fan data.blocks = 1; 10163697e599SPeng Fan data.flags = MMC_DATA_READ; 10173697e599SPeng Fan 10183697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, &data); 10193697e599SPeng Fan if (err) { 10203697e599SPeng Fan if (timeout--) 10213697e599SPeng Fan goto retry_ssr; 10223697e599SPeng Fan 10233697e599SPeng Fan return err; 10243697e599SPeng Fan } 10253697e599SPeng Fan 10263697e599SPeng Fan for (i = 0; i < 16; i++) 10273697e599SPeng Fan ssr[i] = be32_to_cpu(ssr[i]); 10283697e599SPeng Fan 10293697e599SPeng Fan au = (ssr[2] >> 12) & 0xF; 10303697e599SPeng Fan if ((au <= 9) || (mmc->version == SD_VERSION_3)) { 10313697e599SPeng Fan mmc->ssr.au = sd_au_size[au]; 10323697e599SPeng Fan es = (ssr[3] >> 24) & 0xFF; 10333697e599SPeng Fan es |= (ssr[2] & 0xFF) << 8; 10343697e599SPeng Fan et = (ssr[3] >> 18) & 0x3F; 10353697e599SPeng Fan if (es && et) { 10363697e599SPeng Fan eo = (ssr[3] >> 16) & 0x3; 10373697e599SPeng Fan mmc->ssr.erase_timeout = (et * 1000) / es; 10383697e599SPeng Fan mmc->ssr.erase_offset = eo * 1000; 10393697e599SPeng Fan } 10403697e599SPeng Fan } else { 10413697e599SPeng Fan debug("Invalid Allocation Unit Size.\n"); 10423697e599SPeng Fan } 10433697e599SPeng Fan 10443697e599SPeng Fan return 0; 10453697e599SPeng Fan } 10463697e599SPeng Fan 1047272cc70bSAndy Fleming /* frequency bases */ 1048272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */ 10495f837c2cSMike Frysinger static const int fbase[] = { 1050272cc70bSAndy Fleming 10000, 1051272cc70bSAndy Fleming 100000, 1052272cc70bSAndy Fleming 1000000, 1053272cc70bSAndy Fleming 10000000, 1054272cc70bSAndy Fleming }; 1055272cc70bSAndy Fleming 1056272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice 1057272cc70bSAndy Fleming * to platforms without floating point. 1058272cc70bSAndy Fleming */ 105961fe076fSSimon Glass static const u8 multipliers[] = { 1060272cc70bSAndy Fleming 0, /* reserved */ 1061272cc70bSAndy Fleming 10, 1062272cc70bSAndy Fleming 12, 1063272cc70bSAndy Fleming 13, 1064272cc70bSAndy Fleming 15, 1065272cc70bSAndy Fleming 20, 1066272cc70bSAndy Fleming 25, 1067272cc70bSAndy Fleming 30, 1068272cc70bSAndy Fleming 35, 1069272cc70bSAndy Fleming 40, 1070272cc70bSAndy Fleming 45, 1071272cc70bSAndy Fleming 50, 1072272cc70bSAndy Fleming 55, 1073272cc70bSAndy Fleming 60, 1074272cc70bSAndy Fleming 70, 1075272cc70bSAndy Fleming 80, 1076272cc70bSAndy Fleming }; 1077272cc70bSAndy Fleming 1078e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 1079fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc) 1080272cc70bSAndy Fleming { 108193bfd616SPantelis Antoniou if (mmc->cfg->ops->set_ios) 108293bfd616SPantelis Antoniou mmc->cfg->ops->set_ios(mmc); 1083272cc70bSAndy Fleming } 10848ca51e51SSimon Glass #endif 1085272cc70bSAndy Fleming 1086272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock) 1087272cc70bSAndy Fleming { 108893bfd616SPantelis Antoniou if (clock > mmc->cfg->f_max) 108993bfd616SPantelis Antoniou clock = mmc->cfg->f_max; 1090272cc70bSAndy Fleming 109193bfd616SPantelis Antoniou if (clock < mmc->cfg->f_min) 109293bfd616SPantelis Antoniou clock = mmc->cfg->f_min; 1093272cc70bSAndy Fleming 1094272cc70bSAndy Fleming mmc->clock = clock; 1095272cc70bSAndy Fleming 1096272cc70bSAndy Fleming mmc_set_ios(mmc); 1097272cc70bSAndy Fleming } 1098272cc70bSAndy Fleming 1099fdbb873eSKim Phillips static void mmc_set_bus_width(struct mmc *mmc, uint width) 1100272cc70bSAndy Fleming { 1101272cc70bSAndy Fleming mmc->bus_width = width; 1102272cc70bSAndy Fleming 1103272cc70bSAndy Fleming mmc_set_ios(mmc); 1104272cc70bSAndy Fleming } 1105272cc70bSAndy Fleming 11068ac8a263SJean-Jacques Hiblot static int sd_select_bus_freq_width(struct mmc *mmc) 11078ac8a263SJean-Jacques Hiblot { 11088ac8a263SJean-Jacques Hiblot int err; 11098ac8a263SJean-Jacques Hiblot struct mmc_cmd cmd; 11108ac8a263SJean-Jacques Hiblot 11118ac8a263SJean-Jacques Hiblot err = sd_change_freq(mmc); 11128ac8a263SJean-Jacques Hiblot if (err) 11138ac8a263SJean-Jacques Hiblot return err; 11148ac8a263SJean-Jacques Hiblot 11158ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */ 11168ac8a263SJean-Jacques Hiblot mmc->card_caps &= mmc->cfg->host_caps; 11178ac8a263SJean-Jacques Hiblot 11188ac8a263SJean-Jacques Hiblot if (mmc->card_caps & MMC_MODE_4BIT) { 11198ac8a263SJean-Jacques Hiblot cmd.cmdidx = MMC_CMD_APP_CMD; 11208ac8a263SJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 11218ac8a263SJean-Jacques Hiblot cmd.cmdarg = mmc->rca << 16; 11228ac8a263SJean-Jacques Hiblot 11238ac8a263SJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 11248ac8a263SJean-Jacques Hiblot if (err) 11258ac8a263SJean-Jacques Hiblot return err; 11268ac8a263SJean-Jacques Hiblot 11278ac8a263SJean-Jacques Hiblot cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; 11288ac8a263SJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 11298ac8a263SJean-Jacques Hiblot cmd.cmdarg = 2; 11308ac8a263SJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 11318ac8a263SJean-Jacques Hiblot if (err) 11328ac8a263SJean-Jacques Hiblot return err; 11338ac8a263SJean-Jacques Hiblot 11348ac8a263SJean-Jacques Hiblot mmc_set_bus_width(mmc, 4); 11358ac8a263SJean-Jacques Hiblot } 11368ac8a263SJean-Jacques Hiblot 11378ac8a263SJean-Jacques Hiblot err = sd_read_ssr(mmc); 11388ac8a263SJean-Jacques Hiblot if (err) 11398ac8a263SJean-Jacques Hiblot return err; 11408ac8a263SJean-Jacques Hiblot 11418ac8a263SJean-Jacques Hiblot if (mmc->card_caps & MMC_MODE_HS) 11428ac8a263SJean-Jacques Hiblot mmc->tran_speed = 50000000; 11438ac8a263SJean-Jacques Hiblot else 11448ac8a263SJean-Jacques Hiblot mmc->tran_speed = 25000000; 11458ac8a263SJean-Jacques Hiblot 11468ac8a263SJean-Jacques Hiblot return 0; 11478ac8a263SJean-Jacques Hiblot } 11488ac8a263SJean-Jacques Hiblot 11498ac8a263SJean-Jacques Hiblot static int mmc_select_bus_freq_width(struct mmc *mmc, const u8 *ext_csd) 11508ac8a263SJean-Jacques Hiblot { 11518ac8a263SJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 11528ac8a263SJean-Jacques Hiblot /* An array of possible bus widths in order of preference */ 11538ac8a263SJean-Jacques Hiblot static const unsigned int ext_csd_bits[] = { 11548ac8a263SJean-Jacques Hiblot EXT_CSD_DDR_BUS_WIDTH_8, 11558ac8a263SJean-Jacques Hiblot EXT_CSD_DDR_BUS_WIDTH_4, 11568ac8a263SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH_8, 11578ac8a263SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH_4, 11588ac8a263SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH_1, 11598ac8a263SJean-Jacques Hiblot }; 11608ac8a263SJean-Jacques Hiblot /* An array to map CSD bus widths to host cap bits */ 11618ac8a263SJean-Jacques Hiblot static const unsigned int ext_to_hostcaps[] = { 11628ac8a263SJean-Jacques Hiblot [EXT_CSD_DDR_BUS_WIDTH_4] = 11638ac8a263SJean-Jacques Hiblot MMC_MODE_DDR_52MHz | MMC_MODE_4BIT, 11648ac8a263SJean-Jacques Hiblot [EXT_CSD_DDR_BUS_WIDTH_8] = 11658ac8a263SJean-Jacques Hiblot MMC_MODE_DDR_52MHz | MMC_MODE_8BIT, 11668ac8a263SJean-Jacques Hiblot [EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT, 11678ac8a263SJean-Jacques Hiblot [EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT, 11688ac8a263SJean-Jacques Hiblot }; 11698ac8a263SJean-Jacques Hiblot /* An array to map chosen bus width to an integer */ 11708ac8a263SJean-Jacques Hiblot static const unsigned int widths[] = { 11718ac8a263SJean-Jacques Hiblot 8, 4, 8, 4, 1, 11728ac8a263SJean-Jacques Hiblot }; 11738ac8a263SJean-Jacques Hiblot int err; 11748ac8a263SJean-Jacques Hiblot int idx; 11758ac8a263SJean-Jacques Hiblot 11768ac8a263SJean-Jacques Hiblot err = mmc_change_freq(mmc); 11778ac8a263SJean-Jacques Hiblot if (err) 11788ac8a263SJean-Jacques Hiblot return err; 11798ac8a263SJean-Jacques Hiblot 11808ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */ 11818ac8a263SJean-Jacques Hiblot mmc->card_caps &= mmc->cfg->host_caps; 11828ac8a263SJean-Jacques Hiblot 11838ac8a263SJean-Jacques Hiblot /* Only version 4 of MMC supports wider bus widths */ 11848ac8a263SJean-Jacques Hiblot if (mmc->version < MMC_VERSION_4) 11858ac8a263SJean-Jacques Hiblot return 0; 11868ac8a263SJean-Jacques Hiblot 11878ac8a263SJean-Jacques Hiblot for (idx = 0; idx < ARRAY_SIZE(ext_csd_bits); idx++) { 11888ac8a263SJean-Jacques Hiblot unsigned int extw = ext_csd_bits[idx]; 11898ac8a263SJean-Jacques Hiblot unsigned int caps = ext_to_hostcaps[extw]; 11908ac8a263SJean-Jacques Hiblot /* 11918ac8a263SJean-Jacques Hiblot * If the bus width is still not changed, 11928ac8a263SJean-Jacques Hiblot * don't try to set the default again. 11938ac8a263SJean-Jacques Hiblot * Otherwise, recover from switch attempts 11948ac8a263SJean-Jacques Hiblot * by switching to 1-bit bus width. 11958ac8a263SJean-Jacques Hiblot */ 11968ac8a263SJean-Jacques Hiblot if (extw == EXT_CSD_BUS_WIDTH_1 && 11978ac8a263SJean-Jacques Hiblot mmc->bus_width == 1) { 11988ac8a263SJean-Jacques Hiblot err = 0; 11998ac8a263SJean-Jacques Hiblot break; 12008ac8a263SJean-Jacques Hiblot } 12018ac8a263SJean-Jacques Hiblot 12028ac8a263SJean-Jacques Hiblot /* 12038ac8a263SJean-Jacques Hiblot * Check to make sure the card and controller support 12048ac8a263SJean-Jacques Hiblot * these capabilities 12058ac8a263SJean-Jacques Hiblot */ 12068ac8a263SJean-Jacques Hiblot if ((mmc->card_caps & caps) != caps) 12078ac8a263SJean-Jacques Hiblot continue; 12088ac8a263SJean-Jacques Hiblot 12098ac8a263SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 12108ac8a263SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, extw); 12118ac8a263SJean-Jacques Hiblot 12128ac8a263SJean-Jacques Hiblot if (err) 12138ac8a263SJean-Jacques Hiblot continue; 12148ac8a263SJean-Jacques Hiblot 12158ac8a263SJean-Jacques Hiblot mmc->ddr_mode = (caps & MMC_MODE_DDR_52MHz) ? 1 : 0; 12168ac8a263SJean-Jacques Hiblot mmc_set_bus_width(mmc, widths[idx]); 12178ac8a263SJean-Jacques Hiblot 12188ac8a263SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, test_csd); 12198ac8a263SJean-Jacques Hiblot 12208ac8a263SJean-Jacques Hiblot if (err) 12218ac8a263SJean-Jacques Hiblot continue; 12228ac8a263SJean-Jacques Hiblot 12238ac8a263SJean-Jacques Hiblot /* Only compare read only fields */ 12248ac8a263SJean-Jacques Hiblot if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] 12258ac8a263SJean-Jacques Hiblot == test_csd[EXT_CSD_PARTITIONING_SUPPORT] && 12268ac8a263SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_WP_GRP_SIZE] 12278ac8a263SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_WP_GRP_SIZE] && 12288ac8a263SJean-Jacques Hiblot ext_csd[EXT_CSD_REV] 12298ac8a263SJean-Jacques Hiblot == test_csd[EXT_CSD_REV] && 12308ac8a263SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 12318ac8a263SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] && 12328ac8a263SJean-Jacques Hiblot memcmp(&ext_csd[EXT_CSD_SEC_CNT], 12338ac8a263SJean-Jacques Hiblot &test_csd[EXT_CSD_SEC_CNT], 4) == 0) 12348ac8a263SJean-Jacques Hiblot break; 12358ac8a263SJean-Jacques Hiblot 12368ac8a263SJean-Jacques Hiblot err = -EBADMSG; 12378ac8a263SJean-Jacques Hiblot } 12388ac8a263SJean-Jacques Hiblot 12398ac8a263SJean-Jacques Hiblot if (err) 12408ac8a263SJean-Jacques Hiblot return err; 12418ac8a263SJean-Jacques Hiblot 12428ac8a263SJean-Jacques Hiblot if (mmc->card_caps & MMC_MODE_HS) { 12438ac8a263SJean-Jacques Hiblot if (mmc->card_caps & MMC_MODE_HS_52MHz) 12448ac8a263SJean-Jacques Hiblot mmc->tran_speed = 52000000; 12458ac8a263SJean-Jacques Hiblot else 12468ac8a263SJean-Jacques Hiblot mmc->tran_speed = 26000000; 12478ac8a263SJean-Jacques Hiblot } 12488ac8a263SJean-Jacques Hiblot 12498ac8a263SJean-Jacques Hiblot return err; 12508ac8a263SJean-Jacques Hiblot } 12518ac8a263SJean-Jacques Hiblot 1252*c744b6f6SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc, u8 *ext_csd) 1253*c744b6f6SJean-Jacques Hiblot { 1254*c744b6f6SJean-Jacques Hiblot int err, i; 1255*c744b6f6SJean-Jacques Hiblot u64 capacity; 1256*c744b6f6SJean-Jacques Hiblot bool has_parts = false; 1257*c744b6f6SJean-Jacques Hiblot bool part_completed; 1258*c744b6f6SJean-Jacques Hiblot 1259*c744b6f6SJean-Jacques Hiblot if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4)) 1260*c744b6f6SJean-Jacques Hiblot return 0; 1261*c744b6f6SJean-Jacques Hiblot 1262*c744b6f6SJean-Jacques Hiblot /* check ext_csd version and capacity */ 1263*c744b6f6SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, ext_csd); 1264*c744b6f6SJean-Jacques Hiblot if (err) 1265*c744b6f6SJean-Jacques Hiblot return err; 1266*c744b6f6SJean-Jacques Hiblot if (ext_csd[EXT_CSD_REV] >= 2) { 1267*c744b6f6SJean-Jacques Hiblot /* 1268*c744b6f6SJean-Jacques Hiblot * According to the JEDEC Standard, the value of 1269*c744b6f6SJean-Jacques Hiblot * ext_csd's capacity is valid if the value is more 1270*c744b6f6SJean-Jacques Hiblot * than 2GB 1271*c744b6f6SJean-Jacques Hiblot */ 1272*c744b6f6SJean-Jacques Hiblot capacity = ext_csd[EXT_CSD_SEC_CNT] << 0 1273*c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 1274*c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 1275*c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; 1276*c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN; 1277*c744b6f6SJean-Jacques Hiblot if ((capacity >> 20) > 2 * 1024) 1278*c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity; 1279*c744b6f6SJean-Jacques Hiblot } 1280*c744b6f6SJean-Jacques Hiblot 1281*c744b6f6SJean-Jacques Hiblot switch (ext_csd[EXT_CSD_REV]) { 1282*c744b6f6SJean-Jacques Hiblot case 1: 1283*c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_1; 1284*c744b6f6SJean-Jacques Hiblot break; 1285*c744b6f6SJean-Jacques Hiblot case 2: 1286*c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_2; 1287*c744b6f6SJean-Jacques Hiblot break; 1288*c744b6f6SJean-Jacques Hiblot case 3: 1289*c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_3; 1290*c744b6f6SJean-Jacques Hiblot break; 1291*c744b6f6SJean-Jacques Hiblot case 5: 1292*c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_41; 1293*c744b6f6SJean-Jacques Hiblot break; 1294*c744b6f6SJean-Jacques Hiblot case 6: 1295*c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_5; 1296*c744b6f6SJean-Jacques Hiblot break; 1297*c744b6f6SJean-Jacques Hiblot case 7: 1298*c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_5_0; 1299*c744b6f6SJean-Jacques Hiblot break; 1300*c744b6f6SJean-Jacques Hiblot case 8: 1301*c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_5_1; 1302*c744b6f6SJean-Jacques Hiblot break; 1303*c744b6f6SJean-Jacques Hiblot } 1304*c744b6f6SJean-Jacques Hiblot 1305*c744b6f6SJean-Jacques Hiblot /* The partition data may be non-zero but it is only 1306*c744b6f6SJean-Jacques Hiblot * effective if PARTITION_SETTING_COMPLETED is set in 1307*c744b6f6SJean-Jacques Hiblot * EXT_CSD, so ignore any data if this bit is not set, 1308*c744b6f6SJean-Jacques Hiblot * except for enabling the high-capacity group size 1309*c744b6f6SJean-Jacques Hiblot * definition (see below). 1310*c744b6f6SJean-Jacques Hiblot */ 1311*c744b6f6SJean-Jacques Hiblot part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] & 1312*c744b6f6SJean-Jacques Hiblot EXT_CSD_PARTITION_SETTING_COMPLETED); 1313*c744b6f6SJean-Jacques Hiblot 1314*c744b6f6SJean-Jacques Hiblot /* store the partition info of emmc */ 1315*c744b6f6SJean-Jacques Hiblot mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT]; 1316*c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || 1317*c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_BOOT_MULT]) 1318*c744b6f6SJean-Jacques Hiblot mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; 1319*c744b6f6SJean-Jacques Hiblot if (part_completed && 1320*c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT)) 1321*c744b6f6SJean-Jacques Hiblot mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]; 1322*c744b6f6SJean-Jacques Hiblot 1323*c744b6f6SJean-Jacques Hiblot mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17; 1324*c744b6f6SJean-Jacques Hiblot 1325*c744b6f6SJean-Jacques Hiblot mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17; 1326*c744b6f6SJean-Jacques Hiblot 1327*c744b6f6SJean-Jacques Hiblot for (i = 0; i < 4; i++) { 1328*c744b6f6SJean-Jacques Hiblot int idx = EXT_CSD_GP_SIZE_MULT + i * 3; 1329*c744b6f6SJean-Jacques Hiblot uint mult = (ext_csd[idx + 2] << 16) + 1330*c744b6f6SJean-Jacques Hiblot (ext_csd[idx + 1] << 8) + ext_csd[idx]; 1331*c744b6f6SJean-Jacques Hiblot if (mult) 1332*c744b6f6SJean-Jacques Hiblot has_parts = true; 1333*c744b6f6SJean-Jacques Hiblot if (!part_completed) 1334*c744b6f6SJean-Jacques Hiblot continue; 1335*c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] = mult; 1336*c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= 1337*c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1338*c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1339*c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] <<= 19; 1340*c744b6f6SJean-Jacques Hiblot } 1341*c744b6f6SJean-Jacques Hiblot 1342*c744b6f6SJean-Jacques Hiblot if (part_completed) { 1343*c744b6f6SJean-Jacques Hiblot mmc->enh_user_size = 1344*c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) + 1345*c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) + 1346*c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_SIZE_MULT]; 1347*c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1348*c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1349*c744b6f6SJean-Jacques Hiblot mmc->enh_user_size <<= 19; 1350*c744b6f6SJean-Jacques Hiblot mmc->enh_user_start = 1351*c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) + 1352*c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) + 1353*c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) + 1354*c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_START_ADDR]; 1355*c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity) 1356*c744b6f6SJean-Jacques Hiblot mmc->enh_user_start <<= 9; 1357*c744b6f6SJean-Jacques Hiblot } 1358*c744b6f6SJean-Jacques Hiblot 1359*c744b6f6SJean-Jacques Hiblot /* 1360*c744b6f6SJean-Jacques Hiblot * Host needs to enable ERASE_GRP_DEF bit if device is 1361*c744b6f6SJean-Jacques Hiblot * partitioned. This bit will be lost every time after a reset 1362*c744b6f6SJean-Jacques Hiblot * or power off. This will affect erase size. 1363*c744b6f6SJean-Jacques Hiblot */ 1364*c744b6f6SJean-Jacques Hiblot if (part_completed) 1365*c744b6f6SJean-Jacques Hiblot has_parts = true; 1366*c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) && 1367*c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) 1368*c744b6f6SJean-Jacques Hiblot has_parts = true; 1369*c744b6f6SJean-Jacques Hiblot if (has_parts) { 1370*c744b6f6SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1371*c744b6f6SJean-Jacques Hiblot EXT_CSD_ERASE_GROUP_DEF, 1); 1372*c744b6f6SJean-Jacques Hiblot 1373*c744b6f6SJean-Jacques Hiblot if (err) 1374*c744b6f6SJean-Jacques Hiblot return err; 1375*c744b6f6SJean-Jacques Hiblot 1376*c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 1377*c744b6f6SJean-Jacques Hiblot } 1378*c744b6f6SJean-Jacques Hiblot 1379*c744b6f6SJean-Jacques Hiblot if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) { 1380*c744b6f6SJean-Jacques Hiblot /* Read out group size from ext_csd */ 1381*c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = 1382*c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 1383*c744b6f6SJean-Jacques Hiblot /* 1384*c744b6f6SJean-Jacques Hiblot * if high capacity and partition setting completed 1385*c744b6f6SJean-Jacques Hiblot * SEC_COUNT is valid even if it is smaller than 2 GiB 1386*c744b6f6SJean-Jacques Hiblot * JEDEC Standard JESD84-B45, 6.2.4 1387*c744b6f6SJean-Jacques Hiblot */ 1388*c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity && part_completed) { 1389*c744b6f6SJean-Jacques Hiblot capacity = (ext_csd[EXT_CSD_SEC_CNT]) | 1390*c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) | 1391*c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) | 1392*c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 3] << 24); 1393*c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN; 1394*c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity; 1395*c744b6f6SJean-Jacques Hiblot } 1396*c744b6f6SJean-Jacques Hiblot } else { 1397*c744b6f6SJean-Jacques Hiblot /* Calculate the group size from the csd value. */ 1398*c744b6f6SJean-Jacques Hiblot int erase_gsz, erase_gmul; 1399*c744b6f6SJean-Jacques Hiblot 1400*c744b6f6SJean-Jacques Hiblot erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; 1401*c744b6f6SJean-Jacques Hiblot erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; 1402*c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = (erase_gsz + 1) 1403*c744b6f6SJean-Jacques Hiblot * (erase_gmul + 1); 1404*c744b6f6SJean-Jacques Hiblot } 1405*c744b6f6SJean-Jacques Hiblot 1406*c744b6f6SJean-Jacques Hiblot mmc->hc_wp_grp_size = 1024 1407*c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 1408*c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1409*c744b6f6SJean-Jacques Hiblot 1410*c744b6f6SJean-Jacques Hiblot mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 1411*c744b6f6SJean-Jacques Hiblot 1412*c744b6f6SJean-Jacques Hiblot return 0; 1413*c744b6f6SJean-Jacques Hiblot } 1414*c744b6f6SJean-Jacques Hiblot 1415fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc) 1416272cc70bSAndy Fleming { 1417f866a46dSStephen Warren int err, i; 1418272cc70bSAndy Fleming uint mult, freq; 1419*c744b6f6SJean-Jacques Hiblot u64 cmult, csize; 1420272cc70bSAndy Fleming struct mmc_cmd cmd; 14218bfa195eSSimon Glass ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 1422c40fdca6SSimon Glass struct blk_desc *bdesc; 1423272cc70bSAndy Fleming 1424d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON 1425d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ 1426d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; 1427d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R1; 1428d52ebf10SThomas Chou cmd.cmdarg = 1; 1429d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 1430d52ebf10SThomas Chou 1431d52ebf10SThomas Chou if (err) 1432d52ebf10SThomas Chou return err; 1433d52ebf10SThomas Chou } 1434d52ebf10SThomas Chou #endif 1435d52ebf10SThomas Chou 1436272cc70bSAndy Fleming /* Put the Card in Identify Mode */ 1437d52ebf10SThomas Chou cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : 1438d52ebf10SThomas Chou MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ 1439272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1440272cc70bSAndy Fleming cmd.cmdarg = 0; 1441272cc70bSAndy Fleming 1442272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1443272cc70bSAndy Fleming 1444272cc70bSAndy Fleming if (err) 1445272cc70bSAndy Fleming return err; 1446272cc70bSAndy Fleming 1447272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16); 1448272cc70bSAndy Fleming 1449272cc70bSAndy Fleming /* 1450272cc70bSAndy Fleming * For MMC cards, set the Relative Address. 1451272cc70bSAndy Fleming * For SD cards, get the Relatvie Address. 1452272cc70bSAndy Fleming * This also puts the cards into Standby State 1453272cc70bSAndy Fleming */ 1454d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1455272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; 1456272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1457272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6; 1458272cc70bSAndy Fleming 1459272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1460272cc70bSAndy Fleming 1461272cc70bSAndy Fleming if (err) 1462272cc70bSAndy Fleming return err; 1463272cc70bSAndy Fleming 1464272cc70bSAndy Fleming if (IS_SD(mmc)) 1465998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff; 1466d52ebf10SThomas Chou } 1467272cc70bSAndy Fleming 1468272cc70bSAndy Fleming /* Get the Card-Specific Data */ 1469272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD; 1470272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1471272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1472272cc70bSAndy Fleming 1473272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1474272cc70bSAndy Fleming 1475272cc70bSAndy Fleming if (err) 1476272cc70bSAndy Fleming return err; 1477272cc70bSAndy Fleming 1478998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0]; 1479998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1]; 1480998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2]; 1481998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3]; 1482272cc70bSAndy Fleming 1483272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) { 14840b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf; 1485272cc70bSAndy Fleming 1486272cc70bSAndy Fleming switch (version) { 1487272cc70bSAndy Fleming case 0: 1488272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1489272cc70bSAndy Fleming break; 1490272cc70bSAndy Fleming case 1: 1491272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4; 1492272cc70bSAndy Fleming break; 1493272cc70bSAndy Fleming case 2: 1494272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2; 1495272cc70bSAndy Fleming break; 1496272cc70bSAndy Fleming case 3: 1497272cc70bSAndy Fleming mmc->version = MMC_VERSION_3; 1498272cc70bSAndy Fleming break; 1499272cc70bSAndy Fleming case 4: 1500272cc70bSAndy Fleming mmc->version = MMC_VERSION_4; 1501272cc70bSAndy Fleming break; 1502272cc70bSAndy Fleming default: 1503272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1504272cc70bSAndy Fleming break; 1505272cc70bSAndy Fleming } 1506272cc70bSAndy Fleming } 1507272cc70bSAndy Fleming 1508272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */ 15090b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)]; 15100b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; 1511272cc70bSAndy Fleming 1512272cc70bSAndy Fleming mmc->tran_speed = freq * mult; 1513272cc70bSAndy Fleming 1514ab71188cSMarkus Niebel mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); 1515998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); 1516272cc70bSAndy Fleming 1517272cc70bSAndy Fleming if (IS_SD(mmc)) 1518272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len; 1519272cc70bSAndy Fleming else 1520998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); 1521272cc70bSAndy Fleming 1522272cc70bSAndy Fleming if (mmc->high_capacity) { 1523272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16 1524272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16; 1525272cc70bSAndy Fleming cmult = 8; 1526272cc70bSAndy Fleming } else { 1527272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2 1528272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30; 1529272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15; 1530272cc70bSAndy Fleming } 1531272cc70bSAndy Fleming 1532f866a46dSStephen Warren mmc->capacity_user = (csize + 1) << (cmult + 2); 1533f866a46dSStephen Warren mmc->capacity_user *= mmc->read_bl_len; 1534f866a46dSStephen Warren mmc->capacity_boot = 0; 1535f866a46dSStephen Warren mmc->capacity_rpmb = 0; 1536f866a46dSStephen Warren for (i = 0; i < 4; i++) 1537f866a46dSStephen Warren mmc->capacity_gp[i] = 0; 1538272cc70bSAndy Fleming 15398bfa195eSSimon Glass if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN) 15408bfa195eSSimon Glass mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 1541272cc70bSAndy Fleming 15428bfa195eSSimon Glass if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) 15438bfa195eSSimon Glass mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 1544272cc70bSAndy Fleming 1545ab71188cSMarkus Niebel if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) { 1546ab71188cSMarkus Niebel cmd.cmdidx = MMC_CMD_SET_DSR; 1547ab71188cSMarkus Niebel cmd.cmdarg = (mmc->dsr & 0xffff) << 16; 1548ab71188cSMarkus Niebel cmd.resp_type = MMC_RSP_NONE; 1549ab71188cSMarkus Niebel if (mmc_send_cmd(mmc, &cmd, NULL)) 1550ab71188cSMarkus Niebel printf("MMC: SET_DSR failed\n"); 1551ab71188cSMarkus Niebel } 1552ab71188cSMarkus Niebel 1553272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */ 1554d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1555272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD; 1556fe8f7066SAjay Bhargav cmd.resp_type = MMC_RSP_R1; 1557272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1558272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1559272cc70bSAndy Fleming 1560272cc70bSAndy Fleming if (err) 1561272cc70bSAndy Fleming return err; 1562d52ebf10SThomas Chou } 1563272cc70bSAndy Fleming 1564e6f99a56SLei Wen /* 1565e6f99a56SLei Wen * For SD, its erase group is always one sector 1566e6f99a56SLei Wen */ 1567e6f99a56SLei Wen mmc->erase_grp_size = 1; 1568bc897b1dSLei Wen mmc->part_config = MMCPART_NOAVAILABLE; 1569*c744b6f6SJean-Jacques Hiblot 1570*c744b6f6SJean-Jacques Hiblot err = mmc_startup_v4(mmc, ext_csd); 15719cf199ebSDiego Santa Cruz if (err) 15729cf199ebSDiego Santa Cruz return err; 1573f866a46dSStephen Warren 1574c40fdca6SSimon Glass err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart); 1575f866a46dSStephen Warren if (err) 1576f866a46dSStephen Warren return err; 1577d23e2c09SSukumar Ghorai 1578272cc70bSAndy Fleming if (IS_SD(mmc)) 15798ac8a263SJean-Jacques Hiblot err = sd_select_bus_freq_width(mmc); 1580272cc70bSAndy Fleming else 15818ac8a263SJean-Jacques Hiblot err = mmc_select_bus_freq_width(mmc, ext_csd); 1582272cc70bSAndy Fleming 1583272cc70bSAndy Fleming if (err) 1584272cc70bSAndy Fleming return err; 1585272cc70bSAndy Fleming 1586ad5fd922SJaehoon Chung mmc_set_clock(mmc, mmc->tran_speed); 1587272cc70bSAndy Fleming 15885af8f45cSAndrew Gabbasov /* Fix the block length for DDR mode */ 15895af8f45cSAndrew Gabbasov if (mmc->ddr_mode) { 15905af8f45cSAndrew Gabbasov mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 15915af8f45cSAndrew Gabbasov mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 15925af8f45cSAndrew Gabbasov } 15935af8f45cSAndrew Gabbasov 1594272cc70bSAndy Fleming /* fill in device description */ 1595c40fdca6SSimon Glass bdesc = mmc_get_blk_desc(mmc); 1596c40fdca6SSimon Glass bdesc->lun = 0; 1597c40fdca6SSimon Glass bdesc->hwpart = 0; 1598c40fdca6SSimon Glass bdesc->type = 0; 1599c40fdca6SSimon Glass bdesc->blksz = mmc->read_bl_len; 1600c40fdca6SSimon Glass bdesc->log2blksz = LOG2(bdesc->blksz); 1601c40fdca6SSimon Glass bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len); 1602fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \ 1603fc011f64SSjoerd Simons (defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \ 1604fc011f64SSjoerd Simons !defined(CONFIG_USE_TINY_PRINTF)) 1605c40fdca6SSimon Glass sprintf(bdesc->vendor, "Man %06x Snr %04x%04x", 1606babce5f6STaylor Hutt mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), 1607babce5f6STaylor Hutt (mmc->cid[3] >> 16) & 0xffff); 1608c40fdca6SSimon Glass sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff, 16090b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 1610babce5f6STaylor Hutt (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff, 1611babce5f6STaylor Hutt (mmc->cid[2] >> 24) & 0xff); 1612c40fdca6SSimon Glass sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf, 1613babce5f6STaylor Hutt (mmc->cid[2] >> 16) & 0xf); 161456196826SPaul Burton #else 1615c40fdca6SSimon Glass bdesc->vendor[0] = 0; 1616c40fdca6SSimon Glass bdesc->product[0] = 0; 1617c40fdca6SSimon Glass bdesc->revision[0] = 0; 161856196826SPaul Burton #endif 1619122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT) 1620c40fdca6SSimon Glass part_init(bdesc); 1621122efd43SMikhail Kshevetskiy #endif 1622272cc70bSAndy Fleming 1623272cc70bSAndy Fleming return 0; 1624272cc70bSAndy Fleming } 1625272cc70bSAndy Fleming 1626fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc) 1627272cc70bSAndy Fleming { 1628272cc70bSAndy Fleming struct mmc_cmd cmd; 1629272cc70bSAndy Fleming int err; 1630272cc70bSAndy Fleming 1631272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND; 1632272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ 163393bfd616SPantelis Antoniou cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa; 1634272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7; 1635272cc70bSAndy Fleming 1636272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1637272cc70bSAndy Fleming 1638272cc70bSAndy Fleming if (err) 1639272cc70bSAndy Fleming return err; 1640272cc70bSAndy Fleming 1641998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa) 1642915ffa52SJaehoon Chung return -EOPNOTSUPP; 1643272cc70bSAndy Fleming else 1644272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 1645272cc70bSAndy Fleming 1646272cc70bSAndy Fleming return 0; 1647272cc70bSAndy Fleming } 1648272cc70bSAndy Fleming 1649c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 165095de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */ 165195de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void) 165295de9ab2SPaul Kocialkowski { 165395de9ab2SPaul Kocialkowski } 165405cbeb7cSSimon Glass #endif 165595de9ab2SPaul Kocialkowski 16562051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc) 16572051aefeSPeng Fan { 1658c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 165906ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR) 16602051aefeSPeng Fan int ret; 16612051aefeSPeng Fan 16622051aefeSPeng Fan ret = device_get_supply_regulator(mmc->dev, "vmmc-supply", 166306ec045fSJean-Jacques Hiblot &mmc->vmmc_supply); 166406ec045fSJean-Jacques Hiblot if (ret) 1665288db7c7SJaehoon Chung debug("%s: No vmmc supply\n", mmc->dev->name); 16662051aefeSPeng Fan 166706ec045fSJean-Jacques Hiblot ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply", 166806ec045fSJean-Jacques Hiblot &mmc->vqmmc_supply); 166906ec045fSJean-Jacques Hiblot if (ret) 167006ec045fSJean-Jacques Hiblot debug("%s: No vqmmc supply\n", mmc->dev->name); 167106ec045fSJean-Jacques Hiblot 167206ec045fSJean-Jacques Hiblot if (mmc->vmmc_supply) { 167306ec045fSJean-Jacques Hiblot ret = regulator_set_enable(mmc->vmmc_supply, true); 16742051aefeSPeng Fan if (ret) { 16752051aefeSPeng Fan puts("Error enabling VMMC supply\n"); 16762051aefeSPeng Fan return ret; 16772051aefeSPeng Fan } 167806ec045fSJean-Jacques Hiblot } 16792051aefeSPeng Fan #endif 168005cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */ 168105cbeb7cSSimon Glass /* 168205cbeb7cSSimon Glass * Driver model should use a regulator, as above, rather than calling 168305cbeb7cSSimon Glass * out to board code. 168405cbeb7cSSimon Glass */ 168505cbeb7cSSimon Glass board_mmc_power_init(); 168605cbeb7cSSimon Glass #endif 16872051aefeSPeng Fan return 0; 16882051aefeSPeng Fan } 16892051aefeSPeng Fan 1690e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc) 1691272cc70bSAndy Fleming { 16928ca51e51SSimon Glass bool no_card; 1693afd5932bSMacpaul Lin int err; 1694272cc70bSAndy Fleming 1695ab769f22SPantelis Antoniou /* we pretend there's no card when init is NULL */ 16968ca51e51SSimon Glass no_card = mmc_getcd(mmc) == 0; 1697e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 16988ca51e51SSimon Glass no_card = no_card || (mmc->cfg->ops->init == NULL); 16998ca51e51SSimon Glass #endif 17008ca51e51SSimon Glass if (no_card) { 170148972d90SThierry Reding mmc->has_init = 0; 170256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 170348972d90SThierry Reding printf("MMC: no card present\n"); 170456196826SPaul Burton #endif 1705915ffa52SJaehoon Chung return -ENOMEDIUM; 170648972d90SThierry Reding } 170748972d90SThierry Reding 1708bc897b1dSLei Wen if (mmc->has_init) 1709bc897b1dSLei Wen return 0; 1710bc897b1dSLei Wen 17115a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 17125a8dbdc6SYangbo Lu mmc_adapter_card_type_ident(); 17135a8dbdc6SYangbo Lu #endif 17142051aefeSPeng Fan err = mmc_power_init(mmc); 17152051aefeSPeng Fan if (err) 17162051aefeSPeng Fan return err; 171795de9ab2SPaul Kocialkowski 1718e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 17198ca51e51SSimon Glass /* The device has already been probed ready for use */ 17208ca51e51SSimon Glass #else 1721ab769f22SPantelis Antoniou /* made sure it's not NULL earlier */ 172293bfd616SPantelis Antoniou err = mmc->cfg->ops->init(mmc); 1723272cc70bSAndy Fleming if (err) 1724272cc70bSAndy Fleming return err; 17258ca51e51SSimon Glass #endif 1726786e8f81SAndrew Gabbasov mmc->ddr_mode = 0; 1727b86b85e2SIlya Yanok mmc_set_bus_width(mmc, 1); 1728b86b85e2SIlya Yanok mmc_set_clock(mmc, 1); 1729b86b85e2SIlya Yanok 1730272cc70bSAndy Fleming /* Reset the Card */ 1731272cc70bSAndy Fleming err = mmc_go_idle(mmc); 1732272cc70bSAndy Fleming 1733272cc70bSAndy Fleming if (err) 1734272cc70bSAndy Fleming return err; 1735272cc70bSAndy Fleming 1736bc897b1dSLei Wen /* The internal partition reset to user partition(0) at every CMD0*/ 1737c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->hwpart = 0; 1738bc897b1dSLei Wen 1739272cc70bSAndy Fleming /* Test for SD version 2 */ 1740272cc70bSAndy Fleming err = mmc_send_if_cond(mmc); 1741272cc70bSAndy Fleming 1742272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */ 1743272cc70bSAndy Fleming err = sd_send_op_cond(mmc); 1744272cc70bSAndy Fleming 1745272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */ 1746915ffa52SJaehoon Chung if (err == -ETIMEDOUT) { 1747272cc70bSAndy Fleming err = mmc_send_op_cond(mmc); 1748272cc70bSAndy Fleming 1749bd47c135SAndrew Gabbasov if (err) { 175056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 1751272cc70bSAndy Fleming printf("Card did not respond to voltage select!\n"); 175256196826SPaul Burton #endif 1753915ffa52SJaehoon Chung return -EOPNOTSUPP; 1754272cc70bSAndy Fleming } 1755272cc70bSAndy Fleming } 1756272cc70bSAndy Fleming 1757bd47c135SAndrew Gabbasov if (!err) 1758e9550449SChe-Liang Chiou mmc->init_in_progress = 1; 1759e9550449SChe-Liang Chiou 1760e9550449SChe-Liang Chiou return err; 1761e9550449SChe-Liang Chiou } 1762e9550449SChe-Liang Chiou 1763e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc) 1764e9550449SChe-Liang Chiou { 1765e9550449SChe-Liang Chiou int err = 0; 1766e9550449SChe-Liang Chiou 1767bd47c135SAndrew Gabbasov mmc->init_in_progress = 0; 1768e9550449SChe-Liang Chiou if (mmc->op_cond_pending) 1769e9550449SChe-Liang Chiou err = mmc_complete_op_cond(mmc); 1770e9550449SChe-Liang Chiou 1771e9550449SChe-Liang Chiou if (!err) 1772bc897b1dSLei Wen err = mmc_startup(mmc); 1773bc897b1dSLei Wen if (err) 1774bc897b1dSLei Wen mmc->has_init = 0; 1775bc897b1dSLei Wen else 1776bc897b1dSLei Wen mmc->has_init = 1; 1777e9550449SChe-Liang Chiou return err; 1778e9550449SChe-Liang Chiou } 1779e9550449SChe-Liang Chiou 1780e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc) 1781e9550449SChe-Liang Chiou { 1782bd47c135SAndrew Gabbasov int err = 0; 1783ce9eca94SMarek Vasut __maybe_unused unsigned start; 1784c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 178533fb211dSSimon Glass struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev); 1786e9550449SChe-Liang Chiou 178733fb211dSSimon Glass upriv->mmc = mmc; 178833fb211dSSimon Glass #endif 1789e9550449SChe-Liang Chiou if (mmc->has_init) 1790e9550449SChe-Liang Chiou return 0; 1791d803fea5SMateusz Zalega 1792d803fea5SMateusz Zalega start = get_timer(0); 1793d803fea5SMateusz Zalega 1794e9550449SChe-Liang Chiou if (!mmc->init_in_progress) 1795e9550449SChe-Liang Chiou err = mmc_start_init(mmc); 1796e9550449SChe-Liang Chiou 1797bd47c135SAndrew Gabbasov if (!err) 1798e9550449SChe-Liang Chiou err = mmc_complete_init(mmc); 1799919b4858SJagan Teki if (err) 1800919b4858SJagan Teki printf("%s: %d, time %lu\n", __func__, err, get_timer(start)); 1801919b4858SJagan Teki 1802bc897b1dSLei Wen return err; 1803272cc70bSAndy Fleming } 1804272cc70bSAndy Fleming 1805ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val) 1806ab71188cSMarkus Niebel { 1807ab71188cSMarkus Niebel mmc->dsr = val; 1808ab71188cSMarkus Niebel return 0; 1809ab71188cSMarkus Niebel } 1810ab71188cSMarkus Niebel 1811cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */ 1812cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis) 1813272cc70bSAndy Fleming { 1814272cc70bSAndy Fleming return -1; 1815272cc70bSAndy Fleming } 1816272cc70bSAndy Fleming 1817cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */ 1818cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis) 1819cee9ab7cSJeroen Hofstee { 1820cee9ab7cSJeroen Hofstee return -1; 1821cee9ab7cSJeroen Hofstee } 1822272cc70bSAndy Fleming 1823e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit) 1824e9550449SChe-Liang Chiou { 1825e9550449SChe-Liang Chiou mmc->preinit = preinit; 1826e9550449SChe-Liang Chiou } 1827e9550449SChe-Liang Chiou 1828c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD) 18298e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 18308e3332e2SSjoerd Simons { 18318e3332e2SSjoerd Simons return 0; 18328e3332e2SSjoerd Simons } 1833c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC) 18348e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 18358e3332e2SSjoerd Simons { 18364a1db6d8SSimon Glass int ret, i; 18378e3332e2SSjoerd Simons struct uclass *uc; 18384a1db6d8SSimon Glass struct udevice *dev; 18398e3332e2SSjoerd Simons 18408e3332e2SSjoerd Simons ret = uclass_get(UCLASS_MMC, &uc); 18418e3332e2SSjoerd Simons if (ret) 18428e3332e2SSjoerd Simons return ret; 18438e3332e2SSjoerd Simons 18444a1db6d8SSimon Glass /* 18454a1db6d8SSimon Glass * Try to add them in sequence order. Really with driver model we 18464a1db6d8SSimon Glass * should allow holes, but the current MMC list does not allow that. 18474a1db6d8SSimon Glass * So if we request 0, 1, 3 we will get 0, 1, 2. 18484a1db6d8SSimon Glass */ 18494a1db6d8SSimon Glass for (i = 0; ; i++) { 18504a1db6d8SSimon Glass ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev); 18514a1db6d8SSimon Glass if (ret == -ENODEV) 18524a1db6d8SSimon Glass break; 18534a1db6d8SSimon Glass } 18544a1db6d8SSimon Glass uclass_foreach_dev(dev, uc) { 18554a1db6d8SSimon Glass ret = device_probe(dev); 18568e3332e2SSjoerd Simons if (ret) 18574a1db6d8SSimon Glass printf("%s - probe failed: %d\n", dev->name, ret); 18588e3332e2SSjoerd Simons } 18598e3332e2SSjoerd Simons 18608e3332e2SSjoerd Simons return 0; 18618e3332e2SSjoerd Simons } 18628e3332e2SSjoerd Simons #else 18638e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 18648e3332e2SSjoerd Simons { 18658e3332e2SSjoerd Simons if (board_mmc_init(bis) < 0) 18668e3332e2SSjoerd Simons cpu_mmc_init(bis); 18678e3332e2SSjoerd Simons 18688e3332e2SSjoerd Simons return 0; 18698e3332e2SSjoerd Simons } 18708e3332e2SSjoerd Simons #endif 1871e9550449SChe-Liang Chiou 1872272cc70bSAndy Fleming int mmc_initialize(bd_t *bis) 1873272cc70bSAndy Fleming { 18741b26bab1SDaniel Kochmański static int initialized = 0; 18758e3332e2SSjoerd Simons int ret; 18761b26bab1SDaniel Kochmański if (initialized) /* Avoid initializing mmc multiple times */ 18771b26bab1SDaniel Kochmański return 0; 18781b26bab1SDaniel Kochmański initialized = 1; 18791b26bab1SDaniel Kochmański 1880c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK) 1881b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY) 1882c40fdca6SSimon Glass mmc_list_init(); 1883c40fdca6SSimon Glass #endif 1884b5b838f1SMarek Vasut #endif 18858e3332e2SSjoerd Simons ret = mmc_probe(bis); 18868e3332e2SSjoerd Simons if (ret) 18878e3332e2SSjoerd Simons return ret; 1888272cc70bSAndy Fleming 1889bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD 1890272cc70bSAndy Fleming print_mmc_devices(','); 1891bb0dc108SYing Zhang #endif 1892272cc70bSAndy Fleming 1893c40fdca6SSimon Glass mmc_do_preinit(); 1894272cc70bSAndy Fleming return 0; 1895272cc70bSAndy Fleming } 1896cd3d4880STomas Melin 1897cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE 1898cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc) 1899cd3d4880STomas Melin { 1900cd3d4880STomas Melin int err; 1901cd3d4880STomas Melin ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 1902cd3d4880STomas Melin 1903cd3d4880STomas Melin err = mmc_send_ext_csd(mmc, ext_csd); 1904cd3d4880STomas Melin if (err) { 1905cd3d4880STomas Melin puts("Could not get ext_csd register values\n"); 1906cd3d4880STomas Melin return err; 1907cd3d4880STomas Melin } 1908cd3d4880STomas Melin 1909cd3d4880STomas Melin if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) { 1910cd3d4880STomas Melin puts("Background operations not supported on device\n"); 1911cd3d4880STomas Melin return -EMEDIUMTYPE; 1912cd3d4880STomas Melin } 1913cd3d4880STomas Melin 1914cd3d4880STomas Melin if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) { 1915cd3d4880STomas Melin puts("Background operations already enabled\n"); 1916cd3d4880STomas Melin return 0; 1917cd3d4880STomas Melin } 1918cd3d4880STomas Melin 1919cd3d4880STomas Melin err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1); 1920cd3d4880STomas Melin if (err) { 1921cd3d4880STomas Melin puts("Failed to enable manual background operations\n"); 1922cd3d4880STomas Melin return err; 1923cd3d4880STomas Melin } 1924cd3d4880STomas Melin 1925cd3d4880STomas Melin puts("Enabled manual background operations\n"); 1926cd3d4880STomas Melin 1927cd3d4880STomas Melin return 0; 1928cd3d4880STomas Melin } 1929cd3d4880STomas Melin #endif 1930