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; 28283dc4227SKishon 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 29183dc4227SKishon Vijay Abraham I err = mmc_send_cmd(mmc, &cmd, NULL); 29283dc4227SKishon Vijay Abraham I 29383dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS 29483dc4227SKishon Vijay Abraham I if (err && (mmc->quirks & MMC_QUIRK_RETRY_SET_BLOCKLEN)) { 29583dc4227SKishon Vijay Abraham I int retries = 4; 29683dc4227SKishon Vijay Abraham I /* 29783dc4227SKishon Vijay Abraham I * It has been seen that SET_BLOCKLEN may fail on the first 29883dc4227SKishon Vijay Abraham I * attempt, let's try a few more time 29983dc4227SKishon Vijay Abraham I */ 30083dc4227SKishon Vijay Abraham I do { 30183dc4227SKishon Vijay Abraham I err = mmc_send_cmd(mmc, &cmd, NULL); 30283dc4227SKishon Vijay Abraham I if (!err) 30383dc4227SKishon Vijay Abraham I break; 30483dc4227SKishon Vijay Abraham I } while (retries--); 30583dc4227SKishon Vijay Abraham I } 30683dc4227SKishon Vijay Abraham I #endif 30783dc4227SKishon Vijay Abraham I 30883dc4227SKishon 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; 770*bc1e3272SJean-Jacques Hiblot mmc->cardtype = cardtype; 771272cc70bSAndy Fleming 772634d4849SKishon Vijay Abraham I if (cardtype & (EXT_CSD_CARD_TYPE_HS200_1_2V | 773634d4849SKishon Vijay Abraham I EXT_CSD_CARD_TYPE_HS200_1_8V)) { 774634d4849SKishon Vijay Abraham I mmc->card_caps |= MMC_MODE_HS200; 775634d4849SKishon Vijay Abraham I } 776d22e3d46SJaehoon Chung if (cardtype & EXT_CSD_CARD_TYPE_52) { 7773862b854SJean-Jacques Hiblot if (cardtype & EXT_CSD_CARD_TYPE_DDR_52) 778d22e3d46SJaehoon Chung mmc->card_caps |= MMC_MODE_DDR_52MHz; 7793862b854SJean-Jacques Hiblot mmc->card_caps |= MMC_MODE_HS_52MHz; 780d22e3d46SJaehoon Chung } 7813862b854SJean-Jacques Hiblot if (cardtype & EXT_CSD_CARD_TYPE_26) 7823862b854SJean-Jacques Hiblot mmc->card_caps |= MMC_MODE_HS; 783272cc70bSAndy Fleming 784272cc70bSAndy Fleming return 0; 785272cc70bSAndy Fleming } 786272cc70bSAndy Fleming 787f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num) 788f866a46dSStephen Warren { 789f866a46dSStephen Warren switch (part_num) { 790f866a46dSStephen Warren case 0: 791f866a46dSStephen Warren mmc->capacity = mmc->capacity_user; 792f866a46dSStephen Warren break; 793f866a46dSStephen Warren case 1: 794f866a46dSStephen Warren case 2: 795f866a46dSStephen Warren mmc->capacity = mmc->capacity_boot; 796f866a46dSStephen Warren break; 797f866a46dSStephen Warren case 3: 798f866a46dSStephen Warren mmc->capacity = mmc->capacity_rpmb; 799f866a46dSStephen Warren break; 800f866a46dSStephen Warren case 4: 801f866a46dSStephen Warren case 5: 802f866a46dSStephen Warren case 6: 803f866a46dSStephen Warren case 7: 804f866a46dSStephen Warren mmc->capacity = mmc->capacity_gp[part_num - 4]; 805f866a46dSStephen Warren break; 806f866a46dSStephen Warren default: 807f866a46dSStephen Warren return -1; 808f866a46dSStephen Warren } 809f866a46dSStephen Warren 810c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len); 811f866a46dSStephen Warren 812f866a46dSStephen Warren return 0; 813f866a46dSStephen Warren } 814f866a46dSStephen Warren 81501298da3SJean-Jacques Hiblot static int mmc_boot_part_access_chk(struct mmc *mmc, unsigned int part_num) 81601298da3SJean-Jacques Hiblot { 81701298da3SJean-Jacques Hiblot int forbidden = 0; 81801298da3SJean-Jacques Hiblot bool change = false; 81901298da3SJean-Jacques Hiblot 82001298da3SJean-Jacques Hiblot if (part_num & PART_ACCESS_MASK) 82101298da3SJean-Jacques Hiblot forbidden = MMC_CAP(MMC_HS_200); 82201298da3SJean-Jacques Hiblot 82301298da3SJean-Jacques Hiblot if (MMC_CAP(mmc->selected_mode) & forbidden) { 82401298da3SJean-Jacques Hiblot debug("selected mode (%s) is forbidden for part %d\n", 82501298da3SJean-Jacques Hiblot mmc_mode_name(mmc->selected_mode), part_num); 82601298da3SJean-Jacques Hiblot change = true; 82701298da3SJean-Jacques Hiblot } else if (mmc->selected_mode != mmc->best_mode) { 82801298da3SJean-Jacques Hiblot debug("selected mode is not optimal\n"); 82901298da3SJean-Jacques Hiblot change = true; 83001298da3SJean-Jacques Hiblot } 83101298da3SJean-Jacques Hiblot 83201298da3SJean-Jacques Hiblot if (change) 83301298da3SJean-Jacques Hiblot return mmc_select_mode_and_width(mmc, 83401298da3SJean-Jacques Hiblot mmc->card_caps & ~forbidden); 83501298da3SJean-Jacques Hiblot 83601298da3SJean-Jacques Hiblot return 0; 83701298da3SJean-Jacques Hiblot } 83801298da3SJean-Jacques Hiblot 8397dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num) 840bc897b1dSLei Wen { 841f866a46dSStephen Warren int ret; 842bc897b1dSLei Wen 84301298da3SJean-Jacques Hiblot ret = mmc_boot_part_access_chk(mmc, part_num); 84401298da3SJean-Jacques Hiblot if (ret) 84501298da3SJean-Jacques Hiblot return ret; 84601298da3SJean-Jacques Hiblot 847f866a46dSStephen Warren ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 848bc897b1dSLei Wen (mmc->part_config & ~PART_ACCESS_MASK) 849bc897b1dSLei Wen | (part_num & PART_ACCESS_MASK)); 850f866a46dSStephen Warren 8516dc93e70SPeter Bigot /* 8526dc93e70SPeter Bigot * Set the capacity if the switch succeeded or was intended 8536dc93e70SPeter Bigot * to return to representing the raw device. 8546dc93e70SPeter Bigot */ 855873cc1d7SStephen Warren if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) { 8566dc93e70SPeter Bigot ret = mmc_set_capacity(mmc, part_num); 857fdbb139fSSimon Glass mmc_get_blk_desc(mmc)->hwpart = part_num; 858873cc1d7SStephen Warren } 8596dc93e70SPeter Bigot 8606dc93e70SPeter Bigot return ret; 861bc897b1dSLei Wen } 862bc897b1dSLei Wen 863ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc, 864ac9da0e0SDiego Santa Cruz const struct mmc_hwpart_conf *conf, 865ac9da0e0SDiego Santa Cruz enum mmc_hwpart_conf_mode mode) 866ac9da0e0SDiego Santa Cruz { 867ac9da0e0SDiego Santa Cruz u8 part_attrs = 0; 868ac9da0e0SDiego Santa Cruz u32 enh_size_mult; 869ac9da0e0SDiego Santa Cruz u32 enh_start_addr; 870ac9da0e0SDiego Santa Cruz u32 gp_size_mult[4]; 871ac9da0e0SDiego Santa Cruz u32 max_enh_size_mult; 872ac9da0e0SDiego Santa Cruz u32 tot_enh_size_mult = 0; 8738dda5b0eSDiego Santa Cruz u8 wr_rel_set; 874ac9da0e0SDiego Santa Cruz int i, pidx, err; 875ac9da0e0SDiego Santa Cruz ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 876ac9da0e0SDiego Santa Cruz 877ac9da0e0SDiego Santa Cruz if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE) 878ac9da0e0SDiego Santa Cruz return -EINVAL; 879ac9da0e0SDiego Santa Cruz 880ac9da0e0SDiego Santa Cruz if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) { 881ac9da0e0SDiego Santa Cruz printf("eMMC >= 4.4 required for enhanced user data area\n"); 882ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 883ac9da0e0SDiego Santa Cruz } 884ac9da0e0SDiego Santa Cruz 885ac9da0e0SDiego Santa Cruz if (!(mmc->part_support & PART_SUPPORT)) { 886ac9da0e0SDiego Santa Cruz printf("Card does not support partitioning\n"); 887ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 888ac9da0e0SDiego Santa Cruz } 889ac9da0e0SDiego Santa Cruz 890ac9da0e0SDiego Santa Cruz if (!mmc->hc_wp_grp_size) { 891ac9da0e0SDiego Santa Cruz printf("Card does not define HC WP group size\n"); 892ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 893ac9da0e0SDiego Santa Cruz } 894ac9da0e0SDiego Santa Cruz 895ac9da0e0SDiego Santa Cruz /* check partition alignment and total enhanced size */ 896ac9da0e0SDiego Santa Cruz if (conf->user.enh_size) { 897ac9da0e0SDiego Santa Cruz if (conf->user.enh_size % mmc->hc_wp_grp_size || 898ac9da0e0SDiego Santa Cruz conf->user.enh_start % mmc->hc_wp_grp_size) { 899ac9da0e0SDiego Santa Cruz printf("User data enhanced area not HC WP group " 900ac9da0e0SDiego Santa Cruz "size aligned\n"); 901ac9da0e0SDiego Santa Cruz return -EINVAL; 902ac9da0e0SDiego Santa Cruz } 903ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_USR; 904ac9da0e0SDiego Santa Cruz enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size; 905ac9da0e0SDiego Santa Cruz if (mmc->high_capacity) { 906ac9da0e0SDiego Santa Cruz enh_start_addr = conf->user.enh_start; 907ac9da0e0SDiego Santa Cruz } else { 908ac9da0e0SDiego Santa Cruz enh_start_addr = (conf->user.enh_start << 9); 909ac9da0e0SDiego Santa Cruz } 910ac9da0e0SDiego Santa Cruz } else { 911ac9da0e0SDiego Santa Cruz enh_size_mult = 0; 912ac9da0e0SDiego Santa Cruz enh_start_addr = 0; 913ac9da0e0SDiego Santa Cruz } 914ac9da0e0SDiego Santa Cruz tot_enh_size_mult += enh_size_mult; 915ac9da0e0SDiego Santa Cruz 916ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 917ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) { 918ac9da0e0SDiego Santa Cruz printf("GP%i partition not HC WP group size " 919ac9da0e0SDiego Santa Cruz "aligned\n", pidx+1); 920ac9da0e0SDiego Santa Cruz return -EINVAL; 921ac9da0e0SDiego Santa Cruz } 922ac9da0e0SDiego Santa Cruz gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size; 923ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) { 924ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_GP(pidx); 925ac9da0e0SDiego Santa Cruz tot_enh_size_mult += gp_size_mult[pidx]; 926ac9da0e0SDiego Santa Cruz } 927ac9da0e0SDiego Santa Cruz } 928ac9da0e0SDiego Santa Cruz 929ac9da0e0SDiego Santa Cruz if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) { 930ac9da0e0SDiego Santa Cruz printf("Card does not support enhanced attribute\n"); 931ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 932ac9da0e0SDiego Santa Cruz } 933ac9da0e0SDiego Santa Cruz 934ac9da0e0SDiego Santa Cruz err = mmc_send_ext_csd(mmc, ext_csd); 935ac9da0e0SDiego Santa Cruz if (err) 936ac9da0e0SDiego Santa Cruz return err; 937ac9da0e0SDiego Santa Cruz 938ac9da0e0SDiego Santa Cruz max_enh_size_mult = 939ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) + 940ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) + 941ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]; 942ac9da0e0SDiego Santa Cruz if (tot_enh_size_mult > max_enh_size_mult) { 943ac9da0e0SDiego Santa Cruz printf("Total enhanced size exceeds maximum (%u > %u)\n", 944ac9da0e0SDiego Santa Cruz tot_enh_size_mult, max_enh_size_mult); 945ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 946ac9da0e0SDiego Santa Cruz } 947ac9da0e0SDiego Santa Cruz 9488dda5b0eSDiego Santa Cruz /* The default value of EXT_CSD_WR_REL_SET is device 9498dda5b0eSDiego Santa Cruz * dependent, the values can only be changed if the 9508dda5b0eSDiego Santa Cruz * EXT_CSD_HS_CTRL_REL bit is set. The values can be 9518dda5b0eSDiego Santa Cruz * changed only once and before partitioning is completed. */ 9528dda5b0eSDiego Santa Cruz wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 9538dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_change) { 9548dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_set) 9558dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_USR; 9568dda5b0eSDiego Santa Cruz else 9578dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR; 9588dda5b0eSDiego Santa Cruz } 9598dda5b0eSDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 9608dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_change) { 9618dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_set) 9628dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx); 9638dda5b0eSDiego Santa Cruz else 9648dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx); 9658dda5b0eSDiego Santa Cruz } 9668dda5b0eSDiego Santa Cruz } 9678dda5b0eSDiego Santa Cruz 9688dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] && 9698dda5b0eSDiego Santa Cruz !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) { 9708dda5b0eSDiego Santa Cruz puts("Card does not support host controlled partition write " 9718dda5b0eSDiego Santa Cruz "reliability settings\n"); 9728dda5b0eSDiego Santa Cruz return -EMEDIUMTYPE; 9738dda5b0eSDiego Santa Cruz } 9748dda5b0eSDiego Santa Cruz 975ac9da0e0SDiego Santa Cruz if (ext_csd[EXT_CSD_PARTITION_SETTING] & 976ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED) { 977ac9da0e0SDiego Santa Cruz printf("Card already partitioned\n"); 978ac9da0e0SDiego Santa Cruz return -EPERM; 979ac9da0e0SDiego Santa Cruz } 980ac9da0e0SDiego Santa Cruz 981ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_CHECK) 982ac9da0e0SDiego Santa Cruz return 0; 983ac9da0e0SDiego Santa Cruz 984ac9da0e0SDiego Santa Cruz /* Partitioning requires high-capacity size definitions */ 985ac9da0e0SDiego Santa Cruz if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) { 986ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 987ac9da0e0SDiego Santa Cruz EXT_CSD_ERASE_GROUP_DEF, 1); 988ac9da0e0SDiego Santa Cruz 989ac9da0e0SDiego Santa Cruz if (err) 990ac9da0e0SDiego Santa Cruz return err; 991ac9da0e0SDiego Santa Cruz 992ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 993ac9da0e0SDiego Santa Cruz 994ac9da0e0SDiego Santa Cruz /* update erase group size to be high-capacity */ 995ac9da0e0SDiego Santa Cruz mmc->erase_grp_size = 996ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 997ac9da0e0SDiego Santa Cruz 998ac9da0e0SDiego Santa Cruz } 999ac9da0e0SDiego Santa Cruz 1000ac9da0e0SDiego Santa Cruz /* all OK, write the configuration */ 1001ac9da0e0SDiego Santa Cruz for (i = 0; i < 4; i++) { 1002ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1003ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_START_ADDR+i, 1004ac9da0e0SDiego Santa Cruz (enh_start_addr >> (i*8)) & 0xFF); 1005ac9da0e0SDiego Santa Cruz if (err) 1006ac9da0e0SDiego Santa Cruz return err; 1007ac9da0e0SDiego Santa Cruz } 1008ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 1009ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1010ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_SIZE_MULT+i, 1011ac9da0e0SDiego Santa Cruz (enh_size_mult >> (i*8)) & 0xFF); 1012ac9da0e0SDiego Santa Cruz if (err) 1013ac9da0e0SDiego Santa Cruz return err; 1014ac9da0e0SDiego Santa Cruz } 1015ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 1016ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 1017ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1018ac9da0e0SDiego Santa Cruz EXT_CSD_GP_SIZE_MULT+pidx*3+i, 1019ac9da0e0SDiego Santa Cruz (gp_size_mult[pidx] >> (i*8)) & 0xFF); 1020ac9da0e0SDiego Santa Cruz if (err) 1021ac9da0e0SDiego Santa Cruz return err; 1022ac9da0e0SDiego Santa Cruz } 1023ac9da0e0SDiego Santa Cruz } 1024ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1025ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs); 1026ac9da0e0SDiego Santa Cruz if (err) 1027ac9da0e0SDiego Santa Cruz return err; 1028ac9da0e0SDiego Santa Cruz 1029ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_SET) 1030ac9da0e0SDiego Santa Cruz return 0; 1031ac9da0e0SDiego Santa Cruz 10328dda5b0eSDiego Santa Cruz /* The WR_REL_SET is a write-once register but shall be 10338dda5b0eSDiego Santa Cruz * written before setting PART_SETTING_COMPLETED. As it is 10348dda5b0eSDiego Santa Cruz * write-once we can only write it when completing the 10358dda5b0eSDiego Santa Cruz * partitioning. */ 10368dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) { 10378dda5b0eSDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 10388dda5b0eSDiego Santa Cruz EXT_CSD_WR_REL_SET, wr_rel_set); 10398dda5b0eSDiego Santa Cruz if (err) 10408dda5b0eSDiego Santa Cruz return err; 10418dda5b0eSDiego Santa Cruz } 10428dda5b0eSDiego Santa Cruz 1043ac9da0e0SDiego Santa Cruz /* Setting PART_SETTING_COMPLETED confirms the partition 1044ac9da0e0SDiego Santa Cruz * configuration but it only becomes effective after power 1045ac9da0e0SDiego Santa Cruz * cycle, so we do not adjust the partition related settings 1046ac9da0e0SDiego Santa Cruz * in the mmc struct. */ 1047ac9da0e0SDiego Santa Cruz 1048ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1049ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING, 1050ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 1051ac9da0e0SDiego Santa Cruz if (err) 1052ac9da0e0SDiego Santa Cruz return err; 1053ac9da0e0SDiego Santa Cruz 1054ac9da0e0SDiego Santa Cruz return 0; 1055ac9da0e0SDiego Santa Cruz } 1056ac9da0e0SDiego Santa Cruz 1057e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 105848972d90SThierry Reding int mmc_getcd(struct mmc *mmc) 105948972d90SThierry Reding { 106048972d90SThierry Reding int cd; 106148972d90SThierry Reding 106248972d90SThierry Reding cd = board_mmc_getcd(mmc); 106348972d90SThierry Reding 1064d4e1da4eSPeter Korsgaard if (cd < 0) { 106593bfd616SPantelis Antoniou if (mmc->cfg->ops->getcd) 106693bfd616SPantelis Antoniou cd = mmc->cfg->ops->getcd(mmc); 1067d4e1da4eSPeter Korsgaard else 1068d4e1da4eSPeter Korsgaard cd = 1; 1069d4e1da4eSPeter Korsgaard } 107048972d90SThierry Reding 107148972d90SThierry Reding return cd; 107248972d90SThierry Reding } 10738ca51e51SSimon Glass #endif 107448972d90SThierry Reding 1075fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) 1076272cc70bSAndy Fleming { 1077272cc70bSAndy Fleming struct mmc_cmd cmd; 1078272cc70bSAndy Fleming struct mmc_data data; 1079272cc70bSAndy Fleming 1080272cc70bSAndy Fleming /* Switch the frequency */ 1081272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC; 1082272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1083272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff; 1084272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4)); 1085272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4); 1086272cc70bSAndy Fleming 1087272cc70bSAndy Fleming data.dest = (char *)resp; 1088272cc70bSAndy Fleming data.blocksize = 64; 1089272cc70bSAndy Fleming data.blocks = 1; 1090272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1091272cc70bSAndy Fleming 1092272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 1093272cc70bSAndy Fleming } 1094272cc70bSAndy Fleming 1095272cc70bSAndy Fleming 1096d0c221feSJean-Jacques Hiblot static int sd_get_capabilities(struct mmc *mmc) 1097272cc70bSAndy Fleming { 1098272cc70bSAndy Fleming int err; 1099272cc70bSAndy Fleming struct mmc_cmd cmd; 110018e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2); 110118e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16); 1102272cc70bSAndy Fleming struct mmc_data data; 1103272cc70bSAndy Fleming int timeout; 1104c10b85d6SJean-Jacques Hiblot u32 sd3_bus_mode; 1105272cc70bSAndy Fleming 1106d0c221feSJean-Jacques Hiblot mmc->card_caps = MMC_MODE_1BIT; 1107272cc70bSAndy Fleming 1108d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 1109d52ebf10SThomas Chou return 0; 1110d52ebf10SThomas Chou 1111272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */ 1112272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 1113272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1114272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1115272cc70bSAndy Fleming 1116272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1117272cc70bSAndy Fleming 1118272cc70bSAndy Fleming if (err) 1119272cc70bSAndy Fleming return err; 1120272cc70bSAndy Fleming 1121272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR; 1122272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1123272cc70bSAndy Fleming cmd.cmdarg = 0; 1124272cc70bSAndy Fleming 1125272cc70bSAndy Fleming timeout = 3; 1126272cc70bSAndy Fleming 1127272cc70bSAndy Fleming retry_scr: 1128f781dd38SAnton staaf data.dest = (char *)scr; 1129272cc70bSAndy Fleming data.blocksize = 8; 1130272cc70bSAndy Fleming data.blocks = 1; 1131272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1132272cc70bSAndy Fleming 1133272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 1134272cc70bSAndy Fleming 1135272cc70bSAndy Fleming if (err) { 1136272cc70bSAndy Fleming if (timeout--) 1137272cc70bSAndy Fleming goto retry_scr; 1138272cc70bSAndy Fleming 1139272cc70bSAndy Fleming return err; 1140272cc70bSAndy Fleming } 1141272cc70bSAndy Fleming 11424e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]); 11434e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]); 1144272cc70bSAndy Fleming 1145272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) { 1146272cc70bSAndy Fleming case 0: 1147272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1148272cc70bSAndy Fleming break; 1149272cc70bSAndy Fleming case 1: 1150272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10; 1151272cc70bSAndy Fleming break; 1152272cc70bSAndy Fleming case 2: 1153272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 11541741c64dSJaehoon Chung if ((mmc->scr[0] >> 15) & 0x1) 11551741c64dSJaehoon Chung mmc->version = SD_VERSION_3; 1156272cc70bSAndy Fleming break; 1157272cc70bSAndy Fleming default: 1158272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1159272cc70bSAndy Fleming break; 1160272cc70bSAndy Fleming } 1161272cc70bSAndy Fleming 1162b44c7083SAlagu Sankar if (mmc->scr[0] & SD_DATA_4BIT) 1163b44c7083SAlagu Sankar mmc->card_caps |= MMC_MODE_4BIT; 1164b44c7083SAlagu Sankar 1165272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */ 1166272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0) 1167272cc70bSAndy Fleming return 0; 1168272cc70bSAndy Fleming 1169272cc70bSAndy Fleming timeout = 4; 1170272cc70bSAndy Fleming while (timeout--) { 1171272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, 1172f781dd38SAnton staaf (u8 *)switch_status); 1173272cc70bSAndy Fleming 1174272cc70bSAndy Fleming if (err) 1175272cc70bSAndy Fleming return err; 1176272cc70bSAndy Fleming 1177272cc70bSAndy Fleming /* The high-speed function is busy. Try again */ 11784e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) 1179272cc70bSAndy Fleming break; 1180272cc70bSAndy Fleming } 1181272cc70bSAndy Fleming 1182272cc70bSAndy Fleming /* If high-speed isn't supported, we return */ 1183d0c221feSJean-Jacques Hiblot if (__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED) 1184d0c221feSJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(SD_HS); 1185272cc70bSAndy Fleming 1186c10b85d6SJean-Jacques Hiblot /* Version before 3.0 don't support UHS modes */ 1187c10b85d6SJean-Jacques Hiblot if (mmc->version < SD_VERSION_3) 1188c10b85d6SJean-Jacques Hiblot return 0; 1189c10b85d6SJean-Jacques Hiblot 1190c10b85d6SJean-Jacques Hiblot sd3_bus_mode = __be32_to_cpu(switch_status[3]) >> 16 & 0x1f; 1191c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR104) 1192c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR104); 1193c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR50) 1194c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR50); 1195c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR25) 1196c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR25); 1197c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR12) 1198c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR12); 1199c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_DDR50) 1200c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_DDR50); 1201c10b85d6SJean-Jacques Hiblot 12022c3fbf4cSMacpaul Lin return 0; 1203d0c221feSJean-Jacques Hiblot } 1204d0c221feSJean-Jacques Hiblot 1205d0c221feSJean-Jacques Hiblot static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode) 1206d0c221feSJean-Jacques Hiblot { 1207d0c221feSJean-Jacques Hiblot int err; 1208d0c221feSJean-Jacques Hiblot 1209d0c221feSJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16); 1210c10b85d6SJean-Jacques Hiblot int speed; 12112c3fbf4cSMacpaul Lin 1212c10b85d6SJean-Jacques Hiblot switch (mode) { 1213c10b85d6SJean-Jacques Hiblot case SD_LEGACY: 1214c10b85d6SJean-Jacques Hiblot case UHS_SDR12: 1215c10b85d6SJean-Jacques Hiblot speed = UHS_SDR12_BUS_SPEED; 1216c10b85d6SJean-Jacques Hiblot break; 1217c10b85d6SJean-Jacques Hiblot case SD_HS: 1218c10b85d6SJean-Jacques Hiblot case UHS_SDR25: 1219c10b85d6SJean-Jacques Hiblot speed = UHS_SDR25_BUS_SPEED; 1220c10b85d6SJean-Jacques Hiblot break; 1221c10b85d6SJean-Jacques Hiblot case UHS_SDR50: 1222c10b85d6SJean-Jacques Hiblot speed = UHS_SDR50_BUS_SPEED; 1223c10b85d6SJean-Jacques Hiblot break; 1224c10b85d6SJean-Jacques Hiblot case UHS_DDR50: 1225c10b85d6SJean-Jacques Hiblot speed = UHS_DDR50_BUS_SPEED; 1226c10b85d6SJean-Jacques Hiblot break; 1227c10b85d6SJean-Jacques Hiblot case UHS_SDR104: 1228c10b85d6SJean-Jacques Hiblot speed = UHS_SDR104_BUS_SPEED; 1229c10b85d6SJean-Jacques Hiblot break; 1230c10b85d6SJean-Jacques Hiblot default: 1231c10b85d6SJean-Jacques Hiblot return -EINVAL; 1232c10b85d6SJean-Jacques Hiblot } 1233c10b85d6SJean-Jacques Hiblot 1234c10b85d6SJean-Jacques Hiblot err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, speed, (u8 *)switch_status); 1235272cc70bSAndy Fleming if (err) 1236272cc70bSAndy Fleming return err; 1237272cc70bSAndy Fleming 1238c10b85d6SJean-Jacques Hiblot if ((__be32_to_cpu(switch_status[4]) >> 24) != speed) 1239d0c221feSJean-Jacques Hiblot return -ENOTSUPP; 1240d0c221feSJean-Jacques Hiblot 1241d0c221feSJean-Jacques Hiblot return 0; 1242d0c221feSJean-Jacques Hiblot } 1243d0c221feSJean-Jacques Hiblot 1244d0c221feSJean-Jacques Hiblot int sd_select_bus_width(struct mmc *mmc, int w) 1245d0c221feSJean-Jacques Hiblot { 1246d0c221feSJean-Jacques Hiblot int err; 1247d0c221feSJean-Jacques Hiblot struct mmc_cmd cmd; 1248d0c221feSJean-Jacques Hiblot 1249d0c221feSJean-Jacques Hiblot if ((w != 4) && (w != 1)) 1250d0c221feSJean-Jacques Hiblot return -EINVAL; 1251d0c221feSJean-Jacques Hiblot 1252d0c221feSJean-Jacques Hiblot cmd.cmdidx = MMC_CMD_APP_CMD; 1253d0c221feSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 1254d0c221feSJean-Jacques Hiblot cmd.cmdarg = mmc->rca << 16; 1255d0c221feSJean-Jacques Hiblot 1256d0c221feSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 1257d0c221feSJean-Jacques Hiblot if (err) 1258d0c221feSJean-Jacques Hiblot return err; 1259d0c221feSJean-Jacques Hiblot 1260d0c221feSJean-Jacques Hiblot cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; 1261d0c221feSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 1262d0c221feSJean-Jacques Hiblot if (w == 4) 1263d0c221feSJean-Jacques Hiblot cmd.cmdarg = 2; 1264d0c221feSJean-Jacques Hiblot else if (w == 1) 1265d0c221feSJean-Jacques Hiblot cmd.cmdarg = 0; 1266d0c221feSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 1267d0c221feSJean-Jacques Hiblot if (err) 1268d0c221feSJean-Jacques Hiblot return err; 1269272cc70bSAndy Fleming 1270272cc70bSAndy Fleming return 0; 1271272cc70bSAndy Fleming } 1272272cc70bSAndy Fleming 12733697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc) 12743697e599SPeng Fan { 12753697e599SPeng Fan int err, i; 12763697e599SPeng Fan struct mmc_cmd cmd; 12773697e599SPeng Fan ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16); 12783697e599SPeng Fan struct mmc_data data; 12793697e599SPeng Fan int timeout = 3; 12803697e599SPeng Fan unsigned int au, eo, et, es; 12813697e599SPeng Fan 12823697e599SPeng Fan cmd.cmdidx = MMC_CMD_APP_CMD; 12833697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 12843697e599SPeng Fan cmd.cmdarg = mmc->rca << 16; 12853697e599SPeng Fan 12863697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, NULL); 12873697e599SPeng Fan if (err) 12883697e599SPeng Fan return err; 12893697e599SPeng Fan 12903697e599SPeng Fan cmd.cmdidx = SD_CMD_APP_SD_STATUS; 12913697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 12923697e599SPeng Fan cmd.cmdarg = 0; 12933697e599SPeng Fan 12943697e599SPeng Fan retry_ssr: 12953697e599SPeng Fan data.dest = (char *)ssr; 12963697e599SPeng Fan data.blocksize = 64; 12973697e599SPeng Fan data.blocks = 1; 12983697e599SPeng Fan data.flags = MMC_DATA_READ; 12993697e599SPeng Fan 13003697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, &data); 13013697e599SPeng Fan if (err) { 13023697e599SPeng Fan if (timeout--) 13033697e599SPeng Fan goto retry_ssr; 13043697e599SPeng Fan 13053697e599SPeng Fan return err; 13063697e599SPeng Fan } 13073697e599SPeng Fan 13083697e599SPeng Fan for (i = 0; i < 16; i++) 13093697e599SPeng Fan ssr[i] = be32_to_cpu(ssr[i]); 13103697e599SPeng Fan 13113697e599SPeng Fan au = (ssr[2] >> 12) & 0xF; 13123697e599SPeng Fan if ((au <= 9) || (mmc->version == SD_VERSION_3)) { 13133697e599SPeng Fan mmc->ssr.au = sd_au_size[au]; 13143697e599SPeng Fan es = (ssr[3] >> 24) & 0xFF; 13153697e599SPeng Fan es |= (ssr[2] & 0xFF) << 8; 13163697e599SPeng Fan et = (ssr[3] >> 18) & 0x3F; 13173697e599SPeng Fan if (es && et) { 13183697e599SPeng Fan eo = (ssr[3] >> 16) & 0x3; 13193697e599SPeng Fan mmc->ssr.erase_timeout = (et * 1000) / es; 13203697e599SPeng Fan mmc->ssr.erase_offset = eo * 1000; 13213697e599SPeng Fan } 13223697e599SPeng Fan } else { 13233697e599SPeng Fan debug("Invalid Allocation Unit Size.\n"); 13243697e599SPeng Fan } 13253697e599SPeng Fan 13263697e599SPeng Fan return 0; 13273697e599SPeng Fan } 13283697e599SPeng Fan 1329272cc70bSAndy Fleming /* frequency bases */ 1330272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */ 13315f837c2cSMike Frysinger static const int fbase[] = { 1332272cc70bSAndy Fleming 10000, 1333272cc70bSAndy Fleming 100000, 1334272cc70bSAndy Fleming 1000000, 1335272cc70bSAndy Fleming 10000000, 1336272cc70bSAndy Fleming }; 1337272cc70bSAndy Fleming 1338272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice 1339272cc70bSAndy Fleming * to platforms without floating point. 1340272cc70bSAndy Fleming */ 134161fe076fSSimon Glass static const u8 multipliers[] = { 1342272cc70bSAndy Fleming 0, /* reserved */ 1343272cc70bSAndy Fleming 10, 1344272cc70bSAndy Fleming 12, 1345272cc70bSAndy Fleming 13, 1346272cc70bSAndy Fleming 15, 1347272cc70bSAndy Fleming 20, 1348272cc70bSAndy Fleming 25, 1349272cc70bSAndy Fleming 30, 1350272cc70bSAndy Fleming 35, 1351272cc70bSAndy Fleming 40, 1352272cc70bSAndy Fleming 45, 1353272cc70bSAndy Fleming 50, 1354272cc70bSAndy Fleming 55, 1355272cc70bSAndy Fleming 60, 1356272cc70bSAndy Fleming 70, 1357272cc70bSAndy Fleming 80, 1358272cc70bSAndy Fleming }; 1359272cc70bSAndy Fleming 1360d0c221feSJean-Jacques Hiblot static inline int bus_width(uint cap) 1361d0c221feSJean-Jacques Hiblot { 1362d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_8BIT) 1363d0c221feSJean-Jacques Hiblot return 8; 1364d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_4BIT) 1365d0c221feSJean-Jacques Hiblot return 4; 1366d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_1BIT) 1367d0c221feSJean-Jacques Hiblot return 1; 1368d0c221feSJean-Jacques Hiblot printf("invalid bus witdh capability 0x%x\n", cap); 1369d0c221feSJean-Jacques Hiblot return 0; 1370d0c221feSJean-Jacques Hiblot } 1371d0c221feSJean-Jacques Hiblot 1372e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 1373ec841209SKishon Vijay Abraham I static int mmc_execute_tuning(struct mmc *mmc, uint opcode) 1374ec841209SKishon Vijay Abraham I { 1375ec841209SKishon Vijay Abraham I return -ENOTSUPP; 1376ec841209SKishon Vijay Abraham I } 1377ec841209SKishon Vijay Abraham I 1378318a7a57SJean-Jacques Hiblot static void mmc_send_init_stream(struct mmc *mmc) 1379318a7a57SJean-Jacques Hiblot { 1380318a7a57SJean-Jacques Hiblot } 1381318a7a57SJean-Jacques Hiblot 13822a4d212fSKishon Vijay Abraham I static int mmc_set_ios(struct mmc *mmc) 1383272cc70bSAndy Fleming { 13842a4d212fSKishon Vijay Abraham I int ret = 0; 13852a4d212fSKishon Vijay Abraham I 138693bfd616SPantelis Antoniou if (mmc->cfg->ops->set_ios) 13872a4d212fSKishon Vijay Abraham I ret = mmc->cfg->ops->set_ios(mmc); 13882a4d212fSKishon Vijay Abraham I 13892a4d212fSKishon Vijay Abraham I return ret; 1390272cc70bSAndy Fleming } 13918ca51e51SSimon Glass #endif 1392272cc70bSAndy Fleming 139335f67820SKishon Vijay Abraham I int mmc_set_clock(struct mmc *mmc, uint clock, bool disable) 1394272cc70bSAndy Fleming { 139593bfd616SPantelis Antoniou if (clock > mmc->cfg->f_max) 139693bfd616SPantelis Antoniou clock = mmc->cfg->f_max; 1397272cc70bSAndy Fleming 139893bfd616SPantelis Antoniou if (clock < mmc->cfg->f_min) 139993bfd616SPantelis Antoniou clock = mmc->cfg->f_min; 1400272cc70bSAndy Fleming 1401272cc70bSAndy Fleming mmc->clock = clock; 140235f67820SKishon Vijay Abraham I mmc->clk_disable = disable; 1403272cc70bSAndy Fleming 14042a4d212fSKishon Vijay Abraham I return mmc_set_ios(mmc); 1405272cc70bSAndy Fleming } 1406272cc70bSAndy Fleming 14072a4d212fSKishon Vijay Abraham I static int mmc_set_bus_width(struct mmc *mmc, uint width) 1408272cc70bSAndy Fleming { 1409272cc70bSAndy Fleming mmc->bus_width = width; 1410272cc70bSAndy Fleming 14112a4d212fSKishon Vijay Abraham I return mmc_set_ios(mmc); 1412272cc70bSAndy Fleming } 1413272cc70bSAndy Fleming 14144c9d2aaaSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG) 14154c9d2aaaSJean-Jacques Hiblot /* 14164c9d2aaaSJean-Jacques Hiblot * helper function to display the capabilities in a human 14174c9d2aaaSJean-Jacques Hiblot * friendly manner. The capabilities include bus width and 14184c9d2aaaSJean-Jacques Hiblot * supported modes. 14194c9d2aaaSJean-Jacques Hiblot */ 14204c9d2aaaSJean-Jacques Hiblot void mmc_dump_capabilities(const char *text, uint caps) 14214c9d2aaaSJean-Jacques Hiblot { 14224c9d2aaaSJean-Jacques Hiblot enum bus_mode mode; 14234c9d2aaaSJean-Jacques Hiblot 14244c9d2aaaSJean-Jacques Hiblot printf("%s: widths [", text); 14254c9d2aaaSJean-Jacques Hiblot if (caps & MMC_MODE_8BIT) 14264c9d2aaaSJean-Jacques Hiblot printf("8, "); 14274c9d2aaaSJean-Jacques Hiblot if (caps & MMC_MODE_4BIT) 14284c9d2aaaSJean-Jacques Hiblot printf("4, "); 1429d0c221feSJean-Jacques Hiblot if (caps & MMC_MODE_1BIT) 1430d0c221feSJean-Jacques Hiblot printf("1, "); 1431d0c221feSJean-Jacques Hiblot printf("\b\b] modes ["); 14324c9d2aaaSJean-Jacques Hiblot for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++) 14334c9d2aaaSJean-Jacques Hiblot if (MMC_CAP(mode) & caps) 14344c9d2aaaSJean-Jacques Hiblot printf("%s, ", mmc_mode_name(mode)); 14354c9d2aaaSJean-Jacques Hiblot printf("\b\b]\n"); 14364c9d2aaaSJean-Jacques Hiblot } 14374c9d2aaaSJean-Jacques Hiblot #endif 14384c9d2aaaSJean-Jacques Hiblot 1439d0c221feSJean-Jacques Hiblot struct mode_width_tuning { 1440d0c221feSJean-Jacques Hiblot enum bus_mode mode; 1441d0c221feSJean-Jacques Hiblot uint widths; 1442634d4849SKishon Vijay Abraham I uint tuning; 1443d0c221feSJean-Jacques Hiblot }; 1444d0c221feSJean-Jacques Hiblot 1445*bc1e3272SJean-Jacques Hiblot int mmc_voltage_to_mv(enum mmc_voltage voltage) 1446*bc1e3272SJean-Jacques Hiblot { 1447*bc1e3272SJean-Jacques Hiblot switch (voltage) { 1448*bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_000: return 0; 1449*bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_330: return 3300; 1450*bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_180: return 1800; 1451*bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_120: return 1200; 1452*bc1e3272SJean-Jacques Hiblot } 1453*bc1e3272SJean-Jacques Hiblot return -EINVAL; 1454*bc1e3272SJean-Jacques Hiblot } 1455*bc1e3272SJean-Jacques Hiblot 1456aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage) 1457aff5d3c8SKishon Vijay Abraham I { 1458*bc1e3272SJean-Jacques Hiblot int err; 1459*bc1e3272SJean-Jacques Hiblot 1460*bc1e3272SJean-Jacques Hiblot if (mmc->signal_voltage == signal_voltage) 1461*bc1e3272SJean-Jacques Hiblot return 0; 1462*bc1e3272SJean-Jacques Hiblot 1463aff5d3c8SKishon Vijay Abraham I mmc->signal_voltage = signal_voltage; 1464*bc1e3272SJean-Jacques Hiblot err = mmc_set_ios(mmc); 1465*bc1e3272SJean-Jacques Hiblot if (err) 1466*bc1e3272SJean-Jacques Hiblot debug("unable to set voltage (err %d)\n", err); 1467*bc1e3272SJean-Jacques Hiblot 1468*bc1e3272SJean-Jacques Hiblot return err; 1469aff5d3c8SKishon Vijay Abraham I } 1470aff5d3c8SKishon Vijay Abraham I 1471d0c221feSJean-Jacques Hiblot static const struct mode_width_tuning sd_modes_by_pref[] = { 1472d0c221feSJean-Jacques Hiblot { 1473c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR104, 1474c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1475c10b85d6SJean-Jacques Hiblot .tuning = MMC_CMD_SEND_TUNING_BLOCK 1476c10b85d6SJean-Jacques Hiblot }, 1477c10b85d6SJean-Jacques Hiblot { 1478c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR50, 1479c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1480c10b85d6SJean-Jacques Hiblot }, 1481c10b85d6SJean-Jacques Hiblot { 1482c10b85d6SJean-Jacques Hiblot .mode = UHS_DDR50, 1483c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1484c10b85d6SJean-Jacques Hiblot }, 1485c10b85d6SJean-Jacques Hiblot { 1486c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR25, 1487c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1488c10b85d6SJean-Jacques Hiblot }, 1489c10b85d6SJean-Jacques Hiblot { 1490d0c221feSJean-Jacques Hiblot .mode = SD_HS, 1491d0c221feSJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1492d0c221feSJean-Jacques Hiblot }, 1493d0c221feSJean-Jacques Hiblot { 1494c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR12, 1495c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1496c10b85d6SJean-Jacques Hiblot }, 1497c10b85d6SJean-Jacques Hiblot { 1498d0c221feSJean-Jacques Hiblot .mode = SD_LEGACY, 1499d0c221feSJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1500d0c221feSJean-Jacques Hiblot } 1501d0c221feSJean-Jacques Hiblot }; 1502d0c221feSJean-Jacques Hiblot 1503d0c221feSJean-Jacques Hiblot #define for_each_sd_mode_by_pref(caps, mwt) \ 1504d0c221feSJean-Jacques Hiblot for (mwt = sd_modes_by_pref;\ 1505d0c221feSJean-Jacques Hiblot mwt < sd_modes_by_pref + ARRAY_SIZE(sd_modes_by_pref);\ 1506d0c221feSJean-Jacques Hiblot mwt++) \ 1507d0c221feSJean-Jacques Hiblot if (caps & MMC_CAP(mwt->mode)) 1508d0c221feSJean-Jacques Hiblot 150901298da3SJean-Jacques Hiblot static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps) 15108ac8a263SJean-Jacques Hiblot { 15118ac8a263SJean-Jacques Hiblot int err; 1512d0c221feSJean-Jacques Hiblot uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT}; 1513d0c221feSJean-Jacques Hiblot const struct mode_width_tuning *mwt; 1514c10b85d6SJean-Jacques Hiblot bool uhs_en = (mmc->ocr & OCR_S18R) ? true : false; 1515c10b85d6SJean-Jacques Hiblot uint caps; 1516c10b85d6SJean-Jacques Hiblot 15178ac8a263SJean-Jacques Hiblot 15188ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */ 151901298da3SJean-Jacques Hiblot caps = card_caps & (mmc->host_caps | MMC_MODE_1BIT); 15208ac8a263SJean-Jacques Hiblot 1521c10b85d6SJean-Jacques Hiblot if (!uhs_en) 1522c10b85d6SJean-Jacques Hiblot caps &= ~UHS_CAPS; 1523c10b85d6SJean-Jacques Hiblot 1524c10b85d6SJean-Jacques Hiblot for_each_sd_mode_by_pref(caps, mwt) { 1525d0c221feSJean-Jacques Hiblot uint *w; 15268ac8a263SJean-Jacques Hiblot 1527d0c221feSJean-Jacques Hiblot for (w = widths; w < widths + ARRAY_SIZE(widths); w++) { 1528c10b85d6SJean-Jacques Hiblot if (*w & caps & mwt->widths) { 1529d0c221feSJean-Jacques Hiblot debug("trying mode %s width %d (at %d MHz)\n", 1530d0c221feSJean-Jacques Hiblot mmc_mode_name(mwt->mode), 1531d0c221feSJean-Jacques Hiblot bus_width(*w), 1532d0c221feSJean-Jacques Hiblot mmc_mode2freq(mmc, mwt->mode) / 1000000); 1533d0c221feSJean-Jacques Hiblot 1534d0c221feSJean-Jacques Hiblot /* configure the bus width (card + host) */ 1535d0c221feSJean-Jacques Hiblot err = sd_select_bus_width(mmc, bus_width(*w)); 15368ac8a263SJean-Jacques Hiblot if (err) 1537d0c221feSJean-Jacques Hiblot goto error; 1538d0c221feSJean-Jacques Hiblot mmc_set_bus_width(mmc, bus_width(*w)); 15398ac8a263SJean-Jacques Hiblot 1540d0c221feSJean-Jacques Hiblot /* configure the bus mode (card) */ 1541d0c221feSJean-Jacques Hiblot err = sd_set_card_speed(mmc, mwt->mode); 15428ac8a263SJean-Jacques Hiblot if (err) 1543d0c221feSJean-Jacques Hiblot goto error; 15448ac8a263SJean-Jacques Hiblot 1545d0c221feSJean-Jacques Hiblot /* configure the bus mode (host) */ 1546d0c221feSJean-Jacques Hiblot mmc_select_mode(mmc, mwt->mode); 154735f67820SKishon Vijay Abraham I mmc_set_clock(mmc, mmc->tran_speed, false); 15488ac8a263SJean-Jacques Hiblot 1549c10b85d6SJean-Jacques Hiblot /* execute tuning if needed */ 1550c10b85d6SJean-Jacques Hiblot if (mwt->tuning && !mmc_host_is_spi(mmc)) { 1551c10b85d6SJean-Jacques Hiblot err = mmc_execute_tuning(mmc, 1552c10b85d6SJean-Jacques Hiblot mwt->tuning); 1553c10b85d6SJean-Jacques Hiblot if (err) { 1554c10b85d6SJean-Jacques Hiblot debug("tuning failed\n"); 1555c10b85d6SJean-Jacques Hiblot goto error; 1556c10b85d6SJean-Jacques Hiblot } 1557c10b85d6SJean-Jacques Hiblot } 1558c10b85d6SJean-Jacques Hiblot 15598ac8a263SJean-Jacques Hiblot err = sd_read_ssr(mmc); 1560d0c221feSJean-Jacques Hiblot if (!err) 15618ac8a263SJean-Jacques Hiblot return 0; 1562d0c221feSJean-Jacques Hiblot 1563d0c221feSJean-Jacques Hiblot printf("bad ssr\n"); 1564d0c221feSJean-Jacques Hiblot 1565d0c221feSJean-Jacques Hiblot error: 1566d0c221feSJean-Jacques Hiblot /* revert to a safer bus speed */ 1567d0c221feSJean-Jacques Hiblot mmc_select_mode(mmc, SD_LEGACY); 156835f67820SKishon Vijay Abraham I mmc_set_clock(mmc, mmc->tran_speed, false); 1569d0c221feSJean-Jacques Hiblot } 1570d0c221feSJean-Jacques Hiblot } 1571d0c221feSJean-Jacques Hiblot } 1572d0c221feSJean-Jacques Hiblot 1573d0c221feSJean-Jacques Hiblot printf("unable to select a mode\n"); 1574d0c221feSJean-Jacques Hiblot return -ENOTSUPP; 15758ac8a263SJean-Jacques Hiblot } 15768ac8a263SJean-Jacques Hiblot 15777382e691SJean-Jacques Hiblot /* 15787382e691SJean-Jacques Hiblot * read the compare the part of ext csd that is constant. 15797382e691SJean-Jacques Hiblot * This can be used to check that the transfer is working 15807382e691SJean-Jacques Hiblot * as expected. 15817382e691SJean-Jacques Hiblot */ 15827382e691SJean-Jacques Hiblot static int mmc_read_and_compare_ext_csd(struct mmc *mmc) 15837382e691SJean-Jacques Hiblot { 15847382e691SJean-Jacques Hiblot int err; 15857382e691SJean-Jacques Hiblot const u8 *ext_csd = mmc->ext_csd; 15867382e691SJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 15877382e691SJean-Jacques Hiblot 15887382e691SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, test_csd); 15897382e691SJean-Jacques Hiblot if (err) 15907382e691SJean-Jacques Hiblot return err; 15917382e691SJean-Jacques Hiblot 15927382e691SJean-Jacques Hiblot /* Only compare read only fields */ 15937382e691SJean-Jacques Hiblot if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] 15947382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_PARTITIONING_SUPPORT] && 15957382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_WP_GRP_SIZE] 15967382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_WP_GRP_SIZE] && 15977382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_REV] 15987382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_REV] && 15997382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 16007382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] && 16017382e691SJean-Jacques Hiblot memcmp(&ext_csd[EXT_CSD_SEC_CNT], 16027382e691SJean-Jacques Hiblot &test_csd[EXT_CSD_SEC_CNT], 4) == 0) 16037382e691SJean-Jacques Hiblot return 0; 16047382e691SJean-Jacques Hiblot 16057382e691SJean-Jacques Hiblot return -EBADMSG; 16067382e691SJean-Jacques Hiblot } 16077382e691SJean-Jacques Hiblot 1608*bc1e3272SJean-Jacques Hiblot static int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode, 1609*bc1e3272SJean-Jacques Hiblot uint32_t allowed_mask) 1610*bc1e3272SJean-Jacques Hiblot { 1611*bc1e3272SJean-Jacques Hiblot u32 card_mask = 0; 1612*bc1e3272SJean-Jacques Hiblot 1613*bc1e3272SJean-Jacques Hiblot switch (mode) { 1614*bc1e3272SJean-Jacques Hiblot case MMC_HS_200: 1615*bc1e3272SJean-Jacques Hiblot if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_8V) 1616*bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_180; 1617*bc1e3272SJean-Jacques Hiblot if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_2V) 1618*bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_120; 1619*bc1e3272SJean-Jacques Hiblot break; 1620*bc1e3272SJean-Jacques Hiblot case MMC_DDR_52: 1621*bc1e3272SJean-Jacques Hiblot if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V) 1622*bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_330 | 1623*bc1e3272SJean-Jacques Hiblot MMC_SIGNAL_VOLTAGE_180; 1624*bc1e3272SJean-Jacques Hiblot if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_2V) 1625*bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_120; 1626*bc1e3272SJean-Jacques Hiblot break; 1627*bc1e3272SJean-Jacques Hiblot default: 1628*bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_330; 1629*bc1e3272SJean-Jacques Hiblot break; 1630*bc1e3272SJean-Jacques Hiblot } 1631*bc1e3272SJean-Jacques Hiblot 1632*bc1e3272SJean-Jacques Hiblot while (card_mask & allowed_mask) { 1633*bc1e3272SJean-Jacques Hiblot enum mmc_voltage best_match; 1634*bc1e3272SJean-Jacques Hiblot 1635*bc1e3272SJean-Jacques Hiblot best_match = 1 << (ffs(card_mask & allowed_mask) - 1); 1636*bc1e3272SJean-Jacques Hiblot if (!mmc_set_signal_voltage(mmc, best_match)) 1637*bc1e3272SJean-Jacques Hiblot return 0; 1638*bc1e3272SJean-Jacques Hiblot 1639*bc1e3272SJean-Jacques Hiblot allowed_mask &= ~best_match; 1640*bc1e3272SJean-Jacques Hiblot } 1641*bc1e3272SJean-Jacques Hiblot 1642*bc1e3272SJean-Jacques Hiblot return -ENOTSUPP; 1643*bc1e3272SJean-Jacques Hiblot } 1644*bc1e3272SJean-Jacques Hiblot 16453862b854SJean-Jacques Hiblot static const struct mode_width_tuning mmc_modes_by_pref[] = { 16468ac8a263SJean-Jacques Hiblot { 16473862b854SJean-Jacques Hiblot .mode = MMC_HS_200, 16483862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT, 1649634d4849SKishon Vijay Abraham I .tuning = MMC_CMD_SEND_TUNING_BLOCK_HS200 16503862b854SJean-Jacques Hiblot }, 16513862b854SJean-Jacques Hiblot { 16523862b854SJean-Jacques Hiblot .mode = MMC_DDR_52, 16533862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT, 16543862b854SJean-Jacques Hiblot }, 16553862b854SJean-Jacques Hiblot { 16563862b854SJean-Jacques Hiblot .mode = MMC_HS_52, 16573862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 16583862b854SJean-Jacques Hiblot }, 16593862b854SJean-Jacques Hiblot { 16603862b854SJean-Jacques Hiblot .mode = MMC_HS, 16613862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 16623862b854SJean-Jacques Hiblot }, 16633862b854SJean-Jacques Hiblot { 16643862b854SJean-Jacques Hiblot .mode = MMC_LEGACY, 16653862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 16663862b854SJean-Jacques Hiblot } 16678ac8a263SJean-Jacques Hiblot }; 16688ac8a263SJean-Jacques Hiblot 16693862b854SJean-Jacques Hiblot #define for_each_mmc_mode_by_pref(caps, mwt) \ 16703862b854SJean-Jacques Hiblot for (mwt = mmc_modes_by_pref;\ 16713862b854SJean-Jacques Hiblot mwt < mmc_modes_by_pref + ARRAY_SIZE(mmc_modes_by_pref);\ 16723862b854SJean-Jacques Hiblot mwt++) \ 16733862b854SJean-Jacques Hiblot if (caps & MMC_CAP(mwt->mode)) 16743862b854SJean-Jacques Hiblot 16753862b854SJean-Jacques Hiblot static const struct ext_csd_bus_width { 16763862b854SJean-Jacques Hiblot uint cap; 16773862b854SJean-Jacques Hiblot bool is_ddr; 16783862b854SJean-Jacques Hiblot uint ext_csd_bits; 16793862b854SJean-Jacques Hiblot } ext_csd_bus_width[] = { 16803862b854SJean-Jacques Hiblot {MMC_MODE_8BIT, true, EXT_CSD_DDR_BUS_WIDTH_8}, 16813862b854SJean-Jacques Hiblot {MMC_MODE_4BIT, true, EXT_CSD_DDR_BUS_WIDTH_4}, 16823862b854SJean-Jacques Hiblot {MMC_MODE_8BIT, false, EXT_CSD_BUS_WIDTH_8}, 16833862b854SJean-Jacques Hiblot {MMC_MODE_4BIT, false, EXT_CSD_BUS_WIDTH_4}, 16843862b854SJean-Jacques Hiblot {MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1}, 16853862b854SJean-Jacques Hiblot }; 16863862b854SJean-Jacques Hiblot 16873862b854SJean-Jacques Hiblot #define for_each_supported_width(caps, ddr, ecbv) \ 16883862b854SJean-Jacques Hiblot for (ecbv = ext_csd_bus_width;\ 16893862b854SJean-Jacques Hiblot ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\ 16903862b854SJean-Jacques Hiblot ecbv++) \ 16913862b854SJean-Jacques Hiblot if ((ddr == ecbv->is_ddr) && (caps & ecbv->cap)) 16923862b854SJean-Jacques Hiblot 169301298da3SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps) 16943862b854SJean-Jacques Hiblot { 16953862b854SJean-Jacques Hiblot int err; 16963862b854SJean-Jacques Hiblot const struct mode_width_tuning *mwt; 16973862b854SJean-Jacques Hiblot const struct ext_csd_bus_width *ecbw; 16983862b854SJean-Jacques Hiblot 16998ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */ 170001298da3SJean-Jacques Hiblot card_caps &= (mmc->host_caps | MMC_MODE_1BIT); 17018ac8a263SJean-Jacques Hiblot 17028ac8a263SJean-Jacques Hiblot /* Only version 4 of MMC supports wider bus widths */ 17038ac8a263SJean-Jacques Hiblot if (mmc->version < MMC_VERSION_4) 17048ac8a263SJean-Jacques Hiblot return 0; 17058ac8a263SJean-Jacques Hiblot 1706dfda9d88SJean-Jacques Hiblot if (!mmc->ext_csd) { 1707dfda9d88SJean-Jacques Hiblot debug("No ext_csd found!\n"); /* this should enver happen */ 1708dfda9d88SJean-Jacques Hiblot return -ENOTSUPP; 1709dfda9d88SJean-Jacques Hiblot } 1710dfda9d88SJean-Jacques Hiblot 171101298da3SJean-Jacques Hiblot mmc_set_clock(mmc, mmc->legacy_speed, false); 171201298da3SJean-Jacques Hiblot 171301298da3SJean-Jacques Hiblot for_each_mmc_mode_by_pref(card_caps, mwt) { 171401298da3SJean-Jacques Hiblot for_each_supported_width(card_caps & mwt->widths, 17153862b854SJean-Jacques Hiblot mmc_is_mode_ddr(mwt->mode), ecbw) { 1716*bc1e3272SJean-Jacques Hiblot enum mmc_voltage old_voltage; 17173862b854SJean-Jacques Hiblot debug("trying mode %s width %d (at %d MHz)\n", 17183862b854SJean-Jacques Hiblot mmc_mode_name(mwt->mode), 17193862b854SJean-Jacques Hiblot bus_width(ecbw->cap), 17203862b854SJean-Jacques Hiblot mmc_mode2freq(mmc, mwt->mode) / 1000000); 1721*bc1e3272SJean-Jacques Hiblot old_voltage = mmc->signal_voltage; 1722*bc1e3272SJean-Jacques Hiblot err = mmc_set_lowest_voltage(mmc, mwt->mode, 1723*bc1e3272SJean-Jacques Hiblot MMC_ALL_SIGNAL_VOLTAGE); 1724*bc1e3272SJean-Jacques Hiblot if (err) 1725*bc1e3272SJean-Jacques Hiblot continue; 1726*bc1e3272SJean-Jacques Hiblot 17273862b854SJean-Jacques Hiblot /* configure the bus width (card + host) */ 17283862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 17293862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, 17303862b854SJean-Jacques Hiblot ecbw->ext_csd_bits & ~EXT_CSD_DDR_FLAG); 17313862b854SJean-Jacques Hiblot if (err) 17323862b854SJean-Jacques Hiblot goto error; 17333862b854SJean-Jacques Hiblot mmc_set_bus_width(mmc, bus_width(ecbw->cap)); 17343862b854SJean-Jacques Hiblot 17353862b854SJean-Jacques Hiblot /* configure the bus speed (card) */ 17363862b854SJean-Jacques Hiblot err = mmc_set_card_speed(mmc, mwt->mode); 17373862b854SJean-Jacques Hiblot if (err) 17383862b854SJean-Jacques Hiblot goto error; 17393862b854SJean-Jacques Hiblot 17408ac8a263SJean-Jacques Hiblot /* 17413862b854SJean-Jacques Hiblot * configure the bus width AND the ddr mode (card) 17423862b854SJean-Jacques Hiblot * The host side will be taken care of in the next step 17438ac8a263SJean-Jacques Hiblot */ 17443862b854SJean-Jacques Hiblot if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) { 17453862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 17463862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, 17473862b854SJean-Jacques Hiblot ecbw->ext_csd_bits); 17483862b854SJean-Jacques Hiblot if (err) 17493862b854SJean-Jacques Hiblot goto error; 17508ac8a263SJean-Jacques Hiblot } 17518ac8a263SJean-Jacques Hiblot 17523862b854SJean-Jacques Hiblot /* configure the bus mode (host) */ 17533862b854SJean-Jacques Hiblot mmc_select_mode(mmc, mwt->mode); 175435f67820SKishon Vijay Abraham I mmc_set_clock(mmc, mmc->tran_speed, false); 17558ac8a263SJean-Jacques Hiblot 1756634d4849SKishon Vijay Abraham I /* execute tuning if needed */ 1757634d4849SKishon Vijay Abraham I if (mwt->tuning) { 1758634d4849SKishon Vijay Abraham I err = mmc_execute_tuning(mmc, mwt->tuning); 1759634d4849SKishon Vijay Abraham I if (err) { 1760634d4849SKishon Vijay Abraham I debug("tuning failed\n"); 1761634d4849SKishon Vijay Abraham I goto error; 1762634d4849SKishon Vijay Abraham I } 1763634d4849SKishon Vijay Abraham I } 1764634d4849SKishon Vijay Abraham I 17653862b854SJean-Jacques Hiblot /* do a transfer to check the configuration */ 17667382e691SJean-Jacques Hiblot err = mmc_read_and_compare_ext_csd(mmc); 17677382e691SJean-Jacques Hiblot if (!err) 17683862b854SJean-Jacques Hiblot return 0; 17693862b854SJean-Jacques Hiblot error: 1770*bc1e3272SJean-Jacques Hiblot mmc_set_signal_voltage(mmc, old_voltage); 17713862b854SJean-Jacques Hiblot /* if an error occured, revert to a safer bus mode */ 17723862b854SJean-Jacques Hiblot mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 17733862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1); 17743862b854SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_LEGACY); 17753862b854SJean-Jacques Hiblot mmc_set_bus_width(mmc, 1); 17763862b854SJean-Jacques Hiblot } 17778ac8a263SJean-Jacques Hiblot } 17788ac8a263SJean-Jacques Hiblot 17793862b854SJean-Jacques Hiblot printf("unable to select a mode\n"); 17808ac8a263SJean-Jacques Hiblot 17813862b854SJean-Jacques Hiblot return -ENOTSUPP; 17828ac8a263SJean-Jacques Hiblot } 17838ac8a263SJean-Jacques Hiblot 1784dfda9d88SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc) 1785c744b6f6SJean-Jacques Hiblot { 1786c744b6f6SJean-Jacques Hiblot int err, i; 1787c744b6f6SJean-Jacques Hiblot u64 capacity; 1788c744b6f6SJean-Jacques Hiblot bool has_parts = false; 1789c744b6f6SJean-Jacques Hiblot bool part_completed; 1790dfda9d88SJean-Jacques Hiblot u8 *ext_csd; 1791c744b6f6SJean-Jacques Hiblot 1792c744b6f6SJean-Jacques Hiblot if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4)) 1793c744b6f6SJean-Jacques Hiblot return 0; 1794c744b6f6SJean-Jacques Hiblot 1795dfda9d88SJean-Jacques Hiblot ext_csd = malloc_cache_aligned(MMC_MAX_BLOCK_LEN); 1796dfda9d88SJean-Jacques Hiblot if (!ext_csd) 1797dfda9d88SJean-Jacques Hiblot return -ENOMEM; 1798dfda9d88SJean-Jacques Hiblot 1799dfda9d88SJean-Jacques Hiblot mmc->ext_csd = ext_csd; 1800dfda9d88SJean-Jacques Hiblot 1801c744b6f6SJean-Jacques Hiblot /* check ext_csd version and capacity */ 1802c744b6f6SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, ext_csd); 1803c744b6f6SJean-Jacques Hiblot if (err) 1804c744b6f6SJean-Jacques Hiblot return err; 1805c744b6f6SJean-Jacques Hiblot if (ext_csd[EXT_CSD_REV] >= 2) { 1806c744b6f6SJean-Jacques Hiblot /* 1807c744b6f6SJean-Jacques Hiblot * According to the JEDEC Standard, the value of 1808c744b6f6SJean-Jacques Hiblot * ext_csd's capacity is valid if the value is more 1809c744b6f6SJean-Jacques Hiblot * than 2GB 1810c744b6f6SJean-Jacques Hiblot */ 1811c744b6f6SJean-Jacques Hiblot capacity = ext_csd[EXT_CSD_SEC_CNT] << 0 1812c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 1813c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 1814c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; 1815c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN; 1816c744b6f6SJean-Jacques Hiblot if ((capacity >> 20) > 2 * 1024) 1817c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity; 1818c744b6f6SJean-Jacques Hiblot } 1819c744b6f6SJean-Jacques Hiblot 1820c744b6f6SJean-Jacques Hiblot switch (ext_csd[EXT_CSD_REV]) { 1821c744b6f6SJean-Jacques Hiblot case 1: 1822c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_1; 1823c744b6f6SJean-Jacques Hiblot break; 1824c744b6f6SJean-Jacques Hiblot case 2: 1825c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_2; 1826c744b6f6SJean-Jacques Hiblot break; 1827c744b6f6SJean-Jacques Hiblot case 3: 1828c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_3; 1829c744b6f6SJean-Jacques Hiblot break; 1830c744b6f6SJean-Jacques Hiblot case 5: 1831c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_41; 1832c744b6f6SJean-Jacques Hiblot break; 1833c744b6f6SJean-Jacques Hiblot case 6: 1834c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_5; 1835c744b6f6SJean-Jacques Hiblot break; 1836c744b6f6SJean-Jacques Hiblot case 7: 1837c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_5_0; 1838c744b6f6SJean-Jacques Hiblot break; 1839c744b6f6SJean-Jacques Hiblot case 8: 1840c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_5_1; 1841c744b6f6SJean-Jacques Hiblot break; 1842c744b6f6SJean-Jacques Hiblot } 1843c744b6f6SJean-Jacques Hiblot 1844c744b6f6SJean-Jacques Hiblot /* The partition data may be non-zero but it is only 1845c744b6f6SJean-Jacques Hiblot * effective if PARTITION_SETTING_COMPLETED is set in 1846c744b6f6SJean-Jacques Hiblot * EXT_CSD, so ignore any data if this bit is not set, 1847c744b6f6SJean-Jacques Hiblot * except for enabling the high-capacity group size 1848c744b6f6SJean-Jacques Hiblot * definition (see below). 1849c744b6f6SJean-Jacques Hiblot */ 1850c744b6f6SJean-Jacques Hiblot part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] & 1851c744b6f6SJean-Jacques Hiblot EXT_CSD_PARTITION_SETTING_COMPLETED); 1852c744b6f6SJean-Jacques Hiblot 1853c744b6f6SJean-Jacques Hiblot /* store the partition info of emmc */ 1854c744b6f6SJean-Jacques Hiblot mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT]; 1855c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || 1856c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_BOOT_MULT]) 1857c744b6f6SJean-Jacques Hiblot mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; 1858c744b6f6SJean-Jacques Hiblot if (part_completed && 1859c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT)) 1860c744b6f6SJean-Jacques Hiblot mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]; 1861c744b6f6SJean-Jacques Hiblot 1862c744b6f6SJean-Jacques Hiblot mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17; 1863c744b6f6SJean-Jacques Hiblot 1864c744b6f6SJean-Jacques Hiblot mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17; 1865c744b6f6SJean-Jacques Hiblot 1866c744b6f6SJean-Jacques Hiblot for (i = 0; i < 4; i++) { 1867c744b6f6SJean-Jacques Hiblot int idx = EXT_CSD_GP_SIZE_MULT + i * 3; 1868c744b6f6SJean-Jacques Hiblot uint mult = (ext_csd[idx + 2] << 16) + 1869c744b6f6SJean-Jacques Hiblot (ext_csd[idx + 1] << 8) + ext_csd[idx]; 1870c744b6f6SJean-Jacques Hiblot if (mult) 1871c744b6f6SJean-Jacques Hiblot has_parts = true; 1872c744b6f6SJean-Jacques Hiblot if (!part_completed) 1873c744b6f6SJean-Jacques Hiblot continue; 1874c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] = mult; 1875c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= 1876c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1877c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1878c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] <<= 19; 1879c744b6f6SJean-Jacques Hiblot } 1880c744b6f6SJean-Jacques Hiblot 1881c744b6f6SJean-Jacques Hiblot if (part_completed) { 1882c744b6f6SJean-Jacques Hiblot mmc->enh_user_size = 1883c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) + 1884c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) + 1885c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_SIZE_MULT]; 1886c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 1887c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1888c744b6f6SJean-Jacques Hiblot mmc->enh_user_size <<= 19; 1889c744b6f6SJean-Jacques Hiblot mmc->enh_user_start = 1890c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) + 1891c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) + 1892c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) + 1893c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_START_ADDR]; 1894c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity) 1895c744b6f6SJean-Jacques Hiblot mmc->enh_user_start <<= 9; 1896c744b6f6SJean-Jacques Hiblot } 1897c744b6f6SJean-Jacques Hiblot 1898c744b6f6SJean-Jacques Hiblot /* 1899c744b6f6SJean-Jacques Hiblot * Host needs to enable ERASE_GRP_DEF bit if device is 1900c744b6f6SJean-Jacques Hiblot * partitioned. This bit will be lost every time after a reset 1901c744b6f6SJean-Jacques Hiblot * or power off. This will affect erase size. 1902c744b6f6SJean-Jacques Hiblot */ 1903c744b6f6SJean-Jacques Hiblot if (part_completed) 1904c744b6f6SJean-Jacques Hiblot has_parts = true; 1905c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) && 1906c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) 1907c744b6f6SJean-Jacques Hiblot has_parts = true; 1908c744b6f6SJean-Jacques Hiblot if (has_parts) { 1909c744b6f6SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1910c744b6f6SJean-Jacques Hiblot EXT_CSD_ERASE_GROUP_DEF, 1); 1911c744b6f6SJean-Jacques Hiblot 1912c744b6f6SJean-Jacques Hiblot if (err) 1913c744b6f6SJean-Jacques Hiblot return err; 1914c744b6f6SJean-Jacques Hiblot 1915c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 1916c744b6f6SJean-Jacques Hiblot } 1917c744b6f6SJean-Jacques Hiblot 1918c744b6f6SJean-Jacques Hiblot if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) { 1919c744b6f6SJean-Jacques Hiblot /* Read out group size from ext_csd */ 1920c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = 1921c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 1922c744b6f6SJean-Jacques Hiblot /* 1923c744b6f6SJean-Jacques Hiblot * if high capacity and partition setting completed 1924c744b6f6SJean-Jacques Hiblot * SEC_COUNT is valid even if it is smaller than 2 GiB 1925c744b6f6SJean-Jacques Hiblot * JEDEC Standard JESD84-B45, 6.2.4 1926c744b6f6SJean-Jacques Hiblot */ 1927c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity && part_completed) { 1928c744b6f6SJean-Jacques Hiblot capacity = (ext_csd[EXT_CSD_SEC_CNT]) | 1929c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) | 1930c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) | 1931c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 3] << 24); 1932c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN; 1933c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity; 1934c744b6f6SJean-Jacques Hiblot } 1935c744b6f6SJean-Jacques Hiblot } else { 1936c744b6f6SJean-Jacques Hiblot /* Calculate the group size from the csd value. */ 1937c744b6f6SJean-Jacques Hiblot int erase_gsz, erase_gmul; 1938c744b6f6SJean-Jacques Hiblot 1939c744b6f6SJean-Jacques Hiblot erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; 1940c744b6f6SJean-Jacques Hiblot erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; 1941c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = (erase_gsz + 1) 1942c744b6f6SJean-Jacques Hiblot * (erase_gmul + 1); 1943c744b6f6SJean-Jacques Hiblot } 1944c744b6f6SJean-Jacques Hiblot 1945c744b6f6SJean-Jacques Hiblot mmc->hc_wp_grp_size = 1024 1946c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 1947c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 1948c744b6f6SJean-Jacques Hiblot 1949c744b6f6SJean-Jacques Hiblot mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 1950c744b6f6SJean-Jacques Hiblot 1951c744b6f6SJean-Jacques Hiblot return 0; 1952c744b6f6SJean-Jacques Hiblot } 1953c744b6f6SJean-Jacques Hiblot 1954fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc) 1955272cc70bSAndy Fleming { 1956f866a46dSStephen Warren int err, i; 1957272cc70bSAndy Fleming uint mult, freq; 1958c744b6f6SJean-Jacques Hiblot u64 cmult, csize; 1959272cc70bSAndy Fleming struct mmc_cmd cmd; 1960c40fdca6SSimon Glass struct blk_desc *bdesc; 1961272cc70bSAndy Fleming 1962d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON 1963d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ 1964d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; 1965d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R1; 1966d52ebf10SThomas Chou cmd.cmdarg = 1; 1967d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 1968d52ebf10SThomas Chou if (err) 1969d52ebf10SThomas Chou return err; 1970d52ebf10SThomas Chou } 1971d52ebf10SThomas Chou #endif 1972d52ebf10SThomas Chou 1973272cc70bSAndy Fleming /* Put the Card in Identify Mode */ 1974d52ebf10SThomas Chou cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : 1975d52ebf10SThomas Chou MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ 1976272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 1977272cc70bSAndy Fleming cmd.cmdarg = 0; 1978272cc70bSAndy Fleming 1979272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1980272cc70bSAndy Fleming 198183dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS 198283dc4227SKishon Vijay Abraham I if (err && (mmc->quirks & MMC_QUIRK_RETRY_SEND_CID)) { 198383dc4227SKishon Vijay Abraham I int retries = 4; 198483dc4227SKishon Vijay Abraham I /* 198583dc4227SKishon Vijay Abraham I * It has been seen that SEND_CID may fail on the first 198683dc4227SKishon Vijay Abraham I * attempt, let's try a few more time 198783dc4227SKishon Vijay Abraham I */ 198883dc4227SKishon Vijay Abraham I do { 198983dc4227SKishon Vijay Abraham I err = mmc_send_cmd(mmc, &cmd, NULL); 199083dc4227SKishon Vijay Abraham I if (!err) 199183dc4227SKishon Vijay Abraham I break; 199283dc4227SKishon Vijay Abraham I } while (retries--); 199383dc4227SKishon Vijay Abraham I } 199483dc4227SKishon Vijay Abraham I #endif 199583dc4227SKishon Vijay Abraham I 1996272cc70bSAndy Fleming if (err) 1997272cc70bSAndy Fleming return err; 1998272cc70bSAndy Fleming 1999272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16); 2000272cc70bSAndy Fleming 2001272cc70bSAndy Fleming /* 2002272cc70bSAndy Fleming * For MMC cards, set the Relative Address. 2003272cc70bSAndy Fleming * For SD cards, get the Relatvie Address. 2004272cc70bSAndy Fleming * This also puts the cards into Standby State 2005272cc70bSAndy Fleming */ 2006d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 2007272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; 2008272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 2009272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6; 2010272cc70bSAndy Fleming 2011272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2012272cc70bSAndy Fleming 2013272cc70bSAndy Fleming if (err) 2014272cc70bSAndy Fleming return err; 2015272cc70bSAndy Fleming 2016272cc70bSAndy Fleming if (IS_SD(mmc)) 2017998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff; 2018d52ebf10SThomas Chou } 2019272cc70bSAndy Fleming 2020272cc70bSAndy Fleming /* Get the Card-Specific Data */ 2021272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD; 2022272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 2023272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 2024272cc70bSAndy Fleming 2025272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2026272cc70bSAndy Fleming 2027272cc70bSAndy Fleming if (err) 2028272cc70bSAndy Fleming return err; 2029272cc70bSAndy Fleming 2030998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0]; 2031998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1]; 2032998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2]; 2033998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3]; 2034272cc70bSAndy Fleming 2035272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) { 20360b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf; 2037272cc70bSAndy Fleming 2038272cc70bSAndy Fleming switch (version) { 2039272cc70bSAndy Fleming case 0: 2040272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 2041272cc70bSAndy Fleming break; 2042272cc70bSAndy Fleming case 1: 2043272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4; 2044272cc70bSAndy Fleming break; 2045272cc70bSAndy Fleming case 2: 2046272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2; 2047272cc70bSAndy Fleming break; 2048272cc70bSAndy Fleming case 3: 2049272cc70bSAndy Fleming mmc->version = MMC_VERSION_3; 2050272cc70bSAndy Fleming break; 2051272cc70bSAndy Fleming case 4: 2052272cc70bSAndy Fleming mmc->version = MMC_VERSION_4; 2053272cc70bSAndy Fleming break; 2054272cc70bSAndy Fleming default: 2055272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 2056272cc70bSAndy Fleming break; 2057272cc70bSAndy Fleming } 2058272cc70bSAndy Fleming } 2059272cc70bSAndy Fleming 2060272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */ 20610b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)]; 20620b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; 2063272cc70bSAndy Fleming 206435f9e196SJean-Jacques Hiblot mmc->legacy_speed = freq * mult; 206535f9e196SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_LEGACY); 2066272cc70bSAndy Fleming 2067ab71188cSMarkus Niebel mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); 2068998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); 2069272cc70bSAndy Fleming 2070272cc70bSAndy Fleming if (IS_SD(mmc)) 2071272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len; 2072272cc70bSAndy Fleming else 2073998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); 2074272cc70bSAndy Fleming 2075272cc70bSAndy Fleming if (mmc->high_capacity) { 2076272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16 2077272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16; 2078272cc70bSAndy Fleming cmult = 8; 2079272cc70bSAndy Fleming } else { 2080272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2 2081272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30; 2082272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15; 2083272cc70bSAndy Fleming } 2084272cc70bSAndy Fleming 2085f866a46dSStephen Warren mmc->capacity_user = (csize + 1) << (cmult + 2); 2086f866a46dSStephen Warren mmc->capacity_user *= mmc->read_bl_len; 2087f866a46dSStephen Warren mmc->capacity_boot = 0; 2088f866a46dSStephen Warren mmc->capacity_rpmb = 0; 2089f866a46dSStephen Warren for (i = 0; i < 4; i++) 2090f866a46dSStephen Warren mmc->capacity_gp[i] = 0; 2091272cc70bSAndy Fleming 20928bfa195eSSimon Glass if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN) 20938bfa195eSSimon Glass mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 2094272cc70bSAndy Fleming 20958bfa195eSSimon Glass if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) 20968bfa195eSSimon Glass mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 2097272cc70bSAndy Fleming 2098ab71188cSMarkus Niebel if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) { 2099ab71188cSMarkus Niebel cmd.cmdidx = MMC_CMD_SET_DSR; 2100ab71188cSMarkus Niebel cmd.cmdarg = (mmc->dsr & 0xffff) << 16; 2101ab71188cSMarkus Niebel cmd.resp_type = MMC_RSP_NONE; 2102ab71188cSMarkus Niebel if (mmc_send_cmd(mmc, &cmd, NULL)) 2103ab71188cSMarkus Niebel printf("MMC: SET_DSR failed\n"); 2104ab71188cSMarkus Niebel } 2105ab71188cSMarkus Niebel 2106272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */ 2107d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 2108272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD; 2109fe8f7066SAjay Bhargav cmd.resp_type = MMC_RSP_R1; 2110272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 2111272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2112272cc70bSAndy Fleming 2113272cc70bSAndy Fleming if (err) 2114272cc70bSAndy Fleming return err; 2115d52ebf10SThomas Chou } 2116272cc70bSAndy Fleming 2117e6f99a56SLei Wen /* 2118e6f99a56SLei Wen * For SD, its erase group is always one sector 2119e6f99a56SLei Wen */ 2120e6f99a56SLei Wen mmc->erase_grp_size = 1; 2121bc897b1dSLei Wen mmc->part_config = MMCPART_NOAVAILABLE; 2122c744b6f6SJean-Jacques Hiblot 2123dfda9d88SJean-Jacques Hiblot err = mmc_startup_v4(mmc); 21249cf199ebSDiego Santa Cruz if (err) 21259cf199ebSDiego Santa Cruz return err; 2126f866a46dSStephen Warren 2127c40fdca6SSimon Glass err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart); 2128f866a46dSStephen Warren if (err) 2129f866a46dSStephen Warren return err; 2130d23e2c09SSukumar Ghorai 213101298da3SJean-Jacques Hiblot if (IS_SD(mmc)) { 213201298da3SJean-Jacques Hiblot err = sd_get_capabilities(mmc); 213301298da3SJean-Jacques Hiblot if (err) 213401298da3SJean-Jacques Hiblot return err; 213501298da3SJean-Jacques Hiblot err = sd_select_mode_and_width(mmc, mmc->card_caps); 213601298da3SJean-Jacques Hiblot } else { 213701298da3SJean-Jacques Hiblot err = mmc_get_capabilities(mmc); 213801298da3SJean-Jacques Hiblot if (err) 213901298da3SJean-Jacques Hiblot return err; 214001298da3SJean-Jacques Hiblot mmc_select_mode_and_width(mmc, mmc->card_caps); 214101298da3SJean-Jacques Hiblot } 2142272cc70bSAndy Fleming 2143272cc70bSAndy Fleming if (err) 2144272cc70bSAndy Fleming return err; 2145272cc70bSAndy Fleming 214601298da3SJean-Jacques Hiblot mmc->best_mode = mmc->selected_mode; 2147272cc70bSAndy Fleming 21485af8f45cSAndrew Gabbasov /* Fix the block length for DDR mode */ 21495af8f45cSAndrew Gabbasov if (mmc->ddr_mode) { 21505af8f45cSAndrew Gabbasov mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 21515af8f45cSAndrew Gabbasov mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 21525af8f45cSAndrew Gabbasov } 21535af8f45cSAndrew Gabbasov 2154272cc70bSAndy Fleming /* fill in device description */ 2155c40fdca6SSimon Glass bdesc = mmc_get_blk_desc(mmc); 2156c40fdca6SSimon Glass bdesc->lun = 0; 2157c40fdca6SSimon Glass bdesc->hwpart = 0; 2158c40fdca6SSimon Glass bdesc->type = 0; 2159c40fdca6SSimon Glass bdesc->blksz = mmc->read_bl_len; 2160c40fdca6SSimon Glass bdesc->log2blksz = LOG2(bdesc->blksz); 2161c40fdca6SSimon Glass bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len); 2162fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \ 2163fc011f64SSjoerd Simons (defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \ 2164fc011f64SSjoerd Simons !defined(CONFIG_USE_TINY_PRINTF)) 2165c40fdca6SSimon Glass sprintf(bdesc->vendor, "Man %06x Snr %04x%04x", 2166babce5f6STaylor Hutt mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), 2167babce5f6STaylor Hutt (mmc->cid[3] >> 16) & 0xffff); 2168c40fdca6SSimon Glass sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff, 21690b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 2170babce5f6STaylor Hutt (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff, 2171babce5f6STaylor Hutt (mmc->cid[2] >> 24) & 0xff); 2172c40fdca6SSimon Glass sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf, 2173babce5f6STaylor Hutt (mmc->cid[2] >> 16) & 0xf); 217456196826SPaul Burton #else 2175c40fdca6SSimon Glass bdesc->vendor[0] = 0; 2176c40fdca6SSimon Glass bdesc->product[0] = 0; 2177c40fdca6SSimon Glass bdesc->revision[0] = 0; 217856196826SPaul Burton #endif 2179122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT) 2180c40fdca6SSimon Glass part_init(bdesc); 2181122efd43SMikhail Kshevetskiy #endif 2182272cc70bSAndy Fleming 2183272cc70bSAndy Fleming return 0; 2184272cc70bSAndy Fleming } 2185272cc70bSAndy Fleming 2186fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc) 2187272cc70bSAndy Fleming { 2188272cc70bSAndy Fleming struct mmc_cmd cmd; 2189272cc70bSAndy Fleming int err; 2190272cc70bSAndy Fleming 2191272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND; 2192272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ 219393bfd616SPantelis Antoniou cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa; 2194272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7; 2195272cc70bSAndy Fleming 2196272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2197272cc70bSAndy Fleming 2198272cc70bSAndy Fleming if (err) 2199272cc70bSAndy Fleming return err; 2200272cc70bSAndy Fleming 2201998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa) 2202915ffa52SJaehoon Chung return -EOPNOTSUPP; 2203272cc70bSAndy Fleming else 2204272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 2205272cc70bSAndy Fleming 2206272cc70bSAndy Fleming return 0; 2207272cc70bSAndy Fleming } 2208272cc70bSAndy Fleming 2209c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 221095de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */ 221195de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void) 221295de9ab2SPaul Kocialkowski { 221395de9ab2SPaul Kocialkowski } 221405cbeb7cSSimon Glass #endif 221595de9ab2SPaul Kocialkowski 22162051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc) 22172051aefeSPeng Fan { 2218c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 221906ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR) 22202051aefeSPeng Fan int ret; 22212051aefeSPeng Fan 22222051aefeSPeng Fan ret = device_get_supply_regulator(mmc->dev, "vmmc-supply", 222306ec045fSJean-Jacques Hiblot &mmc->vmmc_supply); 222406ec045fSJean-Jacques Hiblot if (ret) 2225288db7c7SJaehoon Chung debug("%s: No vmmc supply\n", mmc->dev->name); 22262051aefeSPeng Fan 222706ec045fSJean-Jacques Hiblot ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply", 222806ec045fSJean-Jacques Hiblot &mmc->vqmmc_supply); 222906ec045fSJean-Jacques Hiblot if (ret) 223006ec045fSJean-Jacques Hiblot debug("%s: No vqmmc supply\n", mmc->dev->name); 22312051aefeSPeng Fan #endif 223205cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */ 223305cbeb7cSSimon Glass /* 223405cbeb7cSSimon Glass * Driver model should use a regulator, as above, rather than calling 223505cbeb7cSSimon Glass * out to board code. 223605cbeb7cSSimon Glass */ 223705cbeb7cSSimon Glass board_mmc_power_init(); 223805cbeb7cSSimon Glass #endif 22392051aefeSPeng Fan return 0; 22402051aefeSPeng Fan } 22412051aefeSPeng Fan 2242fb7c3bebSKishon Vijay Abraham I /* 2243fb7c3bebSKishon Vijay Abraham I * put the host in the initial state: 2244fb7c3bebSKishon Vijay Abraham I * - turn on Vdd (card power supply) 2245fb7c3bebSKishon Vijay Abraham I * - configure the bus width and clock to minimal values 2246fb7c3bebSKishon Vijay Abraham I */ 2247fb7c3bebSKishon Vijay Abraham I static void mmc_set_initial_state(struct mmc *mmc) 2248fb7c3bebSKishon Vijay Abraham I { 2249fb7c3bebSKishon Vijay Abraham I int err; 2250fb7c3bebSKishon Vijay Abraham I 2251fb7c3bebSKishon Vijay Abraham I /* First try to set 3.3V. If it fails set to 1.8V */ 2252fb7c3bebSKishon Vijay Abraham I err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_330); 2253fb7c3bebSKishon Vijay Abraham I if (err != 0) 2254fb7c3bebSKishon Vijay Abraham I err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_180); 2255fb7c3bebSKishon Vijay Abraham I if (err != 0) 2256fb7c3bebSKishon Vijay Abraham I printf("mmc: failed to set signal voltage\n"); 2257fb7c3bebSKishon Vijay Abraham I 2258fb7c3bebSKishon Vijay Abraham I mmc_select_mode(mmc, MMC_LEGACY); 2259fb7c3bebSKishon Vijay Abraham I mmc_set_bus_width(mmc, 1); 226035f67820SKishon Vijay Abraham I mmc_set_clock(mmc, 0, false); 2261fb7c3bebSKishon Vijay Abraham I } 2262fb7c3bebSKishon Vijay Abraham I 2263fb7c3bebSKishon Vijay Abraham I static int mmc_power_on(struct mmc *mmc) 2264fb7c3bebSKishon Vijay Abraham I { 2265fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR) 2266fb7c3bebSKishon Vijay Abraham I if (mmc->vmmc_supply) { 2267fb7c3bebSKishon Vijay Abraham I int ret = regulator_set_enable(mmc->vmmc_supply, true); 2268fb7c3bebSKishon Vijay Abraham I 2269fb7c3bebSKishon Vijay Abraham I if (ret) { 2270fb7c3bebSKishon Vijay Abraham I puts("Error enabling VMMC supply\n"); 2271fb7c3bebSKishon Vijay Abraham I return ret; 2272fb7c3bebSKishon Vijay Abraham I } 2273fb7c3bebSKishon Vijay Abraham I } 2274fb7c3bebSKishon Vijay Abraham I #endif 2275fb7c3bebSKishon Vijay Abraham I return 0; 2276fb7c3bebSKishon Vijay Abraham I } 2277fb7c3bebSKishon Vijay Abraham I 2278fb7c3bebSKishon Vijay Abraham I static int mmc_power_off(struct mmc *mmc) 2279fb7c3bebSKishon Vijay Abraham I { 22802e7410d7SKishon Vijay Abraham I mmc_set_clock(mmc, 1, true); 2281fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR) 2282fb7c3bebSKishon Vijay Abraham I if (mmc->vmmc_supply) { 2283fb7c3bebSKishon Vijay Abraham I int ret = regulator_set_enable(mmc->vmmc_supply, false); 2284fb7c3bebSKishon Vijay Abraham I 2285fb7c3bebSKishon Vijay Abraham I if (ret) { 2286c10b85d6SJean-Jacques Hiblot debug("Error disabling VMMC supply\n"); 2287fb7c3bebSKishon Vijay Abraham I return ret; 2288fb7c3bebSKishon Vijay Abraham I } 2289fb7c3bebSKishon Vijay Abraham I } 2290fb7c3bebSKishon Vijay Abraham I #endif 2291fb7c3bebSKishon Vijay Abraham I return 0; 2292fb7c3bebSKishon Vijay Abraham I } 2293fb7c3bebSKishon Vijay Abraham I 2294fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc) 2295fb7c3bebSKishon Vijay Abraham I { 2296fb7c3bebSKishon Vijay Abraham I int ret; 2297fb7c3bebSKishon Vijay Abraham I 2298fb7c3bebSKishon Vijay Abraham I ret = mmc_power_off(mmc); 2299fb7c3bebSKishon Vijay Abraham I if (ret) 2300fb7c3bebSKishon Vijay Abraham I return ret; 2301fb7c3bebSKishon Vijay Abraham I /* 2302fb7c3bebSKishon Vijay Abraham I * SD spec recommends at least 1ms of delay. Let's wait for 2ms 2303fb7c3bebSKishon Vijay Abraham I * to be on the safer side. 2304fb7c3bebSKishon Vijay Abraham I */ 2305fb7c3bebSKishon Vijay Abraham I udelay(2000); 2306fb7c3bebSKishon Vijay Abraham I return mmc_power_on(mmc); 2307fb7c3bebSKishon Vijay Abraham I } 2308fb7c3bebSKishon Vijay Abraham I 2309e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc) 2310272cc70bSAndy Fleming { 23118ca51e51SSimon Glass bool no_card; 2312c10b85d6SJean-Jacques Hiblot bool uhs_en = supports_uhs(mmc->cfg->host_caps); 2313afd5932bSMacpaul Lin int err; 2314272cc70bSAndy Fleming 231504a2ea24SJean-Jacques Hiblot mmc->host_caps = mmc->cfg->host_caps; 231604a2ea24SJean-Jacques Hiblot 2317ab769f22SPantelis Antoniou /* we pretend there's no card when init is NULL */ 23188ca51e51SSimon Glass no_card = mmc_getcd(mmc) == 0; 2319e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 23208ca51e51SSimon Glass no_card = no_card || (mmc->cfg->ops->init == NULL); 23218ca51e51SSimon Glass #endif 23228ca51e51SSimon Glass if (no_card) { 232348972d90SThierry Reding mmc->has_init = 0; 232456196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 232548972d90SThierry Reding printf("MMC: no card present\n"); 232656196826SPaul Burton #endif 2327915ffa52SJaehoon Chung return -ENOMEDIUM; 232848972d90SThierry Reding } 232948972d90SThierry Reding 2330bc897b1dSLei Wen if (mmc->has_init) 2331bc897b1dSLei Wen return 0; 2332bc897b1dSLei Wen 23335a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 23345a8dbdc6SYangbo Lu mmc_adapter_card_type_ident(); 23355a8dbdc6SYangbo Lu #endif 23362051aefeSPeng Fan err = mmc_power_init(mmc); 23372051aefeSPeng Fan if (err) 23382051aefeSPeng Fan return err; 233995de9ab2SPaul Kocialkowski 234083dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS 234183dc4227SKishon Vijay Abraham I mmc->quirks = MMC_QUIRK_RETRY_SET_BLOCKLEN | 234283dc4227SKishon Vijay Abraham I MMC_QUIRK_RETRY_SEND_CID; 234383dc4227SKishon Vijay Abraham I #endif 234483dc4227SKishon Vijay Abraham I 234504a2ea24SJean-Jacques Hiblot err = mmc_power_cycle(mmc); 234604a2ea24SJean-Jacques Hiblot if (err) { 234704a2ea24SJean-Jacques Hiblot /* 234804a2ea24SJean-Jacques Hiblot * if power cycling is not supported, we should not try 234904a2ea24SJean-Jacques Hiblot * to use the UHS modes, because we wouldn't be able to 235004a2ea24SJean-Jacques Hiblot * recover from an error during the UHS initialization. 235104a2ea24SJean-Jacques Hiblot */ 235204a2ea24SJean-Jacques Hiblot debug("Unable to do a full power cycle. Disabling the UHS modes for safety\n"); 235304a2ea24SJean-Jacques Hiblot uhs_en = false; 235404a2ea24SJean-Jacques Hiblot mmc->host_caps &= ~UHS_CAPS; 2355fb7c3bebSKishon Vijay Abraham I err = mmc_power_on(mmc); 235604a2ea24SJean-Jacques Hiblot } 2357fb7c3bebSKishon Vijay Abraham I if (err) 2358fb7c3bebSKishon Vijay Abraham I return err; 2359fb7c3bebSKishon Vijay Abraham I 2360e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 23618ca51e51SSimon Glass /* The device has already been probed ready for use */ 23628ca51e51SSimon Glass #else 2363ab769f22SPantelis Antoniou /* made sure it's not NULL earlier */ 236493bfd616SPantelis Antoniou err = mmc->cfg->ops->init(mmc); 2365272cc70bSAndy Fleming if (err) 2366272cc70bSAndy Fleming return err; 23678ca51e51SSimon Glass #endif 2368786e8f81SAndrew Gabbasov mmc->ddr_mode = 0; 2369aff5d3c8SKishon Vijay Abraham I 2370c10b85d6SJean-Jacques Hiblot retry: 2371fb7c3bebSKishon Vijay Abraham I mmc_set_initial_state(mmc); 2372318a7a57SJean-Jacques Hiblot mmc_send_init_stream(mmc); 2373318a7a57SJean-Jacques Hiblot 2374272cc70bSAndy Fleming /* Reset the Card */ 2375272cc70bSAndy Fleming err = mmc_go_idle(mmc); 2376272cc70bSAndy Fleming 2377272cc70bSAndy Fleming if (err) 2378272cc70bSAndy Fleming return err; 2379272cc70bSAndy Fleming 2380bc897b1dSLei Wen /* The internal partition reset to user partition(0) at every CMD0*/ 2381c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->hwpart = 0; 2382bc897b1dSLei Wen 2383272cc70bSAndy Fleming /* Test for SD version 2 */ 2384272cc70bSAndy Fleming err = mmc_send_if_cond(mmc); 2385272cc70bSAndy Fleming 2386272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */ 2387c10b85d6SJean-Jacques Hiblot err = sd_send_op_cond(mmc, uhs_en); 2388c10b85d6SJean-Jacques Hiblot if (err && uhs_en) { 2389c10b85d6SJean-Jacques Hiblot uhs_en = false; 2390c10b85d6SJean-Jacques Hiblot mmc_power_cycle(mmc); 2391c10b85d6SJean-Jacques Hiblot goto retry; 2392c10b85d6SJean-Jacques Hiblot } 2393272cc70bSAndy Fleming 2394272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */ 2395915ffa52SJaehoon Chung if (err == -ETIMEDOUT) { 2396272cc70bSAndy Fleming err = mmc_send_op_cond(mmc); 2397272cc70bSAndy Fleming 2398bd47c135SAndrew Gabbasov if (err) { 239956196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2400272cc70bSAndy Fleming printf("Card did not respond to voltage select!\n"); 240156196826SPaul Burton #endif 2402915ffa52SJaehoon Chung return -EOPNOTSUPP; 2403272cc70bSAndy Fleming } 2404272cc70bSAndy Fleming } 2405272cc70bSAndy Fleming 2406bd47c135SAndrew Gabbasov if (!err) 2407e9550449SChe-Liang Chiou mmc->init_in_progress = 1; 2408e9550449SChe-Liang Chiou 2409e9550449SChe-Liang Chiou return err; 2410e9550449SChe-Liang Chiou } 2411e9550449SChe-Liang Chiou 2412e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc) 2413e9550449SChe-Liang Chiou { 2414e9550449SChe-Liang Chiou int err = 0; 2415e9550449SChe-Liang Chiou 2416bd47c135SAndrew Gabbasov mmc->init_in_progress = 0; 2417e9550449SChe-Liang Chiou if (mmc->op_cond_pending) 2418e9550449SChe-Liang Chiou err = mmc_complete_op_cond(mmc); 2419e9550449SChe-Liang Chiou 2420e9550449SChe-Liang Chiou if (!err) 2421bc897b1dSLei Wen err = mmc_startup(mmc); 2422bc897b1dSLei Wen if (err) 2423bc897b1dSLei Wen mmc->has_init = 0; 2424bc897b1dSLei Wen else 2425bc897b1dSLei Wen mmc->has_init = 1; 2426e9550449SChe-Liang Chiou return err; 2427e9550449SChe-Liang Chiou } 2428e9550449SChe-Liang Chiou 2429e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc) 2430e9550449SChe-Liang Chiou { 2431bd47c135SAndrew Gabbasov int err = 0; 2432ce9eca94SMarek Vasut __maybe_unused unsigned start; 2433c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 243433fb211dSSimon Glass struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev); 2435e9550449SChe-Liang Chiou 243633fb211dSSimon Glass upriv->mmc = mmc; 243733fb211dSSimon Glass #endif 2438e9550449SChe-Liang Chiou if (mmc->has_init) 2439e9550449SChe-Liang Chiou return 0; 2440d803fea5SMateusz Zalega 2441d803fea5SMateusz Zalega start = get_timer(0); 2442d803fea5SMateusz Zalega 2443e9550449SChe-Liang Chiou if (!mmc->init_in_progress) 2444e9550449SChe-Liang Chiou err = mmc_start_init(mmc); 2445e9550449SChe-Liang Chiou 2446bd47c135SAndrew Gabbasov if (!err) 2447e9550449SChe-Liang Chiou err = mmc_complete_init(mmc); 2448919b4858SJagan Teki if (err) 2449919b4858SJagan Teki printf("%s: %d, time %lu\n", __func__, err, get_timer(start)); 2450919b4858SJagan Teki 2451bc897b1dSLei Wen return err; 2452272cc70bSAndy Fleming } 2453272cc70bSAndy Fleming 2454ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val) 2455ab71188cSMarkus Niebel { 2456ab71188cSMarkus Niebel mmc->dsr = val; 2457ab71188cSMarkus Niebel return 0; 2458ab71188cSMarkus Niebel } 2459ab71188cSMarkus Niebel 2460cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */ 2461cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis) 2462272cc70bSAndy Fleming { 2463272cc70bSAndy Fleming return -1; 2464272cc70bSAndy Fleming } 2465272cc70bSAndy Fleming 2466cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */ 2467cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis) 2468cee9ab7cSJeroen Hofstee { 2469cee9ab7cSJeroen Hofstee return -1; 2470cee9ab7cSJeroen Hofstee } 2471272cc70bSAndy Fleming 2472e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit) 2473e9550449SChe-Liang Chiou { 2474e9550449SChe-Liang Chiou mmc->preinit = preinit; 2475e9550449SChe-Liang Chiou } 2476e9550449SChe-Liang Chiou 2477c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD) 24788e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 24798e3332e2SSjoerd Simons { 24808e3332e2SSjoerd Simons return 0; 24818e3332e2SSjoerd Simons } 2482c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC) 24838e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 24848e3332e2SSjoerd Simons { 24854a1db6d8SSimon Glass int ret, i; 24868e3332e2SSjoerd Simons struct uclass *uc; 24874a1db6d8SSimon Glass struct udevice *dev; 24888e3332e2SSjoerd Simons 24898e3332e2SSjoerd Simons ret = uclass_get(UCLASS_MMC, &uc); 24908e3332e2SSjoerd Simons if (ret) 24918e3332e2SSjoerd Simons return ret; 24928e3332e2SSjoerd Simons 24934a1db6d8SSimon Glass /* 24944a1db6d8SSimon Glass * Try to add them in sequence order. Really with driver model we 24954a1db6d8SSimon Glass * should allow holes, but the current MMC list does not allow that. 24964a1db6d8SSimon Glass * So if we request 0, 1, 3 we will get 0, 1, 2. 24974a1db6d8SSimon Glass */ 24984a1db6d8SSimon Glass for (i = 0; ; i++) { 24994a1db6d8SSimon Glass ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev); 25004a1db6d8SSimon Glass if (ret == -ENODEV) 25014a1db6d8SSimon Glass break; 25024a1db6d8SSimon Glass } 25034a1db6d8SSimon Glass uclass_foreach_dev(dev, uc) { 25044a1db6d8SSimon Glass ret = device_probe(dev); 25058e3332e2SSjoerd Simons if (ret) 25064a1db6d8SSimon Glass printf("%s - probe failed: %d\n", dev->name, ret); 25078e3332e2SSjoerd Simons } 25088e3332e2SSjoerd Simons 25098e3332e2SSjoerd Simons return 0; 25108e3332e2SSjoerd Simons } 25118e3332e2SSjoerd Simons #else 25128e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 25138e3332e2SSjoerd Simons { 25148e3332e2SSjoerd Simons if (board_mmc_init(bis) < 0) 25158e3332e2SSjoerd Simons cpu_mmc_init(bis); 25168e3332e2SSjoerd Simons 25178e3332e2SSjoerd Simons return 0; 25188e3332e2SSjoerd Simons } 25198e3332e2SSjoerd Simons #endif 2520e9550449SChe-Liang Chiou 2521272cc70bSAndy Fleming int mmc_initialize(bd_t *bis) 2522272cc70bSAndy Fleming { 25231b26bab1SDaniel Kochmański static int initialized = 0; 25248e3332e2SSjoerd Simons int ret; 25251b26bab1SDaniel Kochmański if (initialized) /* Avoid initializing mmc multiple times */ 25261b26bab1SDaniel Kochmański return 0; 25271b26bab1SDaniel Kochmański initialized = 1; 25281b26bab1SDaniel Kochmański 2529c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK) 2530b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY) 2531c40fdca6SSimon Glass mmc_list_init(); 2532c40fdca6SSimon Glass #endif 2533b5b838f1SMarek Vasut #endif 25348e3332e2SSjoerd Simons ret = mmc_probe(bis); 25358e3332e2SSjoerd Simons if (ret) 25368e3332e2SSjoerd Simons return ret; 2537272cc70bSAndy Fleming 2538bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD 2539272cc70bSAndy Fleming print_mmc_devices(','); 2540bb0dc108SYing Zhang #endif 2541272cc70bSAndy Fleming 2542c40fdca6SSimon Glass mmc_do_preinit(); 2543272cc70bSAndy Fleming return 0; 2544272cc70bSAndy Fleming } 2545cd3d4880STomas Melin 2546cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE 2547cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc) 2548cd3d4880STomas Melin { 2549cd3d4880STomas Melin int err; 2550cd3d4880STomas Melin ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 2551cd3d4880STomas Melin 2552cd3d4880STomas Melin err = mmc_send_ext_csd(mmc, ext_csd); 2553cd3d4880STomas Melin if (err) { 2554cd3d4880STomas Melin puts("Could not get ext_csd register values\n"); 2555cd3d4880STomas Melin return err; 2556cd3d4880STomas Melin } 2557cd3d4880STomas Melin 2558cd3d4880STomas Melin if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) { 2559cd3d4880STomas Melin puts("Background operations not supported on device\n"); 2560cd3d4880STomas Melin return -EMEDIUMTYPE; 2561cd3d4880STomas Melin } 2562cd3d4880STomas Melin 2563cd3d4880STomas Melin if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) { 2564cd3d4880STomas Melin puts("Background operations already enabled\n"); 2565cd3d4880STomas Melin return 0; 2566cd3d4880STomas Melin } 2567cd3d4880STomas Melin 2568cd3d4880STomas Melin err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1); 2569cd3d4880STomas Melin if (err) { 2570cd3d4880STomas Melin puts("Failed to enable manual background operations\n"); 2571cd3d4880STomas Melin return err; 2572cd3d4880STomas Melin } 2573cd3d4880STomas Melin 2574cd3d4880STomas Melin puts("Enabled manual background operations\n"); 2575cd3d4880STomas Melin 2576cd3d4880STomas Melin return 0; 2577cd3d4880STomas Melin } 2578cd3d4880STomas Melin #endif 2579