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 25aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage); 26fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc); 2701298da3SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps); 28aff5d3c8SKishon Vijay Abraham I 29b5b838f1SMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY) 30b5b838f1SMarek Vasut static struct mmc mmc_static; 31b5b838f1SMarek Vasut struct mmc *find_mmc_device(int dev_num) 32b5b838f1SMarek Vasut { 33b5b838f1SMarek Vasut return &mmc_static; 34b5b838f1SMarek Vasut } 35b5b838f1SMarek Vasut 36b5b838f1SMarek Vasut void mmc_do_preinit(void) 37b5b838f1SMarek Vasut { 38b5b838f1SMarek Vasut struct mmc *m = &mmc_static; 39b5b838f1SMarek Vasut #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 40b5b838f1SMarek Vasut mmc_set_preinit(m, 1); 41b5b838f1SMarek Vasut #endif 42b5b838f1SMarek Vasut if (m->preinit) 43b5b838f1SMarek Vasut mmc_start_init(m); 44b5b838f1SMarek Vasut } 45b5b838f1SMarek Vasut 46b5b838f1SMarek Vasut struct blk_desc *mmc_get_blk_desc(struct mmc *mmc) 47b5b838f1SMarek Vasut { 48b5b838f1SMarek Vasut return &mmc->block_dev; 49b5b838f1SMarek Vasut } 50b5b838f1SMarek Vasut #endif 51b5b838f1SMarek Vasut 52e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 53c10b85d6SJean-Jacques Hiblot 54f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 55c10b85d6SJean-Jacques Hiblot static int mmc_wait_dat0(struct mmc *mmc, int state, int timeout) 56c10b85d6SJean-Jacques Hiblot { 57c10b85d6SJean-Jacques Hiblot return -ENOSYS; 58c10b85d6SJean-Jacques Hiblot } 59f99c2efeSJean-Jacques Hiblot #endif 60c10b85d6SJean-Jacques Hiblot 61750121c3SJeroen Hofstee __weak int board_mmc_getwp(struct mmc *mmc) 62d23d8d7eSNikita Kiryanov { 63d23d8d7eSNikita Kiryanov return -1; 64d23d8d7eSNikita Kiryanov } 65d23d8d7eSNikita Kiryanov 66d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc) 67d23d8d7eSNikita Kiryanov { 68d23d8d7eSNikita Kiryanov int wp; 69d23d8d7eSNikita Kiryanov 70d23d8d7eSNikita Kiryanov wp = board_mmc_getwp(mmc); 71d23d8d7eSNikita Kiryanov 72d4e1da4eSPeter Korsgaard if (wp < 0) { 7393bfd616SPantelis Antoniou if (mmc->cfg->ops->getwp) 7493bfd616SPantelis Antoniou wp = mmc->cfg->ops->getwp(mmc); 75d4e1da4eSPeter Korsgaard else 76d4e1da4eSPeter Korsgaard wp = 0; 77d4e1da4eSPeter Korsgaard } 78d23d8d7eSNikita Kiryanov 79d23d8d7eSNikita Kiryanov return wp; 80d23d8d7eSNikita Kiryanov } 81d23d8d7eSNikita Kiryanov 82cee9ab7cSJeroen Hofstee __weak int board_mmc_getcd(struct mmc *mmc) 83cee9ab7cSJeroen Hofstee { 8411fdade2SStefano Babic return -1; 8511fdade2SStefano Babic } 868ca51e51SSimon Glass #endif 8711fdade2SStefano Babic 888635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE 89c0c76ebaSSimon Glass void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd) 90c0c76ebaSSimon Glass { 91c0c76ebaSSimon Glass printf("CMD_SEND:%d\n", cmd->cmdidx); 92c0c76ebaSSimon Glass printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg); 93c0c76ebaSSimon Glass } 94c0c76ebaSSimon Glass 95c0c76ebaSSimon Glass void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret) 96c0c76ebaSSimon Glass { 975db2fe3aSRaffaele Recalcati int i; 985db2fe3aSRaffaele Recalcati u8 *ptr; 995db2fe3aSRaffaele Recalcati 1007863ce58SBin Meng if (ret) { 1017863ce58SBin Meng printf("\t\tRET\t\t\t %d\n", ret); 1027863ce58SBin Meng } else { 1035db2fe3aSRaffaele Recalcati switch (cmd->resp_type) { 1045db2fe3aSRaffaele Recalcati case MMC_RSP_NONE: 1055db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_NONE\n"); 1065db2fe3aSRaffaele Recalcati break; 1075db2fe3aSRaffaele Recalcati case MMC_RSP_R1: 1085db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n", 1095db2fe3aSRaffaele Recalcati cmd->response[0]); 1105db2fe3aSRaffaele Recalcati break; 1115db2fe3aSRaffaele Recalcati case MMC_RSP_R1b: 1125db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n", 1135db2fe3aSRaffaele Recalcati cmd->response[0]); 1145db2fe3aSRaffaele Recalcati break; 1155db2fe3aSRaffaele Recalcati case MMC_RSP_R2: 1165db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R2\t\t 0x%08X \n", 1175db2fe3aSRaffaele Recalcati cmd->response[0]); 1185db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1195db2fe3aSRaffaele Recalcati cmd->response[1]); 1205db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1215db2fe3aSRaffaele Recalcati cmd->response[2]); 1225db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1235db2fe3aSRaffaele Recalcati cmd->response[3]); 1245db2fe3aSRaffaele Recalcati printf("\n"); 1255db2fe3aSRaffaele Recalcati printf("\t\t\t\t\tDUMPING DATA\n"); 1265db2fe3aSRaffaele Recalcati for (i = 0; i < 4; i++) { 1275db2fe3aSRaffaele Recalcati int j; 1285db2fe3aSRaffaele Recalcati printf("\t\t\t\t\t%03d - ", i*4); 129146bec79SDirk Behme ptr = (u8 *)&cmd->response[i]; 1305db2fe3aSRaffaele Recalcati ptr += 3; 1315db2fe3aSRaffaele Recalcati for (j = 0; j < 4; j++) 1325db2fe3aSRaffaele Recalcati printf("%02X ", *ptr--); 1335db2fe3aSRaffaele Recalcati printf("\n"); 1345db2fe3aSRaffaele Recalcati } 1355db2fe3aSRaffaele Recalcati break; 1365db2fe3aSRaffaele Recalcati case MMC_RSP_R3: 1375db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n", 1385db2fe3aSRaffaele Recalcati cmd->response[0]); 1395db2fe3aSRaffaele Recalcati break; 1405db2fe3aSRaffaele Recalcati default: 1415db2fe3aSRaffaele Recalcati printf("\t\tERROR MMC rsp not supported\n"); 1425db2fe3aSRaffaele Recalcati break; 1435db2fe3aSRaffaele Recalcati } 1447863ce58SBin Meng } 145c0c76ebaSSimon Glass } 146c0c76ebaSSimon Glass 147c0c76ebaSSimon Glass void mmc_trace_state(struct mmc *mmc, struct mmc_cmd *cmd) 148c0c76ebaSSimon Glass { 149c0c76ebaSSimon Glass int status; 150c0c76ebaSSimon Glass 151c0c76ebaSSimon Glass status = (cmd->response[0] & MMC_STATUS_CURR_STATE) >> 9; 152c0c76ebaSSimon Glass printf("CURR STATE:%d\n", status); 153c0c76ebaSSimon Glass } 1545db2fe3aSRaffaele Recalcati #endif 155c0c76ebaSSimon Glass 15635f9e196SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG) 15735f9e196SJean-Jacques Hiblot const char *mmc_mode_name(enum bus_mode mode) 15835f9e196SJean-Jacques Hiblot { 15935f9e196SJean-Jacques Hiblot static const char *const names[] = { 16035f9e196SJean-Jacques Hiblot [MMC_LEGACY] = "MMC legacy", 16135f9e196SJean-Jacques Hiblot [SD_LEGACY] = "SD Legacy", 16235f9e196SJean-Jacques Hiblot [MMC_HS] = "MMC High Speed (26MHz)", 16335f9e196SJean-Jacques Hiblot [SD_HS] = "SD High Speed (50MHz)", 16435f9e196SJean-Jacques Hiblot [UHS_SDR12] = "UHS SDR12 (25MHz)", 16535f9e196SJean-Jacques Hiblot [UHS_SDR25] = "UHS SDR25 (50MHz)", 16635f9e196SJean-Jacques Hiblot [UHS_SDR50] = "UHS SDR50 (100MHz)", 16735f9e196SJean-Jacques Hiblot [UHS_SDR104] = "UHS SDR104 (208MHz)", 16835f9e196SJean-Jacques Hiblot [UHS_DDR50] = "UHS DDR50 (50MHz)", 16935f9e196SJean-Jacques Hiblot [MMC_HS_52] = "MMC High Speed (52MHz)", 17035f9e196SJean-Jacques Hiblot [MMC_DDR_52] = "MMC DDR52 (52MHz)", 17135f9e196SJean-Jacques Hiblot [MMC_HS_200] = "HS200 (200MHz)", 17235f9e196SJean-Jacques Hiblot }; 17335f9e196SJean-Jacques Hiblot 17435f9e196SJean-Jacques Hiblot if (mode >= MMC_MODES_END) 17535f9e196SJean-Jacques Hiblot return "Unknown mode"; 17635f9e196SJean-Jacques Hiblot else 17735f9e196SJean-Jacques Hiblot return names[mode]; 17835f9e196SJean-Jacques Hiblot } 17935f9e196SJean-Jacques Hiblot #endif 18035f9e196SJean-Jacques Hiblot 18105038576SJean-Jacques Hiblot static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode) 18205038576SJean-Jacques Hiblot { 18305038576SJean-Jacques Hiblot static const int freqs[] = { 18405038576SJean-Jacques Hiblot [SD_LEGACY] = 25000000, 18505038576SJean-Jacques Hiblot [MMC_HS] = 26000000, 18605038576SJean-Jacques Hiblot [SD_HS] = 50000000, 187f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 18805038576SJean-Jacques Hiblot [UHS_SDR12] = 25000000, 18905038576SJean-Jacques Hiblot [UHS_SDR25] = 50000000, 19005038576SJean-Jacques Hiblot [UHS_SDR50] = 100000000, 19105038576SJean-Jacques Hiblot [UHS_DDR50] = 50000000, 192f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 193f99c2efeSJean-Jacques Hiblot [UHS_SDR104] = 208000000, 194f99c2efeSJean-Jacques Hiblot #endif 195f99c2efeSJean-Jacques Hiblot #endif 19605038576SJean-Jacques Hiblot [MMC_HS_52] = 52000000, 19705038576SJean-Jacques Hiblot [MMC_DDR_52] = 52000000, 198f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) 19905038576SJean-Jacques Hiblot [MMC_HS_200] = 200000000, 200f99c2efeSJean-Jacques Hiblot #endif 20105038576SJean-Jacques Hiblot }; 20205038576SJean-Jacques Hiblot 20305038576SJean-Jacques Hiblot if (mode == MMC_LEGACY) 20405038576SJean-Jacques Hiblot return mmc->legacy_speed; 20505038576SJean-Jacques Hiblot else if (mode >= MMC_MODES_END) 20605038576SJean-Jacques Hiblot return 0; 20705038576SJean-Jacques Hiblot else 20805038576SJean-Jacques Hiblot return freqs[mode]; 20905038576SJean-Jacques Hiblot } 21005038576SJean-Jacques Hiblot 21135f9e196SJean-Jacques Hiblot static int mmc_select_mode(struct mmc *mmc, enum bus_mode mode) 21235f9e196SJean-Jacques Hiblot { 21335f9e196SJean-Jacques Hiblot mmc->selected_mode = mode; 21405038576SJean-Jacques Hiblot mmc->tran_speed = mmc_mode2freq(mmc, mode); 2153862b854SJean-Jacques Hiblot mmc->ddr_mode = mmc_is_mode_ddr(mode); 216*d4d64889SMasahiro Yamada pr_debug("selecting mode %s (freq : %d MHz)\n", mmc_mode_name(mode), 21735f9e196SJean-Jacques Hiblot mmc->tran_speed / 1000000); 21835f9e196SJean-Jacques Hiblot return 0; 21935f9e196SJean-Jacques Hiblot } 22035f9e196SJean-Jacques Hiblot 221e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 222c0c76ebaSSimon Glass int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) 223c0c76ebaSSimon Glass { 224c0c76ebaSSimon Glass int ret; 225c0c76ebaSSimon Glass 226c0c76ebaSSimon Glass mmmc_trace_before_send(mmc, cmd); 227c0c76ebaSSimon Glass ret = mmc->cfg->ops->send_cmd(mmc, cmd, data); 228c0c76ebaSSimon Glass mmmc_trace_after_send(mmc, cmd, ret); 229c0c76ebaSSimon Glass 2308635ff9eSMarek Vasut return ret; 231272cc70bSAndy Fleming } 2328ca51e51SSimon Glass #endif 233272cc70bSAndy Fleming 234da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout) 2355d4fc8d9SRaffaele Recalcati { 2365d4fc8d9SRaffaele Recalcati struct mmc_cmd cmd; 237d617c426SJan Kloetzke int err, retries = 5; 2385d4fc8d9SRaffaele Recalcati 2395d4fc8d9SRaffaele Recalcati cmd.cmdidx = MMC_CMD_SEND_STATUS; 2405d4fc8d9SRaffaele Recalcati cmd.resp_type = MMC_RSP_R1; 241aaf3d41aSMarek Vasut if (!mmc_host_is_spi(mmc)) 242aaf3d41aSMarek Vasut cmd.cmdarg = mmc->rca << 16; 2435d4fc8d9SRaffaele Recalcati 2441677eef4SAndrew Gabbasov while (1) { 2455d4fc8d9SRaffaele Recalcati err = mmc_send_cmd(mmc, &cmd, NULL); 246d617c426SJan Kloetzke if (!err) { 247d617c426SJan Kloetzke if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) && 248d617c426SJan Kloetzke (cmd.response[0] & MMC_STATUS_CURR_STATE) != 249d617c426SJan Kloetzke MMC_STATE_PRG) 2505d4fc8d9SRaffaele Recalcati break; 251d0c221feSJean-Jacques Hiblot 252d0c221feSJean-Jacques Hiblot if (cmd.response[0] & MMC_STATUS_MASK) { 25356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 254d8e3d420SJean-Jacques Hiblot pr_err("Status Error: 0x%08X\n", 255d617c426SJan Kloetzke cmd.response[0]); 25656196826SPaul Burton #endif 257915ffa52SJaehoon Chung return -ECOMM; 258d617c426SJan Kloetzke } 259d617c426SJan Kloetzke } else if (--retries < 0) 260d617c426SJan Kloetzke return err; 2615d4fc8d9SRaffaele Recalcati 2621677eef4SAndrew Gabbasov if (timeout-- <= 0) 2631677eef4SAndrew Gabbasov break; 2645d4fc8d9SRaffaele Recalcati 2651677eef4SAndrew Gabbasov udelay(1000); 2661677eef4SAndrew Gabbasov } 2675d4fc8d9SRaffaele Recalcati 268c0c76ebaSSimon Glass mmc_trace_state(mmc, &cmd); 2695b0c942fSJongman Heo if (timeout <= 0) { 27056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 271d8e3d420SJean-Jacques Hiblot pr_err("Timeout waiting card ready\n"); 27256196826SPaul Burton #endif 273915ffa52SJaehoon Chung return -ETIMEDOUT; 2745d4fc8d9SRaffaele Recalcati } 2755d4fc8d9SRaffaele Recalcati 2765d4fc8d9SRaffaele Recalcati return 0; 2775d4fc8d9SRaffaele Recalcati } 2785d4fc8d9SRaffaele Recalcati 279da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len) 280272cc70bSAndy Fleming { 281272cc70bSAndy Fleming struct mmc_cmd cmd; 28283dc4227SKishon Vijay Abraham I int err; 283272cc70bSAndy Fleming 284786e8f81SAndrew Gabbasov if (mmc->ddr_mode) 285d22e3d46SJaehoon Chung return 0; 286d22e3d46SJaehoon Chung 287272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SET_BLOCKLEN; 288272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 289272cc70bSAndy Fleming cmd.cmdarg = len; 290272cc70bSAndy Fleming 29183dc4227SKishon Vijay Abraham I err = mmc_send_cmd(mmc, &cmd, NULL); 29283dc4227SKishon Vijay Abraham I 29383dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS 29483dc4227SKishon Vijay Abraham I if (err && (mmc->quirks & MMC_QUIRK_RETRY_SET_BLOCKLEN)) { 29583dc4227SKishon Vijay Abraham I int retries = 4; 29683dc4227SKishon Vijay Abraham I /* 29783dc4227SKishon Vijay Abraham I * It has been seen that SET_BLOCKLEN may fail on the first 29883dc4227SKishon Vijay Abraham I * attempt, let's try a few more time 29983dc4227SKishon Vijay Abraham I */ 30083dc4227SKishon Vijay Abraham I do { 30183dc4227SKishon Vijay Abraham I err = mmc_send_cmd(mmc, &cmd, NULL); 30283dc4227SKishon Vijay Abraham I if (!err) 30383dc4227SKishon Vijay Abraham I break; 30483dc4227SKishon Vijay Abraham I } while (retries--); 30583dc4227SKishon Vijay Abraham I } 30683dc4227SKishon Vijay Abraham I #endif 30783dc4227SKishon Vijay Abraham I 30883dc4227SKishon Vijay Abraham I return err; 309272cc70bSAndy Fleming } 310272cc70bSAndy Fleming 311f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 3129815e3baSJean-Jacques Hiblot static const u8 tuning_blk_pattern_4bit[] = { 3139815e3baSJean-Jacques Hiblot 0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc, 3149815e3baSJean-Jacques Hiblot 0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef, 3159815e3baSJean-Jacques Hiblot 0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb, 3169815e3baSJean-Jacques Hiblot 0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef, 3179815e3baSJean-Jacques Hiblot 0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c, 3189815e3baSJean-Jacques Hiblot 0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee, 3199815e3baSJean-Jacques Hiblot 0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff, 3209815e3baSJean-Jacques Hiblot 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde, 3219815e3baSJean-Jacques Hiblot }; 3229815e3baSJean-Jacques Hiblot 3239815e3baSJean-Jacques Hiblot static const u8 tuning_blk_pattern_8bit[] = { 3249815e3baSJean-Jacques Hiblot 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 3259815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc, 3269815e3baSJean-Jacques Hiblot 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff, 3279815e3baSJean-Jacques Hiblot 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff, 3289815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd, 3299815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, 3309815e3baSJean-Jacques Hiblot 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff, 3319815e3baSJean-Jacques Hiblot 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff, 3329815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 3339815e3baSJean-Jacques Hiblot 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 3349815e3baSJean-Jacques Hiblot 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 3359815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 3369815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 3379815e3baSJean-Jacques Hiblot 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 3389815e3baSJean-Jacques Hiblot 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 3399815e3baSJean-Jacques Hiblot 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 3409815e3baSJean-Jacques Hiblot }; 3419815e3baSJean-Jacques Hiblot 3429815e3baSJean-Jacques Hiblot int mmc_send_tuning(struct mmc *mmc, u32 opcode, int *cmd_error) 3439815e3baSJean-Jacques Hiblot { 3449815e3baSJean-Jacques Hiblot struct mmc_cmd cmd; 3459815e3baSJean-Jacques Hiblot struct mmc_data data; 3469815e3baSJean-Jacques Hiblot const u8 *tuning_block_pattern; 3479815e3baSJean-Jacques Hiblot int size, err; 3489815e3baSJean-Jacques Hiblot 3499815e3baSJean-Jacques Hiblot if (mmc->bus_width == 8) { 3509815e3baSJean-Jacques Hiblot tuning_block_pattern = tuning_blk_pattern_8bit; 3519815e3baSJean-Jacques Hiblot size = sizeof(tuning_blk_pattern_8bit); 3529815e3baSJean-Jacques Hiblot } else if (mmc->bus_width == 4) { 3539815e3baSJean-Jacques Hiblot tuning_block_pattern = tuning_blk_pattern_4bit; 3549815e3baSJean-Jacques Hiblot size = sizeof(tuning_blk_pattern_4bit); 3559815e3baSJean-Jacques Hiblot } else { 3569815e3baSJean-Jacques Hiblot return -EINVAL; 3579815e3baSJean-Jacques Hiblot } 3589815e3baSJean-Jacques Hiblot 3599815e3baSJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, data_buf, size); 3609815e3baSJean-Jacques Hiblot 3619815e3baSJean-Jacques Hiblot cmd.cmdidx = opcode; 3629815e3baSJean-Jacques Hiblot cmd.cmdarg = 0; 3639815e3baSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 3649815e3baSJean-Jacques Hiblot 3659815e3baSJean-Jacques Hiblot data.dest = (void *)data_buf; 3669815e3baSJean-Jacques Hiblot data.blocks = 1; 3679815e3baSJean-Jacques Hiblot data.blocksize = size; 3689815e3baSJean-Jacques Hiblot data.flags = MMC_DATA_READ; 3699815e3baSJean-Jacques Hiblot 3709815e3baSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, &data); 3719815e3baSJean-Jacques Hiblot if (err) 3729815e3baSJean-Jacques Hiblot return err; 3739815e3baSJean-Jacques Hiblot 3749815e3baSJean-Jacques Hiblot if (memcmp(data_buf, tuning_block_pattern, size)) 3759815e3baSJean-Jacques Hiblot return -EIO; 3769815e3baSJean-Jacques Hiblot 3779815e3baSJean-Jacques Hiblot return 0; 3789815e3baSJean-Jacques Hiblot } 379f99c2efeSJean-Jacques Hiblot #endif 3809815e3baSJean-Jacques Hiblot 381ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start, 382fdbb873eSKim Phillips lbaint_t blkcnt) 383272cc70bSAndy Fleming { 384272cc70bSAndy Fleming struct mmc_cmd cmd; 385272cc70bSAndy Fleming struct mmc_data data; 386272cc70bSAndy Fleming 3874a1a06bcSAlagu Sankar if (blkcnt > 1) 3884a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; 3894a1a06bcSAlagu Sankar else 390272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; 391272cc70bSAndy Fleming 392272cc70bSAndy Fleming if (mmc->high_capacity) 3934a1a06bcSAlagu Sankar cmd.cmdarg = start; 394272cc70bSAndy Fleming else 3954a1a06bcSAlagu Sankar cmd.cmdarg = start * mmc->read_bl_len; 396272cc70bSAndy Fleming 397272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 398272cc70bSAndy Fleming 399272cc70bSAndy Fleming data.dest = dst; 4004a1a06bcSAlagu Sankar data.blocks = blkcnt; 401272cc70bSAndy Fleming data.blocksize = mmc->read_bl_len; 402272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 403272cc70bSAndy Fleming 4044a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, &data)) 4054a1a06bcSAlagu Sankar return 0; 4064a1a06bcSAlagu Sankar 4074a1a06bcSAlagu Sankar if (blkcnt > 1) { 4084a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; 4094a1a06bcSAlagu Sankar cmd.cmdarg = 0; 4104a1a06bcSAlagu Sankar cmd.resp_type = MMC_RSP_R1b; 4114a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, NULL)) { 41256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 413d8e3d420SJean-Jacques Hiblot pr_err("mmc fail to send stop cmd\n"); 41456196826SPaul Burton #endif 4154a1a06bcSAlagu Sankar return 0; 4164a1a06bcSAlagu Sankar } 417272cc70bSAndy Fleming } 418272cc70bSAndy Fleming 4194a1a06bcSAlagu Sankar return blkcnt; 420272cc70bSAndy Fleming } 421272cc70bSAndy Fleming 422c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK) 4237dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst) 42433fb211dSSimon Glass #else 4257dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, 4267dba0b93SSimon Glass void *dst) 42733fb211dSSimon Glass #endif 428272cc70bSAndy Fleming { 429c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK) 43033fb211dSSimon Glass struct blk_desc *block_dev = dev_get_uclass_platdata(dev); 43133fb211dSSimon Glass #endif 432bcce53d0SSimon Glass int dev_num = block_dev->devnum; 433873cc1d7SStephen Warren int err; 4344a1a06bcSAlagu Sankar lbaint_t cur, blocks_todo = blkcnt; 435272cc70bSAndy Fleming 4364a1a06bcSAlagu Sankar if (blkcnt == 0) 4374a1a06bcSAlagu Sankar return 0; 4384a1a06bcSAlagu Sankar 4394a1a06bcSAlagu Sankar struct mmc *mmc = find_mmc_device(dev_num); 440272cc70bSAndy Fleming if (!mmc) 441272cc70bSAndy Fleming return 0; 442272cc70bSAndy Fleming 443b5b838f1SMarek Vasut if (CONFIG_IS_ENABLED(MMC_TINY)) 444b5b838f1SMarek Vasut err = mmc_switch_part(mmc, block_dev->hwpart); 445b5b838f1SMarek Vasut else 44669f45cd5SSimon Glass err = blk_dselect_hwpart(block_dev, block_dev->hwpart); 447b5b838f1SMarek Vasut 448873cc1d7SStephen Warren if (err < 0) 449873cc1d7SStephen Warren return 0; 450873cc1d7SStephen Warren 451c40fdca6SSimon Glass if ((start + blkcnt) > block_dev->lba) { 45256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 453d8e3d420SJean-Jacques Hiblot pr_err("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", 454c40fdca6SSimon Glass start + blkcnt, block_dev->lba); 45556196826SPaul Burton #endif 456d2bf29e3SLei Wen return 0; 457d2bf29e3SLei Wen } 458272cc70bSAndy Fleming 45911692991SSimon Glass if (mmc_set_blocklen(mmc, mmc->read_bl_len)) { 460*d4d64889SMasahiro Yamada pr_debug("%s: Failed to set blocklen\n", __func__); 461272cc70bSAndy Fleming return 0; 46211692991SSimon Glass } 463272cc70bSAndy Fleming 4644a1a06bcSAlagu Sankar do { 46593bfd616SPantelis Antoniou cur = (blocks_todo > mmc->cfg->b_max) ? 46693bfd616SPantelis Antoniou mmc->cfg->b_max : blocks_todo; 46711692991SSimon Glass if (mmc_read_blocks(mmc, dst, start, cur) != cur) { 468*d4d64889SMasahiro Yamada pr_debug("%s: Failed to read blocks\n", __func__); 4694a1a06bcSAlagu Sankar return 0; 47011692991SSimon Glass } 4714a1a06bcSAlagu Sankar blocks_todo -= cur; 4724a1a06bcSAlagu Sankar start += cur; 4734a1a06bcSAlagu Sankar dst += cur * mmc->read_bl_len; 4744a1a06bcSAlagu Sankar } while (blocks_todo > 0); 475272cc70bSAndy Fleming 476272cc70bSAndy Fleming return blkcnt; 477272cc70bSAndy Fleming } 478272cc70bSAndy Fleming 479fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc) 480272cc70bSAndy Fleming { 481272cc70bSAndy Fleming struct mmc_cmd cmd; 482272cc70bSAndy Fleming int err; 483272cc70bSAndy Fleming 484272cc70bSAndy Fleming udelay(1000); 485272cc70bSAndy Fleming 486272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_GO_IDLE_STATE; 487272cc70bSAndy Fleming cmd.cmdarg = 0; 488272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_NONE; 489272cc70bSAndy Fleming 490272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 491272cc70bSAndy Fleming 492272cc70bSAndy Fleming if (err) 493272cc70bSAndy Fleming return err; 494272cc70bSAndy Fleming 495272cc70bSAndy Fleming udelay(2000); 496272cc70bSAndy Fleming 497272cc70bSAndy Fleming return 0; 498272cc70bSAndy Fleming } 499272cc70bSAndy Fleming 500f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 501c10b85d6SJean-Jacques Hiblot static int mmc_switch_voltage(struct mmc *mmc, int signal_voltage) 502c10b85d6SJean-Jacques Hiblot { 503c10b85d6SJean-Jacques Hiblot struct mmc_cmd cmd; 504c10b85d6SJean-Jacques Hiblot int err = 0; 505c10b85d6SJean-Jacques Hiblot 506c10b85d6SJean-Jacques Hiblot /* 507c10b85d6SJean-Jacques Hiblot * Send CMD11 only if the request is to switch the card to 508c10b85d6SJean-Jacques Hiblot * 1.8V signalling. 509c10b85d6SJean-Jacques Hiblot */ 510c10b85d6SJean-Jacques Hiblot if (signal_voltage == MMC_SIGNAL_VOLTAGE_330) 511c10b85d6SJean-Jacques Hiblot return mmc_set_signal_voltage(mmc, signal_voltage); 512c10b85d6SJean-Jacques Hiblot 513c10b85d6SJean-Jacques Hiblot cmd.cmdidx = SD_CMD_SWITCH_UHS18V; 514c10b85d6SJean-Jacques Hiblot cmd.cmdarg = 0; 515c10b85d6SJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 516c10b85d6SJean-Jacques Hiblot 517c10b85d6SJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 518c10b85d6SJean-Jacques Hiblot if (err) 519c10b85d6SJean-Jacques Hiblot return err; 520c10b85d6SJean-Jacques Hiblot 521c10b85d6SJean-Jacques Hiblot if (!mmc_host_is_spi(mmc) && (cmd.response[0] & MMC_STATUS_ERROR)) 522c10b85d6SJean-Jacques Hiblot return -EIO; 523c10b85d6SJean-Jacques Hiblot 524c10b85d6SJean-Jacques Hiblot /* 525c10b85d6SJean-Jacques Hiblot * The card should drive cmd and dat[0:3] low immediately 526c10b85d6SJean-Jacques Hiblot * after the response of cmd11, but wait 100 us to be sure 527c10b85d6SJean-Jacques Hiblot */ 528c10b85d6SJean-Jacques Hiblot err = mmc_wait_dat0(mmc, 0, 100); 529c10b85d6SJean-Jacques Hiblot if (err == -ENOSYS) 530c10b85d6SJean-Jacques Hiblot udelay(100); 531c10b85d6SJean-Jacques Hiblot else if (err) 532c10b85d6SJean-Jacques Hiblot return -ETIMEDOUT; 533c10b85d6SJean-Jacques Hiblot 534c10b85d6SJean-Jacques Hiblot /* 535c10b85d6SJean-Jacques Hiblot * During a signal voltage level switch, the clock must be gated 536c10b85d6SJean-Jacques Hiblot * for 5 ms according to the SD spec 537c10b85d6SJean-Jacques Hiblot */ 538c10b85d6SJean-Jacques Hiblot mmc_set_clock(mmc, mmc->clock, true); 539c10b85d6SJean-Jacques Hiblot 540c10b85d6SJean-Jacques Hiblot err = mmc_set_signal_voltage(mmc, signal_voltage); 541c10b85d6SJean-Jacques Hiblot if (err) 542c10b85d6SJean-Jacques Hiblot return err; 543c10b85d6SJean-Jacques Hiblot 544c10b85d6SJean-Jacques Hiblot /* Keep clock gated for at least 10 ms, though spec only says 5 ms */ 545c10b85d6SJean-Jacques Hiblot mdelay(10); 546c10b85d6SJean-Jacques Hiblot mmc_set_clock(mmc, mmc->clock, false); 547c10b85d6SJean-Jacques Hiblot 548c10b85d6SJean-Jacques Hiblot /* 549c10b85d6SJean-Jacques Hiblot * Failure to switch is indicated by the card holding 550c10b85d6SJean-Jacques Hiblot * dat[0:3] low. Wait for at least 1 ms according to spec 551c10b85d6SJean-Jacques Hiblot */ 552c10b85d6SJean-Jacques Hiblot err = mmc_wait_dat0(mmc, 1, 1000); 553c10b85d6SJean-Jacques Hiblot if (err == -ENOSYS) 554c10b85d6SJean-Jacques Hiblot udelay(1000); 555c10b85d6SJean-Jacques Hiblot else if (err) 556c10b85d6SJean-Jacques Hiblot return -ETIMEDOUT; 557c10b85d6SJean-Jacques Hiblot 558c10b85d6SJean-Jacques Hiblot return 0; 559c10b85d6SJean-Jacques Hiblot } 560f99c2efeSJean-Jacques Hiblot #endif 561c10b85d6SJean-Jacques Hiblot 562c10b85d6SJean-Jacques Hiblot static int sd_send_op_cond(struct mmc *mmc, bool uhs_en) 563272cc70bSAndy Fleming { 564272cc70bSAndy Fleming int timeout = 1000; 565272cc70bSAndy Fleming int err; 566272cc70bSAndy Fleming struct mmc_cmd cmd; 567272cc70bSAndy Fleming 5681677eef4SAndrew Gabbasov while (1) { 569272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 570272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 571272cc70bSAndy Fleming cmd.cmdarg = 0; 572272cc70bSAndy Fleming 573272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 574272cc70bSAndy Fleming 575272cc70bSAndy Fleming if (err) 576272cc70bSAndy Fleming return err; 577272cc70bSAndy Fleming 578272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_OP_COND; 579272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R3; 580250de12bSStefano Babic 581250de12bSStefano Babic /* 582250de12bSStefano Babic * Most cards do not answer if some reserved bits 583250de12bSStefano Babic * in the ocr are set. However, Some controller 584250de12bSStefano Babic * can set bit 7 (reserved for low voltages), but 585250de12bSStefano Babic * how to manage low voltages SD card is not yet 586250de12bSStefano Babic * specified. 587250de12bSStefano Babic */ 588d52ebf10SThomas Chou cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 : 58993bfd616SPantelis Antoniou (mmc->cfg->voltages & 0xff8000); 590272cc70bSAndy Fleming 591272cc70bSAndy Fleming if (mmc->version == SD_VERSION_2) 592272cc70bSAndy Fleming cmd.cmdarg |= OCR_HCS; 593272cc70bSAndy Fleming 594c10b85d6SJean-Jacques Hiblot if (uhs_en) 595c10b85d6SJean-Jacques Hiblot cmd.cmdarg |= OCR_S18R; 596c10b85d6SJean-Jacques Hiblot 597272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 598272cc70bSAndy Fleming 599272cc70bSAndy Fleming if (err) 600272cc70bSAndy Fleming return err; 601272cc70bSAndy Fleming 6021677eef4SAndrew Gabbasov if (cmd.response[0] & OCR_BUSY) 6031677eef4SAndrew Gabbasov break; 604272cc70bSAndy Fleming 6051677eef4SAndrew Gabbasov if (timeout-- <= 0) 606915ffa52SJaehoon Chung return -EOPNOTSUPP; 607272cc70bSAndy Fleming 6081677eef4SAndrew Gabbasov udelay(1000); 6091677eef4SAndrew Gabbasov } 6101677eef4SAndrew Gabbasov 611272cc70bSAndy Fleming if (mmc->version != SD_VERSION_2) 612272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 613272cc70bSAndy Fleming 614d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 615d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 616d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 617d52ebf10SThomas Chou cmd.cmdarg = 0; 618d52ebf10SThomas Chou 619d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 620d52ebf10SThomas Chou 621d52ebf10SThomas Chou if (err) 622d52ebf10SThomas Chou return err; 623d52ebf10SThomas Chou } 624d52ebf10SThomas Chou 625998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 626272cc70bSAndy Fleming 627f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 628c10b85d6SJean-Jacques Hiblot if (uhs_en && !(mmc_host_is_spi(mmc)) && (cmd.response[0] & 0x41000000) 629c10b85d6SJean-Jacques Hiblot == 0x41000000) { 630c10b85d6SJean-Jacques Hiblot err = mmc_switch_voltage(mmc, MMC_SIGNAL_VOLTAGE_180); 631c10b85d6SJean-Jacques Hiblot if (err) 632c10b85d6SJean-Jacques Hiblot return err; 633c10b85d6SJean-Jacques Hiblot } 634f99c2efeSJean-Jacques Hiblot #endif 635c10b85d6SJean-Jacques Hiblot 636272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 637272cc70bSAndy Fleming mmc->rca = 0; 638272cc70bSAndy Fleming 639272cc70bSAndy Fleming return 0; 640272cc70bSAndy Fleming } 641272cc70bSAndy Fleming 6425289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg) 643272cc70bSAndy Fleming { 6445289b535SAndrew Gabbasov struct mmc_cmd cmd; 645272cc70bSAndy Fleming int err; 646272cc70bSAndy Fleming 6475289b535SAndrew Gabbasov cmd.cmdidx = MMC_CMD_SEND_OP_COND; 6485289b535SAndrew Gabbasov cmd.resp_type = MMC_RSP_R3; 6495289b535SAndrew Gabbasov cmd.cmdarg = 0; 6505a20397bSRob Herring if (use_arg && !mmc_host_is_spi(mmc)) 6515a20397bSRob Herring cmd.cmdarg = OCR_HCS | 65293bfd616SPantelis Antoniou (mmc->cfg->voltages & 653a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_VOLTAGE_MASK)) | 654a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_ACCESS_MODE); 655e9550449SChe-Liang Chiou 6565289b535SAndrew Gabbasov err = mmc_send_cmd(mmc, &cmd, NULL); 657e9550449SChe-Liang Chiou if (err) 658e9550449SChe-Liang Chiou return err; 6595289b535SAndrew Gabbasov mmc->ocr = cmd.response[0]; 660e9550449SChe-Liang Chiou return 0; 661e9550449SChe-Liang Chiou } 662e9550449SChe-Liang Chiou 663750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc) 664e9550449SChe-Liang Chiou { 665e9550449SChe-Liang Chiou int err, i; 666e9550449SChe-Liang Chiou 667272cc70bSAndy Fleming /* Some cards seem to need this */ 668272cc70bSAndy Fleming mmc_go_idle(mmc); 669272cc70bSAndy Fleming 67031cacbabSRaffaele Recalcati /* Asking to the card its capabilities */ 671e9550449SChe-Liang Chiou for (i = 0; i < 2; i++) { 6725289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, i != 0); 67331cacbabSRaffaele Recalcati if (err) 67431cacbabSRaffaele Recalcati return err; 67531cacbabSRaffaele Recalcati 676e9550449SChe-Liang Chiou /* exit if not busy (flag seems to be inverted) */ 677a626c8d4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 678bd47c135SAndrew Gabbasov break; 679e9550449SChe-Liang Chiou } 680bd47c135SAndrew Gabbasov mmc->op_cond_pending = 1; 681bd47c135SAndrew Gabbasov return 0; 682e9550449SChe-Liang Chiou } 68331cacbabSRaffaele Recalcati 684750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc) 685e9550449SChe-Liang Chiou { 686e9550449SChe-Liang Chiou struct mmc_cmd cmd; 687e9550449SChe-Liang Chiou int timeout = 1000; 688e9550449SChe-Liang Chiou uint start; 689e9550449SChe-Liang Chiou int err; 690e9550449SChe-Liang Chiou 691e9550449SChe-Liang Chiou mmc->op_cond_pending = 0; 692cc17c01fSAndrew Gabbasov if (!(mmc->ocr & OCR_BUSY)) { 693d188b113SYangbo Lu /* Some cards seem to need this */ 694d188b113SYangbo Lu mmc_go_idle(mmc); 695d188b113SYangbo Lu 696e9550449SChe-Liang Chiou start = get_timer(0); 6971677eef4SAndrew Gabbasov while (1) { 6985289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, 1); 699272cc70bSAndy Fleming if (err) 700272cc70bSAndy Fleming return err; 7011677eef4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 7021677eef4SAndrew Gabbasov break; 703e9550449SChe-Liang Chiou if (get_timer(start) > timeout) 704915ffa52SJaehoon Chung return -EOPNOTSUPP; 705e9550449SChe-Liang Chiou udelay(100); 7061677eef4SAndrew Gabbasov } 707cc17c01fSAndrew Gabbasov } 708272cc70bSAndy Fleming 709d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 710d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 711d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 712d52ebf10SThomas Chou cmd.cmdarg = 0; 713d52ebf10SThomas Chou 714d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 715d52ebf10SThomas Chou 716d52ebf10SThomas Chou if (err) 717d52ebf10SThomas Chou return err; 718a626c8d4SAndrew Gabbasov 719a626c8d4SAndrew Gabbasov mmc->ocr = cmd.response[0]; 720d52ebf10SThomas Chou } 721d52ebf10SThomas Chou 722272cc70bSAndy Fleming mmc->version = MMC_VERSION_UNKNOWN; 723272cc70bSAndy Fleming 724272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 725def816a2SStephen Warren mmc->rca = 1; 726272cc70bSAndy Fleming 727272cc70bSAndy Fleming return 0; 728272cc70bSAndy Fleming } 729272cc70bSAndy Fleming 730272cc70bSAndy Fleming 731fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) 732272cc70bSAndy Fleming { 733272cc70bSAndy Fleming struct mmc_cmd cmd; 734272cc70bSAndy Fleming struct mmc_data data; 735272cc70bSAndy Fleming int err; 736272cc70bSAndy Fleming 737272cc70bSAndy Fleming /* Get the Card Status Register */ 738272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_EXT_CSD; 739272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 740272cc70bSAndy Fleming cmd.cmdarg = 0; 741272cc70bSAndy Fleming 742cdfd1ac6SYoshihiro Shimoda data.dest = (char *)ext_csd; 743272cc70bSAndy Fleming data.blocks = 1; 7448bfa195eSSimon Glass data.blocksize = MMC_MAX_BLOCK_LEN; 745272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 746272cc70bSAndy Fleming 747272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 748272cc70bSAndy Fleming 749272cc70bSAndy Fleming return err; 750272cc70bSAndy Fleming } 751272cc70bSAndy Fleming 752c40704f4SSimon Glass int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) 753272cc70bSAndy Fleming { 754272cc70bSAndy Fleming struct mmc_cmd cmd; 7555d4fc8d9SRaffaele Recalcati int timeout = 1000; 756a9003dc6SMaxime Ripard int retries = 3; 7575d4fc8d9SRaffaele Recalcati int ret; 758272cc70bSAndy Fleming 759272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SWITCH; 760272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 761272cc70bSAndy Fleming cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 762272cc70bSAndy Fleming (index << 16) | 763272cc70bSAndy Fleming (value << 8); 764272cc70bSAndy Fleming 765a9003dc6SMaxime Ripard while (retries > 0) { 7665d4fc8d9SRaffaele Recalcati ret = mmc_send_cmd(mmc, &cmd, NULL); 7675d4fc8d9SRaffaele Recalcati 7685d4fc8d9SRaffaele Recalcati /* Waiting for the ready status */ 769a9003dc6SMaxime Ripard if (!ret) { 77093ad0d18SJan Kloetzke ret = mmc_send_status(mmc, timeout); 771a9003dc6SMaxime Ripard return ret; 772a9003dc6SMaxime Ripard } 773a9003dc6SMaxime Ripard 774a9003dc6SMaxime Ripard retries--; 775a9003dc6SMaxime Ripard } 7765d4fc8d9SRaffaele Recalcati 7775d4fc8d9SRaffaele Recalcati return ret; 7785d4fc8d9SRaffaele Recalcati 779272cc70bSAndy Fleming } 780272cc70bSAndy Fleming 7813862b854SJean-Jacques Hiblot static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode) 782272cc70bSAndy Fleming { 783272cc70bSAndy Fleming int err; 7843862b854SJean-Jacques Hiblot int speed_bits; 7853862b854SJean-Jacques Hiblot 7863862b854SJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 7873862b854SJean-Jacques Hiblot 7883862b854SJean-Jacques Hiblot switch (mode) { 7893862b854SJean-Jacques Hiblot case MMC_HS: 7903862b854SJean-Jacques Hiblot case MMC_HS_52: 7913862b854SJean-Jacques Hiblot case MMC_DDR_52: 7923862b854SJean-Jacques Hiblot speed_bits = EXT_CSD_TIMING_HS; 793634d4849SKishon Vijay Abraham I break; 794baef2070SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) 795634d4849SKishon Vijay Abraham I case MMC_HS_200: 796634d4849SKishon Vijay Abraham I speed_bits = EXT_CSD_TIMING_HS200; 797634d4849SKishon Vijay Abraham I break; 798baef2070SJean-Jacques Hiblot #endif 7993862b854SJean-Jacques Hiblot case MMC_LEGACY: 8003862b854SJean-Jacques Hiblot speed_bits = EXT_CSD_TIMING_LEGACY; 8013862b854SJean-Jacques Hiblot break; 8023862b854SJean-Jacques Hiblot default: 8033862b854SJean-Jacques Hiblot return -EINVAL; 8043862b854SJean-Jacques Hiblot } 8053862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 8063862b854SJean-Jacques Hiblot speed_bits); 8073862b854SJean-Jacques Hiblot if (err) 8083862b854SJean-Jacques Hiblot return err; 8093862b854SJean-Jacques Hiblot 8103862b854SJean-Jacques Hiblot if ((mode == MMC_HS) || (mode == MMC_HS_52)) { 8113862b854SJean-Jacques Hiblot /* Now check to see that it worked */ 8123862b854SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, test_csd); 8133862b854SJean-Jacques Hiblot if (err) 8143862b854SJean-Jacques Hiblot return err; 8153862b854SJean-Jacques Hiblot 8163862b854SJean-Jacques Hiblot /* No high-speed support */ 8173862b854SJean-Jacques Hiblot if (!test_csd[EXT_CSD_HS_TIMING]) 8183862b854SJean-Jacques Hiblot return -ENOTSUPP; 8193862b854SJean-Jacques Hiblot } 8203862b854SJean-Jacques Hiblot 8213862b854SJean-Jacques Hiblot return 0; 8223862b854SJean-Jacques Hiblot } 8233862b854SJean-Jacques Hiblot 8243862b854SJean-Jacques Hiblot static int mmc_get_capabilities(struct mmc *mmc) 8253862b854SJean-Jacques Hiblot { 8263862b854SJean-Jacques Hiblot u8 *ext_csd = mmc->ext_csd; 8273862b854SJean-Jacques Hiblot char cardtype; 828272cc70bSAndy Fleming 82900e446faSJean-Jacques Hiblot mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(MMC_LEGACY); 830272cc70bSAndy Fleming 831d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 832d52ebf10SThomas Chou return 0; 833d52ebf10SThomas Chou 834272cc70bSAndy Fleming /* Only version 4 supports high-speed */ 835272cc70bSAndy Fleming if (mmc->version < MMC_VERSION_4) 836272cc70bSAndy Fleming return 0; 837272cc70bSAndy Fleming 8383862b854SJean-Jacques Hiblot if (!ext_csd) { 839d8e3d420SJean-Jacques Hiblot pr_err("No ext_csd found!\n"); /* this should enver happen */ 8403862b854SJean-Jacques Hiblot return -ENOTSUPP; 8413862b854SJean-Jacques Hiblot } 8423862b854SJean-Jacques Hiblot 843fc5b32fbSAndrew Gabbasov mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; 844fc5b32fbSAndrew Gabbasov 845634d4849SKishon Vijay Abraham I cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0x3f; 846bc1e3272SJean-Jacques Hiblot mmc->cardtype = cardtype; 847272cc70bSAndy Fleming 848baef2070SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) 849634d4849SKishon Vijay Abraham I if (cardtype & (EXT_CSD_CARD_TYPE_HS200_1_2V | 850634d4849SKishon Vijay Abraham I EXT_CSD_CARD_TYPE_HS200_1_8V)) { 851634d4849SKishon Vijay Abraham I mmc->card_caps |= MMC_MODE_HS200; 852634d4849SKishon Vijay Abraham I } 853baef2070SJean-Jacques Hiblot #endif 854d22e3d46SJaehoon Chung if (cardtype & EXT_CSD_CARD_TYPE_52) { 8553862b854SJean-Jacques Hiblot if (cardtype & EXT_CSD_CARD_TYPE_DDR_52) 856d22e3d46SJaehoon Chung mmc->card_caps |= MMC_MODE_DDR_52MHz; 8573862b854SJean-Jacques Hiblot mmc->card_caps |= MMC_MODE_HS_52MHz; 858d22e3d46SJaehoon Chung } 8593862b854SJean-Jacques Hiblot if (cardtype & EXT_CSD_CARD_TYPE_26) 8603862b854SJean-Jacques Hiblot mmc->card_caps |= MMC_MODE_HS; 861272cc70bSAndy Fleming 862272cc70bSAndy Fleming return 0; 863272cc70bSAndy Fleming } 864272cc70bSAndy Fleming 865f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num) 866f866a46dSStephen Warren { 867f866a46dSStephen Warren switch (part_num) { 868f866a46dSStephen Warren case 0: 869f866a46dSStephen Warren mmc->capacity = mmc->capacity_user; 870f866a46dSStephen Warren break; 871f866a46dSStephen Warren case 1: 872f866a46dSStephen Warren case 2: 873f866a46dSStephen Warren mmc->capacity = mmc->capacity_boot; 874f866a46dSStephen Warren break; 875f866a46dSStephen Warren case 3: 876f866a46dSStephen Warren mmc->capacity = mmc->capacity_rpmb; 877f866a46dSStephen Warren break; 878f866a46dSStephen Warren case 4: 879f866a46dSStephen Warren case 5: 880f866a46dSStephen Warren case 6: 881f866a46dSStephen Warren case 7: 882f866a46dSStephen Warren mmc->capacity = mmc->capacity_gp[part_num - 4]; 883f866a46dSStephen Warren break; 884f866a46dSStephen Warren default: 885f866a46dSStephen Warren return -1; 886f866a46dSStephen Warren } 887f866a46dSStephen Warren 888c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len); 889f866a46dSStephen Warren 890f866a46dSStephen Warren return 0; 891f866a46dSStephen Warren } 892f866a46dSStephen Warren 893f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) 89401298da3SJean-Jacques Hiblot static int mmc_boot_part_access_chk(struct mmc *mmc, unsigned int part_num) 89501298da3SJean-Jacques Hiblot { 89601298da3SJean-Jacques Hiblot int forbidden = 0; 89701298da3SJean-Jacques Hiblot bool change = false; 89801298da3SJean-Jacques Hiblot 89901298da3SJean-Jacques Hiblot if (part_num & PART_ACCESS_MASK) 90001298da3SJean-Jacques Hiblot forbidden = MMC_CAP(MMC_HS_200); 90101298da3SJean-Jacques Hiblot 90201298da3SJean-Jacques Hiblot if (MMC_CAP(mmc->selected_mode) & forbidden) { 903*d4d64889SMasahiro Yamada pr_debug("selected mode (%s) is forbidden for part %d\n", 90401298da3SJean-Jacques Hiblot mmc_mode_name(mmc->selected_mode), part_num); 90501298da3SJean-Jacques Hiblot change = true; 90601298da3SJean-Jacques Hiblot } else if (mmc->selected_mode != mmc->best_mode) { 907*d4d64889SMasahiro Yamada pr_debug("selected mode is not optimal\n"); 90801298da3SJean-Jacques Hiblot change = true; 90901298da3SJean-Jacques Hiblot } 91001298da3SJean-Jacques Hiblot 91101298da3SJean-Jacques Hiblot if (change) 91201298da3SJean-Jacques Hiblot return mmc_select_mode_and_width(mmc, 91301298da3SJean-Jacques Hiblot mmc->card_caps & ~forbidden); 91401298da3SJean-Jacques Hiblot 91501298da3SJean-Jacques Hiblot return 0; 91601298da3SJean-Jacques Hiblot } 917f99c2efeSJean-Jacques Hiblot #else 918f99c2efeSJean-Jacques Hiblot static inline int mmc_boot_part_access_chk(struct mmc *mmc, 919f99c2efeSJean-Jacques Hiblot unsigned int part_num) 920f99c2efeSJean-Jacques Hiblot { 921f99c2efeSJean-Jacques Hiblot return 0; 922f99c2efeSJean-Jacques Hiblot } 923f99c2efeSJean-Jacques Hiblot #endif 92401298da3SJean-Jacques Hiblot 9257dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num) 926bc897b1dSLei Wen { 927f866a46dSStephen Warren int ret; 928bc897b1dSLei Wen 92901298da3SJean-Jacques Hiblot ret = mmc_boot_part_access_chk(mmc, part_num); 93001298da3SJean-Jacques Hiblot if (ret) 93101298da3SJean-Jacques Hiblot return ret; 93201298da3SJean-Jacques Hiblot 933f866a46dSStephen Warren ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 934bc897b1dSLei Wen (mmc->part_config & ~PART_ACCESS_MASK) 935bc897b1dSLei Wen | (part_num & PART_ACCESS_MASK)); 936f866a46dSStephen Warren 9376dc93e70SPeter Bigot /* 9386dc93e70SPeter Bigot * Set the capacity if the switch succeeded or was intended 9396dc93e70SPeter Bigot * to return to representing the raw device. 9406dc93e70SPeter Bigot */ 941873cc1d7SStephen Warren if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) { 9426dc93e70SPeter Bigot ret = mmc_set_capacity(mmc, part_num); 943fdbb139fSSimon Glass mmc_get_blk_desc(mmc)->hwpart = part_num; 944873cc1d7SStephen Warren } 9456dc93e70SPeter Bigot 9466dc93e70SPeter Bigot return ret; 947bc897b1dSLei Wen } 948bc897b1dSLei Wen 949cf17789eSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING) 950ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc, 951ac9da0e0SDiego Santa Cruz const struct mmc_hwpart_conf *conf, 952ac9da0e0SDiego Santa Cruz enum mmc_hwpart_conf_mode mode) 953ac9da0e0SDiego Santa Cruz { 954ac9da0e0SDiego Santa Cruz u8 part_attrs = 0; 955ac9da0e0SDiego Santa Cruz u32 enh_size_mult; 956ac9da0e0SDiego Santa Cruz u32 enh_start_addr; 957ac9da0e0SDiego Santa Cruz u32 gp_size_mult[4]; 958ac9da0e0SDiego Santa Cruz u32 max_enh_size_mult; 959ac9da0e0SDiego Santa Cruz u32 tot_enh_size_mult = 0; 9608dda5b0eSDiego Santa Cruz u8 wr_rel_set; 961ac9da0e0SDiego Santa Cruz int i, pidx, err; 962ac9da0e0SDiego Santa Cruz ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 963ac9da0e0SDiego Santa Cruz 964ac9da0e0SDiego Santa Cruz if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE) 965ac9da0e0SDiego Santa Cruz return -EINVAL; 966ac9da0e0SDiego Santa Cruz 967ac9da0e0SDiego Santa Cruz if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) { 968d8e3d420SJean-Jacques Hiblot pr_err("eMMC >= 4.4 required for enhanced user data area\n"); 969ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 970ac9da0e0SDiego Santa Cruz } 971ac9da0e0SDiego Santa Cruz 972ac9da0e0SDiego Santa Cruz if (!(mmc->part_support & PART_SUPPORT)) { 973d8e3d420SJean-Jacques Hiblot pr_err("Card does not support partitioning\n"); 974ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 975ac9da0e0SDiego Santa Cruz } 976ac9da0e0SDiego Santa Cruz 977ac9da0e0SDiego Santa Cruz if (!mmc->hc_wp_grp_size) { 978d8e3d420SJean-Jacques Hiblot pr_err("Card does not define HC WP group size\n"); 979ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 980ac9da0e0SDiego Santa Cruz } 981ac9da0e0SDiego Santa Cruz 982ac9da0e0SDiego Santa Cruz /* check partition alignment and total enhanced size */ 983ac9da0e0SDiego Santa Cruz if (conf->user.enh_size) { 984ac9da0e0SDiego Santa Cruz if (conf->user.enh_size % mmc->hc_wp_grp_size || 985ac9da0e0SDiego Santa Cruz conf->user.enh_start % mmc->hc_wp_grp_size) { 986d8e3d420SJean-Jacques Hiblot pr_err("User data enhanced area not HC WP group " 987ac9da0e0SDiego Santa Cruz "size aligned\n"); 988ac9da0e0SDiego Santa Cruz return -EINVAL; 989ac9da0e0SDiego Santa Cruz } 990ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_USR; 991ac9da0e0SDiego Santa Cruz enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size; 992ac9da0e0SDiego Santa Cruz if (mmc->high_capacity) { 993ac9da0e0SDiego Santa Cruz enh_start_addr = conf->user.enh_start; 994ac9da0e0SDiego Santa Cruz } else { 995ac9da0e0SDiego Santa Cruz enh_start_addr = (conf->user.enh_start << 9); 996ac9da0e0SDiego Santa Cruz } 997ac9da0e0SDiego Santa Cruz } else { 998ac9da0e0SDiego Santa Cruz enh_size_mult = 0; 999ac9da0e0SDiego Santa Cruz enh_start_addr = 0; 1000ac9da0e0SDiego Santa Cruz } 1001ac9da0e0SDiego Santa Cruz tot_enh_size_mult += enh_size_mult; 1002ac9da0e0SDiego Santa Cruz 1003ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 1004ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) { 1005d8e3d420SJean-Jacques Hiblot pr_err("GP%i partition not HC WP group size " 1006ac9da0e0SDiego Santa Cruz "aligned\n", pidx+1); 1007ac9da0e0SDiego Santa Cruz return -EINVAL; 1008ac9da0e0SDiego Santa Cruz } 1009ac9da0e0SDiego Santa Cruz gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size; 1010ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) { 1011ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_GP(pidx); 1012ac9da0e0SDiego Santa Cruz tot_enh_size_mult += gp_size_mult[pidx]; 1013ac9da0e0SDiego Santa Cruz } 1014ac9da0e0SDiego Santa Cruz } 1015ac9da0e0SDiego Santa Cruz 1016ac9da0e0SDiego Santa Cruz if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) { 1017d8e3d420SJean-Jacques Hiblot pr_err("Card does not support enhanced attribute\n"); 1018ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1019ac9da0e0SDiego Santa Cruz } 1020ac9da0e0SDiego Santa Cruz 1021ac9da0e0SDiego Santa Cruz err = mmc_send_ext_csd(mmc, ext_csd); 1022ac9da0e0SDiego Santa Cruz if (err) 1023ac9da0e0SDiego Santa Cruz return err; 1024ac9da0e0SDiego Santa Cruz 1025ac9da0e0SDiego Santa Cruz max_enh_size_mult = 1026ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) + 1027ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) + 1028ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]; 1029ac9da0e0SDiego Santa Cruz if (tot_enh_size_mult > max_enh_size_mult) { 1030d8e3d420SJean-Jacques Hiblot pr_err("Total enhanced size exceeds maximum (%u > %u)\n", 1031ac9da0e0SDiego Santa Cruz tot_enh_size_mult, max_enh_size_mult); 1032ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1033ac9da0e0SDiego Santa Cruz } 1034ac9da0e0SDiego Santa Cruz 10358dda5b0eSDiego Santa Cruz /* The default value of EXT_CSD_WR_REL_SET is device 10368dda5b0eSDiego Santa Cruz * dependent, the values can only be changed if the 10378dda5b0eSDiego Santa Cruz * EXT_CSD_HS_CTRL_REL bit is set. The values can be 10388dda5b0eSDiego Santa Cruz * changed only once and before partitioning is completed. */ 10398dda5b0eSDiego Santa Cruz wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 10408dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_change) { 10418dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_set) 10428dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_USR; 10438dda5b0eSDiego Santa Cruz else 10448dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR; 10458dda5b0eSDiego Santa Cruz } 10468dda5b0eSDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 10478dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_change) { 10488dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_set) 10498dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx); 10508dda5b0eSDiego Santa Cruz else 10518dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx); 10528dda5b0eSDiego Santa Cruz } 10538dda5b0eSDiego Santa Cruz } 10548dda5b0eSDiego Santa Cruz 10558dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] && 10568dda5b0eSDiego Santa Cruz !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) { 10578dda5b0eSDiego Santa Cruz puts("Card does not support host controlled partition write " 10588dda5b0eSDiego Santa Cruz "reliability settings\n"); 10598dda5b0eSDiego Santa Cruz return -EMEDIUMTYPE; 10608dda5b0eSDiego Santa Cruz } 10618dda5b0eSDiego Santa Cruz 1062ac9da0e0SDiego Santa Cruz if (ext_csd[EXT_CSD_PARTITION_SETTING] & 1063ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED) { 1064d8e3d420SJean-Jacques Hiblot pr_err("Card already partitioned\n"); 1065ac9da0e0SDiego Santa Cruz return -EPERM; 1066ac9da0e0SDiego Santa Cruz } 1067ac9da0e0SDiego Santa Cruz 1068ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_CHECK) 1069ac9da0e0SDiego Santa Cruz return 0; 1070ac9da0e0SDiego Santa Cruz 1071ac9da0e0SDiego Santa Cruz /* Partitioning requires high-capacity size definitions */ 1072ac9da0e0SDiego Santa Cruz if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) { 1073ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1074ac9da0e0SDiego Santa Cruz EXT_CSD_ERASE_GROUP_DEF, 1); 1075ac9da0e0SDiego Santa Cruz 1076ac9da0e0SDiego Santa Cruz if (err) 1077ac9da0e0SDiego Santa Cruz return err; 1078ac9da0e0SDiego Santa Cruz 1079ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 1080ac9da0e0SDiego Santa Cruz 1081ac9da0e0SDiego Santa Cruz /* update erase group size to be high-capacity */ 1082ac9da0e0SDiego Santa Cruz mmc->erase_grp_size = 1083ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 1084ac9da0e0SDiego Santa Cruz 1085ac9da0e0SDiego Santa Cruz } 1086ac9da0e0SDiego Santa Cruz 1087ac9da0e0SDiego Santa Cruz /* all OK, write the configuration */ 1088ac9da0e0SDiego Santa Cruz for (i = 0; i < 4; i++) { 1089ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1090ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_START_ADDR+i, 1091ac9da0e0SDiego Santa Cruz (enh_start_addr >> (i*8)) & 0xFF); 1092ac9da0e0SDiego Santa Cruz if (err) 1093ac9da0e0SDiego Santa Cruz return err; 1094ac9da0e0SDiego Santa Cruz } 1095ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 1096ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1097ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_SIZE_MULT+i, 1098ac9da0e0SDiego Santa Cruz (enh_size_mult >> (i*8)) & 0xFF); 1099ac9da0e0SDiego Santa Cruz if (err) 1100ac9da0e0SDiego Santa Cruz return err; 1101ac9da0e0SDiego Santa Cruz } 1102ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 1103ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 1104ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1105ac9da0e0SDiego Santa Cruz EXT_CSD_GP_SIZE_MULT+pidx*3+i, 1106ac9da0e0SDiego Santa Cruz (gp_size_mult[pidx] >> (i*8)) & 0xFF); 1107ac9da0e0SDiego Santa Cruz if (err) 1108ac9da0e0SDiego Santa Cruz return err; 1109ac9da0e0SDiego Santa Cruz } 1110ac9da0e0SDiego Santa Cruz } 1111ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1112ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs); 1113ac9da0e0SDiego Santa Cruz if (err) 1114ac9da0e0SDiego Santa Cruz return err; 1115ac9da0e0SDiego Santa Cruz 1116ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_SET) 1117ac9da0e0SDiego Santa Cruz return 0; 1118ac9da0e0SDiego Santa Cruz 11198dda5b0eSDiego Santa Cruz /* The WR_REL_SET is a write-once register but shall be 11208dda5b0eSDiego Santa Cruz * written before setting PART_SETTING_COMPLETED. As it is 11218dda5b0eSDiego Santa Cruz * write-once we can only write it when completing the 11228dda5b0eSDiego Santa Cruz * partitioning. */ 11238dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) { 11248dda5b0eSDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 11258dda5b0eSDiego Santa Cruz EXT_CSD_WR_REL_SET, wr_rel_set); 11268dda5b0eSDiego Santa Cruz if (err) 11278dda5b0eSDiego Santa Cruz return err; 11288dda5b0eSDiego Santa Cruz } 11298dda5b0eSDiego Santa Cruz 1130ac9da0e0SDiego Santa Cruz /* Setting PART_SETTING_COMPLETED confirms the partition 1131ac9da0e0SDiego Santa Cruz * configuration but it only becomes effective after power 1132ac9da0e0SDiego Santa Cruz * cycle, so we do not adjust the partition related settings 1133ac9da0e0SDiego Santa Cruz * in the mmc struct. */ 1134ac9da0e0SDiego Santa Cruz 1135ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1136ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING, 1137ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 1138ac9da0e0SDiego Santa Cruz if (err) 1139ac9da0e0SDiego Santa Cruz return err; 1140ac9da0e0SDiego Santa Cruz 1141ac9da0e0SDiego Santa Cruz return 0; 1142ac9da0e0SDiego Santa Cruz } 1143cf17789eSJean-Jacques Hiblot #endif 1144ac9da0e0SDiego Santa Cruz 1145e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 114648972d90SThierry Reding int mmc_getcd(struct mmc *mmc) 114748972d90SThierry Reding { 114848972d90SThierry Reding int cd; 114948972d90SThierry Reding 115048972d90SThierry Reding cd = board_mmc_getcd(mmc); 115148972d90SThierry Reding 1152d4e1da4eSPeter Korsgaard if (cd < 0) { 115393bfd616SPantelis Antoniou if (mmc->cfg->ops->getcd) 115493bfd616SPantelis Antoniou cd = mmc->cfg->ops->getcd(mmc); 1155d4e1da4eSPeter Korsgaard else 1156d4e1da4eSPeter Korsgaard cd = 1; 1157d4e1da4eSPeter Korsgaard } 115848972d90SThierry Reding 115948972d90SThierry Reding return cd; 116048972d90SThierry Reding } 11618ca51e51SSimon Glass #endif 116248972d90SThierry Reding 1163fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) 1164272cc70bSAndy Fleming { 1165272cc70bSAndy Fleming struct mmc_cmd cmd; 1166272cc70bSAndy Fleming struct mmc_data data; 1167272cc70bSAndy Fleming 1168272cc70bSAndy Fleming /* Switch the frequency */ 1169272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC; 1170272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1171272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff; 1172272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4)); 1173272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4); 1174272cc70bSAndy Fleming 1175272cc70bSAndy Fleming data.dest = (char *)resp; 1176272cc70bSAndy Fleming data.blocksize = 64; 1177272cc70bSAndy Fleming data.blocks = 1; 1178272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1179272cc70bSAndy Fleming 1180272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 1181272cc70bSAndy Fleming } 1182272cc70bSAndy Fleming 1183272cc70bSAndy Fleming 1184d0c221feSJean-Jacques Hiblot static int sd_get_capabilities(struct mmc *mmc) 1185272cc70bSAndy Fleming { 1186272cc70bSAndy Fleming int err; 1187272cc70bSAndy Fleming struct mmc_cmd cmd; 118818e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2); 118918e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16); 1190272cc70bSAndy Fleming struct mmc_data data; 1191272cc70bSAndy Fleming int timeout; 1192f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1193c10b85d6SJean-Jacques Hiblot u32 sd3_bus_mode; 1194f99c2efeSJean-Jacques Hiblot #endif 1195272cc70bSAndy Fleming 119600e446faSJean-Jacques Hiblot mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(SD_LEGACY); 1197272cc70bSAndy Fleming 1198d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 1199d52ebf10SThomas Chou return 0; 1200d52ebf10SThomas Chou 1201272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */ 1202272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 1203272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1204272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1205272cc70bSAndy Fleming 1206272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1207272cc70bSAndy Fleming 1208272cc70bSAndy Fleming if (err) 1209272cc70bSAndy Fleming return err; 1210272cc70bSAndy Fleming 1211272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR; 1212272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1213272cc70bSAndy Fleming cmd.cmdarg = 0; 1214272cc70bSAndy Fleming 1215272cc70bSAndy Fleming timeout = 3; 1216272cc70bSAndy Fleming 1217272cc70bSAndy Fleming retry_scr: 1218f781dd38SAnton staaf data.dest = (char *)scr; 1219272cc70bSAndy Fleming data.blocksize = 8; 1220272cc70bSAndy Fleming data.blocks = 1; 1221272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1222272cc70bSAndy Fleming 1223272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 1224272cc70bSAndy Fleming 1225272cc70bSAndy Fleming if (err) { 1226272cc70bSAndy Fleming if (timeout--) 1227272cc70bSAndy Fleming goto retry_scr; 1228272cc70bSAndy Fleming 1229272cc70bSAndy Fleming return err; 1230272cc70bSAndy Fleming } 1231272cc70bSAndy Fleming 12324e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]); 12334e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]); 1234272cc70bSAndy Fleming 1235272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) { 1236272cc70bSAndy Fleming case 0: 1237272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1238272cc70bSAndy Fleming break; 1239272cc70bSAndy Fleming case 1: 1240272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10; 1241272cc70bSAndy Fleming break; 1242272cc70bSAndy Fleming case 2: 1243272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 12441741c64dSJaehoon Chung if ((mmc->scr[0] >> 15) & 0x1) 12451741c64dSJaehoon Chung mmc->version = SD_VERSION_3; 1246272cc70bSAndy Fleming break; 1247272cc70bSAndy Fleming default: 1248272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1249272cc70bSAndy Fleming break; 1250272cc70bSAndy Fleming } 1251272cc70bSAndy Fleming 1252b44c7083SAlagu Sankar if (mmc->scr[0] & SD_DATA_4BIT) 1253b44c7083SAlagu Sankar mmc->card_caps |= MMC_MODE_4BIT; 1254b44c7083SAlagu Sankar 1255272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */ 1256272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0) 1257272cc70bSAndy Fleming return 0; 1258272cc70bSAndy Fleming 1259272cc70bSAndy Fleming timeout = 4; 1260272cc70bSAndy Fleming while (timeout--) { 1261272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, 1262f781dd38SAnton staaf (u8 *)switch_status); 1263272cc70bSAndy Fleming 1264272cc70bSAndy Fleming if (err) 1265272cc70bSAndy Fleming return err; 1266272cc70bSAndy Fleming 1267272cc70bSAndy Fleming /* The high-speed function is busy. Try again */ 12684e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) 1269272cc70bSAndy Fleming break; 1270272cc70bSAndy Fleming } 1271272cc70bSAndy Fleming 1272272cc70bSAndy Fleming /* If high-speed isn't supported, we return */ 1273d0c221feSJean-Jacques Hiblot if (__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED) 1274d0c221feSJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(SD_HS); 1275272cc70bSAndy Fleming 1276f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1277c10b85d6SJean-Jacques Hiblot /* Version before 3.0 don't support UHS modes */ 1278c10b85d6SJean-Jacques Hiblot if (mmc->version < SD_VERSION_3) 1279c10b85d6SJean-Jacques Hiblot return 0; 1280c10b85d6SJean-Jacques Hiblot 1281c10b85d6SJean-Jacques Hiblot sd3_bus_mode = __be32_to_cpu(switch_status[3]) >> 16 & 0x1f; 1282c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR104) 1283c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR104); 1284c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR50) 1285c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR50); 1286c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR25) 1287c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR25); 1288c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR12) 1289c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR12); 1290c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_DDR50) 1291c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_DDR50); 1292f99c2efeSJean-Jacques Hiblot #endif 1293c10b85d6SJean-Jacques Hiblot 12942c3fbf4cSMacpaul Lin return 0; 1295d0c221feSJean-Jacques Hiblot } 1296d0c221feSJean-Jacques Hiblot 1297d0c221feSJean-Jacques Hiblot static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode) 1298d0c221feSJean-Jacques Hiblot { 1299d0c221feSJean-Jacques Hiblot int err; 1300d0c221feSJean-Jacques Hiblot 1301d0c221feSJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16); 1302c10b85d6SJean-Jacques Hiblot int speed; 13032c3fbf4cSMacpaul Lin 1304c10b85d6SJean-Jacques Hiblot switch (mode) { 1305c10b85d6SJean-Jacques Hiblot case SD_LEGACY: 1306c10b85d6SJean-Jacques Hiblot speed = UHS_SDR12_BUS_SPEED; 1307c10b85d6SJean-Jacques Hiblot break; 1308c10b85d6SJean-Jacques Hiblot case SD_HS: 1309baef2070SJean-Jacques Hiblot speed = HIGH_SPEED_BUS_SPEED; 1310baef2070SJean-Jacques Hiblot break; 1311baef2070SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1312baef2070SJean-Jacques Hiblot case UHS_SDR12: 1313baef2070SJean-Jacques Hiblot speed = UHS_SDR12_BUS_SPEED; 1314baef2070SJean-Jacques Hiblot break; 1315c10b85d6SJean-Jacques Hiblot case UHS_SDR25: 1316c10b85d6SJean-Jacques Hiblot speed = UHS_SDR25_BUS_SPEED; 1317c10b85d6SJean-Jacques Hiblot break; 1318c10b85d6SJean-Jacques Hiblot case UHS_SDR50: 1319c10b85d6SJean-Jacques Hiblot speed = UHS_SDR50_BUS_SPEED; 1320c10b85d6SJean-Jacques Hiblot break; 1321c10b85d6SJean-Jacques Hiblot case UHS_DDR50: 1322c10b85d6SJean-Jacques Hiblot speed = UHS_DDR50_BUS_SPEED; 1323c10b85d6SJean-Jacques Hiblot break; 1324c10b85d6SJean-Jacques Hiblot case UHS_SDR104: 1325c10b85d6SJean-Jacques Hiblot speed = UHS_SDR104_BUS_SPEED; 1326c10b85d6SJean-Jacques Hiblot break; 1327baef2070SJean-Jacques Hiblot #endif 1328c10b85d6SJean-Jacques Hiblot default: 1329c10b85d6SJean-Jacques Hiblot return -EINVAL; 1330c10b85d6SJean-Jacques Hiblot } 1331c10b85d6SJean-Jacques Hiblot 1332c10b85d6SJean-Jacques Hiblot err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, speed, (u8 *)switch_status); 1333272cc70bSAndy Fleming if (err) 1334272cc70bSAndy Fleming return err; 1335272cc70bSAndy Fleming 1336c10b85d6SJean-Jacques Hiblot if ((__be32_to_cpu(switch_status[4]) >> 24) != speed) 1337d0c221feSJean-Jacques Hiblot return -ENOTSUPP; 1338d0c221feSJean-Jacques Hiblot 1339d0c221feSJean-Jacques Hiblot return 0; 1340d0c221feSJean-Jacques Hiblot } 1341d0c221feSJean-Jacques Hiblot 1342d0c221feSJean-Jacques Hiblot int sd_select_bus_width(struct mmc *mmc, int w) 1343d0c221feSJean-Jacques Hiblot { 1344d0c221feSJean-Jacques Hiblot int err; 1345d0c221feSJean-Jacques Hiblot struct mmc_cmd cmd; 1346d0c221feSJean-Jacques Hiblot 1347d0c221feSJean-Jacques Hiblot if ((w != 4) && (w != 1)) 1348d0c221feSJean-Jacques Hiblot return -EINVAL; 1349d0c221feSJean-Jacques Hiblot 1350d0c221feSJean-Jacques Hiblot cmd.cmdidx = MMC_CMD_APP_CMD; 1351d0c221feSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 1352d0c221feSJean-Jacques Hiblot cmd.cmdarg = mmc->rca << 16; 1353d0c221feSJean-Jacques Hiblot 1354d0c221feSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 1355d0c221feSJean-Jacques Hiblot if (err) 1356d0c221feSJean-Jacques Hiblot return err; 1357d0c221feSJean-Jacques Hiblot 1358d0c221feSJean-Jacques Hiblot cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; 1359d0c221feSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 1360d0c221feSJean-Jacques Hiblot if (w == 4) 1361d0c221feSJean-Jacques Hiblot cmd.cmdarg = 2; 1362d0c221feSJean-Jacques Hiblot else if (w == 1) 1363d0c221feSJean-Jacques Hiblot cmd.cmdarg = 0; 1364d0c221feSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 1365d0c221feSJean-Jacques Hiblot if (err) 1366d0c221feSJean-Jacques Hiblot return err; 1367272cc70bSAndy Fleming 1368272cc70bSAndy Fleming return 0; 1369272cc70bSAndy Fleming } 1370272cc70bSAndy Fleming 13715b2e72f3SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE) 13723697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc) 13733697e599SPeng Fan { 13745b2e72f3SJean-Jacques Hiblot static const unsigned int sd_au_size[] = { 13755b2e72f3SJean-Jacques Hiblot 0, SZ_16K / 512, SZ_32K / 512, 13765b2e72f3SJean-Jacques Hiblot SZ_64K / 512, SZ_128K / 512, SZ_256K / 512, 13775b2e72f3SJean-Jacques Hiblot SZ_512K / 512, SZ_1M / 512, SZ_2M / 512, 13785b2e72f3SJean-Jacques Hiblot SZ_4M / 512, SZ_8M / 512, (SZ_8M + SZ_4M) / 512, 13795b2e72f3SJean-Jacques Hiblot SZ_16M / 512, (SZ_16M + SZ_8M) / 512, SZ_32M / 512, 13805b2e72f3SJean-Jacques Hiblot SZ_64M / 512, 13815b2e72f3SJean-Jacques Hiblot }; 13823697e599SPeng Fan int err, i; 13833697e599SPeng Fan struct mmc_cmd cmd; 13843697e599SPeng Fan ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16); 13853697e599SPeng Fan struct mmc_data data; 13863697e599SPeng Fan int timeout = 3; 13873697e599SPeng Fan unsigned int au, eo, et, es; 13883697e599SPeng Fan 13893697e599SPeng Fan cmd.cmdidx = MMC_CMD_APP_CMD; 13903697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 13913697e599SPeng Fan cmd.cmdarg = mmc->rca << 16; 13923697e599SPeng Fan 13933697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, NULL); 13943697e599SPeng Fan if (err) 13953697e599SPeng Fan return err; 13963697e599SPeng Fan 13973697e599SPeng Fan cmd.cmdidx = SD_CMD_APP_SD_STATUS; 13983697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 13993697e599SPeng Fan cmd.cmdarg = 0; 14003697e599SPeng Fan 14013697e599SPeng Fan retry_ssr: 14023697e599SPeng Fan data.dest = (char *)ssr; 14033697e599SPeng Fan data.blocksize = 64; 14043697e599SPeng Fan data.blocks = 1; 14053697e599SPeng Fan data.flags = MMC_DATA_READ; 14063697e599SPeng Fan 14073697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, &data); 14083697e599SPeng Fan if (err) { 14093697e599SPeng Fan if (timeout--) 14103697e599SPeng Fan goto retry_ssr; 14113697e599SPeng Fan 14123697e599SPeng Fan return err; 14133697e599SPeng Fan } 14143697e599SPeng Fan 14153697e599SPeng Fan for (i = 0; i < 16; i++) 14163697e599SPeng Fan ssr[i] = be32_to_cpu(ssr[i]); 14173697e599SPeng Fan 14183697e599SPeng Fan au = (ssr[2] >> 12) & 0xF; 14193697e599SPeng Fan if ((au <= 9) || (mmc->version == SD_VERSION_3)) { 14203697e599SPeng Fan mmc->ssr.au = sd_au_size[au]; 14213697e599SPeng Fan es = (ssr[3] >> 24) & 0xFF; 14223697e599SPeng Fan es |= (ssr[2] & 0xFF) << 8; 14233697e599SPeng Fan et = (ssr[3] >> 18) & 0x3F; 14243697e599SPeng Fan if (es && et) { 14253697e599SPeng Fan eo = (ssr[3] >> 16) & 0x3; 14263697e599SPeng Fan mmc->ssr.erase_timeout = (et * 1000) / es; 14273697e599SPeng Fan mmc->ssr.erase_offset = eo * 1000; 14283697e599SPeng Fan } 14293697e599SPeng Fan } else { 1430*d4d64889SMasahiro Yamada pr_debug("Invalid Allocation Unit Size.\n"); 14313697e599SPeng Fan } 14323697e599SPeng Fan 14333697e599SPeng Fan return 0; 14343697e599SPeng Fan } 14355b2e72f3SJean-Jacques Hiblot #endif 1436272cc70bSAndy Fleming /* frequency bases */ 1437272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */ 14385f837c2cSMike Frysinger static const int fbase[] = { 1439272cc70bSAndy Fleming 10000, 1440272cc70bSAndy Fleming 100000, 1441272cc70bSAndy Fleming 1000000, 1442272cc70bSAndy Fleming 10000000, 1443272cc70bSAndy Fleming }; 1444272cc70bSAndy Fleming 1445272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice 1446272cc70bSAndy Fleming * to platforms without floating point. 1447272cc70bSAndy Fleming */ 144861fe076fSSimon Glass static const u8 multipliers[] = { 1449272cc70bSAndy Fleming 0, /* reserved */ 1450272cc70bSAndy Fleming 10, 1451272cc70bSAndy Fleming 12, 1452272cc70bSAndy Fleming 13, 1453272cc70bSAndy Fleming 15, 1454272cc70bSAndy Fleming 20, 1455272cc70bSAndy Fleming 25, 1456272cc70bSAndy Fleming 30, 1457272cc70bSAndy Fleming 35, 1458272cc70bSAndy Fleming 40, 1459272cc70bSAndy Fleming 45, 1460272cc70bSAndy Fleming 50, 1461272cc70bSAndy Fleming 55, 1462272cc70bSAndy Fleming 60, 1463272cc70bSAndy Fleming 70, 1464272cc70bSAndy Fleming 80, 1465272cc70bSAndy Fleming }; 1466272cc70bSAndy Fleming 1467d0c221feSJean-Jacques Hiblot static inline int bus_width(uint cap) 1468d0c221feSJean-Jacques Hiblot { 1469d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_8BIT) 1470d0c221feSJean-Jacques Hiblot return 8; 1471d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_4BIT) 1472d0c221feSJean-Jacques Hiblot return 4; 1473d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_1BIT) 1474d0c221feSJean-Jacques Hiblot return 1; 1475d8e3d420SJean-Jacques Hiblot pr_warn("invalid bus witdh capability 0x%x\n", cap); 1476d0c221feSJean-Jacques Hiblot return 0; 1477d0c221feSJean-Jacques Hiblot } 1478d0c221feSJean-Jacques Hiblot 1479e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 1480f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 1481ec841209SKishon Vijay Abraham I static int mmc_execute_tuning(struct mmc *mmc, uint opcode) 1482ec841209SKishon Vijay Abraham I { 1483ec841209SKishon Vijay Abraham I return -ENOTSUPP; 1484ec841209SKishon Vijay Abraham I } 1485f99c2efeSJean-Jacques Hiblot #endif 1486ec841209SKishon Vijay Abraham I 1487318a7a57SJean-Jacques Hiblot static void mmc_send_init_stream(struct mmc *mmc) 1488318a7a57SJean-Jacques Hiblot { 1489318a7a57SJean-Jacques Hiblot } 1490318a7a57SJean-Jacques Hiblot 14912a4d212fSKishon Vijay Abraham I static int mmc_set_ios(struct mmc *mmc) 1492272cc70bSAndy Fleming { 14932a4d212fSKishon Vijay Abraham I int ret = 0; 14942a4d212fSKishon Vijay Abraham I 149593bfd616SPantelis Antoniou if (mmc->cfg->ops->set_ios) 14962a4d212fSKishon Vijay Abraham I ret = mmc->cfg->ops->set_ios(mmc); 14972a4d212fSKishon Vijay Abraham I 14982a4d212fSKishon Vijay Abraham I return ret; 1499272cc70bSAndy Fleming } 15008ca51e51SSimon Glass #endif 1501272cc70bSAndy Fleming 150235f67820SKishon Vijay Abraham I int mmc_set_clock(struct mmc *mmc, uint clock, bool disable) 1503272cc70bSAndy Fleming { 1504c0fafe64SJaehoon Chung if (!disable) { 150593bfd616SPantelis Antoniou if (clock > mmc->cfg->f_max) 150693bfd616SPantelis Antoniou clock = mmc->cfg->f_max; 1507272cc70bSAndy Fleming 150893bfd616SPantelis Antoniou if (clock < mmc->cfg->f_min) 150993bfd616SPantelis Antoniou clock = mmc->cfg->f_min; 15109546eb92SJaehoon Chung } 1511272cc70bSAndy Fleming 1512272cc70bSAndy Fleming mmc->clock = clock; 151335f67820SKishon Vijay Abraham I mmc->clk_disable = disable; 1514272cc70bSAndy Fleming 15152a4d212fSKishon Vijay Abraham I return mmc_set_ios(mmc); 1516272cc70bSAndy Fleming } 1517272cc70bSAndy Fleming 15182a4d212fSKishon Vijay Abraham I static int mmc_set_bus_width(struct mmc *mmc, uint width) 1519272cc70bSAndy Fleming { 1520272cc70bSAndy Fleming mmc->bus_width = width; 1521272cc70bSAndy Fleming 15222a4d212fSKishon Vijay Abraham I return mmc_set_ios(mmc); 1523272cc70bSAndy Fleming } 1524272cc70bSAndy Fleming 15254c9d2aaaSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG) 15264c9d2aaaSJean-Jacques Hiblot /* 15274c9d2aaaSJean-Jacques Hiblot * helper function to display the capabilities in a human 15284c9d2aaaSJean-Jacques Hiblot * friendly manner. The capabilities include bus width and 15294c9d2aaaSJean-Jacques Hiblot * supported modes. 15304c9d2aaaSJean-Jacques Hiblot */ 15314c9d2aaaSJean-Jacques Hiblot void mmc_dump_capabilities(const char *text, uint caps) 15324c9d2aaaSJean-Jacques Hiblot { 15334c9d2aaaSJean-Jacques Hiblot enum bus_mode mode; 15344c9d2aaaSJean-Jacques Hiblot 1535*d4d64889SMasahiro Yamada pr_debug("%s: widths [", text); 15364c9d2aaaSJean-Jacques Hiblot if (caps & MMC_MODE_8BIT) 1537*d4d64889SMasahiro Yamada pr_debug("8, "); 15384c9d2aaaSJean-Jacques Hiblot if (caps & MMC_MODE_4BIT) 1539*d4d64889SMasahiro Yamada pr_debug("4, "); 1540d0c221feSJean-Jacques Hiblot if (caps & MMC_MODE_1BIT) 1541*d4d64889SMasahiro Yamada pr_debug("1, "); 1542*d4d64889SMasahiro Yamada pr_debug("\b\b] modes ["); 15434c9d2aaaSJean-Jacques Hiblot for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++) 15444c9d2aaaSJean-Jacques Hiblot if (MMC_CAP(mode) & caps) 1545*d4d64889SMasahiro Yamada pr_debug("%s, ", mmc_mode_name(mode)); 1546*d4d64889SMasahiro Yamada pr_debug("\b\b]\n"); 15474c9d2aaaSJean-Jacques Hiblot } 15484c9d2aaaSJean-Jacques Hiblot #endif 15494c9d2aaaSJean-Jacques Hiblot 1550d0c221feSJean-Jacques Hiblot struct mode_width_tuning { 1551d0c221feSJean-Jacques Hiblot enum bus_mode mode; 1552d0c221feSJean-Jacques Hiblot uint widths; 1553f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 1554634d4849SKishon Vijay Abraham I uint tuning; 1555f99c2efeSJean-Jacques Hiblot #endif 1556d0c221feSJean-Jacques Hiblot }; 1557d0c221feSJean-Jacques Hiblot 1558f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE) 1559bc1e3272SJean-Jacques Hiblot int mmc_voltage_to_mv(enum mmc_voltage voltage) 1560bc1e3272SJean-Jacques Hiblot { 1561bc1e3272SJean-Jacques Hiblot switch (voltage) { 1562bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_000: return 0; 1563bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_330: return 3300; 1564bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_180: return 1800; 1565bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_120: return 1200; 1566bc1e3272SJean-Jacques Hiblot } 1567bc1e3272SJean-Jacques Hiblot return -EINVAL; 1568bc1e3272SJean-Jacques Hiblot } 1569bc1e3272SJean-Jacques Hiblot 1570aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage) 1571aff5d3c8SKishon Vijay Abraham I { 1572bc1e3272SJean-Jacques Hiblot int err; 1573bc1e3272SJean-Jacques Hiblot 1574bc1e3272SJean-Jacques Hiblot if (mmc->signal_voltage == signal_voltage) 1575bc1e3272SJean-Jacques Hiblot return 0; 1576bc1e3272SJean-Jacques Hiblot 1577aff5d3c8SKishon Vijay Abraham I mmc->signal_voltage = signal_voltage; 1578bc1e3272SJean-Jacques Hiblot err = mmc_set_ios(mmc); 1579bc1e3272SJean-Jacques Hiblot if (err) 1580*d4d64889SMasahiro Yamada pr_debug("unable to set voltage (err %d)\n", err); 1581bc1e3272SJean-Jacques Hiblot 1582bc1e3272SJean-Jacques Hiblot return err; 1583aff5d3c8SKishon Vijay Abraham I } 1584f99c2efeSJean-Jacques Hiblot #else 1585f99c2efeSJean-Jacques Hiblot static inline int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage) 1586f99c2efeSJean-Jacques Hiblot { 1587f99c2efeSJean-Jacques Hiblot return 0; 1588f99c2efeSJean-Jacques Hiblot } 1589f99c2efeSJean-Jacques Hiblot #endif 1590aff5d3c8SKishon Vijay Abraham I 1591d0c221feSJean-Jacques Hiblot static const struct mode_width_tuning sd_modes_by_pref[] = { 1592f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1593f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 1594d0c221feSJean-Jacques Hiblot { 1595c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR104, 1596c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1597c10b85d6SJean-Jacques Hiblot .tuning = MMC_CMD_SEND_TUNING_BLOCK 1598c10b85d6SJean-Jacques Hiblot }, 1599f99c2efeSJean-Jacques Hiblot #endif 1600c10b85d6SJean-Jacques Hiblot { 1601c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR50, 1602c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1603c10b85d6SJean-Jacques Hiblot }, 1604c10b85d6SJean-Jacques Hiblot { 1605c10b85d6SJean-Jacques Hiblot .mode = UHS_DDR50, 1606c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1607c10b85d6SJean-Jacques Hiblot }, 1608c10b85d6SJean-Jacques Hiblot { 1609c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR25, 1610c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1611c10b85d6SJean-Jacques Hiblot }, 1612f99c2efeSJean-Jacques Hiblot #endif 1613c10b85d6SJean-Jacques Hiblot { 1614d0c221feSJean-Jacques Hiblot .mode = SD_HS, 1615d0c221feSJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1616d0c221feSJean-Jacques Hiblot }, 1617f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1618d0c221feSJean-Jacques Hiblot { 1619c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR12, 1620c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1621c10b85d6SJean-Jacques Hiblot }, 1622f99c2efeSJean-Jacques Hiblot #endif 1623c10b85d6SJean-Jacques Hiblot { 1624d0c221feSJean-Jacques Hiblot .mode = SD_LEGACY, 1625d0c221feSJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1626d0c221feSJean-Jacques Hiblot } 1627d0c221feSJean-Jacques Hiblot }; 1628d0c221feSJean-Jacques Hiblot 1629d0c221feSJean-Jacques Hiblot #define for_each_sd_mode_by_pref(caps, mwt) \ 1630d0c221feSJean-Jacques Hiblot for (mwt = sd_modes_by_pref;\ 1631d0c221feSJean-Jacques Hiblot mwt < sd_modes_by_pref + ARRAY_SIZE(sd_modes_by_pref);\ 1632d0c221feSJean-Jacques Hiblot mwt++) \ 1633d0c221feSJean-Jacques Hiblot if (caps & MMC_CAP(mwt->mode)) 1634d0c221feSJean-Jacques Hiblot 163501298da3SJean-Jacques Hiblot static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps) 16368ac8a263SJean-Jacques Hiblot { 16378ac8a263SJean-Jacques Hiblot int err; 1638d0c221feSJean-Jacques Hiblot uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT}; 1639d0c221feSJean-Jacques Hiblot const struct mode_width_tuning *mwt; 1640f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1641c10b85d6SJean-Jacques Hiblot bool uhs_en = (mmc->ocr & OCR_S18R) ? true : false; 1642f99c2efeSJean-Jacques Hiblot #else 1643f99c2efeSJean-Jacques Hiblot bool uhs_en = false; 1644f99c2efeSJean-Jacques Hiblot #endif 1645c10b85d6SJean-Jacques Hiblot uint caps; 1646c10b85d6SJean-Jacques Hiblot 164752d241dfSJean-Jacques Hiblot #ifdef DEBUG 164852d241dfSJean-Jacques Hiblot mmc_dump_capabilities("sd card", card_caps); 16491da8eb59SJean-Jacques Hiblot mmc_dump_capabilities("host", mmc->host_caps); 165052d241dfSJean-Jacques Hiblot #endif 16518ac8a263SJean-Jacques Hiblot 16528ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */ 16531da8eb59SJean-Jacques Hiblot caps = card_caps & mmc->host_caps; 16548ac8a263SJean-Jacques Hiblot 1655c10b85d6SJean-Jacques Hiblot if (!uhs_en) 1656c10b85d6SJean-Jacques Hiblot caps &= ~UHS_CAPS; 1657c10b85d6SJean-Jacques Hiblot 1658c10b85d6SJean-Jacques Hiblot for_each_sd_mode_by_pref(caps, mwt) { 1659d0c221feSJean-Jacques Hiblot uint *w; 16608ac8a263SJean-Jacques Hiblot 1661d0c221feSJean-Jacques Hiblot for (w = widths; w < widths + ARRAY_SIZE(widths); w++) { 1662c10b85d6SJean-Jacques Hiblot if (*w & caps & mwt->widths) { 1663*d4d64889SMasahiro Yamada pr_debug("trying mode %s width %d (at %d MHz)\n", 1664d0c221feSJean-Jacques Hiblot mmc_mode_name(mwt->mode), 1665d0c221feSJean-Jacques Hiblot bus_width(*w), 1666d0c221feSJean-Jacques Hiblot mmc_mode2freq(mmc, mwt->mode) / 1000000); 1667d0c221feSJean-Jacques Hiblot 1668d0c221feSJean-Jacques Hiblot /* configure the bus width (card + host) */ 1669d0c221feSJean-Jacques Hiblot err = sd_select_bus_width(mmc, bus_width(*w)); 16708ac8a263SJean-Jacques Hiblot if (err) 1671d0c221feSJean-Jacques Hiblot goto error; 1672d0c221feSJean-Jacques Hiblot mmc_set_bus_width(mmc, bus_width(*w)); 16738ac8a263SJean-Jacques Hiblot 1674d0c221feSJean-Jacques Hiblot /* configure the bus mode (card) */ 1675d0c221feSJean-Jacques Hiblot err = sd_set_card_speed(mmc, mwt->mode); 16768ac8a263SJean-Jacques Hiblot if (err) 1677d0c221feSJean-Jacques Hiblot goto error; 16788ac8a263SJean-Jacques Hiblot 1679d0c221feSJean-Jacques Hiblot /* configure the bus mode (host) */ 1680d0c221feSJean-Jacques Hiblot mmc_select_mode(mmc, mwt->mode); 168135f67820SKishon Vijay Abraham I mmc_set_clock(mmc, mmc->tran_speed, false); 16828ac8a263SJean-Jacques Hiblot 1683f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 1684c10b85d6SJean-Jacques Hiblot /* execute tuning if needed */ 1685c10b85d6SJean-Jacques Hiblot if (mwt->tuning && !mmc_host_is_spi(mmc)) { 1686c10b85d6SJean-Jacques Hiblot err = mmc_execute_tuning(mmc, 1687c10b85d6SJean-Jacques Hiblot mwt->tuning); 1688c10b85d6SJean-Jacques Hiblot if (err) { 1689*d4d64889SMasahiro Yamada pr_debug("tuning failed\n"); 1690c10b85d6SJean-Jacques Hiblot goto error; 1691c10b85d6SJean-Jacques Hiblot } 1692c10b85d6SJean-Jacques Hiblot } 1693f99c2efeSJean-Jacques Hiblot #endif 1694c10b85d6SJean-Jacques Hiblot 16955b2e72f3SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE) 16968ac8a263SJean-Jacques Hiblot err = sd_read_ssr(mmc); 1697d0c221feSJean-Jacques Hiblot if (!err) 16985b2e72f3SJean-Jacques Hiblot pr_warn("unable to read ssr\n"); 16995b2e72f3SJean-Jacques Hiblot #endif 17005b2e72f3SJean-Jacques Hiblot if (!err) 17018ac8a263SJean-Jacques Hiblot return 0; 1702d0c221feSJean-Jacques Hiblot 1703d0c221feSJean-Jacques Hiblot error: 1704d0c221feSJean-Jacques Hiblot /* revert to a safer bus speed */ 1705d0c221feSJean-Jacques Hiblot mmc_select_mode(mmc, SD_LEGACY); 170635f67820SKishon Vijay Abraham I mmc_set_clock(mmc, mmc->tran_speed, false); 1707d0c221feSJean-Jacques Hiblot } 1708d0c221feSJean-Jacques Hiblot } 1709d0c221feSJean-Jacques Hiblot } 1710d0c221feSJean-Jacques Hiblot 1711*d4d64889SMasahiro Yamada pr_err("unable to select a mode\n"); 1712d0c221feSJean-Jacques Hiblot return -ENOTSUPP; 17138ac8a263SJean-Jacques Hiblot } 17148ac8a263SJean-Jacques Hiblot 17157382e691SJean-Jacques Hiblot /* 17167382e691SJean-Jacques Hiblot * read the compare the part of ext csd that is constant. 17177382e691SJean-Jacques Hiblot * This can be used to check that the transfer is working 17187382e691SJean-Jacques Hiblot * as expected. 17197382e691SJean-Jacques Hiblot */ 17207382e691SJean-Jacques Hiblot static int mmc_read_and_compare_ext_csd(struct mmc *mmc) 17217382e691SJean-Jacques Hiblot { 17227382e691SJean-Jacques Hiblot int err; 17237382e691SJean-Jacques Hiblot const u8 *ext_csd = mmc->ext_csd; 17247382e691SJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 17257382e691SJean-Jacques Hiblot 17261de06b9fSJean-Jacques Hiblot if (mmc->version < MMC_VERSION_4) 17271de06b9fSJean-Jacques Hiblot return 0; 17281de06b9fSJean-Jacques Hiblot 17297382e691SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, test_csd); 17307382e691SJean-Jacques Hiblot if (err) 17317382e691SJean-Jacques Hiblot return err; 17327382e691SJean-Jacques Hiblot 17337382e691SJean-Jacques Hiblot /* Only compare read only fields */ 17347382e691SJean-Jacques Hiblot if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] 17357382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_PARTITIONING_SUPPORT] && 17367382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_WP_GRP_SIZE] 17377382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_WP_GRP_SIZE] && 17387382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_REV] 17397382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_REV] && 17407382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 17417382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] && 17427382e691SJean-Jacques Hiblot memcmp(&ext_csd[EXT_CSD_SEC_CNT], 17437382e691SJean-Jacques Hiblot &test_csd[EXT_CSD_SEC_CNT], 4) == 0) 17447382e691SJean-Jacques Hiblot return 0; 17457382e691SJean-Jacques Hiblot 17467382e691SJean-Jacques Hiblot return -EBADMSG; 17477382e691SJean-Jacques Hiblot } 17487382e691SJean-Jacques Hiblot 1749f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE) 1750bc1e3272SJean-Jacques Hiblot static int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode, 1751bc1e3272SJean-Jacques Hiblot uint32_t allowed_mask) 1752bc1e3272SJean-Jacques Hiblot { 1753bc1e3272SJean-Jacques Hiblot u32 card_mask = 0; 1754bc1e3272SJean-Jacques Hiblot 1755bc1e3272SJean-Jacques Hiblot switch (mode) { 1756bc1e3272SJean-Jacques Hiblot case MMC_HS_200: 1757bc1e3272SJean-Jacques Hiblot if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_8V) 1758bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_180; 1759bc1e3272SJean-Jacques Hiblot if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_2V) 1760bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_120; 1761bc1e3272SJean-Jacques Hiblot break; 1762bc1e3272SJean-Jacques Hiblot case MMC_DDR_52: 1763bc1e3272SJean-Jacques Hiblot if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V) 1764bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_330 | 1765bc1e3272SJean-Jacques Hiblot MMC_SIGNAL_VOLTAGE_180; 1766bc1e3272SJean-Jacques Hiblot if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_2V) 1767bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_120; 1768bc1e3272SJean-Jacques Hiblot break; 1769bc1e3272SJean-Jacques Hiblot default: 1770bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_330; 1771bc1e3272SJean-Jacques Hiblot break; 1772bc1e3272SJean-Jacques Hiblot } 1773bc1e3272SJean-Jacques Hiblot 1774bc1e3272SJean-Jacques Hiblot while (card_mask & allowed_mask) { 1775bc1e3272SJean-Jacques Hiblot enum mmc_voltage best_match; 1776bc1e3272SJean-Jacques Hiblot 1777bc1e3272SJean-Jacques Hiblot best_match = 1 << (ffs(card_mask & allowed_mask) - 1); 1778bc1e3272SJean-Jacques Hiblot if (!mmc_set_signal_voltage(mmc, best_match)) 1779bc1e3272SJean-Jacques Hiblot return 0; 1780bc1e3272SJean-Jacques Hiblot 1781bc1e3272SJean-Jacques Hiblot allowed_mask &= ~best_match; 1782bc1e3272SJean-Jacques Hiblot } 1783bc1e3272SJean-Jacques Hiblot 1784bc1e3272SJean-Jacques Hiblot return -ENOTSUPP; 1785bc1e3272SJean-Jacques Hiblot } 1786f99c2efeSJean-Jacques Hiblot #else 1787f99c2efeSJean-Jacques Hiblot static inline int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode, 1788f99c2efeSJean-Jacques Hiblot uint32_t allowed_mask) 1789f99c2efeSJean-Jacques Hiblot { 1790f99c2efeSJean-Jacques Hiblot return 0; 1791f99c2efeSJean-Jacques Hiblot } 1792f99c2efeSJean-Jacques Hiblot #endif 1793bc1e3272SJean-Jacques Hiblot 17943862b854SJean-Jacques Hiblot static const struct mode_width_tuning mmc_modes_by_pref[] = { 1795f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) 17968ac8a263SJean-Jacques Hiblot { 17973862b854SJean-Jacques Hiblot .mode = MMC_HS_200, 17983862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT, 1799634d4849SKishon Vijay Abraham I .tuning = MMC_CMD_SEND_TUNING_BLOCK_HS200 18003862b854SJean-Jacques Hiblot }, 1801f99c2efeSJean-Jacques Hiblot #endif 18023862b854SJean-Jacques Hiblot { 18033862b854SJean-Jacques Hiblot .mode = MMC_DDR_52, 18043862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT, 18053862b854SJean-Jacques Hiblot }, 18063862b854SJean-Jacques Hiblot { 18073862b854SJean-Jacques Hiblot .mode = MMC_HS_52, 18083862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 18093862b854SJean-Jacques Hiblot }, 18103862b854SJean-Jacques Hiblot { 18113862b854SJean-Jacques Hiblot .mode = MMC_HS, 18123862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 18133862b854SJean-Jacques Hiblot }, 18143862b854SJean-Jacques Hiblot { 18153862b854SJean-Jacques Hiblot .mode = MMC_LEGACY, 18163862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 18173862b854SJean-Jacques Hiblot } 18188ac8a263SJean-Jacques Hiblot }; 18198ac8a263SJean-Jacques Hiblot 18203862b854SJean-Jacques Hiblot #define for_each_mmc_mode_by_pref(caps, mwt) \ 18213862b854SJean-Jacques Hiblot for (mwt = mmc_modes_by_pref;\ 18223862b854SJean-Jacques Hiblot mwt < mmc_modes_by_pref + ARRAY_SIZE(mmc_modes_by_pref);\ 18233862b854SJean-Jacques Hiblot mwt++) \ 18243862b854SJean-Jacques Hiblot if (caps & MMC_CAP(mwt->mode)) 18253862b854SJean-Jacques Hiblot 18263862b854SJean-Jacques Hiblot static const struct ext_csd_bus_width { 18273862b854SJean-Jacques Hiblot uint cap; 18283862b854SJean-Jacques Hiblot bool is_ddr; 18293862b854SJean-Jacques Hiblot uint ext_csd_bits; 18303862b854SJean-Jacques Hiblot } ext_csd_bus_width[] = { 18313862b854SJean-Jacques Hiblot {MMC_MODE_8BIT, true, EXT_CSD_DDR_BUS_WIDTH_8}, 18323862b854SJean-Jacques Hiblot {MMC_MODE_4BIT, true, EXT_CSD_DDR_BUS_WIDTH_4}, 18333862b854SJean-Jacques Hiblot {MMC_MODE_8BIT, false, EXT_CSD_BUS_WIDTH_8}, 18343862b854SJean-Jacques Hiblot {MMC_MODE_4BIT, false, EXT_CSD_BUS_WIDTH_4}, 18353862b854SJean-Jacques Hiblot {MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1}, 18363862b854SJean-Jacques Hiblot }; 18373862b854SJean-Jacques Hiblot 18383862b854SJean-Jacques Hiblot #define for_each_supported_width(caps, ddr, ecbv) \ 18393862b854SJean-Jacques Hiblot for (ecbv = ext_csd_bus_width;\ 18403862b854SJean-Jacques Hiblot ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\ 18413862b854SJean-Jacques Hiblot ecbv++) \ 18423862b854SJean-Jacques Hiblot if ((ddr == ecbv->is_ddr) && (caps & ecbv->cap)) 18433862b854SJean-Jacques Hiblot 184401298da3SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps) 18453862b854SJean-Jacques Hiblot { 18463862b854SJean-Jacques Hiblot int err; 18473862b854SJean-Jacques Hiblot const struct mode_width_tuning *mwt; 18483862b854SJean-Jacques Hiblot const struct ext_csd_bus_width *ecbw; 18493862b854SJean-Jacques Hiblot 185052d241dfSJean-Jacques Hiblot #ifdef DEBUG 185152d241dfSJean-Jacques Hiblot mmc_dump_capabilities("mmc", card_caps); 18521da8eb59SJean-Jacques Hiblot mmc_dump_capabilities("host", mmc->host_caps); 185352d241dfSJean-Jacques Hiblot #endif 185452d241dfSJean-Jacques Hiblot 18558ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */ 18561da8eb59SJean-Jacques Hiblot card_caps &= mmc->host_caps; 18578ac8a263SJean-Jacques Hiblot 18588ac8a263SJean-Jacques Hiblot /* Only version 4 of MMC supports wider bus widths */ 18598ac8a263SJean-Jacques Hiblot if (mmc->version < MMC_VERSION_4) 18608ac8a263SJean-Jacques Hiblot return 0; 18618ac8a263SJean-Jacques Hiblot 1862dfda9d88SJean-Jacques Hiblot if (!mmc->ext_csd) { 1863*d4d64889SMasahiro Yamada pr_debug("No ext_csd found!\n"); /* this should enver happen */ 1864dfda9d88SJean-Jacques Hiblot return -ENOTSUPP; 1865dfda9d88SJean-Jacques Hiblot } 1866dfda9d88SJean-Jacques Hiblot 186701298da3SJean-Jacques Hiblot mmc_set_clock(mmc, mmc->legacy_speed, false); 186801298da3SJean-Jacques Hiblot 186901298da3SJean-Jacques Hiblot for_each_mmc_mode_by_pref(card_caps, mwt) { 187001298da3SJean-Jacques Hiblot for_each_supported_width(card_caps & mwt->widths, 18713862b854SJean-Jacques Hiblot mmc_is_mode_ddr(mwt->mode), ecbw) { 1872bc1e3272SJean-Jacques Hiblot enum mmc_voltage old_voltage; 1873*d4d64889SMasahiro Yamada pr_debug("trying mode %s width %d (at %d MHz)\n", 18743862b854SJean-Jacques Hiblot mmc_mode_name(mwt->mode), 18753862b854SJean-Jacques Hiblot bus_width(ecbw->cap), 18763862b854SJean-Jacques Hiblot mmc_mode2freq(mmc, mwt->mode) / 1000000); 1877bc1e3272SJean-Jacques Hiblot old_voltage = mmc->signal_voltage; 1878bc1e3272SJean-Jacques Hiblot err = mmc_set_lowest_voltage(mmc, mwt->mode, 1879bc1e3272SJean-Jacques Hiblot MMC_ALL_SIGNAL_VOLTAGE); 1880bc1e3272SJean-Jacques Hiblot if (err) 1881bc1e3272SJean-Jacques Hiblot continue; 1882bc1e3272SJean-Jacques Hiblot 18833862b854SJean-Jacques Hiblot /* configure the bus width (card + host) */ 18843862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 18853862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, 18863862b854SJean-Jacques Hiblot ecbw->ext_csd_bits & ~EXT_CSD_DDR_FLAG); 18873862b854SJean-Jacques Hiblot if (err) 18883862b854SJean-Jacques Hiblot goto error; 18893862b854SJean-Jacques Hiblot mmc_set_bus_width(mmc, bus_width(ecbw->cap)); 18903862b854SJean-Jacques Hiblot 18913862b854SJean-Jacques Hiblot /* configure the bus speed (card) */ 18923862b854SJean-Jacques Hiblot err = mmc_set_card_speed(mmc, mwt->mode); 18933862b854SJean-Jacques Hiblot if (err) 18943862b854SJean-Jacques Hiblot goto error; 18953862b854SJean-Jacques Hiblot 18968ac8a263SJean-Jacques Hiblot /* 18973862b854SJean-Jacques Hiblot * configure the bus width AND the ddr mode (card) 18983862b854SJean-Jacques Hiblot * The host side will be taken care of in the next step 18998ac8a263SJean-Jacques Hiblot */ 19003862b854SJean-Jacques Hiblot if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) { 19013862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 19023862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, 19033862b854SJean-Jacques Hiblot ecbw->ext_csd_bits); 19043862b854SJean-Jacques Hiblot if (err) 19053862b854SJean-Jacques Hiblot goto error; 19068ac8a263SJean-Jacques Hiblot } 19078ac8a263SJean-Jacques Hiblot 19083862b854SJean-Jacques Hiblot /* configure the bus mode (host) */ 19093862b854SJean-Jacques Hiblot mmc_select_mode(mmc, mwt->mode); 191035f67820SKishon Vijay Abraham I mmc_set_clock(mmc, mmc->tran_speed, false); 1911f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 19128ac8a263SJean-Jacques Hiblot 1913634d4849SKishon Vijay Abraham I /* execute tuning if needed */ 1914634d4849SKishon Vijay Abraham I if (mwt->tuning) { 1915634d4849SKishon Vijay Abraham I err = mmc_execute_tuning(mmc, mwt->tuning); 1916634d4849SKishon Vijay Abraham I if (err) { 1917*d4d64889SMasahiro Yamada pr_debug("tuning failed\n"); 1918634d4849SKishon Vijay Abraham I goto error; 1919634d4849SKishon Vijay Abraham I } 1920634d4849SKishon Vijay Abraham I } 1921f99c2efeSJean-Jacques Hiblot #endif 1922634d4849SKishon Vijay Abraham I 19233862b854SJean-Jacques Hiblot /* do a transfer to check the configuration */ 19247382e691SJean-Jacques Hiblot err = mmc_read_and_compare_ext_csd(mmc); 19257382e691SJean-Jacques Hiblot if (!err) 19263862b854SJean-Jacques Hiblot return 0; 19273862b854SJean-Jacques Hiblot error: 1928bc1e3272SJean-Jacques Hiblot mmc_set_signal_voltage(mmc, old_voltage); 19293862b854SJean-Jacques Hiblot /* if an error occured, revert to a safer bus mode */ 19303862b854SJean-Jacques Hiblot mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 19313862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1); 19323862b854SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_LEGACY); 19333862b854SJean-Jacques Hiblot mmc_set_bus_width(mmc, 1); 19343862b854SJean-Jacques Hiblot } 19358ac8a263SJean-Jacques Hiblot } 19368ac8a263SJean-Jacques Hiblot 1937d8e3d420SJean-Jacques Hiblot pr_err("unable to select a mode\n"); 19388ac8a263SJean-Jacques Hiblot 19393862b854SJean-Jacques Hiblot return -ENOTSUPP; 19408ac8a263SJean-Jacques Hiblot } 19418ac8a263SJean-Jacques Hiblot 1942dfda9d88SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc) 1943c744b6f6SJean-Jacques Hiblot { 1944c744b6f6SJean-Jacques Hiblot int err, i; 1945c744b6f6SJean-Jacques Hiblot u64 capacity; 1946c744b6f6SJean-Jacques Hiblot bool has_parts = false; 1947c744b6f6SJean-Jacques Hiblot bool part_completed; 194858a6fb7bSJean-Jacques Hiblot static const u32 mmc_versions[] = { 194958a6fb7bSJean-Jacques Hiblot MMC_VERSION_4, 195058a6fb7bSJean-Jacques Hiblot MMC_VERSION_4_1, 195158a6fb7bSJean-Jacques Hiblot MMC_VERSION_4_2, 195258a6fb7bSJean-Jacques Hiblot MMC_VERSION_4_3, 195358a6fb7bSJean-Jacques Hiblot MMC_VERSION_4_41, 195458a6fb7bSJean-Jacques Hiblot MMC_VERSION_4_5, 195558a6fb7bSJean-Jacques Hiblot MMC_VERSION_5_0, 195658a6fb7bSJean-Jacques Hiblot MMC_VERSION_5_1 195758a6fb7bSJean-Jacques Hiblot }; 195858a6fb7bSJean-Jacques Hiblot 1959f7d5dffcSJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 1960c744b6f6SJean-Jacques Hiblot 1961c744b6f6SJean-Jacques Hiblot if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4)) 1962c744b6f6SJean-Jacques Hiblot return 0; 1963c744b6f6SJean-Jacques Hiblot 1964c744b6f6SJean-Jacques Hiblot /* check ext_csd version and capacity */ 1965c744b6f6SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, ext_csd); 1966c744b6f6SJean-Jacques Hiblot if (err) 1967f7d5dffcSJean-Jacques Hiblot goto error; 1968f7d5dffcSJean-Jacques Hiblot 1969f7d5dffcSJean-Jacques Hiblot /* store the ext csd for future reference */ 1970f7d5dffcSJean-Jacques Hiblot if (!mmc->ext_csd) 1971f7d5dffcSJean-Jacques Hiblot mmc->ext_csd = malloc(MMC_MAX_BLOCK_LEN); 1972f7d5dffcSJean-Jacques Hiblot if (!mmc->ext_csd) 1973f7d5dffcSJean-Jacques Hiblot return -ENOMEM; 1974f7d5dffcSJean-Jacques Hiblot memcpy(mmc->ext_csd, ext_csd, MMC_MAX_BLOCK_LEN); 1975f7d5dffcSJean-Jacques Hiblot 197658a6fb7bSJean-Jacques Hiblot if (ext_csd[EXT_CSD_REV] > ARRAY_SIZE(mmc_versions)) 197758a6fb7bSJean-Jacques Hiblot return -EINVAL; 197858a6fb7bSJean-Jacques Hiblot 197958a6fb7bSJean-Jacques Hiblot mmc->version = mmc_versions[ext_csd[EXT_CSD_REV]]; 198058a6fb7bSJean-Jacques Hiblot 198158a6fb7bSJean-Jacques Hiblot if (mmc->version >= MMC_VERSION_4_2) { 1982c744b6f6SJean-Jacques Hiblot /* 1983c744b6f6SJean-Jacques Hiblot * According to the JEDEC Standard, the value of 1984c744b6f6SJean-Jacques Hiblot * ext_csd's capacity is valid if the value is more 1985c744b6f6SJean-Jacques Hiblot * than 2GB 1986c744b6f6SJean-Jacques Hiblot */ 1987c744b6f6SJean-Jacques Hiblot capacity = ext_csd[EXT_CSD_SEC_CNT] << 0 1988c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 1989c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 1990c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; 1991c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN; 1992c744b6f6SJean-Jacques Hiblot if ((capacity >> 20) > 2 * 1024) 1993c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity; 1994c744b6f6SJean-Jacques Hiblot } 1995c744b6f6SJean-Jacques Hiblot 1996c744b6f6SJean-Jacques Hiblot /* The partition data may be non-zero but it is only 1997c744b6f6SJean-Jacques Hiblot * effective if PARTITION_SETTING_COMPLETED is set in 1998c744b6f6SJean-Jacques Hiblot * EXT_CSD, so ignore any data if this bit is not set, 1999c744b6f6SJean-Jacques Hiblot * except for enabling the high-capacity group size 2000c744b6f6SJean-Jacques Hiblot * definition (see below). 2001c744b6f6SJean-Jacques Hiblot */ 2002c744b6f6SJean-Jacques Hiblot part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] & 2003c744b6f6SJean-Jacques Hiblot EXT_CSD_PARTITION_SETTING_COMPLETED); 2004c744b6f6SJean-Jacques Hiblot 2005c744b6f6SJean-Jacques Hiblot /* store the partition info of emmc */ 2006c744b6f6SJean-Jacques Hiblot mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT]; 2007c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || 2008c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_BOOT_MULT]) 2009c744b6f6SJean-Jacques Hiblot mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; 2010c744b6f6SJean-Jacques Hiblot if (part_completed && 2011c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT)) 2012c744b6f6SJean-Jacques Hiblot mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]; 2013c744b6f6SJean-Jacques Hiblot 2014c744b6f6SJean-Jacques Hiblot mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17; 2015c744b6f6SJean-Jacques Hiblot 2016c744b6f6SJean-Jacques Hiblot mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17; 2017c744b6f6SJean-Jacques Hiblot 2018c744b6f6SJean-Jacques Hiblot for (i = 0; i < 4; i++) { 2019c744b6f6SJean-Jacques Hiblot int idx = EXT_CSD_GP_SIZE_MULT + i * 3; 2020c744b6f6SJean-Jacques Hiblot uint mult = (ext_csd[idx + 2] << 16) + 2021c744b6f6SJean-Jacques Hiblot (ext_csd[idx + 1] << 8) + ext_csd[idx]; 2022c744b6f6SJean-Jacques Hiblot if (mult) 2023c744b6f6SJean-Jacques Hiblot has_parts = true; 2024c744b6f6SJean-Jacques Hiblot if (!part_completed) 2025c744b6f6SJean-Jacques Hiblot continue; 2026c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] = mult; 2027c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= 2028c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 2029c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 2030c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] <<= 19; 2031c744b6f6SJean-Jacques Hiblot } 2032c744b6f6SJean-Jacques Hiblot 2033173c06dfSJean-Jacques Hiblot #ifndef CONFIG_SPL_BUILD 2034c744b6f6SJean-Jacques Hiblot if (part_completed) { 2035c744b6f6SJean-Jacques Hiblot mmc->enh_user_size = 2036c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) + 2037c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) + 2038c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_SIZE_MULT]; 2039c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 2040c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 2041c744b6f6SJean-Jacques Hiblot mmc->enh_user_size <<= 19; 2042c744b6f6SJean-Jacques Hiblot mmc->enh_user_start = 2043c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) + 2044c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) + 2045c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) + 2046c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_START_ADDR]; 2047c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity) 2048c744b6f6SJean-Jacques Hiblot mmc->enh_user_start <<= 9; 2049c744b6f6SJean-Jacques Hiblot } 2050173c06dfSJean-Jacques Hiblot #endif 2051c744b6f6SJean-Jacques Hiblot 2052c744b6f6SJean-Jacques Hiblot /* 2053c744b6f6SJean-Jacques Hiblot * Host needs to enable ERASE_GRP_DEF bit if device is 2054c744b6f6SJean-Jacques Hiblot * partitioned. This bit will be lost every time after a reset 2055c744b6f6SJean-Jacques Hiblot * or power off. This will affect erase size. 2056c744b6f6SJean-Jacques Hiblot */ 2057c744b6f6SJean-Jacques Hiblot if (part_completed) 2058c744b6f6SJean-Jacques Hiblot has_parts = true; 2059c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) && 2060c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) 2061c744b6f6SJean-Jacques Hiblot has_parts = true; 2062c744b6f6SJean-Jacques Hiblot if (has_parts) { 2063c744b6f6SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 2064c744b6f6SJean-Jacques Hiblot EXT_CSD_ERASE_GROUP_DEF, 1); 2065c744b6f6SJean-Jacques Hiblot 2066c744b6f6SJean-Jacques Hiblot if (err) 2067f7d5dffcSJean-Jacques Hiblot goto error; 2068c744b6f6SJean-Jacques Hiblot 2069c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 2070c744b6f6SJean-Jacques Hiblot } 2071c744b6f6SJean-Jacques Hiblot 2072c744b6f6SJean-Jacques Hiblot if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) { 2073e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE) 2074c744b6f6SJean-Jacques Hiblot /* Read out group size from ext_csd */ 2075c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = 2076c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 2077e6fa5a54SJean-Jacques Hiblot #endif 2078c744b6f6SJean-Jacques Hiblot /* 2079c744b6f6SJean-Jacques Hiblot * if high capacity and partition setting completed 2080c744b6f6SJean-Jacques Hiblot * SEC_COUNT is valid even if it is smaller than 2 GiB 2081c744b6f6SJean-Jacques Hiblot * JEDEC Standard JESD84-B45, 6.2.4 2082c744b6f6SJean-Jacques Hiblot */ 2083c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity && part_completed) { 2084c744b6f6SJean-Jacques Hiblot capacity = (ext_csd[EXT_CSD_SEC_CNT]) | 2085c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) | 2086c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) | 2087c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 3] << 24); 2088c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN; 2089c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity; 2090c744b6f6SJean-Jacques Hiblot } 2091e6fa5a54SJean-Jacques Hiblot } 2092e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE) 2093e6fa5a54SJean-Jacques Hiblot else { 2094c744b6f6SJean-Jacques Hiblot /* Calculate the group size from the csd value. */ 2095c744b6f6SJean-Jacques Hiblot int erase_gsz, erase_gmul; 2096c744b6f6SJean-Jacques Hiblot 2097c744b6f6SJean-Jacques Hiblot erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; 2098c744b6f6SJean-Jacques Hiblot erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; 2099c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = (erase_gsz + 1) 2100c744b6f6SJean-Jacques Hiblot * (erase_gmul + 1); 2101c744b6f6SJean-Jacques Hiblot } 2102e6fa5a54SJean-Jacques Hiblot #endif 2103b7a6e2c9SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING) 2104c744b6f6SJean-Jacques Hiblot mmc->hc_wp_grp_size = 1024 2105c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 2106c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 2107b7a6e2c9SJean-Jacques Hiblot #endif 2108c744b6f6SJean-Jacques Hiblot 2109c744b6f6SJean-Jacques Hiblot mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 2110c744b6f6SJean-Jacques Hiblot 2111c744b6f6SJean-Jacques Hiblot return 0; 2112f7d5dffcSJean-Jacques Hiblot error: 2113f7d5dffcSJean-Jacques Hiblot if (mmc->ext_csd) { 2114f7d5dffcSJean-Jacques Hiblot free(mmc->ext_csd); 2115f7d5dffcSJean-Jacques Hiblot mmc->ext_csd = NULL; 2116f7d5dffcSJean-Jacques Hiblot } 2117f7d5dffcSJean-Jacques Hiblot return err; 2118c744b6f6SJean-Jacques Hiblot } 2119c744b6f6SJean-Jacques Hiblot 2120fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc) 2121272cc70bSAndy Fleming { 2122f866a46dSStephen Warren int err, i; 2123272cc70bSAndy Fleming uint mult, freq; 2124c744b6f6SJean-Jacques Hiblot u64 cmult, csize; 2125272cc70bSAndy Fleming struct mmc_cmd cmd; 2126c40fdca6SSimon Glass struct blk_desc *bdesc; 2127272cc70bSAndy Fleming 2128d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON 2129d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ 2130d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; 2131d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R1; 2132d52ebf10SThomas Chou cmd.cmdarg = 1; 2133d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 2134d52ebf10SThomas Chou if (err) 2135d52ebf10SThomas Chou return err; 2136d52ebf10SThomas Chou } 2137d52ebf10SThomas Chou #endif 2138d52ebf10SThomas Chou 2139272cc70bSAndy Fleming /* Put the Card in Identify Mode */ 2140d52ebf10SThomas Chou cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : 2141d52ebf10SThomas Chou MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ 2142272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 2143272cc70bSAndy Fleming cmd.cmdarg = 0; 2144272cc70bSAndy Fleming 2145272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2146272cc70bSAndy Fleming 214783dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS 214883dc4227SKishon Vijay Abraham I if (err && (mmc->quirks & MMC_QUIRK_RETRY_SEND_CID)) { 214983dc4227SKishon Vijay Abraham I int retries = 4; 215083dc4227SKishon Vijay Abraham I /* 215183dc4227SKishon Vijay Abraham I * It has been seen that SEND_CID may fail on the first 215283dc4227SKishon Vijay Abraham I * attempt, let's try a few more time 215383dc4227SKishon Vijay Abraham I */ 215483dc4227SKishon Vijay Abraham I do { 215583dc4227SKishon Vijay Abraham I err = mmc_send_cmd(mmc, &cmd, NULL); 215683dc4227SKishon Vijay Abraham I if (!err) 215783dc4227SKishon Vijay Abraham I break; 215883dc4227SKishon Vijay Abraham I } while (retries--); 215983dc4227SKishon Vijay Abraham I } 216083dc4227SKishon Vijay Abraham I #endif 216183dc4227SKishon Vijay Abraham I 2162272cc70bSAndy Fleming if (err) 2163272cc70bSAndy Fleming return err; 2164272cc70bSAndy Fleming 2165272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16); 2166272cc70bSAndy Fleming 2167272cc70bSAndy Fleming /* 2168272cc70bSAndy Fleming * For MMC cards, set the Relative Address. 2169272cc70bSAndy Fleming * For SD cards, get the Relatvie Address. 2170272cc70bSAndy Fleming * This also puts the cards into Standby State 2171272cc70bSAndy Fleming */ 2172d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 2173272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; 2174272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 2175272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6; 2176272cc70bSAndy Fleming 2177272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2178272cc70bSAndy Fleming 2179272cc70bSAndy Fleming if (err) 2180272cc70bSAndy Fleming return err; 2181272cc70bSAndy Fleming 2182272cc70bSAndy Fleming if (IS_SD(mmc)) 2183998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff; 2184d52ebf10SThomas Chou } 2185272cc70bSAndy Fleming 2186272cc70bSAndy Fleming /* Get the Card-Specific Data */ 2187272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD; 2188272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 2189272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 2190272cc70bSAndy Fleming 2191272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2192272cc70bSAndy Fleming 2193272cc70bSAndy Fleming if (err) 2194272cc70bSAndy Fleming return err; 2195272cc70bSAndy Fleming 2196998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0]; 2197998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1]; 2198998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2]; 2199998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3]; 2200272cc70bSAndy Fleming 2201272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) { 22020b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf; 2203272cc70bSAndy Fleming 2204272cc70bSAndy Fleming switch (version) { 2205272cc70bSAndy Fleming case 0: 2206272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 2207272cc70bSAndy Fleming break; 2208272cc70bSAndy Fleming case 1: 2209272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4; 2210272cc70bSAndy Fleming break; 2211272cc70bSAndy Fleming case 2: 2212272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2; 2213272cc70bSAndy Fleming break; 2214272cc70bSAndy Fleming case 3: 2215272cc70bSAndy Fleming mmc->version = MMC_VERSION_3; 2216272cc70bSAndy Fleming break; 2217272cc70bSAndy Fleming case 4: 2218272cc70bSAndy Fleming mmc->version = MMC_VERSION_4; 2219272cc70bSAndy Fleming break; 2220272cc70bSAndy Fleming default: 2221272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 2222272cc70bSAndy Fleming break; 2223272cc70bSAndy Fleming } 2224272cc70bSAndy Fleming } 2225272cc70bSAndy Fleming 2226272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */ 22270b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)]; 22280b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; 2229272cc70bSAndy Fleming 223035f9e196SJean-Jacques Hiblot mmc->legacy_speed = freq * mult; 223135f9e196SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_LEGACY); 2232272cc70bSAndy Fleming 2233ab71188cSMarkus Niebel mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); 2234998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); 2235e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE) 2236272cc70bSAndy Fleming 2237272cc70bSAndy Fleming if (IS_SD(mmc)) 2238272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len; 2239272cc70bSAndy Fleming else 2240998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); 2241e6fa5a54SJean-Jacques Hiblot #endif 2242272cc70bSAndy Fleming 2243272cc70bSAndy Fleming if (mmc->high_capacity) { 2244272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16 2245272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16; 2246272cc70bSAndy Fleming cmult = 8; 2247272cc70bSAndy Fleming } else { 2248272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2 2249272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30; 2250272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15; 2251272cc70bSAndy Fleming } 2252272cc70bSAndy Fleming 2253f866a46dSStephen Warren mmc->capacity_user = (csize + 1) << (cmult + 2); 2254f866a46dSStephen Warren mmc->capacity_user *= mmc->read_bl_len; 2255f866a46dSStephen Warren mmc->capacity_boot = 0; 2256f866a46dSStephen Warren mmc->capacity_rpmb = 0; 2257f866a46dSStephen Warren for (i = 0; i < 4; i++) 2258f866a46dSStephen Warren mmc->capacity_gp[i] = 0; 2259272cc70bSAndy Fleming 22608bfa195eSSimon Glass if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN) 22618bfa195eSSimon Glass mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 2262272cc70bSAndy Fleming 2263e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE) 22648bfa195eSSimon Glass if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) 22658bfa195eSSimon Glass mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 2266e6fa5a54SJean-Jacques Hiblot #endif 2267272cc70bSAndy Fleming 2268ab71188cSMarkus Niebel if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) { 2269ab71188cSMarkus Niebel cmd.cmdidx = MMC_CMD_SET_DSR; 2270ab71188cSMarkus Niebel cmd.cmdarg = (mmc->dsr & 0xffff) << 16; 2271ab71188cSMarkus Niebel cmd.resp_type = MMC_RSP_NONE; 2272ab71188cSMarkus Niebel if (mmc_send_cmd(mmc, &cmd, NULL)) 2273d8e3d420SJean-Jacques Hiblot pr_warn("MMC: SET_DSR failed\n"); 2274ab71188cSMarkus Niebel } 2275ab71188cSMarkus Niebel 2276272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */ 2277d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 2278272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD; 2279fe8f7066SAjay Bhargav cmd.resp_type = MMC_RSP_R1; 2280272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 2281272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2282272cc70bSAndy Fleming 2283272cc70bSAndy Fleming if (err) 2284272cc70bSAndy Fleming return err; 2285d52ebf10SThomas Chou } 2286272cc70bSAndy Fleming 2287e6f99a56SLei Wen /* 2288e6f99a56SLei Wen * For SD, its erase group is always one sector 2289e6f99a56SLei Wen */ 2290e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE) 2291e6f99a56SLei Wen mmc->erase_grp_size = 1; 2292e6fa5a54SJean-Jacques Hiblot #endif 2293bc897b1dSLei Wen mmc->part_config = MMCPART_NOAVAILABLE; 2294c744b6f6SJean-Jacques Hiblot 2295dfda9d88SJean-Jacques Hiblot err = mmc_startup_v4(mmc); 22969cf199ebSDiego Santa Cruz if (err) 22979cf199ebSDiego Santa Cruz return err; 2298f866a46dSStephen Warren 2299c40fdca6SSimon Glass err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart); 2300f866a46dSStephen Warren if (err) 2301f866a46dSStephen Warren return err; 2302d23e2c09SSukumar Ghorai 230301298da3SJean-Jacques Hiblot if (IS_SD(mmc)) { 230401298da3SJean-Jacques Hiblot err = sd_get_capabilities(mmc); 230501298da3SJean-Jacques Hiblot if (err) 230601298da3SJean-Jacques Hiblot return err; 230701298da3SJean-Jacques Hiblot err = sd_select_mode_and_width(mmc, mmc->card_caps); 230801298da3SJean-Jacques Hiblot } else { 230901298da3SJean-Jacques Hiblot err = mmc_get_capabilities(mmc); 231001298da3SJean-Jacques Hiblot if (err) 231101298da3SJean-Jacques Hiblot return err; 231201298da3SJean-Jacques Hiblot mmc_select_mode_and_width(mmc, mmc->card_caps); 231301298da3SJean-Jacques Hiblot } 2314272cc70bSAndy Fleming 2315272cc70bSAndy Fleming if (err) 2316272cc70bSAndy Fleming return err; 2317272cc70bSAndy Fleming 231801298da3SJean-Jacques Hiblot mmc->best_mode = mmc->selected_mode; 2319272cc70bSAndy Fleming 23205af8f45cSAndrew Gabbasov /* Fix the block length for DDR mode */ 23215af8f45cSAndrew Gabbasov if (mmc->ddr_mode) { 23225af8f45cSAndrew Gabbasov mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 2323e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE) 23245af8f45cSAndrew Gabbasov mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 2325e6fa5a54SJean-Jacques Hiblot #endif 23265af8f45cSAndrew Gabbasov } 23275af8f45cSAndrew Gabbasov 2328272cc70bSAndy Fleming /* fill in device description */ 2329c40fdca6SSimon Glass bdesc = mmc_get_blk_desc(mmc); 2330c40fdca6SSimon Glass bdesc->lun = 0; 2331c40fdca6SSimon Glass bdesc->hwpart = 0; 2332c40fdca6SSimon Glass bdesc->type = 0; 2333c40fdca6SSimon Glass bdesc->blksz = mmc->read_bl_len; 2334c40fdca6SSimon Glass bdesc->log2blksz = LOG2(bdesc->blksz); 2335c40fdca6SSimon Glass bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len); 2336fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \ 2337fc011f64SSjoerd Simons (defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \ 2338fc011f64SSjoerd Simons !defined(CONFIG_USE_TINY_PRINTF)) 2339c40fdca6SSimon Glass sprintf(bdesc->vendor, "Man %06x Snr %04x%04x", 2340babce5f6STaylor Hutt mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), 2341babce5f6STaylor Hutt (mmc->cid[3] >> 16) & 0xffff); 2342c40fdca6SSimon Glass sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff, 23430b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 2344babce5f6STaylor Hutt (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff, 2345babce5f6STaylor Hutt (mmc->cid[2] >> 24) & 0xff); 2346c40fdca6SSimon Glass sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf, 2347babce5f6STaylor Hutt (mmc->cid[2] >> 16) & 0xf); 234856196826SPaul Burton #else 2349c40fdca6SSimon Glass bdesc->vendor[0] = 0; 2350c40fdca6SSimon Glass bdesc->product[0] = 0; 2351c40fdca6SSimon Glass bdesc->revision[0] = 0; 235256196826SPaul Burton #endif 2353122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT) 2354c40fdca6SSimon Glass part_init(bdesc); 2355122efd43SMikhail Kshevetskiy #endif 2356272cc70bSAndy Fleming 2357272cc70bSAndy Fleming return 0; 2358272cc70bSAndy Fleming } 2359272cc70bSAndy Fleming 2360fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc) 2361272cc70bSAndy Fleming { 2362272cc70bSAndy Fleming struct mmc_cmd cmd; 2363272cc70bSAndy Fleming int err; 2364272cc70bSAndy Fleming 2365272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND; 2366272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ 236793bfd616SPantelis Antoniou cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa; 2368272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7; 2369272cc70bSAndy Fleming 2370272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2371272cc70bSAndy Fleming 2372272cc70bSAndy Fleming if (err) 2373272cc70bSAndy Fleming return err; 2374272cc70bSAndy Fleming 2375998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa) 2376915ffa52SJaehoon Chung return -EOPNOTSUPP; 2377272cc70bSAndy Fleming else 2378272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 2379272cc70bSAndy Fleming 2380272cc70bSAndy Fleming return 0; 2381272cc70bSAndy Fleming } 2382272cc70bSAndy Fleming 2383c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 238495de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */ 238595de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void) 238695de9ab2SPaul Kocialkowski { 238795de9ab2SPaul Kocialkowski } 238805cbeb7cSSimon Glass #endif 238995de9ab2SPaul Kocialkowski 23902051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc) 23912051aefeSPeng Fan { 2392c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 239306ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR) 23942051aefeSPeng Fan int ret; 23952051aefeSPeng Fan 23962051aefeSPeng Fan ret = device_get_supply_regulator(mmc->dev, "vmmc-supply", 239706ec045fSJean-Jacques Hiblot &mmc->vmmc_supply); 239806ec045fSJean-Jacques Hiblot if (ret) 2399*d4d64889SMasahiro Yamada pr_debug("%s: No vmmc supply\n", mmc->dev->name); 24002051aefeSPeng Fan 240106ec045fSJean-Jacques Hiblot ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply", 240206ec045fSJean-Jacques Hiblot &mmc->vqmmc_supply); 240306ec045fSJean-Jacques Hiblot if (ret) 2404*d4d64889SMasahiro Yamada pr_debug("%s: No vqmmc supply\n", mmc->dev->name); 24052051aefeSPeng Fan #endif 240605cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */ 240705cbeb7cSSimon Glass /* 240805cbeb7cSSimon Glass * Driver model should use a regulator, as above, rather than calling 240905cbeb7cSSimon Glass * out to board code. 241005cbeb7cSSimon Glass */ 241105cbeb7cSSimon Glass board_mmc_power_init(); 241205cbeb7cSSimon Glass #endif 24132051aefeSPeng Fan return 0; 24142051aefeSPeng Fan } 24152051aefeSPeng Fan 2416fb7c3bebSKishon Vijay Abraham I /* 2417fb7c3bebSKishon Vijay Abraham I * put the host in the initial state: 2418fb7c3bebSKishon Vijay Abraham I * - turn on Vdd (card power supply) 2419fb7c3bebSKishon Vijay Abraham I * - configure the bus width and clock to minimal values 2420fb7c3bebSKishon Vijay Abraham I */ 2421fb7c3bebSKishon Vijay Abraham I static void mmc_set_initial_state(struct mmc *mmc) 2422fb7c3bebSKishon Vijay Abraham I { 2423fb7c3bebSKishon Vijay Abraham I int err; 2424fb7c3bebSKishon Vijay Abraham I 2425fb7c3bebSKishon Vijay Abraham I /* First try to set 3.3V. If it fails set to 1.8V */ 2426fb7c3bebSKishon Vijay Abraham I err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_330); 2427fb7c3bebSKishon Vijay Abraham I if (err != 0) 2428fb7c3bebSKishon Vijay Abraham I err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_180); 2429fb7c3bebSKishon Vijay Abraham I if (err != 0) 2430d8e3d420SJean-Jacques Hiblot pr_warn("mmc: failed to set signal voltage\n"); 2431fb7c3bebSKishon Vijay Abraham I 2432fb7c3bebSKishon Vijay Abraham I mmc_select_mode(mmc, MMC_LEGACY); 2433fb7c3bebSKishon Vijay Abraham I mmc_set_bus_width(mmc, 1); 243435f67820SKishon Vijay Abraham I mmc_set_clock(mmc, 0, false); 2435fb7c3bebSKishon Vijay Abraham I } 2436fb7c3bebSKishon Vijay Abraham I 2437fb7c3bebSKishon Vijay Abraham I static int mmc_power_on(struct mmc *mmc) 2438fb7c3bebSKishon Vijay Abraham I { 2439fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR) 2440fb7c3bebSKishon Vijay Abraham I if (mmc->vmmc_supply) { 2441fb7c3bebSKishon Vijay Abraham I int ret = regulator_set_enable(mmc->vmmc_supply, true); 2442fb7c3bebSKishon Vijay Abraham I 2443fb7c3bebSKishon Vijay Abraham I if (ret) { 2444fb7c3bebSKishon Vijay Abraham I puts("Error enabling VMMC supply\n"); 2445fb7c3bebSKishon Vijay Abraham I return ret; 2446fb7c3bebSKishon Vijay Abraham I } 2447fb7c3bebSKishon Vijay Abraham I } 2448fb7c3bebSKishon Vijay Abraham I #endif 2449fb7c3bebSKishon Vijay Abraham I return 0; 2450fb7c3bebSKishon Vijay Abraham I } 2451fb7c3bebSKishon Vijay Abraham I 2452fb7c3bebSKishon Vijay Abraham I static int mmc_power_off(struct mmc *mmc) 2453fb7c3bebSKishon Vijay Abraham I { 24549546eb92SJaehoon Chung mmc_set_clock(mmc, 0, true); 2455fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR) 2456fb7c3bebSKishon Vijay Abraham I if (mmc->vmmc_supply) { 2457fb7c3bebSKishon Vijay Abraham I int ret = regulator_set_enable(mmc->vmmc_supply, false); 2458fb7c3bebSKishon Vijay Abraham I 2459fb7c3bebSKishon Vijay Abraham I if (ret) { 2460*d4d64889SMasahiro Yamada pr_debug("Error disabling VMMC supply\n"); 2461fb7c3bebSKishon Vijay Abraham I return ret; 2462fb7c3bebSKishon Vijay Abraham I } 2463fb7c3bebSKishon Vijay Abraham I } 2464fb7c3bebSKishon Vijay Abraham I #endif 2465fb7c3bebSKishon Vijay Abraham I return 0; 2466fb7c3bebSKishon Vijay Abraham I } 2467fb7c3bebSKishon Vijay Abraham I 2468fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc) 2469fb7c3bebSKishon Vijay Abraham I { 2470fb7c3bebSKishon Vijay Abraham I int ret; 2471fb7c3bebSKishon Vijay Abraham I 2472fb7c3bebSKishon Vijay Abraham I ret = mmc_power_off(mmc); 2473fb7c3bebSKishon Vijay Abraham I if (ret) 2474fb7c3bebSKishon Vijay Abraham I return ret; 2475fb7c3bebSKishon Vijay Abraham I /* 2476fb7c3bebSKishon Vijay Abraham I * SD spec recommends at least 1ms of delay. Let's wait for 2ms 2477fb7c3bebSKishon Vijay Abraham I * to be on the safer side. 2478fb7c3bebSKishon Vijay Abraham I */ 2479fb7c3bebSKishon Vijay Abraham I udelay(2000); 2480fb7c3bebSKishon Vijay Abraham I return mmc_power_on(mmc); 2481fb7c3bebSKishon Vijay Abraham I } 2482fb7c3bebSKishon Vijay Abraham I 2483e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc) 2484272cc70bSAndy Fleming { 24858ca51e51SSimon Glass bool no_card; 2486c10b85d6SJean-Jacques Hiblot bool uhs_en = supports_uhs(mmc->cfg->host_caps); 2487afd5932bSMacpaul Lin int err; 2488272cc70bSAndy Fleming 24891da8eb59SJean-Jacques Hiblot /* 24901da8eb59SJean-Jacques Hiblot * all hosts are capable of 1 bit bus-width and able to use the legacy 24911da8eb59SJean-Jacques Hiblot * timings. 24921da8eb59SJean-Jacques Hiblot */ 24931da8eb59SJean-Jacques Hiblot mmc->host_caps = mmc->cfg->host_caps | MMC_CAP(SD_LEGACY) | 24941da8eb59SJean-Jacques Hiblot MMC_CAP(MMC_LEGACY) | MMC_MODE_1BIT; 249504a2ea24SJean-Jacques Hiblot 24962f516e4aSJun Nie #if !defined(CONFIG_MMC_BROKEN_CD) 2497ab769f22SPantelis Antoniou /* we pretend there's no card when init is NULL */ 24988ca51e51SSimon Glass no_card = mmc_getcd(mmc) == 0; 24992f516e4aSJun Nie #else 25002f516e4aSJun Nie no_card = 0; 25012f516e4aSJun Nie #endif 2502e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 25038ca51e51SSimon Glass no_card = no_card || (mmc->cfg->ops->init == NULL); 25048ca51e51SSimon Glass #endif 25058ca51e51SSimon Glass if (no_card) { 250648972d90SThierry Reding mmc->has_init = 0; 250756196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2508*d4d64889SMasahiro Yamada pr_err("MMC: no card present\n"); 250956196826SPaul Burton #endif 2510915ffa52SJaehoon Chung return -ENOMEDIUM; 251148972d90SThierry Reding } 251248972d90SThierry Reding 2513bc897b1dSLei Wen if (mmc->has_init) 2514bc897b1dSLei Wen return 0; 2515bc897b1dSLei Wen 25165a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 25175a8dbdc6SYangbo Lu mmc_adapter_card_type_ident(); 25185a8dbdc6SYangbo Lu #endif 25192051aefeSPeng Fan err = mmc_power_init(mmc); 25202051aefeSPeng Fan if (err) 25212051aefeSPeng Fan return err; 252295de9ab2SPaul Kocialkowski 252383dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS 252483dc4227SKishon Vijay Abraham I mmc->quirks = MMC_QUIRK_RETRY_SET_BLOCKLEN | 252583dc4227SKishon Vijay Abraham I MMC_QUIRK_RETRY_SEND_CID; 252683dc4227SKishon Vijay Abraham I #endif 252783dc4227SKishon Vijay Abraham I 252804a2ea24SJean-Jacques Hiblot err = mmc_power_cycle(mmc); 252904a2ea24SJean-Jacques Hiblot if (err) { 253004a2ea24SJean-Jacques Hiblot /* 253104a2ea24SJean-Jacques Hiblot * if power cycling is not supported, we should not try 253204a2ea24SJean-Jacques Hiblot * to use the UHS modes, because we wouldn't be able to 253304a2ea24SJean-Jacques Hiblot * recover from an error during the UHS initialization. 253404a2ea24SJean-Jacques Hiblot */ 2535*d4d64889SMasahiro Yamada pr_debug("Unable to do a full power cycle. Disabling the UHS modes for safety\n"); 253604a2ea24SJean-Jacques Hiblot uhs_en = false; 253704a2ea24SJean-Jacques Hiblot mmc->host_caps &= ~UHS_CAPS; 2538fb7c3bebSKishon Vijay Abraham I err = mmc_power_on(mmc); 253904a2ea24SJean-Jacques Hiblot } 2540fb7c3bebSKishon Vijay Abraham I if (err) 2541fb7c3bebSKishon Vijay Abraham I return err; 2542fb7c3bebSKishon Vijay Abraham I 2543e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 25448ca51e51SSimon Glass /* The device has already been probed ready for use */ 25458ca51e51SSimon Glass #else 2546ab769f22SPantelis Antoniou /* made sure it's not NULL earlier */ 254793bfd616SPantelis Antoniou err = mmc->cfg->ops->init(mmc); 2548272cc70bSAndy Fleming if (err) 2549272cc70bSAndy Fleming return err; 25508ca51e51SSimon Glass #endif 2551786e8f81SAndrew Gabbasov mmc->ddr_mode = 0; 2552aff5d3c8SKishon Vijay Abraham I 2553c10b85d6SJean-Jacques Hiblot retry: 2554fb7c3bebSKishon Vijay Abraham I mmc_set_initial_state(mmc); 2555318a7a57SJean-Jacques Hiblot mmc_send_init_stream(mmc); 2556318a7a57SJean-Jacques Hiblot 2557272cc70bSAndy Fleming /* Reset the Card */ 2558272cc70bSAndy Fleming err = mmc_go_idle(mmc); 2559272cc70bSAndy Fleming 2560272cc70bSAndy Fleming if (err) 2561272cc70bSAndy Fleming return err; 2562272cc70bSAndy Fleming 2563bc897b1dSLei Wen /* The internal partition reset to user partition(0) at every CMD0*/ 2564c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->hwpart = 0; 2565bc897b1dSLei Wen 2566272cc70bSAndy Fleming /* Test for SD version 2 */ 2567272cc70bSAndy Fleming err = mmc_send_if_cond(mmc); 2568272cc70bSAndy Fleming 2569272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */ 2570c10b85d6SJean-Jacques Hiblot err = sd_send_op_cond(mmc, uhs_en); 2571c10b85d6SJean-Jacques Hiblot if (err && uhs_en) { 2572c10b85d6SJean-Jacques Hiblot uhs_en = false; 2573c10b85d6SJean-Jacques Hiblot mmc_power_cycle(mmc); 2574c10b85d6SJean-Jacques Hiblot goto retry; 2575c10b85d6SJean-Jacques Hiblot } 2576272cc70bSAndy Fleming 2577272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */ 2578915ffa52SJaehoon Chung if (err == -ETIMEDOUT) { 2579272cc70bSAndy Fleming err = mmc_send_op_cond(mmc); 2580272cc70bSAndy Fleming 2581bd47c135SAndrew Gabbasov if (err) { 258256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2583d8e3d420SJean-Jacques Hiblot pr_err("Card did not respond to voltage select!\n"); 258456196826SPaul Burton #endif 2585915ffa52SJaehoon Chung return -EOPNOTSUPP; 2586272cc70bSAndy Fleming } 2587272cc70bSAndy Fleming } 2588272cc70bSAndy Fleming 2589bd47c135SAndrew Gabbasov if (!err) 2590e9550449SChe-Liang Chiou mmc->init_in_progress = 1; 2591e9550449SChe-Liang Chiou 2592e9550449SChe-Liang Chiou return err; 2593e9550449SChe-Liang Chiou } 2594e9550449SChe-Liang Chiou 2595e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc) 2596e9550449SChe-Liang Chiou { 2597e9550449SChe-Liang Chiou int err = 0; 2598e9550449SChe-Liang Chiou 2599bd47c135SAndrew Gabbasov mmc->init_in_progress = 0; 2600e9550449SChe-Liang Chiou if (mmc->op_cond_pending) 2601e9550449SChe-Liang Chiou err = mmc_complete_op_cond(mmc); 2602e9550449SChe-Liang Chiou 2603e9550449SChe-Liang Chiou if (!err) 2604bc897b1dSLei Wen err = mmc_startup(mmc); 2605bc897b1dSLei Wen if (err) 2606bc897b1dSLei Wen mmc->has_init = 0; 2607bc897b1dSLei Wen else 2608bc897b1dSLei Wen mmc->has_init = 1; 2609e9550449SChe-Liang Chiou return err; 2610e9550449SChe-Liang Chiou } 2611e9550449SChe-Liang Chiou 2612e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc) 2613e9550449SChe-Liang Chiou { 2614bd47c135SAndrew Gabbasov int err = 0; 2615ce9eca94SMarek Vasut __maybe_unused unsigned start; 2616c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 261733fb211dSSimon Glass struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev); 2618e9550449SChe-Liang Chiou 261933fb211dSSimon Glass upriv->mmc = mmc; 262033fb211dSSimon Glass #endif 2621e9550449SChe-Liang Chiou if (mmc->has_init) 2622e9550449SChe-Liang Chiou return 0; 2623d803fea5SMateusz Zalega 2624d803fea5SMateusz Zalega start = get_timer(0); 2625d803fea5SMateusz Zalega 2626e9550449SChe-Liang Chiou if (!mmc->init_in_progress) 2627e9550449SChe-Liang Chiou err = mmc_start_init(mmc); 2628e9550449SChe-Liang Chiou 2629bd47c135SAndrew Gabbasov if (!err) 2630e9550449SChe-Liang Chiou err = mmc_complete_init(mmc); 2631919b4858SJagan Teki if (err) 2632*d4d64889SMasahiro Yamada pr_info("%s: %d, time %lu\n", __func__, err, get_timer(start)); 2633919b4858SJagan Teki 2634bc897b1dSLei Wen return err; 2635272cc70bSAndy Fleming } 2636272cc70bSAndy Fleming 2637ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val) 2638ab71188cSMarkus Niebel { 2639ab71188cSMarkus Niebel mmc->dsr = val; 2640ab71188cSMarkus Niebel return 0; 2641ab71188cSMarkus Niebel } 2642ab71188cSMarkus Niebel 2643cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */ 2644cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis) 2645272cc70bSAndy Fleming { 2646272cc70bSAndy Fleming return -1; 2647272cc70bSAndy Fleming } 2648272cc70bSAndy Fleming 2649cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */ 2650cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis) 2651cee9ab7cSJeroen Hofstee { 2652cee9ab7cSJeroen Hofstee return -1; 2653cee9ab7cSJeroen Hofstee } 2654272cc70bSAndy Fleming 2655e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit) 2656e9550449SChe-Liang Chiou { 2657e9550449SChe-Liang Chiou mmc->preinit = preinit; 2658e9550449SChe-Liang Chiou } 2659e9550449SChe-Liang Chiou 2660c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD) 26618e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 26628e3332e2SSjoerd Simons { 26638e3332e2SSjoerd Simons return 0; 26648e3332e2SSjoerd Simons } 2665c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC) 26668e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 26678e3332e2SSjoerd Simons { 26684a1db6d8SSimon Glass int ret, i; 26698e3332e2SSjoerd Simons struct uclass *uc; 26704a1db6d8SSimon Glass struct udevice *dev; 26718e3332e2SSjoerd Simons 26728e3332e2SSjoerd Simons ret = uclass_get(UCLASS_MMC, &uc); 26738e3332e2SSjoerd Simons if (ret) 26748e3332e2SSjoerd Simons return ret; 26758e3332e2SSjoerd Simons 26764a1db6d8SSimon Glass /* 26774a1db6d8SSimon Glass * Try to add them in sequence order. Really with driver model we 26784a1db6d8SSimon Glass * should allow holes, but the current MMC list does not allow that. 26794a1db6d8SSimon Glass * So if we request 0, 1, 3 we will get 0, 1, 2. 26804a1db6d8SSimon Glass */ 26814a1db6d8SSimon Glass for (i = 0; ; i++) { 26824a1db6d8SSimon Glass ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev); 26834a1db6d8SSimon Glass if (ret == -ENODEV) 26844a1db6d8SSimon Glass break; 26854a1db6d8SSimon Glass } 26864a1db6d8SSimon Glass uclass_foreach_dev(dev, uc) { 26874a1db6d8SSimon Glass ret = device_probe(dev); 26888e3332e2SSjoerd Simons if (ret) 2689d8e3d420SJean-Jacques Hiblot pr_err("%s - probe failed: %d\n", dev->name, ret); 26908e3332e2SSjoerd Simons } 26918e3332e2SSjoerd Simons 26928e3332e2SSjoerd Simons return 0; 26938e3332e2SSjoerd Simons } 26948e3332e2SSjoerd Simons #else 26958e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 26968e3332e2SSjoerd Simons { 26978e3332e2SSjoerd Simons if (board_mmc_init(bis) < 0) 26988e3332e2SSjoerd Simons cpu_mmc_init(bis); 26998e3332e2SSjoerd Simons 27008e3332e2SSjoerd Simons return 0; 27018e3332e2SSjoerd Simons } 27028e3332e2SSjoerd Simons #endif 2703e9550449SChe-Liang Chiou 2704272cc70bSAndy Fleming int mmc_initialize(bd_t *bis) 2705272cc70bSAndy Fleming { 27061b26bab1SDaniel Kochmański static int initialized = 0; 27078e3332e2SSjoerd Simons int ret; 27081b26bab1SDaniel Kochmański if (initialized) /* Avoid initializing mmc multiple times */ 27091b26bab1SDaniel Kochmański return 0; 27101b26bab1SDaniel Kochmański initialized = 1; 27111b26bab1SDaniel Kochmański 2712c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK) 2713b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY) 2714c40fdca6SSimon Glass mmc_list_init(); 2715c40fdca6SSimon Glass #endif 2716b5b838f1SMarek Vasut #endif 27178e3332e2SSjoerd Simons ret = mmc_probe(bis); 27188e3332e2SSjoerd Simons if (ret) 27198e3332e2SSjoerd Simons return ret; 2720272cc70bSAndy Fleming 2721bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD 2722272cc70bSAndy Fleming print_mmc_devices(','); 2723bb0dc108SYing Zhang #endif 2724272cc70bSAndy Fleming 2725c40fdca6SSimon Glass mmc_do_preinit(); 2726272cc70bSAndy Fleming return 0; 2727272cc70bSAndy Fleming } 2728cd3d4880STomas Melin 2729cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE 2730cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc) 2731cd3d4880STomas Melin { 2732cd3d4880STomas Melin int err; 2733cd3d4880STomas Melin ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 2734cd3d4880STomas Melin 2735cd3d4880STomas Melin err = mmc_send_ext_csd(mmc, ext_csd); 2736cd3d4880STomas Melin if (err) { 2737cd3d4880STomas Melin puts("Could not get ext_csd register values\n"); 2738cd3d4880STomas Melin return err; 2739cd3d4880STomas Melin } 2740cd3d4880STomas Melin 2741cd3d4880STomas Melin if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) { 2742cd3d4880STomas Melin puts("Background operations not supported on device\n"); 2743cd3d4880STomas Melin return -EMEDIUMTYPE; 2744cd3d4880STomas Melin } 2745cd3d4880STomas Melin 2746cd3d4880STomas Melin if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) { 2747cd3d4880STomas Melin puts("Background operations already enabled\n"); 2748cd3d4880STomas Melin return 0; 2749cd3d4880STomas Melin } 2750cd3d4880STomas Melin 2751cd3d4880STomas Melin err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1); 2752cd3d4880STomas Melin if (err) { 2753cd3d4880STomas Melin puts("Failed to enable manual background operations\n"); 2754cd3d4880STomas Melin return err; 2755cd3d4880STomas Melin } 2756cd3d4880STomas Melin 2757cd3d4880STomas Melin puts("Enabled manual background operations\n"); 2758cd3d4880STomas Melin 2759cd3d4880STomas Melin return 0; 2760cd3d4880STomas Melin } 2761cd3d4880STomas Melin #endif 2762