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; 802634d4849SKishon Vijay Abraham I case MMC_HS_200: 803634d4849SKishon Vijay Abraham I speed_bits = EXT_CSD_TIMING_HS200; 804634d4849SKishon Vijay Abraham I break; 8053862b854SJean-Jacques Hiblot case MMC_LEGACY: 8063862b854SJean-Jacques Hiblot speed_bits = EXT_CSD_TIMING_LEGACY; 8073862b854SJean-Jacques Hiblot break; 8083862b854SJean-Jacques Hiblot default: 8093862b854SJean-Jacques Hiblot return -EINVAL; 8103862b854SJean-Jacques Hiblot } 8113862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 8123862b854SJean-Jacques Hiblot speed_bits); 8133862b854SJean-Jacques Hiblot if (err) 8143862b854SJean-Jacques Hiblot return err; 8153862b854SJean-Jacques Hiblot 8163862b854SJean-Jacques Hiblot if ((mode == MMC_HS) || (mode == MMC_HS_52)) { 8173862b854SJean-Jacques Hiblot /* Now check to see that it worked */ 8183862b854SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, test_csd); 8193862b854SJean-Jacques Hiblot if (err) 8203862b854SJean-Jacques Hiblot return err; 8213862b854SJean-Jacques Hiblot 8223862b854SJean-Jacques Hiblot /* No high-speed support */ 8233862b854SJean-Jacques Hiblot if (!test_csd[EXT_CSD_HS_TIMING]) 8243862b854SJean-Jacques Hiblot return -ENOTSUPP; 8253862b854SJean-Jacques Hiblot } 8263862b854SJean-Jacques Hiblot 8273862b854SJean-Jacques Hiblot return 0; 8283862b854SJean-Jacques Hiblot } 8293862b854SJean-Jacques Hiblot 8303862b854SJean-Jacques Hiblot static int mmc_get_capabilities(struct mmc *mmc) 8313862b854SJean-Jacques Hiblot { 8323862b854SJean-Jacques Hiblot u8 *ext_csd = mmc->ext_csd; 8333862b854SJean-Jacques Hiblot char cardtype; 834272cc70bSAndy Fleming 83500e446faSJean-Jacques Hiblot mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(MMC_LEGACY); 836272cc70bSAndy Fleming 837d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 838d52ebf10SThomas Chou return 0; 839d52ebf10SThomas Chou 840272cc70bSAndy Fleming /* Only version 4 supports high-speed */ 841272cc70bSAndy Fleming if (mmc->version < MMC_VERSION_4) 842272cc70bSAndy Fleming return 0; 843272cc70bSAndy Fleming 8443862b854SJean-Jacques Hiblot if (!ext_csd) { 845d8e3d420SJean-Jacques Hiblot pr_err("No ext_csd found!\n"); /* this should enver happen */ 8463862b854SJean-Jacques Hiblot return -ENOTSUPP; 8473862b854SJean-Jacques Hiblot } 8483862b854SJean-Jacques Hiblot 849fc5b32fbSAndrew Gabbasov mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; 850fc5b32fbSAndrew Gabbasov 851634d4849SKishon Vijay Abraham I cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0x3f; 852bc1e3272SJean-Jacques Hiblot mmc->cardtype = cardtype; 853272cc70bSAndy Fleming 854634d4849SKishon Vijay Abraham I if (cardtype & (EXT_CSD_CARD_TYPE_HS200_1_2V | 855634d4849SKishon Vijay Abraham I EXT_CSD_CARD_TYPE_HS200_1_8V)) { 856634d4849SKishon Vijay Abraham I mmc->card_caps |= MMC_MODE_HS200; 857634d4849SKishon Vijay Abraham I } 858d22e3d46SJaehoon Chung if (cardtype & EXT_CSD_CARD_TYPE_52) { 8593862b854SJean-Jacques Hiblot if (cardtype & EXT_CSD_CARD_TYPE_DDR_52) 860d22e3d46SJaehoon Chung mmc->card_caps |= MMC_MODE_DDR_52MHz; 8613862b854SJean-Jacques Hiblot mmc->card_caps |= MMC_MODE_HS_52MHz; 862d22e3d46SJaehoon Chung } 8633862b854SJean-Jacques Hiblot if (cardtype & EXT_CSD_CARD_TYPE_26) 8643862b854SJean-Jacques Hiblot mmc->card_caps |= MMC_MODE_HS; 865272cc70bSAndy Fleming 866272cc70bSAndy Fleming return 0; 867272cc70bSAndy Fleming } 868272cc70bSAndy Fleming 869f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num) 870f866a46dSStephen Warren { 871f866a46dSStephen Warren switch (part_num) { 872f866a46dSStephen Warren case 0: 873f866a46dSStephen Warren mmc->capacity = mmc->capacity_user; 874f866a46dSStephen Warren break; 875f866a46dSStephen Warren case 1: 876f866a46dSStephen Warren case 2: 877f866a46dSStephen Warren mmc->capacity = mmc->capacity_boot; 878f866a46dSStephen Warren break; 879f866a46dSStephen Warren case 3: 880f866a46dSStephen Warren mmc->capacity = mmc->capacity_rpmb; 881f866a46dSStephen Warren break; 882f866a46dSStephen Warren case 4: 883f866a46dSStephen Warren case 5: 884f866a46dSStephen Warren case 6: 885f866a46dSStephen Warren case 7: 886f866a46dSStephen Warren mmc->capacity = mmc->capacity_gp[part_num - 4]; 887f866a46dSStephen Warren break; 888f866a46dSStephen Warren default: 889f866a46dSStephen Warren return -1; 890f866a46dSStephen Warren } 891f866a46dSStephen Warren 892c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len); 893f866a46dSStephen Warren 894f866a46dSStephen Warren return 0; 895f866a46dSStephen Warren } 896f866a46dSStephen Warren 897f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) 89801298da3SJean-Jacques Hiblot static int mmc_boot_part_access_chk(struct mmc *mmc, unsigned int part_num) 89901298da3SJean-Jacques Hiblot { 90001298da3SJean-Jacques Hiblot int forbidden = 0; 90101298da3SJean-Jacques Hiblot bool change = false; 90201298da3SJean-Jacques Hiblot 90301298da3SJean-Jacques Hiblot if (part_num & PART_ACCESS_MASK) 90401298da3SJean-Jacques Hiblot forbidden = MMC_CAP(MMC_HS_200); 90501298da3SJean-Jacques Hiblot 90601298da3SJean-Jacques Hiblot if (MMC_CAP(mmc->selected_mode) & forbidden) { 90701298da3SJean-Jacques Hiblot debug("selected mode (%s) is forbidden for part %d\n", 90801298da3SJean-Jacques Hiblot mmc_mode_name(mmc->selected_mode), part_num); 90901298da3SJean-Jacques Hiblot change = true; 91001298da3SJean-Jacques Hiblot } else if (mmc->selected_mode != mmc->best_mode) { 91101298da3SJean-Jacques Hiblot debug("selected mode is not optimal\n"); 91201298da3SJean-Jacques Hiblot change = true; 91301298da3SJean-Jacques Hiblot } 91401298da3SJean-Jacques Hiblot 91501298da3SJean-Jacques Hiblot if (change) 91601298da3SJean-Jacques Hiblot return mmc_select_mode_and_width(mmc, 91701298da3SJean-Jacques Hiblot mmc->card_caps & ~forbidden); 91801298da3SJean-Jacques Hiblot 91901298da3SJean-Jacques Hiblot return 0; 92001298da3SJean-Jacques Hiblot } 921f99c2efeSJean-Jacques Hiblot #else 922f99c2efeSJean-Jacques Hiblot static inline int mmc_boot_part_access_chk(struct mmc *mmc, 923f99c2efeSJean-Jacques Hiblot unsigned int part_num) 924f99c2efeSJean-Jacques Hiblot { 925f99c2efeSJean-Jacques Hiblot return 0; 926f99c2efeSJean-Jacques Hiblot } 927f99c2efeSJean-Jacques Hiblot #endif 92801298da3SJean-Jacques Hiblot 9297dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num) 930bc897b1dSLei Wen { 931f866a46dSStephen Warren int ret; 932bc897b1dSLei Wen 93301298da3SJean-Jacques Hiblot ret = mmc_boot_part_access_chk(mmc, part_num); 93401298da3SJean-Jacques Hiblot if (ret) 93501298da3SJean-Jacques Hiblot return ret; 93601298da3SJean-Jacques Hiblot 937f866a46dSStephen Warren ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 938bc897b1dSLei Wen (mmc->part_config & ~PART_ACCESS_MASK) 939bc897b1dSLei Wen | (part_num & PART_ACCESS_MASK)); 940f866a46dSStephen Warren 9416dc93e70SPeter Bigot /* 9426dc93e70SPeter Bigot * Set the capacity if the switch succeeded or was intended 9436dc93e70SPeter Bigot * to return to representing the raw device. 9446dc93e70SPeter Bigot */ 945873cc1d7SStephen Warren if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) { 9466dc93e70SPeter Bigot ret = mmc_set_capacity(mmc, part_num); 947fdbb139fSSimon Glass mmc_get_blk_desc(mmc)->hwpart = part_num; 948873cc1d7SStephen Warren } 9496dc93e70SPeter Bigot 9506dc93e70SPeter Bigot return ret; 951bc897b1dSLei Wen } 952bc897b1dSLei Wen 953*cf17789eSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING) 954ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc, 955ac9da0e0SDiego Santa Cruz const struct mmc_hwpart_conf *conf, 956ac9da0e0SDiego Santa Cruz enum mmc_hwpart_conf_mode mode) 957ac9da0e0SDiego Santa Cruz { 958ac9da0e0SDiego Santa Cruz u8 part_attrs = 0; 959ac9da0e0SDiego Santa Cruz u32 enh_size_mult; 960ac9da0e0SDiego Santa Cruz u32 enh_start_addr; 961ac9da0e0SDiego Santa Cruz u32 gp_size_mult[4]; 962ac9da0e0SDiego Santa Cruz u32 max_enh_size_mult; 963ac9da0e0SDiego Santa Cruz u32 tot_enh_size_mult = 0; 9648dda5b0eSDiego Santa Cruz u8 wr_rel_set; 965ac9da0e0SDiego Santa Cruz int i, pidx, err; 966ac9da0e0SDiego Santa Cruz ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 967ac9da0e0SDiego Santa Cruz 968ac9da0e0SDiego Santa Cruz if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE) 969ac9da0e0SDiego Santa Cruz return -EINVAL; 970ac9da0e0SDiego Santa Cruz 971ac9da0e0SDiego Santa Cruz if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) { 972d8e3d420SJean-Jacques Hiblot pr_err("eMMC >= 4.4 required for enhanced user data area\n"); 973ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 974ac9da0e0SDiego Santa Cruz } 975ac9da0e0SDiego Santa Cruz 976ac9da0e0SDiego Santa Cruz if (!(mmc->part_support & PART_SUPPORT)) { 977d8e3d420SJean-Jacques Hiblot pr_err("Card does not support partitioning\n"); 978ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 979ac9da0e0SDiego Santa Cruz } 980ac9da0e0SDiego Santa Cruz 981ac9da0e0SDiego Santa Cruz if (!mmc->hc_wp_grp_size) { 982d8e3d420SJean-Jacques Hiblot pr_err("Card does not define HC WP group size\n"); 983ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 984ac9da0e0SDiego Santa Cruz } 985ac9da0e0SDiego Santa Cruz 986ac9da0e0SDiego Santa Cruz /* check partition alignment and total enhanced size */ 987ac9da0e0SDiego Santa Cruz if (conf->user.enh_size) { 988ac9da0e0SDiego Santa Cruz if (conf->user.enh_size % mmc->hc_wp_grp_size || 989ac9da0e0SDiego Santa Cruz conf->user.enh_start % mmc->hc_wp_grp_size) { 990d8e3d420SJean-Jacques Hiblot pr_err("User data enhanced area not HC WP group " 991ac9da0e0SDiego Santa Cruz "size aligned\n"); 992ac9da0e0SDiego Santa Cruz return -EINVAL; 993ac9da0e0SDiego Santa Cruz } 994ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_USR; 995ac9da0e0SDiego Santa Cruz enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size; 996ac9da0e0SDiego Santa Cruz if (mmc->high_capacity) { 997ac9da0e0SDiego Santa Cruz enh_start_addr = conf->user.enh_start; 998ac9da0e0SDiego Santa Cruz } else { 999ac9da0e0SDiego Santa Cruz enh_start_addr = (conf->user.enh_start << 9); 1000ac9da0e0SDiego Santa Cruz } 1001ac9da0e0SDiego Santa Cruz } else { 1002ac9da0e0SDiego Santa Cruz enh_size_mult = 0; 1003ac9da0e0SDiego Santa Cruz enh_start_addr = 0; 1004ac9da0e0SDiego Santa Cruz } 1005ac9da0e0SDiego Santa Cruz tot_enh_size_mult += enh_size_mult; 1006ac9da0e0SDiego Santa Cruz 1007ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 1008ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) { 1009d8e3d420SJean-Jacques Hiblot pr_err("GP%i partition not HC WP group size " 1010ac9da0e0SDiego Santa Cruz "aligned\n", pidx+1); 1011ac9da0e0SDiego Santa Cruz return -EINVAL; 1012ac9da0e0SDiego Santa Cruz } 1013ac9da0e0SDiego Santa Cruz gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size; 1014ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) { 1015ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_GP(pidx); 1016ac9da0e0SDiego Santa Cruz tot_enh_size_mult += gp_size_mult[pidx]; 1017ac9da0e0SDiego Santa Cruz } 1018ac9da0e0SDiego Santa Cruz } 1019ac9da0e0SDiego Santa Cruz 1020ac9da0e0SDiego Santa Cruz if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) { 1021d8e3d420SJean-Jacques Hiblot pr_err("Card does not support enhanced attribute\n"); 1022ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1023ac9da0e0SDiego Santa Cruz } 1024ac9da0e0SDiego Santa Cruz 1025ac9da0e0SDiego Santa Cruz err = mmc_send_ext_csd(mmc, ext_csd); 1026ac9da0e0SDiego Santa Cruz if (err) 1027ac9da0e0SDiego Santa Cruz return err; 1028ac9da0e0SDiego Santa Cruz 1029ac9da0e0SDiego Santa Cruz max_enh_size_mult = 1030ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) + 1031ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) + 1032ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]; 1033ac9da0e0SDiego Santa Cruz if (tot_enh_size_mult > max_enh_size_mult) { 1034d8e3d420SJean-Jacques Hiblot pr_err("Total enhanced size exceeds maximum (%u > %u)\n", 1035ac9da0e0SDiego Santa Cruz tot_enh_size_mult, max_enh_size_mult); 1036ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1037ac9da0e0SDiego Santa Cruz } 1038ac9da0e0SDiego Santa Cruz 10398dda5b0eSDiego Santa Cruz /* The default value of EXT_CSD_WR_REL_SET is device 10408dda5b0eSDiego Santa Cruz * dependent, the values can only be changed if the 10418dda5b0eSDiego Santa Cruz * EXT_CSD_HS_CTRL_REL bit is set. The values can be 10428dda5b0eSDiego Santa Cruz * changed only once and before partitioning is completed. */ 10438dda5b0eSDiego Santa Cruz wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 10448dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_change) { 10458dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_set) 10468dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_USR; 10478dda5b0eSDiego Santa Cruz else 10488dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR; 10498dda5b0eSDiego Santa Cruz } 10508dda5b0eSDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 10518dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_change) { 10528dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_set) 10538dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx); 10548dda5b0eSDiego Santa Cruz else 10558dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx); 10568dda5b0eSDiego Santa Cruz } 10578dda5b0eSDiego Santa Cruz } 10588dda5b0eSDiego Santa Cruz 10598dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] && 10608dda5b0eSDiego Santa Cruz !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) { 10618dda5b0eSDiego Santa Cruz puts("Card does not support host controlled partition write " 10628dda5b0eSDiego Santa Cruz "reliability settings\n"); 10638dda5b0eSDiego Santa Cruz return -EMEDIUMTYPE; 10648dda5b0eSDiego Santa Cruz } 10658dda5b0eSDiego Santa Cruz 1066ac9da0e0SDiego Santa Cruz if (ext_csd[EXT_CSD_PARTITION_SETTING] & 1067ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED) { 1068d8e3d420SJean-Jacques Hiblot pr_err("Card already partitioned\n"); 1069ac9da0e0SDiego Santa Cruz return -EPERM; 1070ac9da0e0SDiego Santa Cruz } 1071ac9da0e0SDiego Santa Cruz 1072ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_CHECK) 1073ac9da0e0SDiego Santa Cruz return 0; 1074ac9da0e0SDiego Santa Cruz 1075ac9da0e0SDiego Santa Cruz /* Partitioning requires high-capacity size definitions */ 1076ac9da0e0SDiego Santa Cruz if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) { 1077ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1078ac9da0e0SDiego Santa Cruz EXT_CSD_ERASE_GROUP_DEF, 1); 1079ac9da0e0SDiego Santa Cruz 1080ac9da0e0SDiego Santa Cruz if (err) 1081ac9da0e0SDiego Santa Cruz return err; 1082ac9da0e0SDiego Santa Cruz 1083ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 1084ac9da0e0SDiego Santa Cruz 1085ac9da0e0SDiego Santa Cruz /* update erase group size to be high-capacity */ 1086ac9da0e0SDiego Santa Cruz mmc->erase_grp_size = 1087ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 1088ac9da0e0SDiego Santa Cruz 1089ac9da0e0SDiego Santa Cruz } 1090ac9da0e0SDiego Santa Cruz 1091ac9da0e0SDiego Santa Cruz /* all OK, write the configuration */ 1092ac9da0e0SDiego Santa Cruz for (i = 0; i < 4; i++) { 1093ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1094ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_START_ADDR+i, 1095ac9da0e0SDiego Santa Cruz (enh_start_addr >> (i*8)) & 0xFF); 1096ac9da0e0SDiego Santa Cruz if (err) 1097ac9da0e0SDiego Santa Cruz return err; 1098ac9da0e0SDiego Santa Cruz } 1099ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 1100ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1101ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_SIZE_MULT+i, 1102ac9da0e0SDiego Santa Cruz (enh_size_mult >> (i*8)) & 0xFF); 1103ac9da0e0SDiego Santa Cruz if (err) 1104ac9da0e0SDiego Santa Cruz return err; 1105ac9da0e0SDiego Santa Cruz } 1106ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 1107ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 1108ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1109ac9da0e0SDiego Santa Cruz EXT_CSD_GP_SIZE_MULT+pidx*3+i, 1110ac9da0e0SDiego Santa Cruz (gp_size_mult[pidx] >> (i*8)) & 0xFF); 1111ac9da0e0SDiego Santa Cruz if (err) 1112ac9da0e0SDiego Santa Cruz return err; 1113ac9da0e0SDiego Santa Cruz } 1114ac9da0e0SDiego Santa Cruz } 1115ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1116ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs); 1117ac9da0e0SDiego Santa Cruz if (err) 1118ac9da0e0SDiego Santa Cruz return err; 1119ac9da0e0SDiego Santa Cruz 1120ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_SET) 1121ac9da0e0SDiego Santa Cruz return 0; 1122ac9da0e0SDiego Santa Cruz 11238dda5b0eSDiego Santa Cruz /* The WR_REL_SET is a write-once register but shall be 11248dda5b0eSDiego Santa Cruz * written before setting PART_SETTING_COMPLETED. As it is 11258dda5b0eSDiego Santa Cruz * write-once we can only write it when completing the 11268dda5b0eSDiego Santa Cruz * partitioning. */ 11278dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) { 11288dda5b0eSDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 11298dda5b0eSDiego Santa Cruz EXT_CSD_WR_REL_SET, wr_rel_set); 11308dda5b0eSDiego Santa Cruz if (err) 11318dda5b0eSDiego Santa Cruz return err; 11328dda5b0eSDiego Santa Cruz } 11338dda5b0eSDiego Santa Cruz 1134ac9da0e0SDiego Santa Cruz /* Setting PART_SETTING_COMPLETED confirms the partition 1135ac9da0e0SDiego Santa Cruz * configuration but it only becomes effective after power 1136ac9da0e0SDiego Santa Cruz * cycle, so we do not adjust the partition related settings 1137ac9da0e0SDiego Santa Cruz * in the mmc struct. */ 1138ac9da0e0SDiego Santa Cruz 1139ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1140ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING, 1141ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 1142ac9da0e0SDiego Santa Cruz if (err) 1143ac9da0e0SDiego Santa Cruz return err; 1144ac9da0e0SDiego Santa Cruz 1145ac9da0e0SDiego Santa Cruz return 0; 1146ac9da0e0SDiego Santa Cruz } 1147*cf17789eSJean-Jacques Hiblot #endif 1148ac9da0e0SDiego Santa Cruz 1149e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 115048972d90SThierry Reding int mmc_getcd(struct mmc *mmc) 115148972d90SThierry Reding { 115248972d90SThierry Reding int cd; 115348972d90SThierry Reding 115448972d90SThierry Reding cd = board_mmc_getcd(mmc); 115548972d90SThierry Reding 1156d4e1da4eSPeter Korsgaard if (cd < 0) { 115793bfd616SPantelis Antoniou if (mmc->cfg->ops->getcd) 115893bfd616SPantelis Antoniou cd = mmc->cfg->ops->getcd(mmc); 1159d4e1da4eSPeter Korsgaard else 1160d4e1da4eSPeter Korsgaard cd = 1; 1161d4e1da4eSPeter Korsgaard } 116248972d90SThierry Reding 116348972d90SThierry Reding return cd; 116448972d90SThierry Reding } 11658ca51e51SSimon Glass #endif 116648972d90SThierry Reding 1167fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) 1168272cc70bSAndy Fleming { 1169272cc70bSAndy Fleming struct mmc_cmd cmd; 1170272cc70bSAndy Fleming struct mmc_data data; 1171272cc70bSAndy Fleming 1172272cc70bSAndy Fleming /* Switch the frequency */ 1173272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC; 1174272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1175272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff; 1176272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4)); 1177272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4); 1178272cc70bSAndy Fleming 1179272cc70bSAndy Fleming data.dest = (char *)resp; 1180272cc70bSAndy Fleming data.blocksize = 64; 1181272cc70bSAndy Fleming data.blocks = 1; 1182272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1183272cc70bSAndy Fleming 1184272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 1185272cc70bSAndy Fleming } 1186272cc70bSAndy Fleming 1187272cc70bSAndy Fleming 1188d0c221feSJean-Jacques Hiblot static int sd_get_capabilities(struct mmc *mmc) 1189272cc70bSAndy Fleming { 1190272cc70bSAndy Fleming int err; 1191272cc70bSAndy Fleming struct mmc_cmd cmd; 119218e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2); 119318e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16); 1194272cc70bSAndy Fleming struct mmc_data data; 1195272cc70bSAndy Fleming int timeout; 1196f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1197c10b85d6SJean-Jacques Hiblot u32 sd3_bus_mode; 1198f99c2efeSJean-Jacques Hiblot #endif 1199272cc70bSAndy Fleming 120000e446faSJean-Jacques Hiblot mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(SD_LEGACY); 1201272cc70bSAndy Fleming 1202d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 1203d52ebf10SThomas Chou return 0; 1204d52ebf10SThomas Chou 1205272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */ 1206272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 1207272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1208272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1209272cc70bSAndy Fleming 1210272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1211272cc70bSAndy Fleming 1212272cc70bSAndy Fleming if (err) 1213272cc70bSAndy Fleming return err; 1214272cc70bSAndy Fleming 1215272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR; 1216272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1217272cc70bSAndy Fleming cmd.cmdarg = 0; 1218272cc70bSAndy Fleming 1219272cc70bSAndy Fleming timeout = 3; 1220272cc70bSAndy Fleming 1221272cc70bSAndy Fleming retry_scr: 1222f781dd38SAnton staaf data.dest = (char *)scr; 1223272cc70bSAndy Fleming data.blocksize = 8; 1224272cc70bSAndy Fleming data.blocks = 1; 1225272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1226272cc70bSAndy Fleming 1227272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 1228272cc70bSAndy Fleming 1229272cc70bSAndy Fleming if (err) { 1230272cc70bSAndy Fleming if (timeout--) 1231272cc70bSAndy Fleming goto retry_scr; 1232272cc70bSAndy Fleming 1233272cc70bSAndy Fleming return err; 1234272cc70bSAndy Fleming } 1235272cc70bSAndy Fleming 12364e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]); 12374e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]); 1238272cc70bSAndy Fleming 1239272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) { 1240272cc70bSAndy Fleming case 0: 1241272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1242272cc70bSAndy Fleming break; 1243272cc70bSAndy Fleming case 1: 1244272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10; 1245272cc70bSAndy Fleming break; 1246272cc70bSAndy Fleming case 2: 1247272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 12481741c64dSJaehoon Chung if ((mmc->scr[0] >> 15) & 0x1) 12491741c64dSJaehoon Chung mmc->version = SD_VERSION_3; 1250272cc70bSAndy Fleming break; 1251272cc70bSAndy Fleming default: 1252272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1253272cc70bSAndy Fleming break; 1254272cc70bSAndy Fleming } 1255272cc70bSAndy Fleming 1256b44c7083SAlagu Sankar if (mmc->scr[0] & SD_DATA_4BIT) 1257b44c7083SAlagu Sankar mmc->card_caps |= MMC_MODE_4BIT; 1258b44c7083SAlagu Sankar 1259272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */ 1260272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0) 1261272cc70bSAndy Fleming return 0; 1262272cc70bSAndy Fleming 1263272cc70bSAndy Fleming timeout = 4; 1264272cc70bSAndy Fleming while (timeout--) { 1265272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, 1266f781dd38SAnton staaf (u8 *)switch_status); 1267272cc70bSAndy Fleming 1268272cc70bSAndy Fleming if (err) 1269272cc70bSAndy Fleming return err; 1270272cc70bSAndy Fleming 1271272cc70bSAndy Fleming /* The high-speed function is busy. Try again */ 12724e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) 1273272cc70bSAndy Fleming break; 1274272cc70bSAndy Fleming } 1275272cc70bSAndy Fleming 1276272cc70bSAndy Fleming /* If high-speed isn't supported, we return */ 1277d0c221feSJean-Jacques Hiblot if (__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED) 1278d0c221feSJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(SD_HS); 1279272cc70bSAndy Fleming 1280f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1281c10b85d6SJean-Jacques Hiblot /* Version before 3.0 don't support UHS modes */ 1282c10b85d6SJean-Jacques Hiblot if (mmc->version < SD_VERSION_3) 1283c10b85d6SJean-Jacques Hiblot return 0; 1284c10b85d6SJean-Jacques Hiblot 1285c10b85d6SJean-Jacques Hiblot sd3_bus_mode = __be32_to_cpu(switch_status[3]) >> 16 & 0x1f; 1286c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR104) 1287c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR104); 1288c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR50) 1289c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR50); 1290c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR25) 1291c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR25); 1292c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR12) 1293c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR12); 1294c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_DDR50) 1295c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_DDR50); 1296f99c2efeSJean-Jacques Hiblot #endif 1297c10b85d6SJean-Jacques Hiblot 12982c3fbf4cSMacpaul Lin return 0; 1299d0c221feSJean-Jacques Hiblot } 1300d0c221feSJean-Jacques Hiblot 1301d0c221feSJean-Jacques Hiblot static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode) 1302d0c221feSJean-Jacques Hiblot { 1303d0c221feSJean-Jacques Hiblot int err; 1304d0c221feSJean-Jacques Hiblot 1305d0c221feSJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16); 1306c10b85d6SJean-Jacques Hiblot int speed; 13072c3fbf4cSMacpaul Lin 1308c10b85d6SJean-Jacques Hiblot switch (mode) { 1309c10b85d6SJean-Jacques Hiblot case SD_LEGACY: 1310c10b85d6SJean-Jacques Hiblot case UHS_SDR12: 1311c10b85d6SJean-Jacques Hiblot speed = UHS_SDR12_BUS_SPEED; 1312c10b85d6SJean-Jacques Hiblot break; 1313c10b85d6SJean-Jacques Hiblot case SD_HS: 1314c10b85d6SJean-Jacques Hiblot case UHS_SDR25: 1315c10b85d6SJean-Jacques Hiblot speed = UHS_SDR25_BUS_SPEED; 1316c10b85d6SJean-Jacques Hiblot break; 1317c10b85d6SJean-Jacques Hiblot case UHS_SDR50: 1318c10b85d6SJean-Jacques Hiblot speed = UHS_SDR50_BUS_SPEED; 1319c10b85d6SJean-Jacques Hiblot break; 1320c10b85d6SJean-Jacques Hiblot case UHS_DDR50: 1321c10b85d6SJean-Jacques Hiblot speed = UHS_DDR50_BUS_SPEED; 1322c10b85d6SJean-Jacques Hiblot break; 1323c10b85d6SJean-Jacques Hiblot case UHS_SDR104: 1324c10b85d6SJean-Jacques Hiblot speed = UHS_SDR104_BUS_SPEED; 1325c10b85d6SJean-Jacques Hiblot break; 1326c10b85d6SJean-Jacques Hiblot default: 1327c10b85d6SJean-Jacques Hiblot return -EINVAL; 1328c10b85d6SJean-Jacques Hiblot } 1329c10b85d6SJean-Jacques Hiblot 1330c10b85d6SJean-Jacques Hiblot err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, speed, (u8 *)switch_status); 1331272cc70bSAndy Fleming if (err) 1332272cc70bSAndy Fleming return err; 1333272cc70bSAndy Fleming 1334c10b85d6SJean-Jacques Hiblot if ((__be32_to_cpu(switch_status[4]) >> 24) != speed) 1335d0c221feSJean-Jacques Hiblot return -ENOTSUPP; 1336d0c221feSJean-Jacques Hiblot 1337d0c221feSJean-Jacques Hiblot return 0; 1338d0c221feSJean-Jacques Hiblot } 1339d0c221feSJean-Jacques Hiblot 1340d0c221feSJean-Jacques Hiblot int sd_select_bus_width(struct mmc *mmc, int w) 1341d0c221feSJean-Jacques Hiblot { 1342d0c221feSJean-Jacques Hiblot int err; 1343d0c221feSJean-Jacques Hiblot struct mmc_cmd cmd; 1344d0c221feSJean-Jacques Hiblot 1345d0c221feSJean-Jacques Hiblot if ((w != 4) && (w != 1)) 1346d0c221feSJean-Jacques Hiblot return -EINVAL; 1347d0c221feSJean-Jacques Hiblot 1348d0c221feSJean-Jacques Hiblot cmd.cmdidx = MMC_CMD_APP_CMD; 1349d0c221feSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 1350d0c221feSJean-Jacques Hiblot cmd.cmdarg = mmc->rca << 16; 1351d0c221feSJean-Jacques Hiblot 1352d0c221feSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 1353d0c221feSJean-Jacques Hiblot if (err) 1354d0c221feSJean-Jacques Hiblot return err; 1355d0c221feSJean-Jacques Hiblot 1356d0c221feSJean-Jacques Hiblot cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; 1357d0c221feSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 1358d0c221feSJean-Jacques Hiblot if (w == 4) 1359d0c221feSJean-Jacques Hiblot cmd.cmdarg = 2; 1360d0c221feSJean-Jacques Hiblot else if (w == 1) 1361d0c221feSJean-Jacques Hiblot cmd.cmdarg = 0; 1362d0c221feSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 1363d0c221feSJean-Jacques Hiblot if (err) 1364d0c221feSJean-Jacques Hiblot return err; 1365272cc70bSAndy Fleming 1366272cc70bSAndy Fleming return 0; 1367272cc70bSAndy Fleming } 1368272cc70bSAndy Fleming 13693697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc) 13703697e599SPeng Fan { 13713697e599SPeng Fan int err, i; 13723697e599SPeng Fan struct mmc_cmd cmd; 13733697e599SPeng Fan ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16); 13743697e599SPeng Fan struct mmc_data data; 13753697e599SPeng Fan int timeout = 3; 13763697e599SPeng Fan unsigned int au, eo, et, es; 13773697e599SPeng Fan 13783697e599SPeng Fan cmd.cmdidx = MMC_CMD_APP_CMD; 13793697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 13803697e599SPeng Fan cmd.cmdarg = mmc->rca << 16; 13813697e599SPeng Fan 13823697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, NULL); 13833697e599SPeng Fan if (err) 13843697e599SPeng Fan return err; 13853697e599SPeng Fan 13863697e599SPeng Fan cmd.cmdidx = SD_CMD_APP_SD_STATUS; 13873697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 13883697e599SPeng Fan cmd.cmdarg = 0; 13893697e599SPeng Fan 13903697e599SPeng Fan retry_ssr: 13913697e599SPeng Fan data.dest = (char *)ssr; 13923697e599SPeng Fan data.blocksize = 64; 13933697e599SPeng Fan data.blocks = 1; 13943697e599SPeng Fan data.flags = MMC_DATA_READ; 13953697e599SPeng Fan 13963697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, &data); 13973697e599SPeng Fan if (err) { 13983697e599SPeng Fan if (timeout--) 13993697e599SPeng Fan goto retry_ssr; 14003697e599SPeng Fan 14013697e599SPeng Fan return err; 14023697e599SPeng Fan } 14033697e599SPeng Fan 14043697e599SPeng Fan for (i = 0; i < 16; i++) 14053697e599SPeng Fan ssr[i] = be32_to_cpu(ssr[i]); 14063697e599SPeng Fan 14073697e599SPeng Fan au = (ssr[2] >> 12) & 0xF; 14083697e599SPeng Fan if ((au <= 9) || (mmc->version == SD_VERSION_3)) { 14093697e599SPeng Fan mmc->ssr.au = sd_au_size[au]; 14103697e599SPeng Fan es = (ssr[3] >> 24) & 0xFF; 14113697e599SPeng Fan es |= (ssr[2] & 0xFF) << 8; 14123697e599SPeng Fan et = (ssr[3] >> 18) & 0x3F; 14133697e599SPeng Fan if (es && et) { 14143697e599SPeng Fan eo = (ssr[3] >> 16) & 0x3; 14153697e599SPeng Fan mmc->ssr.erase_timeout = (et * 1000) / es; 14163697e599SPeng Fan mmc->ssr.erase_offset = eo * 1000; 14173697e599SPeng Fan } 14183697e599SPeng Fan } else { 14193697e599SPeng Fan debug("Invalid Allocation Unit Size.\n"); 14203697e599SPeng Fan } 14213697e599SPeng Fan 14223697e599SPeng Fan return 0; 14233697e599SPeng Fan } 14243697e599SPeng Fan 1425272cc70bSAndy Fleming /* frequency bases */ 1426272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */ 14275f837c2cSMike Frysinger static const int fbase[] = { 1428272cc70bSAndy Fleming 10000, 1429272cc70bSAndy Fleming 100000, 1430272cc70bSAndy Fleming 1000000, 1431272cc70bSAndy Fleming 10000000, 1432272cc70bSAndy Fleming }; 1433272cc70bSAndy Fleming 1434272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice 1435272cc70bSAndy Fleming * to platforms without floating point. 1436272cc70bSAndy Fleming */ 143761fe076fSSimon Glass static const u8 multipliers[] = { 1438272cc70bSAndy Fleming 0, /* reserved */ 1439272cc70bSAndy Fleming 10, 1440272cc70bSAndy Fleming 12, 1441272cc70bSAndy Fleming 13, 1442272cc70bSAndy Fleming 15, 1443272cc70bSAndy Fleming 20, 1444272cc70bSAndy Fleming 25, 1445272cc70bSAndy Fleming 30, 1446272cc70bSAndy Fleming 35, 1447272cc70bSAndy Fleming 40, 1448272cc70bSAndy Fleming 45, 1449272cc70bSAndy Fleming 50, 1450272cc70bSAndy Fleming 55, 1451272cc70bSAndy Fleming 60, 1452272cc70bSAndy Fleming 70, 1453272cc70bSAndy Fleming 80, 1454272cc70bSAndy Fleming }; 1455272cc70bSAndy Fleming 1456d0c221feSJean-Jacques Hiblot static inline int bus_width(uint cap) 1457d0c221feSJean-Jacques Hiblot { 1458d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_8BIT) 1459d0c221feSJean-Jacques Hiblot return 8; 1460d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_4BIT) 1461d0c221feSJean-Jacques Hiblot return 4; 1462d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_1BIT) 1463d0c221feSJean-Jacques Hiblot return 1; 1464d8e3d420SJean-Jacques Hiblot pr_warn("invalid bus witdh capability 0x%x\n", cap); 1465d0c221feSJean-Jacques Hiblot return 0; 1466d0c221feSJean-Jacques Hiblot } 1467d0c221feSJean-Jacques Hiblot 1468e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 1469f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 1470ec841209SKishon Vijay Abraham I static int mmc_execute_tuning(struct mmc *mmc, uint opcode) 1471ec841209SKishon Vijay Abraham I { 1472ec841209SKishon Vijay Abraham I return -ENOTSUPP; 1473ec841209SKishon Vijay Abraham I } 1474f99c2efeSJean-Jacques Hiblot #endif 1475ec841209SKishon Vijay Abraham I 1476318a7a57SJean-Jacques Hiblot static void mmc_send_init_stream(struct mmc *mmc) 1477318a7a57SJean-Jacques Hiblot { 1478318a7a57SJean-Jacques Hiblot } 1479318a7a57SJean-Jacques Hiblot 14802a4d212fSKishon Vijay Abraham I static int mmc_set_ios(struct mmc *mmc) 1481272cc70bSAndy Fleming { 14822a4d212fSKishon Vijay Abraham I int ret = 0; 14832a4d212fSKishon Vijay Abraham I 148493bfd616SPantelis Antoniou if (mmc->cfg->ops->set_ios) 14852a4d212fSKishon Vijay Abraham I ret = mmc->cfg->ops->set_ios(mmc); 14862a4d212fSKishon Vijay Abraham I 14872a4d212fSKishon Vijay Abraham I return ret; 1488272cc70bSAndy Fleming } 14898ca51e51SSimon Glass #endif 1490272cc70bSAndy Fleming 149135f67820SKishon Vijay Abraham I int mmc_set_clock(struct mmc *mmc, uint clock, bool disable) 1492272cc70bSAndy Fleming { 149393bfd616SPantelis Antoniou if (clock > mmc->cfg->f_max) 149493bfd616SPantelis Antoniou clock = mmc->cfg->f_max; 1495272cc70bSAndy Fleming 149693bfd616SPantelis Antoniou if (clock < mmc->cfg->f_min) 149793bfd616SPantelis Antoniou clock = mmc->cfg->f_min; 1498272cc70bSAndy Fleming 1499272cc70bSAndy Fleming mmc->clock = clock; 150035f67820SKishon Vijay Abraham I mmc->clk_disable = disable; 1501272cc70bSAndy Fleming 15022a4d212fSKishon Vijay Abraham I return mmc_set_ios(mmc); 1503272cc70bSAndy Fleming } 1504272cc70bSAndy Fleming 15052a4d212fSKishon Vijay Abraham I static int mmc_set_bus_width(struct mmc *mmc, uint width) 1506272cc70bSAndy Fleming { 1507272cc70bSAndy Fleming mmc->bus_width = width; 1508272cc70bSAndy Fleming 15092a4d212fSKishon Vijay Abraham I return mmc_set_ios(mmc); 1510272cc70bSAndy Fleming } 1511272cc70bSAndy Fleming 15124c9d2aaaSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG) 15134c9d2aaaSJean-Jacques Hiblot /* 15144c9d2aaaSJean-Jacques Hiblot * helper function to display the capabilities in a human 15154c9d2aaaSJean-Jacques Hiblot * friendly manner. The capabilities include bus width and 15164c9d2aaaSJean-Jacques Hiblot * supported modes. 15174c9d2aaaSJean-Jacques Hiblot */ 15184c9d2aaaSJean-Jacques Hiblot void mmc_dump_capabilities(const char *text, uint caps) 15194c9d2aaaSJean-Jacques Hiblot { 15204c9d2aaaSJean-Jacques Hiblot enum bus_mode mode; 15214c9d2aaaSJean-Jacques Hiblot 15224c9d2aaaSJean-Jacques Hiblot printf("%s: widths [", text); 15234c9d2aaaSJean-Jacques Hiblot if (caps & MMC_MODE_8BIT) 15244c9d2aaaSJean-Jacques Hiblot printf("8, "); 15254c9d2aaaSJean-Jacques Hiblot if (caps & MMC_MODE_4BIT) 15264c9d2aaaSJean-Jacques Hiblot printf("4, "); 1527d0c221feSJean-Jacques Hiblot if (caps & MMC_MODE_1BIT) 1528d0c221feSJean-Jacques Hiblot printf("1, "); 1529d0c221feSJean-Jacques Hiblot printf("\b\b] modes ["); 15304c9d2aaaSJean-Jacques Hiblot for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++) 15314c9d2aaaSJean-Jacques Hiblot if (MMC_CAP(mode) & caps) 15324c9d2aaaSJean-Jacques Hiblot printf("%s, ", mmc_mode_name(mode)); 15334c9d2aaaSJean-Jacques Hiblot printf("\b\b]\n"); 15344c9d2aaaSJean-Jacques Hiblot } 15354c9d2aaaSJean-Jacques Hiblot #endif 15364c9d2aaaSJean-Jacques Hiblot 1537d0c221feSJean-Jacques Hiblot struct mode_width_tuning { 1538d0c221feSJean-Jacques Hiblot enum bus_mode mode; 1539d0c221feSJean-Jacques Hiblot uint widths; 1540f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 1541634d4849SKishon Vijay Abraham I uint tuning; 1542f99c2efeSJean-Jacques Hiblot #endif 1543d0c221feSJean-Jacques Hiblot }; 1544d0c221feSJean-Jacques Hiblot 1545f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE) 1546bc1e3272SJean-Jacques Hiblot int mmc_voltage_to_mv(enum mmc_voltage voltage) 1547bc1e3272SJean-Jacques Hiblot { 1548bc1e3272SJean-Jacques Hiblot switch (voltage) { 1549bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_000: return 0; 1550bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_330: return 3300; 1551bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_180: return 1800; 1552bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_120: return 1200; 1553bc1e3272SJean-Jacques Hiblot } 1554bc1e3272SJean-Jacques Hiblot return -EINVAL; 1555bc1e3272SJean-Jacques Hiblot } 1556bc1e3272SJean-Jacques Hiblot 1557aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage) 1558aff5d3c8SKishon Vijay Abraham I { 1559bc1e3272SJean-Jacques Hiblot int err; 1560bc1e3272SJean-Jacques Hiblot 1561bc1e3272SJean-Jacques Hiblot if (mmc->signal_voltage == signal_voltage) 1562bc1e3272SJean-Jacques Hiblot return 0; 1563bc1e3272SJean-Jacques Hiblot 1564aff5d3c8SKishon Vijay Abraham I mmc->signal_voltage = signal_voltage; 1565bc1e3272SJean-Jacques Hiblot err = mmc_set_ios(mmc); 1566bc1e3272SJean-Jacques Hiblot if (err) 1567bc1e3272SJean-Jacques Hiblot debug("unable to set voltage (err %d)\n", err); 1568bc1e3272SJean-Jacques Hiblot 1569bc1e3272SJean-Jacques Hiblot return err; 1570aff5d3c8SKishon Vijay Abraham I } 1571f99c2efeSJean-Jacques Hiblot #else 1572f99c2efeSJean-Jacques Hiblot static inline int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage) 1573f99c2efeSJean-Jacques Hiblot { 1574f99c2efeSJean-Jacques Hiblot return 0; 1575f99c2efeSJean-Jacques Hiblot } 1576f99c2efeSJean-Jacques Hiblot #endif 1577aff5d3c8SKishon Vijay Abraham I 1578d0c221feSJean-Jacques Hiblot static const struct mode_width_tuning sd_modes_by_pref[] = { 1579f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1580f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 1581d0c221feSJean-Jacques Hiblot { 1582c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR104, 1583c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1584c10b85d6SJean-Jacques Hiblot .tuning = MMC_CMD_SEND_TUNING_BLOCK 1585c10b85d6SJean-Jacques Hiblot }, 1586f99c2efeSJean-Jacques Hiblot #endif 1587c10b85d6SJean-Jacques Hiblot { 1588c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR50, 1589c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1590c10b85d6SJean-Jacques Hiblot }, 1591c10b85d6SJean-Jacques Hiblot { 1592c10b85d6SJean-Jacques Hiblot .mode = UHS_DDR50, 1593c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1594c10b85d6SJean-Jacques Hiblot }, 1595c10b85d6SJean-Jacques Hiblot { 1596c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR25, 1597c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1598c10b85d6SJean-Jacques Hiblot }, 1599f99c2efeSJean-Jacques Hiblot #endif 1600c10b85d6SJean-Jacques Hiblot { 1601d0c221feSJean-Jacques Hiblot .mode = SD_HS, 1602d0c221feSJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1603d0c221feSJean-Jacques Hiblot }, 1604f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1605d0c221feSJean-Jacques Hiblot { 1606c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR12, 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_LEGACY, 1612d0c221feSJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1613d0c221feSJean-Jacques Hiblot } 1614d0c221feSJean-Jacques Hiblot }; 1615d0c221feSJean-Jacques Hiblot 1616d0c221feSJean-Jacques Hiblot #define for_each_sd_mode_by_pref(caps, mwt) \ 1617d0c221feSJean-Jacques Hiblot for (mwt = sd_modes_by_pref;\ 1618d0c221feSJean-Jacques Hiblot mwt < sd_modes_by_pref + ARRAY_SIZE(sd_modes_by_pref);\ 1619d0c221feSJean-Jacques Hiblot mwt++) \ 1620d0c221feSJean-Jacques Hiblot if (caps & MMC_CAP(mwt->mode)) 1621d0c221feSJean-Jacques Hiblot 162201298da3SJean-Jacques Hiblot static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps) 16238ac8a263SJean-Jacques Hiblot { 16248ac8a263SJean-Jacques Hiblot int err; 1625d0c221feSJean-Jacques Hiblot uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT}; 1626d0c221feSJean-Jacques Hiblot const struct mode_width_tuning *mwt; 1627f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1628c10b85d6SJean-Jacques Hiblot bool uhs_en = (mmc->ocr & OCR_S18R) ? true : false; 1629f99c2efeSJean-Jacques Hiblot #else 1630f99c2efeSJean-Jacques Hiblot bool uhs_en = false; 1631f99c2efeSJean-Jacques Hiblot #endif 1632c10b85d6SJean-Jacques Hiblot uint caps; 1633c10b85d6SJean-Jacques Hiblot 163452d241dfSJean-Jacques Hiblot #ifdef DEBUG 163552d241dfSJean-Jacques Hiblot mmc_dump_capabilities("sd card", card_caps); 16361da8eb59SJean-Jacques Hiblot mmc_dump_capabilities("host", mmc->host_caps); 163752d241dfSJean-Jacques Hiblot #endif 16388ac8a263SJean-Jacques Hiblot 16398ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */ 16401da8eb59SJean-Jacques Hiblot caps = card_caps & mmc->host_caps; 16418ac8a263SJean-Jacques Hiblot 1642c10b85d6SJean-Jacques Hiblot if (!uhs_en) 1643c10b85d6SJean-Jacques Hiblot caps &= ~UHS_CAPS; 1644c10b85d6SJean-Jacques Hiblot 1645c10b85d6SJean-Jacques Hiblot for_each_sd_mode_by_pref(caps, mwt) { 1646d0c221feSJean-Jacques Hiblot uint *w; 16478ac8a263SJean-Jacques Hiblot 1648d0c221feSJean-Jacques Hiblot for (w = widths; w < widths + ARRAY_SIZE(widths); w++) { 1649c10b85d6SJean-Jacques Hiblot if (*w & caps & mwt->widths) { 1650d0c221feSJean-Jacques Hiblot debug("trying mode %s width %d (at %d MHz)\n", 1651d0c221feSJean-Jacques Hiblot mmc_mode_name(mwt->mode), 1652d0c221feSJean-Jacques Hiblot bus_width(*w), 1653d0c221feSJean-Jacques Hiblot mmc_mode2freq(mmc, mwt->mode) / 1000000); 1654d0c221feSJean-Jacques Hiblot 1655d0c221feSJean-Jacques Hiblot /* configure the bus width (card + host) */ 1656d0c221feSJean-Jacques Hiblot err = sd_select_bus_width(mmc, bus_width(*w)); 16578ac8a263SJean-Jacques Hiblot if (err) 1658d0c221feSJean-Jacques Hiblot goto error; 1659d0c221feSJean-Jacques Hiblot mmc_set_bus_width(mmc, bus_width(*w)); 16608ac8a263SJean-Jacques Hiblot 1661d0c221feSJean-Jacques Hiblot /* configure the bus mode (card) */ 1662d0c221feSJean-Jacques Hiblot err = sd_set_card_speed(mmc, mwt->mode); 16638ac8a263SJean-Jacques Hiblot if (err) 1664d0c221feSJean-Jacques Hiblot goto error; 16658ac8a263SJean-Jacques Hiblot 1666d0c221feSJean-Jacques Hiblot /* configure the bus mode (host) */ 1667d0c221feSJean-Jacques Hiblot mmc_select_mode(mmc, mwt->mode); 166835f67820SKishon Vijay Abraham I mmc_set_clock(mmc, mmc->tran_speed, false); 16698ac8a263SJean-Jacques Hiblot 1670f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 1671c10b85d6SJean-Jacques Hiblot /* execute tuning if needed */ 1672c10b85d6SJean-Jacques Hiblot if (mwt->tuning && !mmc_host_is_spi(mmc)) { 1673c10b85d6SJean-Jacques Hiblot err = mmc_execute_tuning(mmc, 1674c10b85d6SJean-Jacques Hiblot mwt->tuning); 1675c10b85d6SJean-Jacques Hiblot if (err) { 1676c10b85d6SJean-Jacques Hiblot debug("tuning failed\n"); 1677c10b85d6SJean-Jacques Hiblot goto error; 1678c10b85d6SJean-Jacques Hiblot } 1679c10b85d6SJean-Jacques Hiblot } 1680f99c2efeSJean-Jacques Hiblot #endif 1681c10b85d6SJean-Jacques Hiblot 16828ac8a263SJean-Jacques Hiblot err = sd_read_ssr(mmc); 1683d0c221feSJean-Jacques Hiblot if (!err) 16848ac8a263SJean-Jacques Hiblot return 0; 1685d0c221feSJean-Jacques Hiblot 1686d8e3d420SJean-Jacques Hiblot pr_warn("bad ssr\n"); 1687d0c221feSJean-Jacques Hiblot 1688d0c221feSJean-Jacques Hiblot error: 1689d0c221feSJean-Jacques Hiblot /* revert to a safer bus speed */ 1690d0c221feSJean-Jacques Hiblot mmc_select_mode(mmc, SD_LEGACY); 169135f67820SKishon Vijay Abraham I mmc_set_clock(mmc, mmc->tran_speed, false); 1692d0c221feSJean-Jacques Hiblot } 1693d0c221feSJean-Jacques Hiblot } 1694d0c221feSJean-Jacques Hiblot } 1695d0c221feSJean-Jacques Hiblot 1696d0c221feSJean-Jacques Hiblot printf("unable to select a mode\n"); 1697d0c221feSJean-Jacques Hiblot return -ENOTSUPP; 16988ac8a263SJean-Jacques Hiblot } 16998ac8a263SJean-Jacques Hiblot 17007382e691SJean-Jacques Hiblot /* 17017382e691SJean-Jacques Hiblot * read the compare the part of ext csd that is constant. 17027382e691SJean-Jacques Hiblot * This can be used to check that the transfer is working 17037382e691SJean-Jacques Hiblot * as expected. 17047382e691SJean-Jacques Hiblot */ 17057382e691SJean-Jacques Hiblot static int mmc_read_and_compare_ext_csd(struct mmc *mmc) 17067382e691SJean-Jacques Hiblot { 17077382e691SJean-Jacques Hiblot int err; 17087382e691SJean-Jacques Hiblot const u8 *ext_csd = mmc->ext_csd; 17097382e691SJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 17107382e691SJean-Jacques Hiblot 17111de06b9fSJean-Jacques Hiblot if (mmc->version < MMC_VERSION_4) 17121de06b9fSJean-Jacques Hiblot return 0; 17131de06b9fSJean-Jacques Hiblot 17147382e691SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, test_csd); 17157382e691SJean-Jacques Hiblot if (err) 17167382e691SJean-Jacques Hiblot return err; 17177382e691SJean-Jacques Hiblot 17187382e691SJean-Jacques Hiblot /* Only compare read only fields */ 17197382e691SJean-Jacques Hiblot if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] 17207382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_PARTITIONING_SUPPORT] && 17217382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_WP_GRP_SIZE] 17227382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_WP_GRP_SIZE] && 17237382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_REV] 17247382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_REV] && 17257382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 17267382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] && 17277382e691SJean-Jacques Hiblot memcmp(&ext_csd[EXT_CSD_SEC_CNT], 17287382e691SJean-Jacques Hiblot &test_csd[EXT_CSD_SEC_CNT], 4) == 0) 17297382e691SJean-Jacques Hiblot return 0; 17307382e691SJean-Jacques Hiblot 17317382e691SJean-Jacques Hiblot return -EBADMSG; 17327382e691SJean-Jacques Hiblot } 17337382e691SJean-Jacques Hiblot 1734f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE) 1735bc1e3272SJean-Jacques Hiblot static int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode, 1736bc1e3272SJean-Jacques Hiblot uint32_t allowed_mask) 1737bc1e3272SJean-Jacques Hiblot { 1738bc1e3272SJean-Jacques Hiblot u32 card_mask = 0; 1739bc1e3272SJean-Jacques Hiblot 1740bc1e3272SJean-Jacques Hiblot switch (mode) { 1741bc1e3272SJean-Jacques Hiblot case MMC_HS_200: 1742bc1e3272SJean-Jacques Hiblot if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_8V) 1743bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_180; 1744bc1e3272SJean-Jacques Hiblot if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_2V) 1745bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_120; 1746bc1e3272SJean-Jacques Hiblot break; 1747bc1e3272SJean-Jacques Hiblot case MMC_DDR_52: 1748bc1e3272SJean-Jacques Hiblot if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V) 1749bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_330 | 1750bc1e3272SJean-Jacques Hiblot MMC_SIGNAL_VOLTAGE_180; 1751bc1e3272SJean-Jacques Hiblot if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_2V) 1752bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_120; 1753bc1e3272SJean-Jacques Hiblot break; 1754bc1e3272SJean-Jacques Hiblot default: 1755bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_330; 1756bc1e3272SJean-Jacques Hiblot break; 1757bc1e3272SJean-Jacques Hiblot } 1758bc1e3272SJean-Jacques Hiblot 1759bc1e3272SJean-Jacques Hiblot while (card_mask & allowed_mask) { 1760bc1e3272SJean-Jacques Hiblot enum mmc_voltage best_match; 1761bc1e3272SJean-Jacques Hiblot 1762bc1e3272SJean-Jacques Hiblot best_match = 1 << (ffs(card_mask & allowed_mask) - 1); 1763bc1e3272SJean-Jacques Hiblot if (!mmc_set_signal_voltage(mmc, best_match)) 1764bc1e3272SJean-Jacques Hiblot return 0; 1765bc1e3272SJean-Jacques Hiblot 1766bc1e3272SJean-Jacques Hiblot allowed_mask &= ~best_match; 1767bc1e3272SJean-Jacques Hiblot } 1768bc1e3272SJean-Jacques Hiblot 1769bc1e3272SJean-Jacques Hiblot return -ENOTSUPP; 1770bc1e3272SJean-Jacques Hiblot } 1771f99c2efeSJean-Jacques Hiblot #else 1772f99c2efeSJean-Jacques Hiblot static inline int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode, 1773f99c2efeSJean-Jacques Hiblot uint32_t allowed_mask) 1774f99c2efeSJean-Jacques Hiblot { 1775f99c2efeSJean-Jacques Hiblot return 0; 1776f99c2efeSJean-Jacques Hiblot } 1777f99c2efeSJean-Jacques Hiblot #endif 1778bc1e3272SJean-Jacques Hiblot 17793862b854SJean-Jacques Hiblot static const struct mode_width_tuning mmc_modes_by_pref[] = { 1780f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) 17818ac8a263SJean-Jacques Hiblot { 17823862b854SJean-Jacques Hiblot .mode = MMC_HS_200, 17833862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT, 1784634d4849SKishon Vijay Abraham I .tuning = MMC_CMD_SEND_TUNING_BLOCK_HS200 17853862b854SJean-Jacques Hiblot }, 1786f99c2efeSJean-Jacques Hiblot #endif 17873862b854SJean-Jacques Hiblot { 17883862b854SJean-Jacques Hiblot .mode = MMC_DDR_52, 17893862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT, 17903862b854SJean-Jacques Hiblot }, 17913862b854SJean-Jacques Hiblot { 17923862b854SJean-Jacques Hiblot .mode = MMC_HS_52, 17933862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 17943862b854SJean-Jacques Hiblot }, 17953862b854SJean-Jacques Hiblot { 17963862b854SJean-Jacques Hiblot .mode = MMC_HS, 17973862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 17983862b854SJean-Jacques Hiblot }, 17993862b854SJean-Jacques Hiblot { 18003862b854SJean-Jacques Hiblot .mode = MMC_LEGACY, 18013862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 18023862b854SJean-Jacques Hiblot } 18038ac8a263SJean-Jacques Hiblot }; 18048ac8a263SJean-Jacques Hiblot 18053862b854SJean-Jacques Hiblot #define for_each_mmc_mode_by_pref(caps, mwt) \ 18063862b854SJean-Jacques Hiblot for (mwt = mmc_modes_by_pref;\ 18073862b854SJean-Jacques Hiblot mwt < mmc_modes_by_pref + ARRAY_SIZE(mmc_modes_by_pref);\ 18083862b854SJean-Jacques Hiblot mwt++) \ 18093862b854SJean-Jacques Hiblot if (caps & MMC_CAP(mwt->mode)) 18103862b854SJean-Jacques Hiblot 18113862b854SJean-Jacques Hiblot static const struct ext_csd_bus_width { 18123862b854SJean-Jacques Hiblot uint cap; 18133862b854SJean-Jacques Hiblot bool is_ddr; 18143862b854SJean-Jacques Hiblot uint ext_csd_bits; 18153862b854SJean-Jacques Hiblot } ext_csd_bus_width[] = { 18163862b854SJean-Jacques Hiblot {MMC_MODE_8BIT, true, EXT_CSD_DDR_BUS_WIDTH_8}, 18173862b854SJean-Jacques Hiblot {MMC_MODE_4BIT, true, EXT_CSD_DDR_BUS_WIDTH_4}, 18183862b854SJean-Jacques Hiblot {MMC_MODE_8BIT, false, EXT_CSD_BUS_WIDTH_8}, 18193862b854SJean-Jacques Hiblot {MMC_MODE_4BIT, false, EXT_CSD_BUS_WIDTH_4}, 18203862b854SJean-Jacques Hiblot {MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1}, 18213862b854SJean-Jacques Hiblot }; 18223862b854SJean-Jacques Hiblot 18233862b854SJean-Jacques Hiblot #define for_each_supported_width(caps, ddr, ecbv) \ 18243862b854SJean-Jacques Hiblot for (ecbv = ext_csd_bus_width;\ 18253862b854SJean-Jacques Hiblot ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\ 18263862b854SJean-Jacques Hiblot ecbv++) \ 18273862b854SJean-Jacques Hiblot if ((ddr == ecbv->is_ddr) && (caps & ecbv->cap)) 18283862b854SJean-Jacques Hiblot 182901298da3SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps) 18303862b854SJean-Jacques Hiblot { 18313862b854SJean-Jacques Hiblot int err; 18323862b854SJean-Jacques Hiblot const struct mode_width_tuning *mwt; 18333862b854SJean-Jacques Hiblot const struct ext_csd_bus_width *ecbw; 18343862b854SJean-Jacques Hiblot 183552d241dfSJean-Jacques Hiblot #ifdef DEBUG 183652d241dfSJean-Jacques Hiblot mmc_dump_capabilities("mmc", card_caps); 18371da8eb59SJean-Jacques Hiblot mmc_dump_capabilities("host", mmc->host_caps); 183852d241dfSJean-Jacques Hiblot #endif 183952d241dfSJean-Jacques Hiblot 18408ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */ 18411da8eb59SJean-Jacques Hiblot card_caps &= mmc->host_caps; 18428ac8a263SJean-Jacques Hiblot 18438ac8a263SJean-Jacques Hiblot /* Only version 4 of MMC supports wider bus widths */ 18448ac8a263SJean-Jacques Hiblot if (mmc->version < MMC_VERSION_4) 18458ac8a263SJean-Jacques Hiblot return 0; 18468ac8a263SJean-Jacques Hiblot 1847dfda9d88SJean-Jacques Hiblot if (!mmc->ext_csd) { 1848dfda9d88SJean-Jacques Hiblot debug("No ext_csd found!\n"); /* this should enver happen */ 1849dfda9d88SJean-Jacques Hiblot return -ENOTSUPP; 1850dfda9d88SJean-Jacques Hiblot } 1851dfda9d88SJean-Jacques Hiblot 185201298da3SJean-Jacques Hiblot mmc_set_clock(mmc, mmc->legacy_speed, false); 185301298da3SJean-Jacques Hiblot 185401298da3SJean-Jacques Hiblot for_each_mmc_mode_by_pref(card_caps, mwt) { 185501298da3SJean-Jacques Hiblot for_each_supported_width(card_caps & mwt->widths, 18563862b854SJean-Jacques Hiblot mmc_is_mode_ddr(mwt->mode), ecbw) { 1857bc1e3272SJean-Jacques Hiblot enum mmc_voltage old_voltage; 18583862b854SJean-Jacques Hiblot debug("trying mode %s width %d (at %d MHz)\n", 18593862b854SJean-Jacques Hiblot mmc_mode_name(mwt->mode), 18603862b854SJean-Jacques Hiblot bus_width(ecbw->cap), 18613862b854SJean-Jacques Hiblot mmc_mode2freq(mmc, mwt->mode) / 1000000); 1862bc1e3272SJean-Jacques Hiblot old_voltage = mmc->signal_voltage; 1863bc1e3272SJean-Jacques Hiblot err = mmc_set_lowest_voltage(mmc, mwt->mode, 1864bc1e3272SJean-Jacques Hiblot MMC_ALL_SIGNAL_VOLTAGE); 1865bc1e3272SJean-Jacques Hiblot if (err) 1866bc1e3272SJean-Jacques Hiblot continue; 1867bc1e3272SJean-Jacques Hiblot 18683862b854SJean-Jacques Hiblot /* configure the bus width (card + host) */ 18693862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 18703862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, 18713862b854SJean-Jacques Hiblot ecbw->ext_csd_bits & ~EXT_CSD_DDR_FLAG); 18723862b854SJean-Jacques Hiblot if (err) 18733862b854SJean-Jacques Hiblot goto error; 18743862b854SJean-Jacques Hiblot mmc_set_bus_width(mmc, bus_width(ecbw->cap)); 18753862b854SJean-Jacques Hiblot 18763862b854SJean-Jacques Hiblot /* configure the bus speed (card) */ 18773862b854SJean-Jacques Hiblot err = mmc_set_card_speed(mmc, mwt->mode); 18783862b854SJean-Jacques Hiblot if (err) 18793862b854SJean-Jacques Hiblot goto error; 18803862b854SJean-Jacques Hiblot 18818ac8a263SJean-Jacques Hiblot /* 18823862b854SJean-Jacques Hiblot * configure the bus width AND the ddr mode (card) 18833862b854SJean-Jacques Hiblot * The host side will be taken care of in the next step 18848ac8a263SJean-Jacques Hiblot */ 18853862b854SJean-Jacques Hiblot if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) { 18863862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 18873862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, 18883862b854SJean-Jacques Hiblot ecbw->ext_csd_bits); 18893862b854SJean-Jacques Hiblot if (err) 18903862b854SJean-Jacques Hiblot goto error; 18918ac8a263SJean-Jacques Hiblot } 18928ac8a263SJean-Jacques Hiblot 18933862b854SJean-Jacques Hiblot /* configure the bus mode (host) */ 18943862b854SJean-Jacques Hiblot mmc_select_mode(mmc, mwt->mode); 189535f67820SKishon Vijay Abraham I mmc_set_clock(mmc, mmc->tran_speed, false); 1896f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 18978ac8a263SJean-Jacques Hiblot 1898634d4849SKishon Vijay Abraham I /* execute tuning if needed */ 1899634d4849SKishon Vijay Abraham I if (mwt->tuning) { 1900634d4849SKishon Vijay Abraham I err = mmc_execute_tuning(mmc, mwt->tuning); 1901634d4849SKishon Vijay Abraham I if (err) { 1902634d4849SKishon Vijay Abraham I debug("tuning failed\n"); 1903634d4849SKishon Vijay Abraham I goto error; 1904634d4849SKishon Vijay Abraham I } 1905634d4849SKishon Vijay Abraham I } 1906f99c2efeSJean-Jacques Hiblot #endif 1907634d4849SKishon Vijay Abraham I 19083862b854SJean-Jacques Hiblot /* do a transfer to check the configuration */ 19097382e691SJean-Jacques Hiblot err = mmc_read_and_compare_ext_csd(mmc); 19107382e691SJean-Jacques Hiblot if (!err) 19113862b854SJean-Jacques Hiblot return 0; 19123862b854SJean-Jacques Hiblot error: 1913bc1e3272SJean-Jacques Hiblot mmc_set_signal_voltage(mmc, old_voltage); 19143862b854SJean-Jacques Hiblot /* if an error occured, revert to a safer bus mode */ 19153862b854SJean-Jacques Hiblot mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 19163862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1); 19173862b854SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_LEGACY); 19183862b854SJean-Jacques Hiblot mmc_set_bus_width(mmc, 1); 19193862b854SJean-Jacques Hiblot } 19208ac8a263SJean-Jacques Hiblot } 19218ac8a263SJean-Jacques Hiblot 1922d8e3d420SJean-Jacques Hiblot pr_err("unable to select a mode\n"); 19238ac8a263SJean-Jacques Hiblot 19243862b854SJean-Jacques Hiblot return -ENOTSUPP; 19258ac8a263SJean-Jacques Hiblot } 19268ac8a263SJean-Jacques Hiblot 1927dfda9d88SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc) 1928c744b6f6SJean-Jacques Hiblot { 1929c744b6f6SJean-Jacques Hiblot int err, i; 1930c744b6f6SJean-Jacques Hiblot u64 capacity; 1931c744b6f6SJean-Jacques Hiblot bool has_parts = false; 1932c744b6f6SJean-Jacques Hiblot bool part_completed; 1933f7d5dffcSJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 1934c744b6f6SJean-Jacques Hiblot 1935c744b6f6SJean-Jacques Hiblot if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4)) 1936c744b6f6SJean-Jacques Hiblot return 0; 1937c744b6f6SJean-Jacques Hiblot 1938c744b6f6SJean-Jacques Hiblot /* check ext_csd version and capacity */ 1939c744b6f6SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, ext_csd); 1940c744b6f6SJean-Jacques Hiblot if (err) 1941f7d5dffcSJean-Jacques Hiblot goto error; 1942f7d5dffcSJean-Jacques Hiblot 1943f7d5dffcSJean-Jacques Hiblot /* store the ext csd for future reference */ 1944f7d5dffcSJean-Jacques Hiblot if (!mmc->ext_csd) 1945f7d5dffcSJean-Jacques Hiblot mmc->ext_csd = malloc(MMC_MAX_BLOCK_LEN); 1946f7d5dffcSJean-Jacques Hiblot if (!mmc->ext_csd) 1947f7d5dffcSJean-Jacques Hiblot return -ENOMEM; 1948f7d5dffcSJean-Jacques Hiblot memcpy(mmc->ext_csd, ext_csd, MMC_MAX_BLOCK_LEN); 1949f7d5dffcSJean-Jacques Hiblot 1950c744b6f6SJean-Jacques Hiblot if (ext_csd[EXT_CSD_REV] >= 2) { 1951c744b6f6SJean-Jacques Hiblot /* 1952c744b6f6SJean-Jacques Hiblot * According to the JEDEC Standard, the value of 1953c744b6f6SJean-Jacques Hiblot * ext_csd's capacity is valid if the value is more 1954c744b6f6SJean-Jacques Hiblot * than 2GB 1955c744b6f6SJean-Jacques Hiblot */ 1956c744b6f6SJean-Jacques Hiblot capacity = ext_csd[EXT_CSD_SEC_CNT] << 0 1957c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 1958c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 1959c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; 1960c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN; 1961c744b6f6SJean-Jacques Hiblot if ((capacity >> 20) > 2 * 1024) 1962c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity; 1963c744b6f6SJean-Jacques Hiblot } 1964c744b6f6SJean-Jacques Hiblot 1965c744b6f6SJean-Jacques Hiblot switch (ext_csd[EXT_CSD_REV]) { 1966c744b6f6SJean-Jacques Hiblot case 1: 1967c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_1; 1968c744b6f6SJean-Jacques Hiblot break; 1969c744b6f6SJean-Jacques Hiblot case 2: 1970c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_2; 1971c744b6f6SJean-Jacques Hiblot break; 1972c744b6f6SJean-Jacques Hiblot case 3: 1973c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_3; 1974c744b6f6SJean-Jacques Hiblot break; 1975c744b6f6SJean-Jacques Hiblot case 5: 1976c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_41; 1977c744b6f6SJean-Jacques Hiblot break; 1978c744b6f6SJean-Jacques Hiblot case 6: 1979c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_4_5; 1980c744b6f6SJean-Jacques Hiblot break; 1981c744b6f6SJean-Jacques Hiblot case 7: 1982c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_5_0; 1983c744b6f6SJean-Jacques Hiblot break; 1984c744b6f6SJean-Jacques Hiblot case 8: 1985c744b6f6SJean-Jacques Hiblot mmc->version = MMC_VERSION_5_1; 1986c744b6f6SJean-Jacques Hiblot break; 1987c744b6f6SJean-Jacques Hiblot } 1988c744b6f6SJean-Jacques Hiblot 1989c744b6f6SJean-Jacques Hiblot /* The partition data may be non-zero but it is only 1990c744b6f6SJean-Jacques Hiblot * effective if PARTITION_SETTING_COMPLETED is set in 1991c744b6f6SJean-Jacques Hiblot * EXT_CSD, so ignore any data if this bit is not set, 1992c744b6f6SJean-Jacques Hiblot * except for enabling the high-capacity group size 1993c744b6f6SJean-Jacques Hiblot * definition (see below). 1994c744b6f6SJean-Jacques Hiblot */ 1995c744b6f6SJean-Jacques Hiblot part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] & 1996c744b6f6SJean-Jacques Hiblot EXT_CSD_PARTITION_SETTING_COMPLETED); 1997c744b6f6SJean-Jacques Hiblot 1998c744b6f6SJean-Jacques Hiblot /* store the partition info of emmc */ 1999c744b6f6SJean-Jacques Hiblot mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT]; 2000c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || 2001c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_BOOT_MULT]) 2002c744b6f6SJean-Jacques Hiblot mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; 2003c744b6f6SJean-Jacques Hiblot if (part_completed && 2004c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT)) 2005c744b6f6SJean-Jacques Hiblot mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]; 2006c744b6f6SJean-Jacques Hiblot 2007c744b6f6SJean-Jacques Hiblot mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17; 2008c744b6f6SJean-Jacques Hiblot 2009c744b6f6SJean-Jacques Hiblot mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17; 2010c744b6f6SJean-Jacques Hiblot 2011c744b6f6SJean-Jacques Hiblot for (i = 0; i < 4; i++) { 2012c744b6f6SJean-Jacques Hiblot int idx = EXT_CSD_GP_SIZE_MULT + i * 3; 2013c744b6f6SJean-Jacques Hiblot uint mult = (ext_csd[idx + 2] << 16) + 2014c744b6f6SJean-Jacques Hiblot (ext_csd[idx + 1] << 8) + ext_csd[idx]; 2015c744b6f6SJean-Jacques Hiblot if (mult) 2016c744b6f6SJean-Jacques Hiblot has_parts = true; 2017c744b6f6SJean-Jacques Hiblot if (!part_completed) 2018c744b6f6SJean-Jacques Hiblot continue; 2019c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] = mult; 2020c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= 2021c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 2022c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 2023c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] <<= 19; 2024c744b6f6SJean-Jacques Hiblot } 2025c744b6f6SJean-Jacques Hiblot 2026c744b6f6SJean-Jacques Hiblot if (part_completed) { 2027c744b6f6SJean-Jacques Hiblot mmc->enh_user_size = 2028c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) + 2029c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) + 2030c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_SIZE_MULT]; 2031c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 2032c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 2033c744b6f6SJean-Jacques Hiblot mmc->enh_user_size <<= 19; 2034c744b6f6SJean-Jacques Hiblot mmc->enh_user_start = 2035c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) + 2036c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) + 2037c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) + 2038c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_START_ADDR]; 2039c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity) 2040c744b6f6SJean-Jacques Hiblot mmc->enh_user_start <<= 9; 2041c744b6f6SJean-Jacques Hiblot } 2042c744b6f6SJean-Jacques Hiblot 2043c744b6f6SJean-Jacques Hiblot /* 2044c744b6f6SJean-Jacques Hiblot * Host needs to enable ERASE_GRP_DEF bit if device is 2045c744b6f6SJean-Jacques Hiblot * partitioned. This bit will be lost every time after a reset 2046c744b6f6SJean-Jacques Hiblot * or power off. This will affect erase size. 2047c744b6f6SJean-Jacques Hiblot */ 2048c744b6f6SJean-Jacques Hiblot if (part_completed) 2049c744b6f6SJean-Jacques Hiblot has_parts = true; 2050c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) && 2051c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) 2052c744b6f6SJean-Jacques Hiblot has_parts = true; 2053c744b6f6SJean-Jacques Hiblot if (has_parts) { 2054c744b6f6SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 2055c744b6f6SJean-Jacques Hiblot EXT_CSD_ERASE_GROUP_DEF, 1); 2056c744b6f6SJean-Jacques Hiblot 2057c744b6f6SJean-Jacques Hiblot if (err) 2058f7d5dffcSJean-Jacques Hiblot goto error; 2059c744b6f6SJean-Jacques Hiblot 2060c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 2061c744b6f6SJean-Jacques Hiblot } 2062c744b6f6SJean-Jacques Hiblot 2063c744b6f6SJean-Jacques Hiblot if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) { 2064c744b6f6SJean-Jacques Hiblot /* Read out group size from ext_csd */ 2065c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = 2066c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 2067c744b6f6SJean-Jacques Hiblot /* 2068c744b6f6SJean-Jacques Hiblot * if high capacity and partition setting completed 2069c744b6f6SJean-Jacques Hiblot * SEC_COUNT is valid even if it is smaller than 2 GiB 2070c744b6f6SJean-Jacques Hiblot * JEDEC Standard JESD84-B45, 6.2.4 2071c744b6f6SJean-Jacques Hiblot */ 2072c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity && part_completed) { 2073c744b6f6SJean-Jacques Hiblot capacity = (ext_csd[EXT_CSD_SEC_CNT]) | 2074c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) | 2075c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) | 2076c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 3] << 24); 2077c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN; 2078c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity; 2079c744b6f6SJean-Jacques Hiblot } 2080c744b6f6SJean-Jacques Hiblot } else { 2081c744b6f6SJean-Jacques Hiblot /* Calculate the group size from the csd value. */ 2082c744b6f6SJean-Jacques Hiblot int erase_gsz, erase_gmul; 2083c744b6f6SJean-Jacques Hiblot 2084c744b6f6SJean-Jacques Hiblot erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; 2085c744b6f6SJean-Jacques Hiblot erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; 2086c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = (erase_gsz + 1) 2087c744b6f6SJean-Jacques Hiblot * (erase_gmul + 1); 2088c744b6f6SJean-Jacques Hiblot } 2089c744b6f6SJean-Jacques Hiblot 2090c744b6f6SJean-Jacques Hiblot mmc->hc_wp_grp_size = 1024 2091c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 2092c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 2093c744b6f6SJean-Jacques Hiblot 2094c744b6f6SJean-Jacques Hiblot mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 2095c744b6f6SJean-Jacques Hiblot 2096c744b6f6SJean-Jacques Hiblot return 0; 2097f7d5dffcSJean-Jacques Hiblot error: 2098f7d5dffcSJean-Jacques Hiblot if (mmc->ext_csd) { 2099f7d5dffcSJean-Jacques Hiblot free(mmc->ext_csd); 2100f7d5dffcSJean-Jacques Hiblot mmc->ext_csd = NULL; 2101f7d5dffcSJean-Jacques Hiblot } 2102f7d5dffcSJean-Jacques Hiblot return err; 2103c744b6f6SJean-Jacques Hiblot } 2104c744b6f6SJean-Jacques Hiblot 2105fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc) 2106272cc70bSAndy Fleming { 2107f866a46dSStephen Warren int err, i; 2108272cc70bSAndy Fleming uint mult, freq; 2109c744b6f6SJean-Jacques Hiblot u64 cmult, csize; 2110272cc70bSAndy Fleming struct mmc_cmd cmd; 2111c40fdca6SSimon Glass struct blk_desc *bdesc; 2112272cc70bSAndy Fleming 2113d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON 2114d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ 2115d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; 2116d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R1; 2117d52ebf10SThomas Chou cmd.cmdarg = 1; 2118d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 2119d52ebf10SThomas Chou if (err) 2120d52ebf10SThomas Chou return err; 2121d52ebf10SThomas Chou } 2122d52ebf10SThomas Chou #endif 2123d52ebf10SThomas Chou 2124272cc70bSAndy Fleming /* Put the Card in Identify Mode */ 2125d52ebf10SThomas Chou cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : 2126d52ebf10SThomas Chou MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ 2127272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 2128272cc70bSAndy Fleming cmd.cmdarg = 0; 2129272cc70bSAndy Fleming 2130272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2131272cc70bSAndy Fleming 213283dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS 213383dc4227SKishon Vijay Abraham I if (err && (mmc->quirks & MMC_QUIRK_RETRY_SEND_CID)) { 213483dc4227SKishon Vijay Abraham I int retries = 4; 213583dc4227SKishon Vijay Abraham I /* 213683dc4227SKishon Vijay Abraham I * It has been seen that SEND_CID may fail on the first 213783dc4227SKishon Vijay Abraham I * attempt, let's try a few more time 213883dc4227SKishon Vijay Abraham I */ 213983dc4227SKishon Vijay Abraham I do { 214083dc4227SKishon Vijay Abraham I err = mmc_send_cmd(mmc, &cmd, NULL); 214183dc4227SKishon Vijay Abraham I if (!err) 214283dc4227SKishon Vijay Abraham I break; 214383dc4227SKishon Vijay Abraham I } while (retries--); 214483dc4227SKishon Vijay Abraham I } 214583dc4227SKishon Vijay Abraham I #endif 214683dc4227SKishon Vijay Abraham I 2147272cc70bSAndy Fleming if (err) 2148272cc70bSAndy Fleming return err; 2149272cc70bSAndy Fleming 2150272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16); 2151272cc70bSAndy Fleming 2152272cc70bSAndy Fleming /* 2153272cc70bSAndy Fleming * For MMC cards, set the Relative Address. 2154272cc70bSAndy Fleming * For SD cards, get the Relatvie Address. 2155272cc70bSAndy Fleming * This also puts the cards into Standby State 2156272cc70bSAndy Fleming */ 2157d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 2158272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; 2159272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 2160272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6; 2161272cc70bSAndy Fleming 2162272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2163272cc70bSAndy Fleming 2164272cc70bSAndy Fleming if (err) 2165272cc70bSAndy Fleming return err; 2166272cc70bSAndy Fleming 2167272cc70bSAndy Fleming if (IS_SD(mmc)) 2168998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff; 2169d52ebf10SThomas Chou } 2170272cc70bSAndy Fleming 2171272cc70bSAndy Fleming /* Get the Card-Specific Data */ 2172272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD; 2173272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 2174272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 2175272cc70bSAndy Fleming 2176272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2177272cc70bSAndy Fleming 2178272cc70bSAndy Fleming if (err) 2179272cc70bSAndy Fleming return err; 2180272cc70bSAndy Fleming 2181998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0]; 2182998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1]; 2183998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2]; 2184998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3]; 2185272cc70bSAndy Fleming 2186272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) { 21870b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf; 2188272cc70bSAndy Fleming 2189272cc70bSAndy Fleming switch (version) { 2190272cc70bSAndy Fleming case 0: 2191272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 2192272cc70bSAndy Fleming break; 2193272cc70bSAndy Fleming case 1: 2194272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4; 2195272cc70bSAndy Fleming break; 2196272cc70bSAndy Fleming case 2: 2197272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2; 2198272cc70bSAndy Fleming break; 2199272cc70bSAndy Fleming case 3: 2200272cc70bSAndy Fleming mmc->version = MMC_VERSION_3; 2201272cc70bSAndy Fleming break; 2202272cc70bSAndy Fleming case 4: 2203272cc70bSAndy Fleming mmc->version = MMC_VERSION_4; 2204272cc70bSAndy Fleming break; 2205272cc70bSAndy Fleming default: 2206272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 2207272cc70bSAndy Fleming break; 2208272cc70bSAndy Fleming } 2209272cc70bSAndy Fleming } 2210272cc70bSAndy Fleming 2211272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */ 22120b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)]; 22130b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; 2214272cc70bSAndy Fleming 221535f9e196SJean-Jacques Hiblot mmc->legacy_speed = freq * mult; 221635f9e196SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_LEGACY); 2217272cc70bSAndy Fleming 2218ab71188cSMarkus Niebel mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); 2219998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); 2220272cc70bSAndy Fleming 2221272cc70bSAndy Fleming if (IS_SD(mmc)) 2222272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len; 2223272cc70bSAndy Fleming else 2224998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); 2225272cc70bSAndy Fleming 2226272cc70bSAndy Fleming if (mmc->high_capacity) { 2227272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16 2228272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16; 2229272cc70bSAndy Fleming cmult = 8; 2230272cc70bSAndy Fleming } else { 2231272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2 2232272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30; 2233272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15; 2234272cc70bSAndy Fleming } 2235272cc70bSAndy Fleming 2236f866a46dSStephen Warren mmc->capacity_user = (csize + 1) << (cmult + 2); 2237f866a46dSStephen Warren mmc->capacity_user *= mmc->read_bl_len; 2238f866a46dSStephen Warren mmc->capacity_boot = 0; 2239f866a46dSStephen Warren mmc->capacity_rpmb = 0; 2240f866a46dSStephen Warren for (i = 0; i < 4; i++) 2241f866a46dSStephen Warren mmc->capacity_gp[i] = 0; 2242272cc70bSAndy Fleming 22438bfa195eSSimon Glass if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN) 22448bfa195eSSimon Glass mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 2245272cc70bSAndy Fleming 22468bfa195eSSimon Glass if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) 22478bfa195eSSimon Glass mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 2248272cc70bSAndy Fleming 2249ab71188cSMarkus Niebel if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) { 2250ab71188cSMarkus Niebel cmd.cmdidx = MMC_CMD_SET_DSR; 2251ab71188cSMarkus Niebel cmd.cmdarg = (mmc->dsr & 0xffff) << 16; 2252ab71188cSMarkus Niebel cmd.resp_type = MMC_RSP_NONE; 2253ab71188cSMarkus Niebel if (mmc_send_cmd(mmc, &cmd, NULL)) 2254d8e3d420SJean-Jacques Hiblot pr_warn("MMC: SET_DSR failed\n"); 2255ab71188cSMarkus Niebel } 2256ab71188cSMarkus Niebel 2257272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */ 2258d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 2259272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD; 2260fe8f7066SAjay Bhargav cmd.resp_type = MMC_RSP_R1; 2261272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 2262272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2263272cc70bSAndy Fleming 2264272cc70bSAndy Fleming if (err) 2265272cc70bSAndy Fleming return err; 2266d52ebf10SThomas Chou } 2267272cc70bSAndy Fleming 2268e6f99a56SLei Wen /* 2269e6f99a56SLei Wen * For SD, its erase group is always one sector 2270e6f99a56SLei Wen */ 2271e6f99a56SLei Wen mmc->erase_grp_size = 1; 2272bc897b1dSLei Wen mmc->part_config = MMCPART_NOAVAILABLE; 2273c744b6f6SJean-Jacques Hiblot 2274dfda9d88SJean-Jacques Hiblot err = mmc_startup_v4(mmc); 22759cf199ebSDiego Santa Cruz if (err) 22769cf199ebSDiego Santa Cruz return err; 2277f866a46dSStephen Warren 2278c40fdca6SSimon Glass err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart); 2279f866a46dSStephen Warren if (err) 2280f866a46dSStephen Warren return err; 2281d23e2c09SSukumar Ghorai 228201298da3SJean-Jacques Hiblot if (IS_SD(mmc)) { 228301298da3SJean-Jacques Hiblot err = sd_get_capabilities(mmc); 228401298da3SJean-Jacques Hiblot if (err) 228501298da3SJean-Jacques Hiblot return err; 228601298da3SJean-Jacques Hiblot err = sd_select_mode_and_width(mmc, mmc->card_caps); 228701298da3SJean-Jacques Hiblot } else { 228801298da3SJean-Jacques Hiblot err = mmc_get_capabilities(mmc); 228901298da3SJean-Jacques Hiblot if (err) 229001298da3SJean-Jacques Hiblot return err; 229101298da3SJean-Jacques Hiblot mmc_select_mode_and_width(mmc, mmc->card_caps); 229201298da3SJean-Jacques Hiblot } 2293272cc70bSAndy Fleming 2294272cc70bSAndy Fleming if (err) 2295272cc70bSAndy Fleming return err; 2296272cc70bSAndy Fleming 229701298da3SJean-Jacques Hiblot mmc->best_mode = mmc->selected_mode; 2298272cc70bSAndy Fleming 22995af8f45cSAndrew Gabbasov /* Fix the block length for DDR mode */ 23005af8f45cSAndrew Gabbasov if (mmc->ddr_mode) { 23015af8f45cSAndrew Gabbasov mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 23025af8f45cSAndrew Gabbasov mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 23035af8f45cSAndrew Gabbasov } 23045af8f45cSAndrew Gabbasov 2305272cc70bSAndy Fleming /* fill in device description */ 2306c40fdca6SSimon Glass bdesc = mmc_get_blk_desc(mmc); 2307c40fdca6SSimon Glass bdesc->lun = 0; 2308c40fdca6SSimon Glass bdesc->hwpart = 0; 2309c40fdca6SSimon Glass bdesc->type = 0; 2310c40fdca6SSimon Glass bdesc->blksz = mmc->read_bl_len; 2311c40fdca6SSimon Glass bdesc->log2blksz = LOG2(bdesc->blksz); 2312c40fdca6SSimon Glass bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len); 2313fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \ 2314fc011f64SSjoerd Simons (defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \ 2315fc011f64SSjoerd Simons !defined(CONFIG_USE_TINY_PRINTF)) 2316c40fdca6SSimon Glass sprintf(bdesc->vendor, "Man %06x Snr %04x%04x", 2317babce5f6STaylor Hutt mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), 2318babce5f6STaylor Hutt (mmc->cid[3] >> 16) & 0xffff); 2319c40fdca6SSimon Glass sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff, 23200b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 2321babce5f6STaylor Hutt (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff, 2322babce5f6STaylor Hutt (mmc->cid[2] >> 24) & 0xff); 2323c40fdca6SSimon Glass sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf, 2324babce5f6STaylor Hutt (mmc->cid[2] >> 16) & 0xf); 232556196826SPaul Burton #else 2326c40fdca6SSimon Glass bdesc->vendor[0] = 0; 2327c40fdca6SSimon Glass bdesc->product[0] = 0; 2328c40fdca6SSimon Glass bdesc->revision[0] = 0; 232956196826SPaul Burton #endif 2330122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT) 2331c40fdca6SSimon Glass part_init(bdesc); 2332122efd43SMikhail Kshevetskiy #endif 2333272cc70bSAndy Fleming 2334272cc70bSAndy Fleming return 0; 2335272cc70bSAndy Fleming } 2336272cc70bSAndy Fleming 2337fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc) 2338272cc70bSAndy Fleming { 2339272cc70bSAndy Fleming struct mmc_cmd cmd; 2340272cc70bSAndy Fleming int err; 2341272cc70bSAndy Fleming 2342272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND; 2343272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ 234493bfd616SPantelis Antoniou cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa; 2345272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7; 2346272cc70bSAndy Fleming 2347272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2348272cc70bSAndy Fleming 2349272cc70bSAndy Fleming if (err) 2350272cc70bSAndy Fleming return err; 2351272cc70bSAndy Fleming 2352998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa) 2353915ffa52SJaehoon Chung return -EOPNOTSUPP; 2354272cc70bSAndy Fleming else 2355272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 2356272cc70bSAndy Fleming 2357272cc70bSAndy Fleming return 0; 2358272cc70bSAndy Fleming } 2359272cc70bSAndy Fleming 2360c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 236195de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */ 236295de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void) 236395de9ab2SPaul Kocialkowski { 236495de9ab2SPaul Kocialkowski } 236505cbeb7cSSimon Glass #endif 236695de9ab2SPaul Kocialkowski 23672051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc) 23682051aefeSPeng Fan { 2369c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 237006ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR) 23712051aefeSPeng Fan int ret; 23722051aefeSPeng Fan 23732051aefeSPeng Fan ret = device_get_supply_regulator(mmc->dev, "vmmc-supply", 237406ec045fSJean-Jacques Hiblot &mmc->vmmc_supply); 237506ec045fSJean-Jacques Hiblot if (ret) 2376288db7c7SJaehoon Chung debug("%s: No vmmc supply\n", mmc->dev->name); 23772051aefeSPeng Fan 237806ec045fSJean-Jacques Hiblot ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply", 237906ec045fSJean-Jacques Hiblot &mmc->vqmmc_supply); 238006ec045fSJean-Jacques Hiblot if (ret) 238106ec045fSJean-Jacques Hiblot debug("%s: No vqmmc supply\n", mmc->dev->name); 23822051aefeSPeng Fan #endif 238305cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */ 238405cbeb7cSSimon Glass /* 238505cbeb7cSSimon Glass * Driver model should use a regulator, as above, rather than calling 238605cbeb7cSSimon Glass * out to board code. 238705cbeb7cSSimon Glass */ 238805cbeb7cSSimon Glass board_mmc_power_init(); 238905cbeb7cSSimon Glass #endif 23902051aefeSPeng Fan return 0; 23912051aefeSPeng Fan } 23922051aefeSPeng Fan 2393fb7c3bebSKishon Vijay Abraham I /* 2394fb7c3bebSKishon Vijay Abraham I * put the host in the initial state: 2395fb7c3bebSKishon Vijay Abraham I * - turn on Vdd (card power supply) 2396fb7c3bebSKishon Vijay Abraham I * - configure the bus width and clock to minimal values 2397fb7c3bebSKishon Vijay Abraham I */ 2398fb7c3bebSKishon Vijay Abraham I static void mmc_set_initial_state(struct mmc *mmc) 2399fb7c3bebSKishon Vijay Abraham I { 2400fb7c3bebSKishon Vijay Abraham I int err; 2401fb7c3bebSKishon Vijay Abraham I 2402fb7c3bebSKishon Vijay Abraham I /* First try to set 3.3V. If it fails set to 1.8V */ 2403fb7c3bebSKishon Vijay Abraham I err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_330); 2404fb7c3bebSKishon Vijay Abraham I if (err != 0) 2405fb7c3bebSKishon Vijay Abraham I err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_180); 2406fb7c3bebSKishon Vijay Abraham I if (err != 0) 2407d8e3d420SJean-Jacques Hiblot pr_warn("mmc: failed to set signal voltage\n"); 2408fb7c3bebSKishon Vijay Abraham I 2409fb7c3bebSKishon Vijay Abraham I mmc_select_mode(mmc, MMC_LEGACY); 2410fb7c3bebSKishon Vijay Abraham I mmc_set_bus_width(mmc, 1); 241135f67820SKishon Vijay Abraham I mmc_set_clock(mmc, 0, false); 2412fb7c3bebSKishon Vijay Abraham I } 2413fb7c3bebSKishon Vijay Abraham I 2414fb7c3bebSKishon Vijay Abraham I static int mmc_power_on(struct mmc *mmc) 2415fb7c3bebSKishon Vijay Abraham I { 2416fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR) 2417fb7c3bebSKishon Vijay Abraham I if (mmc->vmmc_supply) { 2418fb7c3bebSKishon Vijay Abraham I int ret = regulator_set_enable(mmc->vmmc_supply, true); 2419fb7c3bebSKishon Vijay Abraham I 2420fb7c3bebSKishon Vijay Abraham I if (ret) { 2421fb7c3bebSKishon Vijay Abraham I puts("Error enabling VMMC supply\n"); 2422fb7c3bebSKishon Vijay Abraham I return ret; 2423fb7c3bebSKishon Vijay Abraham I } 2424fb7c3bebSKishon Vijay Abraham I } 2425fb7c3bebSKishon Vijay Abraham I #endif 2426fb7c3bebSKishon Vijay Abraham I return 0; 2427fb7c3bebSKishon Vijay Abraham I } 2428fb7c3bebSKishon Vijay Abraham I 2429fb7c3bebSKishon Vijay Abraham I static int mmc_power_off(struct mmc *mmc) 2430fb7c3bebSKishon Vijay Abraham I { 24312e7410d7SKishon Vijay Abraham I mmc_set_clock(mmc, 1, true); 2432fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR) 2433fb7c3bebSKishon Vijay Abraham I if (mmc->vmmc_supply) { 2434fb7c3bebSKishon Vijay Abraham I int ret = regulator_set_enable(mmc->vmmc_supply, false); 2435fb7c3bebSKishon Vijay Abraham I 2436fb7c3bebSKishon Vijay Abraham I if (ret) { 2437c10b85d6SJean-Jacques Hiblot debug("Error disabling VMMC supply\n"); 2438fb7c3bebSKishon Vijay Abraham I return ret; 2439fb7c3bebSKishon Vijay Abraham I } 2440fb7c3bebSKishon Vijay Abraham I } 2441fb7c3bebSKishon Vijay Abraham I #endif 2442fb7c3bebSKishon Vijay Abraham I return 0; 2443fb7c3bebSKishon Vijay Abraham I } 2444fb7c3bebSKishon Vijay Abraham I 2445fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc) 2446fb7c3bebSKishon Vijay Abraham I { 2447fb7c3bebSKishon Vijay Abraham I int ret; 2448fb7c3bebSKishon Vijay Abraham I 2449fb7c3bebSKishon Vijay Abraham I ret = mmc_power_off(mmc); 2450fb7c3bebSKishon Vijay Abraham I if (ret) 2451fb7c3bebSKishon Vijay Abraham I return ret; 2452fb7c3bebSKishon Vijay Abraham I /* 2453fb7c3bebSKishon Vijay Abraham I * SD spec recommends at least 1ms of delay. Let's wait for 2ms 2454fb7c3bebSKishon Vijay Abraham I * to be on the safer side. 2455fb7c3bebSKishon Vijay Abraham I */ 2456fb7c3bebSKishon Vijay Abraham I udelay(2000); 2457fb7c3bebSKishon Vijay Abraham I return mmc_power_on(mmc); 2458fb7c3bebSKishon Vijay Abraham I } 2459fb7c3bebSKishon Vijay Abraham I 2460e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc) 2461272cc70bSAndy Fleming { 24628ca51e51SSimon Glass bool no_card; 2463c10b85d6SJean-Jacques Hiblot bool uhs_en = supports_uhs(mmc->cfg->host_caps); 2464afd5932bSMacpaul Lin int err; 2465272cc70bSAndy Fleming 24661da8eb59SJean-Jacques Hiblot /* 24671da8eb59SJean-Jacques Hiblot * all hosts are capable of 1 bit bus-width and able to use the legacy 24681da8eb59SJean-Jacques Hiblot * timings. 24691da8eb59SJean-Jacques Hiblot */ 24701da8eb59SJean-Jacques Hiblot mmc->host_caps = mmc->cfg->host_caps | MMC_CAP(SD_LEGACY) | 24711da8eb59SJean-Jacques Hiblot MMC_CAP(MMC_LEGACY) | MMC_MODE_1BIT; 247204a2ea24SJean-Jacques Hiblot 2473ab769f22SPantelis Antoniou /* we pretend there's no card when init is NULL */ 24748ca51e51SSimon Glass no_card = mmc_getcd(mmc) == 0; 2475e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 24768ca51e51SSimon Glass no_card = no_card || (mmc->cfg->ops->init == NULL); 24778ca51e51SSimon Glass #endif 24788ca51e51SSimon Glass if (no_card) { 247948972d90SThierry Reding mmc->has_init = 0; 248056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 248148972d90SThierry Reding printf("MMC: no card present\n"); 248256196826SPaul Burton #endif 2483915ffa52SJaehoon Chung return -ENOMEDIUM; 248448972d90SThierry Reding } 248548972d90SThierry Reding 2486bc897b1dSLei Wen if (mmc->has_init) 2487bc897b1dSLei Wen return 0; 2488bc897b1dSLei Wen 24895a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 24905a8dbdc6SYangbo Lu mmc_adapter_card_type_ident(); 24915a8dbdc6SYangbo Lu #endif 24922051aefeSPeng Fan err = mmc_power_init(mmc); 24932051aefeSPeng Fan if (err) 24942051aefeSPeng Fan return err; 249595de9ab2SPaul Kocialkowski 249683dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS 249783dc4227SKishon Vijay Abraham I mmc->quirks = MMC_QUIRK_RETRY_SET_BLOCKLEN | 249883dc4227SKishon Vijay Abraham I MMC_QUIRK_RETRY_SEND_CID; 249983dc4227SKishon Vijay Abraham I #endif 250083dc4227SKishon Vijay Abraham I 250104a2ea24SJean-Jacques Hiblot err = mmc_power_cycle(mmc); 250204a2ea24SJean-Jacques Hiblot if (err) { 250304a2ea24SJean-Jacques Hiblot /* 250404a2ea24SJean-Jacques Hiblot * if power cycling is not supported, we should not try 250504a2ea24SJean-Jacques Hiblot * to use the UHS modes, because we wouldn't be able to 250604a2ea24SJean-Jacques Hiblot * recover from an error during the UHS initialization. 250704a2ea24SJean-Jacques Hiblot */ 250804a2ea24SJean-Jacques Hiblot debug("Unable to do a full power cycle. Disabling the UHS modes for safety\n"); 250904a2ea24SJean-Jacques Hiblot uhs_en = false; 251004a2ea24SJean-Jacques Hiblot mmc->host_caps &= ~UHS_CAPS; 2511fb7c3bebSKishon Vijay Abraham I err = mmc_power_on(mmc); 251204a2ea24SJean-Jacques Hiblot } 2513fb7c3bebSKishon Vijay Abraham I if (err) 2514fb7c3bebSKishon Vijay Abraham I return err; 2515fb7c3bebSKishon Vijay Abraham I 2516e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 25178ca51e51SSimon Glass /* The device has already been probed ready for use */ 25188ca51e51SSimon Glass #else 2519ab769f22SPantelis Antoniou /* made sure it's not NULL earlier */ 252093bfd616SPantelis Antoniou err = mmc->cfg->ops->init(mmc); 2521272cc70bSAndy Fleming if (err) 2522272cc70bSAndy Fleming return err; 25238ca51e51SSimon Glass #endif 2524786e8f81SAndrew Gabbasov mmc->ddr_mode = 0; 2525aff5d3c8SKishon Vijay Abraham I 2526c10b85d6SJean-Jacques Hiblot retry: 2527fb7c3bebSKishon Vijay Abraham I mmc_set_initial_state(mmc); 2528318a7a57SJean-Jacques Hiblot mmc_send_init_stream(mmc); 2529318a7a57SJean-Jacques Hiblot 2530272cc70bSAndy Fleming /* Reset the Card */ 2531272cc70bSAndy Fleming err = mmc_go_idle(mmc); 2532272cc70bSAndy Fleming 2533272cc70bSAndy Fleming if (err) 2534272cc70bSAndy Fleming return err; 2535272cc70bSAndy Fleming 2536bc897b1dSLei Wen /* The internal partition reset to user partition(0) at every CMD0*/ 2537c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->hwpart = 0; 2538bc897b1dSLei Wen 2539272cc70bSAndy Fleming /* Test for SD version 2 */ 2540272cc70bSAndy Fleming err = mmc_send_if_cond(mmc); 2541272cc70bSAndy Fleming 2542272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */ 2543c10b85d6SJean-Jacques Hiblot err = sd_send_op_cond(mmc, uhs_en); 2544c10b85d6SJean-Jacques Hiblot if (err && uhs_en) { 2545c10b85d6SJean-Jacques Hiblot uhs_en = false; 2546c10b85d6SJean-Jacques Hiblot mmc_power_cycle(mmc); 2547c10b85d6SJean-Jacques Hiblot goto retry; 2548c10b85d6SJean-Jacques Hiblot } 2549272cc70bSAndy Fleming 2550272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */ 2551915ffa52SJaehoon Chung if (err == -ETIMEDOUT) { 2552272cc70bSAndy Fleming err = mmc_send_op_cond(mmc); 2553272cc70bSAndy Fleming 2554bd47c135SAndrew Gabbasov if (err) { 255556196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2556d8e3d420SJean-Jacques Hiblot pr_err("Card did not respond to voltage select!\n"); 255756196826SPaul Burton #endif 2558915ffa52SJaehoon Chung return -EOPNOTSUPP; 2559272cc70bSAndy Fleming } 2560272cc70bSAndy Fleming } 2561272cc70bSAndy Fleming 2562bd47c135SAndrew Gabbasov if (!err) 2563e9550449SChe-Liang Chiou mmc->init_in_progress = 1; 2564e9550449SChe-Liang Chiou 2565e9550449SChe-Liang Chiou return err; 2566e9550449SChe-Liang Chiou } 2567e9550449SChe-Liang Chiou 2568e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc) 2569e9550449SChe-Liang Chiou { 2570e9550449SChe-Liang Chiou int err = 0; 2571e9550449SChe-Liang Chiou 2572bd47c135SAndrew Gabbasov mmc->init_in_progress = 0; 2573e9550449SChe-Liang Chiou if (mmc->op_cond_pending) 2574e9550449SChe-Liang Chiou err = mmc_complete_op_cond(mmc); 2575e9550449SChe-Liang Chiou 2576e9550449SChe-Liang Chiou if (!err) 2577bc897b1dSLei Wen err = mmc_startup(mmc); 2578bc897b1dSLei Wen if (err) 2579bc897b1dSLei Wen mmc->has_init = 0; 2580bc897b1dSLei Wen else 2581bc897b1dSLei Wen mmc->has_init = 1; 2582e9550449SChe-Liang Chiou return err; 2583e9550449SChe-Liang Chiou } 2584e9550449SChe-Liang Chiou 2585e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc) 2586e9550449SChe-Liang Chiou { 2587bd47c135SAndrew Gabbasov int err = 0; 2588ce9eca94SMarek Vasut __maybe_unused unsigned start; 2589c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 259033fb211dSSimon Glass struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev); 2591e9550449SChe-Liang Chiou 259233fb211dSSimon Glass upriv->mmc = mmc; 259333fb211dSSimon Glass #endif 2594e9550449SChe-Liang Chiou if (mmc->has_init) 2595e9550449SChe-Liang Chiou return 0; 2596d803fea5SMateusz Zalega 2597d803fea5SMateusz Zalega start = get_timer(0); 2598d803fea5SMateusz Zalega 2599e9550449SChe-Liang Chiou if (!mmc->init_in_progress) 2600e9550449SChe-Liang Chiou err = mmc_start_init(mmc); 2601e9550449SChe-Liang Chiou 2602bd47c135SAndrew Gabbasov if (!err) 2603e9550449SChe-Liang Chiou err = mmc_complete_init(mmc); 2604919b4858SJagan Teki if (err) 2605919b4858SJagan Teki printf("%s: %d, time %lu\n", __func__, err, get_timer(start)); 2606919b4858SJagan Teki 2607bc897b1dSLei Wen return err; 2608272cc70bSAndy Fleming } 2609272cc70bSAndy Fleming 2610ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val) 2611ab71188cSMarkus Niebel { 2612ab71188cSMarkus Niebel mmc->dsr = val; 2613ab71188cSMarkus Niebel return 0; 2614ab71188cSMarkus Niebel } 2615ab71188cSMarkus Niebel 2616cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */ 2617cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis) 2618272cc70bSAndy Fleming { 2619272cc70bSAndy Fleming return -1; 2620272cc70bSAndy Fleming } 2621272cc70bSAndy Fleming 2622cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */ 2623cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis) 2624cee9ab7cSJeroen Hofstee { 2625cee9ab7cSJeroen Hofstee return -1; 2626cee9ab7cSJeroen Hofstee } 2627272cc70bSAndy Fleming 2628e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit) 2629e9550449SChe-Liang Chiou { 2630e9550449SChe-Liang Chiou mmc->preinit = preinit; 2631e9550449SChe-Liang Chiou } 2632e9550449SChe-Liang Chiou 2633c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD) 26348e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 26358e3332e2SSjoerd Simons { 26368e3332e2SSjoerd Simons return 0; 26378e3332e2SSjoerd Simons } 2638c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC) 26398e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 26408e3332e2SSjoerd Simons { 26414a1db6d8SSimon Glass int ret, i; 26428e3332e2SSjoerd Simons struct uclass *uc; 26434a1db6d8SSimon Glass struct udevice *dev; 26448e3332e2SSjoerd Simons 26458e3332e2SSjoerd Simons ret = uclass_get(UCLASS_MMC, &uc); 26468e3332e2SSjoerd Simons if (ret) 26478e3332e2SSjoerd Simons return ret; 26488e3332e2SSjoerd Simons 26494a1db6d8SSimon Glass /* 26504a1db6d8SSimon Glass * Try to add them in sequence order. Really with driver model we 26514a1db6d8SSimon Glass * should allow holes, but the current MMC list does not allow that. 26524a1db6d8SSimon Glass * So if we request 0, 1, 3 we will get 0, 1, 2. 26534a1db6d8SSimon Glass */ 26544a1db6d8SSimon Glass for (i = 0; ; i++) { 26554a1db6d8SSimon Glass ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev); 26564a1db6d8SSimon Glass if (ret == -ENODEV) 26574a1db6d8SSimon Glass break; 26584a1db6d8SSimon Glass } 26594a1db6d8SSimon Glass uclass_foreach_dev(dev, uc) { 26604a1db6d8SSimon Glass ret = device_probe(dev); 26618e3332e2SSjoerd Simons if (ret) 2662d8e3d420SJean-Jacques Hiblot pr_err("%s - probe failed: %d\n", dev->name, ret); 26638e3332e2SSjoerd Simons } 26648e3332e2SSjoerd Simons 26658e3332e2SSjoerd Simons return 0; 26668e3332e2SSjoerd Simons } 26678e3332e2SSjoerd Simons #else 26688e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 26698e3332e2SSjoerd Simons { 26708e3332e2SSjoerd Simons if (board_mmc_init(bis) < 0) 26718e3332e2SSjoerd Simons cpu_mmc_init(bis); 26728e3332e2SSjoerd Simons 26738e3332e2SSjoerd Simons return 0; 26748e3332e2SSjoerd Simons } 26758e3332e2SSjoerd Simons #endif 2676e9550449SChe-Liang Chiou 2677272cc70bSAndy Fleming int mmc_initialize(bd_t *bis) 2678272cc70bSAndy Fleming { 26791b26bab1SDaniel Kochmański static int initialized = 0; 26808e3332e2SSjoerd Simons int ret; 26811b26bab1SDaniel Kochmański if (initialized) /* Avoid initializing mmc multiple times */ 26821b26bab1SDaniel Kochmański return 0; 26831b26bab1SDaniel Kochmański initialized = 1; 26841b26bab1SDaniel Kochmański 2685c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK) 2686b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY) 2687c40fdca6SSimon Glass mmc_list_init(); 2688c40fdca6SSimon Glass #endif 2689b5b838f1SMarek Vasut #endif 26908e3332e2SSjoerd Simons ret = mmc_probe(bis); 26918e3332e2SSjoerd Simons if (ret) 26928e3332e2SSjoerd Simons return ret; 2693272cc70bSAndy Fleming 2694bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD 2695272cc70bSAndy Fleming print_mmc_devices(','); 2696bb0dc108SYing Zhang #endif 2697272cc70bSAndy Fleming 2698c40fdca6SSimon Glass mmc_do_preinit(); 2699272cc70bSAndy Fleming return 0; 2700272cc70bSAndy Fleming } 2701cd3d4880STomas Melin 2702cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE 2703cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc) 2704cd3d4880STomas Melin { 2705cd3d4880STomas Melin int err; 2706cd3d4880STomas Melin ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 2707cd3d4880STomas Melin 2708cd3d4880STomas Melin err = mmc_send_ext_csd(mmc, ext_csd); 2709cd3d4880STomas Melin if (err) { 2710cd3d4880STomas Melin puts("Could not get ext_csd register values\n"); 2711cd3d4880STomas Melin return err; 2712cd3d4880STomas Melin } 2713cd3d4880STomas Melin 2714cd3d4880STomas Melin if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) { 2715cd3d4880STomas Melin puts("Background operations not supported on device\n"); 2716cd3d4880STomas Melin return -EMEDIUMTYPE; 2717cd3d4880STomas Melin } 2718cd3d4880STomas Melin 2719cd3d4880STomas Melin if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) { 2720cd3d4880STomas Melin puts("Background operations already enabled\n"); 2721cd3d4880STomas Melin return 0; 2722cd3d4880STomas Melin } 2723cd3d4880STomas Melin 2724cd3d4880STomas Melin err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1); 2725cd3d4880STomas Melin if (err) { 2726cd3d4880STomas Melin puts("Failed to enable manual background operations\n"); 2727cd3d4880STomas Melin return err; 2728cd3d4880STomas Melin } 2729cd3d4880STomas Melin 2730cd3d4880STomas Melin puts("Enabled manual background operations\n"); 2731cd3d4880STomas Melin 2732cd3d4880STomas Melin return 0; 2733cd3d4880STomas Melin } 2734cd3d4880STomas Melin #endif 2735