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 62f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 63c10b85d6SJean-Jacques Hiblot static int mmc_wait_dat0(struct mmc *mmc, int state, int timeout) 64c10b85d6SJean-Jacques Hiblot { 65c10b85d6SJean-Jacques Hiblot return -ENOSYS; 66c10b85d6SJean-Jacques Hiblot } 67f99c2efeSJean-Jacques Hiblot #endif 68c10b85d6SJean-Jacques Hiblot 69750121c3SJeroen Hofstee __weak int board_mmc_getwp(struct mmc *mmc) 70d23d8d7eSNikita Kiryanov { 71d23d8d7eSNikita Kiryanov return -1; 72d23d8d7eSNikita Kiryanov } 73d23d8d7eSNikita Kiryanov 74d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc) 75d23d8d7eSNikita Kiryanov { 76d23d8d7eSNikita Kiryanov int wp; 77d23d8d7eSNikita Kiryanov 78d23d8d7eSNikita Kiryanov wp = board_mmc_getwp(mmc); 79d23d8d7eSNikita Kiryanov 80d4e1da4eSPeter Korsgaard if (wp < 0) { 8193bfd616SPantelis Antoniou if (mmc->cfg->ops->getwp) 8293bfd616SPantelis Antoniou wp = mmc->cfg->ops->getwp(mmc); 83d4e1da4eSPeter Korsgaard else 84d4e1da4eSPeter Korsgaard wp = 0; 85d4e1da4eSPeter Korsgaard } 86d23d8d7eSNikita Kiryanov 87d23d8d7eSNikita Kiryanov return wp; 88d23d8d7eSNikita Kiryanov } 89d23d8d7eSNikita Kiryanov 90cee9ab7cSJeroen Hofstee __weak int board_mmc_getcd(struct mmc *mmc) 91cee9ab7cSJeroen Hofstee { 9211fdade2SStefano Babic return -1; 9311fdade2SStefano Babic } 948ca51e51SSimon Glass #endif 9511fdade2SStefano Babic 968635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE 97c0c76ebaSSimon Glass void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd) 98c0c76ebaSSimon Glass { 99c0c76ebaSSimon Glass printf("CMD_SEND:%d\n", cmd->cmdidx); 100c0c76ebaSSimon Glass printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg); 101c0c76ebaSSimon Glass } 102c0c76ebaSSimon Glass 103c0c76ebaSSimon Glass void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret) 104c0c76ebaSSimon Glass { 1055db2fe3aSRaffaele Recalcati int i; 1065db2fe3aSRaffaele Recalcati u8 *ptr; 1075db2fe3aSRaffaele Recalcati 1087863ce58SBin Meng if (ret) { 1097863ce58SBin Meng printf("\t\tRET\t\t\t %d\n", ret); 1107863ce58SBin Meng } else { 1115db2fe3aSRaffaele Recalcati switch (cmd->resp_type) { 1125db2fe3aSRaffaele Recalcati case MMC_RSP_NONE: 1135db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_NONE\n"); 1145db2fe3aSRaffaele Recalcati break; 1155db2fe3aSRaffaele Recalcati case MMC_RSP_R1: 1165db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n", 1175db2fe3aSRaffaele Recalcati cmd->response[0]); 1185db2fe3aSRaffaele Recalcati break; 1195db2fe3aSRaffaele Recalcati case MMC_RSP_R1b: 1205db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n", 1215db2fe3aSRaffaele Recalcati cmd->response[0]); 1225db2fe3aSRaffaele Recalcati break; 1235db2fe3aSRaffaele Recalcati case MMC_RSP_R2: 1245db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R2\t\t 0x%08X \n", 1255db2fe3aSRaffaele Recalcati cmd->response[0]); 1265db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1275db2fe3aSRaffaele Recalcati cmd->response[1]); 1285db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1295db2fe3aSRaffaele Recalcati cmd->response[2]); 1305db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1315db2fe3aSRaffaele Recalcati cmd->response[3]); 1325db2fe3aSRaffaele Recalcati printf("\n"); 1335db2fe3aSRaffaele Recalcati printf("\t\t\t\t\tDUMPING DATA\n"); 1345db2fe3aSRaffaele Recalcati for (i = 0; i < 4; i++) { 1355db2fe3aSRaffaele Recalcati int j; 1365db2fe3aSRaffaele Recalcati printf("\t\t\t\t\t%03d - ", i*4); 137146bec79SDirk Behme ptr = (u8 *)&cmd->response[i]; 1385db2fe3aSRaffaele Recalcati ptr += 3; 1395db2fe3aSRaffaele Recalcati for (j = 0; j < 4; j++) 1405db2fe3aSRaffaele Recalcati printf("%02X ", *ptr--); 1415db2fe3aSRaffaele Recalcati printf("\n"); 1425db2fe3aSRaffaele Recalcati } 1435db2fe3aSRaffaele Recalcati break; 1445db2fe3aSRaffaele Recalcati case MMC_RSP_R3: 1455db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n", 1465db2fe3aSRaffaele Recalcati cmd->response[0]); 1475db2fe3aSRaffaele Recalcati break; 1485db2fe3aSRaffaele Recalcati default: 1495db2fe3aSRaffaele Recalcati printf("\t\tERROR MMC rsp not supported\n"); 1505db2fe3aSRaffaele Recalcati break; 1515db2fe3aSRaffaele Recalcati } 1527863ce58SBin Meng } 153c0c76ebaSSimon Glass } 154c0c76ebaSSimon Glass 155c0c76ebaSSimon Glass void mmc_trace_state(struct mmc *mmc, struct mmc_cmd *cmd) 156c0c76ebaSSimon Glass { 157c0c76ebaSSimon Glass int status; 158c0c76ebaSSimon Glass 159c0c76ebaSSimon Glass status = (cmd->response[0] & MMC_STATUS_CURR_STATE) >> 9; 160c0c76ebaSSimon Glass printf("CURR STATE:%d\n", status); 161c0c76ebaSSimon Glass } 1625db2fe3aSRaffaele Recalcati #endif 163c0c76ebaSSimon Glass 16435f9e196SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG) 16535f9e196SJean-Jacques Hiblot const char *mmc_mode_name(enum bus_mode mode) 16635f9e196SJean-Jacques Hiblot { 16735f9e196SJean-Jacques Hiblot static const char *const names[] = { 16835f9e196SJean-Jacques Hiblot [MMC_LEGACY] = "MMC legacy", 16935f9e196SJean-Jacques Hiblot [SD_LEGACY] = "SD Legacy", 17035f9e196SJean-Jacques Hiblot [MMC_HS] = "MMC High Speed (26MHz)", 17135f9e196SJean-Jacques Hiblot [SD_HS] = "SD High Speed (50MHz)", 17235f9e196SJean-Jacques Hiblot [UHS_SDR12] = "UHS SDR12 (25MHz)", 17335f9e196SJean-Jacques Hiblot [UHS_SDR25] = "UHS SDR25 (50MHz)", 17435f9e196SJean-Jacques Hiblot [UHS_SDR50] = "UHS SDR50 (100MHz)", 17535f9e196SJean-Jacques Hiblot [UHS_SDR104] = "UHS SDR104 (208MHz)", 17635f9e196SJean-Jacques Hiblot [UHS_DDR50] = "UHS DDR50 (50MHz)", 17735f9e196SJean-Jacques Hiblot [MMC_HS_52] = "MMC High Speed (52MHz)", 17835f9e196SJean-Jacques Hiblot [MMC_DDR_52] = "MMC DDR52 (52MHz)", 17935f9e196SJean-Jacques Hiblot [MMC_HS_200] = "HS200 (200MHz)", 18035f9e196SJean-Jacques Hiblot }; 18135f9e196SJean-Jacques Hiblot 18235f9e196SJean-Jacques Hiblot if (mode >= MMC_MODES_END) 18335f9e196SJean-Jacques Hiblot return "Unknown mode"; 18435f9e196SJean-Jacques Hiblot else 18535f9e196SJean-Jacques Hiblot return names[mode]; 18635f9e196SJean-Jacques Hiblot } 18735f9e196SJean-Jacques Hiblot #endif 18835f9e196SJean-Jacques Hiblot 18905038576SJean-Jacques Hiblot static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode) 19005038576SJean-Jacques Hiblot { 19105038576SJean-Jacques Hiblot static const int freqs[] = { 19205038576SJean-Jacques Hiblot [SD_LEGACY] = 25000000, 19305038576SJean-Jacques Hiblot [MMC_HS] = 26000000, 19405038576SJean-Jacques Hiblot [SD_HS] = 50000000, 195f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 19605038576SJean-Jacques Hiblot [UHS_SDR12] = 25000000, 19705038576SJean-Jacques Hiblot [UHS_SDR25] = 50000000, 19805038576SJean-Jacques Hiblot [UHS_SDR50] = 100000000, 19905038576SJean-Jacques Hiblot [UHS_DDR50] = 50000000, 200f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 201f99c2efeSJean-Jacques Hiblot [UHS_SDR104] = 208000000, 202f99c2efeSJean-Jacques Hiblot #endif 203f99c2efeSJean-Jacques Hiblot #endif 20405038576SJean-Jacques Hiblot [MMC_HS_52] = 52000000, 20505038576SJean-Jacques Hiblot [MMC_DDR_52] = 52000000, 206f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) 20705038576SJean-Jacques Hiblot [MMC_HS_200] = 200000000, 208f99c2efeSJean-Jacques Hiblot #endif 20905038576SJean-Jacques Hiblot }; 21005038576SJean-Jacques Hiblot 21105038576SJean-Jacques Hiblot if (mode == MMC_LEGACY) 21205038576SJean-Jacques Hiblot return mmc->legacy_speed; 21305038576SJean-Jacques Hiblot else if (mode >= MMC_MODES_END) 21405038576SJean-Jacques Hiblot return 0; 21505038576SJean-Jacques Hiblot else 21605038576SJean-Jacques Hiblot return freqs[mode]; 21705038576SJean-Jacques Hiblot } 21805038576SJean-Jacques Hiblot 21935f9e196SJean-Jacques Hiblot static int mmc_select_mode(struct mmc *mmc, enum bus_mode mode) 22035f9e196SJean-Jacques Hiblot { 22135f9e196SJean-Jacques Hiblot mmc->selected_mode = mode; 22205038576SJean-Jacques Hiblot mmc->tran_speed = mmc_mode2freq(mmc, mode); 2233862b854SJean-Jacques Hiblot mmc->ddr_mode = mmc_is_mode_ddr(mode); 22435f9e196SJean-Jacques Hiblot debug("selecting mode %s (freq : %d MHz)\n", mmc_mode_name(mode), 22535f9e196SJean-Jacques Hiblot mmc->tran_speed / 1000000); 22635f9e196SJean-Jacques Hiblot return 0; 22735f9e196SJean-Jacques Hiblot } 22835f9e196SJean-Jacques Hiblot 229e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 230c0c76ebaSSimon Glass int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) 231c0c76ebaSSimon Glass { 232c0c76ebaSSimon Glass int ret; 233c0c76ebaSSimon Glass 234c0c76ebaSSimon Glass mmmc_trace_before_send(mmc, cmd); 235c0c76ebaSSimon Glass ret = mmc->cfg->ops->send_cmd(mmc, cmd, data); 236c0c76ebaSSimon Glass mmmc_trace_after_send(mmc, cmd, ret); 237c0c76ebaSSimon Glass 2388635ff9eSMarek Vasut return ret; 239272cc70bSAndy Fleming } 2408ca51e51SSimon Glass #endif 241272cc70bSAndy Fleming 242da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout) 2435d4fc8d9SRaffaele Recalcati { 2445d4fc8d9SRaffaele Recalcati struct mmc_cmd cmd; 245d617c426SJan Kloetzke int err, retries = 5; 2465d4fc8d9SRaffaele Recalcati 2475d4fc8d9SRaffaele Recalcati cmd.cmdidx = MMC_CMD_SEND_STATUS; 2485d4fc8d9SRaffaele Recalcati cmd.resp_type = MMC_RSP_R1; 249aaf3d41aSMarek Vasut if (!mmc_host_is_spi(mmc)) 250aaf3d41aSMarek Vasut cmd.cmdarg = mmc->rca << 16; 2515d4fc8d9SRaffaele Recalcati 2521677eef4SAndrew Gabbasov while (1) { 2535d4fc8d9SRaffaele Recalcati err = mmc_send_cmd(mmc, &cmd, NULL); 254d617c426SJan Kloetzke if (!err) { 255d617c426SJan Kloetzke if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) && 256d617c426SJan Kloetzke (cmd.response[0] & MMC_STATUS_CURR_STATE) != 257d617c426SJan Kloetzke MMC_STATE_PRG) 2585d4fc8d9SRaffaele Recalcati break; 259d0c221feSJean-Jacques Hiblot 260d0c221feSJean-Jacques Hiblot if (cmd.response[0] & MMC_STATUS_MASK) { 26156196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 262d8e3d420SJean-Jacques Hiblot pr_err("Status Error: 0x%08X\n", 263d617c426SJan Kloetzke cmd.response[0]); 26456196826SPaul Burton #endif 265915ffa52SJaehoon Chung return -ECOMM; 266d617c426SJan Kloetzke } 267d617c426SJan Kloetzke } else if (--retries < 0) 268d617c426SJan Kloetzke return err; 2695d4fc8d9SRaffaele Recalcati 2701677eef4SAndrew Gabbasov if (timeout-- <= 0) 2711677eef4SAndrew Gabbasov break; 2725d4fc8d9SRaffaele Recalcati 2731677eef4SAndrew Gabbasov udelay(1000); 2741677eef4SAndrew Gabbasov } 2755d4fc8d9SRaffaele Recalcati 276c0c76ebaSSimon Glass mmc_trace_state(mmc, &cmd); 2775b0c942fSJongman Heo if (timeout <= 0) { 27856196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 279d8e3d420SJean-Jacques Hiblot pr_err("Timeout waiting card ready\n"); 28056196826SPaul Burton #endif 281915ffa52SJaehoon Chung return -ETIMEDOUT; 2825d4fc8d9SRaffaele Recalcati } 2835d4fc8d9SRaffaele Recalcati 2845d4fc8d9SRaffaele Recalcati return 0; 2855d4fc8d9SRaffaele Recalcati } 2865d4fc8d9SRaffaele Recalcati 287da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len) 288272cc70bSAndy Fleming { 289272cc70bSAndy Fleming struct mmc_cmd cmd; 29083dc4227SKishon Vijay Abraham I int err; 291272cc70bSAndy Fleming 292786e8f81SAndrew Gabbasov if (mmc->ddr_mode) 293d22e3d46SJaehoon Chung return 0; 294d22e3d46SJaehoon Chung 295272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SET_BLOCKLEN; 296272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 297272cc70bSAndy Fleming cmd.cmdarg = len; 298272cc70bSAndy Fleming 29983dc4227SKishon Vijay Abraham I err = mmc_send_cmd(mmc, &cmd, NULL); 30083dc4227SKishon Vijay Abraham I 30183dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS 30283dc4227SKishon Vijay Abraham I if (err && (mmc->quirks & MMC_QUIRK_RETRY_SET_BLOCKLEN)) { 30383dc4227SKishon Vijay Abraham I int retries = 4; 30483dc4227SKishon Vijay Abraham I /* 30583dc4227SKishon Vijay Abraham I * It has been seen that SET_BLOCKLEN may fail on the first 30683dc4227SKishon Vijay Abraham I * attempt, let's try a few more time 30783dc4227SKishon Vijay Abraham I */ 30883dc4227SKishon Vijay Abraham I do { 30983dc4227SKishon Vijay Abraham I err = mmc_send_cmd(mmc, &cmd, NULL); 31083dc4227SKishon Vijay Abraham I if (!err) 31183dc4227SKishon Vijay Abraham I break; 31283dc4227SKishon Vijay Abraham I } while (retries--); 31383dc4227SKishon Vijay Abraham I } 31483dc4227SKishon Vijay Abraham I #endif 31583dc4227SKishon Vijay Abraham I 31683dc4227SKishon Vijay Abraham I return err; 317272cc70bSAndy Fleming } 318272cc70bSAndy Fleming 319f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 3209815e3baSJean-Jacques Hiblot static const u8 tuning_blk_pattern_4bit[] = { 3219815e3baSJean-Jacques Hiblot 0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc, 3229815e3baSJean-Jacques Hiblot 0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef, 3239815e3baSJean-Jacques Hiblot 0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb, 3249815e3baSJean-Jacques Hiblot 0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef, 3259815e3baSJean-Jacques Hiblot 0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c, 3269815e3baSJean-Jacques Hiblot 0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee, 3279815e3baSJean-Jacques Hiblot 0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff, 3289815e3baSJean-Jacques Hiblot 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde, 3299815e3baSJean-Jacques Hiblot }; 3309815e3baSJean-Jacques Hiblot 3319815e3baSJean-Jacques Hiblot static const u8 tuning_blk_pattern_8bit[] = { 3329815e3baSJean-Jacques Hiblot 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 3339815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc, 3349815e3baSJean-Jacques Hiblot 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff, 3359815e3baSJean-Jacques Hiblot 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff, 3369815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd, 3379815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, 3389815e3baSJean-Jacques Hiblot 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff, 3399815e3baSJean-Jacques Hiblot 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff, 3409815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 3419815e3baSJean-Jacques Hiblot 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 3429815e3baSJean-Jacques Hiblot 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 3439815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 3449815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 3459815e3baSJean-Jacques Hiblot 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 3469815e3baSJean-Jacques Hiblot 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 3479815e3baSJean-Jacques Hiblot 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 3489815e3baSJean-Jacques Hiblot }; 3499815e3baSJean-Jacques Hiblot 3509815e3baSJean-Jacques Hiblot int mmc_send_tuning(struct mmc *mmc, u32 opcode, int *cmd_error) 3519815e3baSJean-Jacques Hiblot { 3529815e3baSJean-Jacques Hiblot struct mmc_cmd cmd; 3539815e3baSJean-Jacques Hiblot struct mmc_data data; 3549815e3baSJean-Jacques Hiblot const u8 *tuning_block_pattern; 3559815e3baSJean-Jacques Hiblot int size, err; 3569815e3baSJean-Jacques Hiblot 3579815e3baSJean-Jacques Hiblot if (mmc->bus_width == 8) { 3589815e3baSJean-Jacques Hiblot tuning_block_pattern = tuning_blk_pattern_8bit; 3599815e3baSJean-Jacques Hiblot size = sizeof(tuning_blk_pattern_8bit); 3609815e3baSJean-Jacques Hiblot } else if (mmc->bus_width == 4) { 3619815e3baSJean-Jacques Hiblot tuning_block_pattern = tuning_blk_pattern_4bit; 3629815e3baSJean-Jacques Hiblot size = sizeof(tuning_blk_pattern_4bit); 3639815e3baSJean-Jacques Hiblot } else { 3649815e3baSJean-Jacques Hiblot return -EINVAL; 3659815e3baSJean-Jacques Hiblot } 3669815e3baSJean-Jacques Hiblot 3679815e3baSJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, data_buf, size); 3689815e3baSJean-Jacques Hiblot 3699815e3baSJean-Jacques Hiblot cmd.cmdidx = opcode; 3709815e3baSJean-Jacques Hiblot cmd.cmdarg = 0; 3719815e3baSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 3729815e3baSJean-Jacques Hiblot 3739815e3baSJean-Jacques Hiblot data.dest = (void *)data_buf; 3749815e3baSJean-Jacques Hiblot data.blocks = 1; 3759815e3baSJean-Jacques Hiblot data.blocksize = size; 3769815e3baSJean-Jacques Hiblot data.flags = MMC_DATA_READ; 3779815e3baSJean-Jacques Hiblot 3789815e3baSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, &data); 3799815e3baSJean-Jacques Hiblot if (err) 3809815e3baSJean-Jacques Hiblot return err; 3819815e3baSJean-Jacques Hiblot 3829815e3baSJean-Jacques Hiblot if (memcmp(data_buf, tuning_block_pattern, size)) 3839815e3baSJean-Jacques Hiblot return -EIO; 3849815e3baSJean-Jacques Hiblot 3859815e3baSJean-Jacques Hiblot return 0; 3869815e3baSJean-Jacques Hiblot } 387f99c2efeSJean-Jacques Hiblot #endif 3889815e3baSJean-Jacques Hiblot 389ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start, 390fdbb873eSKim Phillips lbaint_t blkcnt) 391272cc70bSAndy Fleming { 392272cc70bSAndy Fleming struct mmc_cmd cmd; 393272cc70bSAndy Fleming struct mmc_data data; 394272cc70bSAndy Fleming 3954a1a06bcSAlagu Sankar if (blkcnt > 1) 3964a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; 3974a1a06bcSAlagu Sankar else 398272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; 399272cc70bSAndy Fleming 400272cc70bSAndy Fleming if (mmc->high_capacity) 4014a1a06bcSAlagu Sankar cmd.cmdarg = start; 402272cc70bSAndy Fleming else 4034a1a06bcSAlagu Sankar cmd.cmdarg = start * mmc->read_bl_len; 404272cc70bSAndy Fleming 405272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 406272cc70bSAndy Fleming 407272cc70bSAndy Fleming data.dest = dst; 4084a1a06bcSAlagu Sankar data.blocks = blkcnt; 409272cc70bSAndy Fleming data.blocksize = mmc->read_bl_len; 410272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 411272cc70bSAndy Fleming 4124a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, &data)) 4134a1a06bcSAlagu Sankar return 0; 4144a1a06bcSAlagu Sankar 4154a1a06bcSAlagu Sankar if (blkcnt > 1) { 4164a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; 4174a1a06bcSAlagu Sankar cmd.cmdarg = 0; 4184a1a06bcSAlagu Sankar cmd.resp_type = MMC_RSP_R1b; 4194a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, NULL)) { 42056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 421d8e3d420SJean-Jacques Hiblot pr_err("mmc fail to send stop cmd\n"); 42256196826SPaul Burton #endif 4234a1a06bcSAlagu Sankar return 0; 4244a1a06bcSAlagu Sankar } 425272cc70bSAndy Fleming } 426272cc70bSAndy Fleming 4274a1a06bcSAlagu Sankar return blkcnt; 428272cc70bSAndy Fleming } 429272cc70bSAndy Fleming 430c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK) 4317dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst) 43233fb211dSSimon Glass #else 4337dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, 4347dba0b93SSimon Glass void *dst) 43533fb211dSSimon Glass #endif 436272cc70bSAndy Fleming { 437c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK) 43833fb211dSSimon Glass struct blk_desc *block_dev = dev_get_uclass_platdata(dev); 43933fb211dSSimon Glass #endif 440bcce53d0SSimon Glass int dev_num = block_dev->devnum; 441873cc1d7SStephen Warren int err; 4424a1a06bcSAlagu Sankar lbaint_t cur, blocks_todo = blkcnt; 443272cc70bSAndy Fleming 4444a1a06bcSAlagu Sankar if (blkcnt == 0) 4454a1a06bcSAlagu Sankar return 0; 4464a1a06bcSAlagu Sankar 4474a1a06bcSAlagu Sankar struct mmc *mmc = find_mmc_device(dev_num); 448272cc70bSAndy Fleming if (!mmc) 449272cc70bSAndy Fleming return 0; 450272cc70bSAndy Fleming 451b5b838f1SMarek Vasut if (CONFIG_IS_ENABLED(MMC_TINY)) 452b5b838f1SMarek Vasut err = mmc_switch_part(mmc, block_dev->hwpart); 453b5b838f1SMarek Vasut else 45469f45cd5SSimon Glass err = blk_dselect_hwpart(block_dev, block_dev->hwpart); 455b5b838f1SMarek Vasut 456873cc1d7SStephen Warren if (err < 0) 457873cc1d7SStephen Warren return 0; 458873cc1d7SStephen Warren 459c40fdca6SSimon Glass if ((start + blkcnt) > block_dev->lba) { 46056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 461d8e3d420SJean-Jacques Hiblot pr_err("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", 462c40fdca6SSimon Glass start + blkcnt, block_dev->lba); 46356196826SPaul Burton #endif 464d2bf29e3SLei Wen return 0; 465d2bf29e3SLei Wen } 466272cc70bSAndy Fleming 46711692991SSimon Glass if (mmc_set_blocklen(mmc, mmc->read_bl_len)) { 46811692991SSimon Glass debug("%s: Failed to set blocklen\n", __func__); 469272cc70bSAndy Fleming return 0; 47011692991SSimon Glass } 471272cc70bSAndy Fleming 4724a1a06bcSAlagu Sankar do { 47393bfd616SPantelis Antoniou cur = (blocks_todo > mmc->cfg->b_max) ? 47493bfd616SPantelis Antoniou mmc->cfg->b_max : blocks_todo; 47511692991SSimon Glass if (mmc_read_blocks(mmc, dst, start, cur) != cur) { 47611692991SSimon Glass debug("%s: Failed to read blocks\n", __func__); 4774a1a06bcSAlagu Sankar return 0; 47811692991SSimon Glass } 4794a1a06bcSAlagu Sankar blocks_todo -= cur; 4804a1a06bcSAlagu Sankar start += cur; 4814a1a06bcSAlagu Sankar dst += cur * mmc->read_bl_len; 4824a1a06bcSAlagu Sankar } while (blocks_todo > 0); 483272cc70bSAndy Fleming 484272cc70bSAndy Fleming return blkcnt; 485272cc70bSAndy Fleming } 486272cc70bSAndy Fleming 487fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc) 488272cc70bSAndy Fleming { 489272cc70bSAndy Fleming struct mmc_cmd cmd; 490272cc70bSAndy Fleming int err; 491272cc70bSAndy Fleming 492272cc70bSAndy Fleming udelay(1000); 493272cc70bSAndy Fleming 494272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_GO_IDLE_STATE; 495272cc70bSAndy Fleming cmd.cmdarg = 0; 496272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_NONE; 497272cc70bSAndy Fleming 498272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 499272cc70bSAndy Fleming 500272cc70bSAndy Fleming if (err) 501272cc70bSAndy Fleming return err; 502272cc70bSAndy Fleming 503272cc70bSAndy Fleming udelay(2000); 504272cc70bSAndy Fleming 505272cc70bSAndy Fleming return 0; 506272cc70bSAndy Fleming } 507272cc70bSAndy Fleming 508f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 509c10b85d6SJean-Jacques Hiblot static int mmc_switch_voltage(struct mmc *mmc, int signal_voltage) 510c10b85d6SJean-Jacques Hiblot { 511c10b85d6SJean-Jacques Hiblot struct mmc_cmd cmd; 512c10b85d6SJean-Jacques Hiblot int err = 0; 513c10b85d6SJean-Jacques Hiblot 514c10b85d6SJean-Jacques Hiblot /* 515c10b85d6SJean-Jacques Hiblot * Send CMD11 only if the request is to switch the card to 516c10b85d6SJean-Jacques Hiblot * 1.8V signalling. 517c10b85d6SJean-Jacques Hiblot */ 518c10b85d6SJean-Jacques Hiblot if (signal_voltage == MMC_SIGNAL_VOLTAGE_330) 519c10b85d6SJean-Jacques Hiblot return mmc_set_signal_voltage(mmc, signal_voltage); 520c10b85d6SJean-Jacques Hiblot 521c10b85d6SJean-Jacques Hiblot cmd.cmdidx = SD_CMD_SWITCH_UHS18V; 522c10b85d6SJean-Jacques Hiblot cmd.cmdarg = 0; 523c10b85d6SJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 524c10b85d6SJean-Jacques Hiblot 525c10b85d6SJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 526c10b85d6SJean-Jacques Hiblot if (err) 527c10b85d6SJean-Jacques Hiblot return err; 528c10b85d6SJean-Jacques Hiblot 529c10b85d6SJean-Jacques Hiblot if (!mmc_host_is_spi(mmc) && (cmd.response[0] & MMC_STATUS_ERROR)) 530c10b85d6SJean-Jacques Hiblot return -EIO; 531c10b85d6SJean-Jacques Hiblot 532c10b85d6SJean-Jacques Hiblot /* 533c10b85d6SJean-Jacques Hiblot * The card should drive cmd and dat[0:3] low immediately 534c10b85d6SJean-Jacques Hiblot * after the response of cmd11, but wait 100 us to be sure 535c10b85d6SJean-Jacques Hiblot */ 536c10b85d6SJean-Jacques Hiblot err = mmc_wait_dat0(mmc, 0, 100); 537c10b85d6SJean-Jacques Hiblot if (err == -ENOSYS) 538c10b85d6SJean-Jacques Hiblot udelay(100); 539c10b85d6SJean-Jacques Hiblot else if (err) 540c10b85d6SJean-Jacques Hiblot return -ETIMEDOUT; 541c10b85d6SJean-Jacques Hiblot 542c10b85d6SJean-Jacques Hiblot /* 543c10b85d6SJean-Jacques Hiblot * During a signal voltage level switch, the clock must be gated 544c10b85d6SJean-Jacques Hiblot * for 5 ms according to the SD spec 545c10b85d6SJean-Jacques Hiblot */ 546c10b85d6SJean-Jacques Hiblot mmc_set_clock(mmc, mmc->clock, true); 547c10b85d6SJean-Jacques Hiblot 548c10b85d6SJean-Jacques Hiblot err = mmc_set_signal_voltage(mmc, signal_voltage); 549c10b85d6SJean-Jacques Hiblot if (err) 550c10b85d6SJean-Jacques Hiblot return err; 551c10b85d6SJean-Jacques Hiblot 552c10b85d6SJean-Jacques Hiblot /* Keep clock gated for at least 10 ms, though spec only says 5 ms */ 553c10b85d6SJean-Jacques Hiblot mdelay(10); 554c10b85d6SJean-Jacques Hiblot mmc_set_clock(mmc, mmc->clock, false); 555c10b85d6SJean-Jacques Hiblot 556c10b85d6SJean-Jacques Hiblot /* 557c10b85d6SJean-Jacques Hiblot * Failure to switch is indicated by the card holding 558c10b85d6SJean-Jacques Hiblot * dat[0:3] low. Wait for at least 1 ms according to spec 559c10b85d6SJean-Jacques Hiblot */ 560c10b85d6SJean-Jacques Hiblot err = mmc_wait_dat0(mmc, 1, 1000); 561c10b85d6SJean-Jacques Hiblot if (err == -ENOSYS) 562c10b85d6SJean-Jacques Hiblot udelay(1000); 563c10b85d6SJean-Jacques Hiblot else if (err) 564c10b85d6SJean-Jacques Hiblot return -ETIMEDOUT; 565c10b85d6SJean-Jacques Hiblot 566c10b85d6SJean-Jacques Hiblot return 0; 567c10b85d6SJean-Jacques Hiblot } 568f99c2efeSJean-Jacques Hiblot #endif 569c10b85d6SJean-Jacques Hiblot 570c10b85d6SJean-Jacques Hiblot static int sd_send_op_cond(struct mmc *mmc, bool uhs_en) 571272cc70bSAndy Fleming { 572272cc70bSAndy Fleming int timeout = 1000; 573272cc70bSAndy Fleming int err; 574272cc70bSAndy Fleming struct mmc_cmd cmd; 575272cc70bSAndy Fleming 5761677eef4SAndrew Gabbasov while (1) { 577272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 578272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 579272cc70bSAndy Fleming cmd.cmdarg = 0; 580272cc70bSAndy Fleming 581272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 582272cc70bSAndy Fleming 583272cc70bSAndy Fleming if (err) 584272cc70bSAndy Fleming return err; 585272cc70bSAndy Fleming 586272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_OP_COND; 587272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R3; 588250de12bSStefano Babic 589250de12bSStefano Babic /* 590250de12bSStefano Babic * Most cards do not answer if some reserved bits 591250de12bSStefano Babic * in the ocr are set. However, Some controller 592250de12bSStefano Babic * can set bit 7 (reserved for low voltages), but 593250de12bSStefano Babic * how to manage low voltages SD card is not yet 594250de12bSStefano Babic * specified. 595250de12bSStefano Babic */ 596d52ebf10SThomas Chou cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 : 59793bfd616SPantelis Antoniou (mmc->cfg->voltages & 0xff8000); 598272cc70bSAndy Fleming 599272cc70bSAndy Fleming if (mmc->version == SD_VERSION_2) 600272cc70bSAndy Fleming cmd.cmdarg |= OCR_HCS; 601272cc70bSAndy Fleming 602c10b85d6SJean-Jacques Hiblot if (uhs_en) 603c10b85d6SJean-Jacques Hiblot cmd.cmdarg |= OCR_S18R; 604c10b85d6SJean-Jacques Hiblot 605272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 606272cc70bSAndy Fleming 607272cc70bSAndy Fleming if (err) 608272cc70bSAndy Fleming return err; 609272cc70bSAndy Fleming 6101677eef4SAndrew Gabbasov if (cmd.response[0] & OCR_BUSY) 6111677eef4SAndrew Gabbasov break; 612272cc70bSAndy Fleming 6131677eef4SAndrew Gabbasov if (timeout-- <= 0) 614915ffa52SJaehoon Chung return -EOPNOTSUPP; 615272cc70bSAndy Fleming 6161677eef4SAndrew Gabbasov udelay(1000); 6171677eef4SAndrew Gabbasov } 6181677eef4SAndrew Gabbasov 619272cc70bSAndy Fleming if (mmc->version != SD_VERSION_2) 620272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 621272cc70bSAndy Fleming 622d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 623d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 624d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 625d52ebf10SThomas Chou cmd.cmdarg = 0; 626d52ebf10SThomas Chou 627d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 628d52ebf10SThomas Chou 629d52ebf10SThomas Chou if (err) 630d52ebf10SThomas Chou return err; 631d52ebf10SThomas Chou } 632d52ebf10SThomas Chou 633998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 634272cc70bSAndy Fleming 635f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 636c10b85d6SJean-Jacques Hiblot if (uhs_en && !(mmc_host_is_spi(mmc)) && (cmd.response[0] & 0x41000000) 637c10b85d6SJean-Jacques Hiblot == 0x41000000) { 638c10b85d6SJean-Jacques Hiblot err = mmc_switch_voltage(mmc, MMC_SIGNAL_VOLTAGE_180); 639c10b85d6SJean-Jacques Hiblot if (err) 640c10b85d6SJean-Jacques Hiblot return err; 641c10b85d6SJean-Jacques Hiblot } 642f99c2efeSJean-Jacques Hiblot #endif 643c10b85d6SJean-Jacques Hiblot 644272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 645272cc70bSAndy Fleming mmc->rca = 0; 646272cc70bSAndy Fleming 647272cc70bSAndy Fleming return 0; 648272cc70bSAndy Fleming } 649272cc70bSAndy Fleming 6505289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg) 651272cc70bSAndy Fleming { 6525289b535SAndrew Gabbasov struct mmc_cmd cmd; 653272cc70bSAndy Fleming int err; 654272cc70bSAndy Fleming 6555289b535SAndrew Gabbasov cmd.cmdidx = MMC_CMD_SEND_OP_COND; 6565289b535SAndrew Gabbasov cmd.resp_type = MMC_RSP_R3; 6575289b535SAndrew Gabbasov cmd.cmdarg = 0; 6585a20397bSRob Herring if (use_arg && !mmc_host_is_spi(mmc)) 6595a20397bSRob Herring cmd.cmdarg = OCR_HCS | 66093bfd616SPantelis Antoniou (mmc->cfg->voltages & 661a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_VOLTAGE_MASK)) | 662a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_ACCESS_MODE); 663e9550449SChe-Liang Chiou 6645289b535SAndrew Gabbasov err = mmc_send_cmd(mmc, &cmd, NULL); 665e9550449SChe-Liang Chiou if (err) 666e9550449SChe-Liang Chiou return err; 6675289b535SAndrew Gabbasov mmc->ocr = cmd.response[0]; 668e9550449SChe-Liang Chiou return 0; 669e9550449SChe-Liang Chiou } 670e9550449SChe-Liang Chiou 671750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc) 672e9550449SChe-Liang Chiou { 673e9550449SChe-Liang Chiou int err, i; 674e9550449SChe-Liang Chiou 675272cc70bSAndy Fleming /* Some cards seem to need this */ 676272cc70bSAndy Fleming mmc_go_idle(mmc); 677272cc70bSAndy Fleming 67831cacbabSRaffaele Recalcati /* Asking to the card its capabilities */ 679e9550449SChe-Liang Chiou for (i = 0; i < 2; i++) { 6805289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, i != 0); 68131cacbabSRaffaele Recalcati if (err) 68231cacbabSRaffaele Recalcati return err; 68331cacbabSRaffaele Recalcati 684e9550449SChe-Liang Chiou /* exit if not busy (flag seems to be inverted) */ 685a626c8d4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 686bd47c135SAndrew Gabbasov break; 687e9550449SChe-Liang Chiou } 688bd47c135SAndrew Gabbasov mmc->op_cond_pending = 1; 689bd47c135SAndrew Gabbasov return 0; 690e9550449SChe-Liang Chiou } 69131cacbabSRaffaele Recalcati 692750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc) 693e9550449SChe-Liang Chiou { 694e9550449SChe-Liang Chiou struct mmc_cmd cmd; 695e9550449SChe-Liang Chiou int timeout = 1000; 696e9550449SChe-Liang Chiou uint start; 697e9550449SChe-Liang Chiou int err; 698e9550449SChe-Liang Chiou 699e9550449SChe-Liang Chiou mmc->op_cond_pending = 0; 700cc17c01fSAndrew Gabbasov if (!(mmc->ocr & OCR_BUSY)) { 701d188b113SYangbo Lu /* Some cards seem to need this */ 702d188b113SYangbo Lu mmc_go_idle(mmc); 703d188b113SYangbo Lu 704e9550449SChe-Liang Chiou start = get_timer(0); 7051677eef4SAndrew Gabbasov while (1) { 7065289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, 1); 707272cc70bSAndy Fleming if (err) 708272cc70bSAndy Fleming return err; 7091677eef4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 7101677eef4SAndrew Gabbasov break; 711e9550449SChe-Liang Chiou if (get_timer(start) > timeout) 712915ffa52SJaehoon Chung return -EOPNOTSUPP; 713e9550449SChe-Liang Chiou udelay(100); 7141677eef4SAndrew Gabbasov } 715cc17c01fSAndrew Gabbasov } 716272cc70bSAndy Fleming 717d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 718d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 719d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 720d52ebf10SThomas Chou cmd.cmdarg = 0; 721d52ebf10SThomas Chou 722d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 723d52ebf10SThomas Chou 724d52ebf10SThomas Chou if (err) 725d52ebf10SThomas Chou return err; 726a626c8d4SAndrew Gabbasov 727a626c8d4SAndrew Gabbasov mmc->ocr = cmd.response[0]; 728d52ebf10SThomas Chou } 729d52ebf10SThomas Chou 730272cc70bSAndy Fleming mmc->version = MMC_VERSION_UNKNOWN; 731272cc70bSAndy Fleming 732272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 733def816a2SStephen Warren mmc->rca = 1; 734272cc70bSAndy Fleming 735272cc70bSAndy Fleming return 0; 736272cc70bSAndy Fleming } 737272cc70bSAndy Fleming 738272cc70bSAndy Fleming 739fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) 740272cc70bSAndy Fleming { 741272cc70bSAndy Fleming struct mmc_cmd cmd; 742272cc70bSAndy Fleming struct mmc_data data; 743272cc70bSAndy Fleming int err; 744272cc70bSAndy Fleming 745272cc70bSAndy Fleming /* Get the Card Status Register */ 746272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_EXT_CSD; 747272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 748272cc70bSAndy Fleming cmd.cmdarg = 0; 749272cc70bSAndy Fleming 750cdfd1ac6SYoshihiro Shimoda data.dest = (char *)ext_csd; 751272cc70bSAndy Fleming data.blocks = 1; 7528bfa195eSSimon Glass data.blocksize = MMC_MAX_BLOCK_LEN; 753272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 754272cc70bSAndy Fleming 755272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 756272cc70bSAndy Fleming 757272cc70bSAndy Fleming return err; 758272cc70bSAndy Fleming } 759272cc70bSAndy Fleming 760c40704f4SSimon Glass int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) 761272cc70bSAndy Fleming { 762272cc70bSAndy Fleming struct mmc_cmd cmd; 7635d4fc8d9SRaffaele Recalcati int timeout = 1000; 764a9003dc6SMaxime Ripard int retries = 3; 7655d4fc8d9SRaffaele Recalcati int ret; 766272cc70bSAndy Fleming 767272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SWITCH; 768272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 769272cc70bSAndy Fleming cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 770272cc70bSAndy Fleming (index << 16) | 771272cc70bSAndy Fleming (value << 8); 772272cc70bSAndy Fleming 773a9003dc6SMaxime Ripard while (retries > 0) { 7745d4fc8d9SRaffaele Recalcati ret = mmc_send_cmd(mmc, &cmd, NULL); 7755d4fc8d9SRaffaele Recalcati 7765d4fc8d9SRaffaele Recalcati /* Waiting for the ready status */ 777a9003dc6SMaxime Ripard if (!ret) { 77893ad0d18SJan Kloetzke ret = mmc_send_status(mmc, timeout); 779a9003dc6SMaxime Ripard return ret; 780a9003dc6SMaxime Ripard } 781a9003dc6SMaxime Ripard 782a9003dc6SMaxime Ripard retries--; 783a9003dc6SMaxime Ripard } 7845d4fc8d9SRaffaele Recalcati 7855d4fc8d9SRaffaele Recalcati return ret; 7865d4fc8d9SRaffaele Recalcati 787272cc70bSAndy Fleming } 788272cc70bSAndy Fleming 7893862b854SJean-Jacques Hiblot static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode) 790272cc70bSAndy Fleming { 791272cc70bSAndy Fleming int err; 7923862b854SJean-Jacques Hiblot int speed_bits; 7933862b854SJean-Jacques Hiblot 7943862b854SJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 7953862b854SJean-Jacques Hiblot 7963862b854SJean-Jacques Hiblot switch (mode) { 7973862b854SJean-Jacques Hiblot case MMC_HS: 7983862b854SJean-Jacques Hiblot case MMC_HS_52: 7993862b854SJean-Jacques Hiblot case MMC_DDR_52: 8003862b854SJean-Jacques Hiblot speed_bits = EXT_CSD_TIMING_HS; 801634d4849SKishon Vijay Abraham I break; 802*baef2070SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) 803634d4849SKishon Vijay Abraham I case MMC_HS_200: 804634d4849SKishon Vijay Abraham I speed_bits = EXT_CSD_TIMING_HS200; 805634d4849SKishon Vijay Abraham I break; 806*baef2070SJean-Jacques Hiblot #endif 8073862b854SJean-Jacques Hiblot case MMC_LEGACY: 8083862b854SJean-Jacques Hiblot speed_bits = EXT_CSD_TIMING_LEGACY; 8093862b854SJean-Jacques Hiblot break; 8103862b854SJean-Jacques Hiblot default: 8113862b854SJean-Jacques Hiblot return -EINVAL; 8123862b854SJean-Jacques Hiblot } 8133862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 8143862b854SJean-Jacques Hiblot speed_bits); 8153862b854SJean-Jacques Hiblot if (err) 8163862b854SJean-Jacques Hiblot return err; 8173862b854SJean-Jacques Hiblot 8183862b854SJean-Jacques Hiblot if ((mode == MMC_HS) || (mode == MMC_HS_52)) { 8193862b854SJean-Jacques Hiblot /* Now check to see that it worked */ 8203862b854SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, test_csd); 8213862b854SJean-Jacques Hiblot if (err) 8223862b854SJean-Jacques Hiblot return err; 8233862b854SJean-Jacques Hiblot 8243862b854SJean-Jacques Hiblot /* No high-speed support */ 8253862b854SJean-Jacques Hiblot if (!test_csd[EXT_CSD_HS_TIMING]) 8263862b854SJean-Jacques Hiblot return -ENOTSUPP; 8273862b854SJean-Jacques Hiblot } 8283862b854SJean-Jacques Hiblot 8293862b854SJean-Jacques Hiblot return 0; 8303862b854SJean-Jacques Hiblot } 8313862b854SJean-Jacques Hiblot 8323862b854SJean-Jacques Hiblot static int mmc_get_capabilities(struct mmc *mmc) 8333862b854SJean-Jacques Hiblot { 8343862b854SJean-Jacques Hiblot u8 *ext_csd = mmc->ext_csd; 8353862b854SJean-Jacques Hiblot char cardtype; 836272cc70bSAndy Fleming 83700e446faSJean-Jacques Hiblot mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(MMC_LEGACY); 838272cc70bSAndy Fleming 839d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 840d52ebf10SThomas Chou return 0; 841d52ebf10SThomas Chou 842272cc70bSAndy Fleming /* Only version 4 supports high-speed */ 843272cc70bSAndy Fleming if (mmc->version < MMC_VERSION_4) 844272cc70bSAndy Fleming return 0; 845272cc70bSAndy Fleming 8463862b854SJean-Jacques Hiblot if (!ext_csd) { 847d8e3d420SJean-Jacques Hiblot pr_err("No ext_csd found!\n"); /* this should enver happen */ 8483862b854SJean-Jacques Hiblot return -ENOTSUPP; 8493862b854SJean-Jacques Hiblot } 8503862b854SJean-Jacques Hiblot 851fc5b32fbSAndrew Gabbasov mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; 852fc5b32fbSAndrew Gabbasov 853634d4849SKishon Vijay Abraham I cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0x3f; 854bc1e3272SJean-Jacques Hiblot mmc->cardtype = cardtype; 855272cc70bSAndy Fleming 856*baef2070SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) 857634d4849SKishon Vijay Abraham I if (cardtype & (EXT_CSD_CARD_TYPE_HS200_1_2V | 858634d4849SKishon Vijay Abraham I EXT_CSD_CARD_TYPE_HS200_1_8V)) { 859634d4849SKishon Vijay Abraham I mmc->card_caps |= MMC_MODE_HS200; 860634d4849SKishon Vijay Abraham I } 861*baef2070SJean-Jacques Hiblot #endif 862d22e3d46SJaehoon Chung if (cardtype & EXT_CSD_CARD_TYPE_52) { 8633862b854SJean-Jacques Hiblot if (cardtype & EXT_CSD_CARD_TYPE_DDR_52) 864d22e3d46SJaehoon Chung mmc->card_caps |= MMC_MODE_DDR_52MHz; 8653862b854SJean-Jacques Hiblot mmc->card_caps |= MMC_MODE_HS_52MHz; 866d22e3d46SJaehoon Chung } 8673862b854SJean-Jacques Hiblot if (cardtype & EXT_CSD_CARD_TYPE_26) 8683862b854SJean-Jacques Hiblot mmc->card_caps |= MMC_MODE_HS; 869272cc70bSAndy Fleming 870272cc70bSAndy Fleming return 0; 871272cc70bSAndy Fleming } 872272cc70bSAndy Fleming 873f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num) 874f866a46dSStephen Warren { 875f866a46dSStephen Warren switch (part_num) { 876f866a46dSStephen Warren case 0: 877f866a46dSStephen Warren mmc->capacity = mmc->capacity_user; 878f866a46dSStephen Warren break; 879f866a46dSStephen Warren case 1: 880f866a46dSStephen Warren case 2: 881f866a46dSStephen Warren mmc->capacity = mmc->capacity_boot; 882f866a46dSStephen Warren break; 883f866a46dSStephen Warren case 3: 884f866a46dSStephen Warren mmc->capacity = mmc->capacity_rpmb; 885f866a46dSStephen Warren break; 886f866a46dSStephen Warren case 4: 887f866a46dSStephen Warren case 5: 888f866a46dSStephen Warren case 6: 889f866a46dSStephen Warren case 7: 890f866a46dSStephen Warren mmc->capacity = mmc->capacity_gp[part_num - 4]; 891f866a46dSStephen Warren break; 892f866a46dSStephen Warren default: 893f866a46dSStephen Warren return -1; 894f866a46dSStephen Warren } 895f866a46dSStephen Warren 896c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len); 897f866a46dSStephen Warren 898f866a46dSStephen Warren return 0; 899f866a46dSStephen Warren } 900f866a46dSStephen Warren 901f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) 90201298da3SJean-Jacques Hiblot static int mmc_boot_part_access_chk(struct mmc *mmc, unsigned int part_num) 90301298da3SJean-Jacques Hiblot { 90401298da3SJean-Jacques Hiblot int forbidden = 0; 90501298da3SJean-Jacques Hiblot bool change = false; 90601298da3SJean-Jacques Hiblot 90701298da3SJean-Jacques Hiblot if (part_num & PART_ACCESS_MASK) 90801298da3SJean-Jacques Hiblot forbidden = MMC_CAP(MMC_HS_200); 90901298da3SJean-Jacques Hiblot 91001298da3SJean-Jacques Hiblot if (MMC_CAP(mmc->selected_mode) & forbidden) { 91101298da3SJean-Jacques Hiblot debug("selected mode (%s) is forbidden for part %d\n", 91201298da3SJean-Jacques Hiblot mmc_mode_name(mmc->selected_mode), part_num); 91301298da3SJean-Jacques Hiblot change = true; 91401298da3SJean-Jacques Hiblot } else if (mmc->selected_mode != mmc->best_mode) { 91501298da3SJean-Jacques Hiblot debug("selected mode is not optimal\n"); 91601298da3SJean-Jacques Hiblot change = true; 91701298da3SJean-Jacques Hiblot } 91801298da3SJean-Jacques Hiblot 91901298da3SJean-Jacques Hiblot if (change) 92001298da3SJean-Jacques Hiblot return mmc_select_mode_and_width(mmc, 92101298da3SJean-Jacques Hiblot mmc->card_caps & ~forbidden); 92201298da3SJean-Jacques Hiblot 92301298da3SJean-Jacques Hiblot return 0; 92401298da3SJean-Jacques Hiblot } 925f99c2efeSJean-Jacques Hiblot #else 926f99c2efeSJean-Jacques Hiblot static inline int mmc_boot_part_access_chk(struct mmc *mmc, 927f99c2efeSJean-Jacques Hiblot unsigned int part_num) 928f99c2efeSJean-Jacques Hiblot { 929f99c2efeSJean-Jacques Hiblot return 0; 930f99c2efeSJean-Jacques Hiblot } 931f99c2efeSJean-Jacques Hiblot #endif 93201298da3SJean-Jacques Hiblot 9337dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num) 934bc897b1dSLei Wen { 935f866a46dSStephen Warren int ret; 936bc897b1dSLei Wen 93701298da3SJean-Jacques Hiblot ret = mmc_boot_part_access_chk(mmc, part_num); 93801298da3SJean-Jacques Hiblot if (ret) 93901298da3SJean-Jacques Hiblot return ret; 94001298da3SJean-Jacques Hiblot 941f866a46dSStephen Warren ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 942bc897b1dSLei Wen (mmc->part_config & ~PART_ACCESS_MASK) 943bc897b1dSLei Wen | (part_num & PART_ACCESS_MASK)); 944f866a46dSStephen Warren 9456dc93e70SPeter Bigot /* 9466dc93e70SPeter Bigot * Set the capacity if the switch succeeded or was intended 9476dc93e70SPeter Bigot * to return to representing the raw device. 9486dc93e70SPeter Bigot */ 949873cc1d7SStephen Warren if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) { 9506dc93e70SPeter Bigot ret = mmc_set_capacity(mmc, part_num); 951fdbb139fSSimon Glass mmc_get_blk_desc(mmc)->hwpart = part_num; 952873cc1d7SStephen Warren } 9536dc93e70SPeter Bigot 9546dc93e70SPeter Bigot return ret; 955bc897b1dSLei Wen } 956bc897b1dSLei Wen 957cf17789eSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING) 958ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc, 959ac9da0e0SDiego Santa Cruz const struct mmc_hwpart_conf *conf, 960ac9da0e0SDiego Santa Cruz enum mmc_hwpart_conf_mode mode) 961ac9da0e0SDiego Santa Cruz { 962ac9da0e0SDiego Santa Cruz u8 part_attrs = 0; 963ac9da0e0SDiego Santa Cruz u32 enh_size_mult; 964ac9da0e0SDiego Santa Cruz u32 enh_start_addr; 965ac9da0e0SDiego Santa Cruz u32 gp_size_mult[4]; 966ac9da0e0SDiego Santa Cruz u32 max_enh_size_mult; 967ac9da0e0SDiego Santa Cruz u32 tot_enh_size_mult = 0; 9688dda5b0eSDiego Santa Cruz u8 wr_rel_set; 969ac9da0e0SDiego Santa Cruz int i, pidx, err; 970ac9da0e0SDiego Santa Cruz ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 971ac9da0e0SDiego Santa Cruz 972ac9da0e0SDiego Santa Cruz if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE) 973ac9da0e0SDiego Santa Cruz return -EINVAL; 974ac9da0e0SDiego Santa Cruz 975ac9da0e0SDiego Santa Cruz if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) { 976d8e3d420SJean-Jacques Hiblot pr_err("eMMC >= 4.4 required for enhanced user data area\n"); 977ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 978ac9da0e0SDiego Santa Cruz } 979ac9da0e0SDiego Santa Cruz 980ac9da0e0SDiego Santa Cruz if (!(mmc->part_support & PART_SUPPORT)) { 981d8e3d420SJean-Jacques Hiblot pr_err("Card does not support partitioning\n"); 982ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 983ac9da0e0SDiego Santa Cruz } 984ac9da0e0SDiego Santa Cruz 985ac9da0e0SDiego Santa Cruz if (!mmc->hc_wp_grp_size) { 986d8e3d420SJean-Jacques Hiblot pr_err("Card does not define HC WP group size\n"); 987ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 988ac9da0e0SDiego Santa Cruz } 989ac9da0e0SDiego Santa Cruz 990ac9da0e0SDiego Santa Cruz /* check partition alignment and total enhanced size */ 991ac9da0e0SDiego Santa Cruz if (conf->user.enh_size) { 992ac9da0e0SDiego Santa Cruz if (conf->user.enh_size % mmc->hc_wp_grp_size || 993ac9da0e0SDiego Santa Cruz conf->user.enh_start % mmc->hc_wp_grp_size) { 994d8e3d420SJean-Jacques Hiblot pr_err("User data enhanced area not HC WP group " 995ac9da0e0SDiego Santa Cruz "size aligned\n"); 996ac9da0e0SDiego Santa Cruz return -EINVAL; 997ac9da0e0SDiego Santa Cruz } 998ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_USR; 999ac9da0e0SDiego Santa Cruz enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size; 1000ac9da0e0SDiego Santa Cruz if (mmc->high_capacity) { 1001ac9da0e0SDiego Santa Cruz enh_start_addr = conf->user.enh_start; 1002ac9da0e0SDiego Santa Cruz } else { 1003ac9da0e0SDiego Santa Cruz enh_start_addr = (conf->user.enh_start << 9); 1004ac9da0e0SDiego Santa Cruz } 1005ac9da0e0SDiego Santa Cruz } else { 1006ac9da0e0SDiego Santa Cruz enh_size_mult = 0; 1007ac9da0e0SDiego Santa Cruz enh_start_addr = 0; 1008ac9da0e0SDiego Santa Cruz } 1009ac9da0e0SDiego Santa Cruz tot_enh_size_mult += enh_size_mult; 1010ac9da0e0SDiego Santa Cruz 1011ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 1012ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) { 1013d8e3d420SJean-Jacques Hiblot pr_err("GP%i partition not HC WP group size " 1014ac9da0e0SDiego Santa Cruz "aligned\n", pidx+1); 1015ac9da0e0SDiego Santa Cruz return -EINVAL; 1016ac9da0e0SDiego Santa Cruz } 1017ac9da0e0SDiego Santa Cruz gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size; 1018ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) { 1019ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_GP(pidx); 1020ac9da0e0SDiego Santa Cruz tot_enh_size_mult += gp_size_mult[pidx]; 1021ac9da0e0SDiego Santa Cruz } 1022ac9da0e0SDiego Santa Cruz } 1023ac9da0e0SDiego Santa Cruz 1024ac9da0e0SDiego Santa Cruz if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) { 1025d8e3d420SJean-Jacques Hiblot pr_err("Card does not support enhanced attribute\n"); 1026ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1027ac9da0e0SDiego Santa Cruz } 1028ac9da0e0SDiego Santa Cruz 1029ac9da0e0SDiego Santa Cruz err = mmc_send_ext_csd(mmc, ext_csd); 1030ac9da0e0SDiego Santa Cruz if (err) 1031ac9da0e0SDiego Santa Cruz return err; 1032ac9da0e0SDiego Santa Cruz 1033ac9da0e0SDiego Santa Cruz max_enh_size_mult = 1034ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) + 1035ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) + 1036ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]; 1037ac9da0e0SDiego Santa Cruz if (tot_enh_size_mult > max_enh_size_mult) { 1038d8e3d420SJean-Jacques Hiblot pr_err("Total enhanced size exceeds maximum (%u > %u)\n", 1039ac9da0e0SDiego Santa Cruz tot_enh_size_mult, max_enh_size_mult); 1040ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1041ac9da0e0SDiego Santa Cruz } 1042ac9da0e0SDiego Santa Cruz 10438dda5b0eSDiego Santa Cruz /* The default value of EXT_CSD_WR_REL_SET is device 10448dda5b0eSDiego Santa Cruz * dependent, the values can only be changed if the 10458dda5b0eSDiego Santa Cruz * EXT_CSD_HS_CTRL_REL bit is set. The values can be 10468dda5b0eSDiego Santa Cruz * changed only once and before partitioning is completed. */ 10478dda5b0eSDiego Santa Cruz wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 10488dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_change) { 10498dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_set) 10508dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_USR; 10518dda5b0eSDiego Santa Cruz else 10528dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR; 10538dda5b0eSDiego Santa Cruz } 10548dda5b0eSDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 10558dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_change) { 10568dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_set) 10578dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx); 10588dda5b0eSDiego Santa Cruz else 10598dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx); 10608dda5b0eSDiego Santa Cruz } 10618dda5b0eSDiego Santa Cruz } 10628dda5b0eSDiego Santa Cruz 10638dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] && 10648dda5b0eSDiego Santa Cruz !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) { 10658dda5b0eSDiego Santa Cruz puts("Card does not support host controlled partition write " 10668dda5b0eSDiego Santa Cruz "reliability settings\n"); 10678dda5b0eSDiego Santa Cruz return -EMEDIUMTYPE; 10688dda5b0eSDiego Santa Cruz } 10698dda5b0eSDiego Santa Cruz 1070ac9da0e0SDiego Santa Cruz if (ext_csd[EXT_CSD_PARTITION_SETTING] & 1071ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED) { 1072d8e3d420SJean-Jacques Hiblot pr_err("Card already partitioned\n"); 1073ac9da0e0SDiego Santa Cruz return -EPERM; 1074ac9da0e0SDiego Santa Cruz } 1075ac9da0e0SDiego Santa Cruz 1076ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_CHECK) 1077ac9da0e0SDiego Santa Cruz return 0; 1078ac9da0e0SDiego Santa Cruz 1079ac9da0e0SDiego Santa Cruz /* Partitioning requires high-capacity size definitions */ 1080ac9da0e0SDiego Santa Cruz if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) { 1081ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1082ac9da0e0SDiego Santa Cruz EXT_CSD_ERASE_GROUP_DEF, 1); 1083ac9da0e0SDiego Santa Cruz 1084ac9da0e0SDiego Santa Cruz if (err) 1085ac9da0e0SDiego Santa Cruz return err; 1086ac9da0e0SDiego Santa Cruz 1087ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 1088ac9da0e0SDiego Santa Cruz 1089ac9da0e0SDiego Santa Cruz /* update erase group size to be high-capacity */ 1090ac9da0e0SDiego Santa Cruz mmc->erase_grp_size = 1091ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 1092ac9da0e0SDiego Santa Cruz 1093ac9da0e0SDiego Santa Cruz } 1094ac9da0e0SDiego Santa Cruz 1095ac9da0e0SDiego Santa Cruz /* all OK, write the configuration */ 1096ac9da0e0SDiego Santa Cruz for (i = 0; i < 4; i++) { 1097ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1098ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_START_ADDR+i, 1099ac9da0e0SDiego Santa Cruz (enh_start_addr >> (i*8)) & 0xFF); 1100ac9da0e0SDiego Santa Cruz if (err) 1101ac9da0e0SDiego Santa Cruz return err; 1102ac9da0e0SDiego Santa Cruz } 1103ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 1104ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1105ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_SIZE_MULT+i, 1106ac9da0e0SDiego Santa Cruz (enh_size_mult >> (i*8)) & 0xFF); 1107ac9da0e0SDiego Santa Cruz if (err) 1108ac9da0e0SDiego Santa Cruz return err; 1109ac9da0e0SDiego Santa Cruz } 1110ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 1111ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 1112ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1113ac9da0e0SDiego Santa Cruz EXT_CSD_GP_SIZE_MULT+pidx*3+i, 1114ac9da0e0SDiego Santa Cruz (gp_size_mult[pidx] >> (i*8)) & 0xFF); 1115ac9da0e0SDiego Santa Cruz if (err) 1116ac9da0e0SDiego Santa Cruz return err; 1117ac9da0e0SDiego Santa Cruz } 1118ac9da0e0SDiego Santa Cruz } 1119ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1120ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs); 1121ac9da0e0SDiego Santa Cruz if (err) 1122ac9da0e0SDiego Santa Cruz return err; 1123ac9da0e0SDiego Santa Cruz 1124ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_SET) 1125ac9da0e0SDiego Santa Cruz return 0; 1126ac9da0e0SDiego Santa Cruz 11278dda5b0eSDiego Santa Cruz /* The WR_REL_SET is a write-once register but shall be 11288dda5b0eSDiego Santa Cruz * written before setting PART_SETTING_COMPLETED. As it is 11298dda5b0eSDiego Santa Cruz * write-once we can only write it when completing the 11308dda5b0eSDiego Santa Cruz * partitioning. */ 11318dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) { 11328dda5b0eSDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 11338dda5b0eSDiego Santa Cruz EXT_CSD_WR_REL_SET, wr_rel_set); 11348dda5b0eSDiego Santa Cruz if (err) 11358dda5b0eSDiego Santa Cruz return err; 11368dda5b0eSDiego Santa Cruz } 11378dda5b0eSDiego Santa Cruz 1138ac9da0e0SDiego Santa Cruz /* Setting PART_SETTING_COMPLETED confirms the partition 1139ac9da0e0SDiego Santa Cruz * configuration but it only becomes effective after power 1140ac9da0e0SDiego Santa Cruz * cycle, so we do not adjust the partition related settings 1141ac9da0e0SDiego Santa Cruz * in the mmc struct. */ 1142ac9da0e0SDiego Santa Cruz 1143ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1144ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING, 1145ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 1146ac9da0e0SDiego Santa Cruz if (err) 1147ac9da0e0SDiego Santa Cruz return err; 1148ac9da0e0SDiego Santa Cruz 1149ac9da0e0SDiego Santa Cruz return 0; 1150ac9da0e0SDiego Santa Cruz } 1151cf17789eSJean-Jacques Hiblot #endif 1152ac9da0e0SDiego Santa Cruz 1153e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 115448972d90SThierry Reding int mmc_getcd(struct mmc *mmc) 115548972d90SThierry Reding { 115648972d90SThierry Reding int cd; 115748972d90SThierry Reding 115848972d90SThierry Reding cd = board_mmc_getcd(mmc); 115948972d90SThierry Reding 1160d4e1da4eSPeter Korsgaard if (cd < 0) { 116193bfd616SPantelis Antoniou if (mmc->cfg->ops->getcd) 116293bfd616SPantelis Antoniou cd = mmc->cfg->ops->getcd(mmc); 1163d4e1da4eSPeter Korsgaard else 1164d4e1da4eSPeter Korsgaard cd = 1; 1165d4e1da4eSPeter Korsgaard } 116648972d90SThierry Reding 116748972d90SThierry Reding return cd; 116848972d90SThierry Reding } 11698ca51e51SSimon Glass #endif 117048972d90SThierry Reding 1171fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) 1172272cc70bSAndy Fleming { 1173272cc70bSAndy Fleming struct mmc_cmd cmd; 1174272cc70bSAndy Fleming struct mmc_data data; 1175272cc70bSAndy Fleming 1176272cc70bSAndy Fleming /* Switch the frequency */ 1177272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC; 1178272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1179272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff; 1180272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4)); 1181272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4); 1182272cc70bSAndy Fleming 1183272cc70bSAndy Fleming data.dest = (char *)resp; 1184272cc70bSAndy Fleming data.blocksize = 64; 1185272cc70bSAndy Fleming data.blocks = 1; 1186272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1187272cc70bSAndy Fleming 1188272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 1189272cc70bSAndy Fleming } 1190272cc70bSAndy Fleming 1191272cc70bSAndy Fleming 1192d0c221feSJean-Jacques Hiblot static int sd_get_capabilities(struct mmc *mmc) 1193272cc70bSAndy Fleming { 1194272cc70bSAndy Fleming int err; 1195272cc70bSAndy Fleming struct mmc_cmd cmd; 119618e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2); 119718e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16); 1198272cc70bSAndy Fleming struct mmc_data data; 1199272cc70bSAndy Fleming int timeout; 1200f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1201c10b85d6SJean-Jacques Hiblot u32 sd3_bus_mode; 1202f99c2efeSJean-Jacques Hiblot #endif 1203272cc70bSAndy Fleming 120400e446faSJean-Jacques Hiblot mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(SD_LEGACY); 1205272cc70bSAndy Fleming 1206d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 1207d52ebf10SThomas Chou return 0; 1208d52ebf10SThomas Chou 1209272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */ 1210272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 1211272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1212272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1213272cc70bSAndy Fleming 1214272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1215272cc70bSAndy Fleming 1216272cc70bSAndy Fleming if (err) 1217272cc70bSAndy Fleming return err; 1218272cc70bSAndy Fleming 1219272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR; 1220272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1221272cc70bSAndy Fleming cmd.cmdarg = 0; 1222272cc70bSAndy Fleming 1223272cc70bSAndy Fleming timeout = 3; 1224272cc70bSAndy Fleming 1225272cc70bSAndy Fleming retry_scr: 1226f781dd38SAnton staaf data.dest = (char *)scr; 1227272cc70bSAndy Fleming data.blocksize = 8; 1228272cc70bSAndy Fleming data.blocks = 1; 1229272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1230272cc70bSAndy Fleming 1231272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 1232272cc70bSAndy Fleming 1233272cc70bSAndy Fleming if (err) { 1234272cc70bSAndy Fleming if (timeout--) 1235272cc70bSAndy Fleming goto retry_scr; 1236272cc70bSAndy Fleming 1237272cc70bSAndy Fleming return err; 1238272cc70bSAndy Fleming } 1239272cc70bSAndy Fleming 12404e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]); 12414e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]); 1242272cc70bSAndy Fleming 1243272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) { 1244272cc70bSAndy Fleming case 0: 1245272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1246272cc70bSAndy Fleming break; 1247272cc70bSAndy Fleming case 1: 1248272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10; 1249272cc70bSAndy Fleming break; 1250272cc70bSAndy Fleming case 2: 1251272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 12521741c64dSJaehoon Chung if ((mmc->scr[0] >> 15) & 0x1) 12531741c64dSJaehoon Chung mmc->version = SD_VERSION_3; 1254272cc70bSAndy Fleming break; 1255272cc70bSAndy Fleming default: 1256272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1257272cc70bSAndy Fleming break; 1258272cc70bSAndy Fleming } 1259272cc70bSAndy Fleming 1260b44c7083SAlagu Sankar if (mmc->scr[0] & SD_DATA_4BIT) 1261b44c7083SAlagu Sankar mmc->card_caps |= MMC_MODE_4BIT; 1262b44c7083SAlagu Sankar 1263272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */ 1264272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0) 1265272cc70bSAndy Fleming return 0; 1266272cc70bSAndy Fleming 1267272cc70bSAndy Fleming timeout = 4; 1268272cc70bSAndy Fleming while (timeout--) { 1269272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, 1270f781dd38SAnton staaf (u8 *)switch_status); 1271272cc70bSAndy Fleming 1272272cc70bSAndy Fleming if (err) 1273272cc70bSAndy Fleming return err; 1274272cc70bSAndy Fleming 1275272cc70bSAndy Fleming /* The high-speed function is busy. Try again */ 12764e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) 1277272cc70bSAndy Fleming break; 1278272cc70bSAndy Fleming } 1279272cc70bSAndy Fleming 1280272cc70bSAndy Fleming /* If high-speed isn't supported, we return */ 1281d0c221feSJean-Jacques Hiblot if (__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED) 1282d0c221feSJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(SD_HS); 1283272cc70bSAndy Fleming 1284f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1285c10b85d6SJean-Jacques Hiblot /* Version before 3.0 don't support UHS modes */ 1286c10b85d6SJean-Jacques Hiblot if (mmc->version < SD_VERSION_3) 1287c10b85d6SJean-Jacques Hiblot return 0; 1288c10b85d6SJean-Jacques Hiblot 1289c10b85d6SJean-Jacques Hiblot sd3_bus_mode = __be32_to_cpu(switch_status[3]) >> 16 & 0x1f; 1290c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR104) 1291c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR104); 1292c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR50) 1293c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR50); 1294c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR25) 1295c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR25); 1296c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR12) 1297c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR12); 1298c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_DDR50) 1299c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_DDR50); 1300f99c2efeSJean-Jacques Hiblot #endif 1301c10b85d6SJean-Jacques Hiblot 13022c3fbf4cSMacpaul Lin return 0; 1303d0c221feSJean-Jacques Hiblot } 1304d0c221feSJean-Jacques Hiblot 1305d0c221feSJean-Jacques Hiblot static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode) 1306d0c221feSJean-Jacques Hiblot { 1307d0c221feSJean-Jacques Hiblot int err; 1308d0c221feSJean-Jacques Hiblot 1309d0c221feSJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16); 1310c10b85d6SJean-Jacques Hiblot int speed; 13112c3fbf4cSMacpaul Lin 1312c10b85d6SJean-Jacques Hiblot switch (mode) { 1313c10b85d6SJean-Jacques Hiblot case SD_LEGACY: 1314c10b85d6SJean-Jacques Hiblot speed = UHS_SDR12_BUS_SPEED; 1315c10b85d6SJean-Jacques Hiblot break; 1316c10b85d6SJean-Jacques Hiblot case SD_HS: 1317*baef2070SJean-Jacques Hiblot speed = HIGH_SPEED_BUS_SPEED; 1318*baef2070SJean-Jacques Hiblot break; 1319*baef2070SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1320*baef2070SJean-Jacques Hiblot case UHS_SDR12: 1321*baef2070SJean-Jacques Hiblot speed = UHS_SDR12_BUS_SPEED; 1322*baef2070SJean-Jacques Hiblot break; 1323c10b85d6SJean-Jacques Hiblot case UHS_SDR25: 1324c10b85d6SJean-Jacques Hiblot speed = UHS_SDR25_BUS_SPEED; 1325c10b85d6SJean-Jacques Hiblot break; 1326c10b85d6SJean-Jacques Hiblot case UHS_SDR50: 1327c10b85d6SJean-Jacques Hiblot speed = UHS_SDR50_BUS_SPEED; 1328c10b85d6SJean-Jacques Hiblot break; 1329c10b85d6SJean-Jacques Hiblot case UHS_DDR50: 1330c10b85d6SJean-Jacques Hiblot speed = UHS_DDR50_BUS_SPEED; 1331c10b85d6SJean-Jacques Hiblot break; 1332c10b85d6SJean-Jacques Hiblot case UHS_SDR104: 1333c10b85d6SJean-Jacques Hiblot speed = UHS_SDR104_BUS_SPEED; 1334c10b85d6SJean-Jacques Hiblot break; 1335*baef2070SJean-Jacques Hiblot #endif 1336c10b85d6SJean-Jacques Hiblot default: 1337c10b85d6SJean-Jacques Hiblot return -EINVAL; 1338c10b85d6SJean-Jacques Hiblot } 1339c10b85d6SJean-Jacques Hiblot 1340c10b85d6SJean-Jacques Hiblot err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, speed, (u8 *)switch_status); 1341272cc70bSAndy Fleming if (err) 1342272cc70bSAndy Fleming return err; 1343272cc70bSAndy Fleming 1344c10b85d6SJean-Jacques Hiblot if ((__be32_to_cpu(switch_status[4]) >> 24) != speed) 1345d0c221feSJean-Jacques Hiblot return -ENOTSUPP; 1346d0c221feSJean-Jacques Hiblot 1347d0c221feSJean-Jacques Hiblot return 0; 1348d0c221feSJean-Jacques Hiblot } 1349d0c221feSJean-Jacques Hiblot 1350d0c221feSJean-Jacques Hiblot int sd_select_bus_width(struct mmc *mmc, int w) 1351d0c221feSJean-Jacques Hiblot { 1352d0c221feSJean-Jacques Hiblot int err; 1353d0c221feSJean-Jacques Hiblot struct mmc_cmd cmd; 1354d0c221feSJean-Jacques Hiblot 1355d0c221feSJean-Jacques Hiblot if ((w != 4) && (w != 1)) 1356d0c221feSJean-Jacques Hiblot return -EINVAL; 1357d0c221feSJean-Jacques Hiblot 1358d0c221feSJean-Jacques Hiblot cmd.cmdidx = MMC_CMD_APP_CMD; 1359d0c221feSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 1360d0c221feSJean-Jacques Hiblot cmd.cmdarg = mmc->rca << 16; 1361d0c221feSJean-Jacques Hiblot 1362d0c221feSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 1363d0c221feSJean-Jacques Hiblot if (err) 1364d0c221feSJean-Jacques Hiblot return err; 1365d0c221feSJean-Jacques Hiblot 1366d0c221feSJean-Jacques Hiblot cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; 1367d0c221feSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 1368d0c221feSJean-Jacques Hiblot if (w == 4) 1369d0c221feSJean-Jacques Hiblot cmd.cmdarg = 2; 1370d0c221feSJean-Jacques Hiblot else if (w == 1) 1371d0c221feSJean-Jacques Hiblot cmd.cmdarg = 0; 1372d0c221feSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 1373d0c221feSJean-Jacques Hiblot if (err) 1374d0c221feSJean-Jacques Hiblot return err; 1375272cc70bSAndy Fleming 1376272cc70bSAndy Fleming return 0; 1377272cc70bSAndy Fleming } 1378272cc70bSAndy Fleming 13793697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc) 13803697e599SPeng Fan { 13813697e599SPeng Fan int err, i; 13823697e599SPeng Fan struct mmc_cmd cmd; 13833697e599SPeng Fan ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16); 13843697e599SPeng Fan struct mmc_data data; 13853697e599SPeng Fan int timeout = 3; 13863697e599SPeng Fan unsigned int au, eo, et, es; 13873697e599SPeng Fan 13883697e599SPeng Fan cmd.cmdidx = MMC_CMD_APP_CMD; 13893697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 13903697e599SPeng Fan cmd.cmdarg = mmc->rca << 16; 13913697e599SPeng Fan 13923697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, NULL); 13933697e599SPeng Fan if (err) 13943697e599SPeng Fan return err; 13953697e599SPeng Fan 13963697e599SPeng Fan cmd.cmdidx = SD_CMD_APP_SD_STATUS; 13973697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 13983697e599SPeng Fan cmd.cmdarg = 0; 13993697e599SPeng Fan 14003697e599SPeng Fan retry_ssr: 14013697e599SPeng Fan data.dest = (char *)ssr; 14023697e599SPeng Fan data.blocksize = 64; 14033697e599SPeng Fan data.blocks = 1; 14043697e599SPeng Fan data.flags = MMC_DATA_READ; 14053697e599SPeng Fan 14063697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, &data); 14073697e599SPeng Fan if (err) { 14083697e599SPeng Fan if (timeout--) 14093697e599SPeng Fan goto retry_ssr; 14103697e599SPeng Fan 14113697e599SPeng Fan return err; 14123697e599SPeng Fan } 14133697e599SPeng Fan 14143697e599SPeng Fan for (i = 0; i < 16; i++) 14153697e599SPeng Fan ssr[i] = be32_to_cpu(ssr[i]); 14163697e599SPeng Fan 14173697e599SPeng Fan au = (ssr[2] >> 12) & 0xF; 14183697e599SPeng Fan if ((au <= 9) || (mmc->version == SD_VERSION_3)) { 14193697e599SPeng Fan mmc->ssr.au = sd_au_size[au]; 14203697e599SPeng Fan es = (ssr[3] >> 24) & 0xFF; 14213697e599SPeng Fan es |= (ssr[2] & 0xFF) << 8; 14223697e599SPeng Fan et = (ssr[3] >> 18) & 0x3F; 14233697e599SPeng Fan if (es && et) { 14243697e599SPeng Fan eo = (ssr[3] >> 16) & 0x3; 14253697e599SPeng Fan mmc->ssr.erase_timeout = (et * 1000) / es; 14263697e599SPeng Fan mmc->ssr.erase_offset = eo * 1000; 14273697e599SPeng Fan } 14283697e599SPeng Fan } else { 14293697e599SPeng Fan debug("Invalid Allocation Unit Size.\n"); 14303697e599SPeng Fan } 14313697e599SPeng Fan 14323697e599SPeng Fan return 0; 14333697e599SPeng Fan } 14343697e599SPeng Fan 1435272cc70bSAndy Fleming /* frequency bases */ 1436272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */ 14375f837c2cSMike Frysinger static const int fbase[] = { 1438272cc70bSAndy Fleming 10000, 1439272cc70bSAndy Fleming 100000, 1440272cc70bSAndy Fleming 1000000, 1441272cc70bSAndy Fleming 10000000, 1442272cc70bSAndy Fleming }; 1443272cc70bSAndy Fleming 1444272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice 1445272cc70bSAndy Fleming * to platforms without floating point. 1446272cc70bSAndy Fleming */ 144761fe076fSSimon Glass static const u8 multipliers[] = { 1448272cc70bSAndy Fleming 0, /* reserved */ 1449272cc70bSAndy Fleming 10, 1450272cc70bSAndy Fleming 12, 1451272cc70bSAndy Fleming 13, 1452272cc70bSAndy Fleming 15, 1453272cc70bSAndy Fleming 20, 1454272cc70bSAndy Fleming 25, 1455272cc70bSAndy Fleming 30, 1456272cc70bSAndy Fleming 35, 1457272cc70bSAndy Fleming 40, 1458272cc70bSAndy Fleming 45, 1459272cc70bSAndy Fleming 50, 1460272cc70bSAndy Fleming 55, 1461272cc70bSAndy Fleming 60, 1462272cc70bSAndy Fleming 70, 1463272cc70bSAndy Fleming 80, 1464272cc70bSAndy Fleming }; 1465272cc70bSAndy Fleming 1466d0c221feSJean-Jacques Hiblot static inline int bus_width(uint cap) 1467d0c221feSJean-Jacques Hiblot { 1468d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_8BIT) 1469d0c221feSJean-Jacques Hiblot return 8; 1470d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_4BIT) 1471d0c221feSJean-Jacques Hiblot return 4; 1472d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_1BIT) 1473d0c221feSJean-Jacques Hiblot return 1; 1474d8e3d420SJean-Jacques Hiblot pr_warn("invalid bus witdh capability 0x%x\n", cap); 1475d0c221feSJean-Jacques Hiblot return 0; 1476d0c221feSJean-Jacques Hiblot } 1477d0c221feSJean-Jacques Hiblot 1478e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 1479f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 1480ec841209SKishon Vijay Abraham I static int mmc_execute_tuning(struct mmc *mmc, uint opcode) 1481ec841209SKishon Vijay Abraham I { 1482ec841209SKishon Vijay Abraham I return -ENOTSUPP; 1483ec841209SKishon Vijay Abraham I } 1484f99c2efeSJean-Jacques Hiblot #endif 1485ec841209SKishon Vijay Abraham I 1486318a7a57SJean-Jacques Hiblot static void mmc_send_init_stream(struct mmc *mmc) 1487318a7a57SJean-Jacques Hiblot { 1488318a7a57SJean-Jacques Hiblot } 1489318a7a57SJean-Jacques Hiblot 14902a4d212fSKishon Vijay Abraham I static int mmc_set_ios(struct mmc *mmc) 1491272cc70bSAndy Fleming { 14922a4d212fSKishon Vijay Abraham I int ret = 0; 14932a4d212fSKishon Vijay Abraham I 149493bfd616SPantelis Antoniou if (mmc->cfg->ops->set_ios) 14952a4d212fSKishon Vijay Abraham I ret = mmc->cfg->ops->set_ios(mmc); 14962a4d212fSKishon Vijay Abraham I 14972a4d212fSKishon Vijay Abraham I return ret; 1498272cc70bSAndy Fleming } 14998ca51e51SSimon Glass #endif 1500272cc70bSAndy Fleming 150135f67820SKishon Vijay Abraham I int mmc_set_clock(struct mmc *mmc, uint clock, bool disable) 1502272cc70bSAndy Fleming { 150393bfd616SPantelis Antoniou if (clock > mmc->cfg->f_max) 150493bfd616SPantelis Antoniou clock = mmc->cfg->f_max; 1505272cc70bSAndy Fleming 150693bfd616SPantelis Antoniou if (clock < mmc->cfg->f_min) 150793bfd616SPantelis Antoniou clock = mmc->cfg->f_min; 1508272cc70bSAndy Fleming 1509272cc70bSAndy Fleming mmc->clock = clock; 151035f67820SKishon Vijay Abraham I mmc->clk_disable = disable; 1511272cc70bSAndy Fleming 15122a4d212fSKishon Vijay Abraham I return mmc_set_ios(mmc); 1513272cc70bSAndy Fleming } 1514272cc70bSAndy Fleming 15152a4d212fSKishon Vijay Abraham I static int mmc_set_bus_width(struct mmc *mmc, uint width) 1516272cc70bSAndy Fleming { 1517272cc70bSAndy Fleming mmc->bus_width = width; 1518272cc70bSAndy Fleming 15192a4d212fSKishon Vijay Abraham I return mmc_set_ios(mmc); 1520272cc70bSAndy Fleming } 1521272cc70bSAndy Fleming 15224c9d2aaaSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG) 15234c9d2aaaSJean-Jacques Hiblot /* 15244c9d2aaaSJean-Jacques Hiblot * helper function to display the capabilities in a human 15254c9d2aaaSJean-Jacques Hiblot * friendly manner. The capabilities include bus width and 15264c9d2aaaSJean-Jacques Hiblot * supported modes. 15274c9d2aaaSJean-Jacques Hiblot */ 15284c9d2aaaSJean-Jacques Hiblot void mmc_dump_capabilities(const char *text, uint caps) 15294c9d2aaaSJean-Jacques Hiblot { 15304c9d2aaaSJean-Jacques Hiblot enum bus_mode mode; 15314c9d2aaaSJean-Jacques Hiblot 15324c9d2aaaSJean-Jacques Hiblot printf("%s: widths [", text); 15334c9d2aaaSJean-Jacques Hiblot if (caps & MMC_MODE_8BIT) 15344c9d2aaaSJean-Jacques Hiblot printf("8, "); 15354c9d2aaaSJean-Jacques Hiblot if (caps & MMC_MODE_4BIT) 15364c9d2aaaSJean-Jacques Hiblot printf("4, "); 1537d0c221feSJean-Jacques Hiblot if (caps & MMC_MODE_1BIT) 1538d0c221feSJean-Jacques Hiblot printf("1, "); 1539d0c221feSJean-Jacques Hiblot printf("\b\b] modes ["); 15404c9d2aaaSJean-Jacques Hiblot for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++) 15414c9d2aaaSJean-Jacques Hiblot if (MMC_CAP(mode) & caps) 15424c9d2aaaSJean-Jacques Hiblot printf("%s, ", mmc_mode_name(mode)); 15434c9d2aaaSJean-Jacques Hiblot printf("\b\b]\n"); 15444c9d2aaaSJean-Jacques Hiblot } 15454c9d2aaaSJean-Jacques Hiblot #endif 15464c9d2aaaSJean-Jacques Hiblot 1547d0c221feSJean-Jacques Hiblot struct mode_width_tuning { 1548d0c221feSJean-Jacques Hiblot enum bus_mode mode; 1549d0c221feSJean-Jacques Hiblot uint widths; 1550f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 1551634d4849SKishon Vijay Abraham I uint tuning; 1552f99c2efeSJean-Jacques Hiblot #endif 1553d0c221feSJean-Jacques Hiblot }; 1554d0c221feSJean-Jacques Hiblot 1555f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE) 1556bc1e3272SJean-Jacques Hiblot int mmc_voltage_to_mv(enum mmc_voltage voltage) 1557bc1e3272SJean-Jacques Hiblot { 1558bc1e3272SJean-Jacques Hiblot switch (voltage) { 1559bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_000: return 0; 1560bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_330: return 3300; 1561bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_180: return 1800; 1562bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_120: return 1200; 1563bc1e3272SJean-Jacques Hiblot } 1564bc1e3272SJean-Jacques Hiblot return -EINVAL; 1565bc1e3272SJean-Jacques Hiblot } 1566bc1e3272SJean-Jacques Hiblot 1567aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage) 1568aff5d3c8SKishon Vijay Abraham I { 1569bc1e3272SJean-Jacques Hiblot int err; 1570bc1e3272SJean-Jacques Hiblot 1571bc1e3272SJean-Jacques Hiblot if (mmc->signal_voltage == signal_voltage) 1572bc1e3272SJean-Jacques Hiblot return 0; 1573bc1e3272SJean-Jacques Hiblot 1574aff5d3c8SKishon Vijay Abraham I mmc->signal_voltage = signal_voltage; 1575bc1e3272SJean-Jacques Hiblot err = mmc_set_ios(mmc); 1576bc1e3272SJean-Jacques Hiblot if (err) 1577bc1e3272SJean-Jacques Hiblot debug("unable to set voltage (err %d)\n", err); 1578bc1e3272SJean-Jacques Hiblot 1579bc1e3272SJean-Jacques Hiblot return err; 1580aff5d3c8SKishon Vijay Abraham I } 1581f99c2efeSJean-Jacques Hiblot #else 1582f99c2efeSJean-Jacques Hiblot static inline int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage) 1583f99c2efeSJean-Jacques Hiblot { 1584f99c2efeSJean-Jacques Hiblot return 0; 1585f99c2efeSJean-Jacques Hiblot } 1586f99c2efeSJean-Jacques Hiblot #endif 1587aff5d3c8SKishon Vijay Abraham I 1588d0c221feSJean-Jacques Hiblot static const struct mode_width_tuning sd_modes_by_pref[] = { 1589f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1590f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 1591d0c221feSJean-Jacques Hiblot { 1592c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR104, 1593c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1594c10b85d6SJean-Jacques Hiblot .tuning = MMC_CMD_SEND_TUNING_BLOCK 1595c10b85d6SJean-Jacques Hiblot }, 1596f99c2efeSJean-Jacques Hiblot #endif 1597c10b85d6SJean-Jacques Hiblot { 1598c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR50, 1599c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1600c10b85d6SJean-Jacques Hiblot }, 1601c10b85d6SJean-Jacques Hiblot { 1602c10b85d6SJean-Jacques Hiblot .mode = UHS_DDR50, 1603c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1604c10b85d6SJean-Jacques Hiblot }, 1605c10b85d6SJean-Jacques Hiblot { 1606c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR25, 1607c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1608c10b85d6SJean-Jacques Hiblot }, 1609f99c2efeSJean-Jacques Hiblot #endif 1610c10b85d6SJean-Jacques Hiblot { 1611d0c221feSJean-Jacques Hiblot .mode = SD_HS, 1612d0c221feSJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1613d0c221feSJean-Jacques Hiblot }, 1614f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1615d0c221feSJean-Jacques Hiblot { 1616c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR12, 1617c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1618c10b85d6SJean-Jacques Hiblot }, 1619f99c2efeSJean-Jacques Hiblot #endif 1620c10b85d6SJean-Jacques Hiblot { 1621d0c221feSJean-Jacques Hiblot .mode = SD_LEGACY, 1622d0c221feSJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1623d0c221feSJean-Jacques Hiblot } 1624d0c221feSJean-Jacques Hiblot }; 1625d0c221feSJean-Jacques Hiblot 1626d0c221feSJean-Jacques Hiblot #define for_each_sd_mode_by_pref(caps, mwt) \ 1627d0c221feSJean-Jacques Hiblot for (mwt = sd_modes_by_pref;\ 1628d0c221feSJean-Jacques Hiblot mwt < sd_modes_by_pref + ARRAY_SIZE(sd_modes_by_pref);\ 1629d0c221feSJean-Jacques Hiblot mwt++) \ 1630d0c221feSJean-Jacques Hiblot if (caps & MMC_CAP(mwt->mode)) 1631d0c221feSJean-Jacques Hiblot 163201298da3SJean-Jacques Hiblot static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps) 16338ac8a263SJean-Jacques Hiblot { 16348ac8a263SJean-Jacques Hiblot int err; 1635d0c221feSJean-Jacques Hiblot uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT}; 1636d0c221feSJean-Jacques Hiblot const struct mode_width_tuning *mwt; 1637f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1638c10b85d6SJean-Jacques Hiblot bool uhs_en = (mmc->ocr & OCR_S18R) ? true : false; 1639f99c2efeSJean-Jacques Hiblot #else 1640f99c2efeSJean-Jacques Hiblot bool uhs_en = false; 1641f99c2efeSJean-Jacques Hiblot #endif 1642c10b85d6SJean-Jacques Hiblot uint caps; 1643c10b85d6SJean-Jacques Hiblot 164452d241dfSJean-Jacques Hiblot #ifdef DEBUG 164552d241dfSJean-Jacques Hiblot mmc_dump_capabilities("sd card", card_caps); 16461da8eb59SJean-Jacques Hiblot mmc_dump_capabilities("host", mmc->host_caps); 164752d241dfSJean-Jacques Hiblot #endif 16488ac8a263SJean-Jacques Hiblot 16498ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */ 16501da8eb59SJean-Jacques Hiblot caps = card_caps & mmc->host_caps; 16518ac8a263SJean-Jacques Hiblot 1652c10b85d6SJean-Jacques Hiblot if (!uhs_en) 1653c10b85d6SJean-Jacques Hiblot caps &= ~UHS_CAPS; 1654c10b85d6SJean-Jacques Hiblot 1655c10b85d6SJean-Jacques Hiblot for_each_sd_mode_by_pref(caps, mwt) { 1656d0c221feSJean-Jacques Hiblot uint *w; 16578ac8a263SJean-Jacques Hiblot 1658d0c221feSJean-Jacques Hiblot for (w = widths; w < widths + ARRAY_SIZE(widths); w++) { 1659c10b85d6SJean-Jacques Hiblot if (*w & caps & mwt->widths) { 1660d0c221feSJean-Jacques Hiblot debug("trying mode %s width %d (at %d MHz)\n", 1661d0c221feSJean-Jacques Hiblot mmc_mode_name(mwt->mode), 1662d0c221feSJean-Jacques Hiblot bus_width(*w), 1663d0c221feSJean-Jacques Hiblot mmc_mode2freq(mmc, mwt->mode) / 1000000); 1664d0c221feSJean-Jacques Hiblot 1665d0c221feSJean-Jacques Hiblot /* configure the bus width (card + host) */ 1666d0c221feSJean-Jacques Hiblot err = sd_select_bus_width(mmc, bus_width(*w)); 16678ac8a263SJean-Jacques Hiblot if (err) 1668d0c221feSJean-Jacques Hiblot goto error; 1669d0c221feSJean-Jacques Hiblot mmc_set_bus_width(mmc, bus_width(*w)); 16708ac8a263SJean-Jacques Hiblot 1671d0c221feSJean-Jacques Hiblot /* configure the bus mode (card) */ 1672d0c221feSJean-Jacques Hiblot err = sd_set_card_speed(mmc, mwt->mode); 16738ac8a263SJean-Jacques Hiblot if (err) 1674d0c221feSJean-Jacques Hiblot goto error; 16758ac8a263SJean-Jacques Hiblot 1676d0c221feSJean-Jacques Hiblot /* configure the bus mode (host) */ 1677d0c221feSJean-Jacques Hiblot mmc_select_mode(mmc, mwt->mode); 167835f67820SKishon Vijay Abraham I mmc_set_clock(mmc, mmc->tran_speed, false); 16798ac8a263SJean-Jacques Hiblot 1680f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 1681c10b85d6SJean-Jacques Hiblot /* execute tuning if needed */ 1682c10b85d6SJean-Jacques Hiblot if (mwt->tuning && !mmc_host_is_spi(mmc)) { 1683c10b85d6SJean-Jacques Hiblot err = mmc_execute_tuning(mmc, 1684c10b85d6SJean-Jacques Hiblot mwt->tuning); 1685c10b85d6SJean-Jacques Hiblot if (err) { 1686c10b85d6SJean-Jacques Hiblot debug("tuning failed\n"); 1687c10b85d6SJean-Jacques Hiblot goto error; 1688c10b85d6SJean-Jacques Hiblot } 1689c10b85d6SJean-Jacques Hiblot } 1690f99c2efeSJean-Jacques Hiblot #endif 1691c10b85d6SJean-Jacques Hiblot 16928ac8a263SJean-Jacques Hiblot err = sd_read_ssr(mmc); 1693d0c221feSJean-Jacques Hiblot if (!err) 16948ac8a263SJean-Jacques Hiblot return 0; 1695d0c221feSJean-Jacques Hiblot 1696d8e3d420SJean-Jacques Hiblot pr_warn("bad ssr\n"); 1697d0c221feSJean-Jacques Hiblot 1698d0c221feSJean-Jacques Hiblot error: 1699d0c221feSJean-Jacques Hiblot /* revert to a safer bus speed */ 1700d0c221feSJean-Jacques Hiblot mmc_select_mode(mmc, SD_LEGACY); 170135f67820SKishon Vijay Abraham I mmc_set_clock(mmc, mmc->tran_speed, false); 1702d0c221feSJean-Jacques Hiblot } 1703d0c221feSJean-Jacques Hiblot } 1704d0c221feSJean-Jacques Hiblot } 1705d0c221feSJean-Jacques Hiblot 1706d0c221feSJean-Jacques Hiblot printf("unable to select a mode\n"); 1707d0c221feSJean-Jacques Hiblot return -ENOTSUPP; 17088ac8a263SJean-Jacques Hiblot } 17098ac8a263SJean-Jacques Hiblot 17107382e691SJean-Jacques Hiblot /* 17117382e691SJean-Jacques Hiblot * read the compare the part of ext csd that is constant. 17127382e691SJean-Jacques Hiblot * This can be used to check that the transfer is working 17137382e691SJean-Jacques Hiblot * as expected. 17147382e691SJean-Jacques Hiblot */ 17157382e691SJean-Jacques Hiblot static int mmc_read_and_compare_ext_csd(struct mmc *mmc) 17167382e691SJean-Jacques Hiblot { 17177382e691SJean-Jacques Hiblot int err; 17187382e691SJean-Jacques Hiblot const u8 *ext_csd = mmc->ext_csd; 17197382e691SJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 17207382e691SJean-Jacques Hiblot 17211de06b9fSJean-Jacques Hiblot if (mmc->version < MMC_VERSION_4) 17221de06b9fSJean-Jacques Hiblot return 0; 17231de06b9fSJean-Jacques Hiblot 17247382e691SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, test_csd); 17257382e691SJean-Jacques Hiblot if (err) 17267382e691SJean-Jacques Hiblot return err; 17277382e691SJean-Jacques Hiblot 17287382e691SJean-Jacques Hiblot /* Only compare read only fields */ 17297382e691SJean-Jacques Hiblot if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] 17307382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_PARTITIONING_SUPPORT] && 17317382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_WP_GRP_SIZE] 17327382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_WP_GRP_SIZE] && 17337382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_REV] 17347382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_REV] && 17357382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 17367382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] && 17377382e691SJean-Jacques Hiblot memcmp(&ext_csd[EXT_CSD_SEC_CNT], 17387382e691SJean-Jacques Hiblot &test_csd[EXT_CSD_SEC_CNT], 4) == 0) 17397382e691SJean-Jacques Hiblot return 0; 17407382e691SJean-Jacques Hiblot 17417382e691SJean-Jacques Hiblot return -EBADMSG; 17427382e691SJean-Jacques Hiblot } 17437382e691SJean-Jacques Hiblot 1744f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE) 1745bc1e3272SJean-Jacques Hiblot static int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode, 1746bc1e3272SJean-Jacques Hiblot uint32_t allowed_mask) 1747bc1e3272SJean-Jacques Hiblot { 1748bc1e3272SJean-Jacques Hiblot u32 card_mask = 0; 1749bc1e3272SJean-Jacques Hiblot 1750bc1e3272SJean-Jacques Hiblot switch (mode) { 1751bc1e3272SJean-Jacques Hiblot case MMC_HS_200: 1752bc1e3272SJean-Jacques Hiblot if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_8V) 1753bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_180; 1754bc1e3272SJean-Jacques Hiblot if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_2V) 1755bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_120; 1756bc1e3272SJean-Jacques Hiblot break; 1757bc1e3272SJean-Jacques Hiblot case MMC_DDR_52: 1758bc1e3272SJean-Jacques Hiblot if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V) 1759bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_330 | 1760bc1e3272SJean-Jacques Hiblot MMC_SIGNAL_VOLTAGE_180; 1761bc1e3272SJean-Jacques Hiblot if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_2V) 1762bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_120; 1763bc1e3272SJean-Jacques Hiblot break; 1764bc1e3272SJean-Jacques Hiblot default: 1765bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_330; 1766bc1e3272SJean-Jacques Hiblot break; 1767bc1e3272SJean-Jacques Hiblot } 1768bc1e3272SJean-Jacques Hiblot 1769bc1e3272SJean-Jacques Hiblot while (card_mask & allowed_mask) { 1770bc1e3272SJean-Jacques Hiblot enum mmc_voltage best_match; 1771bc1e3272SJean-Jacques Hiblot 1772bc1e3272SJean-Jacques Hiblot best_match = 1 << (ffs(card_mask & allowed_mask) - 1); 1773bc1e3272SJean-Jacques Hiblot if (!mmc_set_signal_voltage(mmc, best_match)) 1774bc1e3272SJean-Jacques Hiblot return 0; 1775bc1e3272SJean-Jacques Hiblot 1776bc1e3272SJean-Jacques Hiblot allowed_mask &= ~best_match; 1777bc1e3272SJean-Jacques Hiblot } 1778bc1e3272SJean-Jacques Hiblot 1779bc1e3272SJean-Jacques Hiblot return -ENOTSUPP; 1780bc1e3272SJean-Jacques Hiblot } 1781f99c2efeSJean-Jacques Hiblot #else 1782f99c2efeSJean-Jacques Hiblot static inline int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode, 1783f99c2efeSJean-Jacques Hiblot uint32_t allowed_mask) 1784f99c2efeSJean-Jacques Hiblot { 1785f99c2efeSJean-Jacques Hiblot return 0; 1786f99c2efeSJean-Jacques Hiblot } 1787f99c2efeSJean-Jacques Hiblot #endif 1788bc1e3272SJean-Jacques Hiblot 17893862b854SJean-Jacques Hiblot static const struct mode_width_tuning mmc_modes_by_pref[] = { 1790f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) 17918ac8a263SJean-Jacques Hiblot { 17923862b854SJean-Jacques Hiblot .mode = MMC_HS_200, 17933862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT, 1794634d4849SKishon Vijay Abraham I .tuning = MMC_CMD_SEND_TUNING_BLOCK_HS200 17953862b854SJean-Jacques Hiblot }, 1796f99c2efeSJean-Jacques Hiblot #endif 17973862b854SJean-Jacques Hiblot { 17983862b854SJean-Jacques Hiblot .mode = MMC_DDR_52, 17993862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT, 18003862b854SJean-Jacques Hiblot }, 18013862b854SJean-Jacques Hiblot { 18023862b854SJean-Jacques Hiblot .mode = MMC_HS_52, 18033862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 18043862b854SJean-Jacques Hiblot }, 18053862b854SJean-Jacques Hiblot { 18063862b854SJean-Jacques Hiblot .mode = MMC_HS, 18073862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 18083862b854SJean-Jacques Hiblot }, 18093862b854SJean-Jacques Hiblot { 18103862b854SJean-Jacques Hiblot .mode = MMC_LEGACY, 18113862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 18123862b854SJean-Jacques Hiblot } 18138ac8a263SJean-Jacques Hiblot }; 18148ac8a263SJean-Jacques Hiblot 18153862b854SJean-Jacques Hiblot #define for_each_mmc_mode_by_pref(caps, mwt) \ 18163862b854SJean-Jacques Hiblot for (mwt = mmc_modes_by_pref;\ 18173862b854SJean-Jacques Hiblot mwt < mmc_modes_by_pref + ARRAY_SIZE(mmc_modes_by_pref);\ 18183862b854SJean-Jacques Hiblot mwt++) \ 18193862b854SJean-Jacques Hiblot if (caps & MMC_CAP(mwt->mode)) 18203862b854SJean-Jacques Hiblot 18213862b854SJean-Jacques Hiblot static const struct ext_csd_bus_width { 18223862b854SJean-Jacques Hiblot uint cap; 18233862b854SJean-Jacques Hiblot bool is_ddr; 18243862b854SJean-Jacques Hiblot uint ext_csd_bits; 18253862b854SJean-Jacques Hiblot } ext_csd_bus_width[] = { 18263862b854SJean-Jacques Hiblot {MMC_MODE_8BIT, true, EXT_CSD_DDR_BUS_WIDTH_8}, 18273862b854SJean-Jacques Hiblot {MMC_MODE_4BIT, true, EXT_CSD_DDR_BUS_WIDTH_4}, 18283862b854SJean-Jacques Hiblot {MMC_MODE_8BIT, false, EXT_CSD_BUS_WIDTH_8}, 18293862b854SJean-Jacques Hiblot {MMC_MODE_4BIT, false, EXT_CSD_BUS_WIDTH_4}, 18303862b854SJean-Jacques Hiblot {MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1}, 18313862b854SJean-Jacques Hiblot }; 18323862b854SJean-Jacques Hiblot 18333862b854SJean-Jacques Hiblot #define for_each_supported_width(caps, ddr, ecbv) \ 18343862b854SJean-Jacques Hiblot for (ecbv = ext_csd_bus_width;\ 18353862b854SJean-Jacques Hiblot ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\ 18363862b854SJean-Jacques Hiblot ecbv++) \ 18373862b854SJean-Jacques Hiblot if ((ddr == ecbv->is_ddr) && (caps & ecbv->cap)) 18383862b854SJean-Jacques Hiblot 183901298da3SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps) 18403862b854SJean-Jacques Hiblot { 18413862b854SJean-Jacques Hiblot int err; 18423862b854SJean-Jacques Hiblot const struct mode_width_tuning *mwt; 18433862b854SJean-Jacques Hiblot const struct ext_csd_bus_width *ecbw; 18443862b854SJean-Jacques Hiblot 184552d241dfSJean-Jacques Hiblot #ifdef DEBUG 184652d241dfSJean-Jacques Hiblot mmc_dump_capabilities("mmc", card_caps); 18471da8eb59SJean-Jacques Hiblot mmc_dump_capabilities("host", mmc->host_caps); 184852d241dfSJean-Jacques Hiblot #endif 184952d241dfSJean-Jacques Hiblot 18508ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */ 18511da8eb59SJean-Jacques Hiblot card_caps &= mmc->host_caps; 18528ac8a263SJean-Jacques Hiblot 18538ac8a263SJean-Jacques Hiblot /* Only version 4 of MMC supports wider bus widths */ 18548ac8a263SJean-Jacques Hiblot if (mmc->version < MMC_VERSION_4) 18558ac8a263SJean-Jacques Hiblot return 0; 18568ac8a263SJean-Jacques Hiblot 1857dfda9d88SJean-Jacques Hiblot if (!mmc->ext_csd) { 1858dfda9d88SJean-Jacques Hiblot debug("No ext_csd found!\n"); /* this should enver happen */ 1859dfda9d88SJean-Jacques Hiblot return -ENOTSUPP; 1860dfda9d88SJean-Jacques Hiblot } 1861dfda9d88SJean-Jacques Hiblot 186201298da3SJean-Jacques Hiblot mmc_set_clock(mmc, mmc->legacy_speed, false); 186301298da3SJean-Jacques Hiblot 186401298da3SJean-Jacques Hiblot for_each_mmc_mode_by_pref(card_caps, mwt) { 186501298da3SJean-Jacques Hiblot for_each_supported_width(card_caps & mwt->widths, 18663862b854SJean-Jacques Hiblot mmc_is_mode_ddr(mwt->mode), ecbw) { 1867bc1e3272SJean-Jacques Hiblot enum mmc_voltage old_voltage; 18683862b854SJean-Jacques Hiblot debug("trying mode %s width %d (at %d MHz)\n", 18693862b854SJean-Jacques Hiblot mmc_mode_name(mwt->mode), 18703862b854SJean-Jacques Hiblot bus_width(ecbw->cap), 18713862b854SJean-Jacques Hiblot mmc_mode2freq(mmc, mwt->mode) / 1000000); 1872bc1e3272SJean-Jacques Hiblot old_voltage = mmc->signal_voltage; 1873bc1e3272SJean-Jacques Hiblot err = mmc_set_lowest_voltage(mmc, mwt->mode, 1874bc1e3272SJean-Jacques Hiblot MMC_ALL_SIGNAL_VOLTAGE); 1875bc1e3272SJean-Jacques Hiblot if (err) 1876bc1e3272SJean-Jacques Hiblot continue; 1877bc1e3272SJean-Jacques Hiblot 18783862b854SJean-Jacques Hiblot /* configure the bus width (card + host) */ 18793862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 18803862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, 18813862b854SJean-Jacques Hiblot ecbw->ext_csd_bits & ~EXT_CSD_DDR_FLAG); 18823862b854SJean-Jacques Hiblot if (err) 18833862b854SJean-Jacques Hiblot goto error; 18843862b854SJean-Jacques Hiblot mmc_set_bus_width(mmc, bus_width(ecbw->cap)); 18853862b854SJean-Jacques Hiblot 18863862b854SJean-Jacques Hiblot /* configure the bus speed (card) */ 18873862b854SJean-Jacques Hiblot err = mmc_set_card_speed(mmc, mwt->mode); 18883862b854SJean-Jacques Hiblot if (err) 18893862b854SJean-Jacques Hiblot goto error; 18903862b854SJean-Jacques Hiblot 18918ac8a263SJean-Jacques Hiblot /* 18923862b854SJean-Jacques Hiblot * configure the bus width AND the ddr mode (card) 18933862b854SJean-Jacques Hiblot * The host side will be taken care of in the next step 18948ac8a263SJean-Jacques Hiblot */ 18953862b854SJean-Jacques Hiblot if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) { 18963862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 18973862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, 18983862b854SJean-Jacques Hiblot ecbw->ext_csd_bits); 18993862b854SJean-Jacques Hiblot if (err) 19003862b854SJean-Jacques Hiblot goto error; 19018ac8a263SJean-Jacques Hiblot } 19028ac8a263SJean-Jacques Hiblot 19033862b854SJean-Jacques Hiblot /* configure the bus mode (host) */ 19043862b854SJean-Jacques Hiblot mmc_select_mode(mmc, mwt->mode); 190535f67820SKishon Vijay Abraham I mmc_set_clock(mmc, mmc->tran_speed, false); 1906f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 19078ac8a263SJean-Jacques Hiblot 1908634d4849SKishon Vijay Abraham I /* execute tuning if needed */ 1909634d4849SKishon Vijay Abraham I if (mwt->tuning) { 1910634d4849SKishon Vijay Abraham I err = mmc_execute_tuning(mmc, mwt->tuning); 1911634d4849SKishon Vijay Abraham I if (err) { 1912634d4849SKishon Vijay Abraham I debug("tuning failed\n"); 1913634d4849SKishon Vijay Abraham I goto error; 1914634d4849SKishon Vijay Abraham I } 1915634d4849SKishon Vijay Abraham I } 1916f99c2efeSJean-Jacques Hiblot #endif 1917634d4849SKishon Vijay Abraham I 19183862b854SJean-Jacques Hiblot /* do a transfer to check the configuration */ 19197382e691SJean-Jacques Hiblot err = mmc_read_and_compare_ext_csd(mmc); 19207382e691SJean-Jacques Hiblot if (!err) 19213862b854SJean-Jacques Hiblot return 0; 19223862b854SJean-Jacques Hiblot error: 1923bc1e3272SJean-Jacques Hiblot mmc_set_signal_voltage(mmc, old_voltage); 19243862b854SJean-Jacques Hiblot /* if an error occured, revert to a safer bus mode */ 19253862b854SJean-Jacques Hiblot mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 19263862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1); 19273862b854SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_LEGACY); 19283862b854SJean-Jacques Hiblot mmc_set_bus_width(mmc, 1); 19293862b854SJean-Jacques Hiblot } 19308ac8a263SJean-Jacques Hiblot } 19318ac8a263SJean-Jacques Hiblot 1932d8e3d420SJean-Jacques Hiblot pr_err("unable to select a mode\n"); 19338ac8a263SJean-Jacques Hiblot 19343862b854SJean-Jacques Hiblot return -ENOTSUPP; 19358ac8a263SJean-Jacques Hiblot } 19368ac8a263SJean-Jacques Hiblot 1937dfda9d88SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc) 1938c744b6f6SJean-Jacques Hiblot { 1939c744b6f6SJean-Jacques Hiblot int err, i; 1940c744b6f6SJean-Jacques Hiblot u64 capacity; 1941c744b6f6SJean-Jacques Hiblot bool has_parts = false; 1942c744b6f6SJean-Jacques Hiblot bool part_completed; 1943f7d5dffcSJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 1944c744b6f6SJean-Jacques Hiblot 1945c744b6f6SJean-Jacques Hiblot if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4)) 1946c744b6f6SJean-Jacques Hiblot return 0; 1947c744b6f6SJean-Jacques Hiblot 1948c744b6f6SJean-Jacques Hiblot /* check ext_csd version and capacity */ 1949c744b6f6SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, ext_csd); 1950c744b6f6SJean-Jacques Hiblot if (err) 1951f7d5dffcSJean-Jacques Hiblot goto error; 1952f7d5dffcSJean-Jacques Hiblot 1953f7d5dffcSJean-Jacques Hiblot /* store the ext csd for future reference */ 1954f7d5dffcSJean-Jacques Hiblot if (!mmc->ext_csd) 1955f7d5dffcSJean-Jacques Hiblot mmc->ext_csd = malloc(MMC_MAX_BLOCK_LEN); 1956f7d5dffcSJean-Jacques Hiblot if (!mmc->ext_csd) 1957f7d5dffcSJean-Jacques Hiblot return -ENOMEM; 1958f7d5dffcSJean-Jacques Hiblot memcpy(mmc->ext_csd, ext_csd, MMC_MAX_BLOCK_LEN); 1959f7d5dffcSJean-Jacques Hiblot 1960c744b6f6SJean-Jacques Hiblot if (ext_csd[EXT_CSD_REV] >= 2) { 1961c744b6f6SJean-Jacques Hiblot /* 1962c744b6f6SJean-Jacques Hiblot * According to the JEDEC Standard, the value of 1963c744b6f6SJean-Jacques Hiblot * ext_csd's capacity is valid if the value is more 1964c744b6f6SJean-Jacques Hiblot * than 2GB 1965c744b6f6SJean-Jacques Hiblot */ 1966c744b6f6SJean-Jacques Hiblot capacity = ext_csd[EXT_CSD_SEC_CNT] << 0 1967c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 1968c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 1969c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; 1970c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN; 1971c744b6f6SJean-Jacques Hiblot if ((capacity >> 20) > 2 * 1024) 1972c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity; 1973c744b6f6SJean-Jacques Hiblot } 1974c744b6f6SJean-Jacques Hiblot 1975c744b6f6SJean-Jacques Hiblot switch (ext_csd[EXT_CSD_REV]) { 1976c744b6f6SJean-Jacques Hiblot case 1: 1977c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_1; 1978c744b6f6SJean-Jacques Hiblot break; 1979c744b6f6SJean-Jacques Hiblot case 2: 1980c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_2; 1981c744b6f6SJean-Jacques Hiblot break; 1982c744b6f6SJean-Jacques Hiblot case 3: 1983c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_3; 1984c744b6f6SJean-Jacques Hiblot break; 1985c744b6f6SJean-Jacques Hiblot case 5: 1986c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_41; 1987c744b6f6SJean-Jacques Hiblot break; 1988c744b6f6SJean-Jacques Hiblot case 6: 1989c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_5; 1990c744b6f6SJean-Jacques Hiblot break; 1991c744b6f6SJean-Jacques Hiblot case 7: 1992c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_5_0; 1993c744b6f6SJean-Jacques Hiblot break; 1994c744b6f6SJean-Jacques Hiblot case 8: 1995c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_5_1; 1996c744b6f6SJean-Jacques Hiblot break; 1997c744b6f6SJean-Jacques Hiblot } 1998c744b6f6SJean-Jacques Hiblot 1999c744b6f6SJean-Jacques Hiblot /* The partition data may be non-zero but it is only 2000c744b6f6SJean-Jacques Hiblot * effective if PARTITION_SETTING_COMPLETED is set in 2001c744b6f6SJean-Jacques Hiblot * EXT_CSD, so ignore any data if this bit is not set, 2002c744b6f6SJean-Jacques Hiblot * except for enabling the high-capacity group size 2003c744b6f6SJean-Jacques Hiblot * definition (see below). 2004c744b6f6SJean-Jacques Hiblot */ 2005c744b6f6SJean-Jacques Hiblot part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] & 2006c744b6f6SJean-Jacques Hiblot EXT_CSD_PARTITION_SETTING_COMPLETED); 2007c744b6f6SJean-Jacques Hiblot 2008c744b6f6SJean-Jacques Hiblot /* store the partition info of emmc */ 2009c744b6f6SJean-Jacques Hiblot mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT]; 2010c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || 2011c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_BOOT_MULT]) 2012c744b6f6SJean-Jacques Hiblot mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; 2013c744b6f6SJean-Jacques Hiblot if (part_completed && 2014c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT)) 2015c744b6f6SJean-Jacques Hiblot mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]; 2016c744b6f6SJean-Jacques Hiblot 2017c744b6f6SJean-Jacques Hiblot mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17; 2018c744b6f6SJean-Jacques Hiblot 2019c744b6f6SJean-Jacques Hiblot mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17; 2020c744b6f6SJean-Jacques Hiblot 2021c744b6f6SJean-Jacques Hiblot for (i = 0; i < 4; i++) { 2022c744b6f6SJean-Jacques Hiblot int idx = EXT_CSD_GP_SIZE_MULT + i * 3; 2023c744b6f6SJean-Jacques Hiblot uint mult = (ext_csd[idx + 2] << 16) + 2024c744b6f6SJean-Jacques Hiblot (ext_csd[idx + 1] << 8) + ext_csd[idx]; 2025c744b6f6SJean-Jacques Hiblot if (mult) 2026c744b6f6SJean-Jacques Hiblot has_parts = true; 2027c744b6f6SJean-Jacques Hiblot if (!part_completed) 2028c744b6f6SJean-Jacques Hiblot continue; 2029c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] = mult; 2030c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= 2031c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 2032c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 2033c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] <<= 19; 2034c744b6f6SJean-Jacques Hiblot } 2035c744b6f6SJean-Jacques Hiblot 2036c744b6f6SJean-Jacques Hiblot if (part_completed) { 2037c744b6f6SJean-Jacques Hiblot mmc->enh_user_size = 2038c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) + 2039c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) + 2040c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_SIZE_MULT]; 2041c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 2042c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 2043c744b6f6SJean-Jacques Hiblot mmc->enh_user_size <<= 19; 2044c744b6f6SJean-Jacques Hiblot mmc->enh_user_start = 2045c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) + 2046c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) + 2047c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) + 2048c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_START_ADDR]; 2049c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity) 2050c744b6f6SJean-Jacques Hiblot mmc->enh_user_start <<= 9; 2051c744b6f6SJean-Jacques Hiblot } 2052c744b6f6SJean-Jacques Hiblot 2053c744b6f6SJean-Jacques Hiblot /* 2054c744b6f6SJean-Jacques Hiblot * Host needs to enable ERASE_GRP_DEF bit if device is 2055c744b6f6SJean-Jacques Hiblot * partitioned. This bit will be lost every time after a reset 2056c744b6f6SJean-Jacques Hiblot * or power off. This will affect erase size. 2057c744b6f6SJean-Jacques Hiblot */ 2058c744b6f6SJean-Jacques Hiblot if (part_completed) 2059c744b6f6SJean-Jacques Hiblot has_parts = true; 2060c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) && 2061c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) 2062c744b6f6SJean-Jacques Hiblot has_parts = true; 2063c744b6f6SJean-Jacques Hiblot if (has_parts) { 2064c744b6f6SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 2065c744b6f6SJean-Jacques Hiblot EXT_CSD_ERASE_GROUP_DEF, 1); 2066c744b6f6SJean-Jacques Hiblot 2067c744b6f6SJean-Jacques Hiblot if (err) 2068f7d5dffcSJean-Jacques Hiblot goto error; 2069c744b6f6SJean-Jacques Hiblot 2070c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 2071c744b6f6SJean-Jacques Hiblot } 2072c744b6f6SJean-Jacques Hiblot 2073c744b6f6SJean-Jacques Hiblot if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) { 2074c744b6f6SJean-Jacques Hiblot /* Read out group size from ext_csd */ 2075c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = 2076c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 2077c744b6f6SJean-Jacques Hiblot /* 2078c744b6f6SJean-Jacques Hiblot * if high capacity and partition setting completed 2079c744b6f6SJean-Jacques Hiblot * SEC_COUNT is valid even if it is smaller than 2 GiB 2080c744b6f6SJean-Jacques Hiblot * JEDEC Standard JESD84-B45, 6.2.4 2081c744b6f6SJean-Jacques Hiblot */ 2082c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity && part_completed) { 2083c744b6f6SJean-Jacques Hiblot capacity = (ext_csd[EXT_CSD_SEC_CNT]) | 2084c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) | 2085c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) | 2086c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 3] << 24); 2087c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN; 2088c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity; 2089c744b6f6SJean-Jacques Hiblot } 2090c744b6f6SJean-Jacques Hiblot } else { 2091c744b6f6SJean-Jacques Hiblot /* Calculate the group size from the csd value. */ 2092c744b6f6SJean-Jacques Hiblot int erase_gsz, erase_gmul; 2093c744b6f6SJean-Jacques Hiblot 2094c744b6f6SJean-Jacques Hiblot erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; 2095c744b6f6SJean-Jacques Hiblot erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; 2096c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = (erase_gsz + 1) 2097c744b6f6SJean-Jacques Hiblot * (erase_gmul + 1); 2098c744b6f6SJean-Jacques Hiblot } 2099c744b6f6SJean-Jacques Hiblot 2100c744b6f6SJean-Jacques Hiblot mmc->hc_wp_grp_size = 1024 2101c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 2102c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 2103c744b6f6SJean-Jacques Hiblot 2104c744b6f6SJean-Jacques Hiblot mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 2105c744b6f6SJean-Jacques Hiblot 2106c744b6f6SJean-Jacques Hiblot return 0; 2107f7d5dffcSJean-Jacques Hiblot error: 2108f7d5dffcSJean-Jacques Hiblot if (mmc->ext_csd) { 2109f7d5dffcSJean-Jacques Hiblot free(mmc->ext_csd); 2110f7d5dffcSJean-Jacques Hiblot mmc->ext_csd = NULL; 2111f7d5dffcSJean-Jacques Hiblot } 2112f7d5dffcSJean-Jacques Hiblot return err; 2113c744b6f6SJean-Jacques Hiblot } 2114c744b6f6SJean-Jacques Hiblot 2115fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc) 2116272cc70bSAndy Fleming { 2117f866a46dSStephen Warren int err, i; 2118272cc70bSAndy Fleming uint mult, freq; 2119c744b6f6SJean-Jacques Hiblot u64 cmult, csize; 2120272cc70bSAndy Fleming struct mmc_cmd cmd; 2121c40fdca6SSimon Glass struct blk_desc *bdesc; 2122272cc70bSAndy Fleming 2123d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON 2124d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ 2125d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; 2126d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R1; 2127d52ebf10SThomas Chou cmd.cmdarg = 1; 2128d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 2129d52ebf10SThomas Chou if (err) 2130d52ebf10SThomas Chou return err; 2131d52ebf10SThomas Chou } 2132d52ebf10SThomas Chou #endif 2133d52ebf10SThomas Chou 2134272cc70bSAndy Fleming /* Put the Card in Identify Mode */ 2135d52ebf10SThomas Chou cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : 2136d52ebf10SThomas Chou MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ 2137272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 2138272cc70bSAndy Fleming cmd.cmdarg = 0; 2139272cc70bSAndy Fleming 2140272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2141272cc70bSAndy Fleming 214283dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS 214383dc4227SKishon Vijay Abraham I if (err && (mmc->quirks & MMC_QUIRK_RETRY_SEND_CID)) { 214483dc4227SKishon Vijay Abraham I int retries = 4; 214583dc4227SKishon Vijay Abraham I /* 214683dc4227SKishon Vijay Abraham I * It has been seen that SEND_CID may fail on the first 214783dc4227SKishon Vijay Abraham I * attempt, let's try a few more time 214883dc4227SKishon Vijay Abraham I */ 214983dc4227SKishon Vijay Abraham I do { 215083dc4227SKishon Vijay Abraham I err = mmc_send_cmd(mmc, &cmd, NULL); 215183dc4227SKishon Vijay Abraham I if (!err) 215283dc4227SKishon Vijay Abraham I break; 215383dc4227SKishon Vijay Abraham I } while (retries--); 215483dc4227SKishon Vijay Abraham I } 215583dc4227SKishon Vijay Abraham I #endif 215683dc4227SKishon Vijay Abraham I 2157272cc70bSAndy Fleming if (err) 2158272cc70bSAndy Fleming return err; 2159272cc70bSAndy Fleming 2160272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16); 2161272cc70bSAndy Fleming 2162272cc70bSAndy Fleming /* 2163272cc70bSAndy Fleming * For MMC cards, set the Relative Address. 2164272cc70bSAndy Fleming * For SD cards, get the Relatvie Address. 2165272cc70bSAndy Fleming * This also puts the cards into Standby State 2166272cc70bSAndy Fleming */ 2167d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 2168272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; 2169272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 2170272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6; 2171272cc70bSAndy Fleming 2172272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2173272cc70bSAndy Fleming 2174272cc70bSAndy Fleming if (err) 2175272cc70bSAndy Fleming return err; 2176272cc70bSAndy Fleming 2177272cc70bSAndy Fleming if (IS_SD(mmc)) 2178998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff; 2179d52ebf10SThomas Chou } 2180272cc70bSAndy Fleming 2181272cc70bSAndy Fleming /* Get the Card-Specific Data */ 2182272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD; 2183272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 2184272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 2185272cc70bSAndy Fleming 2186272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2187272cc70bSAndy Fleming 2188272cc70bSAndy Fleming if (err) 2189272cc70bSAndy Fleming return err; 2190272cc70bSAndy Fleming 2191998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0]; 2192998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1]; 2193998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2]; 2194998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3]; 2195272cc70bSAndy Fleming 2196272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) { 21970b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf; 2198272cc70bSAndy Fleming 2199272cc70bSAndy Fleming switch (version) { 2200272cc70bSAndy Fleming case 0: 2201272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 2202272cc70bSAndy Fleming break; 2203272cc70bSAndy Fleming case 1: 2204272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4; 2205272cc70bSAndy Fleming break; 2206272cc70bSAndy Fleming case 2: 2207272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2; 2208272cc70bSAndy Fleming break; 2209272cc70bSAndy Fleming case 3: 2210272cc70bSAndy Fleming mmc->version = MMC_VERSION_3; 2211272cc70bSAndy Fleming break; 2212272cc70bSAndy Fleming case 4: 2213272cc70bSAndy Fleming mmc->version = MMC_VERSION_4; 2214272cc70bSAndy Fleming break; 2215272cc70bSAndy Fleming default: 2216272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 2217272cc70bSAndy Fleming break; 2218272cc70bSAndy Fleming } 2219272cc70bSAndy Fleming } 2220272cc70bSAndy Fleming 2221272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */ 22220b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)]; 22230b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; 2224272cc70bSAndy Fleming 222535f9e196SJean-Jacques Hiblot mmc->legacy_speed = freq * mult; 222635f9e196SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_LEGACY); 2227272cc70bSAndy Fleming 2228ab71188cSMarkus Niebel mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); 2229998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); 2230272cc70bSAndy Fleming 2231272cc70bSAndy Fleming if (IS_SD(mmc)) 2232272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len; 2233272cc70bSAndy Fleming else 2234998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); 2235272cc70bSAndy Fleming 2236272cc70bSAndy Fleming if (mmc->high_capacity) { 2237272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16 2238272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16; 2239272cc70bSAndy Fleming cmult = 8; 2240272cc70bSAndy Fleming } else { 2241272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2 2242272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30; 2243272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15; 2244272cc70bSAndy Fleming } 2245272cc70bSAndy Fleming 2246f866a46dSStephen Warren mmc->capacity_user = (csize + 1) << (cmult + 2); 2247f866a46dSStephen Warren mmc->capacity_user *= mmc->read_bl_len; 2248f866a46dSStephen Warren mmc->capacity_boot = 0; 2249f866a46dSStephen Warren mmc->capacity_rpmb = 0; 2250f866a46dSStephen Warren for (i = 0; i < 4; i++) 2251f866a46dSStephen Warren mmc->capacity_gp[i] = 0; 2252272cc70bSAndy Fleming 22538bfa195eSSimon Glass if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN) 22548bfa195eSSimon Glass mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 2255272cc70bSAndy Fleming 22568bfa195eSSimon Glass if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) 22578bfa195eSSimon Glass mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 2258272cc70bSAndy Fleming 2259ab71188cSMarkus Niebel if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) { 2260ab71188cSMarkus Niebel cmd.cmdidx = MMC_CMD_SET_DSR; 2261ab71188cSMarkus Niebel cmd.cmdarg = (mmc->dsr & 0xffff) << 16; 2262ab71188cSMarkus Niebel cmd.resp_type = MMC_RSP_NONE; 2263ab71188cSMarkus Niebel if (mmc_send_cmd(mmc, &cmd, NULL)) 2264d8e3d420SJean-Jacques Hiblot pr_warn("MMC: SET_DSR failed\n"); 2265ab71188cSMarkus Niebel } 2266ab71188cSMarkus Niebel 2267272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */ 2268d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 2269272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD; 2270fe8f7066SAjay Bhargav cmd.resp_type = MMC_RSP_R1; 2271272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 2272272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2273272cc70bSAndy Fleming 2274272cc70bSAndy Fleming if (err) 2275272cc70bSAndy Fleming return err; 2276d52ebf10SThomas Chou } 2277272cc70bSAndy Fleming 2278e6f99a56SLei Wen /* 2279e6f99a56SLei Wen * For SD, its erase group is always one sector 2280e6f99a56SLei Wen */ 2281e6f99a56SLei Wen mmc->erase_grp_size = 1; 2282bc897b1dSLei Wen mmc->part_config = MMCPART_NOAVAILABLE; 2283c744b6f6SJean-Jacques Hiblot 2284dfda9d88SJean-Jacques Hiblot err = mmc_startup_v4(mmc); 22859cf199ebSDiego Santa Cruz if (err) 22869cf199ebSDiego Santa Cruz return err; 2287f866a46dSStephen Warren 2288c40fdca6SSimon Glass err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart); 2289f866a46dSStephen Warren if (err) 2290f866a46dSStephen Warren return err; 2291d23e2c09SSukumar Ghorai 229201298da3SJean-Jacques Hiblot if (IS_SD(mmc)) { 229301298da3SJean-Jacques Hiblot err = sd_get_capabilities(mmc); 229401298da3SJean-Jacques Hiblot if (err) 229501298da3SJean-Jacques Hiblot return err; 229601298da3SJean-Jacques Hiblot err = sd_select_mode_and_width(mmc, mmc->card_caps); 229701298da3SJean-Jacques Hiblot } else { 229801298da3SJean-Jacques Hiblot err = mmc_get_capabilities(mmc); 229901298da3SJean-Jacques Hiblot if (err) 230001298da3SJean-Jacques Hiblot return err; 230101298da3SJean-Jacques Hiblot mmc_select_mode_and_width(mmc, mmc->card_caps); 230201298da3SJean-Jacques Hiblot } 2303272cc70bSAndy Fleming 2304272cc70bSAndy Fleming if (err) 2305272cc70bSAndy Fleming return err; 2306272cc70bSAndy Fleming 230701298da3SJean-Jacques Hiblot mmc->best_mode = mmc->selected_mode; 2308272cc70bSAndy Fleming 23095af8f45cSAndrew Gabbasov /* Fix the block length for DDR mode */ 23105af8f45cSAndrew Gabbasov if (mmc->ddr_mode) { 23115af8f45cSAndrew Gabbasov mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 23125af8f45cSAndrew Gabbasov mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 23135af8f45cSAndrew Gabbasov } 23145af8f45cSAndrew Gabbasov 2315272cc70bSAndy Fleming /* fill in device description */ 2316c40fdca6SSimon Glass bdesc = mmc_get_blk_desc(mmc); 2317c40fdca6SSimon Glass bdesc->lun = 0; 2318c40fdca6SSimon Glass bdesc->hwpart = 0; 2319c40fdca6SSimon Glass bdesc->type = 0; 2320c40fdca6SSimon Glass bdesc->blksz = mmc->read_bl_len; 2321c40fdca6SSimon Glass bdesc->log2blksz = LOG2(bdesc->blksz); 2322c40fdca6SSimon Glass bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len); 2323fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \ 2324fc011f64SSjoerd Simons (defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \ 2325fc011f64SSjoerd Simons !defined(CONFIG_USE_TINY_PRINTF)) 2326c40fdca6SSimon Glass sprintf(bdesc->vendor, "Man %06x Snr %04x%04x", 2327babce5f6STaylor Hutt mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), 2328babce5f6STaylor Hutt (mmc->cid[3] >> 16) & 0xffff); 2329c40fdca6SSimon Glass sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff, 23300b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 2331babce5f6STaylor Hutt (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff, 2332babce5f6STaylor Hutt (mmc->cid[2] >> 24) & 0xff); 2333c40fdca6SSimon Glass sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf, 2334babce5f6STaylor Hutt (mmc->cid[2] >> 16) & 0xf); 233556196826SPaul Burton #else 2336c40fdca6SSimon Glass bdesc->vendor[0] = 0; 2337c40fdca6SSimon Glass bdesc->product[0] = 0; 2338c40fdca6SSimon Glass bdesc->revision[0] = 0; 233956196826SPaul Burton #endif 2340122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT) 2341c40fdca6SSimon Glass part_init(bdesc); 2342122efd43SMikhail Kshevetskiy #endif 2343272cc70bSAndy Fleming 2344272cc70bSAndy Fleming return 0; 2345272cc70bSAndy Fleming } 2346272cc70bSAndy Fleming 2347fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc) 2348272cc70bSAndy Fleming { 2349272cc70bSAndy Fleming struct mmc_cmd cmd; 2350272cc70bSAndy Fleming int err; 2351272cc70bSAndy Fleming 2352272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND; 2353272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ 235493bfd616SPantelis Antoniou cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa; 2355272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7; 2356272cc70bSAndy Fleming 2357272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2358272cc70bSAndy Fleming 2359272cc70bSAndy Fleming if (err) 2360272cc70bSAndy Fleming return err; 2361272cc70bSAndy Fleming 2362998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa) 2363915ffa52SJaehoon Chung return -EOPNOTSUPP; 2364272cc70bSAndy Fleming else 2365272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 2366272cc70bSAndy Fleming 2367272cc70bSAndy Fleming return 0; 2368272cc70bSAndy Fleming } 2369272cc70bSAndy Fleming 2370c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 237195de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */ 237295de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void) 237395de9ab2SPaul Kocialkowski { 237495de9ab2SPaul Kocialkowski } 237505cbeb7cSSimon Glass #endif 237695de9ab2SPaul Kocialkowski 23772051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc) 23782051aefeSPeng Fan { 2379c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 238006ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR) 23812051aefeSPeng Fan int ret; 23822051aefeSPeng Fan 23832051aefeSPeng Fan ret = device_get_supply_regulator(mmc->dev, "vmmc-supply", 238406ec045fSJean-Jacques Hiblot &mmc->vmmc_supply); 238506ec045fSJean-Jacques Hiblot if (ret) 2386288db7c7SJaehoon Chung debug("%s: No vmmc supply\n", mmc->dev->name); 23872051aefeSPeng Fan 238806ec045fSJean-Jacques Hiblot ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply", 238906ec045fSJean-Jacques Hiblot &mmc->vqmmc_supply); 239006ec045fSJean-Jacques Hiblot if (ret) 239106ec045fSJean-Jacques Hiblot debug("%s: No vqmmc supply\n", mmc->dev->name); 23922051aefeSPeng Fan #endif 239305cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */ 239405cbeb7cSSimon Glass /* 239505cbeb7cSSimon Glass * Driver model should use a regulator, as above, rather than calling 239605cbeb7cSSimon Glass * out to board code. 239705cbeb7cSSimon Glass */ 239805cbeb7cSSimon Glass board_mmc_power_init(); 239905cbeb7cSSimon Glass #endif 24002051aefeSPeng Fan return 0; 24012051aefeSPeng Fan } 24022051aefeSPeng Fan 2403fb7c3bebSKishon Vijay Abraham I /* 2404fb7c3bebSKishon Vijay Abraham I * put the host in the initial state: 2405fb7c3bebSKishon Vijay Abraham I * - turn on Vdd (card power supply) 2406fb7c3bebSKishon Vijay Abraham I * - configure the bus width and clock to minimal values 2407fb7c3bebSKishon Vijay Abraham I */ 2408fb7c3bebSKishon Vijay Abraham I static void mmc_set_initial_state(struct mmc *mmc) 2409fb7c3bebSKishon Vijay Abraham I { 2410fb7c3bebSKishon Vijay Abraham I int err; 2411fb7c3bebSKishon Vijay Abraham I 2412fb7c3bebSKishon Vijay Abraham I /* First try to set 3.3V. If it fails set to 1.8V */ 2413fb7c3bebSKishon Vijay Abraham I err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_330); 2414fb7c3bebSKishon Vijay Abraham I if (err != 0) 2415fb7c3bebSKishon Vijay Abraham I err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_180); 2416fb7c3bebSKishon Vijay Abraham I if (err != 0) 2417d8e3d420SJean-Jacques Hiblot pr_warn("mmc: failed to set signal voltage\n"); 2418fb7c3bebSKishon Vijay Abraham I 2419fb7c3bebSKishon Vijay Abraham I mmc_select_mode(mmc, MMC_LEGACY); 2420fb7c3bebSKishon Vijay Abraham I mmc_set_bus_width(mmc, 1); 242135f67820SKishon Vijay Abraham I mmc_set_clock(mmc, 0, false); 2422fb7c3bebSKishon Vijay Abraham I } 2423fb7c3bebSKishon Vijay Abraham I 2424fb7c3bebSKishon Vijay Abraham I static int mmc_power_on(struct mmc *mmc) 2425fb7c3bebSKishon Vijay Abraham I { 2426fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR) 2427fb7c3bebSKishon Vijay Abraham I if (mmc->vmmc_supply) { 2428fb7c3bebSKishon Vijay Abraham I int ret = regulator_set_enable(mmc->vmmc_supply, true); 2429fb7c3bebSKishon Vijay Abraham I 2430fb7c3bebSKishon Vijay Abraham I if (ret) { 2431fb7c3bebSKishon Vijay Abraham I puts("Error enabling VMMC supply\n"); 2432fb7c3bebSKishon Vijay Abraham I return ret; 2433fb7c3bebSKishon Vijay Abraham I } 2434fb7c3bebSKishon Vijay Abraham I } 2435fb7c3bebSKishon Vijay Abraham I #endif 2436fb7c3bebSKishon Vijay Abraham I return 0; 2437fb7c3bebSKishon Vijay Abraham I } 2438fb7c3bebSKishon Vijay Abraham I 2439fb7c3bebSKishon Vijay Abraham I static int mmc_power_off(struct mmc *mmc) 2440fb7c3bebSKishon Vijay Abraham I { 24412e7410d7SKishon Vijay Abraham I mmc_set_clock(mmc, 1, true); 2442fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR) 2443fb7c3bebSKishon Vijay Abraham I if (mmc->vmmc_supply) { 2444fb7c3bebSKishon Vijay Abraham I int ret = regulator_set_enable(mmc->vmmc_supply, false); 2445fb7c3bebSKishon Vijay Abraham I 2446fb7c3bebSKishon Vijay Abraham I if (ret) { 2447c10b85d6SJean-Jacques Hiblot debug("Error disabling VMMC supply\n"); 2448fb7c3bebSKishon Vijay Abraham I return ret; 2449fb7c3bebSKishon Vijay Abraham I } 2450fb7c3bebSKishon Vijay Abraham I } 2451fb7c3bebSKishon Vijay Abraham I #endif 2452fb7c3bebSKishon Vijay Abraham I return 0; 2453fb7c3bebSKishon Vijay Abraham I } 2454fb7c3bebSKishon Vijay Abraham I 2455fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc) 2456fb7c3bebSKishon Vijay Abraham I { 2457fb7c3bebSKishon Vijay Abraham I int ret; 2458fb7c3bebSKishon Vijay Abraham I 2459fb7c3bebSKishon Vijay Abraham I ret = mmc_power_off(mmc); 2460fb7c3bebSKishon Vijay Abraham I if (ret) 2461fb7c3bebSKishon Vijay Abraham I return ret; 2462fb7c3bebSKishon Vijay Abraham I /* 2463fb7c3bebSKishon Vijay Abraham I * SD spec recommends at least 1ms of delay. Let's wait for 2ms 2464fb7c3bebSKishon Vijay Abraham I * to be on the safer side. 2465fb7c3bebSKishon Vijay Abraham I */ 2466fb7c3bebSKishon Vijay Abraham I udelay(2000); 2467fb7c3bebSKishon Vijay Abraham I return mmc_power_on(mmc); 2468fb7c3bebSKishon Vijay Abraham I } 2469fb7c3bebSKishon Vijay Abraham I 2470e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc) 2471272cc70bSAndy Fleming { 24728ca51e51SSimon Glass bool no_card; 2473c10b85d6SJean-Jacques Hiblot bool uhs_en = supports_uhs(mmc->cfg->host_caps); 2474afd5932bSMacpaul Lin int err; 2475272cc70bSAndy Fleming 24761da8eb59SJean-Jacques Hiblot /* 24771da8eb59SJean-Jacques Hiblot * all hosts are capable of 1 bit bus-width and able to use the legacy 24781da8eb59SJean-Jacques Hiblot * timings. 24791da8eb59SJean-Jacques Hiblot */ 24801da8eb59SJean-Jacques Hiblot mmc->host_caps = mmc->cfg->host_caps | MMC_CAP(SD_LEGACY) | 24811da8eb59SJean-Jacques Hiblot MMC_CAP(MMC_LEGACY) | MMC_MODE_1BIT; 248204a2ea24SJean-Jacques Hiblot 2483ab769f22SPantelis Antoniou /* we pretend there's no card when init is NULL */ 24848ca51e51SSimon Glass no_card = mmc_getcd(mmc) == 0; 2485e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 24868ca51e51SSimon Glass no_card = no_card || (mmc->cfg->ops->init == NULL); 24878ca51e51SSimon Glass #endif 24888ca51e51SSimon Glass if (no_card) { 248948972d90SThierry Reding mmc->has_init = 0; 249056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 249148972d90SThierry Reding printf("MMC: no card present\n"); 249256196826SPaul Burton #endif 2493915ffa52SJaehoon Chung return -ENOMEDIUM; 249448972d90SThierry Reding } 249548972d90SThierry Reding 2496bc897b1dSLei Wen if (mmc->has_init) 2497bc897b1dSLei Wen return 0; 2498bc897b1dSLei Wen 24995a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 25005a8dbdc6SYangbo Lu mmc_adapter_card_type_ident(); 25015a8dbdc6SYangbo Lu #endif 25022051aefeSPeng Fan err = mmc_power_init(mmc); 25032051aefeSPeng Fan if (err) 25042051aefeSPeng Fan return err; 250595de9ab2SPaul Kocialkowski 250683dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS 250783dc4227SKishon Vijay Abraham I mmc->quirks = MMC_QUIRK_RETRY_SET_BLOCKLEN | 250883dc4227SKishon Vijay Abraham I MMC_QUIRK_RETRY_SEND_CID; 250983dc4227SKishon Vijay Abraham I #endif 251083dc4227SKishon Vijay Abraham I 251104a2ea24SJean-Jacques Hiblot err = mmc_power_cycle(mmc); 251204a2ea24SJean-Jacques Hiblot if (err) { 251304a2ea24SJean-Jacques Hiblot /* 251404a2ea24SJean-Jacques Hiblot * if power cycling is not supported, we should not try 251504a2ea24SJean-Jacques Hiblot * to use the UHS modes, because we wouldn't be able to 251604a2ea24SJean-Jacques Hiblot * recover from an error during the UHS initialization. 251704a2ea24SJean-Jacques Hiblot */ 251804a2ea24SJean-Jacques Hiblot debug("Unable to do a full power cycle. Disabling the UHS modes for safety\n"); 251904a2ea24SJean-Jacques Hiblot uhs_en = false; 252004a2ea24SJean-Jacques Hiblot mmc->host_caps &= ~UHS_CAPS; 2521fb7c3bebSKishon Vijay Abraham I err = mmc_power_on(mmc); 252204a2ea24SJean-Jacques Hiblot } 2523fb7c3bebSKishon Vijay Abraham I if (err) 2524fb7c3bebSKishon Vijay Abraham I return err; 2525fb7c3bebSKishon Vijay Abraham I 2526e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 25278ca51e51SSimon Glass /* The device has already been probed ready for use */ 25288ca51e51SSimon Glass #else 2529ab769f22SPantelis Antoniou /* made sure it's not NULL earlier */ 253093bfd616SPantelis Antoniou err = mmc->cfg->ops->init(mmc); 2531272cc70bSAndy Fleming if (err) 2532272cc70bSAndy Fleming return err; 25338ca51e51SSimon Glass #endif 2534786e8f81SAndrew Gabbasov mmc->ddr_mode = 0; 2535aff5d3c8SKishon Vijay Abraham I 2536c10b85d6SJean-Jacques Hiblot retry: 2537fb7c3bebSKishon Vijay Abraham I mmc_set_initial_state(mmc); 2538318a7a57SJean-Jacques Hiblot mmc_send_init_stream(mmc); 2539318a7a57SJean-Jacques Hiblot 2540272cc70bSAndy Fleming /* Reset the Card */ 2541272cc70bSAndy Fleming err = mmc_go_idle(mmc); 2542272cc70bSAndy Fleming 2543272cc70bSAndy Fleming if (err) 2544272cc70bSAndy Fleming return err; 2545272cc70bSAndy Fleming 2546bc897b1dSLei Wen /* The internal partition reset to user partition(0) at every CMD0*/ 2547c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->hwpart = 0; 2548bc897b1dSLei Wen 2549272cc70bSAndy Fleming /* Test for SD version 2 */ 2550272cc70bSAndy Fleming err = mmc_send_if_cond(mmc); 2551272cc70bSAndy Fleming 2552272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */ 2553c10b85d6SJean-Jacques Hiblot err = sd_send_op_cond(mmc, uhs_en); 2554c10b85d6SJean-Jacques Hiblot if (err && uhs_en) { 2555c10b85d6SJean-Jacques Hiblot uhs_en = false; 2556c10b85d6SJean-Jacques Hiblot mmc_power_cycle(mmc); 2557c10b85d6SJean-Jacques Hiblot goto retry; 2558c10b85d6SJean-Jacques Hiblot } 2559272cc70bSAndy Fleming 2560272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */ 2561915ffa52SJaehoon Chung if (err == -ETIMEDOUT) { 2562272cc70bSAndy Fleming err = mmc_send_op_cond(mmc); 2563272cc70bSAndy Fleming 2564bd47c135SAndrew Gabbasov if (err) { 256556196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2566d8e3d420SJean-Jacques Hiblot pr_err("Card did not respond to voltage select!\n"); 256756196826SPaul Burton #endif 2568915ffa52SJaehoon Chung return -EOPNOTSUPP; 2569272cc70bSAndy Fleming } 2570272cc70bSAndy Fleming } 2571272cc70bSAndy Fleming 2572bd47c135SAndrew Gabbasov if (!err) 2573e9550449SChe-Liang Chiou mmc->init_in_progress = 1; 2574e9550449SChe-Liang Chiou 2575e9550449SChe-Liang Chiou return err; 2576e9550449SChe-Liang Chiou } 2577e9550449SChe-Liang Chiou 2578e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc) 2579e9550449SChe-Liang Chiou { 2580e9550449SChe-Liang Chiou int err = 0; 2581e9550449SChe-Liang Chiou 2582bd47c135SAndrew Gabbasov mmc->init_in_progress = 0; 2583e9550449SChe-Liang Chiou if (mmc->op_cond_pending) 2584e9550449SChe-Liang Chiou err = mmc_complete_op_cond(mmc); 2585e9550449SChe-Liang Chiou 2586e9550449SChe-Liang Chiou if (!err) 2587bc897b1dSLei Wen err = mmc_startup(mmc); 2588bc897b1dSLei Wen if (err) 2589bc897b1dSLei Wen mmc->has_init = 0; 2590bc897b1dSLei Wen else 2591bc897b1dSLei Wen mmc->has_init = 1; 2592e9550449SChe-Liang Chiou return err; 2593e9550449SChe-Liang Chiou } 2594e9550449SChe-Liang Chiou 2595e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc) 2596e9550449SChe-Liang Chiou { 2597bd47c135SAndrew Gabbasov int err = 0; 2598ce9eca94SMarek Vasut __maybe_unused unsigned start; 2599c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 260033fb211dSSimon Glass struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev); 2601e9550449SChe-Liang Chiou 260233fb211dSSimon Glass upriv->mmc = mmc; 260333fb211dSSimon Glass #endif 2604e9550449SChe-Liang Chiou if (mmc->has_init) 2605e9550449SChe-Liang Chiou return 0; 2606d803fea5SMateusz Zalega 2607d803fea5SMateusz Zalega start = get_timer(0); 2608d803fea5SMateusz Zalega 2609e9550449SChe-Liang Chiou if (!mmc->init_in_progress) 2610e9550449SChe-Liang Chiou err = mmc_start_init(mmc); 2611e9550449SChe-Liang Chiou 2612bd47c135SAndrew Gabbasov if (!err) 2613e9550449SChe-Liang Chiou err = mmc_complete_init(mmc); 2614919b4858SJagan Teki if (err) 2615919b4858SJagan Teki printf("%s: %d, time %lu\n", __func__, err, get_timer(start)); 2616919b4858SJagan Teki 2617bc897b1dSLei Wen return err; 2618272cc70bSAndy Fleming } 2619272cc70bSAndy Fleming 2620ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val) 2621ab71188cSMarkus Niebel { 2622ab71188cSMarkus Niebel mmc->dsr = val; 2623ab71188cSMarkus Niebel return 0; 2624ab71188cSMarkus Niebel } 2625ab71188cSMarkus Niebel 2626cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */ 2627cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis) 2628272cc70bSAndy Fleming { 2629272cc70bSAndy Fleming return -1; 2630272cc70bSAndy Fleming } 2631272cc70bSAndy Fleming 2632cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */ 2633cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis) 2634cee9ab7cSJeroen Hofstee { 2635cee9ab7cSJeroen Hofstee return -1; 2636cee9ab7cSJeroen Hofstee } 2637272cc70bSAndy Fleming 2638e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit) 2639e9550449SChe-Liang Chiou { 2640e9550449SChe-Liang Chiou mmc->preinit = preinit; 2641e9550449SChe-Liang Chiou } 2642e9550449SChe-Liang Chiou 2643c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD) 26448e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 26458e3332e2SSjoerd Simons { 26468e3332e2SSjoerd Simons return 0; 26478e3332e2SSjoerd Simons } 2648c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC) 26498e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 26508e3332e2SSjoerd Simons { 26514a1db6d8SSimon Glass int ret, i; 26528e3332e2SSjoerd Simons struct uclass *uc; 26534a1db6d8SSimon Glass struct udevice *dev; 26548e3332e2SSjoerd Simons 26558e3332e2SSjoerd Simons ret = uclass_get(UCLASS_MMC, &uc); 26568e3332e2SSjoerd Simons if (ret) 26578e3332e2SSjoerd Simons return ret; 26588e3332e2SSjoerd Simons 26594a1db6d8SSimon Glass /* 26604a1db6d8SSimon Glass * Try to add them in sequence order. Really with driver model we 26614a1db6d8SSimon Glass * should allow holes, but the current MMC list does not allow that. 26624a1db6d8SSimon Glass * So if we request 0, 1, 3 we will get 0, 1, 2. 26634a1db6d8SSimon Glass */ 26644a1db6d8SSimon Glass for (i = 0; ; i++) { 26654a1db6d8SSimon Glass ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev); 26664a1db6d8SSimon Glass if (ret == -ENODEV) 26674a1db6d8SSimon Glass break; 26684a1db6d8SSimon Glass } 26694a1db6d8SSimon Glass uclass_foreach_dev(dev, uc) { 26704a1db6d8SSimon Glass ret = device_probe(dev); 26718e3332e2SSjoerd Simons if (ret) 2672d8e3d420SJean-Jacques Hiblot pr_err("%s - probe failed: %d\n", dev->name, ret); 26738e3332e2SSjoerd Simons } 26748e3332e2SSjoerd Simons 26758e3332e2SSjoerd Simons return 0; 26768e3332e2SSjoerd Simons } 26778e3332e2SSjoerd Simons #else 26788e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 26798e3332e2SSjoerd Simons { 26808e3332e2SSjoerd Simons if (board_mmc_init(bis) < 0) 26818e3332e2SSjoerd Simons cpu_mmc_init(bis); 26828e3332e2SSjoerd Simons 26838e3332e2SSjoerd Simons return 0; 26848e3332e2SSjoerd Simons } 26858e3332e2SSjoerd Simons #endif 2686e9550449SChe-Liang Chiou 2687272cc70bSAndy Fleming int mmc_initialize(bd_t *bis) 2688272cc70bSAndy Fleming { 26891b26bab1SDaniel Kochmański static int initialized = 0; 26908e3332e2SSjoerd Simons int ret; 26911b26bab1SDaniel Kochmański if (initialized) /* Avoid initializing mmc multiple times */ 26921b26bab1SDaniel Kochmański return 0; 26931b26bab1SDaniel Kochmański initialized = 1; 26941b26bab1SDaniel Kochmański 2695c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK) 2696b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY) 2697c40fdca6SSimon Glass mmc_list_init(); 2698c40fdca6SSimon Glass #endif 2699b5b838f1SMarek Vasut #endif 27008e3332e2SSjoerd Simons ret = mmc_probe(bis); 27018e3332e2SSjoerd Simons if (ret) 27028e3332e2SSjoerd Simons return ret; 2703272cc70bSAndy Fleming 2704bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD 2705272cc70bSAndy Fleming print_mmc_devices(','); 2706bb0dc108SYing Zhang #endif 2707272cc70bSAndy Fleming 2708c40fdca6SSimon Glass mmc_do_preinit(); 2709272cc70bSAndy Fleming return 0; 2710272cc70bSAndy Fleming } 2711cd3d4880STomas Melin 2712cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE 2713cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc) 2714cd3d4880STomas Melin { 2715cd3d4880STomas Melin int err; 2716cd3d4880STomas Melin ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 2717cd3d4880STomas Melin 2718cd3d4880STomas Melin err = mmc_send_ext_csd(mmc, ext_csd); 2719cd3d4880STomas Melin if (err) { 2720cd3d4880STomas Melin puts("Could not get ext_csd register values\n"); 2721cd3d4880STomas Melin return err; 2722cd3d4880STomas Melin } 2723cd3d4880STomas Melin 2724cd3d4880STomas Melin if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) { 2725cd3d4880STomas Melin puts("Background operations not supported on device\n"); 2726cd3d4880STomas Melin return -EMEDIUMTYPE; 2727cd3d4880STomas Melin } 2728cd3d4880STomas Melin 2729cd3d4880STomas Melin if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) { 2730cd3d4880STomas Melin puts("Background operations already enabled\n"); 2731cd3d4880STomas Melin return 0; 2732cd3d4880STomas Melin } 2733cd3d4880STomas Melin 2734cd3d4880STomas Melin err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1); 2735cd3d4880STomas Melin if (err) { 2736cd3d4880STomas Melin puts("Failed to enable manual background operations\n"); 2737cd3d4880STomas Melin return err; 2738cd3d4880STomas Melin } 2739cd3d4880STomas Melin 2740cd3d4880STomas Melin puts("Enabled manual background operations\n"); 2741cd3d4880STomas Melin 2742cd3d4880STomas Melin return 0; 2743cd3d4880STomas Melin } 2744cd3d4880STomas Melin #endif 2745