1272cc70bSAndy Fleming /* 2272cc70bSAndy Fleming * Copyright 2008, Freescale Semiconductor, Inc 3272cc70bSAndy Fleming * Andy Fleming 4272cc70bSAndy Fleming * 5272cc70bSAndy Fleming * Based vaguely on the Linux code 6272cc70bSAndy Fleming * 71a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 8272cc70bSAndy Fleming */ 9272cc70bSAndy Fleming 10272cc70bSAndy Fleming #include <config.h> 11272cc70bSAndy Fleming #include <common.h> 12272cc70bSAndy Fleming #include <command.h> 138e3332e2SSjoerd Simons #include <dm.h> 148e3332e2SSjoerd Simons #include <dm/device-internal.h> 15d4622df3SStephen Warren #include <errno.h> 16272cc70bSAndy Fleming #include <mmc.h> 17272cc70bSAndy Fleming #include <part.h> 182051aefeSPeng Fan #include <power/regulator.h> 19272cc70bSAndy Fleming #include <malloc.h> 20cf92e05cSSimon Glass #include <memalign.h> 21272cc70bSAndy Fleming #include <linux/list.h> 229b1f942cSRabin Vincent #include <div64.h> 23da61fa5fSPaul Burton #include "mmc_private.h" 24272cc70bSAndy Fleming 253697e599SPeng Fan static const unsigned int sd_au_size[] = { 263697e599SPeng Fan 0, SZ_16K / 512, SZ_32K / 512, 273697e599SPeng Fan SZ_64K / 512, SZ_128K / 512, SZ_256K / 512, 283697e599SPeng Fan SZ_512K / 512, SZ_1M / 512, SZ_2M / 512, 293697e599SPeng Fan SZ_4M / 512, SZ_8M / 512, (SZ_8M + SZ_4M) / 512, 303697e599SPeng Fan SZ_16M / 512, (SZ_16M + SZ_8M) / 512, SZ_32M / 512, SZ_64M / 512, 313697e599SPeng Fan }; 323697e599SPeng Fan 33aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage); 34fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc); 3501298da3SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps); 36aff5d3c8SKishon Vijay Abraham I 37b5b838f1SMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY) 38b5b838f1SMarek Vasut static struct mmc mmc_static; 39b5b838f1SMarek Vasut struct mmc *find_mmc_device(int dev_num) 40b5b838f1SMarek Vasut { 41b5b838f1SMarek Vasut return &mmc_static; 42b5b838f1SMarek Vasut } 43b5b838f1SMarek Vasut 44b5b838f1SMarek Vasut void mmc_do_preinit(void) 45b5b838f1SMarek Vasut { 46b5b838f1SMarek Vasut struct mmc *m = &mmc_static; 47b5b838f1SMarek Vasut #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 48b5b838f1SMarek Vasut mmc_set_preinit(m, 1); 49b5b838f1SMarek Vasut #endif 50b5b838f1SMarek Vasut if (m->preinit) 51b5b838f1SMarek Vasut mmc_start_init(m); 52b5b838f1SMarek Vasut } 53b5b838f1SMarek Vasut 54b5b838f1SMarek Vasut struct blk_desc *mmc_get_blk_desc(struct mmc *mmc) 55b5b838f1SMarek Vasut { 56b5b838f1SMarek Vasut return &mmc->block_dev; 57b5b838f1SMarek Vasut } 58b5b838f1SMarek Vasut #endif 59b5b838f1SMarek Vasut 60e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 61c10b85d6SJean-Jacques Hiblot 62c10b85d6SJean-Jacques Hiblot static int mmc_wait_dat0(struct mmc *mmc, int state, int timeout) 63c10b85d6SJean-Jacques Hiblot { 64c10b85d6SJean-Jacques Hiblot return -ENOSYS; 65c10b85d6SJean-Jacques Hiblot } 66c10b85d6SJean-Jacques Hiblot 67750121c3SJeroen Hofstee __weak int board_mmc_getwp(struct mmc *mmc) 68d23d8d7eSNikita Kiryanov { 69d23d8d7eSNikita Kiryanov return -1; 70d23d8d7eSNikita Kiryanov } 71d23d8d7eSNikita Kiryanov 72d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc) 73d23d8d7eSNikita Kiryanov { 74d23d8d7eSNikita Kiryanov int wp; 75d23d8d7eSNikita Kiryanov 76d23d8d7eSNikita Kiryanov wp = board_mmc_getwp(mmc); 77d23d8d7eSNikita Kiryanov 78d4e1da4eSPeter Korsgaard if (wp < 0) { 7993bfd616SPantelis Antoniou if (mmc->cfg->ops->getwp) 8093bfd616SPantelis Antoniou wp = mmc->cfg->ops->getwp(mmc); 81d4e1da4eSPeter Korsgaard else 82d4e1da4eSPeter Korsgaard wp = 0; 83d4e1da4eSPeter Korsgaard } 84d23d8d7eSNikita Kiryanov 85d23d8d7eSNikita Kiryanov return wp; 86d23d8d7eSNikita Kiryanov } 87d23d8d7eSNikita Kiryanov 88cee9ab7cSJeroen Hofstee __weak int board_mmc_getcd(struct mmc *mmc) 89cee9ab7cSJeroen Hofstee { 9011fdade2SStefano Babic return -1; 9111fdade2SStefano Babic } 928ca51e51SSimon Glass #endif 9311fdade2SStefano Babic 948635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE 95c0c76ebaSSimon Glass void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd) 96c0c76ebaSSimon Glass { 97c0c76ebaSSimon Glass printf("CMD_SEND:%d\n", cmd->cmdidx); 98c0c76ebaSSimon Glass printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg); 99c0c76ebaSSimon Glass } 100c0c76ebaSSimon Glass 101c0c76ebaSSimon Glass void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret) 102c0c76ebaSSimon Glass { 1035db2fe3aSRaffaele Recalcati int i; 1045db2fe3aSRaffaele Recalcati u8 *ptr; 1055db2fe3aSRaffaele Recalcati 1067863ce58SBin Meng if (ret) { 1077863ce58SBin Meng printf("\t\tRET\t\t\t %d\n", ret); 1087863ce58SBin Meng } else { 1095db2fe3aSRaffaele Recalcati switch (cmd->resp_type) { 1105db2fe3aSRaffaele Recalcati case MMC_RSP_NONE: 1115db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_NONE\n"); 1125db2fe3aSRaffaele Recalcati break; 1135db2fe3aSRaffaele Recalcati case MMC_RSP_R1: 1145db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n", 1155db2fe3aSRaffaele Recalcati cmd->response[0]); 1165db2fe3aSRaffaele Recalcati break; 1175db2fe3aSRaffaele Recalcati case MMC_RSP_R1b: 1185db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n", 1195db2fe3aSRaffaele Recalcati cmd->response[0]); 1205db2fe3aSRaffaele Recalcati break; 1215db2fe3aSRaffaele Recalcati case MMC_RSP_R2: 1225db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R2\t\t 0x%08X \n", 1235db2fe3aSRaffaele Recalcati cmd->response[0]); 1245db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1255db2fe3aSRaffaele Recalcati cmd->response[1]); 1265db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1275db2fe3aSRaffaele Recalcati cmd->response[2]); 1285db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1295db2fe3aSRaffaele Recalcati cmd->response[3]); 1305db2fe3aSRaffaele Recalcati printf("\n"); 1315db2fe3aSRaffaele Recalcati printf("\t\t\t\t\tDUMPING DATA\n"); 1325db2fe3aSRaffaele Recalcati for (i = 0; i < 4; i++) { 1335db2fe3aSRaffaele Recalcati int j; 1345db2fe3aSRaffaele Recalcati printf("\t\t\t\t\t%03d - ", i*4); 135146bec79SDirk Behme ptr = (u8 *)&cmd->response[i]; 1365db2fe3aSRaffaele Recalcati ptr += 3; 1375db2fe3aSRaffaele Recalcati for (j = 0; j < 4; j++) 1385db2fe3aSRaffaele Recalcati printf("%02X ", *ptr--); 1395db2fe3aSRaffaele Recalcati printf("\n"); 1405db2fe3aSRaffaele Recalcati } 1415db2fe3aSRaffaele Recalcati break; 1425db2fe3aSRaffaele Recalcati case MMC_RSP_R3: 1435db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n", 1445db2fe3aSRaffaele Recalcati cmd->response[0]); 1455db2fe3aSRaffaele Recalcati break; 1465db2fe3aSRaffaele Recalcati default: 1475db2fe3aSRaffaele Recalcati printf("\t\tERROR MMC rsp not supported\n"); 1485db2fe3aSRaffaele Recalcati break; 1495db2fe3aSRaffaele Recalcati } 1507863ce58SBin Meng } 151c0c76ebaSSimon Glass } 152c0c76ebaSSimon Glass 153c0c76ebaSSimon Glass void mmc_trace_state(struct mmc *mmc, struct mmc_cmd *cmd) 154c0c76ebaSSimon Glass { 155c0c76ebaSSimon Glass int status; 156c0c76ebaSSimon Glass 157c0c76ebaSSimon Glass status = (cmd->response[0] & MMC_STATUS_CURR_STATE) >> 9; 158c0c76ebaSSimon Glass printf("CURR STATE:%d\n", status); 159c0c76ebaSSimon Glass } 1605db2fe3aSRaffaele Recalcati #endif 161c0c76ebaSSimon Glass 16235f9e196SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG) 16335f9e196SJean-Jacques Hiblot const char *mmc_mode_name(enum bus_mode mode) 16435f9e196SJean-Jacques Hiblot { 16535f9e196SJean-Jacques Hiblot static const char *const names[] = { 16635f9e196SJean-Jacques Hiblot [MMC_LEGACY] = "MMC legacy", 16735f9e196SJean-Jacques Hiblot [SD_LEGACY] = "SD Legacy", 16835f9e196SJean-Jacques Hiblot [MMC_HS] = "MMC High Speed (26MHz)", 16935f9e196SJean-Jacques Hiblot [SD_HS] = "SD High Speed (50MHz)", 17035f9e196SJean-Jacques Hiblot [UHS_SDR12] = "UHS SDR12 (25MHz)", 17135f9e196SJean-Jacques Hiblot [UHS_SDR25] = "UHS SDR25 (50MHz)", 17235f9e196SJean-Jacques Hiblot [UHS_SDR50] = "UHS SDR50 (100MHz)", 17335f9e196SJean-Jacques Hiblot [UHS_SDR104] = "UHS SDR104 (208MHz)", 17435f9e196SJean-Jacques Hiblot [UHS_DDR50] = "UHS DDR50 (50MHz)", 17535f9e196SJean-Jacques Hiblot [MMC_HS_52] = "MMC High Speed (52MHz)", 17635f9e196SJean-Jacques Hiblot [MMC_DDR_52] = "MMC DDR52 (52MHz)", 17735f9e196SJean-Jacques Hiblot [MMC_HS_200] = "HS200 (200MHz)", 17835f9e196SJean-Jacques Hiblot }; 17935f9e196SJean-Jacques Hiblot 18035f9e196SJean-Jacques Hiblot if (mode >= MMC_MODES_END) 18135f9e196SJean-Jacques Hiblot return "Unknown mode"; 18235f9e196SJean-Jacques Hiblot else 18335f9e196SJean-Jacques Hiblot return names[mode]; 18435f9e196SJean-Jacques Hiblot } 18535f9e196SJean-Jacques Hiblot #endif 18635f9e196SJean-Jacques Hiblot 18705038576SJean-Jacques Hiblot static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode) 18805038576SJean-Jacques Hiblot { 18905038576SJean-Jacques Hiblot static const int freqs[] = { 19005038576SJean-Jacques Hiblot [SD_LEGACY] = 25000000, 19105038576SJean-Jacques Hiblot [MMC_HS] = 26000000, 19205038576SJean-Jacques Hiblot [SD_HS] = 50000000, 19305038576SJean-Jacques Hiblot [UHS_SDR12] = 25000000, 19405038576SJean-Jacques Hiblot [UHS_SDR25] = 50000000, 19505038576SJean-Jacques Hiblot [UHS_SDR50] = 100000000, 19605038576SJean-Jacques Hiblot [UHS_SDR104] = 208000000, 19705038576SJean-Jacques Hiblot [UHS_DDR50] = 50000000, 19805038576SJean-Jacques Hiblot [MMC_HS_52] = 52000000, 19905038576SJean-Jacques Hiblot [MMC_DDR_52] = 52000000, 20005038576SJean-Jacques Hiblot [MMC_HS_200] = 200000000, 20105038576SJean-Jacques Hiblot }; 20205038576SJean-Jacques Hiblot 20305038576SJean-Jacques Hiblot if (mode == MMC_LEGACY) 20405038576SJean-Jacques Hiblot return mmc->legacy_speed; 20505038576SJean-Jacques Hiblot else if (mode >= MMC_MODES_END) 20605038576SJean-Jacques Hiblot return 0; 20705038576SJean-Jacques Hiblot else 20805038576SJean-Jacques Hiblot return freqs[mode]; 20905038576SJean-Jacques Hiblot } 21005038576SJean-Jacques Hiblot 21135f9e196SJean-Jacques Hiblot static int mmc_select_mode(struct mmc *mmc, enum bus_mode mode) 21235f9e196SJean-Jacques Hiblot { 21335f9e196SJean-Jacques Hiblot mmc->selected_mode = mode; 21405038576SJean-Jacques Hiblot mmc->tran_speed = mmc_mode2freq(mmc, mode); 2153862b854SJean-Jacques Hiblot mmc->ddr_mode = mmc_is_mode_ddr(mode); 21635f9e196SJean-Jacques Hiblot debug("selecting mode %s (freq : %d MHz)\n", mmc_mode_name(mode), 21735f9e196SJean-Jacques Hiblot mmc->tran_speed / 1000000); 21835f9e196SJean-Jacques Hiblot return 0; 21935f9e196SJean-Jacques Hiblot } 22035f9e196SJean-Jacques Hiblot 221e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 222c0c76ebaSSimon Glass int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) 223c0c76ebaSSimon Glass { 224c0c76ebaSSimon Glass int ret; 225c0c76ebaSSimon Glass 226c0c76ebaSSimon Glass mmmc_trace_before_send(mmc, cmd); 227c0c76ebaSSimon Glass ret = mmc->cfg->ops->send_cmd(mmc, cmd, data); 228c0c76ebaSSimon Glass mmmc_trace_after_send(mmc, cmd, ret); 229c0c76ebaSSimon Glass 2308635ff9eSMarek Vasut return ret; 231272cc70bSAndy Fleming } 2328ca51e51SSimon Glass #endif 233272cc70bSAndy Fleming 234da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout) 2355d4fc8d9SRaffaele Recalcati { 2365d4fc8d9SRaffaele Recalcati struct mmc_cmd cmd; 237d617c426SJan Kloetzke int err, retries = 5; 2385d4fc8d9SRaffaele Recalcati 2395d4fc8d9SRaffaele Recalcati cmd.cmdidx = MMC_CMD_SEND_STATUS; 2405d4fc8d9SRaffaele Recalcati cmd.resp_type = MMC_RSP_R1; 241aaf3d41aSMarek Vasut if (!mmc_host_is_spi(mmc)) 242aaf3d41aSMarek Vasut cmd.cmdarg = mmc->rca << 16; 2435d4fc8d9SRaffaele Recalcati 2441677eef4SAndrew Gabbasov while (1) { 2455d4fc8d9SRaffaele Recalcati err = mmc_send_cmd(mmc, &cmd, NULL); 246d617c426SJan Kloetzke if (!err) { 247d617c426SJan Kloetzke if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) && 248d617c426SJan Kloetzke (cmd.response[0] & MMC_STATUS_CURR_STATE) != 249d617c426SJan Kloetzke MMC_STATE_PRG) 2505d4fc8d9SRaffaele Recalcati break; 251d0c221feSJean-Jacques Hiblot 252d0c221feSJean-Jacques Hiblot if (cmd.response[0] & MMC_STATUS_MASK) { 25356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 254d617c426SJan Kloetzke printf("Status Error: 0x%08X\n", 255d617c426SJan Kloetzke cmd.response[0]); 25656196826SPaul Burton #endif 257915ffa52SJaehoon Chung return -ECOMM; 258d617c426SJan Kloetzke } 259d617c426SJan Kloetzke } else if (--retries < 0) 260d617c426SJan Kloetzke return err; 2615d4fc8d9SRaffaele Recalcati 2621677eef4SAndrew Gabbasov if (timeout-- <= 0) 2631677eef4SAndrew Gabbasov break; 2645d4fc8d9SRaffaele Recalcati 2651677eef4SAndrew Gabbasov udelay(1000); 2661677eef4SAndrew Gabbasov } 2675d4fc8d9SRaffaele Recalcati 268c0c76ebaSSimon Glass mmc_trace_state(mmc, &cmd); 2695b0c942fSJongman Heo if (timeout <= 0) { 27056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2715d4fc8d9SRaffaele Recalcati printf("Timeout waiting card ready\n"); 27256196826SPaul Burton #endif 273915ffa52SJaehoon Chung return -ETIMEDOUT; 2745d4fc8d9SRaffaele Recalcati } 2755d4fc8d9SRaffaele Recalcati 2765d4fc8d9SRaffaele Recalcati return 0; 2775d4fc8d9SRaffaele Recalcati } 2785d4fc8d9SRaffaele Recalcati 279da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len) 280272cc70bSAndy Fleming { 281272cc70bSAndy Fleming struct mmc_cmd cmd; 282*83dc4227SKishon Vijay Abraham I int err; 283272cc70bSAndy Fleming 284786e8f81SAndrew Gabbasov if (mmc->ddr_mode) 285d22e3d46SJaehoon Chung return 0; 286d22e3d46SJaehoon Chung 287272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SET_BLOCKLEN; 288272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 289272cc70bSAndy Fleming cmd.cmdarg = len; 290272cc70bSAndy Fleming 291*83dc4227SKishon Vijay Abraham I err = mmc_send_cmd(mmc, &cmd, NULL); 292*83dc4227SKishon Vijay Abraham I 293*83dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS 294*83dc4227SKishon Vijay Abraham I if (err && (mmc->quirks & MMC_QUIRK_RETRY_SET_BLOCKLEN)) { 295*83dc4227SKishon Vijay Abraham I int retries = 4; 296*83dc4227SKishon Vijay Abraham I /* 297*83dc4227SKishon Vijay Abraham I * It has been seen that SET_BLOCKLEN may fail on the first 298*83dc4227SKishon Vijay Abraham I * attempt, let's try a few more time 299*83dc4227SKishon Vijay Abraham I */ 300*83dc4227SKishon Vijay Abraham I do { 301*83dc4227SKishon Vijay Abraham I err = mmc_send_cmd(mmc, &cmd, NULL); 302*83dc4227SKishon Vijay Abraham I if (!err) 303*83dc4227SKishon Vijay Abraham I break; 304*83dc4227SKishon Vijay Abraham I } while (retries--); 305*83dc4227SKishon Vijay Abraham I } 306*83dc4227SKishon Vijay Abraham I #endif 307*83dc4227SKishon Vijay Abraham I 308*83dc4227SKishon Vijay Abraham I return err; 309272cc70bSAndy Fleming } 310272cc70bSAndy Fleming 311ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start, 312fdbb873eSKim Phillips lbaint_t blkcnt) 313272cc70bSAndy Fleming { 314272cc70bSAndy Fleming struct mmc_cmd cmd; 315272cc70bSAndy Fleming struct mmc_data data; 316272cc70bSAndy Fleming 3174a1a06bcSAlagu Sankar if (blkcnt > 1) 3184a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; 3194a1a06bcSAlagu Sankar else 320272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; 321272cc70bSAndy Fleming 322272cc70bSAndy Fleming if (mmc->high_capacity) 3234a1a06bcSAlagu Sankar cmd.cmdarg = start; 324272cc70bSAndy Fleming else 3254a1a06bcSAlagu Sankar cmd.cmdarg = start * mmc->read_bl_len; 326272cc70bSAndy Fleming 327272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 328272cc70bSAndy Fleming 329272cc70bSAndy Fleming data.dest = dst; 3304a1a06bcSAlagu Sankar data.blocks = blkcnt; 331272cc70bSAndy Fleming data.blocksize = mmc->read_bl_len; 332272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 333272cc70bSAndy Fleming 3344a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, &data)) 3354a1a06bcSAlagu Sankar return 0; 3364a1a06bcSAlagu Sankar 3374a1a06bcSAlagu Sankar if (blkcnt > 1) { 3384a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; 3394a1a06bcSAlagu Sankar cmd.cmdarg = 0; 3404a1a06bcSAlagu Sankar cmd.resp_type = MMC_RSP_R1b; 3414a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, NULL)) { 34256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 3434a1a06bcSAlagu Sankar printf("mmc fail to send stop cmd\n"); 34456196826SPaul Burton #endif 3454a1a06bcSAlagu Sankar return 0; 3464a1a06bcSAlagu Sankar } 347272cc70bSAndy Fleming } 348272cc70bSAndy Fleming 3494a1a06bcSAlagu Sankar return blkcnt; 350272cc70bSAndy Fleming } 351272cc70bSAndy Fleming 352c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK) 3537dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst) 35433fb211dSSimon Glass #else 3557dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, 3567dba0b93SSimon Glass void *dst) 35733fb211dSSimon Glass #endif 358272cc70bSAndy Fleming { 359c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK) 36033fb211dSSimon Glass struct blk_desc *block_dev = dev_get_uclass_platdata(dev); 36133fb211dSSimon Glass #endif 362bcce53d0SSimon Glass int dev_num = block_dev->devnum; 363873cc1d7SStephen Warren int err; 3644a1a06bcSAlagu Sankar lbaint_t cur, blocks_todo = blkcnt; 365272cc70bSAndy Fleming 3664a1a06bcSAlagu Sankar if (blkcnt == 0) 3674a1a06bcSAlagu Sankar return 0; 3684a1a06bcSAlagu Sankar 3694a1a06bcSAlagu Sankar struct mmc *mmc = find_mmc_device(dev_num); 370272cc70bSAndy Fleming if (!mmc) 371272cc70bSAndy Fleming return 0; 372272cc70bSAndy Fleming 373b5b838f1SMarek Vasut if (CONFIG_IS_ENABLED(MMC_TINY)) 374b5b838f1SMarek Vasut err = mmc_switch_part(mmc, block_dev->hwpart); 375b5b838f1SMarek Vasut else 37669f45cd5SSimon Glass err = blk_dselect_hwpart(block_dev, block_dev->hwpart); 377b5b838f1SMarek Vasut 378873cc1d7SStephen Warren if (err < 0) 379873cc1d7SStephen Warren return 0; 380873cc1d7SStephen Warren 381c40fdca6SSimon Glass if ((start + blkcnt) > block_dev->lba) { 38256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 383ff8fef56SSascha Silbe printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", 384c40fdca6SSimon Glass start + blkcnt, block_dev->lba); 38556196826SPaul Burton #endif 386d2bf29e3SLei Wen return 0; 387d2bf29e3SLei Wen } 388272cc70bSAndy Fleming 38911692991SSimon Glass if (mmc_set_blocklen(mmc, mmc->read_bl_len)) { 39011692991SSimon Glass debug("%s: Failed to set blocklen\n", __func__); 391272cc70bSAndy Fleming return 0; 39211692991SSimon Glass } 393272cc70bSAndy Fleming 3944a1a06bcSAlagu Sankar do { 39593bfd616SPantelis Antoniou cur = (blocks_todo > mmc->cfg->b_max) ? 39693bfd616SPantelis Antoniou mmc->cfg->b_max : blocks_todo; 39711692991SSimon Glass if (mmc_read_blocks(mmc, dst, start, cur) != cur) { 39811692991SSimon Glass debug("%s: Failed to read blocks\n", __func__); 3994a1a06bcSAlagu Sankar return 0; 40011692991SSimon Glass } 4014a1a06bcSAlagu Sankar blocks_todo -= cur; 4024a1a06bcSAlagu Sankar start += cur; 4034a1a06bcSAlagu Sankar dst += cur * mmc->read_bl_len; 4044a1a06bcSAlagu Sankar } while (blocks_todo > 0); 405272cc70bSAndy Fleming 406272cc70bSAndy Fleming return blkcnt; 407272cc70bSAndy Fleming } 408272cc70bSAndy Fleming 409fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc) 410272cc70bSAndy Fleming { 411272cc70bSAndy Fleming struct mmc_cmd cmd; 412272cc70bSAndy Fleming int err; 413272cc70bSAndy Fleming 414272cc70bSAndy Fleming udelay(1000); 415272cc70bSAndy Fleming 416272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_GO_IDLE_STATE; 417272cc70bSAndy Fleming cmd.cmdarg = 0; 418272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_NONE; 419272cc70bSAndy Fleming 420272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 421272cc70bSAndy Fleming 422272cc70bSAndy Fleming if (err) 423272cc70bSAndy Fleming return err; 424272cc70bSAndy Fleming 425272cc70bSAndy Fleming udelay(2000); 426272cc70bSAndy Fleming 427272cc70bSAndy Fleming return 0; 428272cc70bSAndy Fleming } 429272cc70bSAndy Fleming 430c10b85d6SJean-Jacques Hiblot static int mmc_switch_voltage(struct mmc *mmc, int signal_voltage) 431c10b85d6SJean-Jacques Hiblot { 432c10b85d6SJean-Jacques Hiblot struct mmc_cmd cmd; 433c10b85d6SJean-Jacques Hiblot int err = 0; 434c10b85d6SJean-Jacques Hiblot 435c10b85d6SJean-Jacques Hiblot /* 436c10b85d6SJean-Jacques Hiblot * Send CMD11 only if the request is to switch the card to 437c10b85d6SJean-Jacques Hiblot * 1.8V signalling. 438c10b85d6SJean-Jacques Hiblot */ 439c10b85d6SJean-Jacques Hiblot if (signal_voltage == MMC_SIGNAL_VOLTAGE_330) 440c10b85d6SJean-Jacques Hiblot return mmc_set_signal_voltage(mmc, signal_voltage); 441c10b85d6SJean-Jacques Hiblot 442c10b85d6SJean-Jacques Hiblot cmd.cmdidx = SD_CMD_SWITCH_UHS18V; 443c10b85d6SJean-Jacques Hiblot cmd.cmdarg = 0; 444c10b85d6SJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 445c10b85d6SJean-Jacques Hiblot 446c10b85d6SJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 447c10b85d6SJean-Jacques Hiblot if (err) 448c10b85d6SJean-Jacques Hiblot return err; 449c10b85d6SJean-Jacques Hiblot 450c10b85d6SJean-Jacques Hiblot if (!mmc_host_is_spi(mmc) && (cmd.response[0] & MMC_STATUS_ERROR)) 451c10b85d6SJean-Jacques Hiblot return -EIO; 452c10b85d6SJean-Jacques Hiblot 453c10b85d6SJean-Jacques Hiblot /* 454c10b85d6SJean-Jacques Hiblot * The card should drive cmd and dat[0:3] low immediately 455c10b85d6SJean-Jacques Hiblot * after the response of cmd11, but wait 100 us to be sure 456c10b85d6SJean-Jacques Hiblot */ 457c10b85d6SJean-Jacques Hiblot err = mmc_wait_dat0(mmc, 0, 100); 458c10b85d6SJean-Jacques Hiblot if (err == -ENOSYS) 459c10b85d6SJean-Jacques Hiblot udelay(100); 460c10b85d6SJean-Jacques Hiblot else if (err) 461c10b85d6SJean-Jacques Hiblot return -ETIMEDOUT; 462c10b85d6SJean-Jacques Hiblot 463c10b85d6SJean-Jacques Hiblot /* 464c10b85d6SJean-Jacques Hiblot * During a signal voltage level switch, the clock must be gated 465c10b85d6SJean-Jacques Hiblot * for 5 ms according to the SD spec 466c10b85d6SJean-Jacques Hiblot */ 467c10b85d6SJean-Jacques Hiblot mmc_set_clock(mmc, mmc->clock, true); 468c10b85d6SJean-Jacques Hiblot 469c10b85d6SJean-Jacques Hiblot err = mmc_set_signal_voltage(mmc, signal_voltage); 470c10b85d6SJean-Jacques Hiblot if (err) 471c10b85d6SJean-Jacques Hiblot return err; 472c10b85d6SJean-Jacques Hiblot 473c10b85d6SJean-Jacques Hiblot /* Keep clock gated for at least 10 ms, though spec only says 5 ms */ 474c10b85d6SJean-Jacques Hiblot mdelay(10); 475c10b85d6SJean-Jacques Hiblot mmc_set_clock(mmc, mmc->clock, false); 476c10b85d6SJean-Jacques Hiblot 477c10b85d6SJean-Jacques Hiblot /* 478c10b85d6SJean-Jacques Hiblot * Failure to switch is indicated by the card holding 479c10b85d6SJean-Jacques Hiblot * dat[0:3] low. Wait for at least 1 ms according to spec 480c10b85d6SJean-Jacques Hiblot */ 481c10b85d6SJean-Jacques Hiblot err = mmc_wait_dat0(mmc, 1, 1000); 482c10b85d6SJean-Jacques Hiblot if (err == -ENOSYS) 483c10b85d6SJean-Jacques Hiblot udelay(1000); 484c10b85d6SJean-Jacques Hiblot else if (err) 485c10b85d6SJean-Jacques Hiblot return -ETIMEDOUT; 486c10b85d6SJean-Jacques Hiblot 487c10b85d6SJean-Jacques Hiblot return 0; 488c10b85d6SJean-Jacques Hiblot } 489c10b85d6SJean-Jacques Hiblot 490c10b85d6SJean-Jacques Hiblot static int sd_send_op_cond(struct mmc *mmc, bool uhs_en) 491272cc70bSAndy Fleming { 492272cc70bSAndy Fleming int timeout = 1000; 493272cc70bSAndy Fleming int err; 494272cc70bSAndy Fleming struct mmc_cmd cmd; 495272cc70bSAndy Fleming 4961677eef4SAndrew Gabbasov while (1) { 497272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 498272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 499272cc70bSAndy Fleming cmd.cmdarg = 0; 500272cc70bSAndy Fleming 501272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 502272cc70bSAndy Fleming 503272cc70bSAndy Fleming if (err) 504272cc70bSAndy Fleming return err; 505272cc70bSAndy Fleming 506272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_OP_COND; 507272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R3; 508250de12bSStefano Babic 509250de12bSStefano Babic /* 510250de12bSStefano Babic * Most cards do not answer if some reserved bits 511250de12bSStefano Babic * in the ocr are set. However, Some controller 512250de12bSStefano Babic * can set bit 7 (reserved for low voltages), but 513250de12bSStefano Babic * how to manage low voltages SD card is not yet 514250de12bSStefano Babic * specified. 515250de12bSStefano Babic */ 516d52ebf10SThomas Chou cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 : 51793bfd616SPantelis Antoniou (mmc->cfg->voltages & 0xff8000); 518272cc70bSAndy Fleming 519272cc70bSAndy Fleming if (mmc->version == SD_VERSION_2) 520272cc70bSAndy Fleming cmd.cmdarg |= OCR_HCS; 521272cc70bSAndy Fleming 522c10b85d6SJean-Jacques Hiblot if (uhs_en) 523c10b85d6SJean-Jacques Hiblot cmd.cmdarg |= OCR_S18R; 524c10b85d6SJean-Jacques Hiblot 525272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 526272cc70bSAndy Fleming 527272cc70bSAndy Fleming if (err) 528272cc70bSAndy Fleming return err; 529272cc70bSAndy Fleming 5301677eef4SAndrew Gabbasov if (cmd.response[0] & OCR_BUSY) 5311677eef4SAndrew Gabbasov break; 532272cc70bSAndy Fleming 5331677eef4SAndrew Gabbasov if (timeout-- <= 0) 534915ffa52SJaehoon Chung return -EOPNOTSUPP; 535272cc70bSAndy Fleming 5361677eef4SAndrew Gabbasov udelay(1000); 5371677eef4SAndrew Gabbasov } 5381677eef4SAndrew Gabbasov 539272cc70bSAndy Fleming if (mmc->version != SD_VERSION_2) 540272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 541272cc70bSAndy Fleming 542d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 543d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 544d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 545d52ebf10SThomas Chou cmd.cmdarg = 0; 546d52ebf10SThomas Chou 547d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 548d52ebf10SThomas Chou 549d52ebf10SThomas Chou if (err) 550d52ebf10SThomas Chou return err; 551d52ebf10SThomas Chou } 552d52ebf10SThomas Chou 553998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 554272cc70bSAndy Fleming 555c10b85d6SJean-Jacques Hiblot if (uhs_en && !(mmc_host_is_spi(mmc)) && (cmd.response[0] & 0x41000000) 556c10b85d6SJean-Jacques Hiblot == 0x41000000) { 557c10b85d6SJean-Jacques Hiblot err = mmc_switch_voltage(mmc, MMC_SIGNAL_VOLTAGE_180); 558c10b85d6SJean-Jacques Hiblot if (err) 559c10b85d6SJean-Jacques Hiblot return err; 560c10b85d6SJean-Jacques Hiblot } 561c10b85d6SJean-Jacques Hiblot 562272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 563272cc70bSAndy Fleming mmc->rca = 0; 564272cc70bSAndy Fleming 565272cc70bSAndy Fleming return 0; 566272cc70bSAndy Fleming } 567272cc70bSAndy Fleming 5685289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg) 569272cc70bSAndy Fleming { 5705289b535SAndrew Gabbasov struct mmc_cmd cmd; 571272cc70bSAndy Fleming int err; 572272cc70bSAndy Fleming 5735289b535SAndrew Gabbasov cmd.cmdidx = MMC_CMD_SEND_OP_COND; 5745289b535SAndrew Gabbasov cmd.resp_type = MMC_RSP_R3; 5755289b535SAndrew Gabbasov cmd.cmdarg = 0; 5765a20397bSRob Herring if (use_arg && !mmc_host_is_spi(mmc)) 5775a20397bSRob Herring cmd.cmdarg = OCR_HCS | 57893bfd616SPantelis Antoniou (mmc->cfg->voltages & 579a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_VOLTAGE_MASK)) | 580a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_ACCESS_MODE); 581e9550449SChe-Liang Chiou 5825289b535SAndrew Gabbasov err = mmc_send_cmd(mmc, &cmd, NULL); 583e9550449SChe-Liang Chiou if (err) 584e9550449SChe-Liang Chiou return err; 5855289b535SAndrew Gabbasov mmc->ocr = cmd.response[0]; 586e9550449SChe-Liang Chiou return 0; 587e9550449SChe-Liang Chiou } 588e9550449SChe-Liang Chiou 589750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc) 590e9550449SChe-Liang Chiou { 591e9550449SChe-Liang Chiou int err, i; 592e9550449SChe-Liang Chiou 593272cc70bSAndy Fleming /* Some cards seem to need this */ 594272cc70bSAndy Fleming mmc_go_idle(mmc); 595272cc70bSAndy Fleming 59631cacbabSRaffaele Recalcati /* Asking to the card its capabilities */ 597e9550449SChe-Liang Chiou for (i = 0; i < 2; i++) { 5985289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, i != 0); 59931cacbabSRaffaele Recalcati if (err) 60031cacbabSRaffaele Recalcati return err; 60131cacbabSRaffaele Recalcati 602e9550449SChe-Liang Chiou /* exit if not busy (flag seems to be inverted) */ 603a626c8d4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 604bd47c135SAndrew Gabbasov break; 605e9550449SChe-Liang Chiou } 606bd47c135SAndrew Gabbasov mmc->op_cond_pending = 1; 607bd47c135SAndrew Gabbasov return 0; 608e9550449SChe-Liang Chiou } 60931cacbabSRaffaele Recalcati 610750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc) 611e9550449SChe-Liang Chiou { 612e9550449SChe-Liang Chiou struct mmc_cmd cmd; 613e9550449SChe-Liang Chiou int timeout = 1000; 614e9550449SChe-Liang Chiou uint start; 615e9550449SChe-Liang Chiou int err; 616e9550449SChe-Liang Chiou 617e9550449SChe-Liang Chiou mmc->op_cond_pending = 0; 618cc17c01fSAndrew Gabbasov if (!(mmc->ocr & OCR_BUSY)) { 619d188b113SYangbo Lu /* Some cards seem to need this */ 620d188b113SYangbo Lu mmc_go_idle(mmc); 621d188b113SYangbo Lu 622e9550449SChe-Liang Chiou start = get_timer(0); 6231677eef4SAndrew Gabbasov while (1) { 6245289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, 1); 625272cc70bSAndy Fleming if (err) 626272cc70bSAndy Fleming return err; 6271677eef4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 6281677eef4SAndrew Gabbasov break; 629e9550449SChe-Liang Chiou if (get_timer(start) > timeout) 630915ffa52SJaehoon Chung return -EOPNOTSUPP; 631e9550449SChe-Liang Chiou udelay(100); 6321677eef4SAndrew Gabbasov } 633cc17c01fSAndrew Gabbasov } 634272cc70bSAndy Fleming 635d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 636d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 637d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 638d52ebf10SThomas Chou cmd.cmdarg = 0; 639d52ebf10SThomas Chou 640d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 641d52ebf10SThomas Chou 642d52ebf10SThomas Chou if (err) 643d52ebf10SThomas Chou return err; 644a626c8d4SAndrew Gabbasov 645a626c8d4SAndrew Gabbasov mmc->ocr = cmd.response[0]; 646d52ebf10SThomas Chou } 647d52ebf10SThomas Chou 648272cc70bSAndy Fleming mmc->version = MMC_VERSION_UNKNOWN; 649272cc70bSAndy Fleming 650272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 651def816a2SStephen Warren mmc->rca = 1; 652272cc70bSAndy Fleming 653272cc70bSAndy Fleming return 0; 654272cc70bSAndy Fleming } 655272cc70bSAndy Fleming 656272cc70bSAndy Fleming 657fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) 658272cc70bSAndy Fleming { 659272cc70bSAndy Fleming struct mmc_cmd cmd; 660272cc70bSAndy Fleming struct mmc_data data; 661272cc70bSAndy Fleming int err; 662272cc70bSAndy Fleming 663272cc70bSAndy Fleming /* Get the Card Status Register */ 664272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_EXT_CSD; 665272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 666272cc70bSAndy Fleming cmd.cmdarg = 0; 667272cc70bSAndy Fleming 668cdfd1ac6SYoshihiro Shimoda data.dest = (char *)ext_csd; 669272cc70bSAndy Fleming data.blocks = 1; 6708bfa195eSSimon Glass data.blocksize = MMC_MAX_BLOCK_LEN; 671272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 672272cc70bSAndy Fleming 673272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 674272cc70bSAndy Fleming 675272cc70bSAndy Fleming return err; 676272cc70bSAndy Fleming } 677272cc70bSAndy Fleming 678c40704f4SSimon Glass int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) 679272cc70bSAndy Fleming { 680272cc70bSAndy Fleming struct mmc_cmd cmd; 6815d4fc8d9SRaffaele Recalcati int timeout = 1000; 682a9003dc6SMaxime Ripard int retries = 3; 6835d4fc8d9SRaffaele Recalcati int ret; 684272cc70bSAndy Fleming 685272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SWITCH; 686272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 687272cc70bSAndy Fleming cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 688272cc70bSAndy Fleming (index << 16) | 689272cc70bSAndy Fleming (value << 8); 690272cc70bSAndy Fleming 691a9003dc6SMaxime Ripard while (retries > 0) { 6925d4fc8d9SRaffaele Recalcati ret = mmc_send_cmd(mmc, &cmd, NULL); 6935d4fc8d9SRaffaele Recalcati 6945d4fc8d9SRaffaele Recalcati /* Waiting for the ready status */ 695a9003dc6SMaxime Ripard if (!ret) { 69693ad0d18SJan Kloetzke ret = mmc_send_status(mmc, timeout); 697a9003dc6SMaxime Ripard return ret; 698a9003dc6SMaxime Ripard } 699a9003dc6SMaxime Ripard 700a9003dc6SMaxime Ripard retries--; 701a9003dc6SMaxime Ripard } 7025d4fc8d9SRaffaele Recalcati 7035d4fc8d9SRaffaele Recalcati return ret; 7045d4fc8d9SRaffaele Recalcati 705272cc70bSAndy Fleming } 706272cc70bSAndy Fleming 7073862b854SJean-Jacques Hiblot static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode) 708272cc70bSAndy Fleming { 709272cc70bSAndy Fleming int err; 7103862b854SJean-Jacques Hiblot int speed_bits; 7113862b854SJean-Jacques Hiblot 7123862b854SJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 7133862b854SJean-Jacques Hiblot 7143862b854SJean-Jacques Hiblot switch (mode) { 7153862b854SJean-Jacques Hiblot case MMC_HS: 7163862b854SJean-Jacques Hiblot case MMC_HS_52: 7173862b854SJean-Jacques Hiblot case MMC_DDR_52: 7183862b854SJean-Jacques Hiblot speed_bits = EXT_CSD_TIMING_HS; 719634d4849SKishon Vijay Abraham I break; 720634d4849SKishon Vijay Abraham I case MMC_HS_200: 721634d4849SKishon Vijay Abraham I speed_bits = EXT_CSD_TIMING_HS200; 722634d4849SKishon Vijay Abraham I break; 7233862b854SJean-Jacques Hiblot case MMC_LEGACY: 7243862b854SJean-Jacques Hiblot speed_bits = EXT_CSD_TIMING_LEGACY; 7253862b854SJean-Jacques Hiblot break; 7263862b854SJean-Jacques Hiblot default: 7273862b854SJean-Jacques Hiblot return -EINVAL; 7283862b854SJean-Jacques Hiblot } 7293862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 7303862b854SJean-Jacques Hiblot speed_bits); 7313862b854SJean-Jacques Hiblot if (err) 7323862b854SJean-Jacques Hiblot return err; 7333862b854SJean-Jacques Hiblot 7343862b854SJean-Jacques Hiblot if ((mode == MMC_HS) || (mode == MMC_HS_52)) { 7353862b854SJean-Jacques Hiblot /* Now check to see that it worked */ 7363862b854SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, test_csd); 7373862b854SJean-Jacques Hiblot if (err) 7383862b854SJean-Jacques Hiblot return err; 7393862b854SJean-Jacques Hiblot 7403862b854SJean-Jacques Hiblot /* No high-speed support */ 7413862b854SJean-Jacques Hiblot if (!test_csd[EXT_CSD_HS_TIMING]) 7423862b854SJean-Jacques Hiblot return -ENOTSUPP; 7433862b854SJean-Jacques Hiblot } 7443862b854SJean-Jacques Hiblot 7453862b854SJean-Jacques Hiblot return 0; 7463862b854SJean-Jacques Hiblot } 7473862b854SJean-Jacques Hiblot 7483862b854SJean-Jacques Hiblot static int mmc_get_capabilities(struct mmc *mmc) 7493862b854SJean-Jacques Hiblot { 7503862b854SJean-Jacques Hiblot u8 *ext_csd = mmc->ext_csd; 7513862b854SJean-Jacques Hiblot char cardtype; 752272cc70bSAndy Fleming 753d0c221feSJean-Jacques Hiblot mmc->card_caps = MMC_MODE_1BIT; 754272cc70bSAndy Fleming 755d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 756d52ebf10SThomas Chou return 0; 757d52ebf10SThomas Chou 758272cc70bSAndy Fleming /* Only version 4 supports high-speed */ 759272cc70bSAndy Fleming if (mmc->version < MMC_VERSION_4) 760272cc70bSAndy Fleming return 0; 761272cc70bSAndy Fleming 7623862b854SJean-Jacques Hiblot if (!ext_csd) { 7633862b854SJean-Jacques Hiblot printf("No ext_csd found!\n"); /* this should enver happen */ 7643862b854SJean-Jacques Hiblot return -ENOTSUPP; 7653862b854SJean-Jacques Hiblot } 7663862b854SJean-Jacques Hiblot 767fc5b32fbSAndrew Gabbasov mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; 768fc5b32fbSAndrew Gabbasov 769634d4849SKishon Vijay Abraham I cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0x3f; 770272cc70bSAndy Fleming 771634d4849SKishon Vijay Abraham I if (cardtype & (EXT_CSD_CARD_TYPE_HS200_1_2V | 772634d4849SKishon Vijay Abraham I EXT_CSD_CARD_TYPE_HS200_1_8V)) { 773634d4849SKishon Vijay Abraham I mmc->card_caps |= MMC_MODE_HS200; 774634d4849SKishon Vijay Abraham I } 775d22e3d46SJaehoon Chung if (cardtype & EXT_CSD_CARD_TYPE_52) { 7763862b854SJean-Jacques Hiblot if (cardtype & EXT_CSD_CARD_TYPE_DDR_52) 777d22e3d46SJaehoon Chung mmc->card_caps |= MMC_MODE_DDR_52MHz; 7783862b854SJean-Jacques Hiblot mmc->card_caps |= MMC_MODE_HS_52MHz; 779d22e3d46SJaehoon Chung } 7803862b854SJean-Jacques Hiblot if (cardtype & EXT_CSD_CARD_TYPE_26) 7813862b854SJean-Jacques Hiblot mmc->card_caps |= MMC_MODE_HS; 782272cc70bSAndy Fleming 783272cc70bSAndy Fleming return 0; 784272cc70bSAndy Fleming } 785272cc70bSAndy Fleming 786f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num) 787f866a46dSStephen Warren { 788f866a46dSStephen Warren switch (part_num) { 789f866a46dSStephen Warren case 0: 790f866a46dSStephen Warren mmc->capacity = mmc->capacity_user; 791f866a46dSStephen Warren break; 792f866a46dSStephen Warren case 1: 793f866a46dSStephen Warren case 2: 794f866a46dSStephen Warren mmc->capacity = mmc->capacity_boot; 795f866a46dSStephen Warren break; 796f866a46dSStephen Warren case 3: 797f866a46dSStephen Warren mmc->capacity = mmc->capacity_rpmb; 798f866a46dSStephen Warren break; 799f866a46dSStephen Warren case 4: 800f866a46dSStephen Warren case 5: 801f866a46dSStephen Warren case 6: 802f866a46dSStephen Warren case 7: 803f866a46dSStephen Warren mmc->capacity = mmc->capacity_gp[part_num - 4]; 804f866a46dSStephen Warren break; 805f866a46dSStephen Warren default: 806f866a46dSStephen Warren return -1; 807f866a46dSStephen Warren } 808f866a46dSStephen Warren 809c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len); 810f866a46dSStephen Warren 811f866a46dSStephen Warren return 0; 812f866a46dSStephen Warren } 813f866a46dSStephen Warren 81401298da3SJean-Jacques Hiblot static int mmc_boot_part_access_chk(struct mmc *mmc, unsigned int part_num) 81501298da3SJean-Jacques Hiblot { 81601298da3SJean-Jacques Hiblot int forbidden = 0; 81701298da3SJean-Jacques Hiblot bool change = false; 81801298da3SJean-Jacques Hiblot 81901298da3SJean-Jacques Hiblot if (part_num & PART_ACCESS_MASK) 82001298da3SJean-Jacques Hiblot forbidden = MMC_CAP(MMC_HS_200); 82101298da3SJean-Jacques Hiblot 82201298da3SJean-Jacques Hiblot if (MMC_CAP(mmc->selected_mode) & forbidden) { 82301298da3SJean-Jacques Hiblot debug("selected mode (%s) is forbidden for part %d\n", 82401298da3SJean-Jacques Hiblot mmc_mode_name(mmc->selected_mode), part_num); 82501298da3SJean-Jacques Hiblot change = true; 82601298da3SJean-Jacques Hiblot } else if (mmc->selected_mode != mmc->best_mode) { 82701298da3SJean-Jacques Hiblot debug("selected mode is not optimal\n"); 82801298da3SJean-Jacques Hiblot change = true; 82901298da3SJean-Jacques Hiblot } 83001298da3SJean-Jacques Hiblot 83101298da3SJean-Jacques Hiblot if (change) 83201298da3SJean-Jacques Hiblot return mmc_select_mode_and_width(mmc, 83301298da3SJean-Jacques Hiblot mmc->card_caps & ~forbidden); 83401298da3SJean-Jacques Hiblot 83501298da3SJean-Jacques Hiblot return 0; 83601298da3SJean-Jacques Hiblot } 83701298da3SJean-Jacques Hiblot 8387dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num) 839bc897b1dSLei Wen { 840f866a46dSStephen Warren int ret; 841bc897b1dSLei Wen 84201298da3SJean-Jacques Hiblot ret = mmc_boot_part_access_chk(mmc, part_num); 84301298da3SJean-Jacques Hiblot if (ret) 84401298da3SJean-Jacques Hiblot return ret; 84501298da3SJean-Jacques Hiblot 846f866a46dSStephen Warren ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 847bc897b1dSLei Wen (mmc->part_config & ~PART_ACCESS_MASK) 848bc897b1dSLei Wen | (part_num & PART_ACCESS_MASK)); 849f866a46dSStephen Warren 8506dc93e70SPeter Bigot /* 8516dc93e70SPeter Bigot * Set the capacity if the switch succeeded or was intended 8526dc93e70SPeter Bigot * to return to representing the raw device. 8536dc93e70SPeter Bigot */ 854873cc1d7SStephen Warren if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) { 8556dc93e70SPeter Bigot ret = mmc_set_capacity(mmc, part_num); 856fdbb139fSSimon Glass mmc_get_blk_desc(mmc)->hwpart = part_num; 857873cc1d7SStephen Warren } 8586dc93e70SPeter Bigot 8596dc93e70SPeter Bigot return ret; 860bc897b1dSLei Wen } 861bc897b1dSLei Wen 862ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc, 863ac9da0e0SDiego Santa Cruz const struct mmc_hwpart_conf *conf, 864ac9da0e0SDiego Santa Cruz enum mmc_hwpart_conf_mode mode) 865ac9da0e0SDiego Santa Cruz { 866ac9da0e0SDiego Santa Cruz u8 part_attrs = 0; 867ac9da0e0SDiego Santa Cruz u32 enh_size_mult; 868ac9da0e0SDiego Santa Cruz u32 enh_start_addr; 869ac9da0e0SDiego Santa Cruz u32 gp_size_mult[4]; 870ac9da0e0SDiego Santa Cruz u32 max_enh_size_mult; 871ac9da0e0SDiego Santa Cruz u32 tot_enh_size_mult = 0; 8728dda5b0eSDiego Santa Cruz u8 wr_rel_set; 873ac9da0e0SDiego Santa Cruz int i, pidx, err; 874ac9da0e0SDiego Santa Cruz ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 875ac9da0e0SDiego Santa Cruz 876ac9da0e0SDiego Santa Cruz if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE) 877ac9da0e0SDiego Santa Cruz return -EINVAL; 878ac9da0e0SDiego Santa Cruz 879ac9da0e0SDiego Santa Cruz if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) { 880ac9da0e0SDiego Santa Cruz printf("eMMC >= 4.4 required for enhanced user data area\n"); 881ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 882ac9da0e0SDiego Santa Cruz } 883ac9da0e0SDiego Santa Cruz 884ac9da0e0SDiego Santa Cruz if (!(mmc->part_support & PART_SUPPORT)) { 885ac9da0e0SDiego Santa Cruz printf("Card does not support partitioning\n"); 886ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 887ac9da0e0SDiego Santa Cruz } 888ac9da0e0SDiego Santa Cruz 889ac9da0e0SDiego Santa Cruz if (!mmc->hc_wp_grp_size) { 890ac9da0e0SDiego Santa Cruz printf("Card does not define HC WP group size\n"); 891ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 892ac9da0e0SDiego Santa Cruz } 893ac9da0e0SDiego Santa Cruz 894ac9da0e0SDiego Santa Cruz /* check partition alignment and total enhanced size */ 895ac9da0e0SDiego Santa Cruz if (conf->user.enh_size) { 896ac9da0e0SDiego Santa Cruz if (conf->user.enh_size % mmc->hc_wp_grp_size || 897ac9da0e0SDiego Santa Cruz conf->user.enh_start % mmc->hc_wp_grp_size) { 898ac9da0e0SDiego Santa Cruz printf("User data enhanced area not HC WP group " 899ac9da0e0SDiego Santa Cruz "size aligned\n"); 900ac9da0e0SDiego Santa Cruz return -EINVAL; 901ac9da0e0SDiego Santa Cruz } 902ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_USR; 903ac9da0e0SDiego Santa Cruz enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size; 904ac9da0e0SDiego Santa Cruz if (mmc->high_capacity) { 905ac9da0e0SDiego Santa Cruz enh_start_addr = conf->user.enh_start; 906ac9da0e0SDiego Santa Cruz } else { 907ac9da0e0SDiego Santa Cruz enh_start_addr = (conf->user.enh_start << 9); 908ac9da0e0SDiego Santa Cruz } 909ac9da0e0SDiego Santa Cruz } else { 910ac9da0e0SDiego Santa Cruz enh_size_mult = 0; 911ac9da0e0SDiego Santa Cruz enh_start_addr = 0; 912ac9da0e0SDiego Santa Cruz } 913ac9da0e0SDiego Santa Cruz tot_enh_size_mult += enh_size_mult; 914ac9da0e0SDiego Santa Cruz 915ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 916ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) { 917ac9da0e0SDiego Santa Cruz printf("GP%i partition not HC WP group size " 918ac9da0e0SDiego Santa Cruz "aligned\n", pidx+1); 919ac9da0e0SDiego Santa Cruz return -EINVAL; 920ac9da0e0SDiego Santa Cruz } 921ac9da0e0SDiego Santa Cruz gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size; 922ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) { 923ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_GP(pidx); 924ac9da0e0SDiego Santa Cruz tot_enh_size_mult += gp_size_mult[pidx]; 925ac9da0e0SDiego Santa Cruz } 926ac9da0e0SDiego Santa Cruz } 927ac9da0e0SDiego Santa Cruz 928ac9da0e0SDiego Santa Cruz if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) { 929ac9da0e0SDiego Santa Cruz printf("Card does not support enhanced attribute\n"); 930ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 931ac9da0e0SDiego Santa Cruz } 932ac9da0e0SDiego Santa Cruz 933ac9da0e0SDiego Santa Cruz err = mmc_send_ext_csd(mmc, ext_csd); 934ac9da0e0SDiego Santa Cruz if (err) 935ac9da0e0SDiego Santa Cruz return err; 936ac9da0e0SDiego Santa Cruz 937ac9da0e0SDiego Santa Cruz max_enh_size_mult = 938ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) + 939ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) + 940ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]; 941ac9da0e0SDiego Santa Cruz if (tot_enh_size_mult > max_enh_size_mult) { 942ac9da0e0SDiego Santa Cruz printf("Total enhanced size exceeds maximum (%u > %u)\n", 943ac9da0e0SDiego Santa Cruz tot_enh_size_mult, max_enh_size_mult); 944ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 945ac9da0e0SDiego Santa Cruz } 946ac9da0e0SDiego Santa Cruz 9478dda5b0eSDiego Santa Cruz /* The default value of EXT_CSD_WR_REL_SET is device 9488dda5b0eSDiego Santa Cruz * dependent, the values can only be changed if the 9498dda5b0eSDiego Santa Cruz * EXT_CSD_HS_CTRL_REL bit is set. The values can be 9508dda5b0eSDiego Santa Cruz * changed only once and before partitioning is completed. */ 9518dda5b0eSDiego Santa Cruz wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 9528dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_change) { 9538dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_set) 9548dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_USR; 9558dda5b0eSDiego Santa Cruz else 9568dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR; 9578dda5b0eSDiego Santa Cruz } 9588dda5b0eSDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 9598dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_change) { 9608dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_set) 9618dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx); 9628dda5b0eSDiego Santa Cruz else 9638dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx); 9648dda5b0eSDiego Santa Cruz } 9658dda5b0eSDiego Santa Cruz } 9668dda5b0eSDiego Santa Cruz 9678dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] && 9688dda5b0eSDiego Santa Cruz !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) { 9698dda5b0eSDiego Santa Cruz puts("Card does not support host controlled partition write " 9708dda5b0eSDiego Santa Cruz "reliability settings\n"); 9718dda5b0eSDiego Santa Cruz return -EMEDIUMTYPE; 9728dda5b0eSDiego Santa Cruz } 9738dda5b0eSDiego Santa Cruz 974ac9da0e0SDiego Santa Cruz if (ext_csd[EXT_CSD_PARTITION_SETTING] & 975ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED) { 976ac9da0e0SDiego Santa Cruz printf("Card already partitioned\n"); 977ac9da0e0SDiego Santa Cruz return -EPERM; 978ac9da0e0SDiego Santa Cruz } 979ac9da0e0SDiego Santa Cruz 980ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_CHECK) 981ac9da0e0SDiego Santa Cruz return 0; 982ac9da0e0SDiego Santa Cruz 983ac9da0e0SDiego Santa Cruz /* Partitioning requires high-capacity size definitions */ 984ac9da0e0SDiego Santa Cruz if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) { 985ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 986ac9da0e0SDiego Santa Cruz EXT_CSD_ERASE_GROUP_DEF, 1); 987ac9da0e0SDiego Santa Cruz 988ac9da0e0SDiego Santa Cruz if (err) 989ac9da0e0SDiego Santa Cruz return err; 990ac9da0e0SDiego Santa Cruz 991ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 992ac9da0e0SDiego Santa Cruz 993ac9da0e0SDiego Santa Cruz /* update erase group size to be high-capacity */ 994ac9da0e0SDiego Santa Cruz mmc->erase_grp_size = 995ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 996ac9da0e0SDiego Santa Cruz 997ac9da0e0SDiego Santa Cruz } 998ac9da0e0SDiego Santa Cruz 999ac9da0e0SDiego Santa Cruz /* all OK, write the configuration */ 1000ac9da0e0SDiego Santa Cruz for (i = 0; i < 4; i++) { 1001ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1002ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_START_ADDR+i, 1003ac9da0e0SDiego Santa Cruz (enh_start_addr >> (i*8)) & 0xFF); 1004ac9da0e0SDiego Santa Cruz if (err) 1005ac9da0e0SDiego Santa Cruz return err; 1006ac9da0e0SDiego Santa Cruz } 1007ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 1008ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1009ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_SIZE_MULT+i, 1010ac9da0e0SDiego Santa Cruz (enh_size_mult >> (i*8)) & 0xFF); 1011ac9da0e0SDiego Santa Cruz if (err) 1012ac9da0e0SDiego Santa Cruz return err; 1013ac9da0e0SDiego Santa Cruz } 1014ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 1015ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 1016ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1017ac9da0e0SDiego Santa Cruz EXT_CSD_GP_SIZE_MULT+pidx*3+i, 1018ac9da0e0SDiego Santa Cruz (gp_size_mult[pidx] >> (i*8)) & 0xFF); 1019ac9da0e0SDiego Santa Cruz if (err) 1020ac9da0e0SDiego Santa Cruz return err; 1021ac9da0e0SDiego Santa Cruz } 1022ac9da0e0SDiego Santa Cruz } 1023ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1024ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs); 1025ac9da0e0SDiego Santa Cruz if (err) 1026ac9da0e0SDiego Santa Cruz return err; 1027ac9da0e0SDiego Santa Cruz 1028ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_SET) 1029ac9da0e0SDiego Santa Cruz return 0; 1030ac9da0e0SDiego Santa Cruz 10318dda5b0eSDiego Santa Cruz /* The WR_REL_SET is a write-once register but shall be 10328dda5b0eSDiego Santa Cruz * written before setting PART_SETTING_COMPLETED. As it is 10338dda5b0eSDiego Santa Cruz * write-once we can only write it when completing the 10348dda5b0eSDiego Santa Cruz * partitioning. */ 10358dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) { 10368dda5b0eSDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 10378dda5b0eSDiego Santa Cruz EXT_CSD_WR_REL_SET, wr_rel_set); 10388dda5b0eSDiego Santa Cruz if (err) 10398dda5b0eSDiego Santa Cruz return err; 10408dda5b0eSDiego Santa Cruz } 10418dda5b0eSDiego Santa Cruz 1042ac9da0e0SDiego Santa Cruz /* Setting PART_SETTING_COMPLETED confirms the partition 1043ac9da0e0SDiego Santa Cruz * configuration but it only becomes effective after power 1044ac9da0e0SDiego Santa Cruz * cycle, so we do not adjust the partition related settings 1045ac9da0e0SDiego Santa Cruz * in the mmc struct. */ 1046ac9da0e0SDiego Santa Cruz 1047ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1048ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING, 1049ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 1050ac9da0e0SDiego Santa Cruz if (err) 1051ac9da0e0SDiego Santa Cruz return err; 1052ac9da0e0SDiego Santa Cruz 1053ac9da0e0SDiego Santa Cruz return 0; 1054ac9da0e0SDiego Santa Cruz } 1055ac9da0e0SDiego Santa Cruz 1056e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 105748972d90SThierry Reding int mmc_getcd(struct mmc *mmc) 105848972d90SThierry Reding { 105948972d90SThierry Reding int cd; 106048972d90SThierry Reding 106148972d90SThierry Reding cd = board_mmc_getcd(mmc); 106248972d90SThierry Reding 1063d4e1da4eSPeter Korsgaard if (cd < 0) { 106493bfd616SPantelis Antoniou if (mmc->cfg->ops->getcd) 106593bfd616SPantelis Antoniou cd = mmc->cfg->ops->getcd(mmc); 1066d4e1da4eSPeter Korsgaard else 1067d4e1da4eSPeter Korsgaard cd = 1; 1068d4e1da4eSPeter Korsgaard } 106948972d90SThierry Reding 107048972d90SThierry Reding return cd; 107148972d90SThierry Reding } 10728ca51e51SSimon Glass #endif 107348972d90SThierry Reding 1074fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) 1075272cc70bSAndy Fleming { 1076272cc70bSAndy Fleming struct mmc_cmd cmd; 1077272cc70bSAndy Fleming struct mmc_data data; 1078272cc70bSAndy Fleming 1079272cc70bSAndy Fleming /* Switch the frequency */ 1080272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC; 1081272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1082272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff; 1083272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4)); 1084272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4); 1085272cc70bSAndy Fleming 1086272cc70bSAndy Fleming data.dest = (char *)resp; 1087272cc70bSAndy Fleming data.blocksize = 64; 1088272cc70bSAndy Fleming data.blocks = 1; 1089272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1090272cc70bSAndy Fleming 1091272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 1092272cc70bSAndy Fleming } 1093272cc70bSAndy Fleming 1094272cc70bSAndy Fleming 1095d0c221feSJean-Jacques Hiblot static int sd_get_capabilities(struct mmc *mmc) 1096272cc70bSAndy Fleming { 1097272cc70bSAndy Fleming int err; 1098272cc70bSAndy Fleming struct mmc_cmd cmd; 109918e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2); 110018e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16); 1101272cc70bSAndy Fleming struct mmc_data data; 1102272cc70bSAndy Fleming int timeout; 1103c10b85d6SJean-Jacques Hiblot u32 sd3_bus_mode; 1104272cc70bSAndy Fleming 1105d0c221feSJean-Jacques Hiblot mmc->card_caps = MMC_MODE_1BIT; 1106272cc70bSAndy Fleming 1107d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 1108d52ebf10SThomas Chou return 0; 1109d52ebf10SThomas Chou 1110272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */ 1111272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 1112272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1113272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1114272cc70bSAndy Fleming 1115272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1116272cc70bSAndy Fleming 1117272cc70bSAndy Fleming if (err) 1118272cc70bSAndy Fleming return err; 1119272cc70bSAndy Fleming 1120272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR; 1121272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1122272cc70bSAndy Fleming cmd.cmdarg = 0; 1123272cc70bSAndy Fleming 1124272cc70bSAndy Fleming timeout = 3; 1125272cc70bSAndy Fleming 1126272cc70bSAndy Fleming retry_scr: 1127f781dd38SAnton staaf data.dest = (char *)scr; 1128272cc70bSAndy Fleming data.blocksize = 8; 1129272cc70bSAndy Fleming data.blocks = 1; 1130272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1131272cc70bSAndy Fleming 1132272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 1133272cc70bSAndy Fleming 1134272cc70bSAndy Fleming if (err) { 1135272cc70bSAndy Fleming if (timeout--) 1136272cc70bSAndy Fleming goto retry_scr; 1137272cc70bSAndy Fleming 1138272cc70bSAndy Fleming return err; 1139272cc70bSAndy Fleming } 1140272cc70bSAndy Fleming 11414e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]); 11424e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]); 1143272cc70bSAndy Fleming 1144272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) { 1145272cc70bSAndy Fleming case 0: 1146272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1147272cc70bSAndy Fleming break; 1148272cc70bSAndy Fleming case 1: 1149272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10; 1150272cc70bSAndy Fleming break; 1151272cc70bSAndy Fleming case 2: 1152272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 11531741c64dSJaehoon Chung if ((mmc->scr[0] >> 15) & 0x1) 11541741c64dSJaehoon Chung mmc->version = SD_VERSION_3; 1155272cc70bSAndy Fleming break; 1156272cc70bSAndy Fleming default: 1157272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1158272cc70bSAndy Fleming break; 1159272cc70bSAndy Fleming } 1160272cc70bSAndy Fleming 1161b44c7083SAlagu Sankar if (mmc->scr[0] & SD_DATA_4BIT) 1162b44c7083SAlagu Sankar mmc->card_caps |= MMC_MODE_4BIT; 1163b44c7083SAlagu Sankar 1164272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */ 1165272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0) 1166272cc70bSAndy Fleming return 0; 1167272cc70bSAndy Fleming 1168272cc70bSAndy Fleming timeout = 4; 1169272cc70bSAndy Fleming while (timeout--) { 1170272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, 1171f781dd38SAnton staaf (u8 *)switch_status); 1172272cc70bSAndy Fleming 1173272cc70bSAndy Fleming if (err) 1174272cc70bSAndy Fleming return err; 1175272cc70bSAndy Fleming 1176272cc70bSAndy Fleming /* The high-speed function is busy. Try again */ 11774e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) 1178272cc70bSAndy Fleming break; 1179272cc70bSAndy Fleming } 1180272cc70bSAndy Fleming 1181272cc70bSAndy Fleming /* If high-speed isn't supported, we return */ 1182d0c221feSJean-Jacques Hiblot if (__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED) 1183d0c221feSJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(SD_HS); 1184272cc70bSAndy Fleming 1185c10b85d6SJean-Jacques Hiblot /* Version before 3.0 don't support UHS modes */ 1186c10b85d6SJean-Jacques Hiblot if (mmc->version < SD_VERSION_3) 1187c10b85d6SJean-Jacques Hiblot return 0; 1188c10b85d6SJean-Jacques Hiblot 1189c10b85d6SJean-Jacques Hiblot sd3_bus_mode = __be32_to_cpu(switch_status[3]) >> 16 & 0x1f; 1190c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR104) 1191c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR104); 1192c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR50) 1193c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR50); 1194c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR25) 1195c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR25); 1196c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR12) 1197c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR12); 1198c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_DDR50) 1199c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_DDR50); 1200c10b85d6SJean-Jacques Hiblot 12012c3fbf4cSMacpaul Lin return 0; 1202d0c221feSJean-Jacques Hiblot } 1203d0c221feSJean-Jacques Hiblot 1204d0c221feSJean-Jacques Hiblot static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode) 1205d0c221feSJean-Jacques Hiblot { 1206d0c221feSJean-Jacques Hiblot int err; 1207d0c221feSJean-Jacques Hiblot 1208d0c221feSJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16); 1209c10b85d6SJean-Jacques Hiblot int speed; 12102c3fbf4cSMacpaul Lin 1211c10b85d6SJean-Jacques Hiblot switch (mode) { 1212c10b85d6SJean-Jacques Hiblot case SD_LEGACY: 1213c10b85d6SJean-Jacques Hiblot case UHS_SDR12: 1214c10b85d6SJean-Jacques Hiblot speed = UHS_SDR12_BUS_SPEED; 1215c10b85d6SJean-Jacques Hiblot break; 1216c10b85d6SJean-Jacques Hiblot case SD_HS: 1217c10b85d6SJean-Jacques Hiblot case UHS_SDR25: 1218c10b85d6SJean-Jacques Hiblot speed = UHS_SDR25_BUS_SPEED; 1219c10b85d6SJean-Jacques Hiblot break; 1220c10b85d6SJean-Jacques Hiblot case UHS_SDR50: 1221c10b85d6SJean-Jacques Hiblot speed = UHS_SDR50_BUS_SPEED; 1222c10b85d6SJean-Jacques Hiblot break; 1223c10b85d6SJean-Jacques Hiblot case UHS_DDR50: 1224c10b85d6SJean-Jacques Hiblot speed = UHS_DDR50_BUS_SPEED; 1225c10b85d6SJean-Jacques Hiblot break; 1226c10b85d6SJean-Jacques Hiblot case UHS_SDR104: 1227c10b85d6SJean-Jacques Hiblot speed = UHS_SDR104_BUS_SPEED; 1228c10b85d6SJean-Jacques Hiblot break; 1229c10b85d6SJean-Jacques Hiblot default: 1230c10b85d6SJean-Jacques Hiblot return -EINVAL; 1231c10b85d6SJean-Jacques Hiblot } 1232c10b85d6SJean-Jacques Hiblot 1233c10b85d6SJean-Jacques Hiblot err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, speed, (u8 *)switch_status); 1234272cc70bSAndy Fleming if (err) 1235272cc70bSAndy Fleming return err; 1236272cc70bSAndy Fleming 1237c10b85d6SJean-Jacques Hiblot if ((__be32_to_cpu(switch_status[4]) >> 24) != speed) 1238d0c221feSJean-Jacques Hiblot return -ENOTSUPP; 1239d0c221feSJean-Jacques Hiblot 1240d0c221feSJean-Jacques Hiblot return 0; 1241d0c221feSJean-Jacques Hiblot } 1242d0c221feSJean-Jacques Hiblot 1243d0c221feSJean-Jacques Hiblot int sd_select_bus_width(struct mmc *mmc, int w) 1244d0c221feSJean-Jacques Hiblot { 1245d0c221feSJean-Jacques Hiblot int err; 1246d0c221feSJean-Jacques Hiblot struct mmc_cmd cmd; 1247d0c221feSJean-Jacques Hiblot 1248d0c221feSJean-Jacques Hiblot if ((w != 4) && (w != 1)) 1249d0c221feSJean-Jacques Hiblot return -EINVAL; 1250d0c221feSJean-Jacques Hiblot 1251d0c221feSJean-Jacques Hiblot cmd.cmdidx = MMC_CMD_APP_CMD; 1252d0c221feSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 1253d0c221feSJean-Jacques Hiblot cmd.cmdarg = mmc->rca << 16; 1254d0c221feSJean-Jacques Hiblot 1255d0c221feSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 1256d0c221feSJean-Jacques Hiblot if (err) 1257d0c221feSJean-Jacques Hiblot return err; 1258d0c221feSJean-Jacques Hiblot 1259d0c221feSJean-Jacques Hiblot cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; 1260d0c221feSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 1261d0c221feSJean-Jacques Hiblot if (w == 4) 1262d0c221feSJean-Jacques Hiblot cmd.cmdarg = 2; 1263d0c221feSJean-Jacques Hiblot else if (w == 1) 1264d0c221feSJean-Jacques Hiblot cmd.cmdarg = 0; 1265d0c221feSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 1266d0c221feSJean-Jacques Hiblot if (err) 1267d0c221feSJean-Jacques Hiblot return err; 1268272cc70bSAndy Fleming 1269272cc70bSAndy Fleming return 0; 1270272cc70bSAndy Fleming } 1271272cc70bSAndy Fleming 12723697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc) 12733697e599SPeng Fan { 12743697e599SPeng Fan int err, i; 12753697e599SPeng Fan struct mmc_cmd cmd; 12763697e599SPeng Fan ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16); 12773697e599SPeng Fan struct mmc_data data; 12783697e599SPeng Fan int timeout = 3; 12793697e599SPeng Fan unsigned int au, eo, et, es; 12803697e599SPeng Fan 12813697e599SPeng Fan cmd.cmdidx = MMC_CMD_APP_CMD; 12823697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 12833697e599SPeng Fan cmd.cmdarg = mmc->rca << 16; 12843697e599SPeng Fan 12853697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, NULL); 12863697e599SPeng Fan if (err) 12873697e599SPeng Fan return err; 12883697e599SPeng Fan 12893697e599SPeng Fan cmd.cmdidx = SD_CMD_APP_SD_STATUS; 12903697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 12913697e599SPeng Fan cmd.cmdarg = 0; 12923697e599SPeng Fan 12933697e599SPeng Fan retry_ssr: 12943697e599SPeng Fan data.dest = (char *)ssr; 12953697e599SPeng Fan data.blocksize = 64; 12963697e599SPeng Fan data.blocks = 1; 12973697e599SPeng Fan data.flags = MMC_DATA_READ; 12983697e599SPeng Fan 12993697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, &data); 13003697e599SPeng Fan if (err) { 13013697e599SPeng Fan if (timeout--) 13023697e599SPeng Fan goto retry_ssr; 13033697e599SPeng Fan 13043697e599SPeng Fan return err; 13053697e599SPeng Fan } 13063697e599SPeng Fan 13073697e599SPeng Fan for (i = 0; i < 16; i++) 13083697e599SPeng Fan ssr[i] = be32_to_cpu(ssr[i]); 13093697e599SPeng Fan 13103697e599SPeng Fan au = (ssr[2] >> 12) & 0xF; 13113697e599SPeng Fan if ((au <= 9) || (mmc->version == SD_VERSION_3)) { 13123697e599SPeng Fan mmc->ssr.au = sd_au_size[au]; 13133697e599SPeng Fan es = (ssr[3] >> 24) & 0xFF; 13143697e599SPeng Fan es |= (ssr[2] & 0xFF) << 8; 13153697e599SPeng Fan et = (ssr[3] >> 18) & 0x3F; 13163697e599SPeng Fan if (es && et) { 13173697e599SPeng Fan eo = (ssr[3] >> 16) & 0x3; 13183697e599SPeng Fan mmc->ssr.erase_timeout = (et * 1000) / es; 13193697e599SPeng Fan mmc->ssr.erase_offset = eo * 1000; 13203697e599SPeng Fan } 13213697e599SPeng Fan } else { 13223697e599SPeng Fan debug("Invalid Allocation Unit Size.\n"); 13233697e599SPeng Fan } 13243697e599SPeng Fan 13253697e599SPeng Fan return 0; 13263697e599SPeng Fan } 13273697e599SPeng Fan 1328272cc70bSAndy Fleming /* frequency bases */ 1329272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */ 13305f837c2cSMike Frysinger static const int fbase[] = { 1331272cc70bSAndy Fleming 10000, 1332272cc70bSAndy Fleming 100000, 1333272cc70bSAndy Fleming 1000000, 1334272cc70bSAndy Fleming 10000000, 1335272cc70bSAndy Fleming }; 1336272cc70bSAndy Fleming 1337272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice 1338272cc70bSAndy Fleming * to platforms without floating point. 1339272cc70bSAndy Fleming */ 134061fe076fSSimon Glass static const u8 multipliers[] = { 1341272cc70bSAndy Fleming 0, /* reserved */ 1342272cc70bSAndy Fleming 10, 1343272cc70bSAndy Fleming 12, 1344272cc70bSAndy Fleming 13, 1345272cc70bSAndy Fleming 15, 1346272cc70bSAndy Fleming 20, 1347272cc70bSAndy Fleming 25, 1348272cc70bSAndy Fleming 30, 1349272cc70bSAndy Fleming 35, 1350272cc70bSAndy Fleming 40, 1351272cc70bSAndy Fleming 45, 1352272cc70bSAndy Fleming 50, 1353272cc70bSAndy Fleming 55, 1354272cc70bSAndy Fleming 60, 1355272cc70bSAndy Fleming 70, 1356272cc70bSAndy Fleming 80, 1357272cc70bSAndy Fleming }; 1358272cc70bSAndy Fleming 1359d0c221feSJean-Jacques Hiblot static inline int bus_width(uint cap) 1360d0c221feSJean-Jacques Hiblot { 1361d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_8BIT) 1362d0c221feSJean-Jacques Hiblot return 8; 1363d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_4BIT) 1364d0c221feSJean-Jacques Hiblot return 4; 1365d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_1BIT) 1366d0c221feSJean-Jacques Hiblot return 1; 1367d0c221feSJean-Jacques Hiblot printf("invalid bus witdh capability 0x%x\n", cap); 1368d0c221feSJean-Jacques Hiblot return 0; 1369d0c221feSJean-Jacques Hiblot } 1370d0c221feSJean-Jacques Hiblot 1371e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 1372ec841209SKishon Vijay Abraham I static int mmc_execute_tuning(struct mmc *mmc, uint opcode) 1373ec841209SKishon Vijay Abraham I { 1374ec841209SKishon Vijay Abraham I return -ENOTSUPP; 1375ec841209SKishon Vijay Abraham I } 1376ec841209SKishon Vijay Abraham I 1377318a7a57SJean-Jacques Hiblot static void mmc_send_init_stream(struct mmc *mmc) 1378318a7a57SJean-Jacques Hiblot { 1379318a7a57SJean-Jacques Hiblot } 1380318a7a57SJean-Jacques Hiblot 13812a4d212fSKishon Vijay Abraham I static int mmc_set_ios(struct mmc *mmc) 1382272cc70bSAndy Fleming { 13832a4d212fSKishon Vijay Abraham I int ret = 0; 13842a4d212fSKishon Vijay Abraham I 138593bfd616SPantelis Antoniou if (mmc->cfg->ops->set_ios) 13862a4d212fSKishon Vijay Abraham I ret = mmc->cfg->ops->set_ios(mmc); 13872a4d212fSKishon Vijay Abraham I 13882a4d212fSKishon Vijay Abraham I return ret; 1389272cc70bSAndy Fleming } 13908ca51e51SSimon Glass #endif 1391272cc70bSAndy Fleming 139235f67820SKishon Vijay Abraham I int mmc_set_clock(struct mmc *mmc, uint clock, bool disable) 1393272cc70bSAndy Fleming { 139493bfd616SPantelis Antoniou if (clock > mmc->cfg->f_max) 139593bfd616SPantelis Antoniou clock = mmc->cfg->f_max; 1396272cc70bSAndy Fleming 139793bfd616SPantelis Antoniou if (clock < mmc->cfg->f_min) 139893bfd616SPantelis Antoniou clock = mmc->cfg->f_min; 1399272cc70bSAndy Fleming 1400272cc70bSAndy Fleming mmc->clock = clock; 140135f67820SKishon Vijay Abraham I mmc->clk_disable = disable; 1402272cc70bSAndy Fleming 14032a4d212fSKishon Vijay Abraham I return mmc_set_ios(mmc); 1404272cc70bSAndy Fleming } 1405272cc70bSAndy Fleming 14062a4d212fSKishon Vijay Abraham I static int mmc_set_bus_width(struct mmc *mmc, uint width) 1407272cc70bSAndy Fleming { 1408272cc70bSAndy Fleming mmc->bus_width = width; 1409272cc70bSAndy Fleming 14102a4d212fSKishon Vijay Abraham I return mmc_set_ios(mmc); 1411272cc70bSAndy Fleming } 1412272cc70bSAndy Fleming 14134c9d2aaaSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG) 14144c9d2aaaSJean-Jacques Hiblot /* 14154c9d2aaaSJean-Jacques Hiblot * helper function to display the capabilities in a human 14164c9d2aaaSJean-Jacques Hiblot * friendly manner. The capabilities include bus width and 14174c9d2aaaSJean-Jacques Hiblot * supported modes. 14184c9d2aaaSJean-Jacques Hiblot */ 14194c9d2aaaSJean-Jacques Hiblot void mmc_dump_capabilities(const char *text, uint caps) 14204c9d2aaaSJean-Jacques Hiblot { 14214c9d2aaaSJean-Jacques Hiblot enum bus_mode mode; 14224c9d2aaaSJean-Jacques Hiblot 14234c9d2aaaSJean-Jacques Hiblot printf("%s: widths [", text); 14244c9d2aaaSJean-Jacques Hiblot if (caps & MMC_MODE_8BIT) 14254c9d2aaaSJean-Jacques Hiblot printf("8, "); 14264c9d2aaaSJean-Jacques Hiblot if (caps & MMC_MODE_4BIT) 14274c9d2aaaSJean-Jacques Hiblot printf("4, "); 1428d0c221feSJean-Jacques Hiblot if (caps & MMC_MODE_1BIT) 1429d0c221feSJean-Jacques Hiblot printf("1, "); 1430d0c221feSJean-Jacques Hiblot printf("\b\b] modes ["); 14314c9d2aaaSJean-Jacques Hiblot for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++) 14324c9d2aaaSJean-Jacques Hiblot if (MMC_CAP(mode) & caps) 14334c9d2aaaSJean-Jacques Hiblot printf("%s, ", mmc_mode_name(mode)); 14344c9d2aaaSJean-Jacques Hiblot printf("\b\b]\n"); 14354c9d2aaaSJean-Jacques Hiblot } 14364c9d2aaaSJean-Jacques Hiblot #endif 14374c9d2aaaSJean-Jacques Hiblot 1438d0c221feSJean-Jacques Hiblot struct mode_width_tuning { 1439d0c221feSJean-Jacques Hiblot enum bus_mode mode; 1440d0c221feSJean-Jacques Hiblot uint widths; 1441634d4849SKishon Vijay Abraham I uint tuning; 1442d0c221feSJean-Jacques Hiblot }; 1443d0c221feSJean-Jacques Hiblot 1444aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage) 1445aff5d3c8SKishon Vijay Abraham I { 1446aff5d3c8SKishon Vijay Abraham I mmc->signal_voltage = signal_voltage; 1447aff5d3c8SKishon Vijay Abraham I return mmc_set_ios(mmc); 1448aff5d3c8SKishon Vijay Abraham I } 1449aff5d3c8SKishon Vijay Abraham I 1450d0c221feSJean-Jacques Hiblot static const struct mode_width_tuning sd_modes_by_pref[] = { 1451d0c221feSJean-Jacques Hiblot { 1452c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR104, 1453c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1454c10b85d6SJean-Jacques Hiblot .tuning = MMC_CMD_SEND_TUNING_BLOCK 1455c10b85d6SJean-Jacques Hiblot }, 1456c10b85d6SJean-Jacques Hiblot { 1457c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR50, 1458c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1459c10b85d6SJean-Jacques Hiblot }, 1460c10b85d6SJean-Jacques Hiblot { 1461c10b85d6SJean-Jacques Hiblot .mode = UHS_DDR50, 1462c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1463c10b85d6SJean-Jacques Hiblot }, 1464c10b85d6SJean-Jacques Hiblot { 1465c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR25, 1466c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1467c10b85d6SJean-Jacques Hiblot }, 1468c10b85d6SJean-Jacques Hiblot { 1469d0c221feSJean-Jacques Hiblot .mode = SD_HS, 1470d0c221feSJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1471d0c221feSJean-Jacques Hiblot }, 1472d0c221feSJean-Jacques Hiblot { 1473c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR12, 1474c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1475c10b85d6SJean-Jacques Hiblot }, 1476c10b85d6SJean-Jacques Hiblot { 1477d0c221feSJean-Jacques Hiblot .mode = SD_LEGACY, 1478d0c221feSJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1479d0c221feSJean-Jacques Hiblot } 1480d0c221feSJean-Jacques Hiblot }; 1481d0c221feSJean-Jacques Hiblot 1482d0c221feSJean-Jacques Hiblot #define for_each_sd_mode_by_pref(caps, mwt) \ 1483d0c221feSJean-Jacques Hiblot for (mwt = sd_modes_by_pref;\ 1484d0c221feSJean-Jacques Hiblot mwt < sd_modes_by_pref + ARRAY_SIZE(sd_modes_by_pref);\ 1485d0c221feSJean-Jacques Hiblot mwt++) \ 1486d0c221feSJean-Jacques Hiblot if (caps & MMC_CAP(mwt->mode)) 1487d0c221feSJean-Jacques Hiblot 148801298da3SJean-Jacques Hiblot static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps) 14898ac8a263SJean-Jacques Hiblot { 14908ac8a263SJean-Jacques Hiblot int err; 1491d0c221feSJean-Jacques Hiblot uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT}; 1492d0c221feSJean-Jacques Hiblot const struct mode_width_tuning *mwt; 1493c10b85d6SJean-Jacques Hiblot bool uhs_en = (mmc->ocr & OCR_S18R) ? true : false; 1494c10b85d6SJean-Jacques Hiblot uint caps; 1495c10b85d6SJean-Jacques Hiblot 14968ac8a263SJean-Jacques Hiblot 14978ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */ 149801298da3SJean-Jacques Hiblot caps = card_caps & (mmc->host_caps | MMC_MODE_1BIT); 14998ac8a263SJean-Jacques Hiblot 1500c10b85d6SJean-Jacques Hiblot if (!uhs_en) 1501c10b85d6SJean-Jacques Hiblot caps &= ~UHS_CAPS; 1502c10b85d6SJean-Jacques Hiblot 1503c10b85d6SJean-Jacques Hiblot for_each_sd_mode_by_pref(caps, mwt) { 1504d0c221feSJean-Jacques Hiblot uint *w; 15058ac8a263SJean-Jacques Hiblot 1506d0c221feSJean-Jacques Hiblot for (w = widths; w < widths + ARRAY_SIZE(widths); w++) { 1507c10b85d6SJean-Jacques Hiblot if (*w & caps & mwt->widths) { 1508d0c221feSJean-Jacques Hiblot debug("trying mode %s width %d (at %d MHz)\n", 1509d0c221feSJean-Jacques Hiblot mmc_mode_name(mwt->mode), 1510d0c221feSJean-Jacques Hiblot bus_width(*w), 1511d0c221feSJean-Jacques Hiblot mmc_mode2freq(mmc, mwt->mode) / 1000000); 1512d0c221feSJean-Jacques Hiblot 1513d0c221feSJean-Jacques Hiblot /* configure the bus width (card + host) */ 1514d0c221feSJean-Jacques Hiblot err = sd_select_bus_width(mmc, bus_width(*w)); 15158ac8a263SJean-Jacques Hiblot if (err) 1516d0c221feSJean-Jacques Hiblot goto error; 1517d0c221feSJean-Jacques Hiblot mmc_set_bus_width(mmc, bus_width(*w)); 15188ac8a263SJean-Jacques Hiblot 1519d0c221feSJean-Jacques Hiblot /* configure the bus mode (card) */ 1520d0c221feSJean-Jacques Hiblot err = sd_set_card_speed(mmc, mwt->mode); 15218ac8a263SJean-Jacques Hiblot if (err) 1522d0c221feSJean-Jacques Hiblot goto error; 15238ac8a263SJean-Jacques Hiblot 1524d0c221feSJean-Jacques Hiblot /* configure the bus mode (host) */ 1525d0c221feSJean-Jacques Hiblot mmc_select_mode(mmc, mwt->mode); 152635f67820SKishon Vijay Abraham I mmc_set_clock(mmc, mmc->tran_speed, false); 15278ac8a263SJean-Jacques Hiblot 1528c10b85d6SJean-Jacques Hiblot /* execute tuning if needed */ 1529c10b85d6SJean-Jacques Hiblot if (mwt->tuning && !mmc_host_is_spi(mmc)) { 1530c10b85d6SJean-Jacques Hiblot err = mmc_execute_tuning(mmc, 1531c10b85d6SJean-Jacques Hiblot mwt->tuning); 1532c10b85d6SJean-Jacques Hiblot if (err) { 1533c10b85d6SJean-Jacques Hiblot debug("tuning failed\n"); 1534c10b85d6SJean-Jacques Hiblot goto error; 1535c10b85d6SJean-Jacques Hiblot } 1536c10b85d6SJean-Jacques Hiblot } 1537c10b85d6SJean-Jacques Hiblot 15388ac8a263SJean-Jacques Hiblot err = sd_read_ssr(mmc); 1539d0c221feSJean-Jacques Hiblot if (!err) 15408ac8a263SJean-Jacques Hiblot return 0; 1541d0c221feSJean-Jacques Hiblot 1542d0c221feSJean-Jacques Hiblot printf("bad ssr\n"); 1543d0c221feSJean-Jacques Hiblot 1544d0c221feSJean-Jacques Hiblot error: 1545d0c221feSJean-Jacques Hiblot /* revert to a safer bus speed */ 1546d0c221feSJean-Jacques Hiblot mmc_select_mode(mmc, SD_LEGACY); 154735f67820SKishon Vijay Abraham I mmc_set_clock(mmc, mmc->tran_speed, false); 1548d0c221feSJean-Jacques Hiblot } 1549d0c221feSJean-Jacques Hiblot } 1550d0c221feSJean-Jacques Hiblot } 1551d0c221feSJean-Jacques Hiblot 1552d0c221feSJean-Jacques Hiblot printf("unable to select a mode\n"); 1553d0c221feSJean-Jacques Hiblot return -ENOTSUPP; 15548ac8a263SJean-Jacques Hiblot } 15558ac8a263SJean-Jacques Hiblot 15567382e691SJean-Jacques Hiblot /* 15577382e691SJean-Jacques Hiblot * read the compare the part of ext csd that is constant. 15587382e691SJean-Jacques Hiblot * This can be used to check that the transfer is working 15597382e691SJean-Jacques Hiblot * as expected. 15607382e691SJean-Jacques Hiblot */ 15617382e691SJean-Jacques Hiblot static int mmc_read_and_compare_ext_csd(struct mmc *mmc) 15627382e691SJean-Jacques Hiblot { 15637382e691SJean-Jacques Hiblot int err; 15647382e691SJean-Jacques Hiblot const u8 *ext_csd = mmc->ext_csd; 15657382e691SJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 15667382e691SJean-Jacques Hiblot 15677382e691SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, test_csd); 15687382e691SJean-Jacques Hiblot if (err) 15697382e691SJean-Jacques Hiblot return err; 15707382e691SJean-Jacques Hiblot 15717382e691SJean-Jacques Hiblot /* Only compare read only fields */ 15727382e691SJean-Jacques Hiblot if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] 15737382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_PARTITIONING_SUPPORT] && 15747382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_WP_GRP_SIZE] 15757382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_WP_GRP_SIZE] && 15767382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_REV] 15777382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_REV] && 15787382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 15797382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] && 15807382e691SJean-Jacques Hiblot memcmp(&ext_csd[EXT_CSD_SEC_CNT], 15817382e691SJean-Jacques Hiblot &test_csd[EXT_CSD_SEC_CNT], 4) == 0) 15827382e691SJean-Jacques Hiblot return 0; 15837382e691SJean-Jacques Hiblot 15847382e691SJean-Jacques Hiblot return -EBADMSG; 15857382e691SJean-Jacques Hiblot } 15867382e691SJean-Jacques Hiblot 15873862b854SJean-Jacques Hiblot static const struct mode_width_tuning mmc_modes_by_pref[] = { 15888ac8a263SJean-Jacques Hiblot { 15893862b854SJean-Jacques Hiblot .mode = MMC_HS_200, 15903862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT, 1591634d4849SKishon Vijay Abraham I .tuning = MMC_CMD_SEND_TUNING_BLOCK_HS200 15923862b854SJean-Jacques Hiblot }, 15933862b854SJean-Jacques Hiblot { 15943862b854SJean-Jacques Hiblot .mode = MMC_DDR_52, 15953862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT, 15963862b854SJean-Jacques Hiblot }, 15973862b854SJean-Jacques Hiblot { 15983862b854SJean-Jacques Hiblot .mode = MMC_HS_52, 15993862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 16003862b854SJean-Jacques Hiblot }, 16013862b854SJean-Jacques Hiblot { 16023862b854SJean-Jacques Hiblot .mode = MMC_HS, 16033862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 16043862b854SJean-Jacques Hiblot }, 16053862b854SJean-Jacques Hiblot { 16063862b854SJean-Jacques Hiblot .mode = MMC_LEGACY, 16073862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 16083862b854SJean-Jacques Hiblot } 16098ac8a263SJean-Jacques Hiblot }; 16108ac8a263SJean-Jacques Hiblot 16113862b854SJean-Jacques Hiblot #define for_each_mmc_mode_by_pref(caps, mwt) \ 16123862b854SJean-Jacques Hiblot for (mwt = mmc_modes_by_pref;\ 16133862b854SJean-Jacques Hiblot mwt < mmc_modes_by_pref + ARRAY_SIZE(mmc_modes_by_pref);\ 16143862b854SJean-Jacques Hiblot mwt++) \ 16153862b854SJean-Jacques Hiblot if (caps & MMC_CAP(mwt->mode)) 16163862b854SJean-Jacques Hiblot 16173862b854SJean-Jacques Hiblot static const struct ext_csd_bus_width { 16183862b854SJean-Jacques Hiblot uint cap; 16193862b854SJean-Jacques Hiblot bool is_ddr; 16203862b854SJean-Jacques Hiblot uint ext_csd_bits; 16213862b854SJean-Jacques Hiblot } ext_csd_bus_width[] = { 16223862b854SJean-Jacques Hiblot {MMC_MODE_8BIT, true, EXT_CSD_DDR_BUS_WIDTH_8}, 16233862b854SJean-Jacques Hiblot {MMC_MODE_4BIT, true, EXT_CSD_DDR_BUS_WIDTH_4}, 16243862b854SJean-Jacques Hiblot {MMC_MODE_8BIT, false, EXT_CSD_BUS_WIDTH_8}, 16253862b854SJean-Jacques Hiblot {MMC_MODE_4BIT, false, EXT_CSD_BUS_WIDTH_4}, 16263862b854SJean-Jacques Hiblot {MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1}, 16273862b854SJean-Jacques Hiblot }; 16283862b854SJean-Jacques Hiblot 16293862b854SJean-Jacques Hiblot #define for_each_supported_width(caps, ddr, ecbv) \ 16303862b854SJean-Jacques Hiblot for (ecbv = ext_csd_bus_width;\ 16313862b854SJean-Jacques Hiblot ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\ 16323862b854SJean-Jacques Hiblot ecbv++) \ 16333862b854SJean-Jacques Hiblot if ((ddr == ecbv->is_ddr) && (caps & ecbv->cap)) 16343862b854SJean-Jacques Hiblot 163501298da3SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps) 16363862b854SJean-Jacques Hiblot { 16373862b854SJean-Jacques Hiblot int err; 16383862b854SJean-Jacques Hiblot const struct mode_width_tuning *mwt; 16393862b854SJean-Jacques Hiblot const struct ext_csd_bus_width *ecbw; 16403862b854SJean-Jacques Hiblot 16418ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */ 164201298da3SJean-Jacques Hiblot card_caps &= (mmc->host_caps | MMC_MODE_1BIT); 16438ac8a263SJean-Jacques Hiblot 16448ac8a263SJean-Jacques Hiblot /* Only version 4 of MMC supports wider bus widths */ 16458ac8a263SJean-Jacques Hiblot if (mmc->version < MMC_VERSION_4) 16468ac8a263SJean-Jacques Hiblot return 0; 16478ac8a263SJean-Jacques Hiblot 1648dfda9d88SJean-Jacques Hiblot if (!mmc->ext_csd) { 1649dfda9d88SJean-Jacques Hiblot debug("No ext_csd found!\n"); /* this should enver happen */ 1650dfda9d88SJean-Jacques Hiblot return -ENOTSUPP; 1651dfda9d88SJean-Jacques Hiblot } 1652dfda9d88SJean-Jacques Hiblot 165301298da3SJean-Jacques Hiblot mmc_set_clock(mmc, mmc->legacy_speed, false); 165401298da3SJean-Jacques Hiblot 165501298da3SJean-Jacques Hiblot for_each_mmc_mode_by_pref(card_caps, mwt) { 165601298da3SJean-Jacques Hiblot for_each_supported_width(card_caps & mwt->widths, 16573862b854SJean-Jacques Hiblot mmc_is_mode_ddr(mwt->mode), ecbw) { 16583862b854SJean-Jacques Hiblot debug("trying mode %s width %d (at %d MHz)\n", 16593862b854SJean-Jacques Hiblot mmc_mode_name(mwt->mode), 16603862b854SJean-Jacques Hiblot bus_width(ecbw->cap), 16613862b854SJean-Jacques Hiblot mmc_mode2freq(mmc, mwt->mode) / 1000000); 16623862b854SJean-Jacques Hiblot /* configure the bus width (card + host) */ 16633862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 16643862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, 16653862b854SJean-Jacques Hiblot ecbw->ext_csd_bits & ~EXT_CSD_DDR_FLAG); 16663862b854SJean-Jacques Hiblot if (err) 16673862b854SJean-Jacques Hiblot goto error; 16683862b854SJean-Jacques Hiblot mmc_set_bus_width(mmc, bus_width(ecbw->cap)); 16693862b854SJean-Jacques Hiblot 16703862b854SJean-Jacques Hiblot /* configure the bus speed (card) */ 16713862b854SJean-Jacques Hiblot err = mmc_set_card_speed(mmc, mwt->mode); 16723862b854SJean-Jacques Hiblot if (err) 16733862b854SJean-Jacques Hiblot goto error; 16743862b854SJean-Jacques Hiblot 16758ac8a263SJean-Jacques Hiblot /* 16763862b854SJean-Jacques Hiblot * configure the bus width AND the ddr mode (card) 16773862b854SJean-Jacques Hiblot * The host side will be taken care of in the next step 16788ac8a263SJean-Jacques Hiblot */ 16793862b854SJean-Jacques Hiblot if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) { 16803862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 16813862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, 16823862b854SJean-Jacques Hiblot ecbw->ext_csd_bits); 16833862b854SJean-Jacques Hiblot if (err) 16843862b854SJean-Jacques Hiblot goto error; 16858ac8a263SJean-Jacques Hiblot } 16868ac8a263SJean-Jacques Hiblot 16873862b854SJean-Jacques Hiblot /* configure the bus mode (host) */ 16883862b854SJean-Jacques Hiblot mmc_select_mode(mmc, mwt->mode); 168935f67820SKishon Vijay Abraham I mmc_set_clock(mmc, mmc->tran_speed, false); 16908ac8a263SJean-Jacques Hiblot 1691634d4849SKishon Vijay Abraham I /* execute tuning if needed */ 1692634d4849SKishon Vijay Abraham I if (mwt->tuning) { 1693634d4849SKishon Vijay Abraham I err = mmc_execute_tuning(mmc, mwt->tuning); 1694634d4849SKishon Vijay Abraham I if (err) { 1695634d4849SKishon Vijay Abraham I debug("tuning failed\n"); 1696634d4849SKishon Vijay Abraham I goto error; 1697634d4849SKishon Vijay Abraham I } 1698634d4849SKishon Vijay Abraham I } 1699634d4849SKishon Vijay Abraham I 17003862b854SJean-Jacques Hiblot /* do a transfer to check the configuration */ 17017382e691SJean-Jacques Hiblot err = mmc_read_and_compare_ext_csd(mmc); 17027382e691SJean-Jacques Hiblot if (!err) 17033862b854SJean-Jacques Hiblot return 0; 17043862b854SJean-Jacques Hiblot error: 17053862b854SJean-Jacques Hiblot /* if an error occured, revert to a safer bus mode */ 17063862b854SJean-Jacques Hiblot mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 17073862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1); 17083862b854SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_LEGACY); 17093862b854SJean-Jacques Hiblot mmc_set_bus_width(mmc, 1); 17103862b854SJean-Jacques Hiblot } 17118ac8a263SJean-Jacques Hiblot } 17128ac8a263SJean-Jacques Hiblot 17133862b854SJean-Jacques Hiblot printf("unable to select a mode\n"); 17148ac8a263SJean-Jacques Hiblot 17153862b854SJean-Jacques Hiblot return -ENOTSUPP; 17168ac8a263SJean-Jacques Hiblot } 17178ac8a263SJean-Jacques Hiblot 1718dfda9d88SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc) 1719c744b6f6SJean-Jacques Hiblot { 1720c744b6f6SJean-Jacques Hiblot int err, i; 1721c744b6f6SJean-Jacques Hiblot u64 capacity; 1722c744b6f6SJean-Jacques Hiblot bool has_parts = false; 1723c744b6f6SJean-Jacques Hiblot bool part_completed; 1724dfda9d88SJean-Jacques Hiblot u8 *ext_csd; 1725c744b6f6SJean-Jacques Hiblot 1726c744b6f6SJean-Jacques Hiblot if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4)) 1727c744b6f6SJean-Jacques Hiblot return 0; 1728c744b6f6SJean-Jacques Hiblot 1729dfda9d88SJean-Jacques Hiblot ext_csd = malloc_cache_aligned(MMC_MAX_BLOCK_LEN); 1730dfda9d88SJean-Jacques Hiblot if (!ext_csd) 1731dfda9d88SJean-Jacques Hiblot return -ENOMEM; 1732dfda9d88SJean-Jacques Hiblot 1733dfda9d88SJean-Jacques Hiblot mmc->ext_csd = ext_csd; 1734dfda9d88SJean-Jacques Hiblot 1735c744b6f6SJean-Jacques Hiblot /* check ext_csd version and capacity */ 1736c744b6f6SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, ext_csd); 1737c744b6f6SJean-Jacques Hiblot if (err) 1738c744b6f6SJean-Jacques Hiblot return err; 1739c744b6f6SJean-Jacques Hiblot if (ext_csd[EXT_CSD_REV] >= 2) { 1740c744b6f6SJean-Jacques Hiblot /* 1741c744b6f6SJean-Jacques Hiblot * According to the JEDEC Standard, the value of 1742c744b6f6SJean-Jacques Hiblot * ext_csd's capacity is valid if the value is more 1743c744b6f6SJean-Jacques Hiblot * than 2GB 1744c744b6f6SJean-Jacques Hiblot */ 1745c744b6f6SJean-Jacques Hiblot capacity = ext_csd[EXT_CSD_SEC_CNT] << 0 1746c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 1747c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 1748c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; 1749c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN; 1750c744b6f6SJean-Jacques Hiblot if ((capacity >> 20) > 2 * 1024) 1751c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity; 1752c744b6f6SJean-Jacques Hiblot } 1753c744b6f6SJean-Jacques Hiblot 1754c744b6f6SJean-Jacques Hiblot switch (ext_csd[EXT_CSD_REV]) { 1755c744b6f6SJean-Jacques Hiblot case 1: 1756c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_1; 1757c744b6f6SJean-Jacques Hiblot break; 1758c744b6f6SJean-Jacques Hiblot case 2: 1759c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_2; 1760c744b6f6SJean-Jacques Hiblot break; 1761c744b6f6SJean-Jacques Hiblot case 3: 1762c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_3; 1763c744b6f6SJean-Jacques Hiblot break; 1764c744b6f6SJean-Jacques Hiblot case 5: 1765c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_41; 1766c744b6f6SJean-Jacques Hiblot break; 1767c744b6f6SJean-Jacques Hiblot case 6: 1768c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_5; 1769c744b6f6SJean-Jacques Hiblot break; 1770c744b6f6SJean-Jacques Hiblot case 7: 1771c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_5_0; 1772c744b6f6SJean-Jacques Hiblot break; 1773c744b6f6SJean-Jacques Hiblot case 8: 1774c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_5_1; 1775c744b6f6SJean-Jacques Hiblot break; 1776c744b6f6SJean-Jacques Hiblot } 1777c744b6f6SJean-Jacques Hiblot 1778c744b6f6SJean-Jacques Hiblot /* The partition data may be non-zero but it is only 1779c744b6f6SJean-Jacques Hiblot * effective if PARTITION_SETTING_COMPLETED is set in 1780c744b6f6SJean-Jacques Hiblot * EXT_CSD, so ignore any data if this bit is not set, 1781c744b6f6SJean-Jacques Hiblot * except for enabling the high-capacity group size 1782c744b6f6SJean-Jacques Hiblot * definition (see below). 1783c744b6f6SJean-Jacques Hiblot */ 1784c744b6f6SJean-Jacques Hiblot part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] & 1785c744b6f6SJean-Jacques Hiblot EXT_CSD_PARTITION_SETTING_COMPLETED); 1786c744b6f6SJean-Jacques Hiblot 1787c744b6f6SJean-Jacques Hiblot /* store the partition info of emmc */ 1788c744b6f6SJean-Jacques Hiblot mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT]; 1789c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || 1790c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_BOOT_MULT]) 1791c744b6f6SJean-Jacques Hiblot mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; 1792c744b6f6SJean-Jacques Hiblot if (part_completed && 1793c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT)) 1794c744b6f6SJean-Jacques Hiblot mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]; 1795c744b6f6SJean-Jacques Hiblot 1796c744b6f6SJean-Jacques Hiblot mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17; 1797c744b6f6SJean-Jacques Hiblot 1798c744b6f6SJean-Jacques Hiblot mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17; 1799c744b6f6SJean-Jacques Hiblot 1800c744b6f6SJean-Jacques Hiblot for (i = 0; i < 4; i++) { 1801c744b6f6SJean-Jacques Hiblot int idx = EXT_CSD_GP_SIZE_MULT + i * 3; 1802c744b6f6SJean-Jacques Hiblot uint mult = (ext_csd[idx + 2] << 16) + 1803c744b6f6SJean-Jacques Hiblot (ext_csd[idx + 1] << 8) + ext_csd[idx]; 1804c744b6f6SJean-Jacques Hiblot if (mult) 1805c744b6f6SJean-Jacques Hiblot has_parts = true; 1806c744b6f6SJean-Jacques Hiblot if (!part_completed) 1807c744b6f6SJean-Jacques Hiblot continue; 1808c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] = mult; 1809c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= 1810c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1811c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1812c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] <<= 19; 1813c744b6f6SJean-Jacques Hiblot } 1814c744b6f6SJean-Jacques Hiblot 1815c744b6f6SJean-Jacques Hiblot if (part_completed) { 1816c744b6f6SJean-Jacques Hiblot mmc->enh_user_size = 1817c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) + 1818c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) + 1819c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_SIZE_MULT]; 1820c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1821c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1822c744b6f6SJean-Jacques Hiblot mmc->enh_user_size <<= 19; 1823c744b6f6SJean-Jacques Hiblot mmc->enh_user_start = 1824c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) + 1825c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) + 1826c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) + 1827c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_START_ADDR]; 1828c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity) 1829c744b6f6SJean-Jacques Hiblot mmc->enh_user_start <<= 9; 1830c744b6f6SJean-Jacques Hiblot } 1831c744b6f6SJean-Jacques Hiblot 1832c744b6f6SJean-Jacques Hiblot /* 1833c744b6f6SJean-Jacques Hiblot * Host needs to enable ERASE_GRP_DEF bit if device is 1834c744b6f6SJean-Jacques Hiblot * partitioned. This bit will be lost every time after a reset 1835c744b6f6SJean-Jacques Hiblot * or power off. This will affect erase size. 1836c744b6f6SJean-Jacques Hiblot */ 1837c744b6f6SJean-Jacques Hiblot if (part_completed) 1838c744b6f6SJean-Jacques Hiblot has_parts = true; 1839c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) && 1840c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) 1841c744b6f6SJean-Jacques Hiblot has_parts = true; 1842c744b6f6SJean-Jacques Hiblot if (has_parts) { 1843c744b6f6SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1844c744b6f6SJean-Jacques Hiblot EXT_CSD_ERASE_GROUP_DEF, 1); 1845c744b6f6SJean-Jacques Hiblot 1846c744b6f6SJean-Jacques Hiblot if (err) 1847c744b6f6SJean-Jacques Hiblot return err; 1848c744b6f6SJean-Jacques Hiblot 1849c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 1850c744b6f6SJean-Jacques Hiblot } 1851c744b6f6SJean-Jacques Hiblot 1852c744b6f6SJean-Jacques Hiblot if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) { 1853c744b6f6SJean-Jacques Hiblot /* Read out group size from ext_csd */ 1854c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = 1855c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 1856c744b6f6SJean-Jacques Hiblot /* 1857c744b6f6SJean-Jacques Hiblot * if high capacity and partition setting completed 1858c744b6f6SJean-Jacques Hiblot * SEC_COUNT is valid even if it is smaller than 2 GiB 1859c744b6f6SJean-Jacques Hiblot * JEDEC Standard JESD84-B45, 6.2.4 1860c744b6f6SJean-Jacques Hiblot */ 1861c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity && part_completed) { 1862c744b6f6SJean-Jacques Hiblot capacity = (ext_csd[EXT_CSD_SEC_CNT]) | 1863c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) | 1864c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) | 1865c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 3] << 24); 1866c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN; 1867c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity; 1868c744b6f6SJean-Jacques Hiblot } 1869c744b6f6SJean-Jacques Hiblot } else { 1870c744b6f6SJean-Jacques Hiblot /* Calculate the group size from the csd value. */ 1871c744b6f6SJean-Jacques Hiblot int erase_gsz, erase_gmul; 1872c744b6f6SJean-Jacques Hiblot 1873c744b6f6SJean-Jacques Hiblot erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; 1874c744b6f6SJean-Jacques Hiblot erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; 1875c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = (erase_gsz + 1) 1876c744b6f6SJean-Jacques Hiblot * (erase_gmul + 1); 1877c744b6f6SJean-Jacques Hiblot } 1878c744b6f6SJean-Jacques Hiblot 1879c744b6f6SJean-Jacques Hiblot mmc->hc_wp_grp_size = 1024 1880c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 1881c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1882c744b6f6SJean-Jacques Hiblot 1883c744b6f6SJean-Jacques Hiblot mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 1884c744b6f6SJean-Jacques Hiblot 1885c744b6f6SJean-Jacques Hiblot return 0; 1886c744b6f6SJean-Jacques Hiblot } 1887c744b6f6SJean-Jacques Hiblot 1888fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc) 1889272cc70bSAndy Fleming { 1890f866a46dSStephen Warren int err, i; 1891272cc70bSAndy Fleming uint mult, freq; 1892c744b6f6SJean-Jacques Hiblot u64 cmult, csize; 1893272cc70bSAndy Fleming struct mmc_cmd cmd; 1894c40fdca6SSimon Glass struct blk_desc *bdesc; 1895272cc70bSAndy Fleming 1896d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON 1897d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ 1898d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; 1899d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R1; 1900d52ebf10SThomas Chou cmd.cmdarg = 1; 1901d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 1902d52ebf10SThomas Chou if (err) 1903d52ebf10SThomas Chou return err; 1904d52ebf10SThomas Chou } 1905d52ebf10SThomas Chou #endif 1906d52ebf10SThomas Chou 1907272cc70bSAndy Fleming /* Put the Card in Identify Mode */ 1908d52ebf10SThomas Chou cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : 1909d52ebf10SThomas Chou MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ 1910272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1911272cc70bSAndy Fleming cmd.cmdarg = 0; 1912272cc70bSAndy Fleming 1913272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1914272cc70bSAndy Fleming 1915*83dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS 1916*83dc4227SKishon Vijay Abraham I if (err && (mmc->quirks & MMC_QUIRK_RETRY_SEND_CID)) { 1917*83dc4227SKishon Vijay Abraham I int retries = 4; 1918*83dc4227SKishon Vijay Abraham I /* 1919*83dc4227SKishon Vijay Abraham I * It has been seen that SEND_CID may fail on the first 1920*83dc4227SKishon Vijay Abraham I * attempt, let's try a few more time 1921*83dc4227SKishon Vijay Abraham I */ 1922*83dc4227SKishon Vijay Abraham I do { 1923*83dc4227SKishon Vijay Abraham I err = mmc_send_cmd(mmc, &cmd, NULL); 1924*83dc4227SKishon Vijay Abraham I if (!err) 1925*83dc4227SKishon Vijay Abraham I break; 1926*83dc4227SKishon Vijay Abraham I } while (retries--); 1927*83dc4227SKishon Vijay Abraham I } 1928*83dc4227SKishon Vijay Abraham I #endif 1929*83dc4227SKishon Vijay Abraham I 1930272cc70bSAndy Fleming if (err) 1931272cc70bSAndy Fleming return err; 1932272cc70bSAndy Fleming 1933272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16); 1934272cc70bSAndy Fleming 1935272cc70bSAndy Fleming /* 1936272cc70bSAndy Fleming * For MMC cards, set the Relative Address. 1937272cc70bSAndy Fleming * For SD cards, get the Relatvie Address. 1938272cc70bSAndy Fleming * This also puts the cards into Standby State 1939272cc70bSAndy Fleming */ 1940d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 1941272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; 1942272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1943272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6; 1944272cc70bSAndy Fleming 1945272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1946272cc70bSAndy Fleming 1947272cc70bSAndy Fleming if (err) 1948272cc70bSAndy Fleming return err; 1949272cc70bSAndy Fleming 1950272cc70bSAndy Fleming if (IS_SD(mmc)) 1951998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff; 1952d52ebf10SThomas Chou } 1953272cc70bSAndy Fleming 1954272cc70bSAndy Fleming /* Get the Card-Specific Data */ 1955272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD; 1956272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1957272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1958272cc70bSAndy Fleming 1959272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1960272cc70bSAndy Fleming 1961272cc70bSAndy Fleming if (err) 1962272cc70bSAndy Fleming return err; 1963272cc70bSAndy Fleming 1964998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0]; 1965998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1]; 1966998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2]; 1967998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3]; 1968272cc70bSAndy Fleming 1969272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) { 19700b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf; 1971272cc70bSAndy Fleming 1972272cc70bSAndy Fleming switch (version) { 1973272cc70bSAndy Fleming case 0: 1974272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1975272cc70bSAndy Fleming break; 1976272cc70bSAndy Fleming case 1: 1977272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4; 1978272cc70bSAndy Fleming break; 1979272cc70bSAndy Fleming case 2: 1980272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2; 1981272cc70bSAndy Fleming break; 1982272cc70bSAndy Fleming case 3: 1983272cc70bSAndy Fleming mmc->version = MMC_VERSION_3; 1984272cc70bSAndy Fleming break; 1985272cc70bSAndy Fleming case 4: 1986272cc70bSAndy Fleming mmc->version = MMC_VERSION_4; 1987272cc70bSAndy Fleming break; 1988272cc70bSAndy Fleming default: 1989272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 1990272cc70bSAndy Fleming break; 1991272cc70bSAndy Fleming } 1992272cc70bSAndy Fleming } 1993272cc70bSAndy Fleming 1994272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */ 19950b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)]; 19960b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; 1997272cc70bSAndy Fleming 199835f9e196SJean-Jacques Hiblot mmc->legacy_speed = freq * mult; 199935f9e196SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_LEGACY); 2000272cc70bSAndy Fleming 2001ab71188cSMarkus Niebel mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); 2002998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); 2003272cc70bSAndy Fleming 2004272cc70bSAndy Fleming if (IS_SD(mmc)) 2005272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len; 2006272cc70bSAndy Fleming else 2007998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); 2008272cc70bSAndy Fleming 2009272cc70bSAndy Fleming if (mmc->high_capacity) { 2010272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16 2011272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16; 2012272cc70bSAndy Fleming cmult = 8; 2013272cc70bSAndy Fleming } else { 2014272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2 2015272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30; 2016272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15; 2017272cc70bSAndy Fleming } 2018272cc70bSAndy Fleming 2019f866a46dSStephen Warren mmc->capacity_user = (csize + 1) << (cmult + 2); 2020f866a46dSStephen Warren mmc->capacity_user *= mmc->read_bl_len; 2021f866a46dSStephen Warren mmc->capacity_boot = 0; 2022f866a46dSStephen Warren mmc->capacity_rpmb = 0; 2023f866a46dSStephen Warren for (i = 0; i < 4; i++) 2024f866a46dSStephen Warren mmc->capacity_gp[i] = 0; 2025272cc70bSAndy Fleming 20268bfa195eSSimon Glass if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN) 20278bfa195eSSimon Glass mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 2028272cc70bSAndy Fleming 20298bfa195eSSimon Glass if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) 20308bfa195eSSimon Glass mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 2031272cc70bSAndy Fleming 2032ab71188cSMarkus Niebel if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) { 2033ab71188cSMarkus Niebel cmd.cmdidx = MMC_CMD_SET_DSR; 2034ab71188cSMarkus Niebel cmd.cmdarg = (mmc->dsr & 0xffff) << 16; 2035ab71188cSMarkus Niebel cmd.resp_type = MMC_RSP_NONE; 2036ab71188cSMarkus Niebel if (mmc_send_cmd(mmc, &cmd, NULL)) 2037ab71188cSMarkus Niebel printf("MMC: SET_DSR failed\n"); 2038ab71188cSMarkus Niebel } 2039ab71188cSMarkus Niebel 2040272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */ 2041d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 2042272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD; 2043fe8f7066SAjay Bhargav cmd.resp_type = MMC_RSP_R1; 2044272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 2045272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2046272cc70bSAndy Fleming 2047272cc70bSAndy Fleming if (err) 2048272cc70bSAndy Fleming return err; 2049d52ebf10SThomas Chou } 2050272cc70bSAndy Fleming 2051e6f99a56SLei Wen /* 2052e6f99a56SLei Wen * For SD, its erase group is always one sector 2053e6f99a56SLei Wen */ 2054e6f99a56SLei Wen mmc->erase_grp_size = 1; 2055bc897b1dSLei Wen mmc->part_config = MMCPART_NOAVAILABLE; 2056c744b6f6SJean-Jacques Hiblot 2057dfda9d88SJean-Jacques Hiblot err = mmc_startup_v4(mmc); 20589cf199ebSDiego Santa Cruz if (err) 20599cf199ebSDiego Santa Cruz return err; 2060f866a46dSStephen Warren 2061c40fdca6SSimon Glass err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart); 2062f866a46dSStephen Warren if (err) 2063f866a46dSStephen Warren return err; 2064d23e2c09SSukumar Ghorai 206501298da3SJean-Jacques Hiblot if (IS_SD(mmc)) { 206601298da3SJean-Jacques Hiblot err = sd_get_capabilities(mmc); 206701298da3SJean-Jacques Hiblot if (err) 206801298da3SJean-Jacques Hiblot return err; 206901298da3SJean-Jacques Hiblot err = sd_select_mode_and_width(mmc, mmc->card_caps); 207001298da3SJean-Jacques Hiblot } else { 207101298da3SJean-Jacques Hiblot err = mmc_get_capabilities(mmc); 207201298da3SJean-Jacques Hiblot if (err) 207301298da3SJean-Jacques Hiblot return err; 207401298da3SJean-Jacques Hiblot mmc_select_mode_and_width(mmc, mmc->card_caps); 207501298da3SJean-Jacques Hiblot } 2076272cc70bSAndy Fleming 2077272cc70bSAndy Fleming if (err) 2078272cc70bSAndy Fleming return err; 2079272cc70bSAndy Fleming 208001298da3SJean-Jacques Hiblot mmc->best_mode = mmc->selected_mode; 2081272cc70bSAndy Fleming 20825af8f45cSAndrew Gabbasov /* Fix the block length for DDR mode */ 20835af8f45cSAndrew Gabbasov if (mmc->ddr_mode) { 20845af8f45cSAndrew Gabbasov mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 20855af8f45cSAndrew Gabbasov mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 20865af8f45cSAndrew Gabbasov } 20875af8f45cSAndrew Gabbasov 2088272cc70bSAndy Fleming /* fill in device description */ 2089c40fdca6SSimon Glass bdesc = mmc_get_blk_desc(mmc); 2090c40fdca6SSimon Glass bdesc->lun = 0; 2091c40fdca6SSimon Glass bdesc->hwpart = 0; 2092c40fdca6SSimon Glass bdesc->type = 0; 2093c40fdca6SSimon Glass bdesc->blksz = mmc->read_bl_len; 2094c40fdca6SSimon Glass bdesc->log2blksz = LOG2(bdesc->blksz); 2095c40fdca6SSimon Glass bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len); 2096fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \ 2097fc011f64SSjoerd Simons (defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \ 2098fc011f64SSjoerd Simons !defined(CONFIG_USE_TINY_PRINTF)) 2099c40fdca6SSimon Glass sprintf(bdesc->vendor, "Man %06x Snr %04x%04x", 2100babce5f6STaylor Hutt mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), 2101babce5f6STaylor Hutt (mmc->cid[3] >> 16) & 0xffff); 2102c40fdca6SSimon Glass sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff, 21030b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 2104babce5f6STaylor Hutt (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff, 2105babce5f6STaylor Hutt (mmc->cid[2] >> 24) & 0xff); 2106c40fdca6SSimon Glass sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf, 2107babce5f6STaylor Hutt (mmc->cid[2] >> 16) & 0xf); 210856196826SPaul Burton #else 2109c40fdca6SSimon Glass bdesc->vendor[0] = 0; 2110c40fdca6SSimon Glass bdesc->product[0] = 0; 2111c40fdca6SSimon Glass bdesc->revision[0] = 0; 211256196826SPaul Burton #endif 2113122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT) 2114c40fdca6SSimon Glass part_init(bdesc); 2115122efd43SMikhail Kshevetskiy #endif 2116272cc70bSAndy Fleming 2117272cc70bSAndy Fleming return 0; 2118272cc70bSAndy Fleming } 2119272cc70bSAndy Fleming 2120fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc) 2121272cc70bSAndy Fleming { 2122272cc70bSAndy Fleming struct mmc_cmd cmd; 2123272cc70bSAndy Fleming int err; 2124272cc70bSAndy Fleming 2125272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND; 2126272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ 212793bfd616SPantelis Antoniou cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa; 2128272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7; 2129272cc70bSAndy Fleming 2130272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2131272cc70bSAndy Fleming 2132272cc70bSAndy Fleming if (err) 2133272cc70bSAndy Fleming return err; 2134272cc70bSAndy Fleming 2135998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa) 2136915ffa52SJaehoon Chung return -EOPNOTSUPP; 2137272cc70bSAndy Fleming else 2138272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 2139272cc70bSAndy Fleming 2140272cc70bSAndy Fleming return 0; 2141272cc70bSAndy Fleming } 2142272cc70bSAndy Fleming 2143c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 214495de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */ 214595de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void) 214695de9ab2SPaul Kocialkowski { 214795de9ab2SPaul Kocialkowski } 214805cbeb7cSSimon Glass #endif 214995de9ab2SPaul Kocialkowski 21502051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc) 21512051aefeSPeng Fan { 2152c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 215306ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR) 21542051aefeSPeng Fan int ret; 21552051aefeSPeng Fan 21562051aefeSPeng Fan ret = device_get_supply_regulator(mmc->dev, "vmmc-supply", 215706ec045fSJean-Jacques Hiblot &mmc->vmmc_supply); 215806ec045fSJean-Jacques Hiblot if (ret) 2159288db7c7SJaehoon Chung debug("%s: No vmmc supply\n", mmc->dev->name); 21602051aefeSPeng Fan 216106ec045fSJean-Jacques Hiblot ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply", 216206ec045fSJean-Jacques Hiblot &mmc->vqmmc_supply); 216306ec045fSJean-Jacques Hiblot if (ret) 216406ec045fSJean-Jacques Hiblot debug("%s: No vqmmc supply\n", mmc->dev->name); 21652051aefeSPeng Fan #endif 216605cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */ 216705cbeb7cSSimon Glass /* 216805cbeb7cSSimon Glass * Driver model should use a regulator, as above, rather than calling 216905cbeb7cSSimon Glass * out to board code. 217005cbeb7cSSimon Glass */ 217105cbeb7cSSimon Glass board_mmc_power_init(); 217205cbeb7cSSimon Glass #endif 21732051aefeSPeng Fan return 0; 21742051aefeSPeng Fan } 21752051aefeSPeng Fan 2176fb7c3bebSKishon Vijay Abraham I /* 2177fb7c3bebSKishon Vijay Abraham I * put the host in the initial state: 2178fb7c3bebSKishon Vijay Abraham I * - turn on Vdd (card power supply) 2179fb7c3bebSKishon Vijay Abraham I * - configure the bus width and clock to minimal values 2180fb7c3bebSKishon Vijay Abraham I */ 2181fb7c3bebSKishon Vijay Abraham I static void mmc_set_initial_state(struct mmc *mmc) 2182fb7c3bebSKishon Vijay Abraham I { 2183fb7c3bebSKishon Vijay Abraham I int err; 2184fb7c3bebSKishon Vijay Abraham I 2185fb7c3bebSKishon Vijay Abraham I /* First try to set 3.3V. If it fails set to 1.8V */ 2186fb7c3bebSKishon Vijay Abraham I err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_330); 2187fb7c3bebSKishon Vijay Abraham I if (err != 0) 2188fb7c3bebSKishon Vijay Abraham I err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_180); 2189fb7c3bebSKishon Vijay Abraham I if (err != 0) 2190fb7c3bebSKishon Vijay Abraham I printf("mmc: failed to set signal voltage\n"); 2191fb7c3bebSKishon Vijay Abraham I 2192fb7c3bebSKishon Vijay Abraham I mmc_select_mode(mmc, MMC_LEGACY); 2193fb7c3bebSKishon Vijay Abraham I mmc_set_bus_width(mmc, 1); 219435f67820SKishon Vijay Abraham I mmc_set_clock(mmc, 0, false); 2195fb7c3bebSKishon Vijay Abraham I } 2196fb7c3bebSKishon Vijay Abraham I 2197fb7c3bebSKishon Vijay Abraham I static int mmc_power_on(struct mmc *mmc) 2198fb7c3bebSKishon Vijay Abraham I { 2199fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR) 2200fb7c3bebSKishon Vijay Abraham I if (mmc->vmmc_supply) { 2201fb7c3bebSKishon Vijay Abraham I int ret = regulator_set_enable(mmc->vmmc_supply, true); 2202fb7c3bebSKishon Vijay Abraham I 2203fb7c3bebSKishon Vijay Abraham I if (ret) { 2204fb7c3bebSKishon Vijay Abraham I puts("Error enabling VMMC supply\n"); 2205fb7c3bebSKishon Vijay Abraham I return ret; 2206fb7c3bebSKishon Vijay Abraham I } 2207fb7c3bebSKishon Vijay Abraham I } 2208fb7c3bebSKishon Vijay Abraham I #endif 2209fb7c3bebSKishon Vijay Abraham I return 0; 2210fb7c3bebSKishon Vijay Abraham I } 2211fb7c3bebSKishon Vijay Abraham I 2212fb7c3bebSKishon Vijay Abraham I static int mmc_power_off(struct mmc *mmc) 2213fb7c3bebSKishon Vijay Abraham I { 22142e7410d7SKishon Vijay Abraham I mmc_set_clock(mmc, 1, true); 2215fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR) 2216fb7c3bebSKishon Vijay Abraham I if (mmc->vmmc_supply) { 2217fb7c3bebSKishon Vijay Abraham I int ret = regulator_set_enable(mmc->vmmc_supply, false); 2218fb7c3bebSKishon Vijay Abraham I 2219fb7c3bebSKishon Vijay Abraham I if (ret) { 2220c10b85d6SJean-Jacques Hiblot debug("Error disabling VMMC supply\n"); 2221fb7c3bebSKishon Vijay Abraham I return ret; 2222fb7c3bebSKishon Vijay Abraham I } 2223fb7c3bebSKishon Vijay Abraham I } 2224fb7c3bebSKishon Vijay Abraham I #endif 2225fb7c3bebSKishon Vijay Abraham I return 0; 2226fb7c3bebSKishon Vijay Abraham I } 2227fb7c3bebSKishon Vijay Abraham I 2228fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc) 2229fb7c3bebSKishon Vijay Abraham I { 2230fb7c3bebSKishon Vijay Abraham I int ret; 2231fb7c3bebSKishon Vijay Abraham I 2232fb7c3bebSKishon Vijay Abraham I ret = mmc_power_off(mmc); 2233fb7c3bebSKishon Vijay Abraham I if (ret) 2234fb7c3bebSKishon Vijay Abraham I return ret; 2235fb7c3bebSKishon Vijay Abraham I /* 2236fb7c3bebSKishon Vijay Abraham I * SD spec recommends at least 1ms of delay. Let's wait for 2ms 2237fb7c3bebSKishon Vijay Abraham I * to be on the safer side. 2238fb7c3bebSKishon Vijay Abraham I */ 2239fb7c3bebSKishon Vijay Abraham I udelay(2000); 2240fb7c3bebSKishon Vijay Abraham I return mmc_power_on(mmc); 2241fb7c3bebSKishon Vijay Abraham I } 2242fb7c3bebSKishon Vijay Abraham I 2243e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc) 2244272cc70bSAndy Fleming { 22458ca51e51SSimon Glass bool no_card; 2246c10b85d6SJean-Jacques Hiblot bool uhs_en = supports_uhs(mmc->cfg->host_caps); 2247afd5932bSMacpaul Lin int err; 2248272cc70bSAndy Fleming 224904a2ea24SJean-Jacques Hiblot mmc->host_caps = mmc->cfg->host_caps; 225004a2ea24SJean-Jacques Hiblot 2251ab769f22SPantelis Antoniou /* we pretend there's no card when init is NULL */ 22528ca51e51SSimon Glass no_card = mmc_getcd(mmc) == 0; 2253e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 22548ca51e51SSimon Glass no_card = no_card || (mmc->cfg->ops->init == NULL); 22558ca51e51SSimon Glass #endif 22568ca51e51SSimon Glass if (no_card) { 225748972d90SThierry Reding mmc->has_init = 0; 225856196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 225948972d90SThierry Reding printf("MMC: no card present\n"); 226056196826SPaul Burton #endif 2261915ffa52SJaehoon Chung return -ENOMEDIUM; 226248972d90SThierry Reding } 226348972d90SThierry Reding 2264bc897b1dSLei Wen if (mmc->has_init) 2265bc897b1dSLei Wen return 0; 2266bc897b1dSLei Wen 22675a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 22685a8dbdc6SYangbo Lu mmc_adapter_card_type_ident(); 22695a8dbdc6SYangbo Lu #endif 22702051aefeSPeng Fan err = mmc_power_init(mmc); 22712051aefeSPeng Fan if (err) 22722051aefeSPeng Fan return err; 227395de9ab2SPaul Kocialkowski 2274*83dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS 2275*83dc4227SKishon Vijay Abraham I mmc->quirks = MMC_QUIRK_RETRY_SET_BLOCKLEN | 2276*83dc4227SKishon Vijay Abraham I MMC_QUIRK_RETRY_SEND_CID; 2277*83dc4227SKishon Vijay Abraham I #endif 2278*83dc4227SKishon Vijay Abraham I 227904a2ea24SJean-Jacques Hiblot err = mmc_power_cycle(mmc); 228004a2ea24SJean-Jacques Hiblot if (err) { 228104a2ea24SJean-Jacques Hiblot /* 228204a2ea24SJean-Jacques Hiblot * if power cycling is not supported, we should not try 228304a2ea24SJean-Jacques Hiblot * to use the UHS modes, because we wouldn't be able to 228404a2ea24SJean-Jacques Hiblot * recover from an error during the UHS initialization. 228504a2ea24SJean-Jacques Hiblot */ 228604a2ea24SJean-Jacques Hiblot debug("Unable to do a full power cycle. Disabling the UHS modes for safety\n"); 228704a2ea24SJean-Jacques Hiblot uhs_en = false; 228804a2ea24SJean-Jacques Hiblot mmc->host_caps &= ~UHS_CAPS; 2289fb7c3bebSKishon Vijay Abraham I err = mmc_power_on(mmc); 229004a2ea24SJean-Jacques Hiblot } 2291fb7c3bebSKishon Vijay Abraham I if (err) 2292fb7c3bebSKishon Vijay Abraham I return err; 2293fb7c3bebSKishon Vijay Abraham I 2294e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 22958ca51e51SSimon Glass /* The device has already been probed ready for use */ 22968ca51e51SSimon Glass #else 2297ab769f22SPantelis Antoniou /* made sure it's not NULL earlier */ 229893bfd616SPantelis Antoniou err = mmc->cfg->ops->init(mmc); 2299272cc70bSAndy Fleming if (err) 2300272cc70bSAndy Fleming return err; 23018ca51e51SSimon Glass #endif 2302786e8f81SAndrew Gabbasov mmc->ddr_mode = 0; 2303aff5d3c8SKishon Vijay Abraham I 2304c10b85d6SJean-Jacques Hiblot retry: 2305fb7c3bebSKishon Vijay Abraham I mmc_set_initial_state(mmc); 2306318a7a57SJean-Jacques Hiblot mmc_send_init_stream(mmc); 2307318a7a57SJean-Jacques Hiblot 2308272cc70bSAndy Fleming /* Reset the Card */ 2309272cc70bSAndy Fleming err = mmc_go_idle(mmc); 2310272cc70bSAndy Fleming 2311272cc70bSAndy Fleming if (err) 2312272cc70bSAndy Fleming return err; 2313272cc70bSAndy Fleming 2314bc897b1dSLei Wen /* The internal partition reset to user partition(0) at every CMD0*/ 2315c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->hwpart = 0; 2316bc897b1dSLei Wen 2317272cc70bSAndy Fleming /* Test for SD version 2 */ 2318272cc70bSAndy Fleming err = mmc_send_if_cond(mmc); 2319272cc70bSAndy Fleming 2320272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */ 2321c10b85d6SJean-Jacques Hiblot err = sd_send_op_cond(mmc, uhs_en); 2322c10b85d6SJean-Jacques Hiblot if (err && uhs_en) { 2323c10b85d6SJean-Jacques Hiblot uhs_en = false; 2324c10b85d6SJean-Jacques Hiblot mmc_power_cycle(mmc); 2325c10b85d6SJean-Jacques Hiblot goto retry; 2326c10b85d6SJean-Jacques Hiblot } 2327272cc70bSAndy Fleming 2328272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */ 2329915ffa52SJaehoon Chung if (err == -ETIMEDOUT) { 2330272cc70bSAndy Fleming err = mmc_send_op_cond(mmc); 2331272cc70bSAndy Fleming 2332bd47c135SAndrew Gabbasov if (err) { 233356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2334272cc70bSAndy Fleming printf("Card did not respond to voltage select!\n"); 233556196826SPaul Burton #endif 2336915ffa52SJaehoon Chung return -EOPNOTSUPP; 2337272cc70bSAndy Fleming } 2338272cc70bSAndy Fleming } 2339272cc70bSAndy Fleming 2340bd47c135SAndrew Gabbasov if (!err) 2341e9550449SChe-Liang Chiou mmc->init_in_progress = 1; 2342e9550449SChe-Liang Chiou 2343e9550449SChe-Liang Chiou return err; 2344e9550449SChe-Liang Chiou } 2345e9550449SChe-Liang Chiou 2346e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc) 2347e9550449SChe-Liang Chiou { 2348e9550449SChe-Liang Chiou int err = 0; 2349e9550449SChe-Liang Chiou 2350bd47c135SAndrew Gabbasov mmc->init_in_progress = 0; 2351e9550449SChe-Liang Chiou if (mmc->op_cond_pending) 2352e9550449SChe-Liang Chiou err = mmc_complete_op_cond(mmc); 2353e9550449SChe-Liang Chiou 2354e9550449SChe-Liang Chiou if (!err) 2355bc897b1dSLei Wen err = mmc_startup(mmc); 2356bc897b1dSLei Wen if (err) 2357bc897b1dSLei Wen mmc->has_init = 0; 2358bc897b1dSLei Wen else 2359bc897b1dSLei Wen mmc->has_init = 1; 2360e9550449SChe-Liang Chiou return err; 2361e9550449SChe-Liang Chiou } 2362e9550449SChe-Liang Chiou 2363e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc) 2364e9550449SChe-Liang Chiou { 2365bd47c135SAndrew Gabbasov int err = 0; 2366ce9eca94SMarek Vasut __maybe_unused unsigned start; 2367c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 236833fb211dSSimon Glass struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev); 2369e9550449SChe-Liang Chiou 237033fb211dSSimon Glass upriv->mmc = mmc; 237133fb211dSSimon Glass #endif 2372e9550449SChe-Liang Chiou if (mmc->has_init) 2373e9550449SChe-Liang Chiou return 0; 2374d803fea5SMateusz Zalega 2375d803fea5SMateusz Zalega start = get_timer(0); 2376d803fea5SMateusz Zalega 2377e9550449SChe-Liang Chiou if (!mmc->init_in_progress) 2378e9550449SChe-Liang Chiou err = mmc_start_init(mmc); 2379e9550449SChe-Liang Chiou 2380bd47c135SAndrew Gabbasov if (!err) 2381e9550449SChe-Liang Chiou err = mmc_complete_init(mmc); 2382919b4858SJagan Teki if (err) 2383919b4858SJagan Teki printf("%s: %d, time %lu\n", __func__, err, get_timer(start)); 2384919b4858SJagan Teki 2385bc897b1dSLei Wen return err; 2386272cc70bSAndy Fleming } 2387272cc70bSAndy Fleming 2388ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val) 2389ab71188cSMarkus Niebel { 2390ab71188cSMarkus Niebel mmc->dsr = val; 2391ab71188cSMarkus Niebel return 0; 2392ab71188cSMarkus Niebel } 2393ab71188cSMarkus Niebel 2394cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */ 2395cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis) 2396272cc70bSAndy Fleming { 2397272cc70bSAndy Fleming return -1; 2398272cc70bSAndy Fleming } 2399272cc70bSAndy Fleming 2400cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */ 2401cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis) 2402cee9ab7cSJeroen Hofstee { 2403cee9ab7cSJeroen Hofstee return -1; 2404cee9ab7cSJeroen Hofstee } 2405272cc70bSAndy Fleming 2406e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit) 2407e9550449SChe-Liang Chiou { 2408e9550449SChe-Liang Chiou mmc->preinit = preinit; 2409e9550449SChe-Liang Chiou } 2410e9550449SChe-Liang Chiou 2411c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD) 24128e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 24138e3332e2SSjoerd Simons { 24148e3332e2SSjoerd Simons return 0; 24158e3332e2SSjoerd Simons } 2416c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC) 24178e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 24188e3332e2SSjoerd Simons { 24194a1db6d8SSimon Glass int ret, i; 24208e3332e2SSjoerd Simons struct uclass *uc; 24214a1db6d8SSimon Glass struct udevice *dev; 24228e3332e2SSjoerd Simons 24238e3332e2SSjoerd Simons ret = uclass_get(UCLASS_MMC, &uc); 24248e3332e2SSjoerd Simons if (ret) 24258e3332e2SSjoerd Simons return ret; 24268e3332e2SSjoerd Simons 24274a1db6d8SSimon Glass /* 24284a1db6d8SSimon Glass * Try to add them in sequence order. Really with driver model we 24294a1db6d8SSimon Glass * should allow holes, but the current MMC list does not allow that. 24304a1db6d8SSimon Glass * So if we request 0, 1, 3 we will get 0, 1, 2. 24314a1db6d8SSimon Glass */ 24324a1db6d8SSimon Glass for (i = 0; ; i++) { 24334a1db6d8SSimon Glass ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev); 24344a1db6d8SSimon Glass if (ret == -ENODEV) 24354a1db6d8SSimon Glass break; 24364a1db6d8SSimon Glass } 24374a1db6d8SSimon Glass uclass_foreach_dev(dev, uc) { 24384a1db6d8SSimon Glass ret = device_probe(dev); 24398e3332e2SSjoerd Simons if (ret) 24404a1db6d8SSimon Glass printf("%s - probe failed: %d\n", dev->name, ret); 24418e3332e2SSjoerd Simons } 24428e3332e2SSjoerd Simons 24438e3332e2SSjoerd Simons return 0; 24448e3332e2SSjoerd Simons } 24458e3332e2SSjoerd Simons #else 24468e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 24478e3332e2SSjoerd Simons { 24488e3332e2SSjoerd Simons if (board_mmc_init(bis) < 0) 24498e3332e2SSjoerd Simons cpu_mmc_init(bis); 24508e3332e2SSjoerd Simons 24518e3332e2SSjoerd Simons return 0; 24528e3332e2SSjoerd Simons } 24538e3332e2SSjoerd Simons #endif 2454e9550449SChe-Liang Chiou 2455272cc70bSAndy Fleming int mmc_initialize(bd_t *bis) 2456272cc70bSAndy Fleming { 24571b26bab1SDaniel Kochmański static int initialized = 0; 24588e3332e2SSjoerd Simons int ret; 24591b26bab1SDaniel Kochmański if (initialized) /* Avoid initializing mmc multiple times */ 24601b26bab1SDaniel Kochmański return 0; 24611b26bab1SDaniel Kochmański initialized = 1; 24621b26bab1SDaniel Kochmański 2463c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK) 2464b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY) 2465c40fdca6SSimon Glass mmc_list_init(); 2466c40fdca6SSimon Glass #endif 2467b5b838f1SMarek Vasut #endif 24688e3332e2SSjoerd Simons ret = mmc_probe(bis); 24698e3332e2SSjoerd Simons if (ret) 24708e3332e2SSjoerd Simons return ret; 2471272cc70bSAndy Fleming 2472bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD 2473272cc70bSAndy Fleming print_mmc_devices(','); 2474bb0dc108SYing Zhang #endif 2475272cc70bSAndy Fleming 2476c40fdca6SSimon Glass mmc_do_preinit(); 2477272cc70bSAndy Fleming return 0; 2478272cc70bSAndy Fleming } 2479cd3d4880STomas Melin 2480cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE 2481cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc) 2482cd3d4880STomas Melin { 2483cd3d4880STomas Melin int err; 2484cd3d4880STomas Melin ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 2485cd3d4880STomas Melin 2486cd3d4880STomas Melin err = mmc_send_ext_csd(mmc, ext_csd); 2487cd3d4880STomas Melin if (err) { 2488cd3d4880STomas Melin puts("Could not get ext_csd register values\n"); 2489cd3d4880STomas Melin return err; 2490cd3d4880STomas Melin } 2491cd3d4880STomas Melin 2492cd3d4880STomas Melin if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) { 2493cd3d4880STomas Melin puts("Background operations not supported on device\n"); 2494cd3d4880STomas Melin return -EMEDIUMTYPE; 2495cd3d4880STomas Melin } 2496cd3d4880STomas Melin 2497cd3d4880STomas Melin if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) { 2498cd3d4880STomas Melin puts("Background operations already enabled\n"); 2499cd3d4880STomas Melin return 0; 2500cd3d4880STomas Melin } 2501cd3d4880STomas Melin 2502cd3d4880STomas Melin err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1); 2503cd3d4880STomas Melin if (err) { 2504cd3d4880STomas Melin puts("Failed to enable manual background operations\n"); 2505cd3d4880STomas Melin return err; 2506cd3d4880STomas Melin } 2507cd3d4880STomas Melin 2508cd3d4880STomas Melin puts("Enabled manual background operations\n"); 2509cd3d4880STomas Melin 2510cd3d4880STomas Melin return 0; 2511cd3d4880STomas Melin } 2512cd3d4880STomas Melin #endif 2513