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); 34aff5d3c8SKishon Vijay Abraham I 35b5b838f1SMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY) 36b5b838f1SMarek Vasut static struct mmc mmc_static; 37b5b838f1SMarek Vasut struct mmc *find_mmc_device(int dev_num) 38b5b838f1SMarek Vasut { 39b5b838f1SMarek Vasut return &mmc_static; 40b5b838f1SMarek Vasut } 41b5b838f1SMarek Vasut 42b5b838f1SMarek Vasut void mmc_do_preinit(void) 43b5b838f1SMarek Vasut { 44b5b838f1SMarek Vasut struct mmc *m = &mmc_static; 45b5b838f1SMarek Vasut #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 46b5b838f1SMarek Vasut mmc_set_preinit(m, 1); 47b5b838f1SMarek Vasut #endif 48b5b838f1SMarek Vasut if (m->preinit) 49b5b838f1SMarek Vasut mmc_start_init(m); 50b5b838f1SMarek Vasut } 51b5b838f1SMarek Vasut 52b5b838f1SMarek Vasut struct blk_desc *mmc_get_blk_desc(struct mmc *mmc) 53b5b838f1SMarek Vasut { 54b5b838f1SMarek Vasut return &mmc->block_dev; 55b5b838f1SMarek Vasut } 56b5b838f1SMarek Vasut #endif 57b5b838f1SMarek Vasut 58e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 59750121c3SJeroen Hofstee __weak int board_mmc_getwp(struct mmc *mmc) 60d23d8d7eSNikita Kiryanov { 61d23d8d7eSNikita Kiryanov return -1; 62d23d8d7eSNikita Kiryanov } 63d23d8d7eSNikita Kiryanov 64d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc) 65d23d8d7eSNikita Kiryanov { 66d23d8d7eSNikita Kiryanov int wp; 67d23d8d7eSNikita Kiryanov 68d23d8d7eSNikita Kiryanov wp = board_mmc_getwp(mmc); 69d23d8d7eSNikita Kiryanov 70d4e1da4eSPeter Korsgaard if (wp < 0) { 7193bfd616SPantelis Antoniou if (mmc->cfg->ops->getwp) 7293bfd616SPantelis Antoniou wp = mmc->cfg->ops->getwp(mmc); 73d4e1da4eSPeter Korsgaard else 74d4e1da4eSPeter Korsgaard wp = 0; 75d4e1da4eSPeter Korsgaard } 76d23d8d7eSNikita Kiryanov 77d23d8d7eSNikita Kiryanov return wp; 78d23d8d7eSNikita Kiryanov } 79d23d8d7eSNikita Kiryanov 80cee9ab7cSJeroen Hofstee __weak int board_mmc_getcd(struct mmc *mmc) 81cee9ab7cSJeroen Hofstee { 8211fdade2SStefano Babic return -1; 8311fdade2SStefano Babic } 848ca51e51SSimon Glass #endif 8511fdade2SStefano Babic 868635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE 87c0c76ebaSSimon Glass void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd) 88c0c76ebaSSimon Glass { 89c0c76ebaSSimon Glass printf("CMD_SEND:%d\n", cmd->cmdidx); 90c0c76ebaSSimon Glass printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg); 91c0c76ebaSSimon Glass } 92c0c76ebaSSimon Glass 93c0c76ebaSSimon Glass void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret) 94c0c76ebaSSimon Glass { 955db2fe3aSRaffaele Recalcati int i; 965db2fe3aSRaffaele Recalcati u8 *ptr; 975db2fe3aSRaffaele Recalcati 987863ce58SBin Meng if (ret) { 997863ce58SBin Meng printf("\t\tRET\t\t\t %d\n", ret); 1007863ce58SBin Meng } else { 1015db2fe3aSRaffaele Recalcati switch (cmd->resp_type) { 1025db2fe3aSRaffaele Recalcati case MMC_RSP_NONE: 1035db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_NONE\n"); 1045db2fe3aSRaffaele Recalcati break; 1055db2fe3aSRaffaele Recalcati case MMC_RSP_R1: 1065db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n", 1075db2fe3aSRaffaele Recalcati cmd->response[0]); 1085db2fe3aSRaffaele Recalcati break; 1095db2fe3aSRaffaele Recalcati case MMC_RSP_R1b: 1105db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n", 1115db2fe3aSRaffaele Recalcati cmd->response[0]); 1125db2fe3aSRaffaele Recalcati break; 1135db2fe3aSRaffaele Recalcati case MMC_RSP_R2: 1145db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R2\t\t 0x%08X \n", 1155db2fe3aSRaffaele Recalcati cmd->response[0]); 1165db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1175db2fe3aSRaffaele Recalcati cmd->response[1]); 1185db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1195db2fe3aSRaffaele Recalcati cmd->response[2]); 1205db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1215db2fe3aSRaffaele Recalcati cmd->response[3]); 1225db2fe3aSRaffaele Recalcati printf("\n"); 1235db2fe3aSRaffaele Recalcati printf("\t\t\t\t\tDUMPING DATA\n"); 1245db2fe3aSRaffaele Recalcati for (i = 0; i < 4; i++) { 1255db2fe3aSRaffaele Recalcati int j; 1265db2fe3aSRaffaele Recalcati printf("\t\t\t\t\t%03d - ", i*4); 127146bec79SDirk Behme ptr = (u8 *)&cmd->response[i]; 1285db2fe3aSRaffaele Recalcati ptr += 3; 1295db2fe3aSRaffaele Recalcati for (j = 0; j < 4; j++) 1305db2fe3aSRaffaele Recalcati printf("%02X ", *ptr--); 1315db2fe3aSRaffaele Recalcati printf("\n"); 1325db2fe3aSRaffaele Recalcati } 1335db2fe3aSRaffaele Recalcati break; 1345db2fe3aSRaffaele Recalcati case MMC_RSP_R3: 1355db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n", 1365db2fe3aSRaffaele Recalcati cmd->response[0]); 1375db2fe3aSRaffaele Recalcati break; 1385db2fe3aSRaffaele Recalcati default: 1395db2fe3aSRaffaele Recalcati printf("\t\tERROR MMC rsp not supported\n"); 1405db2fe3aSRaffaele Recalcati break; 1415db2fe3aSRaffaele Recalcati } 1427863ce58SBin Meng } 143c0c76ebaSSimon Glass } 144c0c76ebaSSimon Glass 145c0c76ebaSSimon Glass void mmc_trace_state(struct mmc *mmc, struct mmc_cmd *cmd) 146c0c76ebaSSimon Glass { 147c0c76ebaSSimon Glass int status; 148c0c76ebaSSimon Glass 149c0c76ebaSSimon Glass status = (cmd->response[0] & MMC_STATUS_CURR_STATE) >> 9; 150c0c76ebaSSimon Glass printf("CURR STATE:%d\n", status); 151c0c76ebaSSimon Glass } 1525db2fe3aSRaffaele Recalcati #endif 153c0c76ebaSSimon Glass 15435f9e196SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG) 15535f9e196SJean-Jacques Hiblot const char *mmc_mode_name(enum bus_mode mode) 15635f9e196SJean-Jacques Hiblot { 15735f9e196SJean-Jacques Hiblot static const char *const names[] = { 15835f9e196SJean-Jacques Hiblot [MMC_LEGACY] = "MMC legacy", 15935f9e196SJean-Jacques Hiblot [SD_LEGACY] = "SD Legacy", 16035f9e196SJean-Jacques Hiblot [MMC_HS] = "MMC High Speed (26MHz)", 16135f9e196SJean-Jacques Hiblot [SD_HS] = "SD High Speed (50MHz)", 16235f9e196SJean-Jacques Hiblot [UHS_SDR12] = "UHS SDR12 (25MHz)", 16335f9e196SJean-Jacques Hiblot [UHS_SDR25] = "UHS SDR25 (50MHz)", 16435f9e196SJean-Jacques Hiblot [UHS_SDR50] = "UHS SDR50 (100MHz)", 16535f9e196SJean-Jacques Hiblot [UHS_SDR104] = "UHS SDR104 (208MHz)", 16635f9e196SJean-Jacques Hiblot [UHS_DDR50] = "UHS DDR50 (50MHz)", 16735f9e196SJean-Jacques Hiblot [MMC_HS_52] = "MMC High Speed (52MHz)", 16835f9e196SJean-Jacques Hiblot [MMC_DDR_52] = "MMC DDR52 (52MHz)", 16935f9e196SJean-Jacques Hiblot [MMC_HS_200] = "HS200 (200MHz)", 17035f9e196SJean-Jacques Hiblot }; 17135f9e196SJean-Jacques Hiblot 17235f9e196SJean-Jacques Hiblot if (mode >= MMC_MODES_END) 17335f9e196SJean-Jacques Hiblot return "Unknown mode"; 17435f9e196SJean-Jacques Hiblot else 17535f9e196SJean-Jacques Hiblot return names[mode]; 17635f9e196SJean-Jacques Hiblot } 17735f9e196SJean-Jacques Hiblot #endif 17835f9e196SJean-Jacques Hiblot 17905038576SJean-Jacques Hiblot static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode) 18005038576SJean-Jacques Hiblot { 18105038576SJean-Jacques Hiblot static const int freqs[] = { 18205038576SJean-Jacques Hiblot [SD_LEGACY] = 25000000, 18305038576SJean-Jacques Hiblot [MMC_HS] = 26000000, 18405038576SJean-Jacques Hiblot [SD_HS] = 50000000, 18505038576SJean-Jacques Hiblot [UHS_SDR12] = 25000000, 18605038576SJean-Jacques Hiblot [UHS_SDR25] = 50000000, 18705038576SJean-Jacques Hiblot [UHS_SDR50] = 100000000, 18805038576SJean-Jacques Hiblot [UHS_SDR104] = 208000000, 18905038576SJean-Jacques Hiblot [UHS_DDR50] = 50000000, 19005038576SJean-Jacques Hiblot [MMC_HS_52] = 52000000, 19105038576SJean-Jacques Hiblot [MMC_DDR_52] = 52000000, 19205038576SJean-Jacques Hiblot [MMC_HS_200] = 200000000, 19305038576SJean-Jacques Hiblot }; 19405038576SJean-Jacques Hiblot 19505038576SJean-Jacques Hiblot if (mode == MMC_LEGACY) 19605038576SJean-Jacques Hiblot return mmc->legacy_speed; 19705038576SJean-Jacques Hiblot else if (mode >= MMC_MODES_END) 19805038576SJean-Jacques Hiblot return 0; 19905038576SJean-Jacques Hiblot else 20005038576SJean-Jacques Hiblot return freqs[mode]; 20105038576SJean-Jacques Hiblot } 20205038576SJean-Jacques Hiblot 20335f9e196SJean-Jacques Hiblot static int mmc_select_mode(struct mmc *mmc, enum bus_mode mode) 20435f9e196SJean-Jacques Hiblot { 20535f9e196SJean-Jacques Hiblot mmc->selected_mode = mode; 20605038576SJean-Jacques Hiblot mmc->tran_speed = mmc_mode2freq(mmc, mode); 2073862b854SJean-Jacques Hiblot mmc->ddr_mode = mmc_is_mode_ddr(mode); 20835f9e196SJean-Jacques Hiblot debug("selecting mode %s (freq : %d MHz)\n", mmc_mode_name(mode), 20935f9e196SJean-Jacques Hiblot mmc->tran_speed / 1000000); 21035f9e196SJean-Jacques Hiblot return 0; 21135f9e196SJean-Jacques Hiblot } 21235f9e196SJean-Jacques Hiblot 213e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 214c0c76ebaSSimon Glass int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) 215c0c76ebaSSimon Glass { 216c0c76ebaSSimon Glass int ret; 217c0c76ebaSSimon Glass 218c0c76ebaSSimon Glass mmmc_trace_before_send(mmc, cmd); 219c0c76ebaSSimon Glass ret = mmc->cfg->ops->send_cmd(mmc, cmd, data); 220c0c76ebaSSimon Glass mmmc_trace_after_send(mmc, cmd, ret); 221c0c76ebaSSimon Glass 2228635ff9eSMarek Vasut return ret; 223272cc70bSAndy Fleming } 2248ca51e51SSimon Glass #endif 225272cc70bSAndy Fleming 226da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout) 2275d4fc8d9SRaffaele Recalcati { 2285d4fc8d9SRaffaele Recalcati struct mmc_cmd cmd; 229d617c426SJan Kloetzke int err, retries = 5; 2305d4fc8d9SRaffaele Recalcati 2315d4fc8d9SRaffaele Recalcati cmd.cmdidx = MMC_CMD_SEND_STATUS; 2325d4fc8d9SRaffaele Recalcati cmd.resp_type = MMC_RSP_R1; 233aaf3d41aSMarek Vasut if (!mmc_host_is_spi(mmc)) 234aaf3d41aSMarek Vasut cmd.cmdarg = mmc->rca << 16; 2355d4fc8d9SRaffaele Recalcati 2361677eef4SAndrew Gabbasov while (1) { 2375d4fc8d9SRaffaele Recalcati err = mmc_send_cmd(mmc, &cmd, NULL); 238d617c426SJan Kloetzke if (!err) { 239d617c426SJan Kloetzke if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) && 240d617c426SJan Kloetzke (cmd.response[0] & MMC_STATUS_CURR_STATE) != 241d617c426SJan Kloetzke MMC_STATE_PRG) 2425d4fc8d9SRaffaele Recalcati break; 243d0c221feSJean-Jacques Hiblot 244d0c221feSJean-Jacques Hiblot if (cmd.response[0] & MMC_STATUS_MASK) { 24556196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 246d617c426SJan Kloetzke printf("Status Error: 0x%08X\n", 247d617c426SJan Kloetzke cmd.response[0]); 24856196826SPaul Burton #endif 249915ffa52SJaehoon Chung return -ECOMM; 250d617c426SJan Kloetzke } 251d617c426SJan Kloetzke } else if (--retries < 0) 252d617c426SJan Kloetzke return err; 2535d4fc8d9SRaffaele Recalcati 2541677eef4SAndrew Gabbasov if (timeout-- <= 0) 2551677eef4SAndrew Gabbasov break; 2565d4fc8d9SRaffaele Recalcati 2571677eef4SAndrew Gabbasov udelay(1000); 2581677eef4SAndrew Gabbasov } 2595d4fc8d9SRaffaele Recalcati 260c0c76ebaSSimon Glass mmc_trace_state(mmc, &cmd); 2615b0c942fSJongman Heo if (timeout <= 0) { 26256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2635d4fc8d9SRaffaele Recalcati printf("Timeout waiting card ready\n"); 26456196826SPaul Burton #endif 265915ffa52SJaehoon Chung return -ETIMEDOUT; 2665d4fc8d9SRaffaele Recalcati } 2675d4fc8d9SRaffaele Recalcati 2685d4fc8d9SRaffaele Recalcati return 0; 2695d4fc8d9SRaffaele Recalcati } 2705d4fc8d9SRaffaele Recalcati 271da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len) 272272cc70bSAndy Fleming { 273272cc70bSAndy Fleming struct mmc_cmd cmd; 274272cc70bSAndy Fleming 275786e8f81SAndrew Gabbasov if (mmc->ddr_mode) 276d22e3d46SJaehoon Chung return 0; 277d22e3d46SJaehoon Chung 278272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SET_BLOCKLEN; 279272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 280272cc70bSAndy Fleming cmd.cmdarg = len; 281272cc70bSAndy Fleming 282272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, NULL); 283272cc70bSAndy Fleming } 284272cc70bSAndy Fleming 285ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start, 286fdbb873eSKim Phillips lbaint_t blkcnt) 287272cc70bSAndy Fleming { 288272cc70bSAndy Fleming struct mmc_cmd cmd; 289272cc70bSAndy Fleming struct mmc_data data; 290272cc70bSAndy Fleming 2914a1a06bcSAlagu Sankar if (blkcnt > 1) 2924a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; 2934a1a06bcSAlagu Sankar else 294272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; 295272cc70bSAndy Fleming 296272cc70bSAndy Fleming if (mmc->high_capacity) 2974a1a06bcSAlagu Sankar cmd.cmdarg = start; 298272cc70bSAndy Fleming else 2994a1a06bcSAlagu Sankar cmd.cmdarg = start * mmc->read_bl_len; 300272cc70bSAndy Fleming 301272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 302272cc70bSAndy Fleming 303272cc70bSAndy Fleming data.dest = dst; 3044a1a06bcSAlagu Sankar data.blocks = blkcnt; 305272cc70bSAndy Fleming data.blocksize = mmc->read_bl_len; 306272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 307272cc70bSAndy Fleming 3084a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, &data)) 3094a1a06bcSAlagu Sankar return 0; 3104a1a06bcSAlagu Sankar 3114a1a06bcSAlagu Sankar if (blkcnt > 1) { 3124a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; 3134a1a06bcSAlagu Sankar cmd.cmdarg = 0; 3144a1a06bcSAlagu Sankar cmd.resp_type = MMC_RSP_R1b; 3154a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, NULL)) { 31656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 3174a1a06bcSAlagu Sankar printf("mmc fail to send stop cmd\n"); 31856196826SPaul Burton #endif 3194a1a06bcSAlagu Sankar return 0; 3204a1a06bcSAlagu Sankar } 321272cc70bSAndy Fleming } 322272cc70bSAndy Fleming 3234a1a06bcSAlagu Sankar return blkcnt; 324272cc70bSAndy Fleming } 325272cc70bSAndy Fleming 326c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK) 3277dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst) 32833fb211dSSimon Glass #else 3297dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, 3307dba0b93SSimon Glass void *dst) 33133fb211dSSimon Glass #endif 332272cc70bSAndy Fleming { 333c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK) 33433fb211dSSimon Glass struct blk_desc *block_dev = dev_get_uclass_platdata(dev); 33533fb211dSSimon Glass #endif 336bcce53d0SSimon Glass int dev_num = block_dev->devnum; 337873cc1d7SStephen Warren int err; 3384a1a06bcSAlagu Sankar lbaint_t cur, blocks_todo = blkcnt; 339272cc70bSAndy Fleming 3404a1a06bcSAlagu Sankar if (blkcnt == 0) 3414a1a06bcSAlagu Sankar return 0; 3424a1a06bcSAlagu Sankar 3434a1a06bcSAlagu Sankar struct mmc *mmc = find_mmc_device(dev_num); 344272cc70bSAndy Fleming if (!mmc) 345272cc70bSAndy Fleming return 0; 346272cc70bSAndy Fleming 347b5b838f1SMarek Vasut if (CONFIG_IS_ENABLED(MMC_TINY)) 348b5b838f1SMarek Vasut err = mmc_switch_part(mmc, block_dev->hwpart); 349b5b838f1SMarek Vasut else 35069f45cd5SSimon Glass err = blk_dselect_hwpart(block_dev, block_dev->hwpart); 351b5b838f1SMarek Vasut 352873cc1d7SStephen Warren if (err < 0) 353873cc1d7SStephen Warren return 0; 354873cc1d7SStephen Warren 355c40fdca6SSimon Glass if ((start + blkcnt) > block_dev->lba) { 35656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 357ff8fef56SSascha Silbe printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", 358c40fdca6SSimon Glass start + blkcnt, block_dev->lba); 35956196826SPaul Burton #endif 360d2bf29e3SLei Wen return 0; 361d2bf29e3SLei Wen } 362272cc70bSAndy Fleming 36311692991SSimon Glass if (mmc_set_blocklen(mmc, mmc->read_bl_len)) { 36411692991SSimon Glass debug("%s: Failed to set blocklen\n", __func__); 365272cc70bSAndy Fleming return 0; 36611692991SSimon Glass } 367272cc70bSAndy Fleming 3684a1a06bcSAlagu Sankar do { 36993bfd616SPantelis Antoniou cur = (blocks_todo > mmc->cfg->b_max) ? 37093bfd616SPantelis Antoniou mmc->cfg->b_max : blocks_todo; 37111692991SSimon Glass if (mmc_read_blocks(mmc, dst, start, cur) != cur) { 37211692991SSimon Glass debug("%s: Failed to read blocks\n", __func__); 3734a1a06bcSAlagu Sankar return 0; 37411692991SSimon Glass } 3754a1a06bcSAlagu Sankar blocks_todo -= cur; 3764a1a06bcSAlagu Sankar start += cur; 3774a1a06bcSAlagu Sankar dst += cur * mmc->read_bl_len; 3784a1a06bcSAlagu Sankar } while (blocks_todo > 0); 379272cc70bSAndy Fleming 380272cc70bSAndy Fleming return blkcnt; 381272cc70bSAndy Fleming } 382272cc70bSAndy Fleming 383fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc) 384272cc70bSAndy Fleming { 385272cc70bSAndy Fleming struct mmc_cmd cmd; 386272cc70bSAndy Fleming int err; 387272cc70bSAndy Fleming 388272cc70bSAndy Fleming udelay(1000); 389272cc70bSAndy Fleming 390272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_GO_IDLE_STATE; 391272cc70bSAndy Fleming cmd.cmdarg = 0; 392272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_NONE; 393272cc70bSAndy Fleming 394272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 395272cc70bSAndy Fleming 396272cc70bSAndy Fleming if (err) 397272cc70bSAndy Fleming return err; 398272cc70bSAndy Fleming 399272cc70bSAndy Fleming udelay(2000); 400272cc70bSAndy Fleming 401272cc70bSAndy Fleming return 0; 402272cc70bSAndy Fleming } 403272cc70bSAndy Fleming 404fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc) 405272cc70bSAndy Fleming { 406272cc70bSAndy Fleming int timeout = 1000; 407272cc70bSAndy Fleming int err; 408272cc70bSAndy Fleming struct mmc_cmd cmd; 409272cc70bSAndy Fleming 4101677eef4SAndrew Gabbasov while (1) { 411272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 412272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 413272cc70bSAndy Fleming cmd.cmdarg = 0; 414272cc70bSAndy Fleming 415272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 416272cc70bSAndy Fleming 417272cc70bSAndy Fleming if (err) 418272cc70bSAndy Fleming return err; 419272cc70bSAndy Fleming 420272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_OP_COND; 421272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R3; 422250de12bSStefano Babic 423250de12bSStefano Babic /* 424250de12bSStefano Babic * Most cards do not answer if some reserved bits 425250de12bSStefano Babic * in the ocr are set. However, Some controller 426250de12bSStefano Babic * can set bit 7 (reserved for low voltages), but 427250de12bSStefano Babic * how to manage low voltages SD card is not yet 428250de12bSStefano Babic * specified. 429250de12bSStefano Babic */ 430d52ebf10SThomas Chou cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 : 43193bfd616SPantelis Antoniou (mmc->cfg->voltages & 0xff8000); 432272cc70bSAndy Fleming 433272cc70bSAndy Fleming if (mmc->version == SD_VERSION_2) 434272cc70bSAndy Fleming cmd.cmdarg |= OCR_HCS; 435272cc70bSAndy Fleming 436272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 437272cc70bSAndy Fleming 438272cc70bSAndy Fleming if (err) 439272cc70bSAndy Fleming return err; 440272cc70bSAndy Fleming 4411677eef4SAndrew Gabbasov if (cmd.response[0] & OCR_BUSY) 4421677eef4SAndrew Gabbasov break; 443272cc70bSAndy Fleming 4441677eef4SAndrew Gabbasov if (timeout-- <= 0) 445915ffa52SJaehoon Chung return -EOPNOTSUPP; 446272cc70bSAndy Fleming 4471677eef4SAndrew Gabbasov udelay(1000); 4481677eef4SAndrew Gabbasov } 4491677eef4SAndrew Gabbasov 450272cc70bSAndy Fleming if (mmc->version != SD_VERSION_2) 451272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 452272cc70bSAndy Fleming 453d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 454d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 455d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 456d52ebf10SThomas Chou cmd.cmdarg = 0; 457d52ebf10SThomas Chou 458d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 459d52ebf10SThomas Chou 460d52ebf10SThomas Chou if (err) 461d52ebf10SThomas Chou return err; 462d52ebf10SThomas Chou } 463d52ebf10SThomas Chou 464998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 465272cc70bSAndy Fleming 466272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 467272cc70bSAndy Fleming mmc->rca = 0; 468272cc70bSAndy Fleming 469272cc70bSAndy Fleming return 0; 470272cc70bSAndy Fleming } 471272cc70bSAndy Fleming 4725289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg) 473272cc70bSAndy Fleming { 4745289b535SAndrew Gabbasov struct mmc_cmd cmd; 475272cc70bSAndy Fleming int err; 476272cc70bSAndy Fleming 4775289b535SAndrew Gabbasov cmd.cmdidx = MMC_CMD_SEND_OP_COND; 4785289b535SAndrew Gabbasov cmd.resp_type = MMC_RSP_R3; 4795289b535SAndrew Gabbasov cmd.cmdarg = 0; 4805a20397bSRob Herring if (use_arg && !mmc_host_is_spi(mmc)) 4815a20397bSRob Herring cmd.cmdarg = OCR_HCS | 48293bfd616SPantelis Antoniou (mmc->cfg->voltages & 483a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_VOLTAGE_MASK)) | 484a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_ACCESS_MODE); 485e9550449SChe-Liang Chiou 4865289b535SAndrew Gabbasov err = mmc_send_cmd(mmc, &cmd, NULL); 487e9550449SChe-Liang Chiou if (err) 488e9550449SChe-Liang Chiou return err; 4895289b535SAndrew Gabbasov mmc->ocr = cmd.response[0]; 490e9550449SChe-Liang Chiou return 0; 491e9550449SChe-Liang Chiou } 492e9550449SChe-Liang Chiou 493750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc) 494e9550449SChe-Liang Chiou { 495e9550449SChe-Liang Chiou int err, i; 496e9550449SChe-Liang Chiou 497272cc70bSAndy Fleming /* Some cards seem to need this */ 498272cc70bSAndy Fleming mmc_go_idle(mmc); 499272cc70bSAndy Fleming 50031cacbabSRaffaele Recalcati /* Asking to the card its capabilities */ 501e9550449SChe-Liang Chiou for (i = 0; i < 2; i++) { 5025289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, i != 0); 50331cacbabSRaffaele Recalcati if (err) 50431cacbabSRaffaele Recalcati return err; 50531cacbabSRaffaele Recalcati 506e9550449SChe-Liang Chiou /* exit if not busy (flag seems to be inverted) */ 507a626c8d4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 508bd47c135SAndrew Gabbasov break; 509e9550449SChe-Liang Chiou } 510bd47c135SAndrew Gabbasov mmc->op_cond_pending = 1; 511bd47c135SAndrew Gabbasov return 0; 512e9550449SChe-Liang Chiou } 51331cacbabSRaffaele Recalcati 514750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc) 515e9550449SChe-Liang Chiou { 516e9550449SChe-Liang Chiou struct mmc_cmd cmd; 517e9550449SChe-Liang Chiou int timeout = 1000; 518e9550449SChe-Liang Chiou uint start; 519e9550449SChe-Liang Chiou int err; 520e9550449SChe-Liang Chiou 521e9550449SChe-Liang Chiou mmc->op_cond_pending = 0; 522cc17c01fSAndrew Gabbasov if (!(mmc->ocr & OCR_BUSY)) { 523d188b113SYangbo Lu /* Some cards seem to need this */ 524d188b113SYangbo Lu mmc_go_idle(mmc); 525d188b113SYangbo Lu 526e9550449SChe-Liang Chiou start = get_timer(0); 5271677eef4SAndrew Gabbasov while (1) { 5285289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, 1); 529272cc70bSAndy Fleming if (err) 530272cc70bSAndy Fleming return err; 5311677eef4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 5321677eef4SAndrew Gabbasov break; 533e9550449SChe-Liang Chiou if (get_timer(start) > timeout) 534915ffa52SJaehoon Chung return -EOPNOTSUPP; 535e9550449SChe-Liang Chiou udelay(100); 5361677eef4SAndrew Gabbasov } 537cc17c01fSAndrew Gabbasov } 538272cc70bSAndy Fleming 539d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 540d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 541d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 542d52ebf10SThomas Chou cmd.cmdarg = 0; 543d52ebf10SThomas Chou 544d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 545d52ebf10SThomas Chou 546d52ebf10SThomas Chou if (err) 547d52ebf10SThomas Chou return err; 548a626c8d4SAndrew Gabbasov 549a626c8d4SAndrew Gabbasov mmc->ocr = cmd.response[0]; 550d52ebf10SThomas Chou } 551d52ebf10SThomas Chou 552272cc70bSAndy Fleming mmc->version = MMC_VERSION_UNKNOWN; 553272cc70bSAndy Fleming 554272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 555def816a2SStephen Warren mmc->rca = 1; 556272cc70bSAndy Fleming 557272cc70bSAndy Fleming return 0; 558272cc70bSAndy Fleming } 559272cc70bSAndy Fleming 560272cc70bSAndy Fleming 561fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) 562272cc70bSAndy Fleming { 563272cc70bSAndy Fleming struct mmc_cmd cmd; 564272cc70bSAndy Fleming struct mmc_data data; 565272cc70bSAndy Fleming int err; 566272cc70bSAndy Fleming 567272cc70bSAndy Fleming /* Get the Card Status Register */ 568272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_EXT_CSD; 569272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 570272cc70bSAndy Fleming cmd.cmdarg = 0; 571272cc70bSAndy Fleming 572cdfd1ac6SYoshihiro Shimoda data.dest = (char *)ext_csd; 573272cc70bSAndy Fleming data.blocks = 1; 5748bfa195eSSimon Glass data.blocksize = MMC_MAX_BLOCK_LEN; 575272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 576272cc70bSAndy Fleming 577272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 578272cc70bSAndy Fleming 579272cc70bSAndy Fleming return err; 580272cc70bSAndy Fleming } 581272cc70bSAndy Fleming 582c40704f4SSimon Glass int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) 583272cc70bSAndy Fleming { 584272cc70bSAndy Fleming struct mmc_cmd cmd; 5855d4fc8d9SRaffaele Recalcati int timeout = 1000; 586a9003dc6SMaxime Ripard int retries = 3; 5875d4fc8d9SRaffaele Recalcati int ret; 588272cc70bSAndy Fleming 589272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SWITCH; 590272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 591272cc70bSAndy Fleming cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 592272cc70bSAndy Fleming (index << 16) | 593272cc70bSAndy Fleming (value << 8); 594272cc70bSAndy Fleming 595a9003dc6SMaxime Ripard while (retries > 0) { 5965d4fc8d9SRaffaele Recalcati ret = mmc_send_cmd(mmc, &cmd, NULL); 5975d4fc8d9SRaffaele Recalcati 5985d4fc8d9SRaffaele Recalcati /* Waiting for the ready status */ 599a9003dc6SMaxime Ripard if (!ret) { 60093ad0d18SJan Kloetzke ret = mmc_send_status(mmc, timeout); 601a9003dc6SMaxime Ripard return ret; 602a9003dc6SMaxime Ripard } 603a9003dc6SMaxime Ripard 604a9003dc6SMaxime Ripard retries--; 605a9003dc6SMaxime Ripard } 6065d4fc8d9SRaffaele Recalcati 6075d4fc8d9SRaffaele Recalcati return ret; 6085d4fc8d9SRaffaele Recalcati 609272cc70bSAndy Fleming } 610272cc70bSAndy Fleming 6113862b854SJean-Jacques Hiblot static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode) 612272cc70bSAndy Fleming { 613272cc70bSAndy Fleming int err; 6143862b854SJean-Jacques Hiblot int speed_bits; 6153862b854SJean-Jacques Hiblot 6163862b854SJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 6173862b854SJean-Jacques Hiblot 6183862b854SJean-Jacques Hiblot switch (mode) { 6193862b854SJean-Jacques Hiblot case MMC_HS: 6203862b854SJean-Jacques Hiblot case MMC_HS_52: 6213862b854SJean-Jacques Hiblot case MMC_DDR_52: 6223862b854SJean-Jacques Hiblot speed_bits = EXT_CSD_TIMING_HS; 6233862b854SJean-Jacques Hiblot case MMC_LEGACY: 6243862b854SJean-Jacques Hiblot speed_bits = EXT_CSD_TIMING_LEGACY; 6253862b854SJean-Jacques Hiblot break; 6263862b854SJean-Jacques Hiblot default: 6273862b854SJean-Jacques Hiblot return -EINVAL; 6283862b854SJean-Jacques Hiblot } 6293862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 6303862b854SJean-Jacques Hiblot speed_bits); 6313862b854SJean-Jacques Hiblot if (err) 6323862b854SJean-Jacques Hiblot return err; 6333862b854SJean-Jacques Hiblot 6343862b854SJean-Jacques Hiblot if ((mode == MMC_HS) || (mode == MMC_HS_52)) { 6353862b854SJean-Jacques Hiblot /* Now check to see that it worked */ 6363862b854SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, test_csd); 6373862b854SJean-Jacques Hiblot if (err) 6383862b854SJean-Jacques Hiblot return err; 6393862b854SJean-Jacques Hiblot 6403862b854SJean-Jacques Hiblot /* No high-speed support */ 6413862b854SJean-Jacques Hiblot if (!test_csd[EXT_CSD_HS_TIMING]) 6423862b854SJean-Jacques Hiblot return -ENOTSUPP; 6433862b854SJean-Jacques Hiblot } 6443862b854SJean-Jacques Hiblot 6453862b854SJean-Jacques Hiblot return 0; 6463862b854SJean-Jacques Hiblot } 6473862b854SJean-Jacques Hiblot 6483862b854SJean-Jacques Hiblot static int mmc_get_capabilities(struct mmc *mmc) 6493862b854SJean-Jacques Hiblot { 6503862b854SJean-Jacques Hiblot u8 *ext_csd = mmc->ext_csd; 6513862b854SJean-Jacques Hiblot char cardtype; 652272cc70bSAndy Fleming 653d0c221feSJean-Jacques Hiblot mmc->card_caps = MMC_MODE_1BIT; 654272cc70bSAndy Fleming 655d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 656d52ebf10SThomas Chou return 0; 657d52ebf10SThomas Chou 658272cc70bSAndy Fleming /* Only version 4 supports high-speed */ 659272cc70bSAndy Fleming if (mmc->version < MMC_VERSION_4) 660272cc70bSAndy Fleming return 0; 661272cc70bSAndy Fleming 6623862b854SJean-Jacques Hiblot if (!ext_csd) { 6633862b854SJean-Jacques Hiblot printf("No ext_csd found!\n"); /* this should enver happen */ 6643862b854SJean-Jacques Hiblot return -ENOTSUPP; 6653862b854SJean-Jacques Hiblot } 6663862b854SJean-Jacques Hiblot 667fc5b32fbSAndrew Gabbasov mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; 668fc5b32fbSAndrew Gabbasov 6690560db18SLei Wen cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf; 670272cc70bSAndy Fleming 671272cc70bSAndy Fleming /* High Speed is set, there are two types: 52MHz and 26MHz */ 672d22e3d46SJaehoon Chung if (cardtype & EXT_CSD_CARD_TYPE_52) { 6733862b854SJean-Jacques Hiblot if (cardtype & EXT_CSD_CARD_TYPE_DDR_52) 674d22e3d46SJaehoon Chung mmc->card_caps |= MMC_MODE_DDR_52MHz; 6753862b854SJean-Jacques Hiblot mmc->card_caps |= MMC_MODE_HS_52MHz; 676d22e3d46SJaehoon Chung } 6773862b854SJean-Jacques Hiblot if (cardtype & EXT_CSD_CARD_TYPE_26) 6783862b854SJean-Jacques Hiblot mmc->card_caps |= MMC_MODE_HS; 679272cc70bSAndy Fleming 680272cc70bSAndy Fleming return 0; 681272cc70bSAndy Fleming } 682272cc70bSAndy Fleming 683f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num) 684f866a46dSStephen Warren { 685f866a46dSStephen Warren switch (part_num) { 686f866a46dSStephen Warren case 0: 687f866a46dSStephen Warren mmc->capacity = mmc->capacity_user; 688f866a46dSStephen Warren break; 689f866a46dSStephen Warren case 1: 690f866a46dSStephen Warren case 2: 691f866a46dSStephen Warren mmc->capacity = mmc->capacity_boot; 692f866a46dSStephen Warren break; 693f866a46dSStephen Warren case 3: 694f866a46dSStephen Warren mmc->capacity = mmc->capacity_rpmb; 695f866a46dSStephen Warren break; 696f866a46dSStephen Warren case 4: 697f866a46dSStephen Warren case 5: 698f866a46dSStephen Warren case 6: 699f866a46dSStephen Warren case 7: 700f866a46dSStephen Warren mmc->capacity = mmc->capacity_gp[part_num - 4]; 701f866a46dSStephen Warren break; 702f866a46dSStephen Warren default: 703f866a46dSStephen Warren return -1; 704f866a46dSStephen Warren } 705f866a46dSStephen Warren 706c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len); 707f866a46dSStephen Warren 708f866a46dSStephen Warren return 0; 709f866a46dSStephen Warren } 710f866a46dSStephen Warren 7117dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num) 712bc897b1dSLei Wen { 713f866a46dSStephen Warren int ret; 714bc897b1dSLei Wen 715f866a46dSStephen Warren ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 716bc897b1dSLei Wen (mmc->part_config & ~PART_ACCESS_MASK) 717bc897b1dSLei Wen | (part_num & PART_ACCESS_MASK)); 718f866a46dSStephen Warren 7196dc93e70SPeter Bigot /* 7206dc93e70SPeter Bigot * Set the capacity if the switch succeeded or was intended 7216dc93e70SPeter Bigot * to return to representing the raw device. 7226dc93e70SPeter Bigot */ 723873cc1d7SStephen Warren if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) { 7246dc93e70SPeter Bigot ret = mmc_set_capacity(mmc, part_num); 725fdbb139fSSimon Glass mmc_get_blk_desc(mmc)->hwpart = part_num; 726873cc1d7SStephen Warren } 7276dc93e70SPeter Bigot 7286dc93e70SPeter Bigot return ret; 729bc897b1dSLei Wen } 730bc897b1dSLei Wen 731ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc, 732ac9da0e0SDiego Santa Cruz const struct mmc_hwpart_conf *conf, 733ac9da0e0SDiego Santa Cruz enum mmc_hwpart_conf_mode mode) 734ac9da0e0SDiego Santa Cruz { 735ac9da0e0SDiego Santa Cruz u8 part_attrs = 0; 736ac9da0e0SDiego Santa Cruz u32 enh_size_mult; 737ac9da0e0SDiego Santa Cruz u32 enh_start_addr; 738ac9da0e0SDiego Santa Cruz u32 gp_size_mult[4]; 739ac9da0e0SDiego Santa Cruz u32 max_enh_size_mult; 740ac9da0e0SDiego Santa Cruz u32 tot_enh_size_mult = 0; 7418dda5b0eSDiego Santa Cruz u8 wr_rel_set; 742ac9da0e0SDiego Santa Cruz int i, pidx, err; 743ac9da0e0SDiego Santa Cruz ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 744ac9da0e0SDiego Santa Cruz 745ac9da0e0SDiego Santa Cruz if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE) 746ac9da0e0SDiego Santa Cruz return -EINVAL; 747ac9da0e0SDiego Santa Cruz 748ac9da0e0SDiego Santa Cruz if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) { 749ac9da0e0SDiego Santa Cruz printf("eMMC >= 4.4 required for enhanced user data area\n"); 750ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 751ac9da0e0SDiego Santa Cruz } 752ac9da0e0SDiego Santa Cruz 753ac9da0e0SDiego Santa Cruz if (!(mmc->part_support & PART_SUPPORT)) { 754ac9da0e0SDiego Santa Cruz printf("Card does not support partitioning\n"); 755ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 756ac9da0e0SDiego Santa Cruz } 757ac9da0e0SDiego Santa Cruz 758ac9da0e0SDiego Santa Cruz if (!mmc->hc_wp_grp_size) { 759ac9da0e0SDiego Santa Cruz printf("Card does not define HC WP group size\n"); 760ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 761ac9da0e0SDiego Santa Cruz } 762ac9da0e0SDiego Santa Cruz 763ac9da0e0SDiego Santa Cruz /* check partition alignment and total enhanced size */ 764ac9da0e0SDiego Santa Cruz if (conf->user.enh_size) { 765ac9da0e0SDiego Santa Cruz if (conf->user.enh_size % mmc->hc_wp_grp_size || 766ac9da0e0SDiego Santa Cruz conf->user.enh_start % mmc->hc_wp_grp_size) { 767ac9da0e0SDiego Santa Cruz printf("User data enhanced area not HC WP group " 768ac9da0e0SDiego Santa Cruz "size aligned\n"); 769ac9da0e0SDiego Santa Cruz return -EINVAL; 770ac9da0e0SDiego Santa Cruz } 771ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_USR; 772ac9da0e0SDiego Santa Cruz enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size; 773ac9da0e0SDiego Santa Cruz if (mmc->high_capacity) { 774ac9da0e0SDiego Santa Cruz enh_start_addr = conf->user.enh_start; 775ac9da0e0SDiego Santa Cruz } else { 776ac9da0e0SDiego Santa Cruz enh_start_addr = (conf->user.enh_start << 9); 777ac9da0e0SDiego Santa Cruz } 778ac9da0e0SDiego Santa Cruz } else { 779ac9da0e0SDiego Santa Cruz enh_size_mult = 0; 780ac9da0e0SDiego Santa Cruz enh_start_addr = 0; 781ac9da0e0SDiego Santa Cruz } 782ac9da0e0SDiego Santa Cruz tot_enh_size_mult += enh_size_mult; 783ac9da0e0SDiego Santa Cruz 784ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 785ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) { 786ac9da0e0SDiego Santa Cruz printf("GP%i partition not HC WP group size " 787ac9da0e0SDiego Santa Cruz "aligned\n", pidx+1); 788ac9da0e0SDiego Santa Cruz return -EINVAL; 789ac9da0e0SDiego Santa Cruz } 790ac9da0e0SDiego Santa Cruz gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size; 791ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) { 792ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_GP(pidx); 793ac9da0e0SDiego Santa Cruz tot_enh_size_mult += gp_size_mult[pidx]; 794ac9da0e0SDiego Santa Cruz } 795ac9da0e0SDiego Santa Cruz } 796ac9da0e0SDiego Santa Cruz 797ac9da0e0SDiego Santa Cruz if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) { 798ac9da0e0SDiego Santa Cruz printf("Card does not support enhanced attribute\n"); 799ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 800ac9da0e0SDiego Santa Cruz } 801ac9da0e0SDiego Santa Cruz 802ac9da0e0SDiego Santa Cruz err = mmc_send_ext_csd(mmc, ext_csd); 803ac9da0e0SDiego Santa Cruz if (err) 804ac9da0e0SDiego Santa Cruz return err; 805ac9da0e0SDiego Santa Cruz 806ac9da0e0SDiego Santa Cruz max_enh_size_mult = 807ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) + 808ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) + 809ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]; 810ac9da0e0SDiego Santa Cruz if (tot_enh_size_mult > max_enh_size_mult) { 811ac9da0e0SDiego Santa Cruz printf("Total enhanced size exceeds maximum (%u > %u)\n", 812ac9da0e0SDiego Santa Cruz tot_enh_size_mult, max_enh_size_mult); 813ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 814ac9da0e0SDiego Santa Cruz } 815ac9da0e0SDiego Santa Cruz 8168dda5b0eSDiego Santa Cruz /* The default value of EXT_CSD_WR_REL_SET is device 8178dda5b0eSDiego Santa Cruz * dependent, the values can only be changed if the 8188dda5b0eSDiego Santa Cruz * EXT_CSD_HS_CTRL_REL bit is set. The values can be 8198dda5b0eSDiego Santa Cruz * changed only once and before partitioning is completed. */ 8208dda5b0eSDiego Santa Cruz wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 8218dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_change) { 8228dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_set) 8238dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_USR; 8248dda5b0eSDiego Santa Cruz else 8258dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR; 8268dda5b0eSDiego Santa Cruz } 8278dda5b0eSDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 8288dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_change) { 8298dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_set) 8308dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx); 8318dda5b0eSDiego Santa Cruz else 8328dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx); 8338dda5b0eSDiego Santa Cruz } 8348dda5b0eSDiego Santa Cruz } 8358dda5b0eSDiego Santa Cruz 8368dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] && 8378dda5b0eSDiego Santa Cruz !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) { 8388dda5b0eSDiego Santa Cruz puts("Card does not support host controlled partition write " 8398dda5b0eSDiego Santa Cruz "reliability settings\n"); 8408dda5b0eSDiego Santa Cruz return -EMEDIUMTYPE; 8418dda5b0eSDiego Santa Cruz } 8428dda5b0eSDiego Santa Cruz 843ac9da0e0SDiego Santa Cruz if (ext_csd[EXT_CSD_PARTITION_SETTING] & 844ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED) { 845ac9da0e0SDiego Santa Cruz printf("Card already partitioned\n"); 846ac9da0e0SDiego Santa Cruz return -EPERM; 847ac9da0e0SDiego Santa Cruz } 848ac9da0e0SDiego Santa Cruz 849ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_CHECK) 850ac9da0e0SDiego Santa Cruz return 0; 851ac9da0e0SDiego Santa Cruz 852ac9da0e0SDiego Santa Cruz /* Partitioning requires high-capacity size definitions */ 853ac9da0e0SDiego Santa Cruz if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) { 854ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 855ac9da0e0SDiego Santa Cruz EXT_CSD_ERASE_GROUP_DEF, 1); 856ac9da0e0SDiego Santa Cruz 857ac9da0e0SDiego Santa Cruz if (err) 858ac9da0e0SDiego Santa Cruz return err; 859ac9da0e0SDiego Santa Cruz 860ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 861ac9da0e0SDiego Santa Cruz 862ac9da0e0SDiego Santa Cruz /* update erase group size to be high-capacity */ 863ac9da0e0SDiego Santa Cruz mmc->erase_grp_size = 864ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 865ac9da0e0SDiego Santa Cruz 866ac9da0e0SDiego Santa Cruz } 867ac9da0e0SDiego Santa Cruz 868ac9da0e0SDiego Santa Cruz /* all OK, write the configuration */ 869ac9da0e0SDiego Santa Cruz for (i = 0; i < 4; i++) { 870ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 871ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_START_ADDR+i, 872ac9da0e0SDiego Santa Cruz (enh_start_addr >> (i*8)) & 0xFF); 873ac9da0e0SDiego Santa Cruz if (err) 874ac9da0e0SDiego Santa Cruz return err; 875ac9da0e0SDiego Santa Cruz } 876ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 877ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 878ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_SIZE_MULT+i, 879ac9da0e0SDiego Santa Cruz (enh_size_mult >> (i*8)) & 0xFF); 880ac9da0e0SDiego Santa Cruz if (err) 881ac9da0e0SDiego Santa Cruz return err; 882ac9da0e0SDiego Santa Cruz } 883ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 884ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 885ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 886ac9da0e0SDiego Santa Cruz EXT_CSD_GP_SIZE_MULT+pidx*3+i, 887ac9da0e0SDiego Santa Cruz (gp_size_mult[pidx] >> (i*8)) & 0xFF); 888ac9da0e0SDiego Santa Cruz if (err) 889ac9da0e0SDiego Santa Cruz return err; 890ac9da0e0SDiego Santa Cruz } 891ac9da0e0SDiego Santa Cruz } 892ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 893ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs); 894ac9da0e0SDiego Santa Cruz if (err) 895ac9da0e0SDiego Santa Cruz return err; 896ac9da0e0SDiego Santa Cruz 897ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_SET) 898ac9da0e0SDiego Santa Cruz return 0; 899ac9da0e0SDiego Santa Cruz 9008dda5b0eSDiego Santa Cruz /* The WR_REL_SET is a write-once register but shall be 9018dda5b0eSDiego Santa Cruz * written before setting PART_SETTING_COMPLETED. As it is 9028dda5b0eSDiego Santa Cruz * write-once we can only write it when completing the 9038dda5b0eSDiego Santa Cruz * partitioning. */ 9048dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) { 9058dda5b0eSDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 9068dda5b0eSDiego Santa Cruz EXT_CSD_WR_REL_SET, wr_rel_set); 9078dda5b0eSDiego Santa Cruz if (err) 9088dda5b0eSDiego Santa Cruz return err; 9098dda5b0eSDiego Santa Cruz } 9108dda5b0eSDiego Santa Cruz 911ac9da0e0SDiego Santa Cruz /* Setting PART_SETTING_COMPLETED confirms the partition 912ac9da0e0SDiego Santa Cruz * configuration but it only becomes effective after power 913ac9da0e0SDiego Santa Cruz * cycle, so we do not adjust the partition related settings 914ac9da0e0SDiego Santa Cruz * in the mmc struct. */ 915ac9da0e0SDiego Santa Cruz 916ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 917ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING, 918ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 919ac9da0e0SDiego Santa Cruz if (err) 920ac9da0e0SDiego Santa Cruz return err; 921ac9da0e0SDiego Santa Cruz 922ac9da0e0SDiego Santa Cruz return 0; 923ac9da0e0SDiego Santa Cruz } 924ac9da0e0SDiego Santa Cruz 925e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 92648972d90SThierry Reding int mmc_getcd(struct mmc *mmc) 92748972d90SThierry Reding { 92848972d90SThierry Reding int cd; 92948972d90SThierry Reding 93048972d90SThierry Reding cd = board_mmc_getcd(mmc); 93148972d90SThierry Reding 932d4e1da4eSPeter Korsgaard if (cd < 0) { 93393bfd616SPantelis Antoniou if (mmc->cfg->ops->getcd) 93493bfd616SPantelis Antoniou cd = mmc->cfg->ops->getcd(mmc); 935d4e1da4eSPeter Korsgaard else 936d4e1da4eSPeter Korsgaard cd = 1; 937d4e1da4eSPeter Korsgaard } 93848972d90SThierry Reding 93948972d90SThierry Reding return cd; 94048972d90SThierry Reding } 9418ca51e51SSimon Glass #endif 94248972d90SThierry Reding 943fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) 944272cc70bSAndy Fleming { 945272cc70bSAndy Fleming struct mmc_cmd cmd; 946272cc70bSAndy Fleming struct mmc_data data; 947272cc70bSAndy Fleming 948272cc70bSAndy Fleming /* Switch the frequency */ 949272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC; 950272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 951272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff; 952272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4)); 953272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4); 954272cc70bSAndy Fleming 955272cc70bSAndy Fleming data.dest = (char *)resp; 956272cc70bSAndy Fleming data.blocksize = 64; 957272cc70bSAndy Fleming data.blocks = 1; 958272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 959272cc70bSAndy Fleming 960272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 961272cc70bSAndy Fleming } 962272cc70bSAndy Fleming 963272cc70bSAndy Fleming 964d0c221feSJean-Jacques Hiblot static int sd_get_capabilities(struct mmc *mmc) 965272cc70bSAndy Fleming { 966272cc70bSAndy Fleming int err; 967272cc70bSAndy Fleming struct mmc_cmd cmd; 96818e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2); 96918e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16); 970272cc70bSAndy Fleming struct mmc_data data; 971272cc70bSAndy Fleming int timeout; 972272cc70bSAndy Fleming 973d0c221feSJean-Jacques Hiblot mmc->card_caps = MMC_MODE_1BIT; 974272cc70bSAndy Fleming 975d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 976d52ebf10SThomas Chou return 0; 977d52ebf10SThomas Chou 978272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */ 979272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 980272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 981272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 982272cc70bSAndy Fleming 983272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 984272cc70bSAndy Fleming 985272cc70bSAndy Fleming if (err) 986272cc70bSAndy Fleming return err; 987272cc70bSAndy Fleming 988272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR; 989272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 990272cc70bSAndy Fleming cmd.cmdarg = 0; 991272cc70bSAndy Fleming 992272cc70bSAndy Fleming timeout = 3; 993272cc70bSAndy Fleming 994272cc70bSAndy Fleming retry_scr: 995f781dd38SAnton staaf data.dest = (char *)scr; 996272cc70bSAndy Fleming data.blocksize = 8; 997272cc70bSAndy Fleming data.blocks = 1; 998272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 999272cc70bSAndy Fleming 1000272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 1001272cc70bSAndy Fleming 1002272cc70bSAndy Fleming if (err) { 1003272cc70bSAndy Fleming if (timeout--) 1004272cc70bSAndy Fleming goto retry_scr; 1005272cc70bSAndy Fleming 1006272cc70bSAndy Fleming return err; 1007272cc70bSAndy Fleming } 1008272cc70bSAndy Fleming 10094e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]); 10104e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]); 1011272cc70bSAndy Fleming 1012272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) { 1013272cc70bSAndy Fleming case 0: 1014272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1015272cc70bSAndy Fleming break; 1016272cc70bSAndy Fleming case 1: 1017272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10; 1018272cc70bSAndy Fleming break; 1019272cc70bSAndy Fleming case 2: 1020272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 10211741c64dSJaehoon Chung if ((mmc->scr[0] >> 15) & 0x1) 10221741c64dSJaehoon Chung mmc->version = SD_VERSION_3; 1023272cc70bSAndy Fleming break; 1024272cc70bSAndy Fleming default: 1025272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1026272cc70bSAndy Fleming break; 1027272cc70bSAndy Fleming } 1028272cc70bSAndy Fleming 1029b44c7083SAlagu Sankar if (mmc->scr[0] & SD_DATA_4BIT) 1030b44c7083SAlagu Sankar mmc->card_caps |= MMC_MODE_4BIT; 1031b44c7083SAlagu Sankar 1032272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */ 1033272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0) 1034272cc70bSAndy Fleming return 0; 1035272cc70bSAndy Fleming 1036272cc70bSAndy Fleming timeout = 4; 1037272cc70bSAndy Fleming while (timeout--) { 1038272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, 1039f781dd38SAnton staaf (u8 *)switch_status); 1040272cc70bSAndy Fleming 1041272cc70bSAndy Fleming if (err) 1042272cc70bSAndy Fleming return err; 1043272cc70bSAndy Fleming 1044272cc70bSAndy Fleming /* The high-speed function is busy. Try again */ 10454e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) 1046272cc70bSAndy Fleming break; 1047272cc70bSAndy Fleming } 1048272cc70bSAndy Fleming 1049272cc70bSAndy Fleming /* If high-speed isn't supported, we return */ 1050d0c221feSJean-Jacques Hiblot if (__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED) 1051d0c221feSJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(SD_HS); 1052272cc70bSAndy Fleming 10532c3fbf4cSMacpaul Lin return 0; 1054d0c221feSJean-Jacques Hiblot } 1055d0c221feSJean-Jacques Hiblot 1056d0c221feSJean-Jacques Hiblot static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode) 1057d0c221feSJean-Jacques Hiblot { 1058d0c221feSJean-Jacques Hiblot int err; 1059d0c221feSJean-Jacques Hiblot 1060d0c221feSJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16); 10612c3fbf4cSMacpaul Lin 1062f781dd38SAnton staaf err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status); 1063272cc70bSAndy Fleming if (err) 1064272cc70bSAndy Fleming return err; 1065272cc70bSAndy Fleming 1066d0c221feSJean-Jacques Hiblot if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) != 0x01000000) 1067d0c221feSJean-Jacques Hiblot return -ENOTSUPP; 1068d0c221feSJean-Jacques Hiblot 1069d0c221feSJean-Jacques Hiblot return 0; 1070d0c221feSJean-Jacques Hiblot } 1071d0c221feSJean-Jacques Hiblot 1072d0c221feSJean-Jacques Hiblot int sd_select_bus_width(struct mmc *mmc, int w) 1073d0c221feSJean-Jacques Hiblot { 1074d0c221feSJean-Jacques Hiblot int err; 1075d0c221feSJean-Jacques Hiblot struct mmc_cmd cmd; 1076d0c221feSJean-Jacques Hiblot 1077d0c221feSJean-Jacques Hiblot if ((w != 4) && (w != 1)) 1078d0c221feSJean-Jacques Hiblot return -EINVAL; 1079d0c221feSJean-Jacques Hiblot 1080d0c221feSJean-Jacques Hiblot cmd.cmdidx = MMC_CMD_APP_CMD; 1081d0c221feSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 1082d0c221feSJean-Jacques Hiblot cmd.cmdarg = mmc->rca << 16; 1083d0c221feSJean-Jacques Hiblot 1084d0c221feSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 1085d0c221feSJean-Jacques Hiblot if (err) 1086d0c221feSJean-Jacques Hiblot return err; 1087d0c221feSJean-Jacques Hiblot 1088d0c221feSJean-Jacques Hiblot cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; 1089d0c221feSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 1090d0c221feSJean-Jacques Hiblot if (w == 4) 1091d0c221feSJean-Jacques Hiblot cmd.cmdarg = 2; 1092d0c221feSJean-Jacques Hiblot else if (w == 1) 1093d0c221feSJean-Jacques Hiblot cmd.cmdarg = 0; 1094d0c221feSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 1095d0c221feSJean-Jacques Hiblot if (err) 1096d0c221feSJean-Jacques Hiblot return err; 1097272cc70bSAndy Fleming 1098272cc70bSAndy Fleming return 0; 1099272cc70bSAndy Fleming } 1100272cc70bSAndy Fleming 11013697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc) 11023697e599SPeng Fan { 11033697e599SPeng Fan int err, i; 11043697e599SPeng Fan struct mmc_cmd cmd; 11053697e599SPeng Fan ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16); 11063697e599SPeng Fan struct mmc_data data; 11073697e599SPeng Fan int timeout = 3; 11083697e599SPeng Fan unsigned int au, eo, et, es; 11093697e599SPeng Fan 11103697e599SPeng Fan cmd.cmdidx = MMC_CMD_APP_CMD; 11113697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 11123697e599SPeng Fan cmd.cmdarg = mmc->rca << 16; 11133697e599SPeng Fan 11143697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, NULL); 11153697e599SPeng Fan if (err) 11163697e599SPeng Fan return err; 11173697e599SPeng Fan 11183697e599SPeng Fan cmd.cmdidx = SD_CMD_APP_SD_STATUS; 11193697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 11203697e599SPeng Fan cmd.cmdarg = 0; 11213697e599SPeng Fan 11223697e599SPeng Fan retry_ssr: 11233697e599SPeng Fan data.dest = (char *)ssr; 11243697e599SPeng Fan data.blocksize = 64; 11253697e599SPeng Fan data.blocks = 1; 11263697e599SPeng Fan data.flags = MMC_DATA_READ; 11273697e599SPeng Fan 11283697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, &data); 11293697e599SPeng Fan if (err) { 11303697e599SPeng Fan if (timeout--) 11313697e599SPeng Fan goto retry_ssr; 11323697e599SPeng Fan 11333697e599SPeng Fan return err; 11343697e599SPeng Fan } 11353697e599SPeng Fan 11363697e599SPeng Fan for (i = 0; i < 16; i++) 11373697e599SPeng Fan ssr[i] = be32_to_cpu(ssr[i]); 11383697e599SPeng Fan 11393697e599SPeng Fan au = (ssr[2] >> 12) & 0xF; 11403697e599SPeng Fan if ((au <= 9) || (mmc->version == SD_VERSION_3)) { 11413697e599SPeng Fan mmc->ssr.au = sd_au_size[au]; 11423697e599SPeng Fan es = (ssr[3] >> 24) & 0xFF; 11433697e599SPeng Fan es |= (ssr[2] & 0xFF) << 8; 11443697e599SPeng Fan et = (ssr[3] >> 18) & 0x3F; 11453697e599SPeng Fan if (es && et) { 11463697e599SPeng Fan eo = (ssr[3] >> 16) & 0x3; 11473697e599SPeng Fan mmc->ssr.erase_timeout = (et * 1000) / es; 11483697e599SPeng Fan mmc->ssr.erase_offset = eo * 1000; 11493697e599SPeng Fan } 11503697e599SPeng Fan } else { 11513697e599SPeng Fan debug("Invalid Allocation Unit Size.\n"); 11523697e599SPeng Fan } 11533697e599SPeng Fan 11543697e599SPeng Fan return 0; 11553697e599SPeng Fan } 11563697e599SPeng Fan 1157272cc70bSAndy Fleming /* frequency bases */ 1158272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */ 11595f837c2cSMike Frysinger static const int fbase[] = { 1160272cc70bSAndy Fleming 10000, 1161272cc70bSAndy Fleming 100000, 1162272cc70bSAndy Fleming 1000000, 1163272cc70bSAndy Fleming 10000000, 1164272cc70bSAndy Fleming }; 1165272cc70bSAndy Fleming 1166272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice 1167272cc70bSAndy Fleming * to platforms without floating point. 1168272cc70bSAndy Fleming */ 116961fe076fSSimon Glass static const u8 multipliers[] = { 1170272cc70bSAndy Fleming 0, /* reserved */ 1171272cc70bSAndy Fleming 10, 1172272cc70bSAndy Fleming 12, 1173272cc70bSAndy Fleming 13, 1174272cc70bSAndy Fleming 15, 1175272cc70bSAndy Fleming 20, 1176272cc70bSAndy Fleming 25, 1177272cc70bSAndy Fleming 30, 1178272cc70bSAndy Fleming 35, 1179272cc70bSAndy Fleming 40, 1180272cc70bSAndy Fleming 45, 1181272cc70bSAndy Fleming 50, 1182272cc70bSAndy Fleming 55, 1183272cc70bSAndy Fleming 60, 1184272cc70bSAndy Fleming 70, 1185272cc70bSAndy Fleming 80, 1186272cc70bSAndy Fleming }; 1187272cc70bSAndy Fleming 1188d0c221feSJean-Jacques Hiblot static inline int bus_width(uint cap) 1189d0c221feSJean-Jacques Hiblot { 1190d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_8BIT) 1191d0c221feSJean-Jacques Hiblot return 8; 1192d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_4BIT) 1193d0c221feSJean-Jacques Hiblot return 4; 1194d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_1BIT) 1195d0c221feSJean-Jacques Hiblot return 1; 1196d0c221feSJean-Jacques Hiblot printf("invalid bus witdh capability 0x%x\n", cap); 1197d0c221feSJean-Jacques Hiblot return 0; 1198d0c221feSJean-Jacques Hiblot } 1199d0c221feSJean-Jacques Hiblot 1200e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 1201*318a7a57SJean-Jacques Hiblot static void mmc_send_init_stream(struct mmc *mmc) 1202*318a7a57SJean-Jacques Hiblot { 1203*318a7a57SJean-Jacques Hiblot } 1204*318a7a57SJean-Jacques Hiblot 12052a4d212fSKishon Vijay Abraham I static int mmc_set_ios(struct mmc *mmc) 1206272cc70bSAndy Fleming { 12072a4d212fSKishon Vijay Abraham I int ret = 0; 12082a4d212fSKishon Vijay Abraham I 120993bfd616SPantelis Antoniou if (mmc->cfg->ops->set_ios) 12102a4d212fSKishon Vijay Abraham I ret = mmc->cfg->ops->set_ios(mmc); 12112a4d212fSKishon Vijay Abraham I 12122a4d212fSKishon Vijay Abraham I return ret; 1213272cc70bSAndy Fleming } 12148ca51e51SSimon Glass #endif 1215272cc70bSAndy Fleming 12162a4d212fSKishon Vijay Abraham I int mmc_set_clock(struct mmc *mmc, uint clock) 1217272cc70bSAndy Fleming { 121893bfd616SPantelis Antoniou if (clock > mmc->cfg->f_max) 121993bfd616SPantelis Antoniou clock = mmc->cfg->f_max; 1220272cc70bSAndy Fleming 122193bfd616SPantelis Antoniou if (clock < mmc->cfg->f_min) 122293bfd616SPantelis Antoniou clock = mmc->cfg->f_min; 1223272cc70bSAndy Fleming 1224272cc70bSAndy Fleming mmc->clock = clock; 1225272cc70bSAndy Fleming 12262a4d212fSKishon Vijay Abraham I return mmc_set_ios(mmc); 1227272cc70bSAndy Fleming } 1228272cc70bSAndy Fleming 12292a4d212fSKishon Vijay Abraham I static int mmc_set_bus_width(struct mmc *mmc, uint width) 1230272cc70bSAndy Fleming { 1231272cc70bSAndy Fleming mmc->bus_width = width; 1232272cc70bSAndy Fleming 12332a4d212fSKishon Vijay Abraham I return mmc_set_ios(mmc); 1234272cc70bSAndy Fleming } 1235272cc70bSAndy Fleming 12364c9d2aaaSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG) 12374c9d2aaaSJean-Jacques Hiblot /* 12384c9d2aaaSJean-Jacques Hiblot * helper function to display the capabilities in a human 12394c9d2aaaSJean-Jacques Hiblot * friendly manner. The capabilities include bus width and 12404c9d2aaaSJean-Jacques Hiblot * supported modes. 12414c9d2aaaSJean-Jacques Hiblot */ 12424c9d2aaaSJean-Jacques Hiblot void mmc_dump_capabilities(const char *text, uint caps) 12434c9d2aaaSJean-Jacques Hiblot { 12444c9d2aaaSJean-Jacques Hiblot enum bus_mode mode; 12454c9d2aaaSJean-Jacques Hiblot 12464c9d2aaaSJean-Jacques Hiblot printf("%s: widths [", text); 12474c9d2aaaSJean-Jacques Hiblot if (caps & MMC_MODE_8BIT) 12484c9d2aaaSJean-Jacques Hiblot printf("8, "); 12494c9d2aaaSJean-Jacques Hiblot if (caps & MMC_MODE_4BIT) 12504c9d2aaaSJean-Jacques Hiblot printf("4, "); 1251d0c221feSJean-Jacques Hiblot if (caps & MMC_MODE_1BIT) 1252d0c221feSJean-Jacques Hiblot printf("1, "); 1253d0c221feSJean-Jacques Hiblot printf("\b\b] modes ["); 12544c9d2aaaSJean-Jacques Hiblot for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++) 12554c9d2aaaSJean-Jacques Hiblot if (MMC_CAP(mode) & caps) 12564c9d2aaaSJean-Jacques Hiblot printf("%s, ", mmc_mode_name(mode)); 12574c9d2aaaSJean-Jacques Hiblot printf("\b\b]\n"); 12584c9d2aaaSJean-Jacques Hiblot } 12594c9d2aaaSJean-Jacques Hiblot #endif 12604c9d2aaaSJean-Jacques Hiblot 1261d0c221feSJean-Jacques Hiblot struct mode_width_tuning { 1262d0c221feSJean-Jacques Hiblot enum bus_mode mode; 1263d0c221feSJean-Jacques Hiblot uint widths; 1264d0c221feSJean-Jacques Hiblot }; 1265d0c221feSJean-Jacques Hiblot 1266aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage) 1267aff5d3c8SKishon Vijay Abraham I { 1268aff5d3c8SKishon Vijay Abraham I mmc->signal_voltage = signal_voltage; 1269aff5d3c8SKishon Vijay Abraham I return mmc_set_ios(mmc); 1270aff5d3c8SKishon Vijay Abraham I } 1271aff5d3c8SKishon Vijay Abraham I 1272d0c221feSJean-Jacques Hiblot static const struct mode_width_tuning sd_modes_by_pref[] = { 1273d0c221feSJean-Jacques Hiblot { 1274d0c221feSJean-Jacques Hiblot .mode = SD_HS, 1275d0c221feSJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1276d0c221feSJean-Jacques Hiblot }, 1277d0c221feSJean-Jacques Hiblot { 1278d0c221feSJean-Jacques Hiblot .mode = SD_LEGACY, 1279d0c221feSJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1280d0c221feSJean-Jacques Hiblot } 1281d0c221feSJean-Jacques Hiblot }; 1282d0c221feSJean-Jacques Hiblot 1283d0c221feSJean-Jacques Hiblot #define for_each_sd_mode_by_pref(caps, mwt) \ 1284d0c221feSJean-Jacques Hiblot for (mwt = sd_modes_by_pref;\ 1285d0c221feSJean-Jacques Hiblot mwt < sd_modes_by_pref + ARRAY_SIZE(sd_modes_by_pref);\ 1286d0c221feSJean-Jacques Hiblot mwt++) \ 1287d0c221feSJean-Jacques Hiblot if (caps & MMC_CAP(mwt->mode)) 1288d0c221feSJean-Jacques Hiblot 1289d0c221feSJean-Jacques Hiblot static int sd_select_mode_and_width(struct mmc *mmc) 12908ac8a263SJean-Jacques Hiblot { 12918ac8a263SJean-Jacques Hiblot int err; 1292d0c221feSJean-Jacques Hiblot uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT}; 1293d0c221feSJean-Jacques Hiblot const struct mode_width_tuning *mwt; 12948ac8a263SJean-Jacques Hiblot 1295d0c221feSJean-Jacques Hiblot err = sd_get_capabilities(mmc); 12968ac8a263SJean-Jacques Hiblot if (err) 12978ac8a263SJean-Jacques Hiblot return err; 12988ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */ 1299d0c221feSJean-Jacques Hiblot mmc->card_caps &= (mmc->cfg->host_caps | MMC_MODE_1BIT); 13008ac8a263SJean-Jacques Hiblot 1301d0c221feSJean-Jacques Hiblot for_each_sd_mode_by_pref(mmc->card_caps, mwt) { 1302d0c221feSJean-Jacques Hiblot uint *w; 13038ac8a263SJean-Jacques Hiblot 1304d0c221feSJean-Jacques Hiblot for (w = widths; w < widths + ARRAY_SIZE(widths); w++) { 1305d0c221feSJean-Jacques Hiblot if (*w & mmc->card_caps & mwt->widths) { 1306d0c221feSJean-Jacques Hiblot debug("trying mode %s width %d (at %d MHz)\n", 1307d0c221feSJean-Jacques Hiblot mmc_mode_name(mwt->mode), 1308d0c221feSJean-Jacques Hiblot bus_width(*w), 1309d0c221feSJean-Jacques Hiblot mmc_mode2freq(mmc, mwt->mode) / 1000000); 1310d0c221feSJean-Jacques Hiblot 1311d0c221feSJean-Jacques Hiblot /* configure the bus width (card + host) */ 1312d0c221feSJean-Jacques Hiblot err = sd_select_bus_width(mmc, bus_width(*w)); 13138ac8a263SJean-Jacques Hiblot if (err) 1314d0c221feSJean-Jacques Hiblot goto error; 1315d0c221feSJean-Jacques Hiblot mmc_set_bus_width(mmc, bus_width(*w)); 13168ac8a263SJean-Jacques Hiblot 1317d0c221feSJean-Jacques Hiblot /* configure the bus mode (card) */ 1318d0c221feSJean-Jacques Hiblot err = sd_set_card_speed(mmc, mwt->mode); 13198ac8a263SJean-Jacques Hiblot if (err) 1320d0c221feSJean-Jacques Hiblot goto error; 13218ac8a263SJean-Jacques Hiblot 1322d0c221feSJean-Jacques Hiblot /* configure the bus mode (host) */ 1323d0c221feSJean-Jacques Hiblot mmc_select_mode(mmc, mwt->mode); 1324d0c221feSJean-Jacques Hiblot mmc_set_clock(mmc, mmc->tran_speed); 13258ac8a263SJean-Jacques Hiblot 13268ac8a263SJean-Jacques Hiblot err = sd_read_ssr(mmc); 1327d0c221feSJean-Jacques Hiblot if (!err) 13288ac8a263SJean-Jacques Hiblot return 0; 1329d0c221feSJean-Jacques Hiblot 1330d0c221feSJean-Jacques Hiblot printf("bad ssr\n"); 1331d0c221feSJean-Jacques Hiblot 1332d0c221feSJean-Jacques Hiblot error: 1333d0c221feSJean-Jacques Hiblot /* revert to a safer bus speed */ 1334d0c221feSJean-Jacques Hiblot mmc_select_mode(mmc, SD_LEGACY); 1335d0c221feSJean-Jacques Hiblot mmc_set_clock(mmc, mmc->tran_speed); 1336d0c221feSJean-Jacques Hiblot } 1337d0c221feSJean-Jacques Hiblot } 1338d0c221feSJean-Jacques Hiblot } 1339d0c221feSJean-Jacques Hiblot 1340d0c221feSJean-Jacques Hiblot printf("unable to select a mode\n"); 1341d0c221feSJean-Jacques Hiblot return -ENOTSUPP; 13428ac8a263SJean-Jacques Hiblot } 13438ac8a263SJean-Jacques Hiblot 13447382e691SJean-Jacques Hiblot /* 13457382e691SJean-Jacques Hiblot * read the compare the part of ext csd that is constant. 13467382e691SJean-Jacques Hiblot * This can be used to check that the transfer is working 13477382e691SJean-Jacques Hiblot * as expected. 13487382e691SJean-Jacques Hiblot */ 13497382e691SJean-Jacques Hiblot static int mmc_read_and_compare_ext_csd(struct mmc *mmc) 13507382e691SJean-Jacques Hiblot { 13517382e691SJean-Jacques Hiblot int err; 13527382e691SJean-Jacques Hiblot const u8 *ext_csd = mmc->ext_csd; 13537382e691SJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 13547382e691SJean-Jacques Hiblot 13557382e691SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, test_csd); 13567382e691SJean-Jacques Hiblot if (err) 13577382e691SJean-Jacques Hiblot return err; 13587382e691SJean-Jacques Hiblot 13597382e691SJean-Jacques Hiblot /* Only compare read only fields */ 13607382e691SJean-Jacques Hiblot if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] 13617382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_PARTITIONING_SUPPORT] && 13627382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_WP_GRP_SIZE] 13637382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_WP_GRP_SIZE] && 13647382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_REV] 13657382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_REV] && 13667382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 13677382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] && 13687382e691SJean-Jacques Hiblot memcmp(&ext_csd[EXT_CSD_SEC_CNT], 13697382e691SJean-Jacques Hiblot &test_csd[EXT_CSD_SEC_CNT], 4) == 0) 13707382e691SJean-Jacques Hiblot return 0; 13717382e691SJean-Jacques Hiblot 13727382e691SJean-Jacques Hiblot return -EBADMSG; 13737382e691SJean-Jacques Hiblot } 13747382e691SJean-Jacques Hiblot 13753862b854SJean-Jacques Hiblot static const struct mode_width_tuning mmc_modes_by_pref[] = { 13768ac8a263SJean-Jacques Hiblot { 13773862b854SJean-Jacques Hiblot .mode = MMC_HS_200, 13783862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT, 13793862b854SJean-Jacques Hiblot }, 13803862b854SJean-Jacques Hiblot { 13813862b854SJean-Jacques Hiblot .mode = MMC_DDR_52, 13823862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT, 13833862b854SJean-Jacques Hiblot }, 13843862b854SJean-Jacques Hiblot { 13853862b854SJean-Jacques Hiblot .mode = MMC_HS_52, 13863862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 13873862b854SJean-Jacques Hiblot }, 13883862b854SJean-Jacques Hiblot { 13893862b854SJean-Jacques Hiblot .mode = MMC_HS, 13903862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 13913862b854SJean-Jacques Hiblot }, 13923862b854SJean-Jacques Hiblot { 13933862b854SJean-Jacques Hiblot .mode = MMC_LEGACY, 13943862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 13953862b854SJean-Jacques Hiblot } 13968ac8a263SJean-Jacques Hiblot }; 13978ac8a263SJean-Jacques Hiblot 13983862b854SJean-Jacques Hiblot #define for_each_mmc_mode_by_pref(caps, mwt) \ 13993862b854SJean-Jacques Hiblot for (mwt = mmc_modes_by_pref;\ 14003862b854SJean-Jacques Hiblot mwt < mmc_modes_by_pref + ARRAY_SIZE(mmc_modes_by_pref);\ 14013862b854SJean-Jacques Hiblot mwt++) \ 14023862b854SJean-Jacques Hiblot if (caps & MMC_CAP(mwt->mode)) 14033862b854SJean-Jacques Hiblot 14043862b854SJean-Jacques Hiblot static const struct ext_csd_bus_width { 14053862b854SJean-Jacques Hiblot uint cap; 14063862b854SJean-Jacques Hiblot bool is_ddr; 14073862b854SJean-Jacques Hiblot uint ext_csd_bits; 14083862b854SJean-Jacques Hiblot } ext_csd_bus_width[] = { 14093862b854SJean-Jacques Hiblot {MMC_MODE_8BIT, true, EXT_CSD_DDR_BUS_WIDTH_8}, 14103862b854SJean-Jacques Hiblot {MMC_MODE_4BIT, true, EXT_CSD_DDR_BUS_WIDTH_4}, 14113862b854SJean-Jacques Hiblot {MMC_MODE_8BIT, false, EXT_CSD_BUS_WIDTH_8}, 14123862b854SJean-Jacques Hiblot {MMC_MODE_4BIT, false, EXT_CSD_BUS_WIDTH_4}, 14133862b854SJean-Jacques Hiblot {MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1}, 14143862b854SJean-Jacques Hiblot }; 14153862b854SJean-Jacques Hiblot 14163862b854SJean-Jacques Hiblot #define for_each_supported_width(caps, ddr, ecbv) \ 14173862b854SJean-Jacques Hiblot for (ecbv = ext_csd_bus_width;\ 14183862b854SJean-Jacques Hiblot ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\ 14193862b854SJean-Jacques Hiblot ecbv++) \ 14203862b854SJean-Jacques Hiblot if ((ddr == ecbv->is_ddr) && (caps & ecbv->cap)) 14213862b854SJean-Jacques Hiblot 14223862b854SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc) 14233862b854SJean-Jacques Hiblot { 14243862b854SJean-Jacques Hiblot int err; 14253862b854SJean-Jacques Hiblot const struct mode_width_tuning *mwt; 14263862b854SJean-Jacques Hiblot const struct ext_csd_bus_width *ecbw; 14273862b854SJean-Jacques Hiblot 14283862b854SJean-Jacques Hiblot err = mmc_get_capabilities(mmc); 14298ac8a263SJean-Jacques Hiblot if (err) 14308ac8a263SJean-Jacques Hiblot return err; 14318ac8a263SJean-Jacques Hiblot 14328ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */ 1433d0c221feSJean-Jacques Hiblot mmc->card_caps &= (mmc->cfg->host_caps | MMC_MODE_1BIT); 14348ac8a263SJean-Jacques Hiblot 14358ac8a263SJean-Jacques Hiblot /* Only version 4 of MMC supports wider bus widths */ 14368ac8a263SJean-Jacques Hiblot if (mmc->version < MMC_VERSION_4) 14378ac8a263SJean-Jacques Hiblot return 0; 14388ac8a263SJean-Jacques Hiblot 1439dfda9d88SJean-Jacques Hiblot if (!mmc->ext_csd) { 1440dfda9d88SJean-Jacques Hiblot debug("No ext_csd found!\n"); /* this should enver happen */ 1441dfda9d88SJean-Jacques Hiblot return -ENOTSUPP; 1442dfda9d88SJean-Jacques Hiblot } 1443dfda9d88SJean-Jacques Hiblot 14443862b854SJean-Jacques Hiblot for_each_mmc_mode_by_pref(mmc->card_caps, mwt) { 14453862b854SJean-Jacques Hiblot for_each_supported_width(mmc->card_caps & mwt->widths, 14463862b854SJean-Jacques Hiblot mmc_is_mode_ddr(mwt->mode), ecbw) { 14473862b854SJean-Jacques Hiblot debug("trying mode %s width %d (at %d MHz)\n", 14483862b854SJean-Jacques Hiblot mmc_mode_name(mwt->mode), 14493862b854SJean-Jacques Hiblot bus_width(ecbw->cap), 14503862b854SJean-Jacques Hiblot mmc_mode2freq(mmc, mwt->mode) / 1000000); 14513862b854SJean-Jacques Hiblot /* configure the bus width (card + host) */ 14523862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 14533862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, 14543862b854SJean-Jacques Hiblot ecbw->ext_csd_bits & ~EXT_CSD_DDR_FLAG); 14553862b854SJean-Jacques Hiblot if (err) 14563862b854SJean-Jacques Hiblot goto error; 14573862b854SJean-Jacques Hiblot mmc_set_bus_width(mmc, bus_width(ecbw->cap)); 14583862b854SJean-Jacques Hiblot 14593862b854SJean-Jacques Hiblot /* configure the bus speed (card) */ 14603862b854SJean-Jacques Hiblot err = mmc_set_card_speed(mmc, mwt->mode); 14613862b854SJean-Jacques Hiblot if (err) 14623862b854SJean-Jacques Hiblot goto error; 14633862b854SJean-Jacques Hiblot 14648ac8a263SJean-Jacques Hiblot /* 14653862b854SJean-Jacques Hiblot * configure the bus width AND the ddr mode (card) 14663862b854SJean-Jacques Hiblot * The host side will be taken care of in the next step 14678ac8a263SJean-Jacques Hiblot */ 14683862b854SJean-Jacques Hiblot if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) { 14693862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 14703862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, 14713862b854SJean-Jacques Hiblot ecbw->ext_csd_bits); 14723862b854SJean-Jacques Hiblot if (err) 14733862b854SJean-Jacques Hiblot goto error; 14748ac8a263SJean-Jacques Hiblot } 14758ac8a263SJean-Jacques Hiblot 14763862b854SJean-Jacques Hiblot /* configure the bus mode (host) */ 14773862b854SJean-Jacques Hiblot mmc_select_mode(mmc, mwt->mode); 14783862b854SJean-Jacques Hiblot mmc_set_clock(mmc, mmc->tran_speed); 14798ac8a263SJean-Jacques Hiblot 14803862b854SJean-Jacques Hiblot /* do a transfer to check the configuration */ 14817382e691SJean-Jacques Hiblot err = mmc_read_and_compare_ext_csd(mmc); 14827382e691SJean-Jacques Hiblot if (!err) 14833862b854SJean-Jacques Hiblot return 0; 14843862b854SJean-Jacques Hiblot error: 14853862b854SJean-Jacques Hiblot /* if an error occured, revert to a safer bus mode */ 14863862b854SJean-Jacques Hiblot mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 14873862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1); 14883862b854SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_LEGACY); 14893862b854SJean-Jacques Hiblot mmc_set_bus_width(mmc, 1); 14903862b854SJean-Jacques Hiblot } 14918ac8a263SJean-Jacques Hiblot } 14928ac8a263SJean-Jacques Hiblot 14933862b854SJean-Jacques Hiblot printf("unable to select a mode\n"); 14948ac8a263SJean-Jacques Hiblot 14953862b854SJean-Jacques Hiblot return -ENOTSUPP; 14968ac8a263SJean-Jacques Hiblot } 14978ac8a263SJean-Jacques Hiblot 1498dfda9d88SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc) 1499c744b6f6SJean-Jacques Hiblot { 1500c744b6f6SJean-Jacques Hiblot int err, i; 1501c744b6f6SJean-Jacques Hiblot u64 capacity; 1502c744b6f6SJean-Jacques Hiblot bool has_parts = false; 1503c744b6f6SJean-Jacques Hiblot bool part_completed; 1504dfda9d88SJean-Jacques Hiblot u8 *ext_csd; 1505c744b6f6SJean-Jacques Hiblot 1506c744b6f6SJean-Jacques Hiblot if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4)) 1507c744b6f6SJean-Jacques Hiblot return 0; 1508c744b6f6SJean-Jacques Hiblot 1509dfda9d88SJean-Jacques Hiblot ext_csd = malloc_cache_aligned(MMC_MAX_BLOCK_LEN); 1510dfda9d88SJean-Jacques Hiblot if (!ext_csd) 1511dfda9d88SJean-Jacques Hiblot return -ENOMEM; 1512dfda9d88SJean-Jacques Hiblot 1513dfda9d88SJean-Jacques Hiblot mmc->ext_csd = ext_csd; 1514dfda9d88SJean-Jacques Hiblot 1515c744b6f6SJean-Jacques Hiblot /* check ext_csd version and capacity */ 1516c744b6f6SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, ext_csd); 1517c744b6f6SJean-Jacques Hiblot if (err) 1518c744b6f6SJean-Jacques Hiblot return err; 1519c744b6f6SJean-Jacques Hiblot if (ext_csd[EXT_CSD_REV] >= 2) { 1520c744b6f6SJean-Jacques Hiblot /* 1521c744b6f6SJean-Jacques Hiblot * According to the JEDEC Standard, the value of 1522c744b6f6SJean-Jacques Hiblot * ext_csd's capacity is valid if the value is more 1523c744b6f6SJean-Jacques Hiblot * than 2GB 1524c744b6f6SJean-Jacques Hiblot */ 1525c744b6f6SJean-Jacques Hiblot capacity = ext_csd[EXT_CSD_SEC_CNT] << 0 1526c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 1527c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 1528c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; 1529c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN; 1530c744b6f6SJean-Jacques Hiblot if ((capacity >> 20) > 2 * 1024) 1531c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity; 1532c744b6f6SJean-Jacques Hiblot } 1533c744b6f6SJean-Jacques Hiblot 1534c744b6f6SJean-Jacques Hiblot switch (ext_csd[EXT_CSD_REV]) { 1535c744b6f6SJean-Jacques Hiblot case 1: 1536c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_1; 1537c744b6f6SJean-Jacques Hiblot break; 1538c744b6f6SJean-Jacques Hiblot case 2: 1539c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_2; 1540c744b6f6SJean-Jacques Hiblot break; 1541c744b6f6SJean-Jacques Hiblot case 3: 1542c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_3; 1543c744b6f6SJean-Jacques Hiblot break; 1544c744b6f6SJean-Jacques Hiblot case 5: 1545c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_41; 1546c744b6f6SJean-Jacques Hiblot break; 1547c744b6f6SJean-Jacques Hiblot case 6: 1548c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_5; 1549c744b6f6SJean-Jacques Hiblot break; 1550c744b6f6SJean-Jacques Hiblot case 7: 1551c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_5_0; 1552c744b6f6SJean-Jacques Hiblot break; 1553c744b6f6SJean-Jacques Hiblot case 8: 1554c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_5_1; 1555c744b6f6SJean-Jacques Hiblot break; 1556c744b6f6SJean-Jacques Hiblot } 1557c744b6f6SJean-Jacques Hiblot 1558c744b6f6SJean-Jacques Hiblot /* The partition data may be non-zero but it is only 1559c744b6f6SJean-Jacques Hiblot * effective if PARTITION_SETTING_COMPLETED is set in 1560c744b6f6SJean-Jacques Hiblot * EXT_CSD, so ignore any data if this bit is not set, 1561c744b6f6SJean-Jacques Hiblot * except for enabling the high-capacity group size 1562c744b6f6SJean-Jacques Hiblot * definition (see below). 1563c744b6f6SJean-Jacques Hiblot */ 1564c744b6f6SJean-Jacques Hiblot part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] & 1565c744b6f6SJean-Jacques Hiblot EXT_CSD_PARTITION_SETTING_COMPLETED); 1566c744b6f6SJean-Jacques Hiblot 1567c744b6f6SJean-Jacques Hiblot /* store the partition info of emmc */ 1568c744b6f6SJean-Jacques Hiblot mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT]; 1569c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || 1570c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_BOOT_MULT]) 1571c744b6f6SJean-Jacques Hiblot mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; 1572c744b6f6SJean-Jacques Hiblot if (part_completed && 1573c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT)) 1574c744b6f6SJean-Jacques Hiblot mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]; 1575c744b6f6SJean-Jacques Hiblot 1576c744b6f6SJean-Jacques Hiblot mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17; 1577c744b6f6SJean-Jacques Hiblot 1578c744b6f6SJean-Jacques Hiblot mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17; 1579c744b6f6SJean-Jacques Hiblot 1580c744b6f6SJean-Jacques Hiblot for (i = 0; i < 4; i++) { 1581c744b6f6SJean-Jacques Hiblot int idx = EXT_CSD_GP_SIZE_MULT + i * 3; 1582c744b6f6SJean-Jacques Hiblot uint mult = (ext_csd[idx + 2] << 16) + 1583c744b6f6SJean-Jacques Hiblot (ext_csd[idx + 1] << 8) + ext_csd[idx]; 1584c744b6f6SJean-Jacques Hiblot if (mult) 1585c744b6f6SJean-Jacques Hiblot has_parts = true; 1586c744b6f6SJean-Jacques Hiblot if (!part_completed) 1587c744b6f6SJean-Jacques Hiblot continue; 1588c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] = mult; 1589c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= 1590c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1591c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1592c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] <<= 19; 1593c744b6f6SJean-Jacques Hiblot } 1594c744b6f6SJean-Jacques Hiblot 1595c744b6f6SJean-Jacques Hiblot if (part_completed) { 1596c744b6f6SJean-Jacques Hiblot mmc->enh_user_size = 1597c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) + 1598c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) + 1599c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_SIZE_MULT]; 1600c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1601c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1602c744b6f6SJean-Jacques Hiblot mmc->enh_user_size <<= 19; 1603c744b6f6SJean-Jacques Hiblot mmc->enh_user_start = 1604c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) + 1605c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) + 1606c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) + 1607c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_START_ADDR]; 1608c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity) 1609c744b6f6SJean-Jacques Hiblot mmc->enh_user_start <<= 9; 1610c744b6f6SJean-Jacques Hiblot } 1611c744b6f6SJean-Jacques Hiblot 1612c744b6f6SJean-Jacques Hiblot /* 1613c744b6f6SJean-Jacques Hiblot * Host needs to enable ERASE_GRP_DEF bit if device is 1614c744b6f6SJean-Jacques Hiblot * partitioned. This bit will be lost every time after a reset 1615c744b6f6SJean-Jacques Hiblot * or power off. This will affect erase size. 1616c744b6f6SJean-Jacques Hiblot */ 1617c744b6f6SJean-Jacques Hiblot if (part_completed) 1618c744b6f6SJean-Jacques Hiblot has_parts = true; 1619c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) && 1620c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) 1621c744b6f6SJean-Jacques Hiblot has_parts = true; 1622c744b6f6SJean-Jacques Hiblot if (has_parts) { 1623c744b6f6SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1624c744b6f6SJean-Jacques Hiblot EXT_CSD_ERASE_GROUP_DEF, 1); 1625c744b6f6SJean-Jacques Hiblot 1626c744b6f6SJean-Jacques Hiblot if (err) 1627c744b6f6SJean-Jacques Hiblot return err; 1628c744b6f6SJean-Jacques Hiblot 1629c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 1630c744b6f6SJean-Jacques Hiblot } 1631c744b6f6SJean-Jacques Hiblot 1632c744b6f6SJean-Jacques Hiblot if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) { 1633c744b6f6SJean-Jacques Hiblot /* Read out group size from ext_csd */ 1634c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = 1635c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 1636c744b6f6SJean-Jacques Hiblot /* 1637c744b6f6SJean-Jacques Hiblot * if high capacity and partition setting completed 1638c744b6f6SJean-Jacques Hiblot * SEC_COUNT is valid even if it is smaller than 2 GiB 1639c744b6f6SJean-Jacques Hiblot * JEDEC Standard JESD84-B45, 6.2.4 1640c744b6f6SJean-Jacques Hiblot */ 1641c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity && part_completed) { 1642c744b6f6SJean-Jacques Hiblot capacity = (ext_csd[EXT_CSD_SEC_CNT]) | 1643c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) | 1644c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) | 1645c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 3] << 24); 1646c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN; 1647c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity; 1648c744b6f6SJean-Jacques Hiblot } 1649c744b6f6SJean-Jacques Hiblot } else { 1650c744b6f6SJean-Jacques Hiblot /* Calculate the group size from the csd value. */ 1651c744b6f6SJean-Jacques Hiblot int erase_gsz, erase_gmul; 1652c744b6f6SJean-Jacques Hiblot 1653c744b6f6SJean-Jacques Hiblot erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; 1654c744b6f6SJean-Jacques Hiblot erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; 1655c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = (erase_gsz + 1) 1656c744b6f6SJean-Jacques Hiblot * (erase_gmul + 1); 1657c744b6f6SJean-Jacques Hiblot } 1658c744b6f6SJean-Jacques Hiblot 1659c744b6f6SJean-Jacques Hiblot mmc->hc_wp_grp_size = 1024 1660c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 1661c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1662c744b6f6SJean-Jacques Hiblot 1663c744b6f6SJean-Jacques Hiblot mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 1664c744b6f6SJean-Jacques Hiblot 1665c744b6f6SJean-Jacques Hiblot return 0; 1666c744b6f6SJean-Jacques Hiblot } 1667c744b6f6SJean-Jacques Hiblot 1668fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc) 1669272cc70bSAndy Fleming { 1670f866a46dSStephen Warren int err, i; 1671272cc70bSAndy Fleming uint mult, freq; 1672c744b6f6SJean-Jacques Hiblot u64 cmult, csize; 1673272cc70bSAndy Fleming struct mmc_cmd cmd; 1674c40fdca6SSimon Glass struct blk_desc *bdesc; 1675272cc70bSAndy Fleming 1676d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON 1677d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ 1678d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; 1679d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R1; 1680d52ebf10SThomas Chou cmd.cmdarg = 1; 1681d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 1682d52ebf10SThomas Chou 1683d52ebf10SThomas Chou if (err) 1684d52ebf10SThomas Chou return err; 1685d52ebf10SThomas Chou } 1686d52ebf10SThomas Chou #endif 1687d52ebf10SThomas Chou 1688272cc70bSAndy Fleming /* Put the Card in Identify Mode */ 1689d52ebf10SThomas Chou cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : 1690d52ebf10SThomas Chou MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ 1691272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1692272cc70bSAndy Fleming cmd.cmdarg = 0; 1693272cc70bSAndy Fleming 1694272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1695272cc70bSAndy Fleming 1696272cc70bSAndy Fleming if (err) 1697272cc70bSAndy Fleming return err; 1698272cc70bSAndy Fleming 1699272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16); 1700272cc70bSAndy Fleming 1701272cc70bSAndy Fleming /* 1702272cc70bSAndy Fleming * For MMC cards, set the Relative Address. 1703272cc70bSAndy Fleming * For SD cards, get the Relatvie Address. 1704272cc70bSAndy Fleming * This also puts the cards into Standby State 1705272cc70bSAndy Fleming */ 1706d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1707272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; 1708272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1709272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6; 1710272cc70bSAndy Fleming 1711272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1712272cc70bSAndy Fleming 1713272cc70bSAndy Fleming if (err) 1714272cc70bSAndy Fleming return err; 1715272cc70bSAndy Fleming 1716272cc70bSAndy Fleming if (IS_SD(mmc)) 1717998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff; 1718d52ebf10SThomas Chou } 1719272cc70bSAndy Fleming 1720272cc70bSAndy Fleming /* Get the Card-Specific Data */ 1721272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD; 1722272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1723272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1724272cc70bSAndy Fleming 1725272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1726272cc70bSAndy Fleming 1727272cc70bSAndy Fleming if (err) 1728272cc70bSAndy Fleming return err; 1729272cc70bSAndy Fleming 1730998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0]; 1731998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1]; 1732998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2]; 1733998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3]; 1734272cc70bSAndy Fleming 1735272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) { 17360b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf; 1737272cc70bSAndy Fleming 1738272cc70bSAndy Fleming switch (version) { 1739272cc70bSAndy Fleming case 0: 1740272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1741272cc70bSAndy Fleming break; 1742272cc70bSAndy Fleming case 1: 1743272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4; 1744272cc70bSAndy Fleming break; 1745272cc70bSAndy Fleming case 2: 1746272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2; 1747272cc70bSAndy Fleming break; 1748272cc70bSAndy Fleming case 3: 1749272cc70bSAndy Fleming mmc->version = MMC_VERSION_3; 1750272cc70bSAndy Fleming break; 1751272cc70bSAndy Fleming case 4: 1752272cc70bSAndy Fleming mmc->version = MMC_VERSION_4; 1753272cc70bSAndy Fleming break; 1754272cc70bSAndy Fleming default: 1755272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1756272cc70bSAndy Fleming break; 1757272cc70bSAndy Fleming } 1758272cc70bSAndy Fleming } 1759272cc70bSAndy Fleming 1760272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */ 17610b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)]; 17620b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; 1763272cc70bSAndy Fleming 176435f9e196SJean-Jacques Hiblot mmc->legacy_speed = freq * mult; 176535f9e196SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_LEGACY); 1766272cc70bSAndy Fleming 1767ab71188cSMarkus Niebel mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); 1768998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); 1769272cc70bSAndy Fleming 1770272cc70bSAndy Fleming if (IS_SD(mmc)) 1771272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len; 1772272cc70bSAndy Fleming else 1773998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); 1774272cc70bSAndy Fleming 1775272cc70bSAndy Fleming if (mmc->high_capacity) { 1776272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16 1777272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16; 1778272cc70bSAndy Fleming cmult = 8; 1779272cc70bSAndy Fleming } else { 1780272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2 1781272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30; 1782272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15; 1783272cc70bSAndy Fleming } 1784272cc70bSAndy Fleming 1785f866a46dSStephen Warren mmc->capacity_user = (csize + 1) << (cmult + 2); 1786f866a46dSStephen Warren mmc->capacity_user *= mmc->read_bl_len; 1787f866a46dSStephen Warren mmc->capacity_boot = 0; 1788f866a46dSStephen Warren mmc->capacity_rpmb = 0; 1789f866a46dSStephen Warren for (i = 0; i < 4; i++) 1790f866a46dSStephen Warren mmc->capacity_gp[i] = 0; 1791272cc70bSAndy Fleming 17928bfa195eSSimon Glass if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN) 17938bfa195eSSimon Glass mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 1794272cc70bSAndy Fleming 17958bfa195eSSimon Glass if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) 17968bfa195eSSimon Glass mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 1797272cc70bSAndy Fleming 1798ab71188cSMarkus Niebel if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) { 1799ab71188cSMarkus Niebel cmd.cmdidx = MMC_CMD_SET_DSR; 1800ab71188cSMarkus Niebel cmd.cmdarg = (mmc->dsr & 0xffff) << 16; 1801ab71188cSMarkus Niebel cmd.resp_type = MMC_RSP_NONE; 1802ab71188cSMarkus Niebel if (mmc_send_cmd(mmc, &cmd, NULL)) 1803ab71188cSMarkus Niebel printf("MMC: SET_DSR failed\n"); 1804ab71188cSMarkus Niebel } 1805ab71188cSMarkus Niebel 1806272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */ 1807d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1808272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD; 1809fe8f7066SAjay Bhargav cmd.resp_type = MMC_RSP_R1; 1810272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1811272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1812272cc70bSAndy Fleming 1813272cc70bSAndy Fleming if (err) 1814272cc70bSAndy Fleming return err; 1815d52ebf10SThomas Chou } 1816272cc70bSAndy Fleming 1817e6f99a56SLei Wen /* 1818e6f99a56SLei Wen * For SD, its erase group is always one sector 1819e6f99a56SLei Wen */ 1820e6f99a56SLei Wen mmc->erase_grp_size = 1; 1821bc897b1dSLei Wen mmc->part_config = MMCPART_NOAVAILABLE; 1822c744b6f6SJean-Jacques Hiblot 1823dfda9d88SJean-Jacques Hiblot err = mmc_startup_v4(mmc); 18249cf199ebSDiego Santa Cruz if (err) 18259cf199ebSDiego Santa Cruz return err; 1826f866a46dSStephen Warren 1827c40fdca6SSimon Glass err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart); 1828f866a46dSStephen Warren if (err) 1829f866a46dSStephen Warren return err; 1830d23e2c09SSukumar Ghorai 1831272cc70bSAndy Fleming if (IS_SD(mmc)) 1832d0c221feSJean-Jacques Hiblot err = sd_select_mode_and_width(mmc); 1833272cc70bSAndy Fleming else 18343862b854SJean-Jacques Hiblot err = mmc_select_mode_and_width(mmc); 1835272cc70bSAndy Fleming 1836272cc70bSAndy Fleming if (err) 1837272cc70bSAndy Fleming return err; 1838272cc70bSAndy Fleming 1839272cc70bSAndy Fleming 18405af8f45cSAndrew Gabbasov /* Fix the block length for DDR mode */ 18415af8f45cSAndrew Gabbasov if (mmc->ddr_mode) { 18425af8f45cSAndrew Gabbasov mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 18435af8f45cSAndrew Gabbasov mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 18445af8f45cSAndrew Gabbasov } 18455af8f45cSAndrew Gabbasov 1846272cc70bSAndy Fleming /* fill in device description */ 1847c40fdca6SSimon Glass bdesc = mmc_get_blk_desc(mmc); 1848c40fdca6SSimon Glass bdesc->lun = 0; 1849c40fdca6SSimon Glass bdesc->hwpart = 0; 1850c40fdca6SSimon Glass bdesc->type = 0; 1851c40fdca6SSimon Glass bdesc->blksz = mmc->read_bl_len; 1852c40fdca6SSimon Glass bdesc->log2blksz = LOG2(bdesc->blksz); 1853c40fdca6SSimon Glass bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len); 1854fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \ 1855fc011f64SSjoerd Simons (defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \ 1856fc011f64SSjoerd Simons !defined(CONFIG_USE_TINY_PRINTF)) 1857c40fdca6SSimon Glass sprintf(bdesc->vendor, "Man %06x Snr %04x%04x", 1858babce5f6STaylor Hutt mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), 1859babce5f6STaylor Hutt (mmc->cid[3] >> 16) & 0xffff); 1860c40fdca6SSimon Glass sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff, 18610b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 1862babce5f6STaylor Hutt (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff, 1863babce5f6STaylor Hutt (mmc->cid[2] >> 24) & 0xff); 1864c40fdca6SSimon Glass sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf, 1865babce5f6STaylor Hutt (mmc->cid[2] >> 16) & 0xf); 186656196826SPaul Burton #else 1867c40fdca6SSimon Glass bdesc->vendor[0] = 0; 1868c40fdca6SSimon Glass bdesc->product[0] = 0; 1869c40fdca6SSimon Glass bdesc->revision[0] = 0; 187056196826SPaul Burton #endif 1871122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT) 1872c40fdca6SSimon Glass part_init(bdesc); 1873122efd43SMikhail Kshevetskiy #endif 1874272cc70bSAndy Fleming 1875272cc70bSAndy Fleming return 0; 1876272cc70bSAndy Fleming } 1877272cc70bSAndy Fleming 1878fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc) 1879272cc70bSAndy Fleming { 1880272cc70bSAndy Fleming struct mmc_cmd cmd; 1881272cc70bSAndy Fleming int err; 1882272cc70bSAndy Fleming 1883272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND; 1884272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ 188593bfd616SPantelis Antoniou cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa; 1886272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7; 1887272cc70bSAndy Fleming 1888272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1889272cc70bSAndy Fleming 1890272cc70bSAndy Fleming if (err) 1891272cc70bSAndy Fleming return err; 1892272cc70bSAndy Fleming 1893998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa) 1894915ffa52SJaehoon Chung return -EOPNOTSUPP; 1895272cc70bSAndy Fleming else 1896272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 1897272cc70bSAndy Fleming 1898272cc70bSAndy Fleming return 0; 1899272cc70bSAndy Fleming } 1900272cc70bSAndy Fleming 1901c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 190295de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */ 190395de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void) 190495de9ab2SPaul Kocialkowski { 190595de9ab2SPaul Kocialkowski } 190605cbeb7cSSimon Glass #endif 190795de9ab2SPaul Kocialkowski 19082051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc) 19092051aefeSPeng Fan { 1910c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 191106ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR) 19122051aefeSPeng Fan int ret; 19132051aefeSPeng Fan 19142051aefeSPeng Fan ret = device_get_supply_regulator(mmc->dev, "vmmc-supply", 191506ec045fSJean-Jacques Hiblot &mmc->vmmc_supply); 191606ec045fSJean-Jacques Hiblot if (ret) 1917288db7c7SJaehoon Chung debug("%s: No vmmc supply\n", mmc->dev->name); 19182051aefeSPeng Fan 191906ec045fSJean-Jacques Hiblot ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply", 192006ec045fSJean-Jacques Hiblot &mmc->vqmmc_supply); 192106ec045fSJean-Jacques Hiblot if (ret) 192206ec045fSJean-Jacques Hiblot debug("%s: No vqmmc supply\n", mmc->dev->name); 192306ec045fSJean-Jacques Hiblot 192406ec045fSJean-Jacques Hiblot if (mmc->vmmc_supply) { 192506ec045fSJean-Jacques Hiblot ret = regulator_set_enable(mmc->vmmc_supply, true); 19262051aefeSPeng Fan if (ret) { 19272051aefeSPeng Fan puts("Error enabling VMMC supply\n"); 19282051aefeSPeng Fan return ret; 19292051aefeSPeng Fan } 193006ec045fSJean-Jacques Hiblot } 19312051aefeSPeng Fan #endif 193205cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */ 193305cbeb7cSSimon Glass /* 193405cbeb7cSSimon Glass * Driver model should use a regulator, as above, rather than calling 193505cbeb7cSSimon Glass * out to board code. 193605cbeb7cSSimon Glass */ 193705cbeb7cSSimon Glass board_mmc_power_init(); 193805cbeb7cSSimon Glass #endif 19392051aefeSPeng Fan return 0; 19402051aefeSPeng Fan } 19412051aefeSPeng Fan 1942e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc) 1943272cc70bSAndy Fleming { 19448ca51e51SSimon Glass bool no_card; 1945afd5932bSMacpaul Lin int err; 1946272cc70bSAndy Fleming 1947ab769f22SPantelis Antoniou /* we pretend there's no card when init is NULL */ 19488ca51e51SSimon Glass no_card = mmc_getcd(mmc) == 0; 1949e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 19508ca51e51SSimon Glass no_card = no_card || (mmc->cfg->ops->init == NULL); 19518ca51e51SSimon Glass #endif 19528ca51e51SSimon Glass if (no_card) { 195348972d90SThierry Reding mmc->has_init = 0; 195456196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 195548972d90SThierry Reding printf("MMC: no card present\n"); 195656196826SPaul Burton #endif 1957915ffa52SJaehoon Chung return -ENOMEDIUM; 195848972d90SThierry Reding } 195948972d90SThierry Reding 1960bc897b1dSLei Wen if (mmc->has_init) 1961bc897b1dSLei Wen return 0; 1962bc897b1dSLei Wen 19635a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 19645a8dbdc6SYangbo Lu mmc_adapter_card_type_ident(); 19655a8dbdc6SYangbo Lu #endif 19662051aefeSPeng Fan err = mmc_power_init(mmc); 19672051aefeSPeng Fan if (err) 19682051aefeSPeng Fan return err; 196995de9ab2SPaul Kocialkowski 1970e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 19718ca51e51SSimon Glass /* The device has already been probed ready for use */ 19728ca51e51SSimon Glass #else 1973ab769f22SPantelis Antoniou /* made sure it's not NULL earlier */ 197493bfd616SPantelis Antoniou err = mmc->cfg->ops->init(mmc); 1975272cc70bSAndy Fleming if (err) 1976272cc70bSAndy Fleming return err; 19778ca51e51SSimon Glass #endif 1978786e8f81SAndrew Gabbasov mmc->ddr_mode = 0; 1979aff5d3c8SKishon Vijay Abraham I 1980aff5d3c8SKishon Vijay Abraham I /* First try to set 3.3V. If it fails set to 1.8V */ 1981aff5d3c8SKishon Vijay Abraham I err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_330); 1982aff5d3c8SKishon Vijay Abraham I if (err != 0) 1983aff5d3c8SKishon Vijay Abraham I err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_180); 1984aff5d3c8SKishon Vijay Abraham I if (err != 0) 1985aff5d3c8SKishon Vijay Abraham I printf("failed to set signal voltage\n"); 1986aff5d3c8SKishon Vijay Abraham I 1987b86b85e2SIlya Yanok mmc_set_bus_width(mmc, 1); 1988b86b85e2SIlya Yanok mmc_set_clock(mmc, 1); 1989b86b85e2SIlya Yanok 1990*318a7a57SJean-Jacques Hiblot mmc_send_init_stream(mmc); 1991*318a7a57SJean-Jacques Hiblot 1992272cc70bSAndy Fleming /* Reset the Card */ 1993272cc70bSAndy Fleming err = mmc_go_idle(mmc); 1994272cc70bSAndy Fleming 1995272cc70bSAndy Fleming if (err) 1996272cc70bSAndy Fleming return err; 1997272cc70bSAndy Fleming 1998bc897b1dSLei Wen /* The internal partition reset to user partition(0) at every CMD0*/ 1999c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->hwpart = 0; 2000bc897b1dSLei Wen 2001272cc70bSAndy Fleming /* Test for SD version 2 */ 2002272cc70bSAndy Fleming err = mmc_send_if_cond(mmc); 2003272cc70bSAndy Fleming 2004272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */ 2005272cc70bSAndy Fleming err = sd_send_op_cond(mmc); 2006272cc70bSAndy Fleming 2007272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */ 2008915ffa52SJaehoon Chung if (err == -ETIMEDOUT) { 2009272cc70bSAndy Fleming err = mmc_send_op_cond(mmc); 2010272cc70bSAndy Fleming 2011bd47c135SAndrew Gabbasov if (err) { 201256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2013272cc70bSAndy Fleming printf("Card did not respond to voltage select!\n"); 201456196826SPaul Burton #endif 2015915ffa52SJaehoon Chung return -EOPNOTSUPP; 2016272cc70bSAndy Fleming } 2017272cc70bSAndy Fleming } 2018272cc70bSAndy Fleming 2019bd47c135SAndrew Gabbasov if (!err) 2020e9550449SChe-Liang Chiou mmc->init_in_progress = 1; 2021e9550449SChe-Liang Chiou 2022e9550449SChe-Liang Chiou return err; 2023e9550449SChe-Liang Chiou } 2024e9550449SChe-Liang Chiou 2025e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc) 2026e9550449SChe-Liang Chiou { 2027e9550449SChe-Liang Chiou int err = 0; 2028e9550449SChe-Liang Chiou 2029bd47c135SAndrew Gabbasov mmc->init_in_progress = 0; 2030e9550449SChe-Liang Chiou if (mmc->op_cond_pending) 2031e9550449SChe-Liang Chiou err = mmc_complete_op_cond(mmc); 2032e9550449SChe-Liang Chiou 2033e9550449SChe-Liang Chiou if (!err) 2034bc897b1dSLei Wen err = mmc_startup(mmc); 2035bc897b1dSLei Wen if (err) 2036bc897b1dSLei Wen mmc->has_init = 0; 2037bc897b1dSLei Wen else 2038bc897b1dSLei Wen mmc->has_init = 1; 2039e9550449SChe-Liang Chiou return err; 2040e9550449SChe-Liang Chiou } 2041e9550449SChe-Liang Chiou 2042e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc) 2043e9550449SChe-Liang Chiou { 2044bd47c135SAndrew Gabbasov int err = 0; 2045ce9eca94SMarek Vasut __maybe_unused unsigned start; 2046c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 204733fb211dSSimon Glass struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev); 2048e9550449SChe-Liang Chiou 204933fb211dSSimon Glass upriv->mmc = mmc; 205033fb211dSSimon Glass #endif 2051e9550449SChe-Liang Chiou if (mmc->has_init) 2052e9550449SChe-Liang Chiou return 0; 2053d803fea5SMateusz Zalega 2054d803fea5SMateusz Zalega start = get_timer(0); 2055d803fea5SMateusz Zalega 2056e9550449SChe-Liang Chiou if (!mmc->init_in_progress) 2057e9550449SChe-Liang Chiou err = mmc_start_init(mmc); 2058e9550449SChe-Liang Chiou 2059bd47c135SAndrew Gabbasov if (!err) 2060e9550449SChe-Liang Chiou err = mmc_complete_init(mmc); 2061919b4858SJagan Teki if (err) 2062919b4858SJagan Teki printf("%s: %d, time %lu\n", __func__, err, get_timer(start)); 2063919b4858SJagan Teki 2064bc897b1dSLei Wen return err; 2065272cc70bSAndy Fleming } 2066272cc70bSAndy Fleming 2067ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val) 2068ab71188cSMarkus Niebel { 2069ab71188cSMarkus Niebel mmc->dsr = val; 2070ab71188cSMarkus Niebel return 0; 2071ab71188cSMarkus Niebel } 2072ab71188cSMarkus Niebel 2073cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */ 2074cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis) 2075272cc70bSAndy Fleming { 2076272cc70bSAndy Fleming return -1; 2077272cc70bSAndy Fleming } 2078272cc70bSAndy Fleming 2079cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */ 2080cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis) 2081cee9ab7cSJeroen Hofstee { 2082cee9ab7cSJeroen Hofstee return -1; 2083cee9ab7cSJeroen Hofstee } 2084272cc70bSAndy Fleming 2085e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit) 2086e9550449SChe-Liang Chiou { 2087e9550449SChe-Liang Chiou mmc->preinit = preinit; 2088e9550449SChe-Liang Chiou } 2089e9550449SChe-Liang Chiou 2090c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD) 20918e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 20928e3332e2SSjoerd Simons { 20938e3332e2SSjoerd Simons return 0; 20948e3332e2SSjoerd Simons } 2095c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC) 20968e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 20978e3332e2SSjoerd Simons { 20984a1db6d8SSimon Glass int ret, i; 20998e3332e2SSjoerd Simons struct uclass *uc; 21004a1db6d8SSimon Glass struct udevice *dev; 21018e3332e2SSjoerd Simons 21028e3332e2SSjoerd Simons ret = uclass_get(UCLASS_MMC, &uc); 21038e3332e2SSjoerd Simons if (ret) 21048e3332e2SSjoerd Simons return ret; 21058e3332e2SSjoerd Simons 21064a1db6d8SSimon Glass /* 21074a1db6d8SSimon Glass * Try to add them in sequence order. Really with driver model we 21084a1db6d8SSimon Glass * should allow holes, but the current MMC list does not allow that. 21094a1db6d8SSimon Glass * So if we request 0, 1, 3 we will get 0, 1, 2. 21104a1db6d8SSimon Glass */ 21114a1db6d8SSimon Glass for (i = 0; ; i++) { 21124a1db6d8SSimon Glass ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev); 21134a1db6d8SSimon Glass if (ret == -ENODEV) 21144a1db6d8SSimon Glass break; 21154a1db6d8SSimon Glass } 21164a1db6d8SSimon Glass uclass_foreach_dev(dev, uc) { 21174a1db6d8SSimon Glass ret = device_probe(dev); 21188e3332e2SSjoerd Simons if (ret) 21194a1db6d8SSimon Glass printf("%s - probe failed: %d\n", dev->name, ret); 21208e3332e2SSjoerd Simons } 21218e3332e2SSjoerd Simons 21228e3332e2SSjoerd Simons return 0; 21238e3332e2SSjoerd Simons } 21248e3332e2SSjoerd Simons #else 21258e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 21268e3332e2SSjoerd Simons { 21278e3332e2SSjoerd Simons if (board_mmc_init(bis) < 0) 21288e3332e2SSjoerd Simons cpu_mmc_init(bis); 21298e3332e2SSjoerd Simons 21308e3332e2SSjoerd Simons return 0; 21318e3332e2SSjoerd Simons } 21328e3332e2SSjoerd Simons #endif 2133e9550449SChe-Liang Chiou 2134272cc70bSAndy Fleming int mmc_initialize(bd_t *bis) 2135272cc70bSAndy Fleming { 21361b26bab1SDaniel Kochmański static int initialized = 0; 21378e3332e2SSjoerd Simons int ret; 21381b26bab1SDaniel Kochmański if (initialized) /* Avoid initializing mmc multiple times */ 21391b26bab1SDaniel Kochmański return 0; 21401b26bab1SDaniel Kochmański initialized = 1; 21411b26bab1SDaniel Kochmański 2142c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK) 2143b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY) 2144c40fdca6SSimon Glass mmc_list_init(); 2145c40fdca6SSimon Glass #endif 2146b5b838f1SMarek Vasut #endif 21478e3332e2SSjoerd Simons ret = mmc_probe(bis); 21488e3332e2SSjoerd Simons if (ret) 21498e3332e2SSjoerd Simons return ret; 2150272cc70bSAndy Fleming 2151bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD 2152272cc70bSAndy Fleming print_mmc_devices(','); 2153bb0dc108SYing Zhang #endif 2154272cc70bSAndy Fleming 2155c40fdca6SSimon Glass mmc_do_preinit(); 2156272cc70bSAndy Fleming return 0; 2157272cc70bSAndy Fleming } 2158cd3d4880STomas Melin 2159cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE 2160cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc) 2161cd3d4880STomas Melin { 2162cd3d4880STomas Melin int err; 2163cd3d4880STomas Melin ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 2164cd3d4880STomas Melin 2165cd3d4880STomas Melin err = mmc_send_ext_csd(mmc, ext_csd); 2166cd3d4880STomas Melin if (err) { 2167cd3d4880STomas Melin puts("Could not get ext_csd register values\n"); 2168cd3d4880STomas Melin return err; 2169cd3d4880STomas Melin } 2170cd3d4880STomas Melin 2171cd3d4880STomas Melin if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) { 2172cd3d4880STomas Melin puts("Background operations not supported on device\n"); 2173cd3d4880STomas Melin return -EMEDIUMTYPE; 2174cd3d4880STomas Melin } 2175cd3d4880STomas Melin 2176cd3d4880STomas Melin if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) { 2177cd3d4880STomas Melin puts("Background operations already enabled\n"); 2178cd3d4880STomas Melin return 0; 2179cd3d4880STomas Melin } 2180cd3d4880STomas Melin 2181cd3d4880STomas Melin err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1); 2182cd3d4880STomas Melin if (err) { 2183cd3d4880STomas Melin puts("Failed to enable manual background operations\n"); 2184cd3d4880STomas Melin return err; 2185cd3d4880STomas Melin } 2186cd3d4880STomas Melin 2187cd3d4880STomas Melin puts("Enabled manual background operations\n"); 2188cd3d4880STomas Melin 2189cd3d4880STomas Melin return 0; 2190cd3d4880STomas Melin } 2191cd3d4880STomas Melin #endif 2192