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) 60750121c3SJeroen Hofstee __weak int board_mmc_getwp(struct mmc *mmc) 61d23d8d7eSNikita Kiryanov { 62d23d8d7eSNikita Kiryanov return -1; 63d23d8d7eSNikita Kiryanov } 64d23d8d7eSNikita Kiryanov 65d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc) 66d23d8d7eSNikita Kiryanov { 67d23d8d7eSNikita Kiryanov int wp; 68d23d8d7eSNikita Kiryanov 69d23d8d7eSNikita Kiryanov wp = board_mmc_getwp(mmc); 70d23d8d7eSNikita Kiryanov 71d4e1da4eSPeter Korsgaard if (wp < 0) { 7293bfd616SPantelis Antoniou if (mmc->cfg->ops->getwp) 7393bfd616SPantelis Antoniou wp = mmc->cfg->ops->getwp(mmc); 74d4e1da4eSPeter Korsgaard else 75d4e1da4eSPeter Korsgaard wp = 0; 76d4e1da4eSPeter Korsgaard } 77d23d8d7eSNikita Kiryanov 78d23d8d7eSNikita Kiryanov return wp; 79d23d8d7eSNikita Kiryanov } 80d23d8d7eSNikita Kiryanov 81cee9ab7cSJeroen Hofstee __weak int board_mmc_getcd(struct mmc *mmc) 82cee9ab7cSJeroen Hofstee { 8311fdade2SStefano Babic return -1; 8411fdade2SStefano Babic } 858ca51e51SSimon Glass #endif 8611fdade2SStefano Babic 878635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE 88c0c76ebaSSimon Glass void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd) 89c0c76ebaSSimon Glass { 90c0c76ebaSSimon Glass printf("CMD_SEND:%d\n", cmd->cmdidx); 91c0c76ebaSSimon Glass printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg); 92c0c76ebaSSimon Glass } 93c0c76ebaSSimon Glass 94c0c76ebaSSimon Glass void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret) 95c0c76ebaSSimon Glass { 965db2fe3aSRaffaele Recalcati int i; 975db2fe3aSRaffaele Recalcati u8 *ptr; 985db2fe3aSRaffaele Recalcati 997863ce58SBin Meng if (ret) { 1007863ce58SBin Meng printf("\t\tRET\t\t\t %d\n", ret); 1017863ce58SBin Meng } else { 1025db2fe3aSRaffaele Recalcati switch (cmd->resp_type) { 1035db2fe3aSRaffaele Recalcati case MMC_RSP_NONE: 1045db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_NONE\n"); 1055db2fe3aSRaffaele Recalcati break; 1065db2fe3aSRaffaele Recalcati case MMC_RSP_R1: 1075db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n", 1085db2fe3aSRaffaele Recalcati cmd->response[0]); 1095db2fe3aSRaffaele Recalcati break; 1105db2fe3aSRaffaele Recalcati case MMC_RSP_R1b: 1115db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n", 1125db2fe3aSRaffaele Recalcati cmd->response[0]); 1135db2fe3aSRaffaele Recalcati break; 1145db2fe3aSRaffaele Recalcati case MMC_RSP_R2: 1155db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R2\t\t 0x%08X \n", 1165db2fe3aSRaffaele Recalcati cmd->response[0]); 1175db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1185db2fe3aSRaffaele Recalcati cmd->response[1]); 1195db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1205db2fe3aSRaffaele Recalcati cmd->response[2]); 1215db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1225db2fe3aSRaffaele Recalcati cmd->response[3]); 1235db2fe3aSRaffaele Recalcati printf("\n"); 1245db2fe3aSRaffaele Recalcati printf("\t\t\t\t\tDUMPING DATA\n"); 1255db2fe3aSRaffaele Recalcati for (i = 0; i < 4; i++) { 1265db2fe3aSRaffaele Recalcati int j; 1275db2fe3aSRaffaele Recalcati printf("\t\t\t\t\t%03d - ", i*4); 128146bec79SDirk Behme ptr = (u8 *)&cmd->response[i]; 1295db2fe3aSRaffaele Recalcati ptr += 3; 1305db2fe3aSRaffaele Recalcati for (j = 0; j < 4; j++) 1315db2fe3aSRaffaele Recalcati printf("%02X ", *ptr--); 1325db2fe3aSRaffaele Recalcati printf("\n"); 1335db2fe3aSRaffaele Recalcati } 1345db2fe3aSRaffaele Recalcati break; 1355db2fe3aSRaffaele Recalcati case MMC_RSP_R3: 1365db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n", 1375db2fe3aSRaffaele Recalcati cmd->response[0]); 1385db2fe3aSRaffaele Recalcati break; 1395db2fe3aSRaffaele Recalcati default: 1405db2fe3aSRaffaele Recalcati printf("\t\tERROR MMC rsp not supported\n"); 1415db2fe3aSRaffaele Recalcati break; 1425db2fe3aSRaffaele Recalcati } 1437863ce58SBin Meng } 144c0c76ebaSSimon Glass } 145c0c76ebaSSimon Glass 146c0c76ebaSSimon Glass void mmc_trace_state(struct mmc *mmc, struct mmc_cmd *cmd) 147c0c76ebaSSimon Glass { 148c0c76ebaSSimon Glass int status; 149c0c76ebaSSimon Glass 150c0c76ebaSSimon Glass status = (cmd->response[0] & MMC_STATUS_CURR_STATE) >> 9; 151c0c76ebaSSimon Glass printf("CURR STATE:%d\n", status); 152c0c76ebaSSimon Glass } 1535db2fe3aSRaffaele Recalcati #endif 154c0c76ebaSSimon Glass 15535f9e196SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG) 15635f9e196SJean-Jacques Hiblot const char *mmc_mode_name(enum bus_mode mode) 15735f9e196SJean-Jacques Hiblot { 15835f9e196SJean-Jacques Hiblot static const char *const names[] = { 15935f9e196SJean-Jacques Hiblot [MMC_LEGACY] = "MMC legacy", 16035f9e196SJean-Jacques Hiblot [SD_LEGACY] = "SD Legacy", 16135f9e196SJean-Jacques Hiblot [MMC_HS] = "MMC High Speed (26MHz)", 16235f9e196SJean-Jacques Hiblot [SD_HS] = "SD High Speed (50MHz)", 16335f9e196SJean-Jacques Hiblot [UHS_SDR12] = "UHS SDR12 (25MHz)", 16435f9e196SJean-Jacques Hiblot [UHS_SDR25] = "UHS SDR25 (50MHz)", 16535f9e196SJean-Jacques Hiblot [UHS_SDR50] = "UHS SDR50 (100MHz)", 16635f9e196SJean-Jacques Hiblot [UHS_SDR104] = "UHS SDR104 (208MHz)", 16735f9e196SJean-Jacques Hiblot [UHS_DDR50] = "UHS DDR50 (50MHz)", 16835f9e196SJean-Jacques Hiblot [MMC_HS_52] = "MMC High Speed (52MHz)", 16935f9e196SJean-Jacques Hiblot [MMC_DDR_52] = "MMC DDR52 (52MHz)", 17035f9e196SJean-Jacques Hiblot [MMC_HS_200] = "HS200 (200MHz)", 17135f9e196SJean-Jacques Hiblot }; 17235f9e196SJean-Jacques Hiblot 17335f9e196SJean-Jacques Hiblot if (mode >= MMC_MODES_END) 17435f9e196SJean-Jacques Hiblot return "Unknown mode"; 17535f9e196SJean-Jacques Hiblot else 17635f9e196SJean-Jacques Hiblot return names[mode]; 17735f9e196SJean-Jacques Hiblot } 17835f9e196SJean-Jacques Hiblot #endif 17935f9e196SJean-Jacques Hiblot 18005038576SJean-Jacques Hiblot static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode) 18105038576SJean-Jacques Hiblot { 18205038576SJean-Jacques Hiblot static const int freqs[] = { 18305038576SJean-Jacques Hiblot [SD_LEGACY] = 25000000, 18405038576SJean-Jacques Hiblot [MMC_HS] = 26000000, 18505038576SJean-Jacques Hiblot [SD_HS] = 50000000, 18605038576SJean-Jacques Hiblot [UHS_SDR12] = 25000000, 18705038576SJean-Jacques Hiblot [UHS_SDR25] = 50000000, 18805038576SJean-Jacques Hiblot [UHS_SDR50] = 100000000, 18905038576SJean-Jacques Hiblot [UHS_SDR104] = 208000000, 19005038576SJean-Jacques Hiblot [UHS_DDR50] = 50000000, 19105038576SJean-Jacques Hiblot [MMC_HS_52] = 52000000, 19205038576SJean-Jacques Hiblot [MMC_DDR_52] = 52000000, 19305038576SJean-Jacques Hiblot [MMC_HS_200] = 200000000, 19405038576SJean-Jacques Hiblot }; 19505038576SJean-Jacques Hiblot 19605038576SJean-Jacques Hiblot if (mode == MMC_LEGACY) 19705038576SJean-Jacques Hiblot return mmc->legacy_speed; 19805038576SJean-Jacques Hiblot else if (mode >= MMC_MODES_END) 19905038576SJean-Jacques Hiblot return 0; 20005038576SJean-Jacques Hiblot else 20105038576SJean-Jacques Hiblot return freqs[mode]; 20205038576SJean-Jacques Hiblot } 20305038576SJean-Jacques Hiblot 20435f9e196SJean-Jacques Hiblot static int mmc_select_mode(struct mmc *mmc, enum bus_mode mode) 20535f9e196SJean-Jacques Hiblot { 20635f9e196SJean-Jacques Hiblot mmc->selected_mode = mode; 20705038576SJean-Jacques Hiblot mmc->tran_speed = mmc_mode2freq(mmc, mode); 2083862b854SJean-Jacques Hiblot mmc->ddr_mode = mmc_is_mode_ddr(mode); 20935f9e196SJean-Jacques Hiblot debug("selecting mode %s (freq : %d MHz)\n", mmc_mode_name(mode), 21035f9e196SJean-Jacques Hiblot mmc->tran_speed / 1000000); 21135f9e196SJean-Jacques Hiblot return 0; 21235f9e196SJean-Jacques Hiblot } 21335f9e196SJean-Jacques Hiblot 214e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 215c0c76ebaSSimon Glass int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) 216c0c76ebaSSimon Glass { 217c0c76ebaSSimon Glass int ret; 218c0c76ebaSSimon Glass 219c0c76ebaSSimon Glass mmmc_trace_before_send(mmc, cmd); 220c0c76ebaSSimon Glass ret = mmc->cfg->ops->send_cmd(mmc, cmd, data); 221c0c76ebaSSimon Glass mmmc_trace_after_send(mmc, cmd, ret); 222c0c76ebaSSimon Glass 2238635ff9eSMarek Vasut return ret; 224272cc70bSAndy Fleming } 2258ca51e51SSimon Glass #endif 226272cc70bSAndy Fleming 227da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout) 2285d4fc8d9SRaffaele Recalcati { 2295d4fc8d9SRaffaele Recalcati struct mmc_cmd cmd; 230d617c426SJan Kloetzke int err, retries = 5; 2315d4fc8d9SRaffaele Recalcati 2325d4fc8d9SRaffaele Recalcati cmd.cmdidx = MMC_CMD_SEND_STATUS; 2335d4fc8d9SRaffaele Recalcati cmd.resp_type = MMC_RSP_R1; 234aaf3d41aSMarek Vasut if (!mmc_host_is_spi(mmc)) 235aaf3d41aSMarek Vasut cmd.cmdarg = mmc->rca << 16; 2365d4fc8d9SRaffaele Recalcati 2371677eef4SAndrew Gabbasov while (1) { 2385d4fc8d9SRaffaele Recalcati err = mmc_send_cmd(mmc, &cmd, NULL); 239d617c426SJan Kloetzke if (!err) { 240d617c426SJan Kloetzke if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) && 241d617c426SJan Kloetzke (cmd.response[0] & MMC_STATUS_CURR_STATE) != 242d617c426SJan Kloetzke MMC_STATE_PRG) 2435d4fc8d9SRaffaele Recalcati break; 244d0c221feSJean-Jacques Hiblot 245d0c221feSJean-Jacques Hiblot if (cmd.response[0] & MMC_STATUS_MASK) { 24656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 247d617c426SJan Kloetzke printf("Status Error: 0x%08X\n", 248d617c426SJan Kloetzke cmd.response[0]); 24956196826SPaul Burton #endif 250915ffa52SJaehoon Chung return -ECOMM; 251d617c426SJan Kloetzke } 252d617c426SJan Kloetzke } else if (--retries < 0) 253d617c426SJan Kloetzke return err; 2545d4fc8d9SRaffaele Recalcati 2551677eef4SAndrew Gabbasov if (timeout-- <= 0) 2561677eef4SAndrew Gabbasov break; 2575d4fc8d9SRaffaele Recalcati 2581677eef4SAndrew Gabbasov udelay(1000); 2591677eef4SAndrew Gabbasov } 2605d4fc8d9SRaffaele Recalcati 261c0c76ebaSSimon Glass mmc_trace_state(mmc, &cmd); 2625b0c942fSJongman Heo if (timeout <= 0) { 26356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2645d4fc8d9SRaffaele Recalcati printf("Timeout waiting card ready\n"); 26556196826SPaul Burton #endif 266915ffa52SJaehoon Chung return -ETIMEDOUT; 2675d4fc8d9SRaffaele Recalcati } 2685d4fc8d9SRaffaele Recalcati 2695d4fc8d9SRaffaele Recalcati return 0; 2705d4fc8d9SRaffaele Recalcati } 2715d4fc8d9SRaffaele Recalcati 272da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len) 273272cc70bSAndy Fleming { 274272cc70bSAndy Fleming struct mmc_cmd cmd; 275272cc70bSAndy Fleming 276786e8f81SAndrew Gabbasov if (mmc->ddr_mode) 277d22e3d46SJaehoon Chung return 0; 278d22e3d46SJaehoon Chung 279272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SET_BLOCKLEN; 280272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 281272cc70bSAndy Fleming cmd.cmdarg = len; 282272cc70bSAndy Fleming 283272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, NULL); 284272cc70bSAndy Fleming } 285272cc70bSAndy Fleming 286ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start, 287fdbb873eSKim Phillips lbaint_t blkcnt) 288272cc70bSAndy Fleming { 289272cc70bSAndy Fleming struct mmc_cmd cmd; 290272cc70bSAndy Fleming struct mmc_data data; 291272cc70bSAndy Fleming 2924a1a06bcSAlagu Sankar if (blkcnt > 1) 2934a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; 2944a1a06bcSAlagu Sankar else 295272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; 296272cc70bSAndy Fleming 297272cc70bSAndy Fleming if (mmc->high_capacity) 2984a1a06bcSAlagu Sankar cmd.cmdarg = start; 299272cc70bSAndy Fleming else 3004a1a06bcSAlagu Sankar cmd.cmdarg = start * mmc->read_bl_len; 301272cc70bSAndy Fleming 302272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 303272cc70bSAndy Fleming 304272cc70bSAndy Fleming data.dest = dst; 3054a1a06bcSAlagu Sankar data.blocks = blkcnt; 306272cc70bSAndy Fleming data.blocksize = mmc->read_bl_len; 307272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 308272cc70bSAndy Fleming 3094a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, &data)) 3104a1a06bcSAlagu Sankar return 0; 3114a1a06bcSAlagu Sankar 3124a1a06bcSAlagu Sankar if (blkcnt > 1) { 3134a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; 3144a1a06bcSAlagu Sankar cmd.cmdarg = 0; 3154a1a06bcSAlagu Sankar cmd.resp_type = MMC_RSP_R1b; 3164a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, NULL)) { 31756196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 3184a1a06bcSAlagu Sankar printf("mmc fail to send stop cmd\n"); 31956196826SPaul Burton #endif 3204a1a06bcSAlagu Sankar return 0; 3214a1a06bcSAlagu Sankar } 322272cc70bSAndy Fleming } 323272cc70bSAndy Fleming 3244a1a06bcSAlagu Sankar return blkcnt; 325272cc70bSAndy Fleming } 326272cc70bSAndy Fleming 327c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK) 3287dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst) 32933fb211dSSimon Glass #else 3307dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, 3317dba0b93SSimon Glass void *dst) 33233fb211dSSimon Glass #endif 333272cc70bSAndy Fleming { 334c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK) 33533fb211dSSimon Glass struct blk_desc *block_dev = dev_get_uclass_platdata(dev); 33633fb211dSSimon Glass #endif 337bcce53d0SSimon Glass int dev_num = block_dev->devnum; 338873cc1d7SStephen Warren int err; 3394a1a06bcSAlagu Sankar lbaint_t cur, blocks_todo = blkcnt; 340272cc70bSAndy Fleming 3414a1a06bcSAlagu Sankar if (blkcnt == 0) 3424a1a06bcSAlagu Sankar return 0; 3434a1a06bcSAlagu Sankar 3444a1a06bcSAlagu Sankar struct mmc *mmc = find_mmc_device(dev_num); 345272cc70bSAndy Fleming if (!mmc) 346272cc70bSAndy Fleming return 0; 347272cc70bSAndy Fleming 348b5b838f1SMarek Vasut if (CONFIG_IS_ENABLED(MMC_TINY)) 349b5b838f1SMarek Vasut err = mmc_switch_part(mmc, block_dev->hwpart); 350b5b838f1SMarek Vasut else 35169f45cd5SSimon Glass err = blk_dselect_hwpart(block_dev, block_dev->hwpart); 352b5b838f1SMarek Vasut 353873cc1d7SStephen Warren if (err < 0) 354873cc1d7SStephen Warren return 0; 355873cc1d7SStephen Warren 356c40fdca6SSimon Glass if ((start + blkcnt) > block_dev->lba) { 35756196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 358ff8fef56SSascha Silbe printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", 359c40fdca6SSimon Glass start + blkcnt, block_dev->lba); 36056196826SPaul Burton #endif 361d2bf29e3SLei Wen return 0; 362d2bf29e3SLei Wen } 363272cc70bSAndy Fleming 36411692991SSimon Glass if (mmc_set_blocklen(mmc, mmc->read_bl_len)) { 36511692991SSimon Glass debug("%s: Failed to set blocklen\n", __func__); 366272cc70bSAndy Fleming return 0; 36711692991SSimon Glass } 368272cc70bSAndy Fleming 3694a1a06bcSAlagu Sankar do { 37093bfd616SPantelis Antoniou cur = (blocks_todo > mmc->cfg->b_max) ? 37193bfd616SPantelis Antoniou mmc->cfg->b_max : blocks_todo; 37211692991SSimon Glass if (mmc_read_blocks(mmc, dst, start, cur) != cur) { 37311692991SSimon Glass debug("%s: Failed to read blocks\n", __func__); 3744a1a06bcSAlagu Sankar return 0; 37511692991SSimon Glass } 3764a1a06bcSAlagu Sankar blocks_todo -= cur; 3774a1a06bcSAlagu Sankar start += cur; 3784a1a06bcSAlagu Sankar dst += cur * mmc->read_bl_len; 3794a1a06bcSAlagu Sankar } while (blocks_todo > 0); 380272cc70bSAndy Fleming 381272cc70bSAndy Fleming return blkcnt; 382272cc70bSAndy Fleming } 383272cc70bSAndy Fleming 384fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc) 385272cc70bSAndy Fleming { 386272cc70bSAndy Fleming struct mmc_cmd cmd; 387272cc70bSAndy Fleming int err; 388272cc70bSAndy Fleming 389272cc70bSAndy Fleming udelay(1000); 390272cc70bSAndy Fleming 391272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_GO_IDLE_STATE; 392272cc70bSAndy Fleming cmd.cmdarg = 0; 393272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_NONE; 394272cc70bSAndy Fleming 395272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 396272cc70bSAndy Fleming 397272cc70bSAndy Fleming if (err) 398272cc70bSAndy Fleming return err; 399272cc70bSAndy Fleming 400272cc70bSAndy Fleming udelay(2000); 401272cc70bSAndy Fleming 402272cc70bSAndy Fleming return 0; 403272cc70bSAndy Fleming } 404272cc70bSAndy Fleming 405fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc) 406272cc70bSAndy Fleming { 407272cc70bSAndy Fleming int timeout = 1000; 408272cc70bSAndy Fleming int err; 409272cc70bSAndy Fleming struct mmc_cmd cmd; 410272cc70bSAndy Fleming 4111677eef4SAndrew Gabbasov while (1) { 412272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 413272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 414272cc70bSAndy Fleming cmd.cmdarg = 0; 415272cc70bSAndy Fleming 416272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 417272cc70bSAndy Fleming 418272cc70bSAndy Fleming if (err) 419272cc70bSAndy Fleming return err; 420272cc70bSAndy Fleming 421272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_OP_COND; 422272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R3; 423250de12bSStefano Babic 424250de12bSStefano Babic /* 425250de12bSStefano Babic * Most cards do not answer if some reserved bits 426250de12bSStefano Babic * in the ocr are set. However, Some controller 427250de12bSStefano Babic * can set bit 7 (reserved for low voltages), but 428250de12bSStefano Babic * how to manage low voltages SD card is not yet 429250de12bSStefano Babic * specified. 430250de12bSStefano Babic */ 431d52ebf10SThomas Chou cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 : 43293bfd616SPantelis Antoniou (mmc->cfg->voltages & 0xff8000); 433272cc70bSAndy Fleming 434272cc70bSAndy Fleming if (mmc->version == SD_VERSION_2) 435272cc70bSAndy Fleming cmd.cmdarg |= OCR_HCS; 436272cc70bSAndy Fleming 437272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 438272cc70bSAndy Fleming 439272cc70bSAndy Fleming if (err) 440272cc70bSAndy Fleming return err; 441272cc70bSAndy Fleming 4421677eef4SAndrew Gabbasov if (cmd.response[0] & OCR_BUSY) 4431677eef4SAndrew Gabbasov break; 444272cc70bSAndy Fleming 4451677eef4SAndrew Gabbasov if (timeout-- <= 0) 446915ffa52SJaehoon Chung return -EOPNOTSUPP; 447272cc70bSAndy Fleming 4481677eef4SAndrew Gabbasov udelay(1000); 4491677eef4SAndrew Gabbasov } 4501677eef4SAndrew Gabbasov 451272cc70bSAndy Fleming if (mmc->version != SD_VERSION_2) 452272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 453272cc70bSAndy Fleming 454d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 455d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 456d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 457d52ebf10SThomas Chou cmd.cmdarg = 0; 458d52ebf10SThomas Chou 459d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 460d52ebf10SThomas Chou 461d52ebf10SThomas Chou if (err) 462d52ebf10SThomas Chou return err; 463d52ebf10SThomas Chou } 464d52ebf10SThomas Chou 465998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 466272cc70bSAndy Fleming 467272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 468272cc70bSAndy Fleming mmc->rca = 0; 469272cc70bSAndy Fleming 470272cc70bSAndy Fleming return 0; 471272cc70bSAndy Fleming } 472272cc70bSAndy Fleming 4735289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg) 474272cc70bSAndy Fleming { 4755289b535SAndrew Gabbasov struct mmc_cmd cmd; 476272cc70bSAndy Fleming int err; 477272cc70bSAndy Fleming 4785289b535SAndrew Gabbasov cmd.cmdidx = MMC_CMD_SEND_OP_COND; 4795289b535SAndrew Gabbasov cmd.resp_type = MMC_RSP_R3; 4805289b535SAndrew Gabbasov cmd.cmdarg = 0; 4815a20397bSRob Herring if (use_arg && !mmc_host_is_spi(mmc)) 4825a20397bSRob Herring cmd.cmdarg = OCR_HCS | 48393bfd616SPantelis Antoniou (mmc->cfg->voltages & 484a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_VOLTAGE_MASK)) | 485a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_ACCESS_MODE); 486e9550449SChe-Liang Chiou 4875289b535SAndrew Gabbasov err = mmc_send_cmd(mmc, &cmd, NULL); 488e9550449SChe-Liang Chiou if (err) 489e9550449SChe-Liang Chiou return err; 4905289b535SAndrew Gabbasov mmc->ocr = cmd.response[0]; 491e9550449SChe-Liang Chiou return 0; 492e9550449SChe-Liang Chiou } 493e9550449SChe-Liang Chiou 494750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc) 495e9550449SChe-Liang Chiou { 496e9550449SChe-Liang Chiou int err, i; 497e9550449SChe-Liang Chiou 498272cc70bSAndy Fleming /* Some cards seem to need this */ 499272cc70bSAndy Fleming mmc_go_idle(mmc); 500272cc70bSAndy Fleming 50131cacbabSRaffaele Recalcati /* Asking to the card its capabilities */ 502e9550449SChe-Liang Chiou for (i = 0; i < 2; i++) { 5035289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, i != 0); 50431cacbabSRaffaele Recalcati if (err) 50531cacbabSRaffaele Recalcati return err; 50631cacbabSRaffaele Recalcati 507e9550449SChe-Liang Chiou /* exit if not busy (flag seems to be inverted) */ 508a626c8d4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 509bd47c135SAndrew Gabbasov break; 510e9550449SChe-Liang Chiou } 511bd47c135SAndrew Gabbasov mmc->op_cond_pending = 1; 512bd47c135SAndrew Gabbasov return 0; 513e9550449SChe-Liang Chiou } 51431cacbabSRaffaele Recalcati 515750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc) 516e9550449SChe-Liang Chiou { 517e9550449SChe-Liang Chiou struct mmc_cmd cmd; 518e9550449SChe-Liang Chiou int timeout = 1000; 519e9550449SChe-Liang Chiou uint start; 520e9550449SChe-Liang Chiou int err; 521e9550449SChe-Liang Chiou 522e9550449SChe-Liang Chiou mmc->op_cond_pending = 0; 523cc17c01fSAndrew Gabbasov if (!(mmc->ocr & OCR_BUSY)) { 524d188b113SYangbo Lu /* Some cards seem to need this */ 525d188b113SYangbo Lu mmc_go_idle(mmc); 526d188b113SYangbo Lu 527e9550449SChe-Liang Chiou start = get_timer(0); 5281677eef4SAndrew Gabbasov while (1) { 5295289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, 1); 530272cc70bSAndy Fleming if (err) 531272cc70bSAndy Fleming return err; 5321677eef4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 5331677eef4SAndrew Gabbasov break; 534e9550449SChe-Liang Chiou if (get_timer(start) > timeout) 535915ffa52SJaehoon Chung return -EOPNOTSUPP; 536e9550449SChe-Liang Chiou udelay(100); 5371677eef4SAndrew Gabbasov } 538cc17c01fSAndrew Gabbasov } 539272cc70bSAndy Fleming 540d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 541d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 542d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 543d52ebf10SThomas Chou cmd.cmdarg = 0; 544d52ebf10SThomas Chou 545d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 546d52ebf10SThomas Chou 547d52ebf10SThomas Chou if (err) 548d52ebf10SThomas Chou return err; 549a626c8d4SAndrew Gabbasov 550a626c8d4SAndrew Gabbasov mmc->ocr = cmd.response[0]; 551d52ebf10SThomas Chou } 552d52ebf10SThomas Chou 553272cc70bSAndy Fleming mmc->version = MMC_VERSION_UNKNOWN; 554272cc70bSAndy Fleming 555272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 556def816a2SStephen Warren mmc->rca = 1; 557272cc70bSAndy Fleming 558272cc70bSAndy Fleming return 0; 559272cc70bSAndy Fleming } 560272cc70bSAndy Fleming 561272cc70bSAndy Fleming 562fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) 563272cc70bSAndy Fleming { 564272cc70bSAndy Fleming struct mmc_cmd cmd; 565272cc70bSAndy Fleming struct mmc_data data; 566272cc70bSAndy Fleming int err; 567272cc70bSAndy Fleming 568272cc70bSAndy Fleming /* Get the Card Status Register */ 569272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_EXT_CSD; 570272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 571272cc70bSAndy Fleming cmd.cmdarg = 0; 572272cc70bSAndy Fleming 573cdfd1ac6SYoshihiro Shimoda data.dest = (char *)ext_csd; 574272cc70bSAndy Fleming data.blocks = 1; 5758bfa195eSSimon Glass data.blocksize = MMC_MAX_BLOCK_LEN; 576272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 577272cc70bSAndy Fleming 578272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 579272cc70bSAndy Fleming 580272cc70bSAndy Fleming return err; 581272cc70bSAndy Fleming } 582272cc70bSAndy Fleming 583c40704f4SSimon Glass int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) 584272cc70bSAndy Fleming { 585272cc70bSAndy Fleming struct mmc_cmd cmd; 5865d4fc8d9SRaffaele Recalcati int timeout = 1000; 587a9003dc6SMaxime Ripard int retries = 3; 5885d4fc8d9SRaffaele Recalcati int ret; 589272cc70bSAndy Fleming 590272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SWITCH; 591272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 592272cc70bSAndy Fleming cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 593272cc70bSAndy Fleming (index << 16) | 594272cc70bSAndy Fleming (value << 8); 595272cc70bSAndy Fleming 596a9003dc6SMaxime Ripard while (retries > 0) { 5975d4fc8d9SRaffaele Recalcati ret = mmc_send_cmd(mmc, &cmd, NULL); 5985d4fc8d9SRaffaele Recalcati 5995d4fc8d9SRaffaele Recalcati /* Waiting for the ready status */ 600a9003dc6SMaxime Ripard if (!ret) { 60193ad0d18SJan Kloetzke ret = mmc_send_status(mmc, timeout); 602a9003dc6SMaxime Ripard return ret; 603a9003dc6SMaxime Ripard } 604a9003dc6SMaxime Ripard 605a9003dc6SMaxime Ripard retries--; 606a9003dc6SMaxime Ripard } 6075d4fc8d9SRaffaele Recalcati 6085d4fc8d9SRaffaele Recalcati return ret; 6095d4fc8d9SRaffaele Recalcati 610272cc70bSAndy Fleming } 611272cc70bSAndy Fleming 6123862b854SJean-Jacques Hiblot static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode) 613272cc70bSAndy Fleming { 614272cc70bSAndy Fleming int err; 6153862b854SJean-Jacques Hiblot int speed_bits; 6163862b854SJean-Jacques Hiblot 6173862b854SJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 6183862b854SJean-Jacques Hiblot 6193862b854SJean-Jacques Hiblot switch (mode) { 6203862b854SJean-Jacques Hiblot case MMC_HS: 6213862b854SJean-Jacques Hiblot case MMC_HS_52: 6223862b854SJean-Jacques Hiblot case MMC_DDR_52: 6233862b854SJean-Jacques Hiblot speed_bits = EXT_CSD_TIMING_HS; 6243862b854SJean-Jacques Hiblot case MMC_LEGACY: 6253862b854SJean-Jacques Hiblot speed_bits = EXT_CSD_TIMING_LEGACY; 6263862b854SJean-Jacques Hiblot break; 6273862b854SJean-Jacques Hiblot default: 6283862b854SJean-Jacques Hiblot return -EINVAL; 6293862b854SJean-Jacques Hiblot } 6303862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 6313862b854SJean-Jacques Hiblot speed_bits); 6323862b854SJean-Jacques Hiblot if (err) 6333862b854SJean-Jacques Hiblot return err; 6343862b854SJean-Jacques Hiblot 6353862b854SJean-Jacques Hiblot if ((mode == MMC_HS) || (mode == MMC_HS_52)) { 6363862b854SJean-Jacques Hiblot /* Now check to see that it worked */ 6373862b854SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, test_csd); 6383862b854SJean-Jacques Hiblot if (err) 6393862b854SJean-Jacques Hiblot return err; 6403862b854SJean-Jacques Hiblot 6413862b854SJean-Jacques Hiblot /* No high-speed support */ 6423862b854SJean-Jacques Hiblot if (!test_csd[EXT_CSD_HS_TIMING]) 6433862b854SJean-Jacques Hiblot return -ENOTSUPP; 6443862b854SJean-Jacques Hiblot } 6453862b854SJean-Jacques Hiblot 6463862b854SJean-Jacques Hiblot return 0; 6473862b854SJean-Jacques Hiblot } 6483862b854SJean-Jacques Hiblot 6493862b854SJean-Jacques Hiblot static int mmc_get_capabilities(struct mmc *mmc) 6503862b854SJean-Jacques Hiblot { 6513862b854SJean-Jacques Hiblot u8 *ext_csd = mmc->ext_csd; 6523862b854SJean-Jacques Hiblot char cardtype; 653272cc70bSAndy Fleming 654d0c221feSJean-Jacques Hiblot mmc->card_caps = MMC_MODE_1BIT; 655272cc70bSAndy Fleming 656d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 657d52ebf10SThomas Chou return 0; 658d52ebf10SThomas Chou 659272cc70bSAndy Fleming /* Only version 4 supports high-speed */ 660272cc70bSAndy Fleming if (mmc->version < MMC_VERSION_4) 661272cc70bSAndy Fleming return 0; 662272cc70bSAndy Fleming 6633862b854SJean-Jacques Hiblot if (!ext_csd) { 6643862b854SJean-Jacques Hiblot printf("No ext_csd found!\n"); /* this should enver happen */ 6653862b854SJean-Jacques Hiblot return -ENOTSUPP; 6663862b854SJean-Jacques Hiblot } 6673862b854SJean-Jacques Hiblot 668fc5b32fbSAndrew Gabbasov mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; 669fc5b32fbSAndrew Gabbasov 6700560db18SLei Wen cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf; 671272cc70bSAndy Fleming 672272cc70bSAndy Fleming /* High Speed is set, there are two types: 52MHz and 26MHz */ 673d22e3d46SJaehoon Chung if (cardtype & EXT_CSD_CARD_TYPE_52) { 6743862b854SJean-Jacques Hiblot if (cardtype & EXT_CSD_CARD_TYPE_DDR_52) 675d22e3d46SJaehoon Chung mmc->card_caps |= MMC_MODE_DDR_52MHz; 6763862b854SJean-Jacques Hiblot mmc->card_caps |= MMC_MODE_HS_52MHz; 677d22e3d46SJaehoon Chung } 6783862b854SJean-Jacques Hiblot if (cardtype & EXT_CSD_CARD_TYPE_26) 6793862b854SJean-Jacques Hiblot mmc->card_caps |= MMC_MODE_HS; 680272cc70bSAndy Fleming 681272cc70bSAndy Fleming return 0; 682272cc70bSAndy Fleming } 683272cc70bSAndy Fleming 684f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num) 685f866a46dSStephen Warren { 686f866a46dSStephen Warren switch (part_num) { 687f866a46dSStephen Warren case 0: 688f866a46dSStephen Warren mmc->capacity = mmc->capacity_user; 689f866a46dSStephen Warren break; 690f866a46dSStephen Warren case 1: 691f866a46dSStephen Warren case 2: 692f866a46dSStephen Warren mmc->capacity = mmc->capacity_boot; 693f866a46dSStephen Warren break; 694f866a46dSStephen Warren case 3: 695f866a46dSStephen Warren mmc->capacity = mmc->capacity_rpmb; 696f866a46dSStephen Warren break; 697f866a46dSStephen Warren case 4: 698f866a46dSStephen Warren case 5: 699f866a46dSStephen Warren case 6: 700f866a46dSStephen Warren case 7: 701f866a46dSStephen Warren mmc->capacity = mmc->capacity_gp[part_num - 4]; 702f866a46dSStephen Warren break; 703f866a46dSStephen Warren default: 704f866a46dSStephen Warren return -1; 705f866a46dSStephen Warren } 706f866a46dSStephen Warren 707c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len); 708f866a46dSStephen Warren 709f866a46dSStephen Warren return 0; 710f866a46dSStephen Warren } 711f866a46dSStephen Warren 7127dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num) 713bc897b1dSLei Wen { 714f866a46dSStephen Warren int ret; 715bc897b1dSLei Wen 716f866a46dSStephen Warren ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 717bc897b1dSLei Wen (mmc->part_config & ~PART_ACCESS_MASK) 718bc897b1dSLei Wen | (part_num & PART_ACCESS_MASK)); 719f866a46dSStephen Warren 7206dc93e70SPeter Bigot /* 7216dc93e70SPeter Bigot * Set the capacity if the switch succeeded or was intended 7226dc93e70SPeter Bigot * to return to representing the raw device. 7236dc93e70SPeter Bigot */ 724873cc1d7SStephen Warren if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) { 7256dc93e70SPeter Bigot ret = mmc_set_capacity(mmc, part_num); 726fdbb139fSSimon Glass mmc_get_blk_desc(mmc)->hwpart = part_num; 727873cc1d7SStephen Warren } 7286dc93e70SPeter Bigot 7296dc93e70SPeter Bigot return ret; 730bc897b1dSLei Wen } 731bc897b1dSLei Wen 732ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc, 733ac9da0e0SDiego Santa Cruz const struct mmc_hwpart_conf *conf, 734ac9da0e0SDiego Santa Cruz enum mmc_hwpart_conf_mode mode) 735ac9da0e0SDiego Santa Cruz { 736ac9da0e0SDiego Santa Cruz u8 part_attrs = 0; 737ac9da0e0SDiego Santa Cruz u32 enh_size_mult; 738ac9da0e0SDiego Santa Cruz u32 enh_start_addr; 739ac9da0e0SDiego Santa Cruz u32 gp_size_mult[4]; 740ac9da0e0SDiego Santa Cruz u32 max_enh_size_mult; 741ac9da0e0SDiego Santa Cruz u32 tot_enh_size_mult = 0; 7428dda5b0eSDiego Santa Cruz u8 wr_rel_set; 743ac9da0e0SDiego Santa Cruz int i, pidx, err; 744ac9da0e0SDiego Santa Cruz ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 745ac9da0e0SDiego Santa Cruz 746ac9da0e0SDiego Santa Cruz if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE) 747ac9da0e0SDiego Santa Cruz return -EINVAL; 748ac9da0e0SDiego Santa Cruz 749ac9da0e0SDiego Santa Cruz if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) { 750ac9da0e0SDiego Santa Cruz printf("eMMC >= 4.4 required for enhanced user data area\n"); 751ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 752ac9da0e0SDiego Santa Cruz } 753ac9da0e0SDiego Santa Cruz 754ac9da0e0SDiego Santa Cruz if (!(mmc->part_support & PART_SUPPORT)) { 755ac9da0e0SDiego Santa Cruz printf("Card does not support partitioning\n"); 756ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 757ac9da0e0SDiego Santa Cruz } 758ac9da0e0SDiego Santa Cruz 759ac9da0e0SDiego Santa Cruz if (!mmc->hc_wp_grp_size) { 760ac9da0e0SDiego Santa Cruz printf("Card does not define HC WP group size\n"); 761ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 762ac9da0e0SDiego Santa Cruz } 763ac9da0e0SDiego Santa Cruz 764ac9da0e0SDiego Santa Cruz /* check partition alignment and total enhanced size */ 765ac9da0e0SDiego Santa Cruz if (conf->user.enh_size) { 766ac9da0e0SDiego Santa Cruz if (conf->user.enh_size % mmc->hc_wp_grp_size || 767ac9da0e0SDiego Santa Cruz conf->user.enh_start % mmc->hc_wp_grp_size) { 768ac9da0e0SDiego Santa Cruz printf("User data enhanced area not HC WP group " 769ac9da0e0SDiego Santa Cruz "size aligned\n"); 770ac9da0e0SDiego Santa Cruz return -EINVAL; 771ac9da0e0SDiego Santa Cruz } 772ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_USR; 773ac9da0e0SDiego Santa Cruz enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size; 774ac9da0e0SDiego Santa Cruz if (mmc->high_capacity) { 775ac9da0e0SDiego Santa Cruz enh_start_addr = conf->user.enh_start; 776ac9da0e0SDiego Santa Cruz } else { 777ac9da0e0SDiego Santa Cruz enh_start_addr = (conf->user.enh_start << 9); 778ac9da0e0SDiego Santa Cruz } 779ac9da0e0SDiego Santa Cruz } else { 780ac9da0e0SDiego Santa Cruz enh_size_mult = 0; 781ac9da0e0SDiego Santa Cruz enh_start_addr = 0; 782ac9da0e0SDiego Santa Cruz } 783ac9da0e0SDiego Santa Cruz tot_enh_size_mult += enh_size_mult; 784ac9da0e0SDiego Santa Cruz 785ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 786ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) { 787ac9da0e0SDiego Santa Cruz printf("GP%i partition not HC WP group size " 788ac9da0e0SDiego Santa Cruz "aligned\n", pidx+1); 789ac9da0e0SDiego Santa Cruz return -EINVAL; 790ac9da0e0SDiego Santa Cruz } 791ac9da0e0SDiego Santa Cruz gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size; 792ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) { 793ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_GP(pidx); 794ac9da0e0SDiego Santa Cruz tot_enh_size_mult += gp_size_mult[pidx]; 795ac9da0e0SDiego Santa Cruz } 796ac9da0e0SDiego Santa Cruz } 797ac9da0e0SDiego Santa Cruz 798ac9da0e0SDiego Santa Cruz if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) { 799ac9da0e0SDiego Santa Cruz printf("Card does not support enhanced attribute\n"); 800ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 801ac9da0e0SDiego Santa Cruz } 802ac9da0e0SDiego Santa Cruz 803ac9da0e0SDiego Santa Cruz err = mmc_send_ext_csd(mmc, ext_csd); 804ac9da0e0SDiego Santa Cruz if (err) 805ac9da0e0SDiego Santa Cruz return err; 806ac9da0e0SDiego Santa Cruz 807ac9da0e0SDiego Santa Cruz max_enh_size_mult = 808ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) + 809ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) + 810ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]; 811ac9da0e0SDiego Santa Cruz if (tot_enh_size_mult > max_enh_size_mult) { 812ac9da0e0SDiego Santa Cruz printf("Total enhanced size exceeds maximum (%u > %u)\n", 813ac9da0e0SDiego Santa Cruz tot_enh_size_mult, max_enh_size_mult); 814ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 815ac9da0e0SDiego Santa Cruz } 816ac9da0e0SDiego Santa Cruz 8178dda5b0eSDiego Santa Cruz /* The default value of EXT_CSD_WR_REL_SET is device 8188dda5b0eSDiego Santa Cruz * dependent, the values can only be changed if the 8198dda5b0eSDiego Santa Cruz * EXT_CSD_HS_CTRL_REL bit is set. The values can be 8208dda5b0eSDiego Santa Cruz * changed only once and before partitioning is completed. */ 8218dda5b0eSDiego Santa Cruz wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 8228dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_change) { 8238dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_set) 8248dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_USR; 8258dda5b0eSDiego Santa Cruz else 8268dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR; 8278dda5b0eSDiego Santa Cruz } 8288dda5b0eSDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 8298dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_change) { 8308dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_set) 8318dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx); 8328dda5b0eSDiego Santa Cruz else 8338dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx); 8348dda5b0eSDiego Santa Cruz } 8358dda5b0eSDiego Santa Cruz } 8368dda5b0eSDiego Santa Cruz 8378dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] && 8388dda5b0eSDiego Santa Cruz !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) { 8398dda5b0eSDiego Santa Cruz puts("Card does not support host controlled partition write " 8408dda5b0eSDiego Santa Cruz "reliability settings\n"); 8418dda5b0eSDiego Santa Cruz return -EMEDIUMTYPE; 8428dda5b0eSDiego Santa Cruz } 8438dda5b0eSDiego Santa Cruz 844ac9da0e0SDiego Santa Cruz if (ext_csd[EXT_CSD_PARTITION_SETTING] & 845ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED) { 846ac9da0e0SDiego Santa Cruz printf("Card already partitioned\n"); 847ac9da0e0SDiego Santa Cruz return -EPERM; 848ac9da0e0SDiego Santa Cruz } 849ac9da0e0SDiego Santa Cruz 850ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_CHECK) 851ac9da0e0SDiego Santa Cruz return 0; 852ac9da0e0SDiego Santa Cruz 853ac9da0e0SDiego Santa Cruz /* Partitioning requires high-capacity size definitions */ 854ac9da0e0SDiego Santa Cruz if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) { 855ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 856ac9da0e0SDiego Santa Cruz EXT_CSD_ERASE_GROUP_DEF, 1); 857ac9da0e0SDiego Santa Cruz 858ac9da0e0SDiego Santa Cruz if (err) 859ac9da0e0SDiego Santa Cruz return err; 860ac9da0e0SDiego Santa Cruz 861ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 862ac9da0e0SDiego Santa Cruz 863ac9da0e0SDiego Santa Cruz /* update erase group size to be high-capacity */ 864ac9da0e0SDiego Santa Cruz mmc->erase_grp_size = 865ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 866ac9da0e0SDiego Santa Cruz 867ac9da0e0SDiego Santa Cruz } 868ac9da0e0SDiego Santa Cruz 869ac9da0e0SDiego Santa Cruz /* all OK, write the configuration */ 870ac9da0e0SDiego Santa Cruz for (i = 0; i < 4; i++) { 871ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 872ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_START_ADDR+i, 873ac9da0e0SDiego Santa Cruz (enh_start_addr >> (i*8)) & 0xFF); 874ac9da0e0SDiego Santa Cruz if (err) 875ac9da0e0SDiego Santa Cruz return err; 876ac9da0e0SDiego Santa Cruz } 877ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 878ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 879ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_SIZE_MULT+i, 880ac9da0e0SDiego Santa Cruz (enh_size_mult >> (i*8)) & 0xFF); 881ac9da0e0SDiego Santa Cruz if (err) 882ac9da0e0SDiego Santa Cruz return err; 883ac9da0e0SDiego Santa Cruz } 884ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 885ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 886ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 887ac9da0e0SDiego Santa Cruz EXT_CSD_GP_SIZE_MULT+pidx*3+i, 888ac9da0e0SDiego Santa Cruz (gp_size_mult[pidx] >> (i*8)) & 0xFF); 889ac9da0e0SDiego Santa Cruz if (err) 890ac9da0e0SDiego Santa Cruz return err; 891ac9da0e0SDiego Santa Cruz } 892ac9da0e0SDiego Santa Cruz } 893ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 894ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs); 895ac9da0e0SDiego Santa Cruz if (err) 896ac9da0e0SDiego Santa Cruz return err; 897ac9da0e0SDiego Santa Cruz 898ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_SET) 899ac9da0e0SDiego Santa Cruz return 0; 900ac9da0e0SDiego Santa Cruz 9018dda5b0eSDiego Santa Cruz /* The WR_REL_SET is a write-once register but shall be 9028dda5b0eSDiego Santa Cruz * written before setting PART_SETTING_COMPLETED. As it is 9038dda5b0eSDiego Santa Cruz * write-once we can only write it when completing the 9048dda5b0eSDiego Santa Cruz * partitioning. */ 9058dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) { 9068dda5b0eSDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 9078dda5b0eSDiego Santa Cruz EXT_CSD_WR_REL_SET, wr_rel_set); 9088dda5b0eSDiego Santa Cruz if (err) 9098dda5b0eSDiego Santa Cruz return err; 9108dda5b0eSDiego Santa Cruz } 9118dda5b0eSDiego Santa Cruz 912ac9da0e0SDiego Santa Cruz /* Setting PART_SETTING_COMPLETED confirms the partition 913ac9da0e0SDiego Santa Cruz * configuration but it only becomes effective after power 914ac9da0e0SDiego Santa Cruz * cycle, so we do not adjust the partition related settings 915ac9da0e0SDiego Santa Cruz * in the mmc struct. */ 916ac9da0e0SDiego Santa Cruz 917ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 918ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING, 919ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 920ac9da0e0SDiego Santa Cruz if (err) 921ac9da0e0SDiego Santa Cruz return err; 922ac9da0e0SDiego Santa Cruz 923ac9da0e0SDiego Santa Cruz return 0; 924ac9da0e0SDiego Santa Cruz } 925ac9da0e0SDiego Santa Cruz 926e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 92748972d90SThierry Reding int mmc_getcd(struct mmc *mmc) 92848972d90SThierry Reding { 92948972d90SThierry Reding int cd; 93048972d90SThierry Reding 93148972d90SThierry Reding cd = board_mmc_getcd(mmc); 93248972d90SThierry Reding 933d4e1da4eSPeter Korsgaard if (cd < 0) { 93493bfd616SPantelis Antoniou if (mmc->cfg->ops->getcd) 93593bfd616SPantelis Antoniou cd = mmc->cfg->ops->getcd(mmc); 936d4e1da4eSPeter Korsgaard else 937d4e1da4eSPeter Korsgaard cd = 1; 938d4e1da4eSPeter Korsgaard } 93948972d90SThierry Reding 94048972d90SThierry Reding return cd; 94148972d90SThierry Reding } 9428ca51e51SSimon Glass #endif 94348972d90SThierry Reding 944fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) 945272cc70bSAndy Fleming { 946272cc70bSAndy Fleming struct mmc_cmd cmd; 947272cc70bSAndy Fleming struct mmc_data data; 948272cc70bSAndy Fleming 949272cc70bSAndy Fleming /* Switch the frequency */ 950272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC; 951272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 952272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff; 953272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4)); 954272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4); 955272cc70bSAndy Fleming 956272cc70bSAndy Fleming data.dest = (char *)resp; 957272cc70bSAndy Fleming data.blocksize = 64; 958272cc70bSAndy Fleming data.blocks = 1; 959272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 960272cc70bSAndy Fleming 961272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 962272cc70bSAndy Fleming } 963272cc70bSAndy Fleming 964272cc70bSAndy Fleming 965d0c221feSJean-Jacques Hiblot static int sd_get_capabilities(struct mmc *mmc) 966272cc70bSAndy Fleming { 967272cc70bSAndy Fleming int err; 968272cc70bSAndy Fleming struct mmc_cmd cmd; 96918e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2); 97018e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16); 971272cc70bSAndy Fleming struct mmc_data data; 972272cc70bSAndy Fleming int timeout; 973272cc70bSAndy Fleming 974d0c221feSJean-Jacques Hiblot mmc->card_caps = MMC_MODE_1BIT; 975272cc70bSAndy Fleming 976d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 977d52ebf10SThomas Chou return 0; 978d52ebf10SThomas Chou 979272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */ 980272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 981272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 982272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 983272cc70bSAndy Fleming 984272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 985272cc70bSAndy Fleming 986272cc70bSAndy Fleming if (err) 987272cc70bSAndy Fleming return err; 988272cc70bSAndy Fleming 989272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR; 990272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 991272cc70bSAndy Fleming cmd.cmdarg = 0; 992272cc70bSAndy Fleming 993272cc70bSAndy Fleming timeout = 3; 994272cc70bSAndy Fleming 995272cc70bSAndy Fleming retry_scr: 996f781dd38SAnton staaf data.dest = (char *)scr; 997272cc70bSAndy Fleming data.blocksize = 8; 998272cc70bSAndy Fleming data.blocks = 1; 999272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1000272cc70bSAndy Fleming 1001272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 1002272cc70bSAndy Fleming 1003272cc70bSAndy Fleming if (err) { 1004272cc70bSAndy Fleming if (timeout--) 1005272cc70bSAndy Fleming goto retry_scr; 1006272cc70bSAndy Fleming 1007272cc70bSAndy Fleming return err; 1008272cc70bSAndy Fleming } 1009272cc70bSAndy Fleming 10104e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]); 10114e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]); 1012272cc70bSAndy Fleming 1013272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) { 1014272cc70bSAndy Fleming case 0: 1015272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1016272cc70bSAndy Fleming break; 1017272cc70bSAndy Fleming case 1: 1018272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10; 1019272cc70bSAndy Fleming break; 1020272cc70bSAndy Fleming case 2: 1021272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 10221741c64dSJaehoon Chung if ((mmc->scr[0] >> 15) & 0x1) 10231741c64dSJaehoon Chung mmc->version = SD_VERSION_3; 1024272cc70bSAndy Fleming break; 1025272cc70bSAndy Fleming default: 1026272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1027272cc70bSAndy Fleming break; 1028272cc70bSAndy Fleming } 1029272cc70bSAndy Fleming 1030b44c7083SAlagu Sankar if (mmc->scr[0] & SD_DATA_4BIT) 1031b44c7083SAlagu Sankar mmc->card_caps |= MMC_MODE_4BIT; 1032b44c7083SAlagu Sankar 1033272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */ 1034272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0) 1035272cc70bSAndy Fleming return 0; 1036272cc70bSAndy Fleming 1037272cc70bSAndy Fleming timeout = 4; 1038272cc70bSAndy Fleming while (timeout--) { 1039272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, 1040f781dd38SAnton staaf (u8 *)switch_status); 1041272cc70bSAndy Fleming 1042272cc70bSAndy Fleming if (err) 1043272cc70bSAndy Fleming return err; 1044272cc70bSAndy Fleming 1045272cc70bSAndy Fleming /* The high-speed function is busy. Try again */ 10464e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) 1047272cc70bSAndy Fleming break; 1048272cc70bSAndy Fleming } 1049272cc70bSAndy Fleming 1050272cc70bSAndy Fleming /* If high-speed isn't supported, we return */ 1051d0c221feSJean-Jacques Hiblot if (__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED) 1052d0c221feSJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(SD_HS); 1053272cc70bSAndy Fleming 10542c3fbf4cSMacpaul Lin return 0; 1055d0c221feSJean-Jacques Hiblot } 1056d0c221feSJean-Jacques Hiblot 1057d0c221feSJean-Jacques Hiblot static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode) 1058d0c221feSJean-Jacques Hiblot { 1059d0c221feSJean-Jacques Hiblot int err; 1060d0c221feSJean-Jacques Hiblot 1061d0c221feSJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16); 10622c3fbf4cSMacpaul Lin 1063f781dd38SAnton staaf err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status); 1064272cc70bSAndy Fleming if (err) 1065272cc70bSAndy Fleming return err; 1066272cc70bSAndy Fleming 1067d0c221feSJean-Jacques Hiblot if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) != 0x01000000) 1068d0c221feSJean-Jacques Hiblot return -ENOTSUPP; 1069d0c221feSJean-Jacques Hiblot 1070d0c221feSJean-Jacques Hiblot return 0; 1071d0c221feSJean-Jacques Hiblot } 1072d0c221feSJean-Jacques Hiblot 1073d0c221feSJean-Jacques Hiblot int sd_select_bus_width(struct mmc *mmc, int w) 1074d0c221feSJean-Jacques Hiblot { 1075d0c221feSJean-Jacques Hiblot int err; 1076d0c221feSJean-Jacques Hiblot struct mmc_cmd cmd; 1077d0c221feSJean-Jacques Hiblot 1078d0c221feSJean-Jacques Hiblot if ((w != 4) && (w != 1)) 1079d0c221feSJean-Jacques Hiblot return -EINVAL; 1080d0c221feSJean-Jacques Hiblot 1081d0c221feSJean-Jacques Hiblot cmd.cmdidx = MMC_CMD_APP_CMD; 1082d0c221feSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 1083d0c221feSJean-Jacques Hiblot cmd.cmdarg = mmc->rca << 16; 1084d0c221feSJean-Jacques Hiblot 1085d0c221feSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 1086d0c221feSJean-Jacques Hiblot if (err) 1087d0c221feSJean-Jacques Hiblot return err; 1088d0c221feSJean-Jacques Hiblot 1089d0c221feSJean-Jacques Hiblot cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; 1090d0c221feSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 1091d0c221feSJean-Jacques Hiblot if (w == 4) 1092d0c221feSJean-Jacques Hiblot cmd.cmdarg = 2; 1093d0c221feSJean-Jacques Hiblot else if (w == 1) 1094d0c221feSJean-Jacques Hiblot cmd.cmdarg = 0; 1095d0c221feSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 1096d0c221feSJean-Jacques Hiblot if (err) 1097d0c221feSJean-Jacques Hiblot return err; 1098272cc70bSAndy Fleming 1099272cc70bSAndy Fleming return 0; 1100272cc70bSAndy Fleming } 1101272cc70bSAndy Fleming 11023697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc) 11033697e599SPeng Fan { 11043697e599SPeng Fan int err, i; 11053697e599SPeng Fan struct mmc_cmd cmd; 11063697e599SPeng Fan ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16); 11073697e599SPeng Fan struct mmc_data data; 11083697e599SPeng Fan int timeout = 3; 11093697e599SPeng Fan unsigned int au, eo, et, es; 11103697e599SPeng Fan 11113697e599SPeng Fan cmd.cmdidx = MMC_CMD_APP_CMD; 11123697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 11133697e599SPeng Fan cmd.cmdarg = mmc->rca << 16; 11143697e599SPeng Fan 11153697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, NULL); 11163697e599SPeng Fan if (err) 11173697e599SPeng Fan return err; 11183697e599SPeng Fan 11193697e599SPeng Fan cmd.cmdidx = SD_CMD_APP_SD_STATUS; 11203697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 11213697e599SPeng Fan cmd.cmdarg = 0; 11223697e599SPeng Fan 11233697e599SPeng Fan retry_ssr: 11243697e599SPeng Fan data.dest = (char *)ssr; 11253697e599SPeng Fan data.blocksize = 64; 11263697e599SPeng Fan data.blocks = 1; 11273697e599SPeng Fan data.flags = MMC_DATA_READ; 11283697e599SPeng Fan 11293697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, &data); 11303697e599SPeng Fan if (err) { 11313697e599SPeng Fan if (timeout--) 11323697e599SPeng Fan goto retry_ssr; 11333697e599SPeng Fan 11343697e599SPeng Fan return err; 11353697e599SPeng Fan } 11363697e599SPeng Fan 11373697e599SPeng Fan for (i = 0; i < 16; i++) 11383697e599SPeng Fan ssr[i] = be32_to_cpu(ssr[i]); 11393697e599SPeng Fan 11403697e599SPeng Fan au = (ssr[2] >> 12) & 0xF; 11413697e599SPeng Fan if ((au <= 9) || (mmc->version == SD_VERSION_3)) { 11423697e599SPeng Fan mmc->ssr.au = sd_au_size[au]; 11433697e599SPeng Fan es = (ssr[3] >> 24) & 0xFF; 11443697e599SPeng Fan es |= (ssr[2] & 0xFF) << 8; 11453697e599SPeng Fan et = (ssr[3] >> 18) & 0x3F; 11463697e599SPeng Fan if (es && et) { 11473697e599SPeng Fan eo = (ssr[3] >> 16) & 0x3; 11483697e599SPeng Fan mmc->ssr.erase_timeout = (et * 1000) / es; 11493697e599SPeng Fan mmc->ssr.erase_offset = eo * 1000; 11503697e599SPeng Fan } 11513697e599SPeng Fan } else { 11523697e599SPeng Fan debug("Invalid Allocation Unit Size.\n"); 11533697e599SPeng Fan } 11543697e599SPeng Fan 11553697e599SPeng Fan return 0; 11563697e599SPeng Fan } 11573697e599SPeng Fan 1158272cc70bSAndy Fleming /* frequency bases */ 1159272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */ 11605f837c2cSMike Frysinger static const int fbase[] = { 1161272cc70bSAndy Fleming 10000, 1162272cc70bSAndy Fleming 100000, 1163272cc70bSAndy Fleming 1000000, 1164272cc70bSAndy Fleming 10000000, 1165272cc70bSAndy Fleming }; 1166272cc70bSAndy Fleming 1167272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice 1168272cc70bSAndy Fleming * to platforms without floating point. 1169272cc70bSAndy Fleming */ 117061fe076fSSimon Glass static const u8 multipliers[] = { 1171272cc70bSAndy Fleming 0, /* reserved */ 1172272cc70bSAndy Fleming 10, 1173272cc70bSAndy Fleming 12, 1174272cc70bSAndy Fleming 13, 1175272cc70bSAndy Fleming 15, 1176272cc70bSAndy Fleming 20, 1177272cc70bSAndy Fleming 25, 1178272cc70bSAndy Fleming 30, 1179272cc70bSAndy Fleming 35, 1180272cc70bSAndy Fleming 40, 1181272cc70bSAndy Fleming 45, 1182272cc70bSAndy Fleming 50, 1183272cc70bSAndy Fleming 55, 1184272cc70bSAndy Fleming 60, 1185272cc70bSAndy Fleming 70, 1186272cc70bSAndy Fleming 80, 1187272cc70bSAndy Fleming }; 1188272cc70bSAndy Fleming 1189d0c221feSJean-Jacques Hiblot static inline int bus_width(uint cap) 1190d0c221feSJean-Jacques Hiblot { 1191d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_8BIT) 1192d0c221feSJean-Jacques Hiblot return 8; 1193d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_4BIT) 1194d0c221feSJean-Jacques Hiblot return 4; 1195d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_1BIT) 1196d0c221feSJean-Jacques Hiblot return 1; 1197d0c221feSJean-Jacques Hiblot printf("invalid bus witdh capability 0x%x\n", cap); 1198d0c221feSJean-Jacques Hiblot return 0; 1199d0c221feSJean-Jacques Hiblot } 1200d0c221feSJean-Jacques Hiblot 1201e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 1202318a7a57SJean-Jacques Hiblot static void mmc_send_init_stream(struct mmc *mmc) 1203318a7a57SJean-Jacques Hiblot { 1204318a7a57SJean-Jacques Hiblot } 1205318a7a57SJean-Jacques Hiblot 12062a4d212fSKishon Vijay Abraham I static int mmc_set_ios(struct mmc *mmc) 1207272cc70bSAndy Fleming { 12082a4d212fSKishon Vijay Abraham I int ret = 0; 12092a4d212fSKishon Vijay Abraham I 121093bfd616SPantelis Antoniou if (mmc->cfg->ops->set_ios) 12112a4d212fSKishon Vijay Abraham I ret = mmc->cfg->ops->set_ios(mmc); 12122a4d212fSKishon Vijay Abraham I 12132a4d212fSKishon Vijay Abraham I return ret; 1214272cc70bSAndy Fleming } 12158ca51e51SSimon Glass #endif 1216272cc70bSAndy Fleming 121735f67820SKishon Vijay Abraham I int mmc_set_clock(struct mmc *mmc, uint clock, bool disable) 1218272cc70bSAndy Fleming { 121993bfd616SPantelis Antoniou if (clock > mmc->cfg->f_max) 122093bfd616SPantelis Antoniou clock = mmc->cfg->f_max; 1221272cc70bSAndy Fleming 122293bfd616SPantelis Antoniou if (clock < mmc->cfg->f_min) 122393bfd616SPantelis Antoniou clock = mmc->cfg->f_min; 1224272cc70bSAndy Fleming 1225272cc70bSAndy Fleming mmc->clock = clock; 122635f67820SKishon Vijay Abraham I mmc->clk_disable = disable; 1227272cc70bSAndy Fleming 12282a4d212fSKishon Vijay Abraham I return mmc_set_ios(mmc); 1229272cc70bSAndy Fleming } 1230272cc70bSAndy Fleming 12312a4d212fSKishon Vijay Abraham I static int mmc_set_bus_width(struct mmc *mmc, uint width) 1232272cc70bSAndy Fleming { 1233272cc70bSAndy Fleming mmc->bus_width = width; 1234272cc70bSAndy Fleming 12352a4d212fSKishon Vijay Abraham I return mmc_set_ios(mmc); 1236272cc70bSAndy Fleming } 1237272cc70bSAndy Fleming 12384c9d2aaaSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG) 12394c9d2aaaSJean-Jacques Hiblot /* 12404c9d2aaaSJean-Jacques Hiblot * helper function to display the capabilities in a human 12414c9d2aaaSJean-Jacques Hiblot * friendly manner. The capabilities include bus width and 12424c9d2aaaSJean-Jacques Hiblot * supported modes. 12434c9d2aaaSJean-Jacques Hiblot */ 12444c9d2aaaSJean-Jacques Hiblot void mmc_dump_capabilities(const char *text, uint caps) 12454c9d2aaaSJean-Jacques Hiblot { 12464c9d2aaaSJean-Jacques Hiblot enum bus_mode mode; 12474c9d2aaaSJean-Jacques Hiblot 12484c9d2aaaSJean-Jacques Hiblot printf("%s: widths [", text); 12494c9d2aaaSJean-Jacques Hiblot if (caps & MMC_MODE_8BIT) 12504c9d2aaaSJean-Jacques Hiblot printf("8, "); 12514c9d2aaaSJean-Jacques Hiblot if (caps & MMC_MODE_4BIT) 12524c9d2aaaSJean-Jacques Hiblot printf("4, "); 1253d0c221feSJean-Jacques Hiblot if (caps & MMC_MODE_1BIT) 1254d0c221feSJean-Jacques Hiblot printf("1, "); 1255d0c221feSJean-Jacques Hiblot printf("\b\b] modes ["); 12564c9d2aaaSJean-Jacques Hiblot for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++) 12574c9d2aaaSJean-Jacques Hiblot if (MMC_CAP(mode) & caps) 12584c9d2aaaSJean-Jacques Hiblot printf("%s, ", mmc_mode_name(mode)); 12594c9d2aaaSJean-Jacques Hiblot printf("\b\b]\n"); 12604c9d2aaaSJean-Jacques Hiblot } 12614c9d2aaaSJean-Jacques Hiblot #endif 12624c9d2aaaSJean-Jacques Hiblot 1263d0c221feSJean-Jacques Hiblot struct mode_width_tuning { 1264d0c221feSJean-Jacques Hiblot enum bus_mode mode; 1265d0c221feSJean-Jacques Hiblot uint widths; 1266d0c221feSJean-Jacques Hiblot }; 1267d0c221feSJean-Jacques Hiblot 1268aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage) 1269aff5d3c8SKishon Vijay Abraham I { 1270aff5d3c8SKishon Vijay Abraham I mmc->signal_voltage = signal_voltage; 1271aff5d3c8SKishon Vijay Abraham I return mmc_set_ios(mmc); 1272aff5d3c8SKishon Vijay Abraham I } 1273aff5d3c8SKishon Vijay Abraham I 1274d0c221feSJean-Jacques Hiblot static const struct mode_width_tuning sd_modes_by_pref[] = { 1275d0c221feSJean-Jacques Hiblot { 1276d0c221feSJean-Jacques Hiblot .mode = SD_HS, 1277d0c221feSJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1278d0c221feSJean-Jacques Hiblot }, 1279d0c221feSJean-Jacques Hiblot { 1280d0c221feSJean-Jacques Hiblot .mode = SD_LEGACY, 1281d0c221feSJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1282d0c221feSJean-Jacques Hiblot } 1283d0c221feSJean-Jacques Hiblot }; 1284d0c221feSJean-Jacques Hiblot 1285d0c221feSJean-Jacques Hiblot #define for_each_sd_mode_by_pref(caps, mwt) \ 1286d0c221feSJean-Jacques Hiblot for (mwt = sd_modes_by_pref;\ 1287d0c221feSJean-Jacques Hiblot mwt < sd_modes_by_pref + ARRAY_SIZE(sd_modes_by_pref);\ 1288d0c221feSJean-Jacques Hiblot mwt++) \ 1289d0c221feSJean-Jacques Hiblot if (caps & MMC_CAP(mwt->mode)) 1290d0c221feSJean-Jacques Hiblot 1291d0c221feSJean-Jacques Hiblot static int sd_select_mode_and_width(struct mmc *mmc) 12928ac8a263SJean-Jacques Hiblot { 12938ac8a263SJean-Jacques Hiblot int err; 1294d0c221feSJean-Jacques Hiblot uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT}; 1295d0c221feSJean-Jacques Hiblot const struct mode_width_tuning *mwt; 12968ac8a263SJean-Jacques Hiblot 1297d0c221feSJean-Jacques Hiblot err = sd_get_capabilities(mmc); 12988ac8a263SJean-Jacques Hiblot if (err) 12998ac8a263SJean-Jacques Hiblot return err; 13008ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */ 1301d0c221feSJean-Jacques Hiblot mmc->card_caps &= (mmc->cfg->host_caps | MMC_MODE_1BIT); 13028ac8a263SJean-Jacques Hiblot 1303d0c221feSJean-Jacques Hiblot for_each_sd_mode_by_pref(mmc->card_caps, mwt) { 1304d0c221feSJean-Jacques Hiblot uint *w; 13058ac8a263SJean-Jacques Hiblot 1306d0c221feSJean-Jacques Hiblot for (w = widths; w < widths + ARRAY_SIZE(widths); w++) { 1307d0c221feSJean-Jacques Hiblot if (*w & mmc->card_caps & mwt->widths) { 1308d0c221feSJean-Jacques Hiblot debug("trying mode %s width %d (at %d MHz)\n", 1309d0c221feSJean-Jacques Hiblot mmc_mode_name(mwt->mode), 1310d0c221feSJean-Jacques Hiblot bus_width(*w), 1311d0c221feSJean-Jacques Hiblot mmc_mode2freq(mmc, mwt->mode) / 1000000); 1312d0c221feSJean-Jacques Hiblot 1313d0c221feSJean-Jacques Hiblot /* configure the bus width (card + host) */ 1314d0c221feSJean-Jacques Hiblot err = sd_select_bus_width(mmc, bus_width(*w)); 13158ac8a263SJean-Jacques Hiblot if (err) 1316d0c221feSJean-Jacques Hiblot goto error; 1317d0c221feSJean-Jacques Hiblot mmc_set_bus_width(mmc, bus_width(*w)); 13188ac8a263SJean-Jacques Hiblot 1319d0c221feSJean-Jacques Hiblot /* configure the bus mode (card) */ 1320d0c221feSJean-Jacques Hiblot err = sd_set_card_speed(mmc, mwt->mode); 13218ac8a263SJean-Jacques Hiblot if (err) 1322d0c221feSJean-Jacques Hiblot goto error; 13238ac8a263SJean-Jacques Hiblot 1324d0c221feSJean-Jacques Hiblot /* configure the bus mode (host) */ 1325d0c221feSJean-Jacques Hiblot mmc_select_mode(mmc, mwt->mode); 132635f67820SKishon Vijay Abraham I mmc_set_clock(mmc, mmc->tran_speed, false); 13278ac8a263SJean-Jacques Hiblot 13288ac8a263SJean-Jacques Hiblot err = sd_read_ssr(mmc); 1329d0c221feSJean-Jacques Hiblot if (!err) 13308ac8a263SJean-Jacques Hiblot return 0; 1331d0c221feSJean-Jacques Hiblot 1332d0c221feSJean-Jacques Hiblot printf("bad ssr\n"); 1333d0c221feSJean-Jacques Hiblot 1334d0c221feSJean-Jacques Hiblot error: 1335d0c221feSJean-Jacques Hiblot /* revert to a safer bus speed */ 1336d0c221feSJean-Jacques Hiblot mmc_select_mode(mmc, SD_LEGACY); 133735f67820SKishon Vijay Abraham I mmc_set_clock(mmc, mmc->tran_speed, false); 1338d0c221feSJean-Jacques Hiblot } 1339d0c221feSJean-Jacques Hiblot } 1340d0c221feSJean-Jacques Hiblot } 1341d0c221feSJean-Jacques Hiblot 1342d0c221feSJean-Jacques Hiblot printf("unable to select a mode\n"); 1343d0c221feSJean-Jacques Hiblot return -ENOTSUPP; 13448ac8a263SJean-Jacques Hiblot } 13458ac8a263SJean-Jacques Hiblot 13467382e691SJean-Jacques Hiblot /* 13477382e691SJean-Jacques Hiblot * read the compare the part of ext csd that is constant. 13487382e691SJean-Jacques Hiblot * This can be used to check that the transfer is working 13497382e691SJean-Jacques Hiblot * as expected. 13507382e691SJean-Jacques Hiblot */ 13517382e691SJean-Jacques Hiblot static int mmc_read_and_compare_ext_csd(struct mmc *mmc) 13527382e691SJean-Jacques Hiblot { 13537382e691SJean-Jacques Hiblot int err; 13547382e691SJean-Jacques Hiblot const u8 *ext_csd = mmc->ext_csd; 13557382e691SJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 13567382e691SJean-Jacques Hiblot 13577382e691SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, test_csd); 13587382e691SJean-Jacques Hiblot if (err) 13597382e691SJean-Jacques Hiblot return err; 13607382e691SJean-Jacques Hiblot 13617382e691SJean-Jacques Hiblot /* Only compare read only fields */ 13627382e691SJean-Jacques Hiblot if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] 13637382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_PARTITIONING_SUPPORT] && 13647382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_WP_GRP_SIZE] 13657382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_WP_GRP_SIZE] && 13667382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_REV] 13677382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_REV] && 13687382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 13697382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] && 13707382e691SJean-Jacques Hiblot memcmp(&ext_csd[EXT_CSD_SEC_CNT], 13717382e691SJean-Jacques Hiblot &test_csd[EXT_CSD_SEC_CNT], 4) == 0) 13727382e691SJean-Jacques Hiblot return 0; 13737382e691SJean-Jacques Hiblot 13747382e691SJean-Jacques Hiblot return -EBADMSG; 13757382e691SJean-Jacques Hiblot } 13767382e691SJean-Jacques Hiblot 13773862b854SJean-Jacques Hiblot static const struct mode_width_tuning mmc_modes_by_pref[] = { 13788ac8a263SJean-Jacques Hiblot { 13793862b854SJean-Jacques Hiblot .mode = MMC_HS_200, 13803862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT, 13813862b854SJean-Jacques Hiblot }, 13823862b854SJean-Jacques Hiblot { 13833862b854SJean-Jacques Hiblot .mode = MMC_DDR_52, 13843862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT, 13853862b854SJean-Jacques Hiblot }, 13863862b854SJean-Jacques Hiblot { 13873862b854SJean-Jacques Hiblot .mode = MMC_HS_52, 13883862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 13893862b854SJean-Jacques Hiblot }, 13903862b854SJean-Jacques Hiblot { 13913862b854SJean-Jacques Hiblot .mode = MMC_HS, 13923862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 13933862b854SJean-Jacques Hiblot }, 13943862b854SJean-Jacques Hiblot { 13953862b854SJean-Jacques Hiblot .mode = MMC_LEGACY, 13963862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 13973862b854SJean-Jacques Hiblot } 13988ac8a263SJean-Jacques Hiblot }; 13998ac8a263SJean-Jacques Hiblot 14003862b854SJean-Jacques Hiblot #define for_each_mmc_mode_by_pref(caps, mwt) \ 14013862b854SJean-Jacques Hiblot for (mwt = mmc_modes_by_pref;\ 14023862b854SJean-Jacques Hiblot mwt < mmc_modes_by_pref + ARRAY_SIZE(mmc_modes_by_pref);\ 14033862b854SJean-Jacques Hiblot mwt++) \ 14043862b854SJean-Jacques Hiblot if (caps & MMC_CAP(mwt->mode)) 14053862b854SJean-Jacques Hiblot 14063862b854SJean-Jacques Hiblot static const struct ext_csd_bus_width { 14073862b854SJean-Jacques Hiblot uint cap; 14083862b854SJean-Jacques Hiblot bool is_ddr; 14093862b854SJean-Jacques Hiblot uint ext_csd_bits; 14103862b854SJean-Jacques Hiblot } ext_csd_bus_width[] = { 14113862b854SJean-Jacques Hiblot {MMC_MODE_8BIT, true, EXT_CSD_DDR_BUS_WIDTH_8}, 14123862b854SJean-Jacques Hiblot {MMC_MODE_4BIT, true, EXT_CSD_DDR_BUS_WIDTH_4}, 14133862b854SJean-Jacques Hiblot {MMC_MODE_8BIT, false, EXT_CSD_BUS_WIDTH_8}, 14143862b854SJean-Jacques Hiblot {MMC_MODE_4BIT, false, EXT_CSD_BUS_WIDTH_4}, 14153862b854SJean-Jacques Hiblot {MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1}, 14163862b854SJean-Jacques Hiblot }; 14173862b854SJean-Jacques Hiblot 14183862b854SJean-Jacques Hiblot #define for_each_supported_width(caps, ddr, ecbv) \ 14193862b854SJean-Jacques Hiblot for (ecbv = ext_csd_bus_width;\ 14203862b854SJean-Jacques Hiblot ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\ 14213862b854SJean-Jacques Hiblot ecbv++) \ 14223862b854SJean-Jacques Hiblot if ((ddr == ecbv->is_ddr) && (caps & ecbv->cap)) 14233862b854SJean-Jacques Hiblot 14243862b854SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc) 14253862b854SJean-Jacques Hiblot { 14263862b854SJean-Jacques Hiblot int err; 14273862b854SJean-Jacques Hiblot const struct mode_width_tuning *mwt; 14283862b854SJean-Jacques Hiblot const struct ext_csd_bus_width *ecbw; 14293862b854SJean-Jacques Hiblot 14303862b854SJean-Jacques Hiblot err = mmc_get_capabilities(mmc); 14318ac8a263SJean-Jacques Hiblot if (err) 14328ac8a263SJean-Jacques Hiblot return err; 14338ac8a263SJean-Jacques Hiblot 14348ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */ 1435d0c221feSJean-Jacques Hiblot mmc->card_caps &= (mmc->cfg->host_caps | MMC_MODE_1BIT); 14368ac8a263SJean-Jacques Hiblot 14378ac8a263SJean-Jacques Hiblot /* Only version 4 of MMC supports wider bus widths */ 14388ac8a263SJean-Jacques Hiblot if (mmc->version < MMC_VERSION_4) 14398ac8a263SJean-Jacques Hiblot return 0; 14408ac8a263SJean-Jacques Hiblot 1441dfda9d88SJean-Jacques Hiblot if (!mmc->ext_csd) { 1442dfda9d88SJean-Jacques Hiblot debug("No ext_csd found!\n"); /* this should enver happen */ 1443dfda9d88SJean-Jacques Hiblot return -ENOTSUPP; 1444dfda9d88SJean-Jacques Hiblot } 1445dfda9d88SJean-Jacques Hiblot 14463862b854SJean-Jacques Hiblot for_each_mmc_mode_by_pref(mmc->card_caps, mwt) { 14473862b854SJean-Jacques Hiblot for_each_supported_width(mmc->card_caps & mwt->widths, 14483862b854SJean-Jacques Hiblot mmc_is_mode_ddr(mwt->mode), ecbw) { 14493862b854SJean-Jacques Hiblot debug("trying mode %s width %d (at %d MHz)\n", 14503862b854SJean-Jacques Hiblot mmc_mode_name(mwt->mode), 14513862b854SJean-Jacques Hiblot bus_width(ecbw->cap), 14523862b854SJean-Jacques Hiblot mmc_mode2freq(mmc, mwt->mode) / 1000000); 14533862b854SJean-Jacques Hiblot /* configure the bus width (card + host) */ 14543862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 14553862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, 14563862b854SJean-Jacques Hiblot ecbw->ext_csd_bits & ~EXT_CSD_DDR_FLAG); 14573862b854SJean-Jacques Hiblot if (err) 14583862b854SJean-Jacques Hiblot goto error; 14593862b854SJean-Jacques Hiblot mmc_set_bus_width(mmc, bus_width(ecbw->cap)); 14603862b854SJean-Jacques Hiblot 14613862b854SJean-Jacques Hiblot /* configure the bus speed (card) */ 14623862b854SJean-Jacques Hiblot err = mmc_set_card_speed(mmc, mwt->mode); 14633862b854SJean-Jacques Hiblot if (err) 14643862b854SJean-Jacques Hiblot goto error; 14653862b854SJean-Jacques Hiblot 14668ac8a263SJean-Jacques Hiblot /* 14673862b854SJean-Jacques Hiblot * configure the bus width AND the ddr mode (card) 14683862b854SJean-Jacques Hiblot * The host side will be taken care of in the next step 14698ac8a263SJean-Jacques Hiblot */ 14703862b854SJean-Jacques Hiblot if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) { 14713862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 14723862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, 14733862b854SJean-Jacques Hiblot ecbw->ext_csd_bits); 14743862b854SJean-Jacques Hiblot if (err) 14753862b854SJean-Jacques Hiblot goto error; 14768ac8a263SJean-Jacques Hiblot } 14778ac8a263SJean-Jacques Hiblot 14783862b854SJean-Jacques Hiblot /* configure the bus mode (host) */ 14793862b854SJean-Jacques Hiblot mmc_select_mode(mmc, mwt->mode); 148035f67820SKishon Vijay Abraham I mmc_set_clock(mmc, mmc->tran_speed, false); 14818ac8a263SJean-Jacques Hiblot 14823862b854SJean-Jacques Hiblot /* do a transfer to check the configuration */ 14837382e691SJean-Jacques Hiblot err = mmc_read_and_compare_ext_csd(mmc); 14847382e691SJean-Jacques Hiblot if (!err) 14853862b854SJean-Jacques Hiblot return 0; 14863862b854SJean-Jacques Hiblot error: 14873862b854SJean-Jacques Hiblot /* if an error occured, revert to a safer bus mode */ 14883862b854SJean-Jacques Hiblot mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 14893862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1); 14903862b854SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_LEGACY); 14913862b854SJean-Jacques Hiblot mmc_set_bus_width(mmc, 1); 14923862b854SJean-Jacques Hiblot } 14938ac8a263SJean-Jacques Hiblot } 14948ac8a263SJean-Jacques Hiblot 14953862b854SJean-Jacques Hiblot printf("unable to select a mode\n"); 14968ac8a263SJean-Jacques Hiblot 14973862b854SJean-Jacques Hiblot return -ENOTSUPP; 14988ac8a263SJean-Jacques Hiblot } 14998ac8a263SJean-Jacques Hiblot 1500dfda9d88SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc) 1501c744b6f6SJean-Jacques Hiblot { 1502c744b6f6SJean-Jacques Hiblot int err, i; 1503c744b6f6SJean-Jacques Hiblot u64 capacity; 1504c744b6f6SJean-Jacques Hiblot bool has_parts = false; 1505c744b6f6SJean-Jacques Hiblot bool part_completed; 1506dfda9d88SJean-Jacques Hiblot u8 *ext_csd; 1507c744b6f6SJean-Jacques Hiblot 1508c744b6f6SJean-Jacques Hiblot if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4)) 1509c744b6f6SJean-Jacques Hiblot return 0; 1510c744b6f6SJean-Jacques Hiblot 1511dfda9d88SJean-Jacques Hiblot ext_csd = malloc_cache_aligned(MMC_MAX_BLOCK_LEN); 1512dfda9d88SJean-Jacques Hiblot if (!ext_csd) 1513dfda9d88SJean-Jacques Hiblot return -ENOMEM; 1514dfda9d88SJean-Jacques Hiblot 1515dfda9d88SJean-Jacques Hiblot mmc->ext_csd = ext_csd; 1516dfda9d88SJean-Jacques Hiblot 1517c744b6f6SJean-Jacques Hiblot /* check ext_csd version and capacity */ 1518c744b6f6SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, ext_csd); 1519c744b6f6SJean-Jacques Hiblot if (err) 1520c744b6f6SJean-Jacques Hiblot return err; 1521c744b6f6SJean-Jacques Hiblot if (ext_csd[EXT_CSD_REV] >= 2) { 1522c744b6f6SJean-Jacques Hiblot /* 1523c744b6f6SJean-Jacques Hiblot * According to the JEDEC Standard, the value of 1524c744b6f6SJean-Jacques Hiblot * ext_csd's capacity is valid if the value is more 1525c744b6f6SJean-Jacques Hiblot * than 2GB 1526c744b6f6SJean-Jacques Hiblot */ 1527c744b6f6SJean-Jacques Hiblot capacity = ext_csd[EXT_CSD_SEC_CNT] << 0 1528c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 1529c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 1530c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; 1531c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN; 1532c744b6f6SJean-Jacques Hiblot if ((capacity >> 20) > 2 * 1024) 1533c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity; 1534c744b6f6SJean-Jacques Hiblot } 1535c744b6f6SJean-Jacques Hiblot 1536c744b6f6SJean-Jacques Hiblot switch (ext_csd[EXT_CSD_REV]) { 1537c744b6f6SJean-Jacques Hiblot case 1: 1538c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_1; 1539c744b6f6SJean-Jacques Hiblot break; 1540c744b6f6SJean-Jacques Hiblot case 2: 1541c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_2; 1542c744b6f6SJean-Jacques Hiblot break; 1543c744b6f6SJean-Jacques Hiblot case 3: 1544c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_3; 1545c744b6f6SJean-Jacques Hiblot break; 1546c744b6f6SJean-Jacques Hiblot case 5: 1547c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_41; 1548c744b6f6SJean-Jacques Hiblot break; 1549c744b6f6SJean-Jacques Hiblot case 6: 1550c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_5; 1551c744b6f6SJean-Jacques Hiblot break; 1552c744b6f6SJean-Jacques Hiblot case 7: 1553c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_5_0; 1554c744b6f6SJean-Jacques Hiblot break; 1555c744b6f6SJean-Jacques Hiblot case 8: 1556c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_5_1; 1557c744b6f6SJean-Jacques Hiblot break; 1558c744b6f6SJean-Jacques Hiblot } 1559c744b6f6SJean-Jacques Hiblot 1560c744b6f6SJean-Jacques Hiblot /* The partition data may be non-zero but it is only 1561c744b6f6SJean-Jacques Hiblot * effective if PARTITION_SETTING_COMPLETED is set in 1562c744b6f6SJean-Jacques Hiblot * EXT_CSD, so ignore any data if this bit is not set, 1563c744b6f6SJean-Jacques Hiblot * except for enabling the high-capacity group size 1564c744b6f6SJean-Jacques Hiblot * definition (see below). 1565c744b6f6SJean-Jacques Hiblot */ 1566c744b6f6SJean-Jacques Hiblot part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] & 1567c744b6f6SJean-Jacques Hiblot EXT_CSD_PARTITION_SETTING_COMPLETED); 1568c744b6f6SJean-Jacques Hiblot 1569c744b6f6SJean-Jacques Hiblot /* store the partition info of emmc */ 1570c744b6f6SJean-Jacques Hiblot mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT]; 1571c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || 1572c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_BOOT_MULT]) 1573c744b6f6SJean-Jacques Hiblot mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; 1574c744b6f6SJean-Jacques Hiblot if (part_completed && 1575c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT)) 1576c744b6f6SJean-Jacques Hiblot mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]; 1577c744b6f6SJean-Jacques Hiblot 1578c744b6f6SJean-Jacques Hiblot mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17; 1579c744b6f6SJean-Jacques Hiblot 1580c744b6f6SJean-Jacques Hiblot mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17; 1581c744b6f6SJean-Jacques Hiblot 1582c744b6f6SJean-Jacques Hiblot for (i = 0; i < 4; i++) { 1583c744b6f6SJean-Jacques Hiblot int idx = EXT_CSD_GP_SIZE_MULT + i * 3; 1584c744b6f6SJean-Jacques Hiblot uint mult = (ext_csd[idx + 2] << 16) + 1585c744b6f6SJean-Jacques Hiblot (ext_csd[idx + 1] << 8) + ext_csd[idx]; 1586c744b6f6SJean-Jacques Hiblot if (mult) 1587c744b6f6SJean-Jacques Hiblot has_parts = true; 1588c744b6f6SJean-Jacques Hiblot if (!part_completed) 1589c744b6f6SJean-Jacques Hiblot continue; 1590c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] = mult; 1591c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= 1592c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1593c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1594c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] <<= 19; 1595c744b6f6SJean-Jacques Hiblot } 1596c744b6f6SJean-Jacques Hiblot 1597c744b6f6SJean-Jacques Hiblot if (part_completed) { 1598c744b6f6SJean-Jacques Hiblot mmc->enh_user_size = 1599c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) + 1600c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) + 1601c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_SIZE_MULT]; 1602c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1603c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1604c744b6f6SJean-Jacques Hiblot mmc->enh_user_size <<= 19; 1605c744b6f6SJean-Jacques Hiblot mmc->enh_user_start = 1606c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) + 1607c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) + 1608c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) + 1609c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_START_ADDR]; 1610c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity) 1611c744b6f6SJean-Jacques Hiblot mmc->enh_user_start <<= 9; 1612c744b6f6SJean-Jacques Hiblot } 1613c744b6f6SJean-Jacques Hiblot 1614c744b6f6SJean-Jacques Hiblot /* 1615c744b6f6SJean-Jacques Hiblot * Host needs to enable ERASE_GRP_DEF bit if device is 1616c744b6f6SJean-Jacques Hiblot * partitioned. This bit will be lost every time after a reset 1617c744b6f6SJean-Jacques Hiblot * or power off. This will affect erase size. 1618c744b6f6SJean-Jacques Hiblot */ 1619c744b6f6SJean-Jacques Hiblot if (part_completed) 1620c744b6f6SJean-Jacques Hiblot has_parts = true; 1621c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) && 1622c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) 1623c744b6f6SJean-Jacques Hiblot has_parts = true; 1624c744b6f6SJean-Jacques Hiblot if (has_parts) { 1625c744b6f6SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1626c744b6f6SJean-Jacques Hiblot EXT_CSD_ERASE_GROUP_DEF, 1); 1627c744b6f6SJean-Jacques Hiblot 1628c744b6f6SJean-Jacques Hiblot if (err) 1629c744b6f6SJean-Jacques Hiblot return err; 1630c744b6f6SJean-Jacques Hiblot 1631c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 1632c744b6f6SJean-Jacques Hiblot } 1633c744b6f6SJean-Jacques Hiblot 1634c744b6f6SJean-Jacques Hiblot if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) { 1635c744b6f6SJean-Jacques Hiblot /* Read out group size from ext_csd */ 1636c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = 1637c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 1638c744b6f6SJean-Jacques Hiblot /* 1639c744b6f6SJean-Jacques Hiblot * if high capacity and partition setting completed 1640c744b6f6SJean-Jacques Hiblot * SEC_COUNT is valid even if it is smaller than 2 GiB 1641c744b6f6SJean-Jacques Hiblot * JEDEC Standard JESD84-B45, 6.2.4 1642c744b6f6SJean-Jacques Hiblot */ 1643c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity && part_completed) { 1644c744b6f6SJean-Jacques Hiblot capacity = (ext_csd[EXT_CSD_SEC_CNT]) | 1645c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) | 1646c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) | 1647c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 3] << 24); 1648c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN; 1649c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity; 1650c744b6f6SJean-Jacques Hiblot } 1651c744b6f6SJean-Jacques Hiblot } else { 1652c744b6f6SJean-Jacques Hiblot /* Calculate the group size from the csd value. */ 1653c744b6f6SJean-Jacques Hiblot int erase_gsz, erase_gmul; 1654c744b6f6SJean-Jacques Hiblot 1655c744b6f6SJean-Jacques Hiblot erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; 1656c744b6f6SJean-Jacques Hiblot erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; 1657c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = (erase_gsz + 1) 1658c744b6f6SJean-Jacques Hiblot * (erase_gmul + 1); 1659c744b6f6SJean-Jacques Hiblot } 1660c744b6f6SJean-Jacques Hiblot 1661c744b6f6SJean-Jacques Hiblot mmc->hc_wp_grp_size = 1024 1662c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 1663c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1664c744b6f6SJean-Jacques Hiblot 1665c744b6f6SJean-Jacques Hiblot mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 1666c744b6f6SJean-Jacques Hiblot 1667c744b6f6SJean-Jacques Hiblot return 0; 1668c744b6f6SJean-Jacques Hiblot } 1669c744b6f6SJean-Jacques Hiblot 1670fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc) 1671272cc70bSAndy Fleming { 1672f866a46dSStephen Warren int err, i; 1673272cc70bSAndy Fleming uint mult, freq; 1674c744b6f6SJean-Jacques Hiblot u64 cmult, csize; 1675272cc70bSAndy Fleming struct mmc_cmd cmd; 1676c40fdca6SSimon Glass struct blk_desc *bdesc; 1677272cc70bSAndy Fleming 1678d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON 1679d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ 1680d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; 1681d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R1; 1682d52ebf10SThomas Chou cmd.cmdarg = 1; 1683d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 1684d52ebf10SThomas Chou 1685d52ebf10SThomas Chou if (err) 1686d52ebf10SThomas Chou return err; 1687d52ebf10SThomas Chou } 1688d52ebf10SThomas Chou #endif 1689d52ebf10SThomas Chou 1690272cc70bSAndy Fleming /* Put the Card in Identify Mode */ 1691d52ebf10SThomas Chou cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : 1692d52ebf10SThomas Chou MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ 1693272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1694272cc70bSAndy Fleming cmd.cmdarg = 0; 1695272cc70bSAndy Fleming 1696272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1697272cc70bSAndy Fleming 1698272cc70bSAndy Fleming if (err) 1699272cc70bSAndy Fleming return err; 1700272cc70bSAndy Fleming 1701272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16); 1702272cc70bSAndy Fleming 1703272cc70bSAndy Fleming /* 1704272cc70bSAndy Fleming * For MMC cards, set the Relative Address. 1705272cc70bSAndy Fleming * For SD cards, get the Relatvie Address. 1706272cc70bSAndy Fleming * This also puts the cards into Standby State 1707272cc70bSAndy Fleming */ 1708d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1709272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; 1710272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1711272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6; 1712272cc70bSAndy Fleming 1713272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1714272cc70bSAndy Fleming 1715272cc70bSAndy Fleming if (err) 1716272cc70bSAndy Fleming return err; 1717272cc70bSAndy Fleming 1718272cc70bSAndy Fleming if (IS_SD(mmc)) 1719998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff; 1720d52ebf10SThomas Chou } 1721272cc70bSAndy Fleming 1722272cc70bSAndy Fleming /* Get the Card-Specific Data */ 1723272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD; 1724272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1725272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1726272cc70bSAndy Fleming 1727272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1728272cc70bSAndy Fleming 1729272cc70bSAndy Fleming if (err) 1730272cc70bSAndy Fleming return err; 1731272cc70bSAndy Fleming 1732998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0]; 1733998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1]; 1734998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2]; 1735998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3]; 1736272cc70bSAndy Fleming 1737272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) { 17380b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf; 1739272cc70bSAndy Fleming 1740272cc70bSAndy Fleming switch (version) { 1741272cc70bSAndy Fleming case 0: 1742272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1743272cc70bSAndy Fleming break; 1744272cc70bSAndy Fleming case 1: 1745272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4; 1746272cc70bSAndy Fleming break; 1747272cc70bSAndy Fleming case 2: 1748272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2; 1749272cc70bSAndy Fleming break; 1750272cc70bSAndy Fleming case 3: 1751272cc70bSAndy Fleming mmc->version = MMC_VERSION_3; 1752272cc70bSAndy Fleming break; 1753272cc70bSAndy Fleming case 4: 1754272cc70bSAndy Fleming mmc->version = MMC_VERSION_4; 1755272cc70bSAndy Fleming break; 1756272cc70bSAndy Fleming default: 1757272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1758272cc70bSAndy Fleming break; 1759272cc70bSAndy Fleming } 1760272cc70bSAndy Fleming } 1761272cc70bSAndy Fleming 1762272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */ 17630b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)]; 17640b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; 1765272cc70bSAndy Fleming 176635f9e196SJean-Jacques Hiblot mmc->legacy_speed = freq * mult; 176735f9e196SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_LEGACY); 1768272cc70bSAndy Fleming 1769ab71188cSMarkus Niebel mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); 1770998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); 1771272cc70bSAndy Fleming 1772272cc70bSAndy Fleming if (IS_SD(mmc)) 1773272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len; 1774272cc70bSAndy Fleming else 1775998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); 1776272cc70bSAndy Fleming 1777272cc70bSAndy Fleming if (mmc->high_capacity) { 1778272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16 1779272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16; 1780272cc70bSAndy Fleming cmult = 8; 1781272cc70bSAndy Fleming } else { 1782272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2 1783272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30; 1784272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15; 1785272cc70bSAndy Fleming } 1786272cc70bSAndy Fleming 1787f866a46dSStephen Warren mmc->capacity_user = (csize + 1) << (cmult + 2); 1788f866a46dSStephen Warren mmc->capacity_user *= mmc->read_bl_len; 1789f866a46dSStephen Warren mmc->capacity_boot = 0; 1790f866a46dSStephen Warren mmc->capacity_rpmb = 0; 1791f866a46dSStephen Warren for (i = 0; i < 4; i++) 1792f866a46dSStephen Warren mmc->capacity_gp[i] = 0; 1793272cc70bSAndy Fleming 17948bfa195eSSimon Glass if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN) 17958bfa195eSSimon Glass mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 1796272cc70bSAndy Fleming 17978bfa195eSSimon Glass if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) 17988bfa195eSSimon Glass mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 1799272cc70bSAndy Fleming 1800ab71188cSMarkus Niebel if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) { 1801ab71188cSMarkus Niebel cmd.cmdidx = MMC_CMD_SET_DSR; 1802ab71188cSMarkus Niebel cmd.cmdarg = (mmc->dsr & 0xffff) << 16; 1803ab71188cSMarkus Niebel cmd.resp_type = MMC_RSP_NONE; 1804ab71188cSMarkus Niebel if (mmc_send_cmd(mmc, &cmd, NULL)) 1805ab71188cSMarkus Niebel printf("MMC: SET_DSR failed\n"); 1806ab71188cSMarkus Niebel } 1807ab71188cSMarkus Niebel 1808272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */ 1809d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1810272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD; 1811fe8f7066SAjay Bhargav cmd.resp_type = MMC_RSP_R1; 1812272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1813272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1814272cc70bSAndy Fleming 1815272cc70bSAndy Fleming if (err) 1816272cc70bSAndy Fleming return err; 1817d52ebf10SThomas Chou } 1818272cc70bSAndy Fleming 1819e6f99a56SLei Wen /* 1820e6f99a56SLei Wen * For SD, its erase group is always one sector 1821e6f99a56SLei Wen */ 1822e6f99a56SLei Wen mmc->erase_grp_size = 1; 1823bc897b1dSLei Wen mmc->part_config = MMCPART_NOAVAILABLE; 1824c744b6f6SJean-Jacques Hiblot 1825dfda9d88SJean-Jacques Hiblot err = mmc_startup_v4(mmc); 18269cf199ebSDiego Santa Cruz if (err) 18279cf199ebSDiego Santa Cruz return err; 1828f866a46dSStephen Warren 1829c40fdca6SSimon Glass err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart); 1830f866a46dSStephen Warren if (err) 1831f866a46dSStephen Warren return err; 1832d23e2c09SSukumar Ghorai 1833272cc70bSAndy Fleming if (IS_SD(mmc)) 1834d0c221feSJean-Jacques Hiblot err = sd_select_mode_and_width(mmc); 1835272cc70bSAndy Fleming else 18363862b854SJean-Jacques Hiblot err = mmc_select_mode_and_width(mmc); 1837272cc70bSAndy Fleming 1838272cc70bSAndy Fleming if (err) 1839272cc70bSAndy Fleming return err; 1840272cc70bSAndy Fleming 1841272cc70bSAndy Fleming 18425af8f45cSAndrew Gabbasov /* Fix the block length for DDR mode */ 18435af8f45cSAndrew Gabbasov if (mmc->ddr_mode) { 18445af8f45cSAndrew Gabbasov mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 18455af8f45cSAndrew Gabbasov mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 18465af8f45cSAndrew Gabbasov } 18475af8f45cSAndrew Gabbasov 1848272cc70bSAndy Fleming /* fill in device description */ 1849c40fdca6SSimon Glass bdesc = mmc_get_blk_desc(mmc); 1850c40fdca6SSimon Glass bdesc->lun = 0; 1851c40fdca6SSimon Glass bdesc->hwpart = 0; 1852c40fdca6SSimon Glass bdesc->type = 0; 1853c40fdca6SSimon Glass bdesc->blksz = mmc->read_bl_len; 1854c40fdca6SSimon Glass bdesc->log2blksz = LOG2(bdesc->blksz); 1855c40fdca6SSimon Glass bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len); 1856fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \ 1857fc011f64SSjoerd Simons (defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \ 1858fc011f64SSjoerd Simons !defined(CONFIG_USE_TINY_PRINTF)) 1859c40fdca6SSimon Glass sprintf(bdesc->vendor, "Man %06x Snr %04x%04x", 1860babce5f6STaylor Hutt mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), 1861babce5f6STaylor Hutt (mmc->cid[3] >> 16) & 0xffff); 1862c40fdca6SSimon Glass sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff, 18630b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 1864babce5f6STaylor Hutt (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff, 1865babce5f6STaylor Hutt (mmc->cid[2] >> 24) & 0xff); 1866c40fdca6SSimon Glass sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf, 1867babce5f6STaylor Hutt (mmc->cid[2] >> 16) & 0xf); 186856196826SPaul Burton #else 1869c40fdca6SSimon Glass bdesc->vendor[0] = 0; 1870c40fdca6SSimon Glass bdesc->product[0] = 0; 1871c40fdca6SSimon Glass bdesc->revision[0] = 0; 187256196826SPaul Burton #endif 1873122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT) 1874c40fdca6SSimon Glass part_init(bdesc); 1875122efd43SMikhail Kshevetskiy #endif 1876272cc70bSAndy Fleming 1877272cc70bSAndy Fleming return 0; 1878272cc70bSAndy Fleming } 1879272cc70bSAndy Fleming 1880fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc) 1881272cc70bSAndy Fleming { 1882272cc70bSAndy Fleming struct mmc_cmd cmd; 1883272cc70bSAndy Fleming int err; 1884272cc70bSAndy Fleming 1885272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND; 1886272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ 188793bfd616SPantelis Antoniou cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa; 1888272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7; 1889272cc70bSAndy Fleming 1890272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1891272cc70bSAndy Fleming 1892272cc70bSAndy Fleming if (err) 1893272cc70bSAndy Fleming return err; 1894272cc70bSAndy Fleming 1895998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa) 1896915ffa52SJaehoon Chung return -EOPNOTSUPP; 1897272cc70bSAndy Fleming else 1898272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 1899272cc70bSAndy Fleming 1900272cc70bSAndy Fleming return 0; 1901272cc70bSAndy Fleming } 1902272cc70bSAndy Fleming 1903c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 190495de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */ 190595de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void) 190695de9ab2SPaul Kocialkowski { 190795de9ab2SPaul Kocialkowski } 190805cbeb7cSSimon Glass #endif 190995de9ab2SPaul Kocialkowski 19102051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc) 19112051aefeSPeng Fan { 1912c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 191306ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR) 19142051aefeSPeng Fan int ret; 19152051aefeSPeng Fan 19162051aefeSPeng Fan ret = device_get_supply_regulator(mmc->dev, "vmmc-supply", 191706ec045fSJean-Jacques Hiblot &mmc->vmmc_supply); 191806ec045fSJean-Jacques Hiblot if (ret) 1919288db7c7SJaehoon Chung debug("%s: No vmmc supply\n", mmc->dev->name); 19202051aefeSPeng Fan 192106ec045fSJean-Jacques Hiblot ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply", 192206ec045fSJean-Jacques Hiblot &mmc->vqmmc_supply); 192306ec045fSJean-Jacques Hiblot if (ret) 192406ec045fSJean-Jacques Hiblot debug("%s: No vqmmc supply\n", mmc->dev->name); 19252051aefeSPeng Fan #endif 192605cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */ 192705cbeb7cSSimon Glass /* 192805cbeb7cSSimon Glass * Driver model should use a regulator, as above, rather than calling 192905cbeb7cSSimon Glass * out to board code. 193005cbeb7cSSimon Glass */ 193105cbeb7cSSimon Glass board_mmc_power_init(); 193205cbeb7cSSimon Glass #endif 19332051aefeSPeng Fan return 0; 19342051aefeSPeng Fan } 19352051aefeSPeng Fan 1936fb7c3bebSKishon Vijay Abraham I /* 1937fb7c3bebSKishon Vijay Abraham I * put the host in the initial state: 1938fb7c3bebSKishon Vijay Abraham I * - turn on Vdd (card power supply) 1939fb7c3bebSKishon Vijay Abraham I * - configure the bus width and clock to minimal values 1940fb7c3bebSKishon Vijay Abraham I */ 1941fb7c3bebSKishon Vijay Abraham I static void mmc_set_initial_state(struct mmc *mmc) 1942fb7c3bebSKishon Vijay Abraham I { 1943fb7c3bebSKishon Vijay Abraham I int err; 1944fb7c3bebSKishon Vijay Abraham I 1945fb7c3bebSKishon Vijay Abraham I /* First try to set 3.3V. If it fails set to 1.8V */ 1946fb7c3bebSKishon Vijay Abraham I err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_330); 1947fb7c3bebSKishon Vijay Abraham I if (err != 0) 1948fb7c3bebSKishon Vijay Abraham I err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_180); 1949fb7c3bebSKishon Vijay Abraham I if (err != 0) 1950fb7c3bebSKishon Vijay Abraham I printf("mmc: failed to set signal voltage\n"); 1951fb7c3bebSKishon Vijay Abraham I 1952fb7c3bebSKishon Vijay Abraham I mmc_select_mode(mmc, MMC_LEGACY); 1953fb7c3bebSKishon Vijay Abraham I mmc_set_bus_width(mmc, 1); 195435f67820SKishon Vijay Abraham I mmc_set_clock(mmc, 0, false); 1955fb7c3bebSKishon Vijay Abraham I } 1956fb7c3bebSKishon Vijay Abraham I 1957fb7c3bebSKishon Vijay Abraham I static int mmc_power_on(struct mmc *mmc) 1958fb7c3bebSKishon Vijay Abraham I { 1959fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR) 1960fb7c3bebSKishon Vijay Abraham I if (mmc->vmmc_supply) { 1961fb7c3bebSKishon Vijay Abraham I int ret = regulator_set_enable(mmc->vmmc_supply, true); 1962fb7c3bebSKishon Vijay Abraham I 1963fb7c3bebSKishon Vijay Abraham I if (ret) { 1964fb7c3bebSKishon Vijay Abraham I puts("Error enabling VMMC supply\n"); 1965fb7c3bebSKishon Vijay Abraham I return ret; 1966fb7c3bebSKishon Vijay Abraham I } 1967fb7c3bebSKishon Vijay Abraham I } 1968fb7c3bebSKishon Vijay Abraham I #endif 1969fb7c3bebSKishon Vijay Abraham I return 0; 1970fb7c3bebSKishon Vijay Abraham I } 1971fb7c3bebSKishon Vijay Abraham I 1972fb7c3bebSKishon Vijay Abraham I static int mmc_power_off(struct mmc *mmc) 1973fb7c3bebSKishon Vijay Abraham I { 1974*2e7410d7SKishon Vijay Abraham I mmc_set_clock(mmc, 1, true); 1975fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR) 1976fb7c3bebSKishon Vijay Abraham I if (mmc->vmmc_supply) { 1977fb7c3bebSKishon Vijay Abraham I int ret = regulator_set_enable(mmc->vmmc_supply, false); 1978fb7c3bebSKishon Vijay Abraham I 1979fb7c3bebSKishon Vijay Abraham I if (ret) { 1980fb7c3bebSKishon Vijay Abraham I puts("Error disabling VMMC supply\n"); 1981fb7c3bebSKishon Vijay Abraham I return ret; 1982fb7c3bebSKishon Vijay Abraham I } 1983fb7c3bebSKishon Vijay Abraham I } 1984fb7c3bebSKishon Vijay Abraham I #endif 1985fb7c3bebSKishon Vijay Abraham I return 0; 1986fb7c3bebSKishon Vijay Abraham I } 1987fb7c3bebSKishon Vijay Abraham I 1988fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc) 1989fb7c3bebSKishon Vijay Abraham I { 1990fb7c3bebSKishon Vijay Abraham I int ret; 1991fb7c3bebSKishon Vijay Abraham I 1992fb7c3bebSKishon Vijay Abraham I ret = mmc_power_off(mmc); 1993fb7c3bebSKishon Vijay Abraham I if (ret) 1994fb7c3bebSKishon Vijay Abraham I return ret; 1995fb7c3bebSKishon Vijay Abraham I /* 1996fb7c3bebSKishon Vijay Abraham I * SD spec recommends at least 1ms of delay. Let's wait for 2ms 1997fb7c3bebSKishon Vijay Abraham I * to be on the safer side. 1998fb7c3bebSKishon Vijay Abraham I */ 1999fb7c3bebSKishon Vijay Abraham I udelay(2000); 2000fb7c3bebSKishon Vijay Abraham I return mmc_power_on(mmc); 2001fb7c3bebSKishon Vijay Abraham I } 2002fb7c3bebSKishon Vijay Abraham I 2003e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc) 2004272cc70bSAndy Fleming { 20058ca51e51SSimon Glass bool no_card; 2006afd5932bSMacpaul Lin int err; 2007272cc70bSAndy Fleming 2008ab769f22SPantelis Antoniou /* we pretend there's no card when init is NULL */ 20098ca51e51SSimon Glass no_card = mmc_getcd(mmc) == 0; 2010e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 20118ca51e51SSimon Glass no_card = no_card || (mmc->cfg->ops->init == NULL); 20128ca51e51SSimon Glass #endif 20138ca51e51SSimon Glass if (no_card) { 201448972d90SThierry Reding mmc->has_init = 0; 201556196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 201648972d90SThierry Reding printf("MMC: no card present\n"); 201756196826SPaul Burton #endif 2018915ffa52SJaehoon Chung return -ENOMEDIUM; 201948972d90SThierry Reding } 202048972d90SThierry Reding 2021bc897b1dSLei Wen if (mmc->has_init) 2022bc897b1dSLei Wen return 0; 2023bc897b1dSLei Wen 20245a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 20255a8dbdc6SYangbo Lu mmc_adapter_card_type_ident(); 20265a8dbdc6SYangbo Lu #endif 20272051aefeSPeng Fan err = mmc_power_init(mmc); 20282051aefeSPeng Fan if (err) 20292051aefeSPeng Fan return err; 203095de9ab2SPaul Kocialkowski 2031fb7c3bebSKishon Vijay Abraham I err = mmc_power_on(mmc); 2032fb7c3bebSKishon Vijay Abraham I if (err) 2033fb7c3bebSKishon Vijay Abraham I return err; 2034fb7c3bebSKishon Vijay Abraham I 2035e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 20368ca51e51SSimon Glass /* The device has already been probed ready for use */ 20378ca51e51SSimon Glass #else 2038ab769f22SPantelis Antoniou /* made sure it's not NULL earlier */ 203993bfd616SPantelis Antoniou err = mmc->cfg->ops->init(mmc); 2040272cc70bSAndy Fleming if (err) 2041272cc70bSAndy Fleming return err; 20428ca51e51SSimon Glass #endif 2043786e8f81SAndrew Gabbasov mmc->ddr_mode = 0; 2044aff5d3c8SKishon Vijay Abraham I 2045fb7c3bebSKishon Vijay Abraham I mmc_set_initial_state(mmc); 2046318a7a57SJean-Jacques Hiblot mmc_send_init_stream(mmc); 2047318a7a57SJean-Jacques Hiblot 2048272cc70bSAndy Fleming /* Reset the Card */ 2049272cc70bSAndy Fleming err = mmc_go_idle(mmc); 2050272cc70bSAndy Fleming 2051272cc70bSAndy Fleming if (err) 2052272cc70bSAndy Fleming return err; 2053272cc70bSAndy Fleming 2054bc897b1dSLei Wen /* The internal partition reset to user partition(0) at every CMD0*/ 2055c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->hwpart = 0; 2056bc897b1dSLei Wen 2057272cc70bSAndy Fleming /* Test for SD version 2 */ 2058272cc70bSAndy Fleming err = mmc_send_if_cond(mmc); 2059272cc70bSAndy Fleming 2060272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */ 2061272cc70bSAndy Fleming err = sd_send_op_cond(mmc); 2062272cc70bSAndy Fleming 2063272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */ 2064915ffa52SJaehoon Chung if (err == -ETIMEDOUT) { 2065272cc70bSAndy Fleming err = mmc_send_op_cond(mmc); 2066272cc70bSAndy Fleming 2067bd47c135SAndrew Gabbasov if (err) { 206856196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2069272cc70bSAndy Fleming printf("Card did not respond to voltage select!\n"); 207056196826SPaul Burton #endif 2071915ffa52SJaehoon Chung return -EOPNOTSUPP; 2072272cc70bSAndy Fleming } 2073272cc70bSAndy Fleming } 2074272cc70bSAndy Fleming 2075bd47c135SAndrew Gabbasov if (!err) 2076e9550449SChe-Liang Chiou mmc->init_in_progress = 1; 2077e9550449SChe-Liang Chiou 2078e9550449SChe-Liang Chiou return err; 2079e9550449SChe-Liang Chiou } 2080e9550449SChe-Liang Chiou 2081e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc) 2082e9550449SChe-Liang Chiou { 2083e9550449SChe-Liang Chiou int err = 0; 2084e9550449SChe-Liang Chiou 2085bd47c135SAndrew Gabbasov mmc->init_in_progress = 0; 2086e9550449SChe-Liang Chiou if (mmc->op_cond_pending) 2087e9550449SChe-Liang Chiou err = mmc_complete_op_cond(mmc); 2088e9550449SChe-Liang Chiou 2089e9550449SChe-Liang Chiou if (!err) 2090bc897b1dSLei Wen err = mmc_startup(mmc); 2091bc897b1dSLei Wen if (err) 2092bc897b1dSLei Wen mmc->has_init = 0; 2093bc897b1dSLei Wen else 2094bc897b1dSLei Wen mmc->has_init = 1; 2095e9550449SChe-Liang Chiou return err; 2096e9550449SChe-Liang Chiou } 2097e9550449SChe-Liang Chiou 2098e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc) 2099e9550449SChe-Liang Chiou { 2100bd47c135SAndrew Gabbasov int err = 0; 2101ce9eca94SMarek Vasut __maybe_unused unsigned start; 2102c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 210333fb211dSSimon Glass struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev); 2104e9550449SChe-Liang Chiou 210533fb211dSSimon Glass upriv->mmc = mmc; 210633fb211dSSimon Glass #endif 2107e9550449SChe-Liang Chiou if (mmc->has_init) 2108e9550449SChe-Liang Chiou return 0; 2109d803fea5SMateusz Zalega 2110d803fea5SMateusz Zalega start = get_timer(0); 2111d803fea5SMateusz Zalega 2112e9550449SChe-Liang Chiou if (!mmc->init_in_progress) 2113e9550449SChe-Liang Chiou err = mmc_start_init(mmc); 2114e9550449SChe-Liang Chiou 2115bd47c135SAndrew Gabbasov if (!err) 2116e9550449SChe-Liang Chiou err = mmc_complete_init(mmc); 2117919b4858SJagan Teki if (err) 2118919b4858SJagan Teki printf("%s: %d, time %lu\n", __func__, err, get_timer(start)); 2119919b4858SJagan Teki 2120bc897b1dSLei Wen return err; 2121272cc70bSAndy Fleming } 2122272cc70bSAndy Fleming 2123ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val) 2124ab71188cSMarkus Niebel { 2125ab71188cSMarkus Niebel mmc->dsr = val; 2126ab71188cSMarkus Niebel return 0; 2127ab71188cSMarkus Niebel } 2128ab71188cSMarkus Niebel 2129cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */ 2130cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis) 2131272cc70bSAndy Fleming { 2132272cc70bSAndy Fleming return -1; 2133272cc70bSAndy Fleming } 2134272cc70bSAndy Fleming 2135cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */ 2136cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis) 2137cee9ab7cSJeroen Hofstee { 2138cee9ab7cSJeroen Hofstee return -1; 2139cee9ab7cSJeroen Hofstee } 2140272cc70bSAndy Fleming 2141e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit) 2142e9550449SChe-Liang Chiou { 2143e9550449SChe-Liang Chiou mmc->preinit = preinit; 2144e9550449SChe-Liang Chiou } 2145e9550449SChe-Liang Chiou 2146c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD) 21478e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 21488e3332e2SSjoerd Simons { 21498e3332e2SSjoerd Simons return 0; 21508e3332e2SSjoerd Simons } 2151c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC) 21528e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 21538e3332e2SSjoerd Simons { 21544a1db6d8SSimon Glass int ret, i; 21558e3332e2SSjoerd Simons struct uclass *uc; 21564a1db6d8SSimon Glass struct udevice *dev; 21578e3332e2SSjoerd Simons 21588e3332e2SSjoerd Simons ret = uclass_get(UCLASS_MMC, &uc); 21598e3332e2SSjoerd Simons if (ret) 21608e3332e2SSjoerd Simons return ret; 21618e3332e2SSjoerd Simons 21624a1db6d8SSimon Glass /* 21634a1db6d8SSimon Glass * Try to add them in sequence order. Really with driver model we 21644a1db6d8SSimon Glass * should allow holes, but the current MMC list does not allow that. 21654a1db6d8SSimon Glass * So if we request 0, 1, 3 we will get 0, 1, 2. 21664a1db6d8SSimon Glass */ 21674a1db6d8SSimon Glass for (i = 0; ; i++) { 21684a1db6d8SSimon Glass ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev); 21694a1db6d8SSimon Glass if (ret == -ENODEV) 21704a1db6d8SSimon Glass break; 21714a1db6d8SSimon Glass } 21724a1db6d8SSimon Glass uclass_foreach_dev(dev, uc) { 21734a1db6d8SSimon Glass ret = device_probe(dev); 21748e3332e2SSjoerd Simons if (ret) 21754a1db6d8SSimon Glass printf("%s - probe failed: %d\n", dev->name, ret); 21768e3332e2SSjoerd Simons } 21778e3332e2SSjoerd Simons 21788e3332e2SSjoerd Simons return 0; 21798e3332e2SSjoerd Simons } 21808e3332e2SSjoerd Simons #else 21818e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 21828e3332e2SSjoerd Simons { 21838e3332e2SSjoerd Simons if (board_mmc_init(bis) < 0) 21848e3332e2SSjoerd Simons cpu_mmc_init(bis); 21858e3332e2SSjoerd Simons 21868e3332e2SSjoerd Simons return 0; 21878e3332e2SSjoerd Simons } 21888e3332e2SSjoerd Simons #endif 2189e9550449SChe-Liang Chiou 2190272cc70bSAndy Fleming int mmc_initialize(bd_t *bis) 2191272cc70bSAndy Fleming { 21921b26bab1SDaniel Kochmański static int initialized = 0; 21938e3332e2SSjoerd Simons int ret; 21941b26bab1SDaniel Kochmański if (initialized) /* Avoid initializing mmc multiple times */ 21951b26bab1SDaniel Kochmański return 0; 21961b26bab1SDaniel Kochmański initialized = 1; 21971b26bab1SDaniel Kochmański 2198c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK) 2199b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY) 2200c40fdca6SSimon Glass mmc_list_init(); 2201c40fdca6SSimon Glass #endif 2202b5b838f1SMarek Vasut #endif 22038e3332e2SSjoerd Simons ret = mmc_probe(bis); 22048e3332e2SSjoerd Simons if (ret) 22058e3332e2SSjoerd Simons return ret; 2206272cc70bSAndy Fleming 2207bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD 2208272cc70bSAndy Fleming print_mmc_devices(','); 2209bb0dc108SYing Zhang #endif 2210272cc70bSAndy Fleming 2211c40fdca6SSimon Glass mmc_do_preinit(); 2212272cc70bSAndy Fleming return 0; 2213272cc70bSAndy Fleming } 2214cd3d4880STomas Melin 2215cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE 2216cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc) 2217cd3d4880STomas Melin { 2218cd3d4880STomas Melin int err; 2219cd3d4880STomas Melin ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 2220cd3d4880STomas Melin 2221cd3d4880STomas Melin err = mmc_send_ext_csd(mmc, ext_csd); 2222cd3d4880STomas Melin if (err) { 2223cd3d4880STomas Melin puts("Could not get ext_csd register values\n"); 2224cd3d4880STomas Melin return err; 2225cd3d4880STomas Melin } 2226cd3d4880STomas Melin 2227cd3d4880STomas Melin if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) { 2228cd3d4880STomas Melin puts("Background operations not supported on device\n"); 2229cd3d4880STomas Melin return -EMEDIUMTYPE; 2230cd3d4880STomas Melin } 2231cd3d4880STomas Melin 2232cd3d4880STomas Melin if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) { 2233cd3d4880STomas Melin puts("Background operations already enabled\n"); 2234cd3d4880STomas Melin return 0; 2235cd3d4880STomas Melin } 2236cd3d4880STomas Melin 2237cd3d4880STomas Melin err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1); 2238cd3d4880STomas Melin if (err) { 2239cd3d4880STomas Melin puts("Failed to enable manual background operations\n"); 2240cd3d4880STomas Melin return err; 2241cd3d4880STomas Melin } 2242cd3d4880STomas Melin 2243cd3d4880STomas Melin puts("Enabled manual background operations\n"); 2244cd3d4880STomas Melin 2245cd3d4880STomas Melin return 0; 2246cd3d4880STomas Melin } 2247cd3d4880STomas Melin #endif 2248