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 33aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage); 34fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc); 35aff5d3c8SKishon Vijay Abraham I 36b5b838f1SMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY) 37b5b838f1SMarek Vasut static struct mmc mmc_static; 38b5b838f1SMarek Vasut struct mmc *find_mmc_device(int dev_num) 39b5b838f1SMarek Vasut { 40b5b838f1SMarek Vasut return &mmc_static; 41b5b838f1SMarek Vasut } 42b5b838f1SMarek Vasut 43b5b838f1SMarek Vasut void mmc_do_preinit(void) 44b5b838f1SMarek Vasut { 45b5b838f1SMarek Vasut struct mmc *m = &mmc_static; 46b5b838f1SMarek Vasut #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 47b5b838f1SMarek Vasut mmc_set_preinit(m, 1); 48b5b838f1SMarek Vasut #endif 49b5b838f1SMarek Vasut if (m->preinit) 50b5b838f1SMarek Vasut mmc_start_init(m); 51b5b838f1SMarek Vasut } 52b5b838f1SMarek Vasut 53b5b838f1SMarek Vasut struct blk_desc *mmc_get_blk_desc(struct mmc *mmc) 54b5b838f1SMarek Vasut { 55b5b838f1SMarek Vasut return &mmc->block_dev; 56b5b838f1SMarek Vasut } 57b5b838f1SMarek Vasut #endif 58b5b838f1SMarek Vasut 59e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 60c10b85d6SJean-Jacques Hiblot 61c10b85d6SJean-Jacques Hiblot static int mmc_wait_dat0(struct mmc *mmc, int state, int timeout) 62c10b85d6SJean-Jacques Hiblot { 63c10b85d6SJean-Jacques Hiblot return -ENOSYS; 64c10b85d6SJean-Jacques Hiblot } 65c10b85d6SJean-Jacques Hiblot 66750121c3SJeroen Hofstee __weak int board_mmc_getwp(struct mmc *mmc) 67d23d8d7eSNikita Kiryanov { 68d23d8d7eSNikita Kiryanov return -1; 69d23d8d7eSNikita Kiryanov } 70d23d8d7eSNikita Kiryanov 71d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc) 72d23d8d7eSNikita Kiryanov { 73d23d8d7eSNikita Kiryanov int wp; 74d23d8d7eSNikita Kiryanov 75d23d8d7eSNikita Kiryanov wp = board_mmc_getwp(mmc); 76d23d8d7eSNikita Kiryanov 77d4e1da4eSPeter Korsgaard if (wp < 0) { 7893bfd616SPantelis Antoniou if (mmc->cfg->ops->getwp) 7993bfd616SPantelis Antoniou wp = mmc->cfg->ops->getwp(mmc); 80d4e1da4eSPeter Korsgaard else 81d4e1da4eSPeter Korsgaard wp = 0; 82d4e1da4eSPeter Korsgaard } 83d23d8d7eSNikita Kiryanov 84d23d8d7eSNikita Kiryanov return wp; 85d23d8d7eSNikita Kiryanov } 86d23d8d7eSNikita Kiryanov 87cee9ab7cSJeroen Hofstee __weak int board_mmc_getcd(struct mmc *mmc) 88cee9ab7cSJeroen Hofstee { 8911fdade2SStefano Babic return -1; 9011fdade2SStefano Babic } 918ca51e51SSimon Glass #endif 9211fdade2SStefano Babic 938635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE 94c0c76ebaSSimon Glass void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd) 95c0c76ebaSSimon Glass { 96c0c76ebaSSimon Glass printf("CMD_SEND:%d\n", cmd->cmdidx); 97c0c76ebaSSimon Glass printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg); 98c0c76ebaSSimon Glass } 99c0c76ebaSSimon Glass 100c0c76ebaSSimon Glass void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret) 101c0c76ebaSSimon Glass { 1025db2fe3aSRaffaele Recalcati int i; 1035db2fe3aSRaffaele Recalcati u8 *ptr; 1045db2fe3aSRaffaele Recalcati 1057863ce58SBin Meng if (ret) { 1067863ce58SBin Meng printf("\t\tRET\t\t\t %d\n", ret); 1077863ce58SBin Meng } else { 1085db2fe3aSRaffaele Recalcati switch (cmd->resp_type) { 1095db2fe3aSRaffaele Recalcati case MMC_RSP_NONE: 1105db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_NONE\n"); 1115db2fe3aSRaffaele Recalcati break; 1125db2fe3aSRaffaele Recalcati case MMC_RSP_R1: 1135db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n", 1145db2fe3aSRaffaele Recalcati cmd->response[0]); 1155db2fe3aSRaffaele Recalcati break; 1165db2fe3aSRaffaele Recalcati case MMC_RSP_R1b: 1175db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n", 1185db2fe3aSRaffaele Recalcati cmd->response[0]); 1195db2fe3aSRaffaele Recalcati break; 1205db2fe3aSRaffaele Recalcati case MMC_RSP_R2: 1215db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R2\t\t 0x%08X \n", 1225db2fe3aSRaffaele Recalcati cmd->response[0]); 1235db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1245db2fe3aSRaffaele Recalcati cmd->response[1]); 1255db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1265db2fe3aSRaffaele Recalcati cmd->response[2]); 1275db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1285db2fe3aSRaffaele Recalcati cmd->response[3]); 1295db2fe3aSRaffaele Recalcati printf("\n"); 1305db2fe3aSRaffaele Recalcati printf("\t\t\t\t\tDUMPING DATA\n"); 1315db2fe3aSRaffaele Recalcati for (i = 0; i < 4; i++) { 1325db2fe3aSRaffaele Recalcati int j; 1335db2fe3aSRaffaele Recalcati printf("\t\t\t\t\t%03d - ", i*4); 134146bec79SDirk Behme ptr = (u8 *)&cmd->response[i]; 1355db2fe3aSRaffaele Recalcati ptr += 3; 1365db2fe3aSRaffaele Recalcati for (j = 0; j < 4; j++) 1375db2fe3aSRaffaele Recalcati printf("%02X ", *ptr--); 1385db2fe3aSRaffaele Recalcati printf("\n"); 1395db2fe3aSRaffaele Recalcati } 1405db2fe3aSRaffaele Recalcati break; 1415db2fe3aSRaffaele Recalcati case MMC_RSP_R3: 1425db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n", 1435db2fe3aSRaffaele Recalcati cmd->response[0]); 1445db2fe3aSRaffaele Recalcati break; 1455db2fe3aSRaffaele Recalcati default: 1465db2fe3aSRaffaele Recalcati printf("\t\tERROR MMC rsp not supported\n"); 1475db2fe3aSRaffaele Recalcati break; 1485db2fe3aSRaffaele Recalcati } 1497863ce58SBin Meng } 150c0c76ebaSSimon Glass } 151c0c76ebaSSimon Glass 152c0c76ebaSSimon Glass void mmc_trace_state(struct mmc *mmc, struct mmc_cmd *cmd) 153c0c76ebaSSimon Glass { 154c0c76ebaSSimon Glass int status; 155c0c76ebaSSimon Glass 156c0c76ebaSSimon Glass status = (cmd->response[0] & MMC_STATUS_CURR_STATE) >> 9; 157c0c76ebaSSimon Glass printf("CURR STATE:%d\n", status); 158c0c76ebaSSimon Glass } 1595db2fe3aSRaffaele Recalcati #endif 160c0c76ebaSSimon Glass 16135f9e196SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG) 16235f9e196SJean-Jacques Hiblot const char *mmc_mode_name(enum bus_mode mode) 16335f9e196SJean-Jacques Hiblot { 16435f9e196SJean-Jacques Hiblot static const char *const names[] = { 16535f9e196SJean-Jacques Hiblot [MMC_LEGACY] = "MMC legacy", 16635f9e196SJean-Jacques Hiblot [SD_LEGACY] = "SD Legacy", 16735f9e196SJean-Jacques Hiblot [MMC_HS] = "MMC High Speed (26MHz)", 16835f9e196SJean-Jacques Hiblot [SD_HS] = "SD High Speed (50MHz)", 16935f9e196SJean-Jacques Hiblot [UHS_SDR12] = "UHS SDR12 (25MHz)", 17035f9e196SJean-Jacques Hiblot [UHS_SDR25] = "UHS SDR25 (50MHz)", 17135f9e196SJean-Jacques Hiblot [UHS_SDR50] = "UHS SDR50 (100MHz)", 17235f9e196SJean-Jacques Hiblot [UHS_SDR104] = "UHS SDR104 (208MHz)", 17335f9e196SJean-Jacques Hiblot [UHS_DDR50] = "UHS DDR50 (50MHz)", 17435f9e196SJean-Jacques Hiblot [MMC_HS_52] = "MMC High Speed (52MHz)", 17535f9e196SJean-Jacques Hiblot [MMC_DDR_52] = "MMC DDR52 (52MHz)", 17635f9e196SJean-Jacques Hiblot [MMC_HS_200] = "HS200 (200MHz)", 17735f9e196SJean-Jacques Hiblot }; 17835f9e196SJean-Jacques Hiblot 17935f9e196SJean-Jacques Hiblot if (mode >= MMC_MODES_END) 18035f9e196SJean-Jacques Hiblot return "Unknown mode"; 18135f9e196SJean-Jacques Hiblot else 18235f9e196SJean-Jacques Hiblot return names[mode]; 18335f9e196SJean-Jacques Hiblot } 18435f9e196SJean-Jacques Hiblot #endif 18535f9e196SJean-Jacques Hiblot 18605038576SJean-Jacques Hiblot static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode) 18705038576SJean-Jacques Hiblot { 18805038576SJean-Jacques Hiblot static const int freqs[] = { 18905038576SJean-Jacques Hiblot [SD_LEGACY] = 25000000, 19005038576SJean-Jacques Hiblot [MMC_HS] = 26000000, 19105038576SJean-Jacques Hiblot [SD_HS] = 50000000, 19205038576SJean-Jacques Hiblot [UHS_SDR12] = 25000000, 19305038576SJean-Jacques Hiblot [UHS_SDR25] = 50000000, 19405038576SJean-Jacques Hiblot [UHS_SDR50] = 100000000, 19505038576SJean-Jacques Hiblot [UHS_SDR104] = 208000000, 19605038576SJean-Jacques Hiblot [UHS_DDR50] = 50000000, 19705038576SJean-Jacques Hiblot [MMC_HS_52] = 52000000, 19805038576SJean-Jacques Hiblot [MMC_DDR_52] = 52000000, 19905038576SJean-Jacques Hiblot [MMC_HS_200] = 200000000, 20005038576SJean-Jacques Hiblot }; 20105038576SJean-Jacques Hiblot 20205038576SJean-Jacques Hiblot if (mode == MMC_LEGACY) 20305038576SJean-Jacques Hiblot return mmc->legacy_speed; 20405038576SJean-Jacques Hiblot else if (mode >= MMC_MODES_END) 20505038576SJean-Jacques Hiblot return 0; 20605038576SJean-Jacques Hiblot else 20705038576SJean-Jacques Hiblot return freqs[mode]; 20805038576SJean-Jacques Hiblot } 20905038576SJean-Jacques Hiblot 21035f9e196SJean-Jacques Hiblot static int mmc_select_mode(struct mmc *mmc, enum bus_mode mode) 21135f9e196SJean-Jacques Hiblot { 21235f9e196SJean-Jacques Hiblot mmc->selected_mode = mode; 21305038576SJean-Jacques Hiblot mmc->tran_speed = mmc_mode2freq(mmc, mode); 2143862b854SJean-Jacques Hiblot mmc->ddr_mode = mmc_is_mode_ddr(mode); 21535f9e196SJean-Jacques Hiblot debug("selecting mode %s (freq : %d MHz)\n", mmc_mode_name(mode), 21635f9e196SJean-Jacques Hiblot mmc->tran_speed / 1000000); 21735f9e196SJean-Jacques Hiblot return 0; 21835f9e196SJean-Jacques Hiblot } 21935f9e196SJean-Jacques Hiblot 220e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 221c0c76ebaSSimon Glass int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) 222c0c76ebaSSimon Glass { 223c0c76ebaSSimon Glass int ret; 224c0c76ebaSSimon Glass 225c0c76ebaSSimon Glass mmmc_trace_before_send(mmc, cmd); 226c0c76ebaSSimon Glass ret = mmc->cfg->ops->send_cmd(mmc, cmd, data); 227c0c76ebaSSimon Glass mmmc_trace_after_send(mmc, cmd, ret); 228c0c76ebaSSimon Glass 2298635ff9eSMarek Vasut return ret; 230272cc70bSAndy Fleming } 2318ca51e51SSimon Glass #endif 232272cc70bSAndy Fleming 233da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout) 2345d4fc8d9SRaffaele Recalcati { 2355d4fc8d9SRaffaele Recalcati struct mmc_cmd cmd; 236d617c426SJan Kloetzke int err, retries = 5; 2375d4fc8d9SRaffaele Recalcati 2385d4fc8d9SRaffaele Recalcati cmd.cmdidx = MMC_CMD_SEND_STATUS; 2395d4fc8d9SRaffaele Recalcati cmd.resp_type = MMC_RSP_R1; 240aaf3d41aSMarek Vasut if (!mmc_host_is_spi(mmc)) 241aaf3d41aSMarek Vasut cmd.cmdarg = mmc->rca << 16; 2425d4fc8d9SRaffaele Recalcati 2431677eef4SAndrew Gabbasov while (1) { 2445d4fc8d9SRaffaele Recalcati err = mmc_send_cmd(mmc, &cmd, NULL); 245d617c426SJan Kloetzke if (!err) { 246d617c426SJan Kloetzke if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) && 247d617c426SJan Kloetzke (cmd.response[0] & MMC_STATUS_CURR_STATE) != 248d617c426SJan Kloetzke MMC_STATE_PRG) 2495d4fc8d9SRaffaele Recalcati break; 250d0c221feSJean-Jacques Hiblot 251d0c221feSJean-Jacques Hiblot if (cmd.response[0] & MMC_STATUS_MASK) { 25256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 253d617c426SJan Kloetzke printf("Status Error: 0x%08X\n", 254d617c426SJan Kloetzke cmd.response[0]); 25556196826SPaul Burton #endif 256915ffa52SJaehoon Chung return -ECOMM; 257d617c426SJan Kloetzke } 258d617c426SJan Kloetzke } else if (--retries < 0) 259d617c426SJan Kloetzke return err; 2605d4fc8d9SRaffaele Recalcati 2611677eef4SAndrew Gabbasov if (timeout-- <= 0) 2621677eef4SAndrew Gabbasov break; 2635d4fc8d9SRaffaele Recalcati 2641677eef4SAndrew Gabbasov udelay(1000); 2651677eef4SAndrew Gabbasov } 2665d4fc8d9SRaffaele Recalcati 267c0c76ebaSSimon Glass mmc_trace_state(mmc, &cmd); 2685b0c942fSJongman Heo if (timeout <= 0) { 26956196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2705d4fc8d9SRaffaele Recalcati printf("Timeout waiting card ready\n"); 27156196826SPaul Burton #endif 272915ffa52SJaehoon Chung return -ETIMEDOUT; 2735d4fc8d9SRaffaele Recalcati } 2745d4fc8d9SRaffaele Recalcati 2755d4fc8d9SRaffaele Recalcati return 0; 2765d4fc8d9SRaffaele Recalcati } 2775d4fc8d9SRaffaele Recalcati 278da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len) 279272cc70bSAndy Fleming { 280272cc70bSAndy Fleming struct mmc_cmd cmd; 281272cc70bSAndy Fleming 282786e8f81SAndrew Gabbasov if (mmc->ddr_mode) 283d22e3d46SJaehoon Chung return 0; 284d22e3d46SJaehoon Chung 285272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SET_BLOCKLEN; 286272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 287272cc70bSAndy Fleming cmd.cmdarg = len; 288272cc70bSAndy Fleming 289272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, NULL); 290272cc70bSAndy Fleming } 291272cc70bSAndy Fleming 292ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start, 293fdbb873eSKim Phillips lbaint_t blkcnt) 294272cc70bSAndy Fleming { 295272cc70bSAndy Fleming struct mmc_cmd cmd; 296272cc70bSAndy Fleming struct mmc_data data; 297272cc70bSAndy Fleming 2984a1a06bcSAlagu Sankar if (blkcnt > 1) 2994a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; 3004a1a06bcSAlagu Sankar else 301272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; 302272cc70bSAndy Fleming 303272cc70bSAndy Fleming if (mmc->high_capacity) 3044a1a06bcSAlagu Sankar cmd.cmdarg = start; 305272cc70bSAndy Fleming else 3064a1a06bcSAlagu Sankar cmd.cmdarg = start * mmc->read_bl_len; 307272cc70bSAndy Fleming 308272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 309272cc70bSAndy Fleming 310272cc70bSAndy Fleming data.dest = dst; 3114a1a06bcSAlagu Sankar data.blocks = blkcnt; 312272cc70bSAndy Fleming data.blocksize = mmc->read_bl_len; 313272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 314272cc70bSAndy Fleming 3154a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, &data)) 3164a1a06bcSAlagu Sankar return 0; 3174a1a06bcSAlagu Sankar 3184a1a06bcSAlagu Sankar if (blkcnt > 1) { 3194a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; 3204a1a06bcSAlagu Sankar cmd.cmdarg = 0; 3214a1a06bcSAlagu Sankar cmd.resp_type = MMC_RSP_R1b; 3224a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, NULL)) { 32356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 3244a1a06bcSAlagu Sankar printf("mmc fail to send stop cmd\n"); 32556196826SPaul Burton #endif 3264a1a06bcSAlagu Sankar return 0; 3274a1a06bcSAlagu Sankar } 328272cc70bSAndy Fleming } 329272cc70bSAndy Fleming 3304a1a06bcSAlagu Sankar return blkcnt; 331272cc70bSAndy Fleming } 332272cc70bSAndy Fleming 333c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK) 3347dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst) 33533fb211dSSimon Glass #else 3367dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, 3377dba0b93SSimon Glass void *dst) 33833fb211dSSimon Glass #endif 339272cc70bSAndy Fleming { 340c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK) 34133fb211dSSimon Glass struct blk_desc *block_dev = dev_get_uclass_platdata(dev); 34233fb211dSSimon Glass #endif 343bcce53d0SSimon Glass int dev_num = block_dev->devnum; 344873cc1d7SStephen Warren int err; 3454a1a06bcSAlagu Sankar lbaint_t cur, blocks_todo = blkcnt; 346272cc70bSAndy Fleming 3474a1a06bcSAlagu Sankar if (blkcnt == 0) 3484a1a06bcSAlagu Sankar return 0; 3494a1a06bcSAlagu Sankar 3504a1a06bcSAlagu Sankar struct mmc *mmc = find_mmc_device(dev_num); 351272cc70bSAndy Fleming if (!mmc) 352272cc70bSAndy Fleming return 0; 353272cc70bSAndy Fleming 354b5b838f1SMarek Vasut if (CONFIG_IS_ENABLED(MMC_TINY)) 355b5b838f1SMarek Vasut err = mmc_switch_part(mmc, block_dev->hwpart); 356b5b838f1SMarek Vasut else 35769f45cd5SSimon Glass err = blk_dselect_hwpart(block_dev, block_dev->hwpart); 358b5b838f1SMarek Vasut 359873cc1d7SStephen Warren if (err < 0) 360873cc1d7SStephen Warren return 0; 361873cc1d7SStephen Warren 362c40fdca6SSimon Glass if ((start + blkcnt) > block_dev->lba) { 36356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 364ff8fef56SSascha Silbe printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", 365c40fdca6SSimon Glass start + blkcnt, block_dev->lba); 36656196826SPaul Burton #endif 367d2bf29e3SLei Wen return 0; 368d2bf29e3SLei Wen } 369272cc70bSAndy Fleming 37011692991SSimon Glass if (mmc_set_blocklen(mmc, mmc->read_bl_len)) { 37111692991SSimon Glass debug("%s: Failed to set blocklen\n", __func__); 372272cc70bSAndy Fleming return 0; 37311692991SSimon Glass } 374272cc70bSAndy Fleming 3754a1a06bcSAlagu Sankar do { 37693bfd616SPantelis Antoniou cur = (blocks_todo > mmc->cfg->b_max) ? 37793bfd616SPantelis Antoniou mmc->cfg->b_max : blocks_todo; 37811692991SSimon Glass if (mmc_read_blocks(mmc, dst, start, cur) != cur) { 37911692991SSimon Glass debug("%s: Failed to read blocks\n", __func__); 3804a1a06bcSAlagu Sankar return 0; 38111692991SSimon Glass } 3824a1a06bcSAlagu Sankar blocks_todo -= cur; 3834a1a06bcSAlagu Sankar start += cur; 3844a1a06bcSAlagu Sankar dst += cur * mmc->read_bl_len; 3854a1a06bcSAlagu Sankar } while (blocks_todo > 0); 386272cc70bSAndy Fleming 387272cc70bSAndy Fleming return blkcnt; 388272cc70bSAndy Fleming } 389272cc70bSAndy Fleming 390fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc) 391272cc70bSAndy Fleming { 392272cc70bSAndy Fleming struct mmc_cmd cmd; 393272cc70bSAndy Fleming int err; 394272cc70bSAndy Fleming 395272cc70bSAndy Fleming udelay(1000); 396272cc70bSAndy Fleming 397272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_GO_IDLE_STATE; 398272cc70bSAndy Fleming cmd.cmdarg = 0; 399272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_NONE; 400272cc70bSAndy Fleming 401272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 402272cc70bSAndy Fleming 403272cc70bSAndy Fleming if (err) 404272cc70bSAndy Fleming return err; 405272cc70bSAndy Fleming 406272cc70bSAndy Fleming udelay(2000); 407272cc70bSAndy Fleming 408272cc70bSAndy Fleming return 0; 409272cc70bSAndy Fleming } 410272cc70bSAndy Fleming 411c10b85d6SJean-Jacques Hiblot static int mmc_switch_voltage(struct mmc *mmc, int signal_voltage) 412c10b85d6SJean-Jacques Hiblot { 413c10b85d6SJean-Jacques Hiblot struct mmc_cmd cmd; 414c10b85d6SJean-Jacques Hiblot int err = 0; 415c10b85d6SJean-Jacques Hiblot 416c10b85d6SJean-Jacques Hiblot /* 417c10b85d6SJean-Jacques Hiblot * Send CMD11 only if the request is to switch the card to 418c10b85d6SJean-Jacques Hiblot * 1.8V signalling. 419c10b85d6SJean-Jacques Hiblot */ 420c10b85d6SJean-Jacques Hiblot if (signal_voltage == MMC_SIGNAL_VOLTAGE_330) 421c10b85d6SJean-Jacques Hiblot return mmc_set_signal_voltage(mmc, signal_voltage); 422c10b85d6SJean-Jacques Hiblot 423c10b85d6SJean-Jacques Hiblot cmd.cmdidx = SD_CMD_SWITCH_UHS18V; 424c10b85d6SJean-Jacques Hiblot cmd.cmdarg = 0; 425c10b85d6SJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 426c10b85d6SJean-Jacques Hiblot 427c10b85d6SJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 428c10b85d6SJean-Jacques Hiblot if (err) 429c10b85d6SJean-Jacques Hiblot return err; 430c10b85d6SJean-Jacques Hiblot 431c10b85d6SJean-Jacques Hiblot if (!mmc_host_is_spi(mmc) && (cmd.response[0] & MMC_STATUS_ERROR)) 432c10b85d6SJean-Jacques Hiblot return -EIO; 433c10b85d6SJean-Jacques Hiblot 434c10b85d6SJean-Jacques Hiblot /* 435c10b85d6SJean-Jacques Hiblot * The card should drive cmd and dat[0:3] low immediately 436c10b85d6SJean-Jacques Hiblot * after the response of cmd11, but wait 100 us to be sure 437c10b85d6SJean-Jacques Hiblot */ 438c10b85d6SJean-Jacques Hiblot err = mmc_wait_dat0(mmc, 0, 100); 439c10b85d6SJean-Jacques Hiblot if (err == -ENOSYS) 440c10b85d6SJean-Jacques Hiblot udelay(100); 441c10b85d6SJean-Jacques Hiblot else if (err) 442c10b85d6SJean-Jacques Hiblot return -ETIMEDOUT; 443c10b85d6SJean-Jacques Hiblot 444c10b85d6SJean-Jacques Hiblot /* 445c10b85d6SJean-Jacques Hiblot * During a signal voltage level switch, the clock must be gated 446c10b85d6SJean-Jacques Hiblot * for 5 ms according to the SD spec 447c10b85d6SJean-Jacques Hiblot */ 448c10b85d6SJean-Jacques Hiblot mmc_set_clock(mmc, mmc->clock, true); 449c10b85d6SJean-Jacques Hiblot 450c10b85d6SJean-Jacques Hiblot err = mmc_set_signal_voltage(mmc, signal_voltage); 451c10b85d6SJean-Jacques Hiblot if (err) 452c10b85d6SJean-Jacques Hiblot return err; 453c10b85d6SJean-Jacques Hiblot 454c10b85d6SJean-Jacques Hiblot /* Keep clock gated for at least 10 ms, though spec only says 5 ms */ 455c10b85d6SJean-Jacques Hiblot mdelay(10); 456c10b85d6SJean-Jacques Hiblot mmc_set_clock(mmc, mmc->clock, false); 457c10b85d6SJean-Jacques Hiblot 458c10b85d6SJean-Jacques Hiblot /* 459c10b85d6SJean-Jacques Hiblot * Failure to switch is indicated by the card holding 460c10b85d6SJean-Jacques Hiblot * dat[0:3] low. Wait for at least 1 ms according to spec 461c10b85d6SJean-Jacques Hiblot */ 462c10b85d6SJean-Jacques Hiblot err = mmc_wait_dat0(mmc, 1, 1000); 463c10b85d6SJean-Jacques Hiblot if (err == -ENOSYS) 464c10b85d6SJean-Jacques Hiblot udelay(1000); 465c10b85d6SJean-Jacques Hiblot else if (err) 466c10b85d6SJean-Jacques Hiblot return -ETIMEDOUT; 467c10b85d6SJean-Jacques Hiblot 468c10b85d6SJean-Jacques Hiblot return 0; 469c10b85d6SJean-Jacques Hiblot } 470c10b85d6SJean-Jacques Hiblot 471c10b85d6SJean-Jacques Hiblot static int sd_send_op_cond(struct mmc *mmc, bool uhs_en) 472272cc70bSAndy Fleming { 473272cc70bSAndy Fleming int timeout = 1000; 474272cc70bSAndy Fleming int err; 475272cc70bSAndy Fleming struct mmc_cmd cmd; 476272cc70bSAndy Fleming 4771677eef4SAndrew Gabbasov while (1) { 478272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 479272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 480272cc70bSAndy Fleming cmd.cmdarg = 0; 481272cc70bSAndy Fleming 482272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 483272cc70bSAndy Fleming 484272cc70bSAndy Fleming if (err) 485272cc70bSAndy Fleming return err; 486272cc70bSAndy Fleming 487272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_OP_COND; 488272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R3; 489250de12bSStefano Babic 490250de12bSStefano Babic /* 491250de12bSStefano Babic * Most cards do not answer if some reserved bits 492250de12bSStefano Babic * in the ocr are set. However, Some controller 493250de12bSStefano Babic * can set bit 7 (reserved for low voltages), but 494250de12bSStefano Babic * how to manage low voltages SD card is not yet 495250de12bSStefano Babic * specified. 496250de12bSStefano Babic */ 497d52ebf10SThomas Chou cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 : 49893bfd616SPantelis Antoniou (mmc->cfg->voltages & 0xff8000); 499272cc70bSAndy Fleming 500272cc70bSAndy Fleming if (mmc->version == SD_VERSION_2) 501272cc70bSAndy Fleming cmd.cmdarg |= OCR_HCS; 502272cc70bSAndy Fleming 503c10b85d6SJean-Jacques Hiblot if (uhs_en) 504c10b85d6SJean-Jacques Hiblot cmd.cmdarg |= OCR_S18R; 505c10b85d6SJean-Jacques Hiblot 506272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 507272cc70bSAndy Fleming 508272cc70bSAndy Fleming if (err) 509272cc70bSAndy Fleming return err; 510272cc70bSAndy Fleming 5111677eef4SAndrew Gabbasov if (cmd.response[0] & OCR_BUSY) 5121677eef4SAndrew Gabbasov break; 513272cc70bSAndy Fleming 5141677eef4SAndrew Gabbasov if (timeout-- <= 0) 515915ffa52SJaehoon Chung return -EOPNOTSUPP; 516272cc70bSAndy Fleming 5171677eef4SAndrew Gabbasov udelay(1000); 5181677eef4SAndrew Gabbasov } 5191677eef4SAndrew Gabbasov 520272cc70bSAndy Fleming if (mmc->version != SD_VERSION_2) 521272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 522272cc70bSAndy Fleming 523d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 524d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 525d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 526d52ebf10SThomas Chou cmd.cmdarg = 0; 527d52ebf10SThomas Chou 528d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 529d52ebf10SThomas Chou 530d52ebf10SThomas Chou if (err) 531d52ebf10SThomas Chou return err; 532d52ebf10SThomas Chou } 533d52ebf10SThomas Chou 534998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 535272cc70bSAndy Fleming 536c10b85d6SJean-Jacques Hiblot if (uhs_en && !(mmc_host_is_spi(mmc)) && (cmd.response[0] & 0x41000000) 537c10b85d6SJean-Jacques Hiblot == 0x41000000) { 538c10b85d6SJean-Jacques Hiblot err = mmc_switch_voltage(mmc, MMC_SIGNAL_VOLTAGE_180); 539c10b85d6SJean-Jacques Hiblot if (err) 540c10b85d6SJean-Jacques Hiblot return err; 541c10b85d6SJean-Jacques Hiblot } 542c10b85d6SJean-Jacques Hiblot 543272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 544272cc70bSAndy Fleming mmc->rca = 0; 545272cc70bSAndy Fleming 546272cc70bSAndy Fleming return 0; 547272cc70bSAndy Fleming } 548272cc70bSAndy Fleming 5495289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg) 550272cc70bSAndy Fleming { 5515289b535SAndrew Gabbasov struct mmc_cmd cmd; 552272cc70bSAndy Fleming int err; 553272cc70bSAndy Fleming 5545289b535SAndrew Gabbasov cmd.cmdidx = MMC_CMD_SEND_OP_COND; 5555289b535SAndrew Gabbasov cmd.resp_type = MMC_RSP_R3; 5565289b535SAndrew Gabbasov cmd.cmdarg = 0; 5575a20397bSRob Herring if (use_arg && !mmc_host_is_spi(mmc)) 5585a20397bSRob Herring cmd.cmdarg = OCR_HCS | 55993bfd616SPantelis Antoniou (mmc->cfg->voltages & 560a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_VOLTAGE_MASK)) | 561a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_ACCESS_MODE); 562e9550449SChe-Liang Chiou 5635289b535SAndrew Gabbasov err = mmc_send_cmd(mmc, &cmd, NULL); 564e9550449SChe-Liang Chiou if (err) 565e9550449SChe-Liang Chiou return err; 5665289b535SAndrew Gabbasov mmc->ocr = cmd.response[0]; 567e9550449SChe-Liang Chiou return 0; 568e9550449SChe-Liang Chiou } 569e9550449SChe-Liang Chiou 570750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc) 571e9550449SChe-Liang Chiou { 572e9550449SChe-Liang Chiou int err, i; 573e9550449SChe-Liang Chiou 574272cc70bSAndy Fleming /* Some cards seem to need this */ 575272cc70bSAndy Fleming mmc_go_idle(mmc); 576272cc70bSAndy Fleming 57731cacbabSRaffaele Recalcati /* Asking to the card its capabilities */ 578e9550449SChe-Liang Chiou for (i = 0; i < 2; i++) { 5795289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, i != 0); 58031cacbabSRaffaele Recalcati if (err) 58131cacbabSRaffaele Recalcati return err; 58231cacbabSRaffaele Recalcati 583e9550449SChe-Liang Chiou /* exit if not busy (flag seems to be inverted) */ 584a626c8d4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 585bd47c135SAndrew Gabbasov break; 586e9550449SChe-Liang Chiou } 587bd47c135SAndrew Gabbasov mmc->op_cond_pending = 1; 588bd47c135SAndrew Gabbasov return 0; 589e9550449SChe-Liang Chiou } 59031cacbabSRaffaele Recalcati 591750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc) 592e9550449SChe-Liang Chiou { 593e9550449SChe-Liang Chiou struct mmc_cmd cmd; 594e9550449SChe-Liang Chiou int timeout = 1000; 595e9550449SChe-Liang Chiou uint start; 596e9550449SChe-Liang Chiou int err; 597e9550449SChe-Liang Chiou 598e9550449SChe-Liang Chiou mmc->op_cond_pending = 0; 599cc17c01fSAndrew Gabbasov if (!(mmc->ocr & OCR_BUSY)) { 600d188b113SYangbo Lu /* Some cards seem to need this */ 601d188b113SYangbo Lu mmc_go_idle(mmc); 602d188b113SYangbo Lu 603e9550449SChe-Liang Chiou start = get_timer(0); 6041677eef4SAndrew Gabbasov while (1) { 6055289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, 1); 606272cc70bSAndy Fleming if (err) 607272cc70bSAndy Fleming return err; 6081677eef4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 6091677eef4SAndrew Gabbasov break; 610e9550449SChe-Liang Chiou if (get_timer(start) > timeout) 611915ffa52SJaehoon Chung return -EOPNOTSUPP; 612e9550449SChe-Liang Chiou udelay(100); 6131677eef4SAndrew Gabbasov } 614cc17c01fSAndrew Gabbasov } 615272cc70bSAndy Fleming 616d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 617d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 618d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 619d52ebf10SThomas Chou cmd.cmdarg = 0; 620d52ebf10SThomas Chou 621d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 622d52ebf10SThomas Chou 623d52ebf10SThomas Chou if (err) 624d52ebf10SThomas Chou return err; 625a626c8d4SAndrew Gabbasov 626a626c8d4SAndrew Gabbasov mmc->ocr = cmd.response[0]; 627d52ebf10SThomas Chou } 628d52ebf10SThomas Chou 629272cc70bSAndy Fleming mmc->version = MMC_VERSION_UNKNOWN; 630272cc70bSAndy Fleming 631272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 632def816a2SStephen Warren mmc->rca = 1; 633272cc70bSAndy Fleming 634272cc70bSAndy Fleming return 0; 635272cc70bSAndy Fleming } 636272cc70bSAndy Fleming 637272cc70bSAndy Fleming 638fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) 639272cc70bSAndy Fleming { 640272cc70bSAndy Fleming struct mmc_cmd cmd; 641272cc70bSAndy Fleming struct mmc_data data; 642272cc70bSAndy Fleming int err; 643272cc70bSAndy Fleming 644272cc70bSAndy Fleming /* Get the Card Status Register */ 645272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_EXT_CSD; 646272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 647272cc70bSAndy Fleming cmd.cmdarg = 0; 648272cc70bSAndy Fleming 649cdfd1ac6SYoshihiro Shimoda data.dest = (char *)ext_csd; 650272cc70bSAndy Fleming data.blocks = 1; 6518bfa195eSSimon Glass data.blocksize = MMC_MAX_BLOCK_LEN; 652272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 653272cc70bSAndy Fleming 654272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 655272cc70bSAndy Fleming 656272cc70bSAndy Fleming return err; 657272cc70bSAndy Fleming } 658272cc70bSAndy Fleming 659c40704f4SSimon Glass int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) 660272cc70bSAndy Fleming { 661272cc70bSAndy Fleming struct mmc_cmd cmd; 6625d4fc8d9SRaffaele Recalcati int timeout = 1000; 663a9003dc6SMaxime Ripard int retries = 3; 6645d4fc8d9SRaffaele Recalcati int ret; 665272cc70bSAndy Fleming 666272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SWITCH; 667272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 668272cc70bSAndy Fleming cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 669272cc70bSAndy Fleming (index << 16) | 670272cc70bSAndy Fleming (value << 8); 671272cc70bSAndy Fleming 672a9003dc6SMaxime Ripard while (retries > 0) { 6735d4fc8d9SRaffaele Recalcati ret = mmc_send_cmd(mmc, &cmd, NULL); 6745d4fc8d9SRaffaele Recalcati 6755d4fc8d9SRaffaele Recalcati /* Waiting for the ready status */ 676a9003dc6SMaxime Ripard if (!ret) { 67793ad0d18SJan Kloetzke ret = mmc_send_status(mmc, timeout); 678a9003dc6SMaxime Ripard return ret; 679a9003dc6SMaxime Ripard } 680a9003dc6SMaxime Ripard 681a9003dc6SMaxime Ripard retries--; 682a9003dc6SMaxime Ripard } 6835d4fc8d9SRaffaele Recalcati 6845d4fc8d9SRaffaele Recalcati return ret; 6855d4fc8d9SRaffaele Recalcati 686272cc70bSAndy Fleming } 687272cc70bSAndy Fleming 6883862b854SJean-Jacques Hiblot static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode) 689272cc70bSAndy Fleming { 690272cc70bSAndy Fleming int err; 6913862b854SJean-Jacques Hiblot int speed_bits; 6923862b854SJean-Jacques Hiblot 6933862b854SJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 6943862b854SJean-Jacques Hiblot 6953862b854SJean-Jacques Hiblot switch (mode) { 6963862b854SJean-Jacques Hiblot case MMC_HS: 6973862b854SJean-Jacques Hiblot case MMC_HS_52: 6983862b854SJean-Jacques Hiblot case MMC_DDR_52: 6993862b854SJean-Jacques Hiblot speed_bits = EXT_CSD_TIMING_HS; 700634d4849SKishon Vijay Abraham I break; 701634d4849SKishon Vijay Abraham I case MMC_HS_200: 702634d4849SKishon Vijay Abraham I speed_bits = EXT_CSD_TIMING_HS200; 703634d4849SKishon Vijay Abraham I break; 7043862b854SJean-Jacques Hiblot case MMC_LEGACY: 7053862b854SJean-Jacques Hiblot speed_bits = EXT_CSD_TIMING_LEGACY; 7063862b854SJean-Jacques Hiblot break; 7073862b854SJean-Jacques Hiblot default: 7083862b854SJean-Jacques Hiblot return -EINVAL; 7093862b854SJean-Jacques Hiblot } 7103862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 7113862b854SJean-Jacques Hiblot speed_bits); 7123862b854SJean-Jacques Hiblot if (err) 7133862b854SJean-Jacques Hiblot return err; 7143862b854SJean-Jacques Hiblot 7153862b854SJean-Jacques Hiblot if ((mode == MMC_HS) || (mode == MMC_HS_52)) { 7163862b854SJean-Jacques Hiblot /* Now check to see that it worked */ 7173862b854SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, test_csd); 7183862b854SJean-Jacques Hiblot if (err) 7193862b854SJean-Jacques Hiblot return err; 7203862b854SJean-Jacques Hiblot 7213862b854SJean-Jacques Hiblot /* No high-speed support */ 7223862b854SJean-Jacques Hiblot if (!test_csd[EXT_CSD_HS_TIMING]) 7233862b854SJean-Jacques Hiblot return -ENOTSUPP; 7243862b854SJean-Jacques Hiblot } 7253862b854SJean-Jacques Hiblot 7263862b854SJean-Jacques Hiblot return 0; 7273862b854SJean-Jacques Hiblot } 7283862b854SJean-Jacques Hiblot 7293862b854SJean-Jacques Hiblot static int mmc_get_capabilities(struct mmc *mmc) 7303862b854SJean-Jacques Hiblot { 7313862b854SJean-Jacques Hiblot u8 *ext_csd = mmc->ext_csd; 7323862b854SJean-Jacques Hiblot char cardtype; 733272cc70bSAndy Fleming 734d0c221feSJean-Jacques Hiblot mmc->card_caps = MMC_MODE_1BIT; 735272cc70bSAndy Fleming 736d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 737d52ebf10SThomas Chou return 0; 738d52ebf10SThomas Chou 739272cc70bSAndy Fleming /* Only version 4 supports high-speed */ 740272cc70bSAndy Fleming if (mmc->version < MMC_VERSION_4) 741272cc70bSAndy Fleming return 0; 742272cc70bSAndy Fleming 7433862b854SJean-Jacques Hiblot if (!ext_csd) { 7443862b854SJean-Jacques Hiblot printf("No ext_csd found!\n"); /* this should enver happen */ 7453862b854SJean-Jacques Hiblot return -ENOTSUPP; 7463862b854SJean-Jacques Hiblot } 7473862b854SJean-Jacques Hiblot 748fc5b32fbSAndrew Gabbasov mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; 749fc5b32fbSAndrew Gabbasov 750634d4849SKishon Vijay Abraham I cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0x3f; 751272cc70bSAndy Fleming 752634d4849SKishon Vijay Abraham I if (cardtype & (EXT_CSD_CARD_TYPE_HS200_1_2V | 753634d4849SKishon Vijay Abraham I EXT_CSD_CARD_TYPE_HS200_1_8V)) { 754634d4849SKishon Vijay Abraham I mmc->card_caps |= MMC_MODE_HS200; 755634d4849SKishon Vijay Abraham I } 756d22e3d46SJaehoon Chung if (cardtype & EXT_CSD_CARD_TYPE_52) { 7573862b854SJean-Jacques Hiblot if (cardtype & EXT_CSD_CARD_TYPE_DDR_52) 758d22e3d46SJaehoon Chung mmc->card_caps |= MMC_MODE_DDR_52MHz; 7593862b854SJean-Jacques Hiblot mmc->card_caps |= MMC_MODE_HS_52MHz; 760d22e3d46SJaehoon Chung } 7613862b854SJean-Jacques Hiblot if (cardtype & EXT_CSD_CARD_TYPE_26) 7623862b854SJean-Jacques Hiblot mmc->card_caps |= MMC_MODE_HS; 763272cc70bSAndy Fleming 764272cc70bSAndy Fleming return 0; 765272cc70bSAndy Fleming } 766272cc70bSAndy Fleming 767f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num) 768f866a46dSStephen Warren { 769f866a46dSStephen Warren switch (part_num) { 770f866a46dSStephen Warren case 0: 771f866a46dSStephen Warren mmc->capacity = mmc->capacity_user; 772f866a46dSStephen Warren break; 773f866a46dSStephen Warren case 1: 774f866a46dSStephen Warren case 2: 775f866a46dSStephen Warren mmc->capacity = mmc->capacity_boot; 776f866a46dSStephen Warren break; 777f866a46dSStephen Warren case 3: 778f866a46dSStephen Warren mmc->capacity = mmc->capacity_rpmb; 779f866a46dSStephen Warren break; 780f866a46dSStephen Warren case 4: 781f866a46dSStephen Warren case 5: 782f866a46dSStephen Warren case 6: 783f866a46dSStephen Warren case 7: 784f866a46dSStephen Warren mmc->capacity = mmc->capacity_gp[part_num - 4]; 785f866a46dSStephen Warren break; 786f866a46dSStephen Warren default: 787f866a46dSStephen Warren return -1; 788f866a46dSStephen Warren } 789f866a46dSStephen Warren 790c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len); 791f866a46dSStephen Warren 792f866a46dSStephen Warren return 0; 793f866a46dSStephen Warren } 794f866a46dSStephen Warren 7957dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num) 796bc897b1dSLei Wen { 797f866a46dSStephen Warren int ret; 798bc897b1dSLei Wen 799f866a46dSStephen Warren ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 800bc897b1dSLei Wen (mmc->part_config & ~PART_ACCESS_MASK) 801bc897b1dSLei Wen | (part_num & PART_ACCESS_MASK)); 802f866a46dSStephen Warren 8036dc93e70SPeter Bigot /* 8046dc93e70SPeter Bigot * Set the capacity if the switch succeeded or was intended 8056dc93e70SPeter Bigot * to return to representing the raw device. 8066dc93e70SPeter Bigot */ 807873cc1d7SStephen Warren if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) { 8086dc93e70SPeter Bigot ret = mmc_set_capacity(mmc, part_num); 809fdbb139fSSimon Glass mmc_get_blk_desc(mmc)->hwpart = part_num; 810873cc1d7SStephen Warren } 8116dc93e70SPeter Bigot 8126dc93e70SPeter Bigot return ret; 813bc897b1dSLei Wen } 814bc897b1dSLei Wen 815ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc, 816ac9da0e0SDiego Santa Cruz const struct mmc_hwpart_conf *conf, 817ac9da0e0SDiego Santa Cruz enum mmc_hwpart_conf_mode mode) 818ac9da0e0SDiego Santa Cruz { 819ac9da0e0SDiego Santa Cruz u8 part_attrs = 0; 820ac9da0e0SDiego Santa Cruz u32 enh_size_mult; 821ac9da0e0SDiego Santa Cruz u32 enh_start_addr; 822ac9da0e0SDiego Santa Cruz u32 gp_size_mult[4]; 823ac9da0e0SDiego Santa Cruz u32 max_enh_size_mult; 824ac9da0e0SDiego Santa Cruz u32 tot_enh_size_mult = 0; 8258dda5b0eSDiego Santa Cruz u8 wr_rel_set; 826ac9da0e0SDiego Santa Cruz int i, pidx, err; 827ac9da0e0SDiego Santa Cruz ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 828ac9da0e0SDiego Santa Cruz 829ac9da0e0SDiego Santa Cruz if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE) 830ac9da0e0SDiego Santa Cruz return -EINVAL; 831ac9da0e0SDiego Santa Cruz 832ac9da0e0SDiego Santa Cruz if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) { 833ac9da0e0SDiego Santa Cruz printf("eMMC >= 4.4 required for enhanced user data area\n"); 834ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 835ac9da0e0SDiego Santa Cruz } 836ac9da0e0SDiego Santa Cruz 837ac9da0e0SDiego Santa Cruz if (!(mmc->part_support & PART_SUPPORT)) { 838ac9da0e0SDiego Santa Cruz printf("Card does not support partitioning\n"); 839ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 840ac9da0e0SDiego Santa Cruz } 841ac9da0e0SDiego Santa Cruz 842ac9da0e0SDiego Santa Cruz if (!mmc->hc_wp_grp_size) { 843ac9da0e0SDiego Santa Cruz printf("Card does not define HC WP group size\n"); 844ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 845ac9da0e0SDiego Santa Cruz } 846ac9da0e0SDiego Santa Cruz 847ac9da0e0SDiego Santa Cruz /* check partition alignment and total enhanced size */ 848ac9da0e0SDiego Santa Cruz if (conf->user.enh_size) { 849ac9da0e0SDiego Santa Cruz if (conf->user.enh_size % mmc->hc_wp_grp_size || 850ac9da0e0SDiego Santa Cruz conf->user.enh_start % mmc->hc_wp_grp_size) { 851ac9da0e0SDiego Santa Cruz printf("User data enhanced area not HC WP group " 852ac9da0e0SDiego Santa Cruz "size aligned\n"); 853ac9da0e0SDiego Santa Cruz return -EINVAL; 854ac9da0e0SDiego Santa Cruz } 855ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_USR; 856ac9da0e0SDiego Santa Cruz enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size; 857ac9da0e0SDiego Santa Cruz if (mmc->high_capacity) { 858ac9da0e0SDiego Santa Cruz enh_start_addr = conf->user.enh_start; 859ac9da0e0SDiego Santa Cruz } else { 860ac9da0e0SDiego Santa Cruz enh_start_addr = (conf->user.enh_start << 9); 861ac9da0e0SDiego Santa Cruz } 862ac9da0e0SDiego Santa Cruz } else { 863ac9da0e0SDiego Santa Cruz enh_size_mult = 0; 864ac9da0e0SDiego Santa Cruz enh_start_addr = 0; 865ac9da0e0SDiego Santa Cruz } 866ac9da0e0SDiego Santa Cruz tot_enh_size_mult += enh_size_mult; 867ac9da0e0SDiego Santa Cruz 868ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 869ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) { 870ac9da0e0SDiego Santa Cruz printf("GP%i partition not HC WP group size " 871ac9da0e0SDiego Santa Cruz "aligned\n", pidx+1); 872ac9da0e0SDiego Santa Cruz return -EINVAL; 873ac9da0e0SDiego Santa Cruz } 874ac9da0e0SDiego Santa Cruz gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size; 875ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) { 876ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_GP(pidx); 877ac9da0e0SDiego Santa Cruz tot_enh_size_mult += gp_size_mult[pidx]; 878ac9da0e0SDiego Santa Cruz } 879ac9da0e0SDiego Santa Cruz } 880ac9da0e0SDiego Santa Cruz 881ac9da0e0SDiego Santa Cruz if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) { 882ac9da0e0SDiego Santa Cruz printf("Card does not support enhanced attribute\n"); 883ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 884ac9da0e0SDiego Santa Cruz } 885ac9da0e0SDiego Santa Cruz 886ac9da0e0SDiego Santa Cruz err = mmc_send_ext_csd(mmc, ext_csd); 887ac9da0e0SDiego Santa Cruz if (err) 888ac9da0e0SDiego Santa Cruz return err; 889ac9da0e0SDiego Santa Cruz 890ac9da0e0SDiego Santa Cruz max_enh_size_mult = 891ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) + 892ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) + 893ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]; 894ac9da0e0SDiego Santa Cruz if (tot_enh_size_mult > max_enh_size_mult) { 895ac9da0e0SDiego Santa Cruz printf("Total enhanced size exceeds maximum (%u > %u)\n", 896ac9da0e0SDiego Santa Cruz tot_enh_size_mult, max_enh_size_mult); 897ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 898ac9da0e0SDiego Santa Cruz } 899ac9da0e0SDiego Santa Cruz 9008dda5b0eSDiego Santa Cruz /* The default value of EXT_CSD_WR_REL_SET is device 9018dda5b0eSDiego Santa Cruz * dependent, the values can only be changed if the 9028dda5b0eSDiego Santa Cruz * EXT_CSD_HS_CTRL_REL bit is set. The values can be 9038dda5b0eSDiego Santa Cruz * changed only once and before partitioning is completed. */ 9048dda5b0eSDiego Santa Cruz wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 9058dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_change) { 9068dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_set) 9078dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_USR; 9088dda5b0eSDiego Santa Cruz else 9098dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR; 9108dda5b0eSDiego Santa Cruz } 9118dda5b0eSDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 9128dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_change) { 9138dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_set) 9148dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx); 9158dda5b0eSDiego Santa Cruz else 9168dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx); 9178dda5b0eSDiego Santa Cruz } 9188dda5b0eSDiego Santa Cruz } 9198dda5b0eSDiego Santa Cruz 9208dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] && 9218dda5b0eSDiego Santa Cruz !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) { 9228dda5b0eSDiego Santa Cruz puts("Card does not support host controlled partition write " 9238dda5b0eSDiego Santa Cruz "reliability settings\n"); 9248dda5b0eSDiego Santa Cruz return -EMEDIUMTYPE; 9258dda5b0eSDiego Santa Cruz } 9268dda5b0eSDiego Santa Cruz 927ac9da0e0SDiego Santa Cruz if (ext_csd[EXT_CSD_PARTITION_SETTING] & 928ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED) { 929ac9da0e0SDiego Santa Cruz printf("Card already partitioned\n"); 930ac9da0e0SDiego Santa Cruz return -EPERM; 931ac9da0e0SDiego Santa Cruz } 932ac9da0e0SDiego Santa Cruz 933ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_CHECK) 934ac9da0e0SDiego Santa Cruz return 0; 935ac9da0e0SDiego Santa Cruz 936ac9da0e0SDiego Santa Cruz /* Partitioning requires high-capacity size definitions */ 937ac9da0e0SDiego Santa Cruz if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) { 938ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 939ac9da0e0SDiego Santa Cruz EXT_CSD_ERASE_GROUP_DEF, 1); 940ac9da0e0SDiego Santa Cruz 941ac9da0e0SDiego Santa Cruz if (err) 942ac9da0e0SDiego Santa Cruz return err; 943ac9da0e0SDiego Santa Cruz 944ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 945ac9da0e0SDiego Santa Cruz 946ac9da0e0SDiego Santa Cruz /* update erase group size to be high-capacity */ 947ac9da0e0SDiego Santa Cruz mmc->erase_grp_size = 948ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 949ac9da0e0SDiego Santa Cruz 950ac9da0e0SDiego Santa Cruz } 951ac9da0e0SDiego Santa Cruz 952ac9da0e0SDiego Santa Cruz /* all OK, write the configuration */ 953ac9da0e0SDiego Santa Cruz for (i = 0; i < 4; i++) { 954ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 955ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_START_ADDR+i, 956ac9da0e0SDiego Santa Cruz (enh_start_addr >> (i*8)) & 0xFF); 957ac9da0e0SDiego Santa Cruz if (err) 958ac9da0e0SDiego Santa Cruz return err; 959ac9da0e0SDiego Santa Cruz } 960ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 961ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 962ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_SIZE_MULT+i, 963ac9da0e0SDiego Santa Cruz (enh_size_mult >> (i*8)) & 0xFF); 964ac9da0e0SDiego Santa Cruz if (err) 965ac9da0e0SDiego Santa Cruz return err; 966ac9da0e0SDiego Santa Cruz } 967ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 968ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 969ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 970ac9da0e0SDiego Santa Cruz EXT_CSD_GP_SIZE_MULT+pidx*3+i, 971ac9da0e0SDiego Santa Cruz (gp_size_mult[pidx] >> (i*8)) & 0xFF); 972ac9da0e0SDiego Santa Cruz if (err) 973ac9da0e0SDiego Santa Cruz return err; 974ac9da0e0SDiego Santa Cruz } 975ac9da0e0SDiego Santa Cruz } 976ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 977ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs); 978ac9da0e0SDiego Santa Cruz if (err) 979ac9da0e0SDiego Santa Cruz return err; 980ac9da0e0SDiego Santa Cruz 981ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_SET) 982ac9da0e0SDiego Santa Cruz return 0; 983ac9da0e0SDiego Santa Cruz 9848dda5b0eSDiego Santa Cruz /* The WR_REL_SET is a write-once register but shall be 9858dda5b0eSDiego Santa Cruz * written before setting PART_SETTING_COMPLETED. As it is 9868dda5b0eSDiego Santa Cruz * write-once we can only write it when completing the 9878dda5b0eSDiego Santa Cruz * partitioning. */ 9888dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) { 9898dda5b0eSDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 9908dda5b0eSDiego Santa Cruz EXT_CSD_WR_REL_SET, wr_rel_set); 9918dda5b0eSDiego Santa Cruz if (err) 9928dda5b0eSDiego Santa Cruz return err; 9938dda5b0eSDiego Santa Cruz } 9948dda5b0eSDiego Santa Cruz 995ac9da0e0SDiego Santa Cruz /* Setting PART_SETTING_COMPLETED confirms the partition 996ac9da0e0SDiego Santa Cruz * configuration but it only becomes effective after power 997ac9da0e0SDiego Santa Cruz * cycle, so we do not adjust the partition related settings 998ac9da0e0SDiego Santa Cruz * in the mmc struct. */ 999ac9da0e0SDiego Santa Cruz 1000ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1001ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING, 1002ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 1003ac9da0e0SDiego Santa Cruz if (err) 1004ac9da0e0SDiego Santa Cruz return err; 1005ac9da0e0SDiego Santa Cruz 1006ac9da0e0SDiego Santa Cruz return 0; 1007ac9da0e0SDiego Santa Cruz } 1008ac9da0e0SDiego Santa Cruz 1009e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 101048972d90SThierry Reding int mmc_getcd(struct mmc *mmc) 101148972d90SThierry Reding { 101248972d90SThierry Reding int cd; 101348972d90SThierry Reding 101448972d90SThierry Reding cd = board_mmc_getcd(mmc); 101548972d90SThierry Reding 1016d4e1da4eSPeter Korsgaard if (cd < 0) { 101793bfd616SPantelis Antoniou if (mmc->cfg->ops->getcd) 101893bfd616SPantelis Antoniou cd = mmc->cfg->ops->getcd(mmc); 1019d4e1da4eSPeter Korsgaard else 1020d4e1da4eSPeter Korsgaard cd = 1; 1021d4e1da4eSPeter Korsgaard } 102248972d90SThierry Reding 102348972d90SThierry Reding return cd; 102448972d90SThierry Reding } 10258ca51e51SSimon Glass #endif 102648972d90SThierry Reding 1027fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) 1028272cc70bSAndy Fleming { 1029272cc70bSAndy Fleming struct mmc_cmd cmd; 1030272cc70bSAndy Fleming struct mmc_data data; 1031272cc70bSAndy Fleming 1032272cc70bSAndy Fleming /* Switch the frequency */ 1033272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC; 1034272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1035272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff; 1036272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4)); 1037272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4); 1038272cc70bSAndy Fleming 1039272cc70bSAndy Fleming data.dest = (char *)resp; 1040272cc70bSAndy Fleming data.blocksize = 64; 1041272cc70bSAndy Fleming data.blocks = 1; 1042272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1043272cc70bSAndy Fleming 1044272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 1045272cc70bSAndy Fleming } 1046272cc70bSAndy Fleming 1047272cc70bSAndy Fleming 1048d0c221feSJean-Jacques Hiblot static int sd_get_capabilities(struct mmc *mmc) 1049272cc70bSAndy Fleming { 1050272cc70bSAndy Fleming int err; 1051272cc70bSAndy Fleming struct mmc_cmd cmd; 105218e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2); 105318e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16); 1054272cc70bSAndy Fleming struct mmc_data data; 1055272cc70bSAndy Fleming int timeout; 1056c10b85d6SJean-Jacques Hiblot u32 sd3_bus_mode; 1057272cc70bSAndy Fleming 1058d0c221feSJean-Jacques Hiblot mmc->card_caps = MMC_MODE_1BIT; 1059272cc70bSAndy Fleming 1060d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 1061d52ebf10SThomas Chou return 0; 1062d52ebf10SThomas Chou 1063272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */ 1064272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 1065272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1066272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1067272cc70bSAndy Fleming 1068272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1069272cc70bSAndy Fleming 1070272cc70bSAndy Fleming if (err) 1071272cc70bSAndy Fleming return err; 1072272cc70bSAndy Fleming 1073272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR; 1074272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1075272cc70bSAndy Fleming cmd.cmdarg = 0; 1076272cc70bSAndy Fleming 1077272cc70bSAndy Fleming timeout = 3; 1078272cc70bSAndy Fleming 1079272cc70bSAndy Fleming retry_scr: 1080f781dd38SAnton staaf data.dest = (char *)scr; 1081272cc70bSAndy Fleming data.blocksize = 8; 1082272cc70bSAndy Fleming data.blocks = 1; 1083272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1084272cc70bSAndy Fleming 1085272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 1086272cc70bSAndy Fleming 1087272cc70bSAndy Fleming if (err) { 1088272cc70bSAndy Fleming if (timeout--) 1089272cc70bSAndy Fleming goto retry_scr; 1090272cc70bSAndy Fleming 1091272cc70bSAndy Fleming return err; 1092272cc70bSAndy Fleming } 1093272cc70bSAndy Fleming 10944e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]); 10954e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]); 1096272cc70bSAndy Fleming 1097272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) { 1098272cc70bSAndy Fleming case 0: 1099272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1100272cc70bSAndy Fleming break; 1101272cc70bSAndy Fleming case 1: 1102272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10; 1103272cc70bSAndy Fleming break; 1104272cc70bSAndy Fleming case 2: 1105272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 11061741c64dSJaehoon Chung if ((mmc->scr[0] >> 15) & 0x1) 11071741c64dSJaehoon Chung mmc->version = SD_VERSION_3; 1108272cc70bSAndy Fleming break; 1109272cc70bSAndy Fleming default: 1110272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1111272cc70bSAndy Fleming break; 1112272cc70bSAndy Fleming } 1113272cc70bSAndy Fleming 1114b44c7083SAlagu Sankar if (mmc->scr[0] & SD_DATA_4BIT) 1115b44c7083SAlagu Sankar mmc->card_caps |= MMC_MODE_4BIT; 1116b44c7083SAlagu Sankar 1117272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */ 1118272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0) 1119272cc70bSAndy Fleming return 0; 1120272cc70bSAndy Fleming 1121272cc70bSAndy Fleming timeout = 4; 1122272cc70bSAndy Fleming while (timeout--) { 1123272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, 1124f781dd38SAnton staaf (u8 *)switch_status); 1125272cc70bSAndy Fleming 1126272cc70bSAndy Fleming if (err) 1127272cc70bSAndy Fleming return err; 1128272cc70bSAndy Fleming 1129272cc70bSAndy Fleming /* The high-speed function is busy. Try again */ 11304e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) 1131272cc70bSAndy Fleming break; 1132272cc70bSAndy Fleming } 1133272cc70bSAndy Fleming 1134272cc70bSAndy Fleming /* If high-speed isn't supported, we return */ 1135d0c221feSJean-Jacques Hiblot if (__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED) 1136d0c221feSJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(SD_HS); 1137272cc70bSAndy Fleming 1138c10b85d6SJean-Jacques Hiblot /* Version before 3.0 don't support UHS modes */ 1139c10b85d6SJean-Jacques Hiblot if (mmc->version < SD_VERSION_3) 1140c10b85d6SJean-Jacques Hiblot return 0; 1141c10b85d6SJean-Jacques Hiblot 1142c10b85d6SJean-Jacques Hiblot sd3_bus_mode = __be32_to_cpu(switch_status[3]) >> 16 & 0x1f; 1143c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR104) 1144c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR104); 1145c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR50) 1146c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR50); 1147c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR25) 1148c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR25); 1149c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR12) 1150c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR12); 1151c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_DDR50) 1152c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_DDR50); 1153c10b85d6SJean-Jacques Hiblot 11542c3fbf4cSMacpaul Lin return 0; 1155d0c221feSJean-Jacques Hiblot } 1156d0c221feSJean-Jacques Hiblot 1157d0c221feSJean-Jacques Hiblot static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode) 1158d0c221feSJean-Jacques Hiblot { 1159d0c221feSJean-Jacques Hiblot int err; 1160d0c221feSJean-Jacques Hiblot 1161d0c221feSJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16); 1162c10b85d6SJean-Jacques Hiblot int speed; 11632c3fbf4cSMacpaul Lin 1164c10b85d6SJean-Jacques Hiblot switch (mode) { 1165c10b85d6SJean-Jacques Hiblot case SD_LEGACY: 1166c10b85d6SJean-Jacques Hiblot case UHS_SDR12: 1167c10b85d6SJean-Jacques Hiblot speed = UHS_SDR12_BUS_SPEED; 1168c10b85d6SJean-Jacques Hiblot break; 1169c10b85d6SJean-Jacques Hiblot case SD_HS: 1170c10b85d6SJean-Jacques Hiblot case UHS_SDR25: 1171c10b85d6SJean-Jacques Hiblot speed = UHS_SDR25_BUS_SPEED; 1172c10b85d6SJean-Jacques Hiblot break; 1173c10b85d6SJean-Jacques Hiblot case UHS_SDR50: 1174c10b85d6SJean-Jacques Hiblot speed = UHS_SDR50_BUS_SPEED; 1175c10b85d6SJean-Jacques Hiblot break; 1176c10b85d6SJean-Jacques Hiblot case UHS_DDR50: 1177c10b85d6SJean-Jacques Hiblot speed = UHS_DDR50_BUS_SPEED; 1178c10b85d6SJean-Jacques Hiblot break; 1179c10b85d6SJean-Jacques Hiblot case UHS_SDR104: 1180c10b85d6SJean-Jacques Hiblot speed = UHS_SDR104_BUS_SPEED; 1181c10b85d6SJean-Jacques Hiblot break; 1182c10b85d6SJean-Jacques Hiblot default: 1183c10b85d6SJean-Jacques Hiblot return -EINVAL; 1184c10b85d6SJean-Jacques Hiblot } 1185c10b85d6SJean-Jacques Hiblot 1186c10b85d6SJean-Jacques Hiblot err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, speed, (u8 *)switch_status); 1187272cc70bSAndy Fleming if (err) 1188272cc70bSAndy Fleming return err; 1189272cc70bSAndy Fleming 1190c10b85d6SJean-Jacques Hiblot if ((__be32_to_cpu(switch_status[4]) >> 24) != speed) 1191d0c221feSJean-Jacques Hiblot return -ENOTSUPP; 1192d0c221feSJean-Jacques Hiblot 1193d0c221feSJean-Jacques Hiblot return 0; 1194d0c221feSJean-Jacques Hiblot } 1195d0c221feSJean-Jacques Hiblot 1196d0c221feSJean-Jacques Hiblot int sd_select_bus_width(struct mmc *mmc, int w) 1197d0c221feSJean-Jacques Hiblot { 1198d0c221feSJean-Jacques Hiblot int err; 1199d0c221feSJean-Jacques Hiblot struct mmc_cmd cmd; 1200d0c221feSJean-Jacques Hiblot 1201d0c221feSJean-Jacques Hiblot if ((w != 4) && (w != 1)) 1202d0c221feSJean-Jacques Hiblot return -EINVAL; 1203d0c221feSJean-Jacques Hiblot 1204d0c221feSJean-Jacques Hiblot cmd.cmdidx = MMC_CMD_APP_CMD; 1205d0c221feSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 1206d0c221feSJean-Jacques Hiblot cmd.cmdarg = mmc->rca << 16; 1207d0c221feSJean-Jacques Hiblot 1208d0c221feSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 1209d0c221feSJean-Jacques Hiblot if (err) 1210d0c221feSJean-Jacques Hiblot return err; 1211d0c221feSJean-Jacques Hiblot 1212d0c221feSJean-Jacques Hiblot cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; 1213d0c221feSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 1214d0c221feSJean-Jacques Hiblot if (w == 4) 1215d0c221feSJean-Jacques Hiblot cmd.cmdarg = 2; 1216d0c221feSJean-Jacques Hiblot else if (w == 1) 1217d0c221feSJean-Jacques Hiblot cmd.cmdarg = 0; 1218d0c221feSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 1219d0c221feSJean-Jacques Hiblot if (err) 1220d0c221feSJean-Jacques Hiblot return err; 1221272cc70bSAndy Fleming 1222272cc70bSAndy Fleming return 0; 1223272cc70bSAndy Fleming } 1224272cc70bSAndy Fleming 12253697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc) 12263697e599SPeng Fan { 12273697e599SPeng Fan int err, i; 12283697e599SPeng Fan struct mmc_cmd cmd; 12293697e599SPeng Fan ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16); 12303697e599SPeng Fan struct mmc_data data; 12313697e599SPeng Fan int timeout = 3; 12323697e599SPeng Fan unsigned int au, eo, et, es; 12333697e599SPeng Fan 12343697e599SPeng Fan cmd.cmdidx = MMC_CMD_APP_CMD; 12353697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 12363697e599SPeng Fan cmd.cmdarg = mmc->rca << 16; 12373697e599SPeng Fan 12383697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, NULL); 12393697e599SPeng Fan if (err) 12403697e599SPeng Fan return err; 12413697e599SPeng Fan 12423697e599SPeng Fan cmd.cmdidx = SD_CMD_APP_SD_STATUS; 12433697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 12443697e599SPeng Fan cmd.cmdarg = 0; 12453697e599SPeng Fan 12463697e599SPeng Fan retry_ssr: 12473697e599SPeng Fan data.dest = (char *)ssr; 12483697e599SPeng Fan data.blocksize = 64; 12493697e599SPeng Fan data.blocks = 1; 12503697e599SPeng Fan data.flags = MMC_DATA_READ; 12513697e599SPeng Fan 12523697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, &data); 12533697e599SPeng Fan if (err) { 12543697e599SPeng Fan if (timeout--) 12553697e599SPeng Fan goto retry_ssr; 12563697e599SPeng Fan 12573697e599SPeng Fan return err; 12583697e599SPeng Fan } 12593697e599SPeng Fan 12603697e599SPeng Fan for (i = 0; i < 16; i++) 12613697e599SPeng Fan ssr[i] = be32_to_cpu(ssr[i]); 12623697e599SPeng Fan 12633697e599SPeng Fan au = (ssr[2] >> 12) & 0xF; 12643697e599SPeng Fan if ((au <= 9) || (mmc->version == SD_VERSION_3)) { 12653697e599SPeng Fan mmc->ssr.au = sd_au_size[au]; 12663697e599SPeng Fan es = (ssr[3] >> 24) & 0xFF; 12673697e599SPeng Fan es |= (ssr[2] & 0xFF) << 8; 12683697e599SPeng Fan et = (ssr[3] >> 18) & 0x3F; 12693697e599SPeng Fan if (es && et) { 12703697e599SPeng Fan eo = (ssr[3] >> 16) & 0x3; 12713697e599SPeng Fan mmc->ssr.erase_timeout = (et * 1000) / es; 12723697e599SPeng Fan mmc->ssr.erase_offset = eo * 1000; 12733697e599SPeng Fan } 12743697e599SPeng Fan } else { 12753697e599SPeng Fan debug("Invalid Allocation Unit Size.\n"); 12763697e599SPeng Fan } 12773697e599SPeng Fan 12783697e599SPeng Fan return 0; 12793697e599SPeng Fan } 12803697e599SPeng Fan 1281272cc70bSAndy Fleming /* frequency bases */ 1282272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */ 12835f837c2cSMike Frysinger static const int fbase[] = { 1284272cc70bSAndy Fleming 10000, 1285272cc70bSAndy Fleming 100000, 1286272cc70bSAndy Fleming 1000000, 1287272cc70bSAndy Fleming 10000000, 1288272cc70bSAndy Fleming }; 1289272cc70bSAndy Fleming 1290272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice 1291272cc70bSAndy Fleming * to platforms without floating point. 1292272cc70bSAndy Fleming */ 129361fe076fSSimon Glass static const u8 multipliers[] = { 1294272cc70bSAndy Fleming 0, /* reserved */ 1295272cc70bSAndy Fleming 10, 1296272cc70bSAndy Fleming 12, 1297272cc70bSAndy Fleming 13, 1298272cc70bSAndy Fleming 15, 1299272cc70bSAndy Fleming 20, 1300272cc70bSAndy Fleming 25, 1301272cc70bSAndy Fleming 30, 1302272cc70bSAndy Fleming 35, 1303272cc70bSAndy Fleming 40, 1304272cc70bSAndy Fleming 45, 1305272cc70bSAndy Fleming 50, 1306272cc70bSAndy Fleming 55, 1307272cc70bSAndy Fleming 60, 1308272cc70bSAndy Fleming 70, 1309272cc70bSAndy Fleming 80, 1310272cc70bSAndy Fleming }; 1311272cc70bSAndy Fleming 1312d0c221feSJean-Jacques Hiblot static inline int bus_width(uint cap) 1313d0c221feSJean-Jacques Hiblot { 1314d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_8BIT) 1315d0c221feSJean-Jacques Hiblot return 8; 1316d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_4BIT) 1317d0c221feSJean-Jacques Hiblot return 4; 1318d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_1BIT) 1319d0c221feSJean-Jacques Hiblot return 1; 1320d0c221feSJean-Jacques Hiblot printf("invalid bus witdh capability 0x%x\n", cap); 1321d0c221feSJean-Jacques Hiblot return 0; 1322d0c221feSJean-Jacques Hiblot } 1323d0c221feSJean-Jacques Hiblot 1324e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 1325ec841209SKishon Vijay Abraham I static int mmc_execute_tuning(struct mmc *mmc, uint opcode) 1326ec841209SKishon Vijay Abraham I { 1327ec841209SKishon Vijay Abraham I return -ENOTSUPP; 1328ec841209SKishon Vijay Abraham I } 1329ec841209SKishon Vijay Abraham I 1330318a7a57SJean-Jacques Hiblot static void mmc_send_init_stream(struct mmc *mmc) 1331318a7a57SJean-Jacques Hiblot { 1332318a7a57SJean-Jacques Hiblot } 1333318a7a57SJean-Jacques Hiblot 13342a4d212fSKishon Vijay Abraham I static int mmc_set_ios(struct mmc *mmc) 1335272cc70bSAndy Fleming { 13362a4d212fSKishon Vijay Abraham I int ret = 0; 13372a4d212fSKishon Vijay Abraham I 133893bfd616SPantelis Antoniou if (mmc->cfg->ops->set_ios) 13392a4d212fSKishon Vijay Abraham I ret = mmc->cfg->ops->set_ios(mmc); 13402a4d212fSKishon Vijay Abraham I 13412a4d212fSKishon Vijay Abraham I return ret; 1342272cc70bSAndy Fleming } 13438ca51e51SSimon Glass #endif 1344272cc70bSAndy Fleming 134535f67820SKishon Vijay Abraham I int mmc_set_clock(struct mmc *mmc, uint clock, bool disable) 1346272cc70bSAndy Fleming { 134793bfd616SPantelis Antoniou if (clock > mmc->cfg->f_max) 134893bfd616SPantelis Antoniou clock = mmc->cfg->f_max; 1349272cc70bSAndy Fleming 135093bfd616SPantelis Antoniou if (clock < mmc->cfg->f_min) 135193bfd616SPantelis Antoniou clock = mmc->cfg->f_min; 1352272cc70bSAndy Fleming 1353272cc70bSAndy Fleming mmc->clock = clock; 135435f67820SKishon Vijay Abraham I mmc->clk_disable = disable; 1355272cc70bSAndy Fleming 13562a4d212fSKishon Vijay Abraham I return mmc_set_ios(mmc); 1357272cc70bSAndy Fleming } 1358272cc70bSAndy Fleming 13592a4d212fSKishon Vijay Abraham I static int mmc_set_bus_width(struct mmc *mmc, uint width) 1360272cc70bSAndy Fleming { 1361272cc70bSAndy Fleming mmc->bus_width = width; 1362272cc70bSAndy Fleming 13632a4d212fSKishon Vijay Abraham I return mmc_set_ios(mmc); 1364272cc70bSAndy Fleming } 1365272cc70bSAndy Fleming 13664c9d2aaaSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG) 13674c9d2aaaSJean-Jacques Hiblot /* 13684c9d2aaaSJean-Jacques Hiblot * helper function to display the capabilities in a human 13694c9d2aaaSJean-Jacques Hiblot * friendly manner. The capabilities include bus width and 13704c9d2aaaSJean-Jacques Hiblot * supported modes. 13714c9d2aaaSJean-Jacques Hiblot */ 13724c9d2aaaSJean-Jacques Hiblot void mmc_dump_capabilities(const char *text, uint caps) 13734c9d2aaaSJean-Jacques Hiblot { 13744c9d2aaaSJean-Jacques Hiblot enum bus_mode mode; 13754c9d2aaaSJean-Jacques Hiblot 13764c9d2aaaSJean-Jacques Hiblot printf("%s: widths [", text); 13774c9d2aaaSJean-Jacques Hiblot if (caps & MMC_MODE_8BIT) 13784c9d2aaaSJean-Jacques Hiblot printf("8, "); 13794c9d2aaaSJean-Jacques Hiblot if (caps & MMC_MODE_4BIT) 13804c9d2aaaSJean-Jacques Hiblot printf("4, "); 1381d0c221feSJean-Jacques Hiblot if (caps & MMC_MODE_1BIT) 1382d0c221feSJean-Jacques Hiblot printf("1, "); 1383d0c221feSJean-Jacques Hiblot printf("\b\b] modes ["); 13844c9d2aaaSJean-Jacques Hiblot for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++) 13854c9d2aaaSJean-Jacques Hiblot if (MMC_CAP(mode) & caps) 13864c9d2aaaSJean-Jacques Hiblot printf("%s, ", mmc_mode_name(mode)); 13874c9d2aaaSJean-Jacques Hiblot printf("\b\b]\n"); 13884c9d2aaaSJean-Jacques Hiblot } 13894c9d2aaaSJean-Jacques Hiblot #endif 13904c9d2aaaSJean-Jacques Hiblot 1391d0c221feSJean-Jacques Hiblot struct mode_width_tuning { 1392d0c221feSJean-Jacques Hiblot enum bus_mode mode; 1393d0c221feSJean-Jacques Hiblot uint widths; 1394634d4849SKishon Vijay Abraham I uint tuning; 1395d0c221feSJean-Jacques Hiblot }; 1396d0c221feSJean-Jacques Hiblot 1397aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage) 1398aff5d3c8SKishon Vijay Abraham I { 1399aff5d3c8SKishon Vijay Abraham I mmc->signal_voltage = signal_voltage; 1400aff5d3c8SKishon Vijay Abraham I return mmc_set_ios(mmc); 1401aff5d3c8SKishon Vijay Abraham I } 1402aff5d3c8SKishon Vijay Abraham I 1403d0c221feSJean-Jacques Hiblot static const struct mode_width_tuning sd_modes_by_pref[] = { 1404d0c221feSJean-Jacques Hiblot { 1405c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR104, 1406c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1407c10b85d6SJean-Jacques Hiblot .tuning = MMC_CMD_SEND_TUNING_BLOCK 1408c10b85d6SJean-Jacques Hiblot }, 1409c10b85d6SJean-Jacques Hiblot { 1410c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR50, 1411c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1412c10b85d6SJean-Jacques Hiblot }, 1413c10b85d6SJean-Jacques Hiblot { 1414c10b85d6SJean-Jacques Hiblot .mode = UHS_DDR50, 1415c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1416c10b85d6SJean-Jacques Hiblot }, 1417c10b85d6SJean-Jacques Hiblot { 1418c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR25, 1419c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1420c10b85d6SJean-Jacques Hiblot }, 1421c10b85d6SJean-Jacques Hiblot { 1422d0c221feSJean-Jacques Hiblot .mode = SD_HS, 1423d0c221feSJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1424d0c221feSJean-Jacques Hiblot }, 1425d0c221feSJean-Jacques Hiblot { 1426c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR12, 1427c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1428c10b85d6SJean-Jacques Hiblot }, 1429c10b85d6SJean-Jacques Hiblot { 1430d0c221feSJean-Jacques Hiblot .mode = SD_LEGACY, 1431d0c221feSJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1432d0c221feSJean-Jacques Hiblot } 1433d0c221feSJean-Jacques Hiblot }; 1434d0c221feSJean-Jacques Hiblot 1435d0c221feSJean-Jacques Hiblot #define for_each_sd_mode_by_pref(caps, mwt) \ 1436d0c221feSJean-Jacques Hiblot for (mwt = sd_modes_by_pref;\ 1437d0c221feSJean-Jacques Hiblot mwt < sd_modes_by_pref + ARRAY_SIZE(sd_modes_by_pref);\ 1438d0c221feSJean-Jacques Hiblot mwt++) \ 1439d0c221feSJean-Jacques Hiblot if (caps & MMC_CAP(mwt->mode)) 1440d0c221feSJean-Jacques Hiblot 1441d0c221feSJean-Jacques Hiblot static int sd_select_mode_and_width(struct mmc *mmc) 14428ac8a263SJean-Jacques Hiblot { 14438ac8a263SJean-Jacques Hiblot int err; 1444d0c221feSJean-Jacques Hiblot uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT}; 1445d0c221feSJean-Jacques Hiblot const struct mode_width_tuning *mwt; 1446c10b85d6SJean-Jacques Hiblot bool uhs_en = (mmc->ocr & OCR_S18R) ? true : false; 1447c10b85d6SJean-Jacques Hiblot uint caps; 1448c10b85d6SJean-Jacques Hiblot 14498ac8a263SJean-Jacques Hiblot 1450d0c221feSJean-Jacques Hiblot err = sd_get_capabilities(mmc); 14518ac8a263SJean-Jacques Hiblot if (err) 14528ac8a263SJean-Jacques Hiblot return err; 14538ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */ 1454*04a2ea24SJean-Jacques Hiblot caps = mmc->card_caps & (mmc->host_caps | MMC_MODE_1BIT); 14558ac8a263SJean-Jacques Hiblot 1456c10b85d6SJean-Jacques Hiblot if (!uhs_en) 1457c10b85d6SJean-Jacques Hiblot caps &= ~UHS_CAPS; 1458c10b85d6SJean-Jacques Hiblot 1459c10b85d6SJean-Jacques Hiblot for_each_sd_mode_by_pref(caps, mwt) { 1460d0c221feSJean-Jacques Hiblot uint *w; 14618ac8a263SJean-Jacques Hiblot 1462d0c221feSJean-Jacques Hiblot for (w = widths; w < widths + ARRAY_SIZE(widths); w++) { 1463c10b85d6SJean-Jacques Hiblot if (*w & caps & mwt->widths) { 1464d0c221feSJean-Jacques Hiblot debug("trying mode %s width %d (at %d MHz)\n", 1465d0c221feSJean-Jacques Hiblot mmc_mode_name(mwt->mode), 1466d0c221feSJean-Jacques Hiblot bus_width(*w), 1467d0c221feSJean-Jacques Hiblot mmc_mode2freq(mmc, mwt->mode) / 1000000); 1468d0c221feSJean-Jacques Hiblot 1469d0c221feSJean-Jacques Hiblot /* configure the bus width (card + host) */ 1470d0c221feSJean-Jacques Hiblot err = sd_select_bus_width(mmc, bus_width(*w)); 14718ac8a263SJean-Jacques Hiblot if (err) 1472d0c221feSJean-Jacques Hiblot goto error; 1473d0c221feSJean-Jacques Hiblot mmc_set_bus_width(mmc, bus_width(*w)); 14748ac8a263SJean-Jacques Hiblot 1475d0c221feSJean-Jacques Hiblot /* configure the bus mode (card) */ 1476d0c221feSJean-Jacques Hiblot err = sd_set_card_speed(mmc, mwt->mode); 14778ac8a263SJean-Jacques Hiblot if (err) 1478d0c221feSJean-Jacques Hiblot goto error; 14798ac8a263SJean-Jacques Hiblot 1480d0c221feSJean-Jacques Hiblot /* configure the bus mode (host) */ 1481d0c221feSJean-Jacques Hiblot mmc_select_mode(mmc, mwt->mode); 148235f67820SKishon Vijay Abraham I mmc_set_clock(mmc, mmc->tran_speed, false); 14838ac8a263SJean-Jacques Hiblot 1484c10b85d6SJean-Jacques Hiblot /* execute tuning if needed */ 1485c10b85d6SJean-Jacques Hiblot if (mwt->tuning && !mmc_host_is_spi(mmc)) { 1486c10b85d6SJean-Jacques Hiblot err = mmc_execute_tuning(mmc, 1487c10b85d6SJean-Jacques Hiblot mwt->tuning); 1488c10b85d6SJean-Jacques Hiblot if (err) { 1489c10b85d6SJean-Jacques Hiblot debug("tuning failed\n"); 1490c10b85d6SJean-Jacques Hiblot goto error; 1491c10b85d6SJean-Jacques Hiblot } 1492c10b85d6SJean-Jacques Hiblot } 1493c10b85d6SJean-Jacques Hiblot 14948ac8a263SJean-Jacques Hiblot err = sd_read_ssr(mmc); 1495d0c221feSJean-Jacques Hiblot if (!err) 14968ac8a263SJean-Jacques Hiblot return 0; 1497d0c221feSJean-Jacques Hiblot 1498d0c221feSJean-Jacques Hiblot printf("bad ssr\n"); 1499d0c221feSJean-Jacques Hiblot 1500d0c221feSJean-Jacques Hiblot error: 1501d0c221feSJean-Jacques Hiblot /* revert to a safer bus speed */ 1502d0c221feSJean-Jacques Hiblot mmc_select_mode(mmc, SD_LEGACY); 150335f67820SKishon Vijay Abraham I mmc_set_clock(mmc, mmc->tran_speed, false); 1504d0c221feSJean-Jacques Hiblot } 1505d0c221feSJean-Jacques Hiblot } 1506d0c221feSJean-Jacques Hiblot } 1507d0c221feSJean-Jacques Hiblot 1508d0c221feSJean-Jacques Hiblot printf("unable to select a mode\n"); 1509d0c221feSJean-Jacques Hiblot return -ENOTSUPP; 15108ac8a263SJean-Jacques Hiblot } 15118ac8a263SJean-Jacques Hiblot 15127382e691SJean-Jacques Hiblot /* 15137382e691SJean-Jacques Hiblot * read the compare the part of ext csd that is constant. 15147382e691SJean-Jacques Hiblot * This can be used to check that the transfer is working 15157382e691SJean-Jacques Hiblot * as expected. 15167382e691SJean-Jacques Hiblot */ 15177382e691SJean-Jacques Hiblot static int mmc_read_and_compare_ext_csd(struct mmc *mmc) 15187382e691SJean-Jacques Hiblot { 15197382e691SJean-Jacques Hiblot int err; 15207382e691SJean-Jacques Hiblot const u8 *ext_csd = mmc->ext_csd; 15217382e691SJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 15227382e691SJean-Jacques Hiblot 15237382e691SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, test_csd); 15247382e691SJean-Jacques Hiblot if (err) 15257382e691SJean-Jacques Hiblot return err; 15267382e691SJean-Jacques Hiblot 15277382e691SJean-Jacques Hiblot /* Only compare read only fields */ 15287382e691SJean-Jacques Hiblot if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] 15297382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_PARTITIONING_SUPPORT] && 15307382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_WP_GRP_SIZE] 15317382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_WP_GRP_SIZE] && 15327382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_REV] 15337382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_REV] && 15347382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 15357382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] && 15367382e691SJean-Jacques Hiblot memcmp(&ext_csd[EXT_CSD_SEC_CNT], 15377382e691SJean-Jacques Hiblot &test_csd[EXT_CSD_SEC_CNT], 4) == 0) 15387382e691SJean-Jacques Hiblot return 0; 15397382e691SJean-Jacques Hiblot 15407382e691SJean-Jacques Hiblot return -EBADMSG; 15417382e691SJean-Jacques Hiblot } 15427382e691SJean-Jacques Hiblot 15433862b854SJean-Jacques Hiblot static const struct mode_width_tuning mmc_modes_by_pref[] = { 15448ac8a263SJean-Jacques Hiblot { 15453862b854SJean-Jacques Hiblot .mode = MMC_HS_200, 15463862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT, 1547634d4849SKishon Vijay Abraham I .tuning = MMC_CMD_SEND_TUNING_BLOCK_HS200 15483862b854SJean-Jacques Hiblot }, 15493862b854SJean-Jacques Hiblot { 15503862b854SJean-Jacques Hiblot .mode = MMC_DDR_52, 15513862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT, 15523862b854SJean-Jacques Hiblot }, 15533862b854SJean-Jacques Hiblot { 15543862b854SJean-Jacques Hiblot .mode = MMC_HS_52, 15553862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 15563862b854SJean-Jacques Hiblot }, 15573862b854SJean-Jacques Hiblot { 15583862b854SJean-Jacques Hiblot .mode = MMC_HS, 15593862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 15603862b854SJean-Jacques Hiblot }, 15613862b854SJean-Jacques Hiblot { 15623862b854SJean-Jacques Hiblot .mode = MMC_LEGACY, 15633862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 15643862b854SJean-Jacques Hiblot } 15658ac8a263SJean-Jacques Hiblot }; 15668ac8a263SJean-Jacques Hiblot 15673862b854SJean-Jacques Hiblot #define for_each_mmc_mode_by_pref(caps, mwt) \ 15683862b854SJean-Jacques Hiblot for (mwt = mmc_modes_by_pref;\ 15693862b854SJean-Jacques Hiblot mwt < mmc_modes_by_pref + ARRAY_SIZE(mmc_modes_by_pref);\ 15703862b854SJean-Jacques Hiblot mwt++) \ 15713862b854SJean-Jacques Hiblot if (caps & MMC_CAP(mwt->mode)) 15723862b854SJean-Jacques Hiblot 15733862b854SJean-Jacques Hiblot static const struct ext_csd_bus_width { 15743862b854SJean-Jacques Hiblot uint cap; 15753862b854SJean-Jacques Hiblot bool is_ddr; 15763862b854SJean-Jacques Hiblot uint ext_csd_bits; 15773862b854SJean-Jacques Hiblot } ext_csd_bus_width[] = { 15783862b854SJean-Jacques Hiblot {MMC_MODE_8BIT, true, EXT_CSD_DDR_BUS_WIDTH_8}, 15793862b854SJean-Jacques Hiblot {MMC_MODE_4BIT, true, EXT_CSD_DDR_BUS_WIDTH_4}, 15803862b854SJean-Jacques Hiblot {MMC_MODE_8BIT, false, EXT_CSD_BUS_WIDTH_8}, 15813862b854SJean-Jacques Hiblot {MMC_MODE_4BIT, false, EXT_CSD_BUS_WIDTH_4}, 15823862b854SJean-Jacques Hiblot {MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1}, 15833862b854SJean-Jacques Hiblot }; 15843862b854SJean-Jacques Hiblot 15853862b854SJean-Jacques Hiblot #define for_each_supported_width(caps, ddr, ecbv) \ 15863862b854SJean-Jacques Hiblot for (ecbv = ext_csd_bus_width;\ 15873862b854SJean-Jacques Hiblot ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\ 15883862b854SJean-Jacques Hiblot ecbv++) \ 15893862b854SJean-Jacques Hiblot if ((ddr == ecbv->is_ddr) && (caps & ecbv->cap)) 15903862b854SJean-Jacques Hiblot 15913862b854SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc) 15923862b854SJean-Jacques Hiblot { 15933862b854SJean-Jacques Hiblot int err; 15943862b854SJean-Jacques Hiblot const struct mode_width_tuning *mwt; 15953862b854SJean-Jacques Hiblot const struct ext_csd_bus_width *ecbw; 15963862b854SJean-Jacques Hiblot 15973862b854SJean-Jacques Hiblot err = mmc_get_capabilities(mmc); 15988ac8a263SJean-Jacques Hiblot if (err) 15998ac8a263SJean-Jacques Hiblot return err; 16008ac8a263SJean-Jacques Hiblot 16018ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */ 1602*04a2ea24SJean-Jacques Hiblot mmc->card_caps &= (mmc->host_caps | MMC_MODE_1BIT); 16038ac8a263SJean-Jacques Hiblot 16048ac8a263SJean-Jacques Hiblot /* Only version 4 of MMC supports wider bus widths */ 16058ac8a263SJean-Jacques Hiblot if (mmc->version < MMC_VERSION_4) 16068ac8a263SJean-Jacques Hiblot return 0; 16078ac8a263SJean-Jacques Hiblot 1608dfda9d88SJean-Jacques Hiblot if (!mmc->ext_csd) { 1609dfda9d88SJean-Jacques Hiblot debug("No ext_csd found!\n"); /* this should enver happen */ 1610dfda9d88SJean-Jacques Hiblot return -ENOTSUPP; 1611dfda9d88SJean-Jacques Hiblot } 1612dfda9d88SJean-Jacques Hiblot 16133862b854SJean-Jacques Hiblot for_each_mmc_mode_by_pref(mmc->card_caps, mwt) { 16143862b854SJean-Jacques Hiblot for_each_supported_width(mmc->card_caps & mwt->widths, 16153862b854SJean-Jacques Hiblot mmc_is_mode_ddr(mwt->mode), ecbw) { 16163862b854SJean-Jacques Hiblot debug("trying mode %s width %d (at %d MHz)\n", 16173862b854SJean-Jacques Hiblot mmc_mode_name(mwt->mode), 16183862b854SJean-Jacques Hiblot bus_width(ecbw->cap), 16193862b854SJean-Jacques Hiblot mmc_mode2freq(mmc, mwt->mode) / 1000000); 16203862b854SJean-Jacques Hiblot /* configure the bus width (card + host) */ 16213862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 16223862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, 16233862b854SJean-Jacques Hiblot ecbw->ext_csd_bits & ~EXT_CSD_DDR_FLAG); 16243862b854SJean-Jacques Hiblot if (err) 16253862b854SJean-Jacques Hiblot goto error; 16263862b854SJean-Jacques Hiblot mmc_set_bus_width(mmc, bus_width(ecbw->cap)); 16273862b854SJean-Jacques Hiblot 16283862b854SJean-Jacques Hiblot /* configure the bus speed (card) */ 16293862b854SJean-Jacques Hiblot err = mmc_set_card_speed(mmc, mwt->mode); 16303862b854SJean-Jacques Hiblot if (err) 16313862b854SJean-Jacques Hiblot goto error; 16323862b854SJean-Jacques Hiblot 16338ac8a263SJean-Jacques Hiblot /* 16343862b854SJean-Jacques Hiblot * configure the bus width AND the ddr mode (card) 16353862b854SJean-Jacques Hiblot * The host side will be taken care of in the next step 16368ac8a263SJean-Jacques Hiblot */ 16373862b854SJean-Jacques Hiblot if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) { 16383862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 16393862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, 16403862b854SJean-Jacques Hiblot ecbw->ext_csd_bits); 16413862b854SJean-Jacques Hiblot if (err) 16423862b854SJean-Jacques Hiblot goto error; 16438ac8a263SJean-Jacques Hiblot } 16448ac8a263SJean-Jacques Hiblot 16453862b854SJean-Jacques Hiblot /* configure the bus mode (host) */ 16463862b854SJean-Jacques Hiblot mmc_select_mode(mmc, mwt->mode); 164735f67820SKishon Vijay Abraham I mmc_set_clock(mmc, mmc->tran_speed, false); 16488ac8a263SJean-Jacques Hiblot 1649634d4849SKishon Vijay Abraham I /* execute tuning if needed */ 1650634d4849SKishon Vijay Abraham I if (mwt->tuning) { 1651634d4849SKishon Vijay Abraham I err = mmc_execute_tuning(mmc, mwt->tuning); 1652634d4849SKishon Vijay Abraham I if (err) { 1653634d4849SKishon Vijay Abraham I debug("tuning failed\n"); 1654634d4849SKishon Vijay Abraham I goto error; 1655634d4849SKishon Vijay Abraham I } 1656634d4849SKishon Vijay Abraham I } 1657634d4849SKishon Vijay Abraham I 16583862b854SJean-Jacques Hiblot /* do a transfer to check the configuration */ 16597382e691SJean-Jacques Hiblot err = mmc_read_and_compare_ext_csd(mmc); 16607382e691SJean-Jacques Hiblot if (!err) 16613862b854SJean-Jacques Hiblot return 0; 16623862b854SJean-Jacques Hiblot error: 16633862b854SJean-Jacques Hiblot /* if an error occured, revert to a safer bus mode */ 16643862b854SJean-Jacques Hiblot mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 16653862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1); 16663862b854SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_LEGACY); 16673862b854SJean-Jacques Hiblot mmc_set_bus_width(mmc, 1); 16683862b854SJean-Jacques Hiblot } 16698ac8a263SJean-Jacques Hiblot } 16708ac8a263SJean-Jacques Hiblot 16713862b854SJean-Jacques Hiblot printf("unable to select a mode\n"); 16728ac8a263SJean-Jacques Hiblot 16733862b854SJean-Jacques Hiblot return -ENOTSUPP; 16748ac8a263SJean-Jacques Hiblot } 16758ac8a263SJean-Jacques Hiblot 1676dfda9d88SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc) 1677c744b6f6SJean-Jacques Hiblot { 1678c744b6f6SJean-Jacques Hiblot int err, i; 1679c744b6f6SJean-Jacques Hiblot u64 capacity; 1680c744b6f6SJean-Jacques Hiblot bool has_parts = false; 1681c744b6f6SJean-Jacques Hiblot bool part_completed; 1682dfda9d88SJean-Jacques Hiblot u8 *ext_csd; 1683c744b6f6SJean-Jacques Hiblot 1684c744b6f6SJean-Jacques Hiblot if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4)) 1685c744b6f6SJean-Jacques Hiblot return 0; 1686c744b6f6SJean-Jacques Hiblot 1687dfda9d88SJean-Jacques Hiblot ext_csd = malloc_cache_aligned(MMC_MAX_BLOCK_LEN); 1688dfda9d88SJean-Jacques Hiblot if (!ext_csd) 1689dfda9d88SJean-Jacques Hiblot return -ENOMEM; 1690dfda9d88SJean-Jacques Hiblot 1691dfda9d88SJean-Jacques Hiblot mmc->ext_csd = ext_csd; 1692dfda9d88SJean-Jacques Hiblot 1693c744b6f6SJean-Jacques Hiblot /* check ext_csd version and capacity */ 1694c744b6f6SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, ext_csd); 1695c744b6f6SJean-Jacques Hiblot if (err) 1696c744b6f6SJean-Jacques Hiblot return err; 1697c744b6f6SJean-Jacques Hiblot if (ext_csd[EXT_CSD_REV] >= 2) { 1698c744b6f6SJean-Jacques Hiblot /* 1699c744b6f6SJean-Jacques Hiblot * According to the JEDEC Standard, the value of 1700c744b6f6SJean-Jacques Hiblot * ext_csd's capacity is valid if the value is more 1701c744b6f6SJean-Jacques Hiblot * than 2GB 1702c744b6f6SJean-Jacques Hiblot */ 1703c744b6f6SJean-Jacques Hiblot capacity = ext_csd[EXT_CSD_SEC_CNT] << 0 1704c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 1705c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 1706c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; 1707c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN; 1708c744b6f6SJean-Jacques Hiblot if ((capacity >> 20) > 2 * 1024) 1709c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity; 1710c744b6f6SJean-Jacques Hiblot } 1711c744b6f6SJean-Jacques Hiblot 1712c744b6f6SJean-Jacques Hiblot switch (ext_csd[EXT_CSD_REV]) { 1713c744b6f6SJean-Jacques Hiblot case 1: 1714c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_1; 1715c744b6f6SJean-Jacques Hiblot break; 1716c744b6f6SJean-Jacques Hiblot case 2: 1717c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_2; 1718c744b6f6SJean-Jacques Hiblot break; 1719c744b6f6SJean-Jacques Hiblot case 3: 1720c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_3; 1721c744b6f6SJean-Jacques Hiblot break; 1722c744b6f6SJean-Jacques Hiblot case 5: 1723c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_41; 1724c744b6f6SJean-Jacques Hiblot break; 1725c744b6f6SJean-Jacques Hiblot case 6: 1726c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_5; 1727c744b6f6SJean-Jacques Hiblot break; 1728c744b6f6SJean-Jacques Hiblot case 7: 1729c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_5_0; 1730c744b6f6SJean-Jacques Hiblot break; 1731c744b6f6SJean-Jacques Hiblot case 8: 1732c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_5_1; 1733c744b6f6SJean-Jacques Hiblot break; 1734c744b6f6SJean-Jacques Hiblot } 1735c744b6f6SJean-Jacques Hiblot 1736c744b6f6SJean-Jacques Hiblot /* The partition data may be non-zero but it is only 1737c744b6f6SJean-Jacques Hiblot * effective if PARTITION_SETTING_COMPLETED is set in 1738c744b6f6SJean-Jacques Hiblot * EXT_CSD, so ignore any data if this bit is not set, 1739c744b6f6SJean-Jacques Hiblot * except for enabling the high-capacity group size 1740c744b6f6SJean-Jacques Hiblot * definition (see below). 1741c744b6f6SJean-Jacques Hiblot */ 1742c744b6f6SJean-Jacques Hiblot part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] & 1743c744b6f6SJean-Jacques Hiblot EXT_CSD_PARTITION_SETTING_COMPLETED); 1744c744b6f6SJean-Jacques Hiblot 1745c744b6f6SJean-Jacques Hiblot /* store the partition info of emmc */ 1746c744b6f6SJean-Jacques Hiblot mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT]; 1747c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || 1748c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_BOOT_MULT]) 1749c744b6f6SJean-Jacques Hiblot mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; 1750c744b6f6SJean-Jacques Hiblot if (part_completed && 1751c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT)) 1752c744b6f6SJean-Jacques Hiblot mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]; 1753c744b6f6SJean-Jacques Hiblot 1754c744b6f6SJean-Jacques Hiblot mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17; 1755c744b6f6SJean-Jacques Hiblot 1756c744b6f6SJean-Jacques Hiblot mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17; 1757c744b6f6SJean-Jacques Hiblot 1758c744b6f6SJean-Jacques Hiblot for (i = 0; i < 4; i++) { 1759c744b6f6SJean-Jacques Hiblot int idx = EXT_CSD_GP_SIZE_MULT + i * 3; 1760c744b6f6SJean-Jacques Hiblot uint mult = (ext_csd[idx + 2] << 16) + 1761c744b6f6SJean-Jacques Hiblot (ext_csd[idx + 1] << 8) + ext_csd[idx]; 1762c744b6f6SJean-Jacques Hiblot if (mult) 1763c744b6f6SJean-Jacques Hiblot has_parts = true; 1764c744b6f6SJean-Jacques Hiblot if (!part_completed) 1765c744b6f6SJean-Jacques Hiblot continue; 1766c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] = mult; 1767c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= 1768c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1769c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1770c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] <<= 19; 1771c744b6f6SJean-Jacques Hiblot } 1772c744b6f6SJean-Jacques Hiblot 1773c744b6f6SJean-Jacques Hiblot if (part_completed) { 1774c744b6f6SJean-Jacques Hiblot mmc->enh_user_size = 1775c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) + 1776c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) + 1777c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_SIZE_MULT]; 1778c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1779c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1780c744b6f6SJean-Jacques Hiblot mmc->enh_user_size <<= 19; 1781c744b6f6SJean-Jacques Hiblot mmc->enh_user_start = 1782c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) + 1783c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) + 1784c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) + 1785c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_START_ADDR]; 1786c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity) 1787c744b6f6SJean-Jacques Hiblot mmc->enh_user_start <<= 9; 1788c744b6f6SJean-Jacques Hiblot } 1789c744b6f6SJean-Jacques Hiblot 1790c744b6f6SJean-Jacques Hiblot /* 1791c744b6f6SJean-Jacques Hiblot * Host needs to enable ERASE_GRP_DEF bit if device is 1792c744b6f6SJean-Jacques Hiblot * partitioned. This bit will be lost every time after a reset 1793c744b6f6SJean-Jacques Hiblot * or power off. This will affect erase size. 1794c744b6f6SJean-Jacques Hiblot */ 1795c744b6f6SJean-Jacques Hiblot if (part_completed) 1796c744b6f6SJean-Jacques Hiblot has_parts = true; 1797c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) && 1798c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) 1799c744b6f6SJean-Jacques Hiblot has_parts = true; 1800c744b6f6SJean-Jacques Hiblot if (has_parts) { 1801c744b6f6SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1802c744b6f6SJean-Jacques Hiblot EXT_CSD_ERASE_GROUP_DEF, 1); 1803c744b6f6SJean-Jacques Hiblot 1804c744b6f6SJean-Jacques Hiblot if (err) 1805c744b6f6SJean-Jacques Hiblot return err; 1806c744b6f6SJean-Jacques Hiblot 1807c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 1808c744b6f6SJean-Jacques Hiblot } 1809c744b6f6SJean-Jacques Hiblot 1810c744b6f6SJean-Jacques Hiblot if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) { 1811c744b6f6SJean-Jacques Hiblot /* Read out group size from ext_csd */ 1812c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = 1813c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 1814c744b6f6SJean-Jacques Hiblot /* 1815c744b6f6SJean-Jacques Hiblot * if high capacity and partition setting completed 1816c744b6f6SJean-Jacques Hiblot * SEC_COUNT is valid even if it is smaller than 2 GiB 1817c744b6f6SJean-Jacques Hiblot * JEDEC Standard JESD84-B45, 6.2.4 1818c744b6f6SJean-Jacques Hiblot */ 1819c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity && part_completed) { 1820c744b6f6SJean-Jacques Hiblot capacity = (ext_csd[EXT_CSD_SEC_CNT]) | 1821c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) | 1822c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) | 1823c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 3] << 24); 1824c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN; 1825c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity; 1826c744b6f6SJean-Jacques Hiblot } 1827c744b6f6SJean-Jacques Hiblot } else { 1828c744b6f6SJean-Jacques Hiblot /* Calculate the group size from the csd value. */ 1829c744b6f6SJean-Jacques Hiblot int erase_gsz, erase_gmul; 1830c744b6f6SJean-Jacques Hiblot 1831c744b6f6SJean-Jacques Hiblot erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; 1832c744b6f6SJean-Jacques Hiblot erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; 1833c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = (erase_gsz + 1) 1834c744b6f6SJean-Jacques Hiblot * (erase_gmul + 1); 1835c744b6f6SJean-Jacques Hiblot } 1836c744b6f6SJean-Jacques Hiblot 1837c744b6f6SJean-Jacques Hiblot mmc->hc_wp_grp_size = 1024 1838c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 1839c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1840c744b6f6SJean-Jacques Hiblot 1841c744b6f6SJean-Jacques Hiblot mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 1842c744b6f6SJean-Jacques Hiblot 1843c744b6f6SJean-Jacques Hiblot return 0; 1844c744b6f6SJean-Jacques Hiblot } 1845c744b6f6SJean-Jacques Hiblot 1846fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc) 1847272cc70bSAndy Fleming { 1848f866a46dSStephen Warren int err, i; 1849272cc70bSAndy Fleming uint mult, freq; 1850c744b6f6SJean-Jacques Hiblot u64 cmult, csize; 1851272cc70bSAndy Fleming struct mmc_cmd cmd; 1852c40fdca6SSimon Glass struct blk_desc *bdesc; 1853272cc70bSAndy Fleming 1854d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON 1855d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ 1856d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; 1857d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R1; 1858d52ebf10SThomas Chou cmd.cmdarg = 1; 1859d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 1860d52ebf10SThomas Chou 1861d52ebf10SThomas Chou if (err) 1862d52ebf10SThomas Chou return err; 1863d52ebf10SThomas Chou } 1864d52ebf10SThomas Chou #endif 1865d52ebf10SThomas Chou 1866272cc70bSAndy Fleming /* Put the Card in Identify Mode */ 1867d52ebf10SThomas Chou cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : 1868d52ebf10SThomas Chou MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ 1869272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1870272cc70bSAndy Fleming cmd.cmdarg = 0; 1871272cc70bSAndy Fleming 1872272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1873272cc70bSAndy Fleming 1874272cc70bSAndy Fleming if (err) 1875272cc70bSAndy Fleming return err; 1876272cc70bSAndy Fleming 1877272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16); 1878272cc70bSAndy Fleming 1879272cc70bSAndy Fleming /* 1880272cc70bSAndy Fleming * For MMC cards, set the Relative Address. 1881272cc70bSAndy Fleming * For SD cards, get the Relatvie Address. 1882272cc70bSAndy Fleming * This also puts the cards into Standby State 1883272cc70bSAndy Fleming */ 1884d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1885272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; 1886272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1887272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6; 1888272cc70bSAndy Fleming 1889272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1890272cc70bSAndy Fleming 1891272cc70bSAndy Fleming if (err) 1892272cc70bSAndy Fleming return err; 1893272cc70bSAndy Fleming 1894272cc70bSAndy Fleming if (IS_SD(mmc)) 1895998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff; 1896d52ebf10SThomas Chou } 1897272cc70bSAndy Fleming 1898272cc70bSAndy Fleming /* Get the Card-Specific Data */ 1899272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD; 1900272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1901272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1902272cc70bSAndy Fleming 1903272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1904272cc70bSAndy Fleming 1905272cc70bSAndy Fleming if (err) 1906272cc70bSAndy Fleming return err; 1907272cc70bSAndy Fleming 1908998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0]; 1909998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1]; 1910998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2]; 1911998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3]; 1912272cc70bSAndy Fleming 1913272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) { 19140b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf; 1915272cc70bSAndy Fleming 1916272cc70bSAndy Fleming switch (version) { 1917272cc70bSAndy Fleming case 0: 1918272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1919272cc70bSAndy Fleming break; 1920272cc70bSAndy Fleming case 1: 1921272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4; 1922272cc70bSAndy Fleming break; 1923272cc70bSAndy Fleming case 2: 1924272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2; 1925272cc70bSAndy Fleming break; 1926272cc70bSAndy Fleming case 3: 1927272cc70bSAndy Fleming mmc->version = MMC_VERSION_3; 1928272cc70bSAndy Fleming break; 1929272cc70bSAndy Fleming case 4: 1930272cc70bSAndy Fleming mmc->version = MMC_VERSION_4; 1931272cc70bSAndy Fleming break; 1932272cc70bSAndy Fleming default: 1933272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1934272cc70bSAndy Fleming break; 1935272cc70bSAndy Fleming } 1936272cc70bSAndy Fleming } 1937272cc70bSAndy Fleming 1938272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */ 19390b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)]; 19400b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; 1941272cc70bSAndy Fleming 194235f9e196SJean-Jacques Hiblot mmc->legacy_speed = freq * mult; 194335f9e196SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_LEGACY); 1944272cc70bSAndy Fleming 1945ab71188cSMarkus Niebel mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); 1946998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); 1947272cc70bSAndy Fleming 1948272cc70bSAndy Fleming if (IS_SD(mmc)) 1949272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len; 1950272cc70bSAndy Fleming else 1951998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); 1952272cc70bSAndy Fleming 1953272cc70bSAndy Fleming if (mmc->high_capacity) { 1954272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16 1955272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16; 1956272cc70bSAndy Fleming cmult = 8; 1957272cc70bSAndy Fleming } else { 1958272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2 1959272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30; 1960272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15; 1961272cc70bSAndy Fleming } 1962272cc70bSAndy Fleming 1963f866a46dSStephen Warren mmc->capacity_user = (csize + 1) << (cmult + 2); 1964f866a46dSStephen Warren mmc->capacity_user *= mmc->read_bl_len; 1965f866a46dSStephen Warren mmc->capacity_boot = 0; 1966f866a46dSStephen Warren mmc->capacity_rpmb = 0; 1967f866a46dSStephen Warren for (i = 0; i < 4; i++) 1968f866a46dSStephen Warren mmc->capacity_gp[i] = 0; 1969272cc70bSAndy Fleming 19708bfa195eSSimon Glass if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN) 19718bfa195eSSimon Glass mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 1972272cc70bSAndy Fleming 19738bfa195eSSimon Glass if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) 19748bfa195eSSimon Glass mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 1975272cc70bSAndy Fleming 1976ab71188cSMarkus Niebel if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) { 1977ab71188cSMarkus Niebel cmd.cmdidx = MMC_CMD_SET_DSR; 1978ab71188cSMarkus Niebel cmd.cmdarg = (mmc->dsr & 0xffff) << 16; 1979ab71188cSMarkus Niebel cmd.resp_type = MMC_RSP_NONE; 1980ab71188cSMarkus Niebel if (mmc_send_cmd(mmc, &cmd, NULL)) 1981ab71188cSMarkus Niebel printf("MMC: SET_DSR failed\n"); 1982ab71188cSMarkus Niebel } 1983ab71188cSMarkus Niebel 1984272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */ 1985d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1986272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD; 1987fe8f7066SAjay Bhargav cmd.resp_type = MMC_RSP_R1; 1988272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1989272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1990272cc70bSAndy Fleming 1991272cc70bSAndy Fleming if (err) 1992272cc70bSAndy Fleming return err; 1993d52ebf10SThomas Chou } 1994272cc70bSAndy Fleming 1995e6f99a56SLei Wen /* 1996e6f99a56SLei Wen * For SD, its erase group is always one sector 1997e6f99a56SLei Wen */ 1998e6f99a56SLei Wen mmc->erase_grp_size = 1; 1999bc897b1dSLei Wen mmc->part_config = MMCPART_NOAVAILABLE; 2000c744b6f6SJean-Jacques Hiblot 2001dfda9d88SJean-Jacques Hiblot err = mmc_startup_v4(mmc); 20029cf199ebSDiego Santa Cruz if (err) 20039cf199ebSDiego Santa Cruz return err; 2004f866a46dSStephen Warren 2005c40fdca6SSimon Glass err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart); 2006f866a46dSStephen Warren if (err) 2007f866a46dSStephen Warren return err; 2008d23e2c09SSukumar Ghorai 2009272cc70bSAndy Fleming if (IS_SD(mmc)) 2010d0c221feSJean-Jacques Hiblot err = sd_select_mode_and_width(mmc); 2011272cc70bSAndy Fleming else 20123862b854SJean-Jacques Hiblot err = mmc_select_mode_and_width(mmc); 2013272cc70bSAndy Fleming 2014272cc70bSAndy Fleming if (err) 2015272cc70bSAndy Fleming return err; 2016272cc70bSAndy Fleming 2017272cc70bSAndy Fleming 20185af8f45cSAndrew Gabbasov /* Fix the block length for DDR mode */ 20195af8f45cSAndrew Gabbasov if (mmc->ddr_mode) { 20205af8f45cSAndrew Gabbasov mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 20215af8f45cSAndrew Gabbasov mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 20225af8f45cSAndrew Gabbasov } 20235af8f45cSAndrew Gabbasov 2024272cc70bSAndy Fleming /* fill in device description */ 2025c40fdca6SSimon Glass bdesc = mmc_get_blk_desc(mmc); 2026c40fdca6SSimon Glass bdesc->lun = 0; 2027c40fdca6SSimon Glass bdesc->hwpart = 0; 2028c40fdca6SSimon Glass bdesc->type = 0; 2029c40fdca6SSimon Glass bdesc->blksz = mmc->read_bl_len; 2030c40fdca6SSimon Glass bdesc->log2blksz = LOG2(bdesc->blksz); 2031c40fdca6SSimon Glass bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len); 2032fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \ 2033fc011f64SSjoerd Simons (defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \ 2034fc011f64SSjoerd Simons !defined(CONFIG_USE_TINY_PRINTF)) 2035c40fdca6SSimon Glass sprintf(bdesc->vendor, "Man %06x Snr %04x%04x", 2036babce5f6STaylor Hutt mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), 2037babce5f6STaylor Hutt (mmc->cid[3] >> 16) & 0xffff); 2038c40fdca6SSimon Glass sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff, 20390b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 2040babce5f6STaylor Hutt (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff, 2041babce5f6STaylor Hutt (mmc->cid[2] >> 24) & 0xff); 2042c40fdca6SSimon Glass sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf, 2043babce5f6STaylor Hutt (mmc->cid[2] >> 16) & 0xf); 204456196826SPaul Burton #else 2045c40fdca6SSimon Glass bdesc->vendor[0] = 0; 2046c40fdca6SSimon Glass bdesc->product[0] = 0; 2047c40fdca6SSimon Glass bdesc->revision[0] = 0; 204856196826SPaul Burton #endif 2049122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT) 2050c40fdca6SSimon Glass part_init(bdesc); 2051122efd43SMikhail Kshevetskiy #endif 2052272cc70bSAndy Fleming 2053272cc70bSAndy Fleming return 0; 2054272cc70bSAndy Fleming } 2055272cc70bSAndy Fleming 2056fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc) 2057272cc70bSAndy Fleming { 2058272cc70bSAndy Fleming struct mmc_cmd cmd; 2059272cc70bSAndy Fleming int err; 2060272cc70bSAndy Fleming 2061272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND; 2062272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ 206393bfd616SPantelis Antoniou cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa; 2064272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7; 2065272cc70bSAndy Fleming 2066272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2067272cc70bSAndy Fleming 2068272cc70bSAndy Fleming if (err) 2069272cc70bSAndy Fleming return err; 2070272cc70bSAndy Fleming 2071998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa) 2072915ffa52SJaehoon Chung return -EOPNOTSUPP; 2073272cc70bSAndy Fleming else 2074272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 2075272cc70bSAndy Fleming 2076272cc70bSAndy Fleming return 0; 2077272cc70bSAndy Fleming } 2078272cc70bSAndy Fleming 2079c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 208095de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */ 208195de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void) 208295de9ab2SPaul Kocialkowski { 208395de9ab2SPaul Kocialkowski } 208405cbeb7cSSimon Glass #endif 208595de9ab2SPaul Kocialkowski 20862051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc) 20872051aefeSPeng Fan { 2088c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 208906ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR) 20902051aefeSPeng Fan int ret; 20912051aefeSPeng Fan 20922051aefeSPeng Fan ret = device_get_supply_regulator(mmc->dev, "vmmc-supply", 209306ec045fSJean-Jacques Hiblot &mmc->vmmc_supply); 209406ec045fSJean-Jacques Hiblot if (ret) 2095288db7c7SJaehoon Chung debug("%s: No vmmc supply\n", mmc->dev->name); 20962051aefeSPeng Fan 209706ec045fSJean-Jacques Hiblot ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply", 209806ec045fSJean-Jacques Hiblot &mmc->vqmmc_supply); 209906ec045fSJean-Jacques Hiblot if (ret) 210006ec045fSJean-Jacques Hiblot debug("%s: No vqmmc supply\n", mmc->dev->name); 21012051aefeSPeng Fan #endif 210205cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */ 210305cbeb7cSSimon Glass /* 210405cbeb7cSSimon Glass * Driver model should use a regulator, as above, rather than calling 210505cbeb7cSSimon Glass * out to board code. 210605cbeb7cSSimon Glass */ 210705cbeb7cSSimon Glass board_mmc_power_init(); 210805cbeb7cSSimon Glass #endif 21092051aefeSPeng Fan return 0; 21102051aefeSPeng Fan } 21112051aefeSPeng Fan 2112fb7c3bebSKishon Vijay Abraham I /* 2113fb7c3bebSKishon Vijay Abraham I * put the host in the initial state: 2114fb7c3bebSKishon Vijay Abraham I * - turn on Vdd (card power supply) 2115fb7c3bebSKishon Vijay Abraham I * - configure the bus width and clock to minimal values 2116fb7c3bebSKishon Vijay Abraham I */ 2117fb7c3bebSKishon Vijay Abraham I static void mmc_set_initial_state(struct mmc *mmc) 2118fb7c3bebSKishon Vijay Abraham I { 2119fb7c3bebSKishon Vijay Abraham I int err; 2120fb7c3bebSKishon Vijay Abraham I 2121fb7c3bebSKishon Vijay Abraham I /* First try to set 3.3V. If it fails set to 1.8V */ 2122fb7c3bebSKishon Vijay Abraham I err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_330); 2123fb7c3bebSKishon Vijay Abraham I if (err != 0) 2124fb7c3bebSKishon Vijay Abraham I err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_180); 2125fb7c3bebSKishon Vijay Abraham I if (err != 0) 2126fb7c3bebSKishon Vijay Abraham I printf("mmc: failed to set signal voltage\n"); 2127fb7c3bebSKishon Vijay Abraham I 2128fb7c3bebSKishon Vijay Abraham I mmc_select_mode(mmc, MMC_LEGACY); 2129fb7c3bebSKishon Vijay Abraham I mmc_set_bus_width(mmc, 1); 213035f67820SKishon Vijay Abraham I mmc_set_clock(mmc, 0, false); 2131fb7c3bebSKishon Vijay Abraham I } 2132fb7c3bebSKishon Vijay Abraham I 2133fb7c3bebSKishon Vijay Abraham I static int mmc_power_on(struct mmc *mmc) 2134fb7c3bebSKishon Vijay Abraham I { 2135fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR) 2136fb7c3bebSKishon Vijay Abraham I if (mmc->vmmc_supply) { 2137fb7c3bebSKishon Vijay Abraham I int ret = regulator_set_enable(mmc->vmmc_supply, true); 2138fb7c3bebSKishon Vijay Abraham I 2139fb7c3bebSKishon Vijay Abraham I if (ret) { 2140fb7c3bebSKishon Vijay Abraham I puts("Error enabling VMMC supply\n"); 2141fb7c3bebSKishon Vijay Abraham I return ret; 2142fb7c3bebSKishon Vijay Abraham I } 2143fb7c3bebSKishon Vijay Abraham I } 2144fb7c3bebSKishon Vijay Abraham I #endif 2145fb7c3bebSKishon Vijay Abraham I return 0; 2146fb7c3bebSKishon Vijay Abraham I } 2147fb7c3bebSKishon Vijay Abraham I 2148fb7c3bebSKishon Vijay Abraham I static int mmc_power_off(struct mmc *mmc) 2149fb7c3bebSKishon Vijay Abraham I { 21502e7410d7SKishon Vijay Abraham I mmc_set_clock(mmc, 1, true); 2151fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR) 2152fb7c3bebSKishon Vijay Abraham I if (mmc->vmmc_supply) { 2153fb7c3bebSKishon Vijay Abraham I int ret = regulator_set_enable(mmc->vmmc_supply, false); 2154fb7c3bebSKishon Vijay Abraham I 2155fb7c3bebSKishon Vijay Abraham I if (ret) { 2156c10b85d6SJean-Jacques Hiblot debug("Error disabling VMMC supply\n"); 2157fb7c3bebSKishon Vijay Abraham I return ret; 2158fb7c3bebSKishon Vijay Abraham I } 2159fb7c3bebSKishon Vijay Abraham I } 2160fb7c3bebSKishon Vijay Abraham I #endif 2161fb7c3bebSKishon Vijay Abraham I return 0; 2162fb7c3bebSKishon Vijay Abraham I } 2163fb7c3bebSKishon Vijay Abraham I 2164fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc) 2165fb7c3bebSKishon Vijay Abraham I { 2166fb7c3bebSKishon Vijay Abraham I int ret; 2167fb7c3bebSKishon Vijay Abraham I 2168fb7c3bebSKishon Vijay Abraham I ret = mmc_power_off(mmc); 2169fb7c3bebSKishon Vijay Abraham I if (ret) 2170fb7c3bebSKishon Vijay Abraham I return ret; 2171fb7c3bebSKishon Vijay Abraham I /* 2172fb7c3bebSKishon Vijay Abraham I * SD spec recommends at least 1ms of delay. Let's wait for 2ms 2173fb7c3bebSKishon Vijay Abraham I * to be on the safer side. 2174fb7c3bebSKishon Vijay Abraham I */ 2175fb7c3bebSKishon Vijay Abraham I udelay(2000); 2176fb7c3bebSKishon Vijay Abraham I return mmc_power_on(mmc); 2177fb7c3bebSKishon Vijay Abraham I } 2178fb7c3bebSKishon Vijay Abraham I 2179e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc) 2180272cc70bSAndy Fleming { 21818ca51e51SSimon Glass bool no_card; 2182c10b85d6SJean-Jacques Hiblot bool uhs_en = supports_uhs(mmc->cfg->host_caps); 2183afd5932bSMacpaul Lin int err; 2184272cc70bSAndy Fleming 2185*04a2ea24SJean-Jacques Hiblot mmc->host_caps = mmc->cfg->host_caps; 2186*04a2ea24SJean-Jacques Hiblot 2187ab769f22SPantelis Antoniou /* we pretend there's no card when init is NULL */ 21888ca51e51SSimon Glass no_card = mmc_getcd(mmc) == 0; 2189e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 21908ca51e51SSimon Glass no_card = no_card || (mmc->cfg->ops->init == NULL); 21918ca51e51SSimon Glass #endif 21928ca51e51SSimon Glass if (no_card) { 219348972d90SThierry Reding mmc->has_init = 0; 219456196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 219548972d90SThierry Reding printf("MMC: no card present\n"); 219656196826SPaul Burton #endif 2197915ffa52SJaehoon Chung return -ENOMEDIUM; 219848972d90SThierry Reding } 219948972d90SThierry Reding 2200bc897b1dSLei Wen if (mmc->has_init) 2201bc897b1dSLei Wen return 0; 2202bc897b1dSLei Wen 22035a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 22045a8dbdc6SYangbo Lu mmc_adapter_card_type_ident(); 22055a8dbdc6SYangbo Lu #endif 22062051aefeSPeng Fan err = mmc_power_init(mmc); 22072051aefeSPeng Fan if (err) 22082051aefeSPeng Fan return err; 220995de9ab2SPaul Kocialkowski 2210*04a2ea24SJean-Jacques Hiblot err = mmc_power_cycle(mmc); 2211*04a2ea24SJean-Jacques Hiblot if (err) { 2212*04a2ea24SJean-Jacques Hiblot /* 2213*04a2ea24SJean-Jacques Hiblot * if power cycling is not supported, we should not try 2214*04a2ea24SJean-Jacques Hiblot * to use the UHS modes, because we wouldn't be able to 2215*04a2ea24SJean-Jacques Hiblot * recover from an error during the UHS initialization. 2216*04a2ea24SJean-Jacques Hiblot */ 2217*04a2ea24SJean-Jacques Hiblot debug("Unable to do a full power cycle. Disabling the UHS modes for safety\n"); 2218*04a2ea24SJean-Jacques Hiblot uhs_en = false; 2219*04a2ea24SJean-Jacques Hiblot mmc->host_caps &= ~UHS_CAPS; 2220fb7c3bebSKishon Vijay Abraham I err = mmc_power_on(mmc); 2221*04a2ea24SJean-Jacques Hiblot } 2222fb7c3bebSKishon Vijay Abraham I if (err) 2223fb7c3bebSKishon Vijay Abraham I return err; 2224fb7c3bebSKishon Vijay Abraham I 2225e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 22268ca51e51SSimon Glass /* The device has already been probed ready for use */ 22278ca51e51SSimon Glass #else 2228ab769f22SPantelis Antoniou /* made sure it's not NULL earlier */ 222993bfd616SPantelis Antoniou err = mmc->cfg->ops->init(mmc); 2230272cc70bSAndy Fleming if (err) 2231272cc70bSAndy Fleming return err; 22328ca51e51SSimon Glass #endif 2233786e8f81SAndrew Gabbasov mmc->ddr_mode = 0; 2234aff5d3c8SKishon Vijay Abraham I 2235c10b85d6SJean-Jacques Hiblot retry: 2236fb7c3bebSKishon Vijay Abraham I mmc_set_initial_state(mmc); 2237318a7a57SJean-Jacques Hiblot mmc_send_init_stream(mmc); 2238318a7a57SJean-Jacques Hiblot 2239272cc70bSAndy Fleming /* Reset the Card */ 2240272cc70bSAndy Fleming err = mmc_go_idle(mmc); 2241272cc70bSAndy Fleming 2242272cc70bSAndy Fleming if (err) 2243272cc70bSAndy Fleming return err; 2244272cc70bSAndy Fleming 2245bc897b1dSLei Wen /* The internal partition reset to user partition(0) at every CMD0*/ 2246c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->hwpart = 0; 2247bc897b1dSLei Wen 2248272cc70bSAndy Fleming /* Test for SD version 2 */ 2249272cc70bSAndy Fleming err = mmc_send_if_cond(mmc); 2250272cc70bSAndy Fleming 2251272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */ 2252c10b85d6SJean-Jacques Hiblot err = sd_send_op_cond(mmc, uhs_en); 2253c10b85d6SJean-Jacques Hiblot if (err && uhs_en) { 2254c10b85d6SJean-Jacques Hiblot uhs_en = false; 2255c10b85d6SJean-Jacques Hiblot mmc_power_cycle(mmc); 2256c10b85d6SJean-Jacques Hiblot goto retry; 2257c10b85d6SJean-Jacques Hiblot } 2258272cc70bSAndy Fleming 2259272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */ 2260915ffa52SJaehoon Chung if (err == -ETIMEDOUT) { 2261272cc70bSAndy Fleming err = mmc_send_op_cond(mmc); 2262272cc70bSAndy Fleming 2263bd47c135SAndrew Gabbasov if (err) { 226456196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2265272cc70bSAndy Fleming printf("Card did not respond to voltage select!\n"); 226656196826SPaul Burton #endif 2267915ffa52SJaehoon Chung return -EOPNOTSUPP; 2268272cc70bSAndy Fleming } 2269272cc70bSAndy Fleming } 2270272cc70bSAndy Fleming 2271bd47c135SAndrew Gabbasov if (!err) 2272e9550449SChe-Liang Chiou mmc->init_in_progress = 1; 2273e9550449SChe-Liang Chiou 2274e9550449SChe-Liang Chiou return err; 2275e9550449SChe-Liang Chiou } 2276e9550449SChe-Liang Chiou 2277e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc) 2278e9550449SChe-Liang Chiou { 2279e9550449SChe-Liang Chiou int err = 0; 2280e9550449SChe-Liang Chiou 2281bd47c135SAndrew Gabbasov mmc->init_in_progress = 0; 2282e9550449SChe-Liang Chiou if (mmc->op_cond_pending) 2283e9550449SChe-Liang Chiou err = mmc_complete_op_cond(mmc); 2284e9550449SChe-Liang Chiou 2285e9550449SChe-Liang Chiou if (!err) 2286bc897b1dSLei Wen err = mmc_startup(mmc); 2287bc897b1dSLei Wen if (err) 2288bc897b1dSLei Wen mmc->has_init = 0; 2289bc897b1dSLei Wen else 2290bc897b1dSLei Wen mmc->has_init = 1; 2291e9550449SChe-Liang Chiou return err; 2292e9550449SChe-Liang Chiou } 2293e9550449SChe-Liang Chiou 2294e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc) 2295e9550449SChe-Liang Chiou { 2296bd47c135SAndrew Gabbasov int err = 0; 2297ce9eca94SMarek Vasut __maybe_unused unsigned start; 2298c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 229933fb211dSSimon Glass struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev); 2300e9550449SChe-Liang Chiou 230133fb211dSSimon Glass upriv->mmc = mmc; 230233fb211dSSimon Glass #endif 2303e9550449SChe-Liang Chiou if (mmc->has_init) 2304e9550449SChe-Liang Chiou return 0; 2305d803fea5SMateusz Zalega 2306d803fea5SMateusz Zalega start = get_timer(0); 2307d803fea5SMateusz Zalega 2308e9550449SChe-Liang Chiou if (!mmc->init_in_progress) 2309e9550449SChe-Liang Chiou err = mmc_start_init(mmc); 2310e9550449SChe-Liang Chiou 2311bd47c135SAndrew Gabbasov if (!err) 2312e9550449SChe-Liang Chiou err = mmc_complete_init(mmc); 2313919b4858SJagan Teki if (err) 2314919b4858SJagan Teki printf("%s: %d, time %lu\n", __func__, err, get_timer(start)); 2315919b4858SJagan Teki 2316bc897b1dSLei Wen return err; 2317272cc70bSAndy Fleming } 2318272cc70bSAndy Fleming 2319ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val) 2320ab71188cSMarkus Niebel { 2321ab71188cSMarkus Niebel mmc->dsr = val; 2322ab71188cSMarkus Niebel return 0; 2323ab71188cSMarkus Niebel } 2324ab71188cSMarkus Niebel 2325cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */ 2326cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis) 2327272cc70bSAndy Fleming { 2328272cc70bSAndy Fleming return -1; 2329272cc70bSAndy Fleming } 2330272cc70bSAndy Fleming 2331cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */ 2332cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis) 2333cee9ab7cSJeroen Hofstee { 2334cee9ab7cSJeroen Hofstee return -1; 2335cee9ab7cSJeroen Hofstee } 2336272cc70bSAndy Fleming 2337e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit) 2338e9550449SChe-Liang Chiou { 2339e9550449SChe-Liang Chiou mmc->preinit = preinit; 2340e9550449SChe-Liang Chiou } 2341e9550449SChe-Liang Chiou 2342c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD) 23438e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 23448e3332e2SSjoerd Simons { 23458e3332e2SSjoerd Simons return 0; 23468e3332e2SSjoerd Simons } 2347c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC) 23488e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 23498e3332e2SSjoerd Simons { 23504a1db6d8SSimon Glass int ret, i; 23518e3332e2SSjoerd Simons struct uclass *uc; 23524a1db6d8SSimon Glass struct udevice *dev; 23538e3332e2SSjoerd Simons 23548e3332e2SSjoerd Simons ret = uclass_get(UCLASS_MMC, &uc); 23558e3332e2SSjoerd Simons if (ret) 23568e3332e2SSjoerd Simons return ret; 23578e3332e2SSjoerd Simons 23584a1db6d8SSimon Glass /* 23594a1db6d8SSimon Glass * Try to add them in sequence order. Really with driver model we 23604a1db6d8SSimon Glass * should allow holes, but the current MMC list does not allow that. 23614a1db6d8SSimon Glass * So if we request 0, 1, 3 we will get 0, 1, 2. 23624a1db6d8SSimon Glass */ 23634a1db6d8SSimon Glass for (i = 0; ; i++) { 23644a1db6d8SSimon Glass ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev); 23654a1db6d8SSimon Glass if (ret == -ENODEV) 23664a1db6d8SSimon Glass break; 23674a1db6d8SSimon Glass } 23684a1db6d8SSimon Glass uclass_foreach_dev(dev, uc) { 23694a1db6d8SSimon Glass ret = device_probe(dev); 23708e3332e2SSjoerd Simons if (ret) 23714a1db6d8SSimon Glass printf("%s - probe failed: %d\n", dev->name, ret); 23728e3332e2SSjoerd Simons } 23738e3332e2SSjoerd Simons 23748e3332e2SSjoerd Simons return 0; 23758e3332e2SSjoerd Simons } 23768e3332e2SSjoerd Simons #else 23778e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 23788e3332e2SSjoerd Simons { 23798e3332e2SSjoerd Simons if (board_mmc_init(bis) < 0) 23808e3332e2SSjoerd Simons cpu_mmc_init(bis); 23818e3332e2SSjoerd Simons 23828e3332e2SSjoerd Simons return 0; 23838e3332e2SSjoerd Simons } 23848e3332e2SSjoerd Simons #endif 2385e9550449SChe-Liang Chiou 2386272cc70bSAndy Fleming int mmc_initialize(bd_t *bis) 2387272cc70bSAndy Fleming { 23881b26bab1SDaniel Kochmański static int initialized = 0; 23898e3332e2SSjoerd Simons int ret; 23901b26bab1SDaniel Kochmański if (initialized) /* Avoid initializing mmc multiple times */ 23911b26bab1SDaniel Kochmański return 0; 23921b26bab1SDaniel Kochmański initialized = 1; 23931b26bab1SDaniel Kochmański 2394c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK) 2395b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY) 2396c40fdca6SSimon Glass mmc_list_init(); 2397c40fdca6SSimon Glass #endif 2398b5b838f1SMarek Vasut #endif 23998e3332e2SSjoerd Simons ret = mmc_probe(bis); 24008e3332e2SSjoerd Simons if (ret) 24018e3332e2SSjoerd Simons return ret; 2402272cc70bSAndy Fleming 2403bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD 2404272cc70bSAndy Fleming print_mmc_devices(','); 2405bb0dc108SYing Zhang #endif 2406272cc70bSAndy Fleming 2407c40fdca6SSimon Glass mmc_do_preinit(); 2408272cc70bSAndy Fleming return 0; 2409272cc70bSAndy Fleming } 2410cd3d4880STomas Melin 2411cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE 2412cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc) 2413cd3d4880STomas Melin { 2414cd3d4880STomas Melin int err; 2415cd3d4880STomas Melin ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 2416cd3d4880STomas Melin 2417cd3d4880STomas Melin err = mmc_send_ext_csd(mmc, ext_csd); 2418cd3d4880STomas Melin if (err) { 2419cd3d4880STomas Melin puts("Could not get ext_csd register values\n"); 2420cd3d4880STomas Melin return err; 2421cd3d4880STomas Melin } 2422cd3d4880STomas Melin 2423cd3d4880STomas Melin if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) { 2424cd3d4880STomas Melin puts("Background operations not supported on device\n"); 2425cd3d4880STomas Melin return -EMEDIUMTYPE; 2426cd3d4880STomas Melin } 2427cd3d4880STomas Melin 2428cd3d4880STomas Melin if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) { 2429cd3d4880STomas Melin puts("Background operations already enabled\n"); 2430cd3d4880STomas Melin return 0; 2431cd3d4880STomas Melin } 2432cd3d4880STomas Melin 2433cd3d4880STomas Melin err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1); 2434cd3d4880STomas Melin if (err) { 2435cd3d4880STomas Melin puts("Failed to enable manual background operations\n"); 2436cd3d4880STomas Melin return err; 2437cd3d4880STomas Melin } 2438cd3d4880STomas Melin 2439cd3d4880STomas Melin puts("Enabled manual background operations\n"); 2440cd3d4880STomas Melin 2441cd3d4880STomas Melin return 0; 2442cd3d4880STomas Melin } 2443cd3d4880STomas Melin #endif 2444