1272cc70bSAndy Fleming /* 2272cc70bSAndy Fleming * Copyright 2008, Freescale Semiconductor, Inc 3272cc70bSAndy Fleming * Andy Fleming 4272cc70bSAndy Fleming * 5272cc70bSAndy Fleming * Based vaguely on the Linux code 6272cc70bSAndy Fleming * 71a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 8272cc70bSAndy Fleming */ 9272cc70bSAndy Fleming 10272cc70bSAndy Fleming #include <config.h> 11272cc70bSAndy Fleming #include <common.h> 12272cc70bSAndy Fleming #include <command.h> 138e3332e2SSjoerd Simons #include <dm.h> 148e3332e2SSjoerd Simons #include <dm/device-internal.h> 15d4622df3SStephen Warren #include <errno.h> 16272cc70bSAndy Fleming #include <mmc.h> 17272cc70bSAndy Fleming #include <part.h> 182051aefeSPeng Fan #include <power/regulator.h> 19272cc70bSAndy Fleming #include <malloc.h> 20cf92e05cSSimon Glass #include <memalign.h> 21272cc70bSAndy Fleming #include <linux/list.h> 229b1f942cSRabin Vincent #include <div64.h> 23da61fa5fSPaul Burton #include "mmc_private.h" 24272cc70bSAndy Fleming 253697e599SPeng Fan static const unsigned int sd_au_size[] = { 263697e599SPeng Fan 0, SZ_16K / 512, SZ_32K / 512, 273697e599SPeng Fan SZ_64K / 512, SZ_128K / 512, SZ_256K / 512, 283697e599SPeng Fan SZ_512K / 512, SZ_1M / 512, SZ_2M / 512, 293697e599SPeng Fan SZ_4M / 512, SZ_8M / 512, (SZ_8M + SZ_4M) / 512, 303697e599SPeng Fan SZ_16M / 512, (SZ_16M + SZ_8M) / 512, SZ_32M / 512, SZ_64M / 512, 313697e599SPeng Fan }; 323697e599SPeng Fan 33b5b838f1SMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY) 34b5b838f1SMarek Vasut static struct mmc mmc_static; 35b5b838f1SMarek Vasut struct mmc *find_mmc_device(int dev_num) 36b5b838f1SMarek Vasut { 37b5b838f1SMarek Vasut return &mmc_static; 38b5b838f1SMarek Vasut } 39b5b838f1SMarek Vasut 40b5b838f1SMarek Vasut void mmc_do_preinit(void) 41b5b838f1SMarek Vasut { 42b5b838f1SMarek Vasut struct mmc *m = &mmc_static; 43b5b838f1SMarek Vasut #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 44b5b838f1SMarek Vasut mmc_set_preinit(m, 1); 45b5b838f1SMarek Vasut #endif 46b5b838f1SMarek Vasut if (m->preinit) 47b5b838f1SMarek Vasut mmc_start_init(m); 48b5b838f1SMarek Vasut } 49b5b838f1SMarek Vasut 50b5b838f1SMarek Vasut struct blk_desc *mmc_get_blk_desc(struct mmc *mmc) 51b5b838f1SMarek Vasut { 52b5b838f1SMarek Vasut return &mmc->block_dev; 53b5b838f1SMarek Vasut } 54b5b838f1SMarek Vasut #endif 55b5b838f1SMarek Vasut 56e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 57750121c3SJeroen Hofstee __weak int board_mmc_getwp(struct mmc *mmc) 58d23d8d7eSNikita Kiryanov { 59d23d8d7eSNikita Kiryanov return -1; 60d23d8d7eSNikita Kiryanov } 61d23d8d7eSNikita Kiryanov 62d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc) 63d23d8d7eSNikita Kiryanov { 64d23d8d7eSNikita Kiryanov int wp; 65d23d8d7eSNikita Kiryanov 66d23d8d7eSNikita Kiryanov wp = board_mmc_getwp(mmc); 67d23d8d7eSNikita Kiryanov 68d4e1da4eSPeter Korsgaard if (wp < 0) { 6993bfd616SPantelis Antoniou if (mmc->cfg->ops->getwp) 7093bfd616SPantelis Antoniou wp = mmc->cfg->ops->getwp(mmc); 71d4e1da4eSPeter Korsgaard else 72d4e1da4eSPeter Korsgaard wp = 0; 73d4e1da4eSPeter Korsgaard } 74d23d8d7eSNikita Kiryanov 75d23d8d7eSNikita Kiryanov return wp; 76d23d8d7eSNikita Kiryanov } 77d23d8d7eSNikita Kiryanov 78cee9ab7cSJeroen Hofstee __weak int board_mmc_getcd(struct mmc *mmc) 79cee9ab7cSJeroen Hofstee { 8011fdade2SStefano Babic return -1; 8111fdade2SStefano Babic } 828ca51e51SSimon Glass #endif 8311fdade2SStefano Babic 848635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE 85c0c76ebaSSimon Glass void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd) 86c0c76ebaSSimon Glass { 87c0c76ebaSSimon Glass printf("CMD_SEND:%d\n", cmd->cmdidx); 88c0c76ebaSSimon Glass printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg); 89c0c76ebaSSimon Glass } 90c0c76ebaSSimon Glass 91c0c76ebaSSimon Glass void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret) 92c0c76ebaSSimon Glass { 935db2fe3aSRaffaele Recalcati int i; 945db2fe3aSRaffaele Recalcati u8 *ptr; 955db2fe3aSRaffaele Recalcati 967863ce58SBin Meng if (ret) { 977863ce58SBin Meng printf("\t\tRET\t\t\t %d\n", ret); 987863ce58SBin Meng } else { 995db2fe3aSRaffaele Recalcati switch (cmd->resp_type) { 1005db2fe3aSRaffaele Recalcati case MMC_RSP_NONE: 1015db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_NONE\n"); 1025db2fe3aSRaffaele Recalcati break; 1035db2fe3aSRaffaele Recalcati case MMC_RSP_R1: 1045db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n", 1055db2fe3aSRaffaele Recalcati cmd->response[0]); 1065db2fe3aSRaffaele Recalcati break; 1075db2fe3aSRaffaele Recalcati case MMC_RSP_R1b: 1085db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n", 1095db2fe3aSRaffaele Recalcati cmd->response[0]); 1105db2fe3aSRaffaele Recalcati break; 1115db2fe3aSRaffaele Recalcati case MMC_RSP_R2: 1125db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R2\t\t 0x%08X \n", 1135db2fe3aSRaffaele Recalcati cmd->response[0]); 1145db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1155db2fe3aSRaffaele Recalcati cmd->response[1]); 1165db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1175db2fe3aSRaffaele Recalcati cmd->response[2]); 1185db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1195db2fe3aSRaffaele Recalcati cmd->response[3]); 1205db2fe3aSRaffaele Recalcati printf("\n"); 1215db2fe3aSRaffaele Recalcati printf("\t\t\t\t\tDUMPING DATA\n"); 1225db2fe3aSRaffaele Recalcati for (i = 0; i < 4; i++) { 1235db2fe3aSRaffaele Recalcati int j; 1245db2fe3aSRaffaele Recalcati printf("\t\t\t\t\t%03d - ", i*4); 125146bec79SDirk Behme ptr = (u8 *)&cmd->response[i]; 1265db2fe3aSRaffaele Recalcati ptr += 3; 1275db2fe3aSRaffaele Recalcati for (j = 0; j < 4; j++) 1285db2fe3aSRaffaele Recalcati printf("%02X ", *ptr--); 1295db2fe3aSRaffaele Recalcati printf("\n"); 1305db2fe3aSRaffaele Recalcati } 1315db2fe3aSRaffaele Recalcati break; 1325db2fe3aSRaffaele Recalcati case MMC_RSP_R3: 1335db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n", 1345db2fe3aSRaffaele Recalcati cmd->response[0]); 1355db2fe3aSRaffaele Recalcati break; 1365db2fe3aSRaffaele Recalcati default: 1375db2fe3aSRaffaele Recalcati printf("\t\tERROR MMC rsp not supported\n"); 1385db2fe3aSRaffaele Recalcati break; 1395db2fe3aSRaffaele Recalcati } 1407863ce58SBin Meng } 141c0c76ebaSSimon Glass } 142c0c76ebaSSimon Glass 143c0c76ebaSSimon Glass void mmc_trace_state(struct mmc *mmc, struct mmc_cmd *cmd) 144c0c76ebaSSimon Glass { 145c0c76ebaSSimon Glass int status; 146c0c76ebaSSimon Glass 147c0c76ebaSSimon Glass status = (cmd->response[0] & MMC_STATUS_CURR_STATE) >> 9; 148c0c76ebaSSimon Glass printf("CURR STATE:%d\n", status); 149c0c76ebaSSimon Glass } 1505db2fe3aSRaffaele Recalcati #endif 151c0c76ebaSSimon Glass 15235f9e196SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG) 15335f9e196SJean-Jacques Hiblot const char *mmc_mode_name(enum bus_mode mode) 15435f9e196SJean-Jacques Hiblot { 15535f9e196SJean-Jacques Hiblot static const char *const names[] = { 15635f9e196SJean-Jacques Hiblot [MMC_LEGACY] = "MMC legacy", 15735f9e196SJean-Jacques Hiblot [SD_LEGACY] = "SD Legacy", 15835f9e196SJean-Jacques Hiblot [MMC_HS] = "MMC High Speed (26MHz)", 15935f9e196SJean-Jacques Hiblot [SD_HS] = "SD High Speed (50MHz)", 16035f9e196SJean-Jacques Hiblot [UHS_SDR12] = "UHS SDR12 (25MHz)", 16135f9e196SJean-Jacques Hiblot [UHS_SDR25] = "UHS SDR25 (50MHz)", 16235f9e196SJean-Jacques Hiblot [UHS_SDR50] = "UHS SDR50 (100MHz)", 16335f9e196SJean-Jacques Hiblot [UHS_SDR104] = "UHS SDR104 (208MHz)", 16435f9e196SJean-Jacques Hiblot [UHS_DDR50] = "UHS DDR50 (50MHz)", 16535f9e196SJean-Jacques Hiblot [MMC_HS_52] = "MMC High Speed (52MHz)", 16635f9e196SJean-Jacques Hiblot [MMC_DDR_52] = "MMC DDR52 (52MHz)", 16735f9e196SJean-Jacques Hiblot [MMC_HS_200] = "HS200 (200MHz)", 16835f9e196SJean-Jacques Hiblot }; 16935f9e196SJean-Jacques Hiblot 17035f9e196SJean-Jacques Hiblot if (mode >= MMC_MODES_END) 17135f9e196SJean-Jacques Hiblot return "Unknown mode"; 17235f9e196SJean-Jacques Hiblot else 17335f9e196SJean-Jacques Hiblot return names[mode]; 17435f9e196SJean-Jacques Hiblot } 17535f9e196SJean-Jacques Hiblot #endif 17635f9e196SJean-Jacques Hiblot 17705038576SJean-Jacques Hiblot static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode) 17805038576SJean-Jacques Hiblot { 17905038576SJean-Jacques Hiblot static const int freqs[] = { 18005038576SJean-Jacques Hiblot [SD_LEGACY] = 25000000, 18105038576SJean-Jacques Hiblot [MMC_HS] = 26000000, 18205038576SJean-Jacques Hiblot [SD_HS] = 50000000, 18305038576SJean-Jacques Hiblot [UHS_SDR12] = 25000000, 18405038576SJean-Jacques Hiblot [UHS_SDR25] = 50000000, 18505038576SJean-Jacques Hiblot [UHS_SDR50] = 100000000, 18605038576SJean-Jacques Hiblot [UHS_SDR104] = 208000000, 18705038576SJean-Jacques Hiblot [UHS_DDR50] = 50000000, 18805038576SJean-Jacques Hiblot [MMC_HS_52] = 52000000, 18905038576SJean-Jacques Hiblot [MMC_DDR_52] = 52000000, 19005038576SJean-Jacques Hiblot [MMC_HS_200] = 200000000, 19105038576SJean-Jacques Hiblot }; 19205038576SJean-Jacques Hiblot 19305038576SJean-Jacques Hiblot if (mode == MMC_LEGACY) 19405038576SJean-Jacques Hiblot return mmc->legacy_speed; 19505038576SJean-Jacques Hiblot else if (mode >= MMC_MODES_END) 19605038576SJean-Jacques Hiblot return 0; 19705038576SJean-Jacques Hiblot else 19805038576SJean-Jacques Hiblot return freqs[mode]; 19905038576SJean-Jacques Hiblot } 20005038576SJean-Jacques Hiblot 20135f9e196SJean-Jacques Hiblot static int mmc_select_mode(struct mmc *mmc, enum bus_mode mode) 20235f9e196SJean-Jacques Hiblot { 20335f9e196SJean-Jacques Hiblot mmc->selected_mode = mode; 20405038576SJean-Jacques Hiblot mmc->tran_speed = mmc_mode2freq(mmc, mode); 205*3862b854SJean-Jacques Hiblot mmc->ddr_mode = mmc_is_mode_ddr(mode); 20635f9e196SJean-Jacques Hiblot debug("selecting mode %s (freq : %d MHz)\n", mmc_mode_name(mode), 20735f9e196SJean-Jacques Hiblot mmc->tran_speed / 1000000); 20835f9e196SJean-Jacques Hiblot return 0; 20935f9e196SJean-Jacques Hiblot } 21035f9e196SJean-Jacques Hiblot 211e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 212c0c76ebaSSimon Glass int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) 213c0c76ebaSSimon Glass { 214c0c76ebaSSimon Glass int ret; 215c0c76ebaSSimon Glass 216c0c76ebaSSimon Glass mmmc_trace_before_send(mmc, cmd); 217c0c76ebaSSimon Glass ret = mmc->cfg->ops->send_cmd(mmc, cmd, data); 218c0c76ebaSSimon Glass mmmc_trace_after_send(mmc, cmd, ret); 219c0c76ebaSSimon Glass 2208635ff9eSMarek Vasut return ret; 221272cc70bSAndy Fleming } 2228ca51e51SSimon Glass #endif 223272cc70bSAndy Fleming 224da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout) 2255d4fc8d9SRaffaele Recalcati { 2265d4fc8d9SRaffaele Recalcati struct mmc_cmd cmd; 227d617c426SJan Kloetzke int err, retries = 5; 2285d4fc8d9SRaffaele Recalcati 2295d4fc8d9SRaffaele Recalcati cmd.cmdidx = MMC_CMD_SEND_STATUS; 2305d4fc8d9SRaffaele Recalcati cmd.resp_type = MMC_RSP_R1; 231aaf3d41aSMarek Vasut if (!mmc_host_is_spi(mmc)) 232aaf3d41aSMarek Vasut cmd.cmdarg = mmc->rca << 16; 2335d4fc8d9SRaffaele Recalcati 2341677eef4SAndrew Gabbasov while (1) { 2355d4fc8d9SRaffaele Recalcati err = mmc_send_cmd(mmc, &cmd, NULL); 236d617c426SJan Kloetzke if (!err) { 237d617c426SJan Kloetzke if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) && 238d617c426SJan Kloetzke (cmd.response[0] & MMC_STATUS_CURR_STATE) != 239d617c426SJan Kloetzke MMC_STATE_PRG) 2405d4fc8d9SRaffaele Recalcati break; 241d0c221feSJean-Jacques Hiblot 242d0c221feSJean-Jacques Hiblot if (cmd.response[0] & MMC_STATUS_MASK) { 24356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 244d617c426SJan Kloetzke printf("Status Error: 0x%08X\n", 245d617c426SJan Kloetzke cmd.response[0]); 24656196826SPaul Burton #endif 247915ffa52SJaehoon Chung return -ECOMM; 248d617c426SJan Kloetzke } 249d617c426SJan Kloetzke } else if (--retries < 0) 250d617c426SJan Kloetzke return err; 2515d4fc8d9SRaffaele Recalcati 2521677eef4SAndrew Gabbasov if (timeout-- <= 0) 2531677eef4SAndrew Gabbasov break; 2545d4fc8d9SRaffaele Recalcati 2551677eef4SAndrew Gabbasov udelay(1000); 2561677eef4SAndrew Gabbasov } 2575d4fc8d9SRaffaele Recalcati 258c0c76ebaSSimon Glass mmc_trace_state(mmc, &cmd); 2595b0c942fSJongman Heo if (timeout <= 0) { 26056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2615d4fc8d9SRaffaele Recalcati printf("Timeout waiting card ready\n"); 26256196826SPaul Burton #endif 263915ffa52SJaehoon Chung return -ETIMEDOUT; 2645d4fc8d9SRaffaele Recalcati } 2655d4fc8d9SRaffaele Recalcati 2665d4fc8d9SRaffaele Recalcati return 0; 2675d4fc8d9SRaffaele Recalcati } 2685d4fc8d9SRaffaele Recalcati 269da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len) 270272cc70bSAndy Fleming { 271272cc70bSAndy Fleming struct mmc_cmd cmd; 272272cc70bSAndy Fleming 273786e8f81SAndrew Gabbasov if (mmc->ddr_mode) 274d22e3d46SJaehoon Chung return 0; 275d22e3d46SJaehoon Chung 276272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SET_BLOCKLEN; 277272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 278272cc70bSAndy Fleming cmd.cmdarg = len; 279272cc70bSAndy Fleming 280272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, NULL); 281272cc70bSAndy Fleming } 282272cc70bSAndy Fleming 283ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start, 284fdbb873eSKim Phillips lbaint_t blkcnt) 285272cc70bSAndy Fleming { 286272cc70bSAndy Fleming struct mmc_cmd cmd; 287272cc70bSAndy Fleming struct mmc_data data; 288272cc70bSAndy Fleming 2894a1a06bcSAlagu Sankar if (blkcnt > 1) 2904a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; 2914a1a06bcSAlagu Sankar else 292272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; 293272cc70bSAndy Fleming 294272cc70bSAndy Fleming if (mmc->high_capacity) 2954a1a06bcSAlagu Sankar cmd.cmdarg = start; 296272cc70bSAndy Fleming else 2974a1a06bcSAlagu Sankar cmd.cmdarg = start * mmc->read_bl_len; 298272cc70bSAndy Fleming 299272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 300272cc70bSAndy Fleming 301272cc70bSAndy Fleming data.dest = dst; 3024a1a06bcSAlagu Sankar data.blocks = blkcnt; 303272cc70bSAndy Fleming data.blocksize = mmc->read_bl_len; 304272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 305272cc70bSAndy Fleming 3064a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, &data)) 3074a1a06bcSAlagu Sankar return 0; 3084a1a06bcSAlagu Sankar 3094a1a06bcSAlagu Sankar if (blkcnt > 1) { 3104a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; 3114a1a06bcSAlagu Sankar cmd.cmdarg = 0; 3124a1a06bcSAlagu Sankar cmd.resp_type = MMC_RSP_R1b; 3134a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, NULL)) { 31456196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 3154a1a06bcSAlagu Sankar printf("mmc fail to send stop cmd\n"); 31656196826SPaul Burton #endif 3174a1a06bcSAlagu Sankar return 0; 3184a1a06bcSAlagu Sankar } 319272cc70bSAndy Fleming } 320272cc70bSAndy Fleming 3214a1a06bcSAlagu Sankar return blkcnt; 322272cc70bSAndy Fleming } 323272cc70bSAndy Fleming 324c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK) 3257dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst) 32633fb211dSSimon Glass #else 3277dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, 3287dba0b93SSimon Glass void *dst) 32933fb211dSSimon Glass #endif 330272cc70bSAndy Fleming { 331c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK) 33233fb211dSSimon Glass struct blk_desc *block_dev = dev_get_uclass_platdata(dev); 33333fb211dSSimon Glass #endif 334bcce53d0SSimon Glass int dev_num = block_dev->devnum; 335873cc1d7SStephen Warren int err; 3364a1a06bcSAlagu Sankar lbaint_t cur, blocks_todo = blkcnt; 337272cc70bSAndy Fleming 3384a1a06bcSAlagu Sankar if (blkcnt == 0) 3394a1a06bcSAlagu Sankar return 0; 3404a1a06bcSAlagu Sankar 3414a1a06bcSAlagu Sankar struct mmc *mmc = find_mmc_device(dev_num); 342272cc70bSAndy Fleming if (!mmc) 343272cc70bSAndy Fleming return 0; 344272cc70bSAndy Fleming 345b5b838f1SMarek Vasut if (CONFIG_IS_ENABLED(MMC_TINY)) 346b5b838f1SMarek Vasut err = mmc_switch_part(mmc, block_dev->hwpart); 347b5b838f1SMarek Vasut else 34869f45cd5SSimon Glass err = blk_dselect_hwpart(block_dev, block_dev->hwpart); 349b5b838f1SMarek Vasut 350873cc1d7SStephen Warren if (err < 0) 351873cc1d7SStephen Warren return 0; 352873cc1d7SStephen Warren 353c40fdca6SSimon Glass if ((start + blkcnt) > block_dev->lba) { 35456196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 355ff8fef56SSascha Silbe printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", 356c40fdca6SSimon Glass start + blkcnt, block_dev->lba); 35756196826SPaul Burton #endif 358d2bf29e3SLei Wen return 0; 359d2bf29e3SLei Wen } 360272cc70bSAndy Fleming 36111692991SSimon Glass if (mmc_set_blocklen(mmc, mmc->read_bl_len)) { 36211692991SSimon Glass debug("%s: Failed to set blocklen\n", __func__); 363272cc70bSAndy Fleming return 0; 36411692991SSimon Glass } 365272cc70bSAndy Fleming 3664a1a06bcSAlagu Sankar do { 36793bfd616SPantelis Antoniou cur = (blocks_todo > mmc->cfg->b_max) ? 36893bfd616SPantelis Antoniou mmc->cfg->b_max : blocks_todo; 36911692991SSimon Glass if (mmc_read_blocks(mmc, dst, start, cur) != cur) { 37011692991SSimon Glass debug("%s: Failed to read blocks\n", __func__); 3714a1a06bcSAlagu Sankar return 0; 37211692991SSimon Glass } 3734a1a06bcSAlagu Sankar blocks_todo -= cur; 3744a1a06bcSAlagu Sankar start += cur; 3754a1a06bcSAlagu Sankar dst += cur * mmc->read_bl_len; 3764a1a06bcSAlagu Sankar } while (blocks_todo > 0); 377272cc70bSAndy Fleming 378272cc70bSAndy Fleming return blkcnt; 379272cc70bSAndy Fleming } 380272cc70bSAndy Fleming 381fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc) 382272cc70bSAndy Fleming { 383272cc70bSAndy Fleming struct mmc_cmd cmd; 384272cc70bSAndy Fleming int err; 385272cc70bSAndy Fleming 386272cc70bSAndy Fleming udelay(1000); 387272cc70bSAndy Fleming 388272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_GO_IDLE_STATE; 389272cc70bSAndy Fleming cmd.cmdarg = 0; 390272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_NONE; 391272cc70bSAndy Fleming 392272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 393272cc70bSAndy Fleming 394272cc70bSAndy Fleming if (err) 395272cc70bSAndy Fleming return err; 396272cc70bSAndy Fleming 397272cc70bSAndy Fleming udelay(2000); 398272cc70bSAndy Fleming 399272cc70bSAndy Fleming return 0; 400272cc70bSAndy Fleming } 401272cc70bSAndy Fleming 402fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc) 403272cc70bSAndy Fleming { 404272cc70bSAndy Fleming int timeout = 1000; 405272cc70bSAndy Fleming int err; 406272cc70bSAndy Fleming struct mmc_cmd cmd; 407272cc70bSAndy Fleming 4081677eef4SAndrew Gabbasov while (1) { 409272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 410272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 411272cc70bSAndy Fleming cmd.cmdarg = 0; 412272cc70bSAndy Fleming 413272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 414272cc70bSAndy Fleming 415272cc70bSAndy Fleming if (err) 416272cc70bSAndy Fleming return err; 417272cc70bSAndy Fleming 418272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_OP_COND; 419272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R3; 420250de12bSStefano Babic 421250de12bSStefano Babic /* 422250de12bSStefano Babic * Most cards do not answer if some reserved bits 423250de12bSStefano Babic * in the ocr are set. However, Some controller 424250de12bSStefano Babic * can set bit 7 (reserved for low voltages), but 425250de12bSStefano Babic * how to manage low voltages SD card is not yet 426250de12bSStefano Babic * specified. 427250de12bSStefano Babic */ 428d52ebf10SThomas Chou cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 : 42993bfd616SPantelis Antoniou (mmc->cfg->voltages & 0xff8000); 430272cc70bSAndy Fleming 431272cc70bSAndy Fleming if (mmc->version == SD_VERSION_2) 432272cc70bSAndy Fleming cmd.cmdarg |= OCR_HCS; 433272cc70bSAndy Fleming 434272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 435272cc70bSAndy Fleming 436272cc70bSAndy Fleming if (err) 437272cc70bSAndy Fleming return err; 438272cc70bSAndy Fleming 4391677eef4SAndrew Gabbasov if (cmd.response[0] & OCR_BUSY) 4401677eef4SAndrew Gabbasov break; 441272cc70bSAndy Fleming 4421677eef4SAndrew Gabbasov if (timeout-- <= 0) 443915ffa52SJaehoon Chung return -EOPNOTSUPP; 444272cc70bSAndy Fleming 4451677eef4SAndrew Gabbasov udelay(1000); 4461677eef4SAndrew Gabbasov } 4471677eef4SAndrew Gabbasov 448272cc70bSAndy Fleming if (mmc->version != SD_VERSION_2) 449272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 450272cc70bSAndy Fleming 451d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 452d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 453d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 454d52ebf10SThomas Chou cmd.cmdarg = 0; 455d52ebf10SThomas Chou 456d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 457d52ebf10SThomas Chou 458d52ebf10SThomas Chou if (err) 459d52ebf10SThomas Chou return err; 460d52ebf10SThomas Chou } 461d52ebf10SThomas Chou 462998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 463272cc70bSAndy Fleming 464272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 465272cc70bSAndy Fleming mmc->rca = 0; 466272cc70bSAndy Fleming 467272cc70bSAndy Fleming return 0; 468272cc70bSAndy Fleming } 469272cc70bSAndy Fleming 4705289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg) 471272cc70bSAndy Fleming { 4725289b535SAndrew Gabbasov struct mmc_cmd cmd; 473272cc70bSAndy Fleming int err; 474272cc70bSAndy Fleming 4755289b535SAndrew Gabbasov cmd.cmdidx = MMC_CMD_SEND_OP_COND; 4765289b535SAndrew Gabbasov cmd.resp_type = MMC_RSP_R3; 4775289b535SAndrew Gabbasov cmd.cmdarg = 0; 4785a20397bSRob Herring if (use_arg && !mmc_host_is_spi(mmc)) 4795a20397bSRob Herring cmd.cmdarg = OCR_HCS | 48093bfd616SPantelis Antoniou (mmc->cfg->voltages & 481a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_VOLTAGE_MASK)) | 482a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_ACCESS_MODE); 483e9550449SChe-Liang Chiou 4845289b535SAndrew Gabbasov err = mmc_send_cmd(mmc, &cmd, NULL); 485e9550449SChe-Liang Chiou if (err) 486e9550449SChe-Liang Chiou return err; 4875289b535SAndrew Gabbasov mmc->ocr = cmd.response[0]; 488e9550449SChe-Liang Chiou return 0; 489e9550449SChe-Liang Chiou } 490e9550449SChe-Liang Chiou 491750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc) 492e9550449SChe-Liang Chiou { 493e9550449SChe-Liang Chiou int err, i; 494e9550449SChe-Liang Chiou 495272cc70bSAndy Fleming /* Some cards seem to need this */ 496272cc70bSAndy Fleming mmc_go_idle(mmc); 497272cc70bSAndy Fleming 49831cacbabSRaffaele Recalcati /* Asking to the card its capabilities */ 499e9550449SChe-Liang Chiou for (i = 0; i < 2; i++) { 5005289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, i != 0); 50131cacbabSRaffaele Recalcati if (err) 50231cacbabSRaffaele Recalcati return err; 50331cacbabSRaffaele Recalcati 504e9550449SChe-Liang Chiou /* exit if not busy (flag seems to be inverted) */ 505a626c8d4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 506bd47c135SAndrew Gabbasov break; 507e9550449SChe-Liang Chiou } 508bd47c135SAndrew Gabbasov mmc->op_cond_pending = 1; 509bd47c135SAndrew Gabbasov return 0; 510e9550449SChe-Liang Chiou } 51131cacbabSRaffaele Recalcati 512750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc) 513e9550449SChe-Liang Chiou { 514e9550449SChe-Liang Chiou struct mmc_cmd cmd; 515e9550449SChe-Liang Chiou int timeout = 1000; 516e9550449SChe-Liang Chiou uint start; 517e9550449SChe-Liang Chiou int err; 518e9550449SChe-Liang Chiou 519e9550449SChe-Liang Chiou mmc->op_cond_pending = 0; 520cc17c01fSAndrew Gabbasov if (!(mmc->ocr & OCR_BUSY)) { 521d188b113SYangbo Lu /* Some cards seem to need this */ 522d188b113SYangbo Lu mmc_go_idle(mmc); 523d188b113SYangbo Lu 524e9550449SChe-Liang Chiou start = get_timer(0); 5251677eef4SAndrew Gabbasov while (1) { 5265289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, 1); 527272cc70bSAndy Fleming if (err) 528272cc70bSAndy Fleming return err; 5291677eef4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 5301677eef4SAndrew Gabbasov break; 531e9550449SChe-Liang Chiou if (get_timer(start) > timeout) 532915ffa52SJaehoon Chung return -EOPNOTSUPP; 533e9550449SChe-Liang Chiou udelay(100); 5341677eef4SAndrew Gabbasov } 535cc17c01fSAndrew Gabbasov } 536272cc70bSAndy Fleming 537d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 538d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 539d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 540d52ebf10SThomas Chou cmd.cmdarg = 0; 541d52ebf10SThomas Chou 542d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 543d52ebf10SThomas Chou 544d52ebf10SThomas Chou if (err) 545d52ebf10SThomas Chou return err; 546a626c8d4SAndrew Gabbasov 547a626c8d4SAndrew Gabbasov mmc->ocr = cmd.response[0]; 548d52ebf10SThomas Chou } 549d52ebf10SThomas Chou 550272cc70bSAndy Fleming mmc->version = MMC_VERSION_UNKNOWN; 551272cc70bSAndy Fleming 552272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 553def816a2SStephen Warren mmc->rca = 1; 554272cc70bSAndy Fleming 555272cc70bSAndy Fleming return 0; 556272cc70bSAndy Fleming } 557272cc70bSAndy Fleming 558272cc70bSAndy Fleming 559fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) 560272cc70bSAndy Fleming { 561272cc70bSAndy Fleming struct mmc_cmd cmd; 562272cc70bSAndy Fleming struct mmc_data data; 563272cc70bSAndy Fleming int err; 564272cc70bSAndy Fleming 565272cc70bSAndy Fleming /* Get the Card Status Register */ 566272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_EXT_CSD; 567272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 568272cc70bSAndy Fleming cmd.cmdarg = 0; 569272cc70bSAndy Fleming 570cdfd1ac6SYoshihiro Shimoda data.dest = (char *)ext_csd; 571272cc70bSAndy Fleming data.blocks = 1; 5728bfa195eSSimon Glass data.blocksize = MMC_MAX_BLOCK_LEN; 573272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 574272cc70bSAndy Fleming 575272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 576272cc70bSAndy Fleming 577272cc70bSAndy Fleming return err; 578272cc70bSAndy Fleming } 579272cc70bSAndy Fleming 580c40704f4SSimon Glass int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) 581272cc70bSAndy Fleming { 582272cc70bSAndy Fleming struct mmc_cmd cmd; 5835d4fc8d9SRaffaele Recalcati int timeout = 1000; 584a9003dc6SMaxime Ripard int retries = 3; 5855d4fc8d9SRaffaele Recalcati int ret; 586272cc70bSAndy Fleming 587272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SWITCH; 588272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 589272cc70bSAndy Fleming cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 590272cc70bSAndy Fleming (index << 16) | 591272cc70bSAndy Fleming (value << 8); 592272cc70bSAndy Fleming 593a9003dc6SMaxime Ripard while (retries > 0) { 5945d4fc8d9SRaffaele Recalcati ret = mmc_send_cmd(mmc, &cmd, NULL); 5955d4fc8d9SRaffaele Recalcati 5965d4fc8d9SRaffaele Recalcati /* Waiting for the ready status */ 597a9003dc6SMaxime Ripard if (!ret) { 59893ad0d18SJan Kloetzke ret = mmc_send_status(mmc, timeout); 599a9003dc6SMaxime Ripard return ret; 600a9003dc6SMaxime Ripard } 601a9003dc6SMaxime Ripard 602a9003dc6SMaxime Ripard retries--; 603a9003dc6SMaxime Ripard } 6045d4fc8d9SRaffaele Recalcati 6055d4fc8d9SRaffaele Recalcati return ret; 6065d4fc8d9SRaffaele Recalcati 607272cc70bSAndy Fleming } 608272cc70bSAndy Fleming 609*3862b854SJean-Jacques Hiblot static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode) 610272cc70bSAndy Fleming { 611272cc70bSAndy Fleming int err; 612*3862b854SJean-Jacques Hiblot int speed_bits; 613*3862b854SJean-Jacques Hiblot 614*3862b854SJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 615*3862b854SJean-Jacques Hiblot 616*3862b854SJean-Jacques Hiblot switch (mode) { 617*3862b854SJean-Jacques Hiblot case MMC_HS: 618*3862b854SJean-Jacques Hiblot case MMC_HS_52: 619*3862b854SJean-Jacques Hiblot case MMC_DDR_52: 620*3862b854SJean-Jacques Hiblot speed_bits = EXT_CSD_TIMING_HS; 621*3862b854SJean-Jacques Hiblot case MMC_LEGACY: 622*3862b854SJean-Jacques Hiblot speed_bits = EXT_CSD_TIMING_LEGACY; 623*3862b854SJean-Jacques Hiblot break; 624*3862b854SJean-Jacques Hiblot default: 625*3862b854SJean-Jacques Hiblot return -EINVAL; 626*3862b854SJean-Jacques Hiblot } 627*3862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 628*3862b854SJean-Jacques Hiblot speed_bits); 629*3862b854SJean-Jacques Hiblot if (err) 630*3862b854SJean-Jacques Hiblot return err; 631*3862b854SJean-Jacques Hiblot 632*3862b854SJean-Jacques Hiblot if ((mode == MMC_HS) || (mode == MMC_HS_52)) { 633*3862b854SJean-Jacques Hiblot /* Now check to see that it worked */ 634*3862b854SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, test_csd); 635*3862b854SJean-Jacques Hiblot if (err) 636*3862b854SJean-Jacques Hiblot return err; 637*3862b854SJean-Jacques Hiblot 638*3862b854SJean-Jacques Hiblot /* No high-speed support */ 639*3862b854SJean-Jacques Hiblot if (!test_csd[EXT_CSD_HS_TIMING]) 640*3862b854SJean-Jacques Hiblot return -ENOTSUPP; 641*3862b854SJean-Jacques Hiblot } 642*3862b854SJean-Jacques Hiblot 643*3862b854SJean-Jacques Hiblot return 0; 644*3862b854SJean-Jacques Hiblot } 645*3862b854SJean-Jacques Hiblot 646*3862b854SJean-Jacques Hiblot static int mmc_get_capabilities(struct mmc *mmc) 647*3862b854SJean-Jacques Hiblot { 648*3862b854SJean-Jacques Hiblot u8 *ext_csd = mmc->ext_csd; 649*3862b854SJean-Jacques Hiblot char cardtype; 650272cc70bSAndy Fleming 651d0c221feSJean-Jacques Hiblot mmc->card_caps = MMC_MODE_1BIT; 652272cc70bSAndy Fleming 653d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 654d52ebf10SThomas Chou return 0; 655d52ebf10SThomas Chou 656272cc70bSAndy Fleming /* Only version 4 supports high-speed */ 657272cc70bSAndy Fleming if (mmc->version < MMC_VERSION_4) 658272cc70bSAndy Fleming return 0; 659272cc70bSAndy Fleming 660*3862b854SJean-Jacques Hiblot if (!ext_csd) { 661*3862b854SJean-Jacques Hiblot printf("No ext_csd found!\n"); /* this should enver happen */ 662*3862b854SJean-Jacques Hiblot return -ENOTSUPP; 663*3862b854SJean-Jacques Hiblot } 664*3862b854SJean-Jacques Hiblot 665fc5b32fbSAndrew Gabbasov mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; 666fc5b32fbSAndrew Gabbasov 6670560db18SLei Wen cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf; 668272cc70bSAndy Fleming 669272cc70bSAndy Fleming /* High Speed is set, there are two types: 52MHz and 26MHz */ 670d22e3d46SJaehoon Chung if (cardtype & EXT_CSD_CARD_TYPE_52) { 671*3862b854SJean-Jacques Hiblot if (cardtype & EXT_CSD_CARD_TYPE_DDR_52) 672d22e3d46SJaehoon Chung mmc->card_caps |= MMC_MODE_DDR_52MHz; 673*3862b854SJean-Jacques Hiblot mmc->card_caps |= MMC_MODE_HS_52MHz; 674d22e3d46SJaehoon Chung } 675*3862b854SJean-Jacques Hiblot if (cardtype & EXT_CSD_CARD_TYPE_26) 676*3862b854SJean-Jacques Hiblot mmc->card_caps |= MMC_MODE_HS; 677272cc70bSAndy Fleming 678272cc70bSAndy Fleming return 0; 679272cc70bSAndy Fleming } 680272cc70bSAndy Fleming 681f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num) 682f866a46dSStephen Warren { 683f866a46dSStephen Warren switch (part_num) { 684f866a46dSStephen Warren case 0: 685f866a46dSStephen Warren mmc->capacity = mmc->capacity_user; 686f866a46dSStephen Warren break; 687f866a46dSStephen Warren case 1: 688f866a46dSStephen Warren case 2: 689f866a46dSStephen Warren mmc->capacity = mmc->capacity_boot; 690f866a46dSStephen Warren break; 691f866a46dSStephen Warren case 3: 692f866a46dSStephen Warren mmc->capacity = mmc->capacity_rpmb; 693f866a46dSStephen Warren break; 694f866a46dSStephen Warren case 4: 695f866a46dSStephen Warren case 5: 696f866a46dSStephen Warren case 6: 697f866a46dSStephen Warren case 7: 698f866a46dSStephen Warren mmc->capacity = mmc->capacity_gp[part_num - 4]; 699f866a46dSStephen Warren break; 700f866a46dSStephen Warren default: 701f866a46dSStephen Warren return -1; 702f866a46dSStephen Warren } 703f866a46dSStephen Warren 704c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len); 705f866a46dSStephen Warren 706f866a46dSStephen Warren return 0; 707f866a46dSStephen Warren } 708f866a46dSStephen Warren 7097dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num) 710bc897b1dSLei Wen { 711f866a46dSStephen Warren int ret; 712bc897b1dSLei Wen 713f866a46dSStephen Warren ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 714bc897b1dSLei Wen (mmc->part_config & ~PART_ACCESS_MASK) 715bc897b1dSLei Wen | (part_num & PART_ACCESS_MASK)); 716f866a46dSStephen Warren 7176dc93e70SPeter Bigot /* 7186dc93e70SPeter Bigot * Set the capacity if the switch succeeded or was intended 7196dc93e70SPeter Bigot * to return to representing the raw device. 7206dc93e70SPeter Bigot */ 721873cc1d7SStephen Warren if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) { 7226dc93e70SPeter Bigot ret = mmc_set_capacity(mmc, part_num); 723fdbb139fSSimon Glass mmc_get_blk_desc(mmc)->hwpart = part_num; 724873cc1d7SStephen Warren } 7256dc93e70SPeter Bigot 7266dc93e70SPeter Bigot return ret; 727bc897b1dSLei Wen } 728bc897b1dSLei Wen 729ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc, 730ac9da0e0SDiego Santa Cruz const struct mmc_hwpart_conf *conf, 731ac9da0e0SDiego Santa Cruz enum mmc_hwpart_conf_mode mode) 732ac9da0e0SDiego Santa Cruz { 733ac9da0e0SDiego Santa Cruz u8 part_attrs = 0; 734ac9da0e0SDiego Santa Cruz u32 enh_size_mult; 735ac9da0e0SDiego Santa Cruz u32 enh_start_addr; 736ac9da0e0SDiego Santa Cruz u32 gp_size_mult[4]; 737ac9da0e0SDiego Santa Cruz u32 max_enh_size_mult; 738ac9da0e0SDiego Santa Cruz u32 tot_enh_size_mult = 0; 7398dda5b0eSDiego Santa Cruz u8 wr_rel_set; 740ac9da0e0SDiego Santa Cruz int i, pidx, err; 741ac9da0e0SDiego Santa Cruz ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 742ac9da0e0SDiego Santa Cruz 743ac9da0e0SDiego Santa Cruz if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE) 744ac9da0e0SDiego Santa Cruz return -EINVAL; 745ac9da0e0SDiego Santa Cruz 746ac9da0e0SDiego Santa Cruz if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) { 747ac9da0e0SDiego Santa Cruz printf("eMMC >= 4.4 required for enhanced user data area\n"); 748ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 749ac9da0e0SDiego Santa Cruz } 750ac9da0e0SDiego Santa Cruz 751ac9da0e0SDiego Santa Cruz if (!(mmc->part_support & PART_SUPPORT)) { 752ac9da0e0SDiego Santa Cruz printf("Card does not support partitioning\n"); 753ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 754ac9da0e0SDiego Santa Cruz } 755ac9da0e0SDiego Santa Cruz 756ac9da0e0SDiego Santa Cruz if (!mmc->hc_wp_grp_size) { 757ac9da0e0SDiego Santa Cruz printf("Card does not define HC WP group size\n"); 758ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 759ac9da0e0SDiego Santa Cruz } 760ac9da0e0SDiego Santa Cruz 761ac9da0e0SDiego Santa Cruz /* check partition alignment and total enhanced size */ 762ac9da0e0SDiego Santa Cruz if (conf->user.enh_size) { 763ac9da0e0SDiego Santa Cruz if (conf->user.enh_size % mmc->hc_wp_grp_size || 764ac9da0e0SDiego Santa Cruz conf->user.enh_start % mmc->hc_wp_grp_size) { 765ac9da0e0SDiego Santa Cruz printf("User data enhanced area not HC WP group " 766ac9da0e0SDiego Santa Cruz "size aligned\n"); 767ac9da0e0SDiego Santa Cruz return -EINVAL; 768ac9da0e0SDiego Santa Cruz } 769ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_USR; 770ac9da0e0SDiego Santa Cruz enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size; 771ac9da0e0SDiego Santa Cruz if (mmc->high_capacity) { 772ac9da0e0SDiego Santa Cruz enh_start_addr = conf->user.enh_start; 773ac9da0e0SDiego Santa Cruz } else { 774ac9da0e0SDiego Santa Cruz enh_start_addr = (conf->user.enh_start << 9); 775ac9da0e0SDiego Santa Cruz } 776ac9da0e0SDiego Santa Cruz } else { 777ac9da0e0SDiego Santa Cruz enh_size_mult = 0; 778ac9da0e0SDiego Santa Cruz enh_start_addr = 0; 779ac9da0e0SDiego Santa Cruz } 780ac9da0e0SDiego Santa Cruz tot_enh_size_mult += enh_size_mult; 781ac9da0e0SDiego Santa Cruz 782ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 783ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) { 784ac9da0e0SDiego Santa Cruz printf("GP%i partition not HC WP group size " 785ac9da0e0SDiego Santa Cruz "aligned\n", pidx+1); 786ac9da0e0SDiego Santa Cruz return -EINVAL; 787ac9da0e0SDiego Santa Cruz } 788ac9da0e0SDiego Santa Cruz gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size; 789ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) { 790ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_GP(pidx); 791ac9da0e0SDiego Santa Cruz tot_enh_size_mult += gp_size_mult[pidx]; 792ac9da0e0SDiego Santa Cruz } 793ac9da0e0SDiego Santa Cruz } 794ac9da0e0SDiego Santa Cruz 795ac9da0e0SDiego Santa Cruz if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) { 796ac9da0e0SDiego Santa Cruz printf("Card does not support enhanced attribute\n"); 797ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 798ac9da0e0SDiego Santa Cruz } 799ac9da0e0SDiego Santa Cruz 800ac9da0e0SDiego Santa Cruz err = mmc_send_ext_csd(mmc, ext_csd); 801ac9da0e0SDiego Santa Cruz if (err) 802ac9da0e0SDiego Santa Cruz return err; 803ac9da0e0SDiego Santa Cruz 804ac9da0e0SDiego Santa Cruz max_enh_size_mult = 805ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) + 806ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) + 807ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]; 808ac9da0e0SDiego Santa Cruz if (tot_enh_size_mult > max_enh_size_mult) { 809ac9da0e0SDiego Santa Cruz printf("Total enhanced size exceeds maximum (%u > %u)\n", 810ac9da0e0SDiego Santa Cruz tot_enh_size_mult, max_enh_size_mult); 811ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 812ac9da0e0SDiego Santa Cruz } 813ac9da0e0SDiego Santa Cruz 8148dda5b0eSDiego Santa Cruz /* The default value of EXT_CSD_WR_REL_SET is device 8158dda5b0eSDiego Santa Cruz * dependent, the values can only be changed if the 8168dda5b0eSDiego Santa Cruz * EXT_CSD_HS_CTRL_REL bit is set. The values can be 8178dda5b0eSDiego Santa Cruz * changed only once and before partitioning is completed. */ 8188dda5b0eSDiego Santa Cruz wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 8198dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_change) { 8208dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_set) 8218dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_USR; 8228dda5b0eSDiego Santa Cruz else 8238dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR; 8248dda5b0eSDiego Santa Cruz } 8258dda5b0eSDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 8268dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_change) { 8278dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_set) 8288dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx); 8298dda5b0eSDiego Santa Cruz else 8308dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx); 8318dda5b0eSDiego Santa Cruz } 8328dda5b0eSDiego Santa Cruz } 8338dda5b0eSDiego Santa Cruz 8348dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] && 8358dda5b0eSDiego Santa Cruz !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) { 8368dda5b0eSDiego Santa Cruz puts("Card does not support host controlled partition write " 8378dda5b0eSDiego Santa Cruz "reliability settings\n"); 8388dda5b0eSDiego Santa Cruz return -EMEDIUMTYPE; 8398dda5b0eSDiego Santa Cruz } 8408dda5b0eSDiego Santa Cruz 841ac9da0e0SDiego Santa Cruz if (ext_csd[EXT_CSD_PARTITION_SETTING] & 842ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED) { 843ac9da0e0SDiego Santa Cruz printf("Card already partitioned\n"); 844ac9da0e0SDiego Santa Cruz return -EPERM; 845ac9da0e0SDiego Santa Cruz } 846ac9da0e0SDiego Santa Cruz 847ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_CHECK) 848ac9da0e0SDiego Santa Cruz return 0; 849ac9da0e0SDiego Santa Cruz 850ac9da0e0SDiego Santa Cruz /* Partitioning requires high-capacity size definitions */ 851ac9da0e0SDiego Santa Cruz if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) { 852ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 853ac9da0e0SDiego Santa Cruz EXT_CSD_ERASE_GROUP_DEF, 1); 854ac9da0e0SDiego Santa Cruz 855ac9da0e0SDiego Santa Cruz if (err) 856ac9da0e0SDiego Santa Cruz return err; 857ac9da0e0SDiego Santa Cruz 858ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 859ac9da0e0SDiego Santa Cruz 860ac9da0e0SDiego Santa Cruz /* update erase group size to be high-capacity */ 861ac9da0e0SDiego Santa Cruz mmc->erase_grp_size = 862ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 863ac9da0e0SDiego Santa Cruz 864ac9da0e0SDiego Santa Cruz } 865ac9da0e0SDiego Santa Cruz 866ac9da0e0SDiego Santa Cruz /* all OK, write the configuration */ 867ac9da0e0SDiego Santa Cruz for (i = 0; i < 4; i++) { 868ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 869ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_START_ADDR+i, 870ac9da0e0SDiego Santa Cruz (enh_start_addr >> (i*8)) & 0xFF); 871ac9da0e0SDiego Santa Cruz if (err) 872ac9da0e0SDiego Santa Cruz return err; 873ac9da0e0SDiego Santa Cruz } 874ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 875ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 876ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_SIZE_MULT+i, 877ac9da0e0SDiego Santa Cruz (enh_size_mult >> (i*8)) & 0xFF); 878ac9da0e0SDiego Santa Cruz if (err) 879ac9da0e0SDiego Santa Cruz return err; 880ac9da0e0SDiego Santa Cruz } 881ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 882ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 883ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 884ac9da0e0SDiego Santa Cruz EXT_CSD_GP_SIZE_MULT+pidx*3+i, 885ac9da0e0SDiego Santa Cruz (gp_size_mult[pidx] >> (i*8)) & 0xFF); 886ac9da0e0SDiego Santa Cruz if (err) 887ac9da0e0SDiego Santa Cruz return err; 888ac9da0e0SDiego Santa Cruz } 889ac9da0e0SDiego Santa Cruz } 890ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 891ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs); 892ac9da0e0SDiego Santa Cruz if (err) 893ac9da0e0SDiego Santa Cruz return err; 894ac9da0e0SDiego Santa Cruz 895ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_SET) 896ac9da0e0SDiego Santa Cruz return 0; 897ac9da0e0SDiego Santa Cruz 8988dda5b0eSDiego Santa Cruz /* The WR_REL_SET is a write-once register but shall be 8998dda5b0eSDiego Santa Cruz * written before setting PART_SETTING_COMPLETED. As it is 9008dda5b0eSDiego Santa Cruz * write-once we can only write it when completing the 9018dda5b0eSDiego Santa Cruz * partitioning. */ 9028dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) { 9038dda5b0eSDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 9048dda5b0eSDiego Santa Cruz EXT_CSD_WR_REL_SET, wr_rel_set); 9058dda5b0eSDiego Santa Cruz if (err) 9068dda5b0eSDiego Santa Cruz return err; 9078dda5b0eSDiego Santa Cruz } 9088dda5b0eSDiego Santa Cruz 909ac9da0e0SDiego Santa Cruz /* Setting PART_SETTING_COMPLETED confirms the partition 910ac9da0e0SDiego Santa Cruz * configuration but it only becomes effective after power 911ac9da0e0SDiego Santa Cruz * cycle, so we do not adjust the partition related settings 912ac9da0e0SDiego Santa Cruz * in the mmc struct. */ 913ac9da0e0SDiego Santa Cruz 914ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 915ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING, 916ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 917ac9da0e0SDiego Santa Cruz if (err) 918ac9da0e0SDiego Santa Cruz return err; 919ac9da0e0SDiego Santa Cruz 920ac9da0e0SDiego Santa Cruz return 0; 921ac9da0e0SDiego Santa Cruz } 922ac9da0e0SDiego Santa Cruz 923e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 92448972d90SThierry Reding int mmc_getcd(struct mmc *mmc) 92548972d90SThierry Reding { 92648972d90SThierry Reding int cd; 92748972d90SThierry Reding 92848972d90SThierry Reding cd = board_mmc_getcd(mmc); 92948972d90SThierry Reding 930d4e1da4eSPeter Korsgaard if (cd < 0) { 93193bfd616SPantelis Antoniou if (mmc->cfg->ops->getcd) 93293bfd616SPantelis Antoniou cd = mmc->cfg->ops->getcd(mmc); 933d4e1da4eSPeter Korsgaard else 934d4e1da4eSPeter Korsgaard cd = 1; 935d4e1da4eSPeter Korsgaard } 93648972d90SThierry Reding 93748972d90SThierry Reding return cd; 93848972d90SThierry Reding } 9398ca51e51SSimon Glass #endif 94048972d90SThierry Reding 941fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) 942272cc70bSAndy Fleming { 943272cc70bSAndy Fleming struct mmc_cmd cmd; 944272cc70bSAndy Fleming struct mmc_data data; 945272cc70bSAndy Fleming 946272cc70bSAndy Fleming /* Switch the frequency */ 947272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC; 948272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 949272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff; 950272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4)); 951272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4); 952272cc70bSAndy Fleming 953272cc70bSAndy Fleming data.dest = (char *)resp; 954272cc70bSAndy Fleming data.blocksize = 64; 955272cc70bSAndy Fleming data.blocks = 1; 956272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 957272cc70bSAndy Fleming 958272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 959272cc70bSAndy Fleming } 960272cc70bSAndy Fleming 961272cc70bSAndy Fleming 962d0c221feSJean-Jacques Hiblot static int sd_get_capabilities(struct mmc *mmc) 963272cc70bSAndy Fleming { 964272cc70bSAndy Fleming int err; 965272cc70bSAndy Fleming struct mmc_cmd cmd; 96618e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2); 96718e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16); 968272cc70bSAndy Fleming struct mmc_data data; 969272cc70bSAndy Fleming int timeout; 970272cc70bSAndy Fleming 971d0c221feSJean-Jacques Hiblot mmc->card_caps = MMC_MODE_1BIT; 972272cc70bSAndy Fleming 973d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 974d52ebf10SThomas Chou return 0; 975d52ebf10SThomas Chou 976272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */ 977272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 978272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 979272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 980272cc70bSAndy Fleming 981272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 982272cc70bSAndy Fleming 983272cc70bSAndy Fleming if (err) 984272cc70bSAndy Fleming return err; 985272cc70bSAndy Fleming 986272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR; 987272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 988272cc70bSAndy Fleming cmd.cmdarg = 0; 989272cc70bSAndy Fleming 990272cc70bSAndy Fleming timeout = 3; 991272cc70bSAndy Fleming 992272cc70bSAndy Fleming retry_scr: 993f781dd38SAnton staaf data.dest = (char *)scr; 994272cc70bSAndy Fleming data.blocksize = 8; 995272cc70bSAndy Fleming data.blocks = 1; 996272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 997272cc70bSAndy Fleming 998272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 999272cc70bSAndy Fleming 1000272cc70bSAndy Fleming if (err) { 1001272cc70bSAndy Fleming if (timeout--) 1002272cc70bSAndy Fleming goto retry_scr; 1003272cc70bSAndy Fleming 1004272cc70bSAndy Fleming return err; 1005272cc70bSAndy Fleming } 1006272cc70bSAndy Fleming 10074e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]); 10084e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]); 1009272cc70bSAndy Fleming 1010272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) { 1011272cc70bSAndy Fleming case 0: 1012272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1013272cc70bSAndy Fleming break; 1014272cc70bSAndy Fleming case 1: 1015272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10; 1016272cc70bSAndy Fleming break; 1017272cc70bSAndy Fleming case 2: 1018272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 10191741c64dSJaehoon Chung if ((mmc->scr[0] >> 15) & 0x1) 10201741c64dSJaehoon Chung mmc->version = SD_VERSION_3; 1021272cc70bSAndy Fleming break; 1022272cc70bSAndy Fleming default: 1023272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1024272cc70bSAndy Fleming break; 1025272cc70bSAndy Fleming } 1026272cc70bSAndy Fleming 1027b44c7083SAlagu Sankar if (mmc->scr[0] & SD_DATA_4BIT) 1028b44c7083SAlagu Sankar mmc->card_caps |= MMC_MODE_4BIT; 1029b44c7083SAlagu Sankar 1030272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */ 1031272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0) 1032272cc70bSAndy Fleming return 0; 1033272cc70bSAndy Fleming 1034272cc70bSAndy Fleming timeout = 4; 1035272cc70bSAndy Fleming while (timeout--) { 1036272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, 1037f781dd38SAnton staaf (u8 *)switch_status); 1038272cc70bSAndy Fleming 1039272cc70bSAndy Fleming if (err) 1040272cc70bSAndy Fleming return err; 1041272cc70bSAndy Fleming 1042272cc70bSAndy Fleming /* The high-speed function is busy. Try again */ 10434e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) 1044272cc70bSAndy Fleming break; 1045272cc70bSAndy Fleming } 1046272cc70bSAndy Fleming 1047272cc70bSAndy Fleming /* If high-speed isn't supported, we return */ 1048d0c221feSJean-Jacques Hiblot if (__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED) 1049d0c221feSJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(SD_HS); 1050272cc70bSAndy Fleming 10512c3fbf4cSMacpaul Lin return 0; 1052d0c221feSJean-Jacques Hiblot } 1053d0c221feSJean-Jacques Hiblot 1054d0c221feSJean-Jacques Hiblot static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode) 1055d0c221feSJean-Jacques Hiblot { 1056d0c221feSJean-Jacques Hiblot int err; 1057d0c221feSJean-Jacques Hiblot 1058d0c221feSJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16); 10592c3fbf4cSMacpaul Lin 1060f781dd38SAnton staaf err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status); 1061272cc70bSAndy Fleming if (err) 1062272cc70bSAndy Fleming return err; 1063272cc70bSAndy Fleming 1064d0c221feSJean-Jacques Hiblot if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) != 0x01000000) 1065d0c221feSJean-Jacques Hiblot return -ENOTSUPP; 1066d0c221feSJean-Jacques Hiblot 1067d0c221feSJean-Jacques Hiblot return 0; 1068d0c221feSJean-Jacques Hiblot } 1069d0c221feSJean-Jacques Hiblot 1070d0c221feSJean-Jacques Hiblot int sd_select_bus_width(struct mmc *mmc, int w) 1071d0c221feSJean-Jacques Hiblot { 1072d0c221feSJean-Jacques Hiblot int err; 1073d0c221feSJean-Jacques Hiblot struct mmc_cmd cmd; 1074d0c221feSJean-Jacques Hiblot 1075d0c221feSJean-Jacques Hiblot if ((w != 4) && (w != 1)) 1076d0c221feSJean-Jacques Hiblot return -EINVAL; 1077d0c221feSJean-Jacques Hiblot 1078d0c221feSJean-Jacques Hiblot cmd.cmdidx = MMC_CMD_APP_CMD; 1079d0c221feSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 1080d0c221feSJean-Jacques Hiblot cmd.cmdarg = mmc->rca << 16; 1081d0c221feSJean-Jacques Hiblot 1082d0c221feSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 1083d0c221feSJean-Jacques Hiblot if (err) 1084d0c221feSJean-Jacques Hiblot return err; 1085d0c221feSJean-Jacques Hiblot 1086d0c221feSJean-Jacques Hiblot cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; 1087d0c221feSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 1088d0c221feSJean-Jacques Hiblot if (w == 4) 1089d0c221feSJean-Jacques Hiblot cmd.cmdarg = 2; 1090d0c221feSJean-Jacques Hiblot else if (w == 1) 1091d0c221feSJean-Jacques Hiblot cmd.cmdarg = 0; 1092d0c221feSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 1093d0c221feSJean-Jacques Hiblot if (err) 1094d0c221feSJean-Jacques Hiblot return err; 1095272cc70bSAndy Fleming 1096272cc70bSAndy Fleming return 0; 1097272cc70bSAndy Fleming } 1098272cc70bSAndy Fleming 10993697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc) 11003697e599SPeng Fan { 11013697e599SPeng Fan int err, i; 11023697e599SPeng Fan struct mmc_cmd cmd; 11033697e599SPeng Fan ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16); 11043697e599SPeng Fan struct mmc_data data; 11053697e599SPeng Fan int timeout = 3; 11063697e599SPeng Fan unsigned int au, eo, et, es; 11073697e599SPeng Fan 11083697e599SPeng Fan cmd.cmdidx = MMC_CMD_APP_CMD; 11093697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 11103697e599SPeng Fan cmd.cmdarg = mmc->rca << 16; 11113697e599SPeng Fan 11123697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, NULL); 11133697e599SPeng Fan if (err) 11143697e599SPeng Fan return err; 11153697e599SPeng Fan 11163697e599SPeng Fan cmd.cmdidx = SD_CMD_APP_SD_STATUS; 11173697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 11183697e599SPeng Fan cmd.cmdarg = 0; 11193697e599SPeng Fan 11203697e599SPeng Fan retry_ssr: 11213697e599SPeng Fan data.dest = (char *)ssr; 11223697e599SPeng Fan data.blocksize = 64; 11233697e599SPeng Fan data.blocks = 1; 11243697e599SPeng Fan data.flags = MMC_DATA_READ; 11253697e599SPeng Fan 11263697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, &data); 11273697e599SPeng Fan if (err) { 11283697e599SPeng Fan if (timeout--) 11293697e599SPeng Fan goto retry_ssr; 11303697e599SPeng Fan 11313697e599SPeng Fan return err; 11323697e599SPeng Fan } 11333697e599SPeng Fan 11343697e599SPeng Fan for (i = 0; i < 16; i++) 11353697e599SPeng Fan ssr[i] = be32_to_cpu(ssr[i]); 11363697e599SPeng Fan 11373697e599SPeng Fan au = (ssr[2] >> 12) & 0xF; 11383697e599SPeng Fan if ((au <= 9) || (mmc->version == SD_VERSION_3)) { 11393697e599SPeng Fan mmc->ssr.au = sd_au_size[au]; 11403697e599SPeng Fan es = (ssr[3] >> 24) & 0xFF; 11413697e599SPeng Fan es |= (ssr[2] & 0xFF) << 8; 11423697e599SPeng Fan et = (ssr[3] >> 18) & 0x3F; 11433697e599SPeng Fan if (es && et) { 11443697e599SPeng Fan eo = (ssr[3] >> 16) & 0x3; 11453697e599SPeng Fan mmc->ssr.erase_timeout = (et * 1000) / es; 11463697e599SPeng Fan mmc->ssr.erase_offset = eo * 1000; 11473697e599SPeng Fan } 11483697e599SPeng Fan } else { 11493697e599SPeng Fan debug("Invalid Allocation Unit Size.\n"); 11503697e599SPeng Fan } 11513697e599SPeng Fan 11523697e599SPeng Fan return 0; 11533697e599SPeng Fan } 11543697e599SPeng Fan 1155272cc70bSAndy Fleming /* frequency bases */ 1156272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */ 11575f837c2cSMike Frysinger static const int fbase[] = { 1158272cc70bSAndy Fleming 10000, 1159272cc70bSAndy Fleming 100000, 1160272cc70bSAndy Fleming 1000000, 1161272cc70bSAndy Fleming 10000000, 1162272cc70bSAndy Fleming }; 1163272cc70bSAndy Fleming 1164272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice 1165272cc70bSAndy Fleming * to platforms without floating point. 1166272cc70bSAndy Fleming */ 116761fe076fSSimon Glass static const u8 multipliers[] = { 1168272cc70bSAndy Fleming 0, /* reserved */ 1169272cc70bSAndy Fleming 10, 1170272cc70bSAndy Fleming 12, 1171272cc70bSAndy Fleming 13, 1172272cc70bSAndy Fleming 15, 1173272cc70bSAndy Fleming 20, 1174272cc70bSAndy Fleming 25, 1175272cc70bSAndy Fleming 30, 1176272cc70bSAndy Fleming 35, 1177272cc70bSAndy Fleming 40, 1178272cc70bSAndy Fleming 45, 1179272cc70bSAndy Fleming 50, 1180272cc70bSAndy Fleming 55, 1181272cc70bSAndy Fleming 60, 1182272cc70bSAndy Fleming 70, 1183272cc70bSAndy Fleming 80, 1184272cc70bSAndy Fleming }; 1185272cc70bSAndy Fleming 1186d0c221feSJean-Jacques Hiblot static inline int bus_width(uint cap) 1187d0c221feSJean-Jacques Hiblot { 1188d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_8BIT) 1189d0c221feSJean-Jacques Hiblot return 8; 1190d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_4BIT) 1191d0c221feSJean-Jacques Hiblot return 4; 1192d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_1BIT) 1193d0c221feSJean-Jacques Hiblot return 1; 1194d0c221feSJean-Jacques Hiblot printf("invalid bus witdh capability 0x%x\n", cap); 1195d0c221feSJean-Jacques Hiblot return 0; 1196d0c221feSJean-Jacques Hiblot } 1197d0c221feSJean-Jacques Hiblot 1198e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 1199fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc) 1200272cc70bSAndy Fleming { 120193bfd616SPantelis Antoniou if (mmc->cfg->ops->set_ios) 120293bfd616SPantelis Antoniou mmc->cfg->ops->set_ios(mmc); 1203272cc70bSAndy Fleming } 12048ca51e51SSimon Glass #endif 1205272cc70bSAndy Fleming 1206272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock) 1207272cc70bSAndy Fleming { 120893bfd616SPantelis Antoniou if (clock > mmc->cfg->f_max) 120993bfd616SPantelis Antoniou clock = mmc->cfg->f_max; 1210272cc70bSAndy Fleming 121193bfd616SPantelis Antoniou if (clock < mmc->cfg->f_min) 121293bfd616SPantelis Antoniou clock = mmc->cfg->f_min; 1213272cc70bSAndy Fleming 1214272cc70bSAndy Fleming mmc->clock = clock; 1215272cc70bSAndy Fleming 1216272cc70bSAndy Fleming mmc_set_ios(mmc); 1217272cc70bSAndy Fleming } 1218272cc70bSAndy Fleming 1219fdbb873eSKim Phillips static void mmc_set_bus_width(struct mmc *mmc, uint width) 1220272cc70bSAndy Fleming { 1221272cc70bSAndy Fleming mmc->bus_width = width; 1222272cc70bSAndy Fleming 1223272cc70bSAndy Fleming mmc_set_ios(mmc); 1224272cc70bSAndy Fleming } 1225272cc70bSAndy Fleming 12264c9d2aaaSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG) 12274c9d2aaaSJean-Jacques Hiblot /* 12284c9d2aaaSJean-Jacques Hiblot * helper function to display the capabilities in a human 12294c9d2aaaSJean-Jacques Hiblot * friendly manner. The capabilities include bus width and 12304c9d2aaaSJean-Jacques Hiblot * supported modes. 12314c9d2aaaSJean-Jacques Hiblot */ 12324c9d2aaaSJean-Jacques Hiblot void mmc_dump_capabilities(const char *text, uint caps) 12334c9d2aaaSJean-Jacques Hiblot { 12344c9d2aaaSJean-Jacques Hiblot enum bus_mode mode; 12354c9d2aaaSJean-Jacques Hiblot 12364c9d2aaaSJean-Jacques Hiblot printf("%s: widths [", text); 12374c9d2aaaSJean-Jacques Hiblot if (caps & MMC_MODE_8BIT) 12384c9d2aaaSJean-Jacques Hiblot printf("8, "); 12394c9d2aaaSJean-Jacques Hiblot if (caps & MMC_MODE_4BIT) 12404c9d2aaaSJean-Jacques Hiblot printf("4, "); 1241d0c221feSJean-Jacques Hiblot if (caps & MMC_MODE_1BIT) 1242d0c221feSJean-Jacques Hiblot printf("1, "); 1243d0c221feSJean-Jacques Hiblot printf("\b\b] modes ["); 12444c9d2aaaSJean-Jacques Hiblot for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++) 12454c9d2aaaSJean-Jacques Hiblot if (MMC_CAP(mode) & caps) 12464c9d2aaaSJean-Jacques Hiblot printf("%s, ", mmc_mode_name(mode)); 12474c9d2aaaSJean-Jacques Hiblot printf("\b\b]\n"); 12484c9d2aaaSJean-Jacques Hiblot } 12494c9d2aaaSJean-Jacques Hiblot #endif 12504c9d2aaaSJean-Jacques Hiblot 1251d0c221feSJean-Jacques Hiblot struct mode_width_tuning { 1252d0c221feSJean-Jacques Hiblot enum bus_mode mode; 1253d0c221feSJean-Jacques Hiblot uint widths; 1254d0c221feSJean-Jacques Hiblot }; 1255d0c221feSJean-Jacques Hiblot 1256d0c221feSJean-Jacques Hiblot static const struct mode_width_tuning sd_modes_by_pref[] = { 1257d0c221feSJean-Jacques Hiblot { 1258d0c221feSJean-Jacques Hiblot .mode = SD_HS, 1259d0c221feSJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1260d0c221feSJean-Jacques Hiblot }, 1261d0c221feSJean-Jacques Hiblot { 1262d0c221feSJean-Jacques Hiblot .mode = SD_LEGACY, 1263d0c221feSJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1264d0c221feSJean-Jacques Hiblot } 1265d0c221feSJean-Jacques Hiblot }; 1266d0c221feSJean-Jacques Hiblot 1267d0c221feSJean-Jacques Hiblot #define for_each_sd_mode_by_pref(caps, mwt) \ 1268d0c221feSJean-Jacques Hiblot for (mwt = sd_modes_by_pref;\ 1269d0c221feSJean-Jacques Hiblot mwt < sd_modes_by_pref + ARRAY_SIZE(sd_modes_by_pref);\ 1270d0c221feSJean-Jacques Hiblot mwt++) \ 1271d0c221feSJean-Jacques Hiblot if (caps & MMC_CAP(mwt->mode)) 1272d0c221feSJean-Jacques Hiblot 1273d0c221feSJean-Jacques Hiblot static int sd_select_mode_and_width(struct mmc *mmc) 12748ac8a263SJean-Jacques Hiblot { 12758ac8a263SJean-Jacques Hiblot int err; 1276d0c221feSJean-Jacques Hiblot uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT}; 1277d0c221feSJean-Jacques Hiblot const struct mode_width_tuning *mwt; 12788ac8a263SJean-Jacques Hiblot 1279d0c221feSJean-Jacques Hiblot err = sd_get_capabilities(mmc); 12808ac8a263SJean-Jacques Hiblot if (err) 12818ac8a263SJean-Jacques Hiblot return err; 12828ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */ 1283d0c221feSJean-Jacques Hiblot mmc->card_caps &= (mmc->cfg->host_caps | MMC_MODE_1BIT); 12848ac8a263SJean-Jacques Hiblot 1285d0c221feSJean-Jacques Hiblot for_each_sd_mode_by_pref(mmc->card_caps, mwt) { 1286d0c221feSJean-Jacques Hiblot uint *w; 12878ac8a263SJean-Jacques Hiblot 1288d0c221feSJean-Jacques Hiblot for (w = widths; w < widths + ARRAY_SIZE(widths); w++) { 1289d0c221feSJean-Jacques Hiblot if (*w & mmc->card_caps & mwt->widths) { 1290d0c221feSJean-Jacques Hiblot debug("trying mode %s width %d (at %d MHz)\n", 1291d0c221feSJean-Jacques Hiblot mmc_mode_name(mwt->mode), 1292d0c221feSJean-Jacques Hiblot bus_width(*w), 1293d0c221feSJean-Jacques Hiblot mmc_mode2freq(mmc, mwt->mode) / 1000000); 1294d0c221feSJean-Jacques Hiblot 1295d0c221feSJean-Jacques Hiblot /* configure the bus width (card + host) */ 1296d0c221feSJean-Jacques Hiblot err = sd_select_bus_width(mmc, bus_width(*w)); 12978ac8a263SJean-Jacques Hiblot if (err) 1298d0c221feSJean-Jacques Hiblot goto error; 1299d0c221feSJean-Jacques Hiblot mmc_set_bus_width(mmc, bus_width(*w)); 13008ac8a263SJean-Jacques Hiblot 1301d0c221feSJean-Jacques Hiblot /* configure the bus mode (card) */ 1302d0c221feSJean-Jacques Hiblot err = sd_set_card_speed(mmc, mwt->mode); 13038ac8a263SJean-Jacques Hiblot if (err) 1304d0c221feSJean-Jacques Hiblot goto error; 13058ac8a263SJean-Jacques Hiblot 1306d0c221feSJean-Jacques Hiblot /* configure the bus mode (host) */ 1307d0c221feSJean-Jacques Hiblot mmc_select_mode(mmc, mwt->mode); 1308d0c221feSJean-Jacques Hiblot mmc_set_clock(mmc, mmc->tran_speed); 13098ac8a263SJean-Jacques Hiblot 13108ac8a263SJean-Jacques Hiblot err = sd_read_ssr(mmc); 1311d0c221feSJean-Jacques Hiblot if (!err) 13128ac8a263SJean-Jacques Hiblot return 0; 1313d0c221feSJean-Jacques Hiblot 1314d0c221feSJean-Jacques Hiblot printf("bad ssr\n"); 1315d0c221feSJean-Jacques Hiblot 1316d0c221feSJean-Jacques Hiblot error: 1317d0c221feSJean-Jacques Hiblot /* revert to a safer bus speed */ 1318d0c221feSJean-Jacques Hiblot mmc_select_mode(mmc, SD_LEGACY); 1319d0c221feSJean-Jacques Hiblot mmc_set_clock(mmc, mmc->tran_speed); 1320d0c221feSJean-Jacques Hiblot } 1321d0c221feSJean-Jacques Hiblot } 1322d0c221feSJean-Jacques Hiblot } 1323d0c221feSJean-Jacques Hiblot 1324d0c221feSJean-Jacques Hiblot printf("unable to select a mode\n"); 1325d0c221feSJean-Jacques Hiblot return -ENOTSUPP; 13268ac8a263SJean-Jacques Hiblot } 13278ac8a263SJean-Jacques Hiblot 13287382e691SJean-Jacques Hiblot /* 13297382e691SJean-Jacques Hiblot * read the compare the part of ext csd that is constant. 13307382e691SJean-Jacques Hiblot * This can be used to check that the transfer is working 13317382e691SJean-Jacques Hiblot * as expected. 13327382e691SJean-Jacques Hiblot */ 13337382e691SJean-Jacques Hiblot static int mmc_read_and_compare_ext_csd(struct mmc *mmc) 13347382e691SJean-Jacques Hiblot { 13357382e691SJean-Jacques Hiblot int err; 13367382e691SJean-Jacques Hiblot const u8 *ext_csd = mmc->ext_csd; 13377382e691SJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 13387382e691SJean-Jacques Hiblot 13397382e691SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, test_csd); 13407382e691SJean-Jacques Hiblot if (err) 13417382e691SJean-Jacques Hiblot return err; 13427382e691SJean-Jacques Hiblot 13437382e691SJean-Jacques Hiblot /* Only compare read only fields */ 13447382e691SJean-Jacques Hiblot if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] 13457382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_PARTITIONING_SUPPORT] && 13467382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_WP_GRP_SIZE] 13477382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_WP_GRP_SIZE] && 13487382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_REV] 13497382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_REV] && 13507382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 13517382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] && 13527382e691SJean-Jacques Hiblot memcmp(&ext_csd[EXT_CSD_SEC_CNT], 13537382e691SJean-Jacques Hiblot &test_csd[EXT_CSD_SEC_CNT], 4) == 0) 13547382e691SJean-Jacques Hiblot return 0; 13557382e691SJean-Jacques Hiblot 13567382e691SJean-Jacques Hiblot return -EBADMSG; 13577382e691SJean-Jacques Hiblot } 13587382e691SJean-Jacques Hiblot 1359*3862b854SJean-Jacques Hiblot static const struct mode_width_tuning mmc_modes_by_pref[] = { 13608ac8a263SJean-Jacques Hiblot { 1361*3862b854SJean-Jacques Hiblot .mode = MMC_HS_200, 1362*3862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT, 1363*3862b854SJean-Jacques Hiblot }, 1364*3862b854SJean-Jacques Hiblot { 1365*3862b854SJean-Jacques Hiblot .mode = MMC_DDR_52, 1366*3862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT, 1367*3862b854SJean-Jacques Hiblot }, 1368*3862b854SJean-Jacques Hiblot { 1369*3862b854SJean-Jacques Hiblot .mode = MMC_HS_52, 1370*3862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 1371*3862b854SJean-Jacques Hiblot }, 1372*3862b854SJean-Jacques Hiblot { 1373*3862b854SJean-Jacques Hiblot .mode = MMC_HS, 1374*3862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 1375*3862b854SJean-Jacques Hiblot }, 1376*3862b854SJean-Jacques Hiblot { 1377*3862b854SJean-Jacques Hiblot .mode = MMC_LEGACY, 1378*3862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 1379*3862b854SJean-Jacques Hiblot } 13808ac8a263SJean-Jacques Hiblot }; 13818ac8a263SJean-Jacques Hiblot 1382*3862b854SJean-Jacques Hiblot #define for_each_mmc_mode_by_pref(caps, mwt) \ 1383*3862b854SJean-Jacques Hiblot for (mwt = mmc_modes_by_pref;\ 1384*3862b854SJean-Jacques Hiblot mwt < mmc_modes_by_pref + ARRAY_SIZE(mmc_modes_by_pref);\ 1385*3862b854SJean-Jacques Hiblot mwt++) \ 1386*3862b854SJean-Jacques Hiblot if (caps & MMC_CAP(mwt->mode)) 1387*3862b854SJean-Jacques Hiblot 1388*3862b854SJean-Jacques Hiblot static const struct ext_csd_bus_width { 1389*3862b854SJean-Jacques Hiblot uint cap; 1390*3862b854SJean-Jacques Hiblot bool is_ddr; 1391*3862b854SJean-Jacques Hiblot uint ext_csd_bits; 1392*3862b854SJean-Jacques Hiblot } ext_csd_bus_width[] = { 1393*3862b854SJean-Jacques Hiblot {MMC_MODE_8BIT, true, EXT_CSD_DDR_BUS_WIDTH_8}, 1394*3862b854SJean-Jacques Hiblot {MMC_MODE_4BIT, true, EXT_CSD_DDR_BUS_WIDTH_4}, 1395*3862b854SJean-Jacques Hiblot {MMC_MODE_8BIT, false, EXT_CSD_BUS_WIDTH_8}, 1396*3862b854SJean-Jacques Hiblot {MMC_MODE_4BIT, false, EXT_CSD_BUS_WIDTH_4}, 1397*3862b854SJean-Jacques Hiblot {MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1}, 1398*3862b854SJean-Jacques Hiblot }; 1399*3862b854SJean-Jacques Hiblot 1400*3862b854SJean-Jacques Hiblot #define for_each_supported_width(caps, ddr, ecbv) \ 1401*3862b854SJean-Jacques Hiblot for (ecbv = ext_csd_bus_width;\ 1402*3862b854SJean-Jacques Hiblot ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\ 1403*3862b854SJean-Jacques Hiblot ecbv++) \ 1404*3862b854SJean-Jacques Hiblot if ((ddr == ecbv->is_ddr) && (caps & ecbv->cap)) 1405*3862b854SJean-Jacques Hiblot 1406*3862b854SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc) 1407*3862b854SJean-Jacques Hiblot { 1408*3862b854SJean-Jacques Hiblot int err; 1409*3862b854SJean-Jacques Hiblot const struct mode_width_tuning *mwt; 1410*3862b854SJean-Jacques Hiblot const struct ext_csd_bus_width *ecbw; 1411*3862b854SJean-Jacques Hiblot 1412*3862b854SJean-Jacques Hiblot err = mmc_get_capabilities(mmc); 14138ac8a263SJean-Jacques Hiblot if (err) 14148ac8a263SJean-Jacques Hiblot return err; 14158ac8a263SJean-Jacques Hiblot 14168ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */ 1417d0c221feSJean-Jacques Hiblot mmc->card_caps &= (mmc->cfg->host_caps | MMC_MODE_1BIT); 14188ac8a263SJean-Jacques Hiblot 14198ac8a263SJean-Jacques Hiblot /* Only version 4 of MMC supports wider bus widths */ 14208ac8a263SJean-Jacques Hiblot if (mmc->version < MMC_VERSION_4) 14218ac8a263SJean-Jacques Hiblot return 0; 14228ac8a263SJean-Jacques Hiblot 1423dfda9d88SJean-Jacques Hiblot if (!mmc->ext_csd) { 1424dfda9d88SJean-Jacques Hiblot debug("No ext_csd found!\n"); /* this should enver happen */ 1425dfda9d88SJean-Jacques Hiblot return -ENOTSUPP; 1426dfda9d88SJean-Jacques Hiblot } 1427dfda9d88SJean-Jacques Hiblot 1428*3862b854SJean-Jacques Hiblot for_each_mmc_mode_by_pref(mmc->card_caps, mwt) { 1429*3862b854SJean-Jacques Hiblot for_each_supported_width(mmc->card_caps & mwt->widths, 1430*3862b854SJean-Jacques Hiblot mmc_is_mode_ddr(mwt->mode), ecbw) { 1431*3862b854SJean-Jacques Hiblot debug("trying mode %s width %d (at %d MHz)\n", 1432*3862b854SJean-Jacques Hiblot mmc_mode_name(mwt->mode), 1433*3862b854SJean-Jacques Hiblot bus_width(ecbw->cap), 1434*3862b854SJean-Jacques Hiblot mmc_mode2freq(mmc, mwt->mode) / 1000000); 1435*3862b854SJean-Jacques Hiblot /* configure the bus width (card + host) */ 1436*3862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1437*3862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, 1438*3862b854SJean-Jacques Hiblot ecbw->ext_csd_bits & ~EXT_CSD_DDR_FLAG); 1439*3862b854SJean-Jacques Hiblot if (err) 1440*3862b854SJean-Jacques Hiblot goto error; 1441*3862b854SJean-Jacques Hiblot mmc_set_bus_width(mmc, bus_width(ecbw->cap)); 1442*3862b854SJean-Jacques Hiblot 1443*3862b854SJean-Jacques Hiblot /* configure the bus speed (card) */ 1444*3862b854SJean-Jacques Hiblot err = mmc_set_card_speed(mmc, mwt->mode); 1445*3862b854SJean-Jacques Hiblot if (err) 1446*3862b854SJean-Jacques Hiblot goto error; 1447*3862b854SJean-Jacques Hiblot 14488ac8a263SJean-Jacques Hiblot /* 1449*3862b854SJean-Jacques Hiblot * configure the bus width AND the ddr mode (card) 1450*3862b854SJean-Jacques Hiblot * The host side will be taken care of in the next step 14518ac8a263SJean-Jacques Hiblot */ 1452*3862b854SJean-Jacques Hiblot if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) { 1453*3862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1454*3862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, 1455*3862b854SJean-Jacques Hiblot ecbw->ext_csd_bits); 1456*3862b854SJean-Jacques Hiblot if (err) 1457*3862b854SJean-Jacques Hiblot goto error; 14588ac8a263SJean-Jacques Hiblot } 14598ac8a263SJean-Jacques Hiblot 1460*3862b854SJean-Jacques Hiblot /* configure the bus mode (host) */ 1461*3862b854SJean-Jacques Hiblot mmc_select_mode(mmc, mwt->mode); 1462*3862b854SJean-Jacques Hiblot mmc_set_clock(mmc, mmc->tran_speed); 14638ac8a263SJean-Jacques Hiblot 1464*3862b854SJean-Jacques Hiblot /* do a transfer to check the configuration */ 14657382e691SJean-Jacques Hiblot err = mmc_read_and_compare_ext_csd(mmc); 14667382e691SJean-Jacques Hiblot if (!err) 1467*3862b854SJean-Jacques Hiblot return 0; 1468*3862b854SJean-Jacques Hiblot error: 1469*3862b854SJean-Jacques Hiblot /* if an error occured, revert to a safer bus mode */ 1470*3862b854SJean-Jacques Hiblot mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1471*3862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1); 1472*3862b854SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_LEGACY); 1473*3862b854SJean-Jacques Hiblot mmc_set_bus_width(mmc, 1); 1474*3862b854SJean-Jacques Hiblot } 14758ac8a263SJean-Jacques Hiblot } 14768ac8a263SJean-Jacques Hiblot 1477*3862b854SJean-Jacques Hiblot printf("unable to select a mode\n"); 14788ac8a263SJean-Jacques Hiblot 1479*3862b854SJean-Jacques Hiblot return -ENOTSUPP; 14808ac8a263SJean-Jacques Hiblot } 14818ac8a263SJean-Jacques Hiblot 1482dfda9d88SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc) 1483c744b6f6SJean-Jacques Hiblot { 1484c744b6f6SJean-Jacques Hiblot int err, i; 1485c744b6f6SJean-Jacques Hiblot u64 capacity; 1486c744b6f6SJean-Jacques Hiblot bool has_parts = false; 1487c744b6f6SJean-Jacques Hiblot bool part_completed; 1488dfda9d88SJean-Jacques Hiblot u8 *ext_csd; 1489c744b6f6SJean-Jacques Hiblot 1490c744b6f6SJean-Jacques Hiblot if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4)) 1491c744b6f6SJean-Jacques Hiblot return 0; 1492c744b6f6SJean-Jacques Hiblot 1493dfda9d88SJean-Jacques Hiblot ext_csd = malloc_cache_aligned(MMC_MAX_BLOCK_LEN); 1494dfda9d88SJean-Jacques Hiblot if (!ext_csd) 1495dfda9d88SJean-Jacques Hiblot return -ENOMEM; 1496dfda9d88SJean-Jacques Hiblot 1497dfda9d88SJean-Jacques Hiblot mmc->ext_csd = ext_csd; 1498dfda9d88SJean-Jacques Hiblot 1499c744b6f6SJean-Jacques Hiblot /* check ext_csd version and capacity */ 1500c744b6f6SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, ext_csd); 1501c744b6f6SJean-Jacques Hiblot if (err) 1502c744b6f6SJean-Jacques Hiblot return err; 1503c744b6f6SJean-Jacques Hiblot if (ext_csd[EXT_CSD_REV] >= 2) { 1504c744b6f6SJean-Jacques Hiblot /* 1505c744b6f6SJean-Jacques Hiblot * According to the JEDEC Standard, the value of 1506c744b6f6SJean-Jacques Hiblot * ext_csd's capacity is valid if the value is more 1507c744b6f6SJean-Jacques Hiblot * than 2GB 1508c744b6f6SJean-Jacques Hiblot */ 1509c744b6f6SJean-Jacques Hiblot capacity = ext_csd[EXT_CSD_SEC_CNT] << 0 1510c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 1511c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 1512c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; 1513c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN; 1514c744b6f6SJean-Jacques Hiblot if ((capacity >> 20) > 2 * 1024) 1515c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity; 1516c744b6f6SJean-Jacques Hiblot } 1517c744b6f6SJean-Jacques Hiblot 1518c744b6f6SJean-Jacques Hiblot switch (ext_csd[EXT_CSD_REV]) { 1519c744b6f6SJean-Jacques Hiblot case 1: 1520c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_1; 1521c744b6f6SJean-Jacques Hiblot break; 1522c744b6f6SJean-Jacques Hiblot case 2: 1523c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_2; 1524c744b6f6SJean-Jacques Hiblot break; 1525c744b6f6SJean-Jacques Hiblot case 3: 1526c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_3; 1527c744b6f6SJean-Jacques Hiblot break; 1528c744b6f6SJean-Jacques Hiblot case 5: 1529c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_41; 1530c744b6f6SJean-Jacques Hiblot break; 1531c744b6f6SJean-Jacques Hiblot case 6: 1532c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_5; 1533c744b6f6SJean-Jacques Hiblot break; 1534c744b6f6SJean-Jacques Hiblot case 7: 1535c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_5_0; 1536c744b6f6SJean-Jacques Hiblot break; 1537c744b6f6SJean-Jacques Hiblot case 8: 1538c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_5_1; 1539c744b6f6SJean-Jacques Hiblot break; 1540c744b6f6SJean-Jacques Hiblot } 1541c744b6f6SJean-Jacques Hiblot 1542c744b6f6SJean-Jacques Hiblot /* The partition data may be non-zero but it is only 1543c744b6f6SJean-Jacques Hiblot * effective if PARTITION_SETTING_COMPLETED is set in 1544c744b6f6SJean-Jacques Hiblot * EXT_CSD, so ignore any data if this bit is not set, 1545c744b6f6SJean-Jacques Hiblot * except for enabling the high-capacity group size 1546c744b6f6SJean-Jacques Hiblot * definition (see below). 1547c744b6f6SJean-Jacques Hiblot */ 1548c744b6f6SJean-Jacques Hiblot part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] & 1549c744b6f6SJean-Jacques Hiblot EXT_CSD_PARTITION_SETTING_COMPLETED); 1550c744b6f6SJean-Jacques Hiblot 1551c744b6f6SJean-Jacques Hiblot /* store the partition info of emmc */ 1552c744b6f6SJean-Jacques Hiblot mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT]; 1553c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || 1554c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_BOOT_MULT]) 1555c744b6f6SJean-Jacques Hiblot mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; 1556c744b6f6SJean-Jacques Hiblot if (part_completed && 1557c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT)) 1558c744b6f6SJean-Jacques Hiblot mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]; 1559c744b6f6SJean-Jacques Hiblot 1560c744b6f6SJean-Jacques Hiblot mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17; 1561c744b6f6SJean-Jacques Hiblot 1562c744b6f6SJean-Jacques Hiblot mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17; 1563c744b6f6SJean-Jacques Hiblot 1564c744b6f6SJean-Jacques Hiblot for (i = 0; i < 4; i++) { 1565c744b6f6SJean-Jacques Hiblot int idx = EXT_CSD_GP_SIZE_MULT + i * 3; 1566c744b6f6SJean-Jacques Hiblot uint mult = (ext_csd[idx + 2] << 16) + 1567c744b6f6SJean-Jacques Hiblot (ext_csd[idx + 1] << 8) + ext_csd[idx]; 1568c744b6f6SJean-Jacques Hiblot if (mult) 1569c744b6f6SJean-Jacques Hiblot has_parts = true; 1570c744b6f6SJean-Jacques Hiblot if (!part_completed) 1571c744b6f6SJean-Jacques Hiblot continue; 1572c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] = mult; 1573c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= 1574c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1575c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1576c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] <<= 19; 1577c744b6f6SJean-Jacques Hiblot } 1578c744b6f6SJean-Jacques Hiblot 1579c744b6f6SJean-Jacques Hiblot if (part_completed) { 1580c744b6f6SJean-Jacques Hiblot mmc->enh_user_size = 1581c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) + 1582c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) + 1583c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_SIZE_MULT]; 1584c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1585c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1586c744b6f6SJean-Jacques Hiblot mmc->enh_user_size <<= 19; 1587c744b6f6SJean-Jacques Hiblot mmc->enh_user_start = 1588c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) + 1589c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) + 1590c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) + 1591c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_START_ADDR]; 1592c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity) 1593c744b6f6SJean-Jacques Hiblot mmc->enh_user_start <<= 9; 1594c744b6f6SJean-Jacques Hiblot } 1595c744b6f6SJean-Jacques Hiblot 1596c744b6f6SJean-Jacques Hiblot /* 1597c744b6f6SJean-Jacques Hiblot * Host needs to enable ERASE_GRP_DEF bit if device is 1598c744b6f6SJean-Jacques Hiblot * partitioned. This bit will be lost every time after a reset 1599c744b6f6SJean-Jacques Hiblot * or power off. This will affect erase size. 1600c744b6f6SJean-Jacques Hiblot */ 1601c744b6f6SJean-Jacques Hiblot if (part_completed) 1602c744b6f6SJean-Jacques Hiblot has_parts = true; 1603c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) && 1604c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) 1605c744b6f6SJean-Jacques Hiblot has_parts = true; 1606c744b6f6SJean-Jacques Hiblot if (has_parts) { 1607c744b6f6SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1608c744b6f6SJean-Jacques Hiblot EXT_CSD_ERASE_GROUP_DEF, 1); 1609c744b6f6SJean-Jacques Hiblot 1610c744b6f6SJean-Jacques Hiblot if (err) 1611c744b6f6SJean-Jacques Hiblot return err; 1612c744b6f6SJean-Jacques Hiblot 1613c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 1614c744b6f6SJean-Jacques Hiblot } 1615c744b6f6SJean-Jacques Hiblot 1616c744b6f6SJean-Jacques Hiblot if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) { 1617c744b6f6SJean-Jacques Hiblot /* Read out group size from ext_csd */ 1618c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = 1619c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 1620c744b6f6SJean-Jacques Hiblot /* 1621c744b6f6SJean-Jacques Hiblot * if high capacity and partition setting completed 1622c744b6f6SJean-Jacques Hiblot * SEC_COUNT is valid even if it is smaller than 2 GiB 1623c744b6f6SJean-Jacques Hiblot * JEDEC Standard JESD84-B45, 6.2.4 1624c744b6f6SJean-Jacques Hiblot */ 1625c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity && part_completed) { 1626c744b6f6SJean-Jacques Hiblot capacity = (ext_csd[EXT_CSD_SEC_CNT]) | 1627c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) | 1628c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) | 1629c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 3] << 24); 1630c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN; 1631c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity; 1632c744b6f6SJean-Jacques Hiblot } 1633c744b6f6SJean-Jacques Hiblot } else { 1634c744b6f6SJean-Jacques Hiblot /* Calculate the group size from the csd value. */ 1635c744b6f6SJean-Jacques Hiblot int erase_gsz, erase_gmul; 1636c744b6f6SJean-Jacques Hiblot 1637c744b6f6SJean-Jacques Hiblot erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; 1638c744b6f6SJean-Jacques Hiblot erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; 1639c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = (erase_gsz + 1) 1640c744b6f6SJean-Jacques Hiblot * (erase_gmul + 1); 1641c744b6f6SJean-Jacques Hiblot } 1642c744b6f6SJean-Jacques Hiblot 1643c744b6f6SJean-Jacques Hiblot mmc->hc_wp_grp_size = 1024 1644c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 1645c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1646c744b6f6SJean-Jacques Hiblot 1647c744b6f6SJean-Jacques Hiblot mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 1648c744b6f6SJean-Jacques Hiblot 1649c744b6f6SJean-Jacques Hiblot return 0; 1650c744b6f6SJean-Jacques Hiblot } 1651c744b6f6SJean-Jacques Hiblot 1652fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc) 1653272cc70bSAndy Fleming { 1654f866a46dSStephen Warren int err, i; 1655272cc70bSAndy Fleming uint mult, freq; 1656c744b6f6SJean-Jacques Hiblot u64 cmult, csize; 1657272cc70bSAndy Fleming struct mmc_cmd cmd; 1658c40fdca6SSimon Glass struct blk_desc *bdesc; 1659272cc70bSAndy Fleming 1660d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON 1661d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ 1662d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; 1663d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R1; 1664d52ebf10SThomas Chou cmd.cmdarg = 1; 1665d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 1666d52ebf10SThomas Chou 1667d52ebf10SThomas Chou if (err) 1668d52ebf10SThomas Chou return err; 1669d52ebf10SThomas Chou } 1670d52ebf10SThomas Chou #endif 1671d52ebf10SThomas Chou 1672272cc70bSAndy Fleming /* Put the Card in Identify Mode */ 1673d52ebf10SThomas Chou cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : 1674d52ebf10SThomas Chou MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ 1675272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1676272cc70bSAndy Fleming cmd.cmdarg = 0; 1677272cc70bSAndy Fleming 1678272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1679272cc70bSAndy Fleming 1680272cc70bSAndy Fleming if (err) 1681272cc70bSAndy Fleming return err; 1682272cc70bSAndy Fleming 1683272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16); 1684272cc70bSAndy Fleming 1685272cc70bSAndy Fleming /* 1686272cc70bSAndy Fleming * For MMC cards, set the Relative Address. 1687272cc70bSAndy Fleming * For SD cards, get the Relatvie Address. 1688272cc70bSAndy Fleming * This also puts the cards into Standby State 1689272cc70bSAndy Fleming */ 1690d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1691272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; 1692272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1693272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6; 1694272cc70bSAndy Fleming 1695272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1696272cc70bSAndy Fleming 1697272cc70bSAndy Fleming if (err) 1698272cc70bSAndy Fleming return err; 1699272cc70bSAndy Fleming 1700272cc70bSAndy Fleming if (IS_SD(mmc)) 1701998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff; 1702d52ebf10SThomas Chou } 1703272cc70bSAndy Fleming 1704272cc70bSAndy Fleming /* Get the Card-Specific Data */ 1705272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD; 1706272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1707272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1708272cc70bSAndy Fleming 1709272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1710272cc70bSAndy Fleming 1711272cc70bSAndy Fleming if (err) 1712272cc70bSAndy Fleming return err; 1713272cc70bSAndy Fleming 1714998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0]; 1715998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1]; 1716998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2]; 1717998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3]; 1718272cc70bSAndy Fleming 1719272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) { 17200b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf; 1721272cc70bSAndy Fleming 1722272cc70bSAndy Fleming switch (version) { 1723272cc70bSAndy Fleming case 0: 1724272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1725272cc70bSAndy Fleming break; 1726272cc70bSAndy Fleming case 1: 1727272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4; 1728272cc70bSAndy Fleming break; 1729272cc70bSAndy Fleming case 2: 1730272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2; 1731272cc70bSAndy Fleming break; 1732272cc70bSAndy Fleming case 3: 1733272cc70bSAndy Fleming mmc->version = MMC_VERSION_3; 1734272cc70bSAndy Fleming break; 1735272cc70bSAndy Fleming case 4: 1736272cc70bSAndy Fleming mmc->version = MMC_VERSION_4; 1737272cc70bSAndy Fleming break; 1738272cc70bSAndy Fleming default: 1739272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1740272cc70bSAndy Fleming break; 1741272cc70bSAndy Fleming } 1742272cc70bSAndy Fleming } 1743272cc70bSAndy Fleming 1744272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */ 17450b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)]; 17460b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; 1747272cc70bSAndy Fleming 174835f9e196SJean-Jacques Hiblot mmc->legacy_speed = freq * mult; 174935f9e196SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_LEGACY); 1750272cc70bSAndy Fleming 1751ab71188cSMarkus Niebel mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); 1752998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); 1753272cc70bSAndy Fleming 1754272cc70bSAndy Fleming if (IS_SD(mmc)) 1755272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len; 1756272cc70bSAndy Fleming else 1757998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); 1758272cc70bSAndy Fleming 1759272cc70bSAndy Fleming if (mmc->high_capacity) { 1760272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16 1761272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16; 1762272cc70bSAndy Fleming cmult = 8; 1763272cc70bSAndy Fleming } else { 1764272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2 1765272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30; 1766272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15; 1767272cc70bSAndy Fleming } 1768272cc70bSAndy Fleming 1769f866a46dSStephen Warren mmc->capacity_user = (csize + 1) << (cmult + 2); 1770f866a46dSStephen Warren mmc->capacity_user *= mmc->read_bl_len; 1771f866a46dSStephen Warren mmc->capacity_boot = 0; 1772f866a46dSStephen Warren mmc->capacity_rpmb = 0; 1773f866a46dSStephen Warren for (i = 0; i < 4; i++) 1774f866a46dSStephen Warren mmc->capacity_gp[i] = 0; 1775272cc70bSAndy Fleming 17768bfa195eSSimon Glass if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN) 17778bfa195eSSimon Glass mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 1778272cc70bSAndy Fleming 17798bfa195eSSimon Glass if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) 17808bfa195eSSimon Glass mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 1781272cc70bSAndy Fleming 1782ab71188cSMarkus Niebel if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) { 1783ab71188cSMarkus Niebel cmd.cmdidx = MMC_CMD_SET_DSR; 1784ab71188cSMarkus Niebel cmd.cmdarg = (mmc->dsr & 0xffff) << 16; 1785ab71188cSMarkus Niebel cmd.resp_type = MMC_RSP_NONE; 1786ab71188cSMarkus Niebel if (mmc_send_cmd(mmc, &cmd, NULL)) 1787ab71188cSMarkus Niebel printf("MMC: SET_DSR failed\n"); 1788ab71188cSMarkus Niebel } 1789ab71188cSMarkus Niebel 1790272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */ 1791d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1792272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD; 1793fe8f7066SAjay Bhargav cmd.resp_type = MMC_RSP_R1; 1794272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1795272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1796272cc70bSAndy Fleming 1797272cc70bSAndy Fleming if (err) 1798272cc70bSAndy Fleming return err; 1799d52ebf10SThomas Chou } 1800272cc70bSAndy Fleming 1801e6f99a56SLei Wen /* 1802e6f99a56SLei Wen * For SD, its erase group is always one sector 1803e6f99a56SLei Wen */ 1804e6f99a56SLei Wen mmc->erase_grp_size = 1; 1805bc897b1dSLei Wen mmc->part_config = MMCPART_NOAVAILABLE; 1806c744b6f6SJean-Jacques Hiblot 1807dfda9d88SJean-Jacques Hiblot err = mmc_startup_v4(mmc); 18089cf199ebSDiego Santa Cruz if (err) 18099cf199ebSDiego Santa Cruz return err; 1810f866a46dSStephen Warren 1811c40fdca6SSimon Glass err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart); 1812f866a46dSStephen Warren if (err) 1813f866a46dSStephen Warren return err; 1814d23e2c09SSukumar Ghorai 1815272cc70bSAndy Fleming if (IS_SD(mmc)) 1816d0c221feSJean-Jacques Hiblot err = sd_select_mode_and_width(mmc); 1817272cc70bSAndy Fleming else 1818*3862b854SJean-Jacques Hiblot err = mmc_select_mode_and_width(mmc); 1819272cc70bSAndy Fleming 1820272cc70bSAndy Fleming if (err) 1821272cc70bSAndy Fleming return err; 1822272cc70bSAndy Fleming 1823272cc70bSAndy Fleming 18245af8f45cSAndrew Gabbasov /* Fix the block length for DDR mode */ 18255af8f45cSAndrew Gabbasov if (mmc->ddr_mode) { 18265af8f45cSAndrew Gabbasov mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 18275af8f45cSAndrew Gabbasov mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 18285af8f45cSAndrew Gabbasov } 18295af8f45cSAndrew Gabbasov 1830272cc70bSAndy Fleming /* fill in device description */ 1831c40fdca6SSimon Glass bdesc = mmc_get_blk_desc(mmc); 1832c40fdca6SSimon Glass bdesc->lun = 0; 1833c40fdca6SSimon Glass bdesc->hwpart = 0; 1834c40fdca6SSimon Glass bdesc->type = 0; 1835c40fdca6SSimon Glass bdesc->blksz = mmc->read_bl_len; 1836c40fdca6SSimon Glass bdesc->log2blksz = LOG2(bdesc->blksz); 1837c40fdca6SSimon Glass bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len); 1838fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \ 1839fc011f64SSjoerd Simons (defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \ 1840fc011f64SSjoerd Simons !defined(CONFIG_USE_TINY_PRINTF)) 1841c40fdca6SSimon Glass sprintf(bdesc->vendor, "Man %06x Snr %04x%04x", 1842babce5f6STaylor Hutt mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), 1843babce5f6STaylor Hutt (mmc->cid[3] >> 16) & 0xffff); 1844c40fdca6SSimon Glass sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff, 18450b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 1846babce5f6STaylor Hutt (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff, 1847babce5f6STaylor Hutt (mmc->cid[2] >> 24) & 0xff); 1848c40fdca6SSimon Glass sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf, 1849babce5f6STaylor Hutt (mmc->cid[2] >> 16) & 0xf); 185056196826SPaul Burton #else 1851c40fdca6SSimon Glass bdesc->vendor[0] = 0; 1852c40fdca6SSimon Glass bdesc->product[0] = 0; 1853c40fdca6SSimon Glass bdesc->revision[0] = 0; 185456196826SPaul Burton #endif 1855122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT) 1856c40fdca6SSimon Glass part_init(bdesc); 1857122efd43SMikhail Kshevetskiy #endif 1858272cc70bSAndy Fleming 1859272cc70bSAndy Fleming return 0; 1860272cc70bSAndy Fleming } 1861272cc70bSAndy Fleming 1862fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc) 1863272cc70bSAndy Fleming { 1864272cc70bSAndy Fleming struct mmc_cmd cmd; 1865272cc70bSAndy Fleming int err; 1866272cc70bSAndy Fleming 1867272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND; 1868272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ 186993bfd616SPantelis Antoniou cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa; 1870272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7; 1871272cc70bSAndy Fleming 1872272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1873272cc70bSAndy Fleming 1874272cc70bSAndy Fleming if (err) 1875272cc70bSAndy Fleming return err; 1876272cc70bSAndy Fleming 1877998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa) 1878915ffa52SJaehoon Chung return -EOPNOTSUPP; 1879272cc70bSAndy Fleming else 1880272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 1881272cc70bSAndy Fleming 1882272cc70bSAndy Fleming return 0; 1883272cc70bSAndy Fleming } 1884272cc70bSAndy Fleming 1885c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 188695de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */ 188795de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void) 188895de9ab2SPaul Kocialkowski { 188995de9ab2SPaul Kocialkowski } 189005cbeb7cSSimon Glass #endif 189195de9ab2SPaul Kocialkowski 18922051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc) 18932051aefeSPeng Fan { 1894c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 189506ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR) 18962051aefeSPeng Fan int ret; 18972051aefeSPeng Fan 18982051aefeSPeng Fan ret = device_get_supply_regulator(mmc->dev, "vmmc-supply", 189906ec045fSJean-Jacques Hiblot &mmc->vmmc_supply); 190006ec045fSJean-Jacques Hiblot if (ret) 1901288db7c7SJaehoon Chung debug("%s: No vmmc supply\n", mmc->dev->name); 19022051aefeSPeng Fan 190306ec045fSJean-Jacques Hiblot ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply", 190406ec045fSJean-Jacques Hiblot &mmc->vqmmc_supply); 190506ec045fSJean-Jacques Hiblot if (ret) 190606ec045fSJean-Jacques Hiblot debug("%s: No vqmmc supply\n", mmc->dev->name); 190706ec045fSJean-Jacques Hiblot 190806ec045fSJean-Jacques Hiblot if (mmc->vmmc_supply) { 190906ec045fSJean-Jacques Hiblot ret = regulator_set_enable(mmc->vmmc_supply, true); 19102051aefeSPeng Fan if (ret) { 19112051aefeSPeng Fan puts("Error enabling VMMC supply\n"); 19122051aefeSPeng Fan return ret; 19132051aefeSPeng Fan } 191406ec045fSJean-Jacques Hiblot } 19152051aefeSPeng Fan #endif 191605cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */ 191705cbeb7cSSimon Glass /* 191805cbeb7cSSimon Glass * Driver model should use a regulator, as above, rather than calling 191905cbeb7cSSimon Glass * out to board code. 192005cbeb7cSSimon Glass */ 192105cbeb7cSSimon Glass board_mmc_power_init(); 192205cbeb7cSSimon Glass #endif 19232051aefeSPeng Fan return 0; 19242051aefeSPeng Fan } 19252051aefeSPeng Fan 1926e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc) 1927272cc70bSAndy Fleming { 19288ca51e51SSimon Glass bool no_card; 1929afd5932bSMacpaul Lin int err; 1930272cc70bSAndy Fleming 1931ab769f22SPantelis Antoniou /* we pretend there's no card when init is NULL */ 19328ca51e51SSimon Glass no_card = mmc_getcd(mmc) == 0; 1933e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 19348ca51e51SSimon Glass no_card = no_card || (mmc->cfg->ops->init == NULL); 19358ca51e51SSimon Glass #endif 19368ca51e51SSimon Glass if (no_card) { 193748972d90SThierry Reding mmc->has_init = 0; 193856196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 193948972d90SThierry Reding printf("MMC: no card present\n"); 194056196826SPaul Burton #endif 1941915ffa52SJaehoon Chung return -ENOMEDIUM; 194248972d90SThierry Reding } 194348972d90SThierry Reding 1944bc897b1dSLei Wen if (mmc->has_init) 1945bc897b1dSLei Wen return 0; 1946bc897b1dSLei Wen 19475a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 19485a8dbdc6SYangbo Lu mmc_adapter_card_type_ident(); 19495a8dbdc6SYangbo Lu #endif 19502051aefeSPeng Fan err = mmc_power_init(mmc); 19512051aefeSPeng Fan if (err) 19522051aefeSPeng Fan return err; 195395de9ab2SPaul Kocialkowski 1954e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 19558ca51e51SSimon Glass /* The device has already been probed ready for use */ 19568ca51e51SSimon Glass #else 1957ab769f22SPantelis Antoniou /* made sure it's not NULL earlier */ 195893bfd616SPantelis Antoniou err = mmc->cfg->ops->init(mmc); 1959272cc70bSAndy Fleming if (err) 1960272cc70bSAndy Fleming return err; 19618ca51e51SSimon Glass #endif 1962786e8f81SAndrew Gabbasov mmc->ddr_mode = 0; 1963b86b85e2SIlya Yanok mmc_set_bus_width(mmc, 1); 1964b86b85e2SIlya Yanok mmc_set_clock(mmc, 1); 1965b86b85e2SIlya Yanok 1966272cc70bSAndy Fleming /* Reset the Card */ 1967272cc70bSAndy Fleming err = mmc_go_idle(mmc); 1968272cc70bSAndy Fleming 1969272cc70bSAndy Fleming if (err) 1970272cc70bSAndy Fleming return err; 1971272cc70bSAndy Fleming 1972bc897b1dSLei Wen /* The internal partition reset to user partition(0) at every CMD0*/ 1973c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->hwpart = 0; 1974bc897b1dSLei Wen 1975272cc70bSAndy Fleming /* Test for SD version 2 */ 1976272cc70bSAndy Fleming err = mmc_send_if_cond(mmc); 1977272cc70bSAndy Fleming 1978272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */ 1979272cc70bSAndy Fleming err = sd_send_op_cond(mmc); 1980272cc70bSAndy Fleming 1981272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */ 1982915ffa52SJaehoon Chung if (err == -ETIMEDOUT) { 1983272cc70bSAndy Fleming err = mmc_send_op_cond(mmc); 1984272cc70bSAndy Fleming 1985bd47c135SAndrew Gabbasov if (err) { 198656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 1987272cc70bSAndy Fleming printf("Card did not respond to voltage select!\n"); 198856196826SPaul Burton #endif 1989915ffa52SJaehoon Chung return -EOPNOTSUPP; 1990272cc70bSAndy Fleming } 1991272cc70bSAndy Fleming } 1992272cc70bSAndy Fleming 1993bd47c135SAndrew Gabbasov if (!err) 1994e9550449SChe-Liang Chiou mmc->init_in_progress = 1; 1995e9550449SChe-Liang Chiou 1996e9550449SChe-Liang Chiou return err; 1997e9550449SChe-Liang Chiou } 1998e9550449SChe-Liang Chiou 1999e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc) 2000e9550449SChe-Liang Chiou { 2001e9550449SChe-Liang Chiou int err = 0; 2002e9550449SChe-Liang Chiou 2003bd47c135SAndrew Gabbasov mmc->init_in_progress = 0; 2004e9550449SChe-Liang Chiou if (mmc->op_cond_pending) 2005e9550449SChe-Liang Chiou err = mmc_complete_op_cond(mmc); 2006e9550449SChe-Liang Chiou 2007e9550449SChe-Liang Chiou if (!err) 2008bc897b1dSLei Wen err = mmc_startup(mmc); 2009bc897b1dSLei Wen if (err) 2010bc897b1dSLei Wen mmc->has_init = 0; 2011bc897b1dSLei Wen else 2012bc897b1dSLei Wen mmc->has_init = 1; 2013e9550449SChe-Liang Chiou return err; 2014e9550449SChe-Liang Chiou } 2015e9550449SChe-Liang Chiou 2016e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc) 2017e9550449SChe-Liang Chiou { 2018bd47c135SAndrew Gabbasov int err = 0; 2019ce9eca94SMarek Vasut __maybe_unused unsigned start; 2020c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 202133fb211dSSimon Glass struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev); 2022e9550449SChe-Liang Chiou 202333fb211dSSimon Glass upriv->mmc = mmc; 202433fb211dSSimon Glass #endif 2025e9550449SChe-Liang Chiou if (mmc->has_init) 2026e9550449SChe-Liang Chiou return 0; 2027d803fea5SMateusz Zalega 2028d803fea5SMateusz Zalega start = get_timer(0); 2029d803fea5SMateusz Zalega 2030e9550449SChe-Liang Chiou if (!mmc->init_in_progress) 2031e9550449SChe-Liang Chiou err = mmc_start_init(mmc); 2032e9550449SChe-Liang Chiou 2033bd47c135SAndrew Gabbasov if (!err) 2034e9550449SChe-Liang Chiou err = mmc_complete_init(mmc); 2035919b4858SJagan Teki if (err) 2036919b4858SJagan Teki printf("%s: %d, time %lu\n", __func__, err, get_timer(start)); 2037919b4858SJagan Teki 2038bc897b1dSLei Wen return err; 2039272cc70bSAndy Fleming } 2040272cc70bSAndy Fleming 2041ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val) 2042ab71188cSMarkus Niebel { 2043ab71188cSMarkus Niebel mmc->dsr = val; 2044ab71188cSMarkus Niebel return 0; 2045ab71188cSMarkus Niebel } 2046ab71188cSMarkus Niebel 2047cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */ 2048cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis) 2049272cc70bSAndy Fleming { 2050272cc70bSAndy Fleming return -1; 2051272cc70bSAndy Fleming } 2052272cc70bSAndy Fleming 2053cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */ 2054cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis) 2055cee9ab7cSJeroen Hofstee { 2056cee9ab7cSJeroen Hofstee return -1; 2057cee9ab7cSJeroen Hofstee } 2058272cc70bSAndy Fleming 2059e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit) 2060e9550449SChe-Liang Chiou { 2061e9550449SChe-Liang Chiou mmc->preinit = preinit; 2062e9550449SChe-Liang Chiou } 2063e9550449SChe-Liang Chiou 2064c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD) 20658e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 20668e3332e2SSjoerd Simons { 20678e3332e2SSjoerd Simons return 0; 20688e3332e2SSjoerd Simons } 2069c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC) 20708e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 20718e3332e2SSjoerd Simons { 20724a1db6d8SSimon Glass int ret, i; 20738e3332e2SSjoerd Simons struct uclass *uc; 20744a1db6d8SSimon Glass struct udevice *dev; 20758e3332e2SSjoerd Simons 20768e3332e2SSjoerd Simons ret = uclass_get(UCLASS_MMC, &uc); 20778e3332e2SSjoerd Simons if (ret) 20788e3332e2SSjoerd Simons return ret; 20798e3332e2SSjoerd Simons 20804a1db6d8SSimon Glass /* 20814a1db6d8SSimon Glass * Try to add them in sequence order. Really with driver model we 20824a1db6d8SSimon Glass * should allow holes, but the current MMC list does not allow that. 20834a1db6d8SSimon Glass * So if we request 0, 1, 3 we will get 0, 1, 2. 20844a1db6d8SSimon Glass */ 20854a1db6d8SSimon Glass for (i = 0; ; i++) { 20864a1db6d8SSimon Glass ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev); 20874a1db6d8SSimon Glass if (ret == -ENODEV) 20884a1db6d8SSimon Glass break; 20894a1db6d8SSimon Glass } 20904a1db6d8SSimon Glass uclass_foreach_dev(dev, uc) { 20914a1db6d8SSimon Glass ret = device_probe(dev); 20928e3332e2SSjoerd Simons if (ret) 20934a1db6d8SSimon Glass printf("%s - probe failed: %d\n", dev->name, ret); 20948e3332e2SSjoerd Simons } 20958e3332e2SSjoerd Simons 20968e3332e2SSjoerd Simons return 0; 20978e3332e2SSjoerd Simons } 20988e3332e2SSjoerd Simons #else 20998e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 21008e3332e2SSjoerd Simons { 21018e3332e2SSjoerd Simons if (board_mmc_init(bis) < 0) 21028e3332e2SSjoerd Simons cpu_mmc_init(bis); 21038e3332e2SSjoerd Simons 21048e3332e2SSjoerd Simons return 0; 21058e3332e2SSjoerd Simons } 21068e3332e2SSjoerd Simons #endif 2107e9550449SChe-Liang Chiou 2108272cc70bSAndy Fleming int mmc_initialize(bd_t *bis) 2109272cc70bSAndy Fleming { 21101b26bab1SDaniel Kochmański static int initialized = 0; 21118e3332e2SSjoerd Simons int ret; 21121b26bab1SDaniel Kochmański if (initialized) /* Avoid initializing mmc multiple times */ 21131b26bab1SDaniel Kochmański return 0; 21141b26bab1SDaniel Kochmański initialized = 1; 21151b26bab1SDaniel Kochmański 2116c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK) 2117b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY) 2118c40fdca6SSimon Glass mmc_list_init(); 2119c40fdca6SSimon Glass #endif 2120b5b838f1SMarek Vasut #endif 21218e3332e2SSjoerd Simons ret = mmc_probe(bis); 21228e3332e2SSjoerd Simons if (ret) 21238e3332e2SSjoerd Simons return ret; 2124272cc70bSAndy Fleming 2125bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD 2126272cc70bSAndy Fleming print_mmc_devices(','); 2127bb0dc108SYing Zhang #endif 2128272cc70bSAndy Fleming 2129c40fdca6SSimon Glass mmc_do_preinit(); 2130272cc70bSAndy Fleming return 0; 2131272cc70bSAndy Fleming } 2132cd3d4880STomas Melin 2133cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE 2134cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc) 2135cd3d4880STomas Melin { 2136cd3d4880STomas Melin int err; 2137cd3d4880STomas Melin ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 2138cd3d4880STomas Melin 2139cd3d4880STomas Melin err = mmc_send_ext_csd(mmc, ext_csd); 2140cd3d4880STomas Melin if (err) { 2141cd3d4880STomas Melin puts("Could not get ext_csd register values\n"); 2142cd3d4880STomas Melin return err; 2143cd3d4880STomas Melin } 2144cd3d4880STomas Melin 2145cd3d4880STomas Melin if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) { 2146cd3d4880STomas Melin puts("Background operations not supported on device\n"); 2147cd3d4880STomas Melin return -EMEDIUMTYPE; 2148cd3d4880STomas Melin } 2149cd3d4880STomas Melin 2150cd3d4880STomas Melin if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) { 2151cd3d4880STomas Melin puts("Background operations already enabled\n"); 2152cd3d4880STomas Melin return 0; 2153cd3d4880STomas Melin } 2154cd3d4880STomas Melin 2155cd3d4880STomas Melin err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1); 2156cd3d4880STomas Melin if (err) { 2157cd3d4880STomas Melin puts("Failed to enable manual background operations\n"); 2158cd3d4880STomas Melin return err; 2159cd3d4880STomas Melin } 2160cd3d4880STomas Melin 2161cd3d4880STomas Melin puts("Enabled manual background operations\n"); 2162cd3d4880STomas Melin 2163cd3d4880STomas Melin return 0; 2164cd3d4880STomas Melin } 2165cd3d4880STomas Melin #endif 2166