183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+ 2272cc70bSAndy Fleming /* 3272cc70bSAndy Fleming * Copyright 2008, Freescale Semiconductor, Inc 4272cc70bSAndy Fleming * Andy Fleming 5272cc70bSAndy Fleming * 6272cc70bSAndy Fleming * Based vaguely on the Linux code 7272cc70bSAndy Fleming */ 8272cc70bSAndy Fleming 9272cc70bSAndy Fleming #include <config.h> 10272cc70bSAndy Fleming #include <common.h> 11272cc70bSAndy Fleming #include <command.h> 128e3332e2SSjoerd Simons #include <dm.h> 138e3332e2SSjoerd Simons #include <dm/device-internal.h> 14d4622df3SStephen Warren #include <errno.h> 15272cc70bSAndy Fleming #include <mmc.h> 16272cc70bSAndy Fleming #include <part.h> 172051aefeSPeng Fan #include <power/regulator.h> 18272cc70bSAndy Fleming #include <malloc.h> 19cf92e05cSSimon Glass #include <memalign.h> 20272cc70bSAndy Fleming #include <linux/list.h> 219b1f942cSRabin Vincent #include <div64.h> 22da61fa5fSPaul Burton #include "mmc_private.h" 23272cc70bSAndy Fleming 24aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage); 25fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc); 2601298da3SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps); 27aff5d3c8SKishon Vijay Abraham I 28b5b838f1SMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY) 29b5b838f1SMarek Vasut static struct mmc mmc_static; 30b5b838f1SMarek Vasut struct mmc *find_mmc_device(int dev_num) 31b5b838f1SMarek Vasut { 32b5b838f1SMarek Vasut return &mmc_static; 33b5b838f1SMarek Vasut } 34b5b838f1SMarek Vasut 35b5b838f1SMarek Vasut void mmc_do_preinit(void) 36b5b838f1SMarek Vasut { 37b5b838f1SMarek Vasut struct mmc *m = &mmc_static; 38b5b838f1SMarek Vasut #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 39b5b838f1SMarek Vasut mmc_set_preinit(m, 1); 40b5b838f1SMarek Vasut #endif 41b5b838f1SMarek Vasut if (m->preinit) 42b5b838f1SMarek Vasut mmc_start_init(m); 43b5b838f1SMarek Vasut } 44b5b838f1SMarek Vasut 45b5b838f1SMarek Vasut struct blk_desc *mmc_get_blk_desc(struct mmc *mmc) 46b5b838f1SMarek Vasut { 47b5b838f1SMarek Vasut return &mmc->block_dev; 48b5b838f1SMarek Vasut } 49b5b838f1SMarek Vasut #endif 50b5b838f1SMarek Vasut 51e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 52c10b85d6SJean-Jacques Hiblot 53f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 54c10b85d6SJean-Jacques Hiblot static int mmc_wait_dat0(struct mmc *mmc, int state, int timeout) 55c10b85d6SJean-Jacques Hiblot { 56c10b85d6SJean-Jacques Hiblot return -ENOSYS; 57c10b85d6SJean-Jacques Hiblot } 58f99c2efeSJean-Jacques Hiblot #endif 59c10b85d6SJean-Jacques Hiblot 60750121c3SJeroen Hofstee __weak int board_mmc_getwp(struct mmc *mmc) 61d23d8d7eSNikita Kiryanov { 62d23d8d7eSNikita Kiryanov return -1; 63d23d8d7eSNikita Kiryanov } 64d23d8d7eSNikita Kiryanov 65d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc) 66d23d8d7eSNikita Kiryanov { 67d23d8d7eSNikita Kiryanov int wp; 68d23d8d7eSNikita Kiryanov 69d23d8d7eSNikita Kiryanov wp = board_mmc_getwp(mmc); 70d23d8d7eSNikita Kiryanov 71d4e1da4eSPeter Korsgaard if (wp < 0) { 7293bfd616SPantelis Antoniou if (mmc->cfg->ops->getwp) 7393bfd616SPantelis Antoniou wp = mmc->cfg->ops->getwp(mmc); 74d4e1da4eSPeter Korsgaard else 75d4e1da4eSPeter Korsgaard wp = 0; 76d4e1da4eSPeter Korsgaard } 77d23d8d7eSNikita Kiryanov 78d23d8d7eSNikita Kiryanov return wp; 79d23d8d7eSNikita Kiryanov } 80d23d8d7eSNikita Kiryanov 81cee9ab7cSJeroen Hofstee __weak int board_mmc_getcd(struct mmc *mmc) 82cee9ab7cSJeroen Hofstee { 8311fdade2SStefano Babic return -1; 8411fdade2SStefano Babic } 858ca51e51SSimon Glass #endif 8611fdade2SStefano Babic 878635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE 88c0c76ebaSSimon Glass void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd) 89c0c76ebaSSimon Glass { 90c0c76ebaSSimon Glass printf("CMD_SEND:%d\n", cmd->cmdidx); 91c0c76ebaSSimon Glass printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg); 92c0c76ebaSSimon Glass } 93c0c76ebaSSimon Glass 94c0c76ebaSSimon Glass void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret) 95c0c76ebaSSimon Glass { 965db2fe3aSRaffaele Recalcati int i; 975db2fe3aSRaffaele Recalcati u8 *ptr; 985db2fe3aSRaffaele Recalcati 997863ce58SBin Meng if (ret) { 1007863ce58SBin Meng printf("\t\tRET\t\t\t %d\n", ret); 1017863ce58SBin Meng } else { 1025db2fe3aSRaffaele Recalcati switch (cmd->resp_type) { 1035db2fe3aSRaffaele Recalcati case MMC_RSP_NONE: 1045db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_NONE\n"); 1055db2fe3aSRaffaele Recalcati break; 1065db2fe3aSRaffaele Recalcati case MMC_RSP_R1: 1075db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n", 1085db2fe3aSRaffaele Recalcati cmd->response[0]); 1095db2fe3aSRaffaele Recalcati break; 1105db2fe3aSRaffaele Recalcati case MMC_RSP_R1b: 1115db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n", 1125db2fe3aSRaffaele Recalcati cmd->response[0]); 1135db2fe3aSRaffaele Recalcati break; 1145db2fe3aSRaffaele Recalcati case MMC_RSP_R2: 1155db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R2\t\t 0x%08X \n", 1165db2fe3aSRaffaele Recalcati cmd->response[0]); 1175db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1185db2fe3aSRaffaele Recalcati cmd->response[1]); 1195db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1205db2fe3aSRaffaele Recalcati cmd->response[2]); 1215db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1225db2fe3aSRaffaele Recalcati cmd->response[3]); 1235db2fe3aSRaffaele Recalcati printf("\n"); 1245db2fe3aSRaffaele Recalcati printf("\t\t\t\t\tDUMPING DATA\n"); 1255db2fe3aSRaffaele Recalcati for (i = 0; i < 4; i++) { 1265db2fe3aSRaffaele Recalcati int j; 1275db2fe3aSRaffaele Recalcati printf("\t\t\t\t\t%03d - ", i*4); 128146bec79SDirk Behme ptr = (u8 *)&cmd->response[i]; 1295db2fe3aSRaffaele Recalcati ptr += 3; 1305db2fe3aSRaffaele Recalcati for (j = 0; j < 4; j++) 1315db2fe3aSRaffaele Recalcati printf("%02X ", *ptr--); 1325db2fe3aSRaffaele Recalcati printf("\n"); 1335db2fe3aSRaffaele Recalcati } 1345db2fe3aSRaffaele Recalcati break; 1355db2fe3aSRaffaele Recalcati case MMC_RSP_R3: 1365db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n", 1375db2fe3aSRaffaele Recalcati cmd->response[0]); 1385db2fe3aSRaffaele Recalcati break; 1395db2fe3aSRaffaele Recalcati default: 1405db2fe3aSRaffaele Recalcati printf("\t\tERROR MMC rsp not supported\n"); 1415db2fe3aSRaffaele Recalcati break; 1425db2fe3aSRaffaele Recalcati } 1437863ce58SBin Meng } 144c0c76ebaSSimon Glass } 145c0c76ebaSSimon Glass 146c0c76ebaSSimon Glass void mmc_trace_state(struct mmc *mmc, struct mmc_cmd *cmd) 147c0c76ebaSSimon Glass { 148c0c76ebaSSimon Glass int status; 149c0c76ebaSSimon Glass 150c0c76ebaSSimon Glass status = (cmd->response[0] & MMC_STATUS_CURR_STATE) >> 9; 151c0c76ebaSSimon Glass printf("CURR STATE:%d\n", status); 152c0c76ebaSSimon Glass } 1535db2fe3aSRaffaele Recalcati #endif 154c0c76ebaSSimon Glass 15535f9e196SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG) 15635f9e196SJean-Jacques Hiblot const char *mmc_mode_name(enum bus_mode mode) 15735f9e196SJean-Jacques Hiblot { 15835f9e196SJean-Jacques Hiblot static const char *const names[] = { 15935f9e196SJean-Jacques Hiblot [MMC_LEGACY] = "MMC legacy", 16035f9e196SJean-Jacques Hiblot [SD_LEGACY] = "SD Legacy", 16135f9e196SJean-Jacques Hiblot [MMC_HS] = "MMC High Speed (26MHz)", 16235f9e196SJean-Jacques Hiblot [SD_HS] = "SD High Speed (50MHz)", 16335f9e196SJean-Jacques Hiblot [UHS_SDR12] = "UHS SDR12 (25MHz)", 16435f9e196SJean-Jacques Hiblot [UHS_SDR25] = "UHS SDR25 (50MHz)", 16535f9e196SJean-Jacques Hiblot [UHS_SDR50] = "UHS SDR50 (100MHz)", 16635f9e196SJean-Jacques Hiblot [UHS_SDR104] = "UHS SDR104 (208MHz)", 16735f9e196SJean-Jacques Hiblot [UHS_DDR50] = "UHS DDR50 (50MHz)", 16835f9e196SJean-Jacques Hiblot [MMC_HS_52] = "MMC High Speed (52MHz)", 16935f9e196SJean-Jacques Hiblot [MMC_DDR_52] = "MMC DDR52 (52MHz)", 17035f9e196SJean-Jacques Hiblot [MMC_HS_200] = "HS200 (200MHz)", 17135f9e196SJean-Jacques Hiblot }; 17235f9e196SJean-Jacques Hiblot 17335f9e196SJean-Jacques Hiblot if (mode >= MMC_MODES_END) 17435f9e196SJean-Jacques Hiblot return "Unknown mode"; 17535f9e196SJean-Jacques Hiblot else 17635f9e196SJean-Jacques Hiblot return names[mode]; 17735f9e196SJean-Jacques Hiblot } 17835f9e196SJean-Jacques Hiblot #endif 17935f9e196SJean-Jacques Hiblot 18005038576SJean-Jacques Hiblot static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode) 18105038576SJean-Jacques Hiblot { 18205038576SJean-Jacques Hiblot static const int freqs[] = { 1831b313aa3SJaehoon Chung [MMC_LEGACY] = 25000000, 18405038576SJean-Jacques Hiblot [SD_LEGACY] = 25000000, 18505038576SJean-Jacques Hiblot [MMC_HS] = 26000000, 18605038576SJean-Jacques Hiblot [SD_HS] = 50000000, 1871b313aa3SJaehoon Chung [MMC_HS_52] = 52000000, 1881b313aa3SJaehoon Chung [MMC_DDR_52] = 52000000, 18905038576SJean-Jacques Hiblot [UHS_SDR12] = 25000000, 19005038576SJean-Jacques Hiblot [UHS_SDR25] = 50000000, 19105038576SJean-Jacques Hiblot [UHS_SDR50] = 100000000, 19205038576SJean-Jacques Hiblot [UHS_DDR50] = 50000000, 193f99c2efeSJean-Jacques Hiblot [UHS_SDR104] = 208000000, 19405038576SJean-Jacques Hiblot [MMC_HS_200] = 200000000, 19505038576SJean-Jacques Hiblot }; 19605038576SJean-Jacques Hiblot 19705038576SJean-Jacques Hiblot if (mode == MMC_LEGACY) 19805038576SJean-Jacques Hiblot return mmc->legacy_speed; 19905038576SJean-Jacques Hiblot else if (mode >= MMC_MODES_END) 20005038576SJean-Jacques Hiblot return 0; 20105038576SJean-Jacques Hiblot else 20205038576SJean-Jacques Hiblot return freqs[mode]; 20305038576SJean-Jacques Hiblot } 20405038576SJean-Jacques Hiblot 20535f9e196SJean-Jacques Hiblot static int mmc_select_mode(struct mmc *mmc, enum bus_mode mode) 20635f9e196SJean-Jacques Hiblot { 20735f9e196SJean-Jacques Hiblot mmc->selected_mode = mode; 20805038576SJean-Jacques Hiblot mmc->tran_speed = mmc_mode2freq(mmc, mode); 2093862b854SJean-Jacques Hiblot mmc->ddr_mode = mmc_is_mode_ddr(mode); 210d4d64889SMasahiro Yamada pr_debug("selecting mode %s (freq : %d MHz)\n", mmc_mode_name(mode), 21135f9e196SJean-Jacques Hiblot mmc->tran_speed / 1000000); 21235f9e196SJean-Jacques Hiblot return 0; 21335f9e196SJean-Jacques Hiblot } 21435f9e196SJean-Jacques Hiblot 215e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 216c0c76ebaSSimon Glass int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) 217c0c76ebaSSimon Glass { 218c0c76ebaSSimon Glass int ret; 219c0c76ebaSSimon Glass 220c0c76ebaSSimon Glass mmmc_trace_before_send(mmc, cmd); 221c0c76ebaSSimon Glass ret = mmc->cfg->ops->send_cmd(mmc, cmd, data); 222c0c76ebaSSimon Glass mmmc_trace_after_send(mmc, cmd, ret); 223c0c76ebaSSimon Glass 2248635ff9eSMarek Vasut return ret; 225272cc70bSAndy Fleming } 2268ca51e51SSimon Glass #endif 227272cc70bSAndy Fleming 228da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout) 2295d4fc8d9SRaffaele Recalcati { 2305d4fc8d9SRaffaele Recalcati struct mmc_cmd cmd; 231d617c426SJan Kloetzke int err, retries = 5; 2325d4fc8d9SRaffaele Recalcati 2335d4fc8d9SRaffaele Recalcati cmd.cmdidx = MMC_CMD_SEND_STATUS; 2345d4fc8d9SRaffaele Recalcati cmd.resp_type = MMC_RSP_R1; 235aaf3d41aSMarek Vasut if (!mmc_host_is_spi(mmc)) 236aaf3d41aSMarek Vasut cmd.cmdarg = mmc->rca << 16; 2375d4fc8d9SRaffaele Recalcati 2381677eef4SAndrew Gabbasov while (1) { 2395d4fc8d9SRaffaele Recalcati err = mmc_send_cmd(mmc, &cmd, NULL); 240d617c426SJan Kloetzke if (!err) { 241d617c426SJan Kloetzke if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) && 242d617c426SJan Kloetzke (cmd.response[0] & MMC_STATUS_CURR_STATE) != 243d617c426SJan Kloetzke MMC_STATE_PRG) 2445d4fc8d9SRaffaele Recalcati break; 245d0c221feSJean-Jacques Hiblot 246d0c221feSJean-Jacques Hiblot if (cmd.response[0] & MMC_STATUS_MASK) { 24756196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 248d8e3d420SJean-Jacques Hiblot pr_err("Status Error: 0x%08X\n", 249d617c426SJan Kloetzke cmd.response[0]); 25056196826SPaul Burton #endif 251915ffa52SJaehoon Chung return -ECOMM; 252d617c426SJan Kloetzke } 253d617c426SJan Kloetzke } else if (--retries < 0) 254d617c426SJan Kloetzke return err; 2555d4fc8d9SRaffaele Recalcati 2561677eef4SAndrew Gabbasov if (timeout-- <= 0) 2571677eef4SAndrew Gabbasov break; 2585d4fc8d9SRaffaele Recalcati 2591677eef4SAndrew Gabbasov udelay(1000); 2601677eef4SAndrew Gabbasov } 2615d4fc8d9SRaffaele Recalcati 262c0c76ebaSSimon Glass mmc_trace_state(mmc, &cmd); 2635b0c942fSJongman Heo if (timeout <= 0) { 26456196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 265d8e3d420SJean-Jacques Hiblot pr_err("Timeout waiting card ready\n"); 26656196826SPaul Burton #endif 267915ffa52SJaehoon Chung return -ETIMEDOUT; 2685d4fc8d9SRaffaele Recalcati } 2695d4fc8d9SRaffaele Recalcati 2705d4fc8d9SRaffaele Recalcati return 0; 2715d4fc8d9SRaffaele Recalcati } 2725d4fc8d9SRaffaele Recalcati 273da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len) 274272cc70bSAndy Fleming { 275272cc70bSAndy Fleming struct mmc_cmd cmd; 27683dc4227SKishon Vijay Abraham I int err; 277272cc70bSAndy Fleming 278786e8f81SAndrew Gabbasov if (mmc->ddr_mode) 279d22e3d46SJaehoon Chung return 0; 280d22e3d46SJaehoon Chung 281272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SET_BLOCKLEN; 282272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 283272cc70bSAndy Fleming cmd.cmdarg = len; 284272cc70bSAndy Fleming 28583dc4227SKishon Vijay Abraham I err = mmc_send_cmd(mmc, &cmd, NULL); 28683dc4227SKishon Vijay Abraham I 28783dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS 28883dc4227SKishon Vijay Abraham I if (err && (mmc->quirks & MMC_QUIRK_RETRY_SET_BLOCKLEN)) { 28983dc4227SKishon Vijay Abraham I int retries = 4; 29083dc4227SKishon Vijay Abraham I /* 29183dc4227SKishon Vijay Abraham I * It has been seen that SET_BLOCKLEN may fail on the first 29283dc4227SKishon Vijay Abraham I * attempt, let's try a few more time 29383dc4227SKishon Vijay Abraham I */ 29483dc4227SKishon Vijay Abraham I do { 29583dc4227SKishon Vijay Abraham I err = mmc_send_cmd(mmc, &cmd, NULL); 29683dc4227SKishon Vijay Abraham I if (!err) 29783dc4227SKishon Vijay Abraham I break; 29883dc4227SKishon Vijay Abraham I } while (retries--); 29983dc4227SKishon Vijay Abraham I } 30083dc4227SKishon Vijay Abraham I #endif 30183dc4227SKishon Vijay Abraham I 30283dc4227SKishon Vijay Abraham I return err; 303272cc70bSAndy Fleming } 304272cc70bSAndy Fleming 305f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 3069815e3baSJean-Jacques Hiblot static const u8 tuning_blk_pattern_4bit[] = { 3079815e3baSJean-Jacques Hiblot 0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc, 3089815e3baSJean-Jacques Hiblot 0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef, 3099815e3baSJean-Jacques Hiblot 0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb, 3109815e3baSJean-Jacques Hiblot 0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef, 3119815e3baSJean-Jacques Hiblot 0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c, 3129815e3baSJean-Jacques Hiblot 0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee, 3139815e3baSJean-Jacques Hiblot 0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff, 3149815e3baSJean-Jacques Hiblot 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde, 3159815e3baSJean-Jacques Hiblot }; 3169815e3baSJean-Jacques Hiblot 3179815e3baSJean-Jacques Hiblot static const u8 tuning_blk_pattern_8bit[] = { 3189815e3baSJean-Jacques Hiblot 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 3199815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc, 3209815e3baSJean-Jacques Hiblot 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff, 3219815e3baSJean-Jacques Hiblot 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff, 3229815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd, 3239815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, 3249815e3baSJean-Jacques Hiblot 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff, 3259815e3baSJean-Jacques Hiblot 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff, 3269815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 3279815e3baSJean-Jacques Hiblot 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 3289815e3baSJean-Jacques Hiblot 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 3299815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 3309815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 3319815e3baSJean-Jacques Hiblot 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 3329815e3baSJean-Jacques Hiblot 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 3339815e3baSJean-Jacques Hiblot 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 3349815e3baSJean-Jacques Hiblot }; 3359815e3baSJean-Jacques Hiblot 3369815e3baSJean-Jacques Hiblot int mmc_send_tuning(struct mmc *mmc, u32 opcode, int *cmd_error) 3379815e3baSJean-Jacques Hiblot { 3389815e3baSJean-Jacques Hiblot struct mmc_cmd cmd; 3399815e3baSJean-Jacques Hiblot struct mmc_data data; 3409815e3baSJean-Jacques Hiblot const u8 *tuning_block_pattern; 3419815e3baSJean-Jacques Hiblot int size, err; 3429815e3baSJean-Jacques Hiblot 3439815e3baSJean-Jacques Hiblot if (mmc->bus_width == 8) { 3449815e3baSJean-Jacques Hiblot tuning_block_pattern = tuning_blk_pattern_8bit; 3459815e3baSJean-Jacques Hiblot size = sizeof(tuning_blk_pattern_8bit); 3469815e3baSJean-Jacques Hiblot } else if (mmc->bus_width == 4) { 3479815e3baSJean-Jacques Hiblot tuning_block_pattern = tuning_blk_pattern_4bit; 3489815e3baSJean-Jacques Hiblot size = sizeof(tuning_blk_pattern_4bit); 3499815e3baSJean-Jacques Hiblot } else { 3509815e3baSJean-Jacques Hiblot return -EINVAL; 3519815e3baSJean-Jacques Hiblot } 3529815e3baSJean-Jacques Hiblot 3539815e3baSJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, data_buf, size); 3549815e3baSJean-Jacques Hiblot 3559815e3baSJean-Jacques Hiblot cmd.cmdidx = opcode; 3569815e3baSJean-Jacques Hiblot cmd.cmdarg = 0; 3579815e3baSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 3589815e3baSJean-Jacques Hiblot 3599815e3baSJean-Jacques Hiblot data.dest = (void *)data_buf; 3609815e3baSJean-Jacques Hiblot data.blocks = 1; 3619815e3baSJean-Jacques Hiblot data.blocksize = size; 3629815e3baSJean-Jacques Hiblot data.flags = MMC_DATA_READ; 3639815e3baSJean-Jacques Hiblot 3649815e3baSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, &data); 3659815e3baSJean-Jacques Hiblot if (err) 3669815e3baSJean-Jacques Hiblot return err; 3679815e3baSJean-Jacques Hiblot 3689815e3baSJean-Jacques Hiblot if (memcmp(data_buf, tuning_block_pattern, size)) 3699815e3baSJean-Jacques Hiblot return -EIO; 3709815e3baSJean-Jacques Hiblot 3719815e3baSJean-Jacques Hiblot return 0; 3729815e3baSJean-Jacques Hiblot } 373f99c2efeSJean-Jacques Hiblot #endif 3749815e3baSJean-Jacques Hiblot 375ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start, 376fdbb873eSKim Phillips lbaint_t blkcnt) 377272cc70bSAndy Fleming { 378272cc70bSAndy Fleming struct mmc_cmd cmd; 379272cc70bSAndy Fleming struct mmc_data data; 380272cc70bSAndy Fleming 3814a1a06bcSAlagu Sankar if (blkcnt > 1) 3824a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; 3834a1a06bcSAlagu Sankar else 384272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; 385272cc70bSAndy Fleming 386272cc70bSAndy Fleming if (mmc->high_capacity) 3874a1a06bcSAlagu Sankar cmd.cmdarg = start; 388272cc70bSAndy Fleming else 3894a1a06bcSAlagu Sankar cmd.cmdarg = start * mmc->read_bl_len; 390272cc70bSAndy Fleming 391272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 392272cc70bSAndy Fleming 393272cc70bSAndy Fleming data.dest = dst; 3944a1a06bcSAlagu Sankar data.blocks = blkcnt; 395272cc70bSAndy Fleming data.blocksize = mmc->read_bl_len; 396272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 397272cc70bSAndy Fleming 3984a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, &data)) 3994a1a06bcSAlagu Sankar return 0; 4004a1a06bcSAlagu Sankar 4014a1a06bcSAlagu Sankar if (blkcnt > 1) { 4024a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; 4034a1a06bcSAlagu Sankar cmd.cmdarg = 0; 4044a1a06bcSAlagu Sankar cmd.resp_type = MMC_RSP_R1b; 4054a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, NULL)) { 40656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 407d8e3d420SJean-Jacques Hiblot pr_err("mmc fail to send stop cmd\n"); 40856196826SPaul Burton #endif 4094a1a06bcSAlagu Sankar return 0; 4104a1a06bcSAlagu Sankar } 411272cc70bSAndy Fleming } 412272cc70bSAndy Fleming 4134a1a06bcSAlagu Sankar return blkcnt; 414272cc70bSAndy Fleming } 415272cc70bSAndy Fleming 416c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK) 4177dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst) 41833fb211dSSimon Glass #else 4197dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, 4207dba0b93SSimon Glass void *dst) 42133fb211dSSimon Glass #endif 422272cc70bSAndy Fleming { 423c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK) 42433fb211dSSimon Glass struct blk_desc *block_dev = dev_get_uclass_platdata(dev); 42533fb211dSSimon Glass #endif 426bcce53d0SSimon Glass int dev_num = block_dev->devnum; 427873cc1d7SStephen Warren int err; 4284a1a06bcSAlagu Sankar lbaint_t cur, blocks_todo = blkcnt; 429272cc70bSAndy Fleming 4304a1a06bcSAlagu Sankar if (blkcnt == 0) 4314a1a06bcSAlagu Sankar return 0; 4324a1a06bcSAlagu Sankar 4334a1a06bcSAlagu Sankar struct mmc *mmc = find_mmc_device(dev_num); 434272cc70bSAndy Fleming if (!mmc) 435272cc70bSAndy Fleming return 0; 436272cc70bSAndy Fleming 437b5b838f1SMarek Vasut if (CONFIG_IS_ENABLED(MMC_TINY)) 438b5b838f1SMarek Vasut err = mmc_switch_part(mmc, block_dev->hwpart); 439b5b838f1SMarek Vasut else 44069f45cd5SSimon Glass err = blk_dselect_hwpart(block_dev, block_dev->hwpart); 441b5b838f1SMarek Vasut 442873cc1d7SStephen Warren if (err < 0) 443873cc1d7SStephen Warren return 0; 444873cc1d7SStephen Warren 445c40fdca6SSimon Glass if ((start + blkcnt) > block_dev->lba) { 44656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 447d8e3d420SJean-Jacques Hiblot pr_err("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", 448c40fdca6SSimon Glass start + blkcnt, block_dev->lba); 44956196826SPaul Burton #endif 450d2bf29e3SLei Wen return 0; 451d2bf29e3SLei Wen } 452272cc70bSAndy Fleming 45311692991SSimon Glass if (mmc_set_blocklen(mmc, mmc->read_bl_len)) { 454d4d64889SMasahiro Yamada pr_debug("%s: Failed to set blocklen\n", __func__); 455272cc70bSAndy Fleming return 0; 45611692991SSimon Glass } 457272cc70bSAndy Fleming 4584a1a06bcSAlagu Sankar do { 45993bfd616SPantelis Antoniou cur = (blocks_todo > mmc->cfg->b_max) ? 46093bfd616SPantelis Antoniou mmc->cfg->b_max : blocks_todo; 46111692991SSimon Glass if (mmc_read_blocks(mmc, dst, start, cur) != cur) { 462d4d64889SMasahiro Yamada pr_debug("%s: Failed to read blocks\n", __func__); 4634a1a06bcSAlagu Sankar return 0; 46411692991SSimon Glass } 4654a1a06bcSAlagu Sankar blocks_todo -= cur; 4664a1a06bcSAlagu Sankar start += cur; 4674a1a06bcSAlagu Sankar dst += cur * mmc->read_bl_len; 4684a1a06bcSAlagu Sankar } while (blocks_todo > 0); 469272cc70bSAndy Fleming 470272cc70bSAndy Fleming return blkcnt; 471272cc70bSAndy Fleming } 472272cc70bSAndy Fleming 473fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc) 474272cc70bSAndy Fleming { 475272cc70bSAndy Fleming struct mmc_cmd cmd; 476272cc70bSAndy Fleming int err; 477272cc70bSAndy Fleming 478272cc70bSAndy Fleming udelay(1000); 479272cc70bSAndy Fleming 480272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_GO_IDLE_STATE; 481272cc70bSAndy Fleming cmd.cmdarg = 0; 482272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_NONE; 483272cc70bSAndy Fleming 484272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 485272cc70bSAndy Fleming 486272cc70bSAndy Fleming if (err) 487272cc70bSAndy Fleming return err; 488272cc70bSAndy Fleming 489272cc70bSAndy Fleming udelay(2000); 490272cc70bSAndy Fleming 491272cc70bSAndy Fleming return 0; 492272cc70bSAndy Fleming } 493272cc70bSAndy Fleming 494f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 495c10b85d6SJean-Jacques Hiblot static int mmc_switch_voltage(struct mmc *mmc, int signal_voltage) 496c10b85d6SJean-Jacques Hiblot { 497c10b85d6SJean-Jacques Hiblot struct mmc_cmd cmd; 498c10b85d6SJean-Jacques Hiblot int err = 0; 499c10b85d6SJean-Jacques Hiblot 500c10b85d6SJean-Jacques Hiblot /* 501c10b85d6SJean-Jacques Hiblot * Send CMD11 only if the request is to switch the card to 502c10b85d6SJean-Jacques Hiblot * 1.8V signalling. 503c10b85d6SJean-Jacques Hiblot */ 504c10b85d6SJean-Jacques Hiblot if (signal_voltage == MMC_SIGNAL_VOLTAGE_330) 505c10b85d6SJean-Jacques Hiblot return mmc_set_signal_voltage(mmc, signal_voltage); 506c10b85d6SJean-Jacques Hiblot 507c10b85d6SJean-Jacques Hiblot cmd.cmdidx = SD_CMD_SWITCH_UHS18V; 508c10b85d6SJean-Jacques Hiblot cmd.cmdarg = 0; 509c10b85d6SJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 510c10b85d6SJean-Jacques Hiblot 511c10b85d6SJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 512c10b85d6SJean-Jacques Hiblot if (err) 513c10b85d6SJean-Jacques Hiblot return err; 514c10b85d6SJean-Jacques Hiblot 515c10b85d6SJean-Jacques Hiblot if (!mmc_host_is_spi(mmc) && (cmd.response[0] & MMC_STATUS_ERROR)) 516c10b85d6SJean-Jacques Hiblot return -EIO; 517c10b85d6SJean-Jacques Hiblot 518c10b85d6SJean-Jacques Hiblot /* 519c10b85d6SJean-Jacques Hiblot * The card should drive cmd and dat[0:3] low immediately 520c10b85d6SJean-Jacques Hiblot * after the response of cmd11, but wait 100 us to be sure 521c10b85d6SJean-Jacques Hiblot */ 522c10b85d6SJean-Jacques Hiblot err = mmc_wait_dat0(mmc, 0, 100); 523c10b85d6SJean-Jacques Hiblot if (err == -ENOSYS) 524c10b85d6SJean-Jacques Hiblot udelay(100); 525c10b85d6SJean-Jacques Hiblot else if (err) 526c10b85d6SJean-Jacques Hiblot return -ETIMEDOUT; 527c10b85d6SJean-Jacques Hiblot 528c10b85d6SJean-Jacques Hiblot /* 529c10b85d6SJean-Jacques Hiblot * During a signal voltage level switch, the clock must be gated 530c10b85d6SJean-Jacques Hiblot * for 5 ms according to the SD spec 531c10b85d6SJean-Jacques Hiblot */ 53265117182SJaehoon Chung mmc_set_clock(mmc, mmc->clock, MMC_CLK_DISABLE); 533c10b85d6SJean-Jacques Hiblot 534c10b85d6SJean-Jacques Hiblot err = mmc_set_signal_voltage(mmc, signal_voltage); 535c10b85d6SJean-Jacques Hiblot if (err) 536c10b85d6SJean-Jacques Hiblot return err; 537c10b85d6SJean-Jacques Hiblot 538c10b85d6SJean-Jacques Hiblot /* Keep clock gated for at least 10 ms, though spec only says 5 ms */ 539c10b85d6SJean-Jacques Hiblot mdelay(10); 54065117182SJaehoon Chung mmc_set_clock(mmc, mmc->clock, MMC_CLK_ENABLE); 541c10b85d6SJean-Jacques Hiblot 542c10b85d6SJean-Jacques Hiblot /* 543c10b85d6SJean-Jacques Hiblot * Failure to switch is indicated by the card holding 544c10b85d6SJean-Jacques Hiblot * dat[0:3] low. Wait for at least 1 ms according to spec 545c10b85d6SJean-Jacques Hiblot */ 546c10b85d6SJean-Jacques Hiblot err = mmc_wait_dat0(mmc, 1, 1000); 547c10b85d6SJean-Jacques Hiblot if (err == -ENOSYS) 548c10b85d6SJean-Jacques Hiblot udelay(1000); 549c10b85d6SJean-Jacques Hiblot else if (err) 550c10b85d6SJean-Jacques Hiblot return -ETIMEDOUT; 551c10b85d6SJean-Jacques Hiblot 552c10b85d6SJean-Jacques Hiblot return 0; 553c10b85d6SJean-Jacques Hiblot } 554f99c2efeSJean-Jacques Hiblot #endif 555c10b85d6SJean-Jacques Hiblot 556c10b85d6SJean-Jacques Hiblot static int sd_send_op_cond(struct mmc *mmc, bool uhs_en) 557272cc70bSAndy Fleming { 558272cc70bSAndy Fleming int timeout = 1000; 559272cc70bSAndy Fleming int err; 560272cc70bSAndy Fleming struct mmc_cmd cmd; 561272cc70bSAndy Fleming 5621677eef4SAndrew Gabbasov while (1) { 563272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 564272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 565272cc70bSAndy Fleming cmd.cmdarg = 0; 566272cc70bSAndy Fleming 567272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 568272cc70bSAndy Fleming 569272cc70bSAndy Fleming if (err) 570272cc70bSAndy Fleming return err; 571272cc70bSAndy Fleming 572272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_OP_COND; 573272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R3; 574250de12bSStefano Babic 575250de12bSStefano Babic /* 576250de12bSStefano Babic * Most cards do not answer if some reserved bits 577250de12bSStefano Babic * in the ocr are set. However, Some controller 578250de12bSStefano Babic * can set bit 7 (reserved for low voltages), but 579250de12bSStefano Babic * how to manage low voltages SD card is not yet 580250de12bSStefano Babic * specified. 581250de12bSStefano Babic */ 582d52ebf10SThomas Chou cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 : 58393bfd616SPantelis Antoniou (mmc->cfg->voltages & 0xff8000); 584272cc70bSAndy Fleming 585272cc70bSAndy Fleming if (mmc->version == SD_VERSION_2) 586272cc70bSAndy Fleming cmd.cmdarg |= OCR_HCS; 587272cc70bSAndy Fleming 588c10b85d6SJean-Jacques Hiblot if (uhs_en) 589c10b85d6SJean-Jacques Hiblot cmd.cmdarg |= OCR_S18R; 590c10b85d6SJean-Jacques Hiblot 591272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 592272cc70bSAndy Fleming 593272cc70bSAndy Fleming if (err) 594272cc70bSAndy Fleming return err; 595272cc70bSAndy Fleming 5961677eef4SAndrew Gabbasov if (cmd.response[0] & OCR_BUSY) 5971677eef4SAndrew Gabbasov break; 598272cc70bSAndy Fleming 5991677eef4SAndrew Gabbasov if (timeout-- <= 0) 600915ffa52SJaehoon Chung return -EOPNOTSUPP; 601272cc70bSAndy Fleming 6021677eef4SAndrew Gabbasov udelay(1000); 6031677eef4SAndrew Gabbasov } 6041677eef4SAndrew Gabbasov 605272cc70bSAndy Fleming if (mmc->version != SD_VERSION_2) 606272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 607272cc70bSAndy Fleming 608d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 609d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 610d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 611d52ebf10SThomas Chou cmd.cmdarg = 0; 612d52ebf10SThomas Chou 613d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 614d52ebf10SThomas Chou 615d52ebf10SThomas Chou if (err) 616d52ebf10SThomas Chou return err; 617d52ebf10SThomas Chou } 618d52ebf10SThomas Chou 619998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 620272cc70bSAndy Fleming 621f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 622c10b85d6SJean-Jacques Hiblot if (uhs_en && !(mmc_host_is_spi(mmc)) && (cmd.response[0] & 0x41000000) 623c10b85d6SJean-Jacques Hiblot == 0x41000000) { 624c10b85d6SJean-Jacques Hiblot err = mmc_switch_voltage(mmc, MMC_SIGNAL_VOLTAGE_180); 625c10b85d6SJean-Jacques Hiblot if (err) 626c10b85d6SJean-Jacques Hiblot return err; 627c10b85d6SJean-Jacques Hiblot } 628f99c2efeSJean-Jacques Hiblot #endif 629c10b85d6SJean-Jacques Hiblot 630272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 631272cc70bSAndy Fleming mmc->rca = 0; 632272cc70bSAndy Fleming 633272cc70bSAndy Fleming return 0; 634272cc70bSAndy Fleming } 635272cc70bSAndy Fleming 6365289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg) 637272cc70bSAndy Fleming { 6385289b535SAndrew Gabbasov struct mmc_cmd cmd; 639272cc70bSAndy Fleming int err; 640272cc70bSAndy Fleming 6415289b535SAndrew Gabbasov cmd.cmdidx = MMC_CMD_SEND_OP_COND; 6425289b535SAndrew Gabbasov cmd.resp_type = MMC_RSP_R3; 6435289b535SAndrew Gabbasov cmd.cmdarg = 0; 6445a20397bSRob Herring if (use_arg && !mmc_host_is_spi(mmc)) 6455a20397bSRob Herring cmd.cmdarg = OCR_HCS | 64693bfd616SPantelis Antoniou (mmc->cfg->voltages & 647a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_VOLTAGE_MASK)) | 648a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_ACCESS_MODE); 649e9550449SChe-Liang Chiou 6505289b535SAndrew Gabbasov err = mmc_send_cmd(mmc, &cmd, NULL); 651e9550449SChe-Liang Chiou if (err) 652e9550449SChe-Liang Chiou return err; 6535289b535SAndrew Gabbasov mmc->ocr = cmd.response[0]; 654e9550449SChe-Liang Chiou return 0; 655e9550449SChe-Liang Chiou } 656e9550449SChe-Liang Chiou 657750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc) 658e9550449SChe-Liang Chiou { 659e9550449SChe-Liang Chiou int err, i; 660e9550449SChe-Liang Chiou 661272cc70bSAndy Fleming /* Some cards seem to need this */ 662272cc70bSAndy Fleming mmc_go_idle(mmc); 663272cc70bSAndy Fleming 66431cacbabSRaffaele Recalcati /* Asking to the card its capabilities */ 665e9550449SChe-Liang Chiou for (i = 0; i < 2; i++) { 6665289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, i != 0); 66731cacbabSRaffaele Recalcati if (err) 66831cacbabSRaffaele Recalcati return err; 66931cacbabSRaffaele Recalcati 670e9550449SChe-Liang Chiou /* exit if not busy (flag seems to be inverted) */ 671a626c8d4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 672bd47c135SAndrew Gabbasov break; 673e9550449SChe-Liang Chiou } 674bd47c135SAndrew Gabbasov mmc->op_cond_pending = 1; 675bd47c135SAndrew Gabbasov return 0; 676e9550449SChe-Liang Chiou } 67731cacbabSRaffaele Recalcati 678750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc) 679e9550449SChe-Liang Chiou { 680e9550449SChe-Liang Chiou struct mmc_cmd cmd; 681e9550449SChe-Liang Chiou int timeout = 1000; 682*36332b6eSVipul Kumar ulong start; 683e9550449SChe-Liang Chiou int err; 684e9550449SChe-Liang Chiou 685e9550449SChe-Liang Chiou mmc->op_cond_pending = 0; 686cc17c01fSAndrew Gabbasov if (!(mmc->ocr & OCR_BUSY)) { 687d188b113SYangbo Lu /* Some cards seem to need this */ 688d188b113SYangbo Lu mmc_go_idle(mmc); 689d188b113SYangbo Lu 690e9550449SChe-Liang Chiou start = get_timer(0); 6911677eef4SAndrew Gabbasov while (1) { 6925289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, 1); 693272cc70bSAndy Fleming if (err) 694272cc70bSAndy Fleming return err; 6951677eef4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 6961677eef4SAndrew Gabbasov break; 697e9550449SChe-Liang Chiou if (get_timer(start) > timeout) 698915ffa52SJaehoon Chung return -EOPNOTSUPP; 699e9550449SChe-Liang Chiou udelay(100); 7001677eef4SAndrew Gabbasov } 701cc17c01fSAndrew Gabbasov } 702272cc70bSAndy Fleming 703d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 704d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 705d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 706d52ebf10SThomas Chou cmd.cmdarg = 0; 707d52ebf10SThomas Chou 708d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 709d52ebf10SThomas Chou 710d52ebf10SThomas Chou if (err) 711d52ebf10SThomas Chou return err; 712a626c8d4SAndrew Gabbasov 713a626c8d4SAndrew Gabbasov mmc->ocr = cmd.response[0]; 714d52ebf10SThomas Chou } 715d52ebf10SThomas Chou 716272cc70bSAndy Fleming mmc->version = MMC_VERSION_UNKNOWN; 717272cc70bSAndy Fleming 718272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 719def816a2SStephen Warren mmc->rca = 1; 720272cc70bSAndy Fleming 721272cc70bSAndy Fleming return 0; 722272cc70bSAndy Fleming } 723272cc70bSAndy Fleming 724272cc70bSAndy Fleming 725fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) 726272cc70bSAndy Fleming { 727272cc70bSAndy Fleming struct mmc_cmd cmd; 728272cc70bSAndy Fleming struct mmc_data data; 729272cc70bSAndy Fleming int err; 730272cc70bSAndy Fleming 731272cc70bSAndy Fleming /* Get the Card Status Register */ 732272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_EXT_CSD; 733272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 734272cc70bSAndy Fleming cmd.cmdarg = 0; 735272cc70bSAndy Fleming 736cdfd1ac6SYoshihiro Shimoda data.dest = (char *)ext_csd; 737272cc70bSAndy Fleming data.blocks = 1; 7388bfa195eSSimon Glass data.blocksize = MMC_MAX_BLOCK_LEN; 739272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 740272cc70bSAndy Fleming 741272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 742272cc70bSAndy Fleming 743272cc70bSAndy Fleming return err; 744272cc70bSAndy Fleming } 745272cc70bSAndy Fleming 746c40704f4SSimon Glass int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) 747272cc70bSAndy Fleming { 748272cc70bSAndy Fleming struct mmc_cmd cmd; 7495d4fc8d9SRaffaele Recalcati int timeout = 1000; 750a9003dc6SMaxime Ripard int retries = 3; 7515d4fc8d9SRaffaele Recalcati int ret; 752272cc70bSAndy Fleming 753272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SWITCH; 754272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 755272cc70bSAndy Fleming cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 756272cc70bSAndy Fleming (index << 16) | 757272cc70bSAndy Fleming (value << 8); 758272cc70bSAndy Fleming 759a9003dc6SMaxime Ripard while (retries > 0) { 7605d4fc8d9SRaffaele Recalcati ret = mmc_send_cmd(mmc, &cmd, NULL); 7615d4fc8d9SRaffaele Recalcati 7625d4fc8d9SRaffaele Recalcati /* Waiting for the ready status */ 763a9003dc6SMaxime Ripard if (!ret) { 76493ad0d18SJan Kloetzke ret = mmc_send_status(mmc, timeout); 765a9003dc6SMaxime Ripard return ret; 766a9003dc6SMaxime Ripard } 767a9003dc6SMaxime Ripard 768a9003dc6SMaxime Ripard retries--; 769a9003dc6SMaxime Ripard } 7705d4fc8d9SRaffaele Recalcati 7715d4fc8d9SRaffaele Recalcati return ret; 7725d4fc8d9SRaffaele Recalcati 773272cc70bSAndy Fleming } 774272cc70bSAndy Fleming 7753862b854SJean-Jacques Hiblot static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode) 776272cc70bSAndy Fleming { 777272cc70bSAndy Fleming int err; 7783862b854SJean-Jacques Hiblot int speed_bits; 7793862b854SJean-Jacques Hiblot 7803862b854SJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 7813862b854SJean-Jacques Hiblot 7823862b854SJean-Jacques Hiblot switch (mode) { 7833862b854SJean-Jacques Hiblot case MMC_HS: 7843862b854SJean-Jacques Hiblot case MMC_HS_52: 7853862b854SJean-Jacques Hiblot case MMC_DDR_52: 7863862b854SJean-Jacques Hiblot speed_bits = EXT_CSD_TIMING_HS; 787634d4849SKishon Vijay Abraham I break; 788baef2070SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) 789634d4849SKishon Vijay Abraham I case MMC_HS_200: 790634d4849SKishon Vijay Abraham I speed_bits = EXT_CSD_TIMING_HS200; 791634d4849SKishon Vijay Abraham I break; 792baef2070SJean-Jacques Hiblot #endif 7933862b854SJean-Jacques Hiblot case MMC_LEGACY: 7943862b854SJean-Jacques Hiblot speed_bits = EXT_CSD_TIMING_LEGACY; 7953862b854SJean-Jacques Hiblot break; 7963862b854SJean-Jacques Hiblot default: 7973862b854SJean-Jacques Hiblot return -EINVAL; 7983862b854SJean-Jacques Hiblot } 7993862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 8003862b854SJean-Jacques Hiblot speed_bits); 8013862b854SJean-Jacques Hiblot if (err) 8023862b854SJean-Jacques Hiblot return err; 8033862b854SJean-Jacques Hiblot 8043862b854SJean-Jacques Hiblot if ((mode == MMC_HS) || (mode == MMC_HS_52)) { 8053862b854SJean-Jacques Hiblot /* Now check to see that it worked */ 8063862b854SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, test_csd); 8073862b854SJean-Jacques Hiblot if (err) 8083862b854SJean-Jacques Hiblot return err; 8093862b854SJean-Jacques Hiblot 8103862b854SJean-Jacques Hiblot /* No high-speed support */ 8113862b854SJean-Jacques Hiblot if (!test_csd[EXT_CSD_HS_TIMING]) 8123862b854SJean-Jacques Hiblot return -ENOTSUPP; 8133862b854SJean-Jacques Hiblot } 8143862b854SJean-Jacques Hiblot 8153862b854SJean-Jacques Hiblot return 0; 8163862b854SJean-Jacques Hiblot } 8173862b854SJean-Jacques Hiblot 8183862b854SJean-Jacques Hiblot static int mmc_get_capabilities(struct mmc *mmc) 8193862b854SJean-Jacques Hiblot { 8203862b854SJean-Jacques Hiblot u8 *ext_csd = mmc->ext_csd; 8213862b854SJean-Jacques Hiblot char cardtype; 822272cc70bSAndy Fleming 82300e446faSJean-Jacques Hiblot mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(MMC_LEGACY); 824272cc70bSAndy Fleming 825d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 826d52ebf10SThomas Chou return 0; 827d52ebf10SThomas Chou 828272cc70bSAndy Fleming /* Only version 4 supports high-speed */ 829272cc70bSAndy Fleming if (mmc->version < MMC_VERSION_4) 830272cc70bSAndy Fleming return 0; 831272cc70bSAndy Fleming 8323862b854SJean-Jacques Hiblot if (!ext_csd) { 833d8e3d420SJean-Jacques Hiblot pr_err("No ext_csd found!\n"); /* this should enver happen */ 8343862b854SJean-Jacques Hiblot return -ENOTSUPP; 8353862b854SJean-Jacques Hiblot } 8363862b854SJean-Jacques Hiblot 837fc5b32fbSAndrew Gabbasov mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; 838fc5b32fbSAndrew Gabbasov 839634d4849SKishon Vijay Abraham I cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0x3f; 840bc1e3272SJean-Jacques Hiblot mmc->cardtype = cardtype; 841272cc70bSAndy Fleming 842baef2070SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) 843634d4849SKishon Vijay Abraham I if (cardtype & (EXT_CSD_CARD_TYPE_HS200_1_2V | 844634d4849SKishon Vijay Abraham I EXT_CSD_CARD_TYPE_HS200_1_8V)) { 845634d4849SKishon Vijay Abraham I mmc->card_caps |= MMC_MODE_HS200; 846634d4849SKishon Vijay Abraham I } 847baef2070SJean-Jacques Hiblot #endif 848d22e3d46SJaehoon Chung if (cardtype & EXT_CSD_CARD_TYPE_52) { 8493862b854SJean-Jacques Hiblot if (cardtype & EXT_CSD_CARD_TYPE_DDR_52) 850d22e3d46SJaehoon Chung mmc->card_caps |= MMC_MODE_DDR_52MHz; 8513862b854SJean-Jacques Hiblot mmc->card_caps |= MMC_MODE_HS_52MHz; 852d22e3d46SJaehoon Chung } 8533862b854SJean-Jacques Hiblot if (cardtype & EXT_CSD_CARD_TYPE_26) 8543862b854SJean-Jacques Hiblot mmc->card_caps |= MMC_MODE_HS; 855272cc70bSAndy Fleming 856272cc70bSAndy Fleming return 0; 857272cc70bSAndy Fleming } 858272cc70bSAndy Fleming 859f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num) 860f866a46dSStephen Warren { 861f866a46dSStephen Warren switch (part_num) { 862f866a46dSStephen Warren case 0: 863f866a46dSStephen Warren mmc->capacity = mmc->capacity_user; 864f866a46dSStephen Warren break; 865f866a46dSStephen Warren case 1: 866f866a46dSStephen Warren case 2: 867f866a46dSStephen Warren mmc->capacity = mmc->capacity_boot; 868f866a46dSStephen Warren break; 869f866a46dSStephen Warren case 3: 870f866a46dSStephen Warren mmc->capacity = mmc->capacity_rpmb; 871f866a46dSStephen Warren break; 872f866a46dSStephen Warren case 4: 873f866a46dSStephen Warren case 5: 874f866a46dSStephen Warren case 6: 875f866a46dSStephen Warren case 7: 876f866a46dSStephen Warren mmc->capacity = mmc->capacity_gp[part_num - 4]; 877f866a46dSStephen Warren break; 878f866a46dSStephen Warren default: 879f866a46dSStephen Warren return -1; 880f866a46dSStephen Warren } 881f866a46dSStephen Warren 882c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len); 883f866a46dSStephen Warren 884f866a46dSStephen Warren return 0; 885f866a46dSStephen Warren } 886f866a46dSStephen Warren 887f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) 88801298da3SJean-Jacques Hiblot static int mmc_boot_part_access_chk(struct mmc *mmc, unsigned int part_num) 88901298da3SJean-Jacques Hiblot { 89001298da3SJean-Jacques Hiblot int forbidden = 0; 89101298da3SJean-Jacques Hiblot bool change = false; 89201298da3SJean-Jacques Hiblot 89301298da3SJean-Jacques Hiblot if (part_num & PART_ACCESS_MASK) 89401298da3SJean-Jacques Hiblot forbidden = MMC_CAP(MMC_HS_200); 89501298da3SJean-Jacques Hiblot 89601298da3SJean-Jacques Hiblot if (MMC_CAP(mmc->selected_mode) & forbidden) { 897d4d64889SMasahiro Yamada pr_debug("selected mode (%s) is forbidden for part %d\n", 89801298da3SJean-Jacques Hiblot mmc_mode_name(mmc->selected_mode), part_num); 89901298da3SJean-Jacques Hiblot change = true; 90001298da3SJean-Jacques Hiblot } else if (mmc->selected_mode != mmc->best_mode) { 901d4d64889SMasahiro Yamada pr_debug("selected mode is not optimal\n"); 90201298da3SJean-Jacques Hiblot change = true; 90301298da3SJean-Jacques Hiblot } 90401298da3SJean-Jacques Hiblot 90501298da3SJean-Jacques Hiblot if (change) 90601298da3SJean-Jacques Hiblot return mmc_select_mode_and_width(mmc, 90701298da3SJean-Jacques Hiblot mmc->card_caps & ~forbidden); 90801298da3SJean-Jacques Hiblot 90901298da3SJean-Jacques Hiblot return 0; 91001298da3SJean-Jacques Hiblot } 911f99c2efeSJean-Jacques Hiblot #else 912f99c2efeSJean-Jacques Hiblot static inline int mmc_boot_part_access_chk(struct mmc *mmc, 913f99c2efeSJean-Jacques Hiblot unsigned int part_num) 914f99c2efeSJean-Jacques Hiblot { 915f99c2efeSJean-Jacques Hiblot return 0; 916f99c2efeSJean-Jacques Hiblot } 917f99c2efeSJean-Jacques Hiblot #endif 91801298da3SJean-Jacques Hiblot 9197dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num) 920bc897b1dSLei Wen { 921f866a46dSStephen Warren int ret; 922bc897b1dSLei Wen 92301298da3SJean-Jacques Hiblot ret = mmc_boot_part_access_chk(mmc, part_num); 92401298da3SJean-Jacques Hiblot if (ret) 92501298da3SJean-Jacques Hiblot return ret; 92601298da3SJean-Jacques Hiblot 927f866a46dSStephen Warren ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 928bc897b1dSLei Wen (mmc->part_config & ~PART_ACCESS_MASK) 929bc897b1dSLei Wen | (part_num & PART_ACCESS_MASK)); 930f866a46dSStephen Warren 9316dc93e70SPeter Bigot /* 9326dc93e70SPeter Bigot * Set the capacity if the switch succeeded or was intended 9336dc93e70SPeter Bigot * to return to representing the raw device. 9346dc93e70SPeter Bigot */ 935873cc1d7SStephen Warren if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) { 9366dc93e70SPeter Bigot ret = mmc_set_capacity(mmc, part_num); 937fdbb139fSSimon Glass mmc_get_blk_desc(mmc)->hwpart = part_num; 938873cc1d7SStephen Warren } 9396dc93e70SPeter Bigot 9406dc93e70SPeter Bigot return ret; 941bc897b1dSLei Wen } 942bc897b1dSLei Wen 943cf17789eSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING) 944ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc, 945ac9da0e0SDiego Santa Cruz const struct mmc_hwpart_conf *conf, 946ac9da0e0SDiego Santa Cruz enum mmc_hwpart_conf_mode mode) 947ac9da0e0SDiego Santa Cruz { 948ac9da0e0SDiego Santa Cruz u8 part_attrs = 0; 949ac9da0e0SDiego Santa Cruz u32 enh_size_mult; 950ac9da0e0SDiego Santa Cruz u32 enh_start_addr; 951ac9da0e0SDiego Santa Cruz u32 gp_size_mult[4]; 952ac9da0e0SDiego Santa Cruz u32 max_enh_size_mult; 953ac9da0e0SDiego Santa Cruz u32 tot_enh_size_mult = 0; 9548dda5b0eSDiego Santa Cruz u8 wr_rel_set; 955ac9da0e0SDiego Santa Cruz int i, pidx, err; 956ac9da0e0SDiego Santa Cruz ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 957ac9da0e0SDiego Santa Cruz 958ac9da0e0SDiego Santa Cruz if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE) 959ac9da0e0SDiego Santa Cruz return -EINVAL; 960ac9da0e0SDiego Santa Cruz 961ac9da0e0SDiego Santa Cruz if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) { 962d8e3d420SJean-Jacques Hiblot pr_err("eMMC >= 4.4 required for enhanced user data area\n"); 963ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 964ac9da0e0SDiego Santa Cruz } 965ac9da0e0SDiego Santa Cruz 966ac9da0e0SDiego Santa Cruz if (!(mmc->part_support & PART_SUPPORT)) { 967d8e3d420SJean-Jacques Hiblot pr_err("Card does not support partitioning\n"); 968ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 969ac9da0e0SDiego Santa Cruz } 970ac9da0e0SDiego Santa Cruz 971ac9da0e0SDiego Santa Cruz if (!mmc->hc_wp_grp_size) { 972d8e3d420SJean-Jacques Hiblot pr_err("Card does not define HC WP group size\n"); 973ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 974ac9da0e0SDiego Santa Cruz } 975ac9da0e0SDiego Santa Cruz 976ac9da0e0SDiego Santa Cruz /* check partition alignment and total enhanced size */ 977ac9da0e0SDiego Santa Cruz if (conf->user.enh_size) { 978ac9da0e0SDiego Santa Cruz if (conf->user.enh_size % mmc->hc_wp_grp_size || 979ac9da0e0SDiego Santa Cruz conf->user.enh_start % mmc->hc_wp_grp_size) { 980d8e3d420SJean-Jacques Hiblot pr_err("User data enhanced area not HC WP group " 981ac9da0e0SDiego Santa Cruz "size aligned\n"); 982ac9da0e0SDiego Santa Cruz return -EINVAL; 983ac9da0e0SDiego Santa Cruz } 984ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_USR; 985ac9da0e0SDiego Santa Cruz enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size; 986ac9da0e0SDiego Santa Cruz if (mmc->high_capacity) { 987ac9da0e0SDiego Santa Cruz enh_start_addr = conf->user.enh_start; 988ac9da0e0SDiego Santa Cruz } else { 989ac9da0e0SDiego Santa Cruz enh_start_addr = (conf->user.enh_start << 9); 990ac9da0e0SDiego Santa Cruz } 991ac9da0e0SDiego Santa Cruz } else { 992ac9da0e0SDiego Santa Cruz enh_size_mult = 0; 993ac9da0e0SDiego Santa Cruz enh_start_addr = 0; 994ac9da0e0SDiego Santa Cruz } 995ac9da0e0SDiego Santa Cruz tot_enh_size_mult += enh_size_mult; 996ac9da0e0SDiego Santa Cruz 997ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 998ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) { 999d8e3d420SJean-Jacques Hiblot pr_err("GP%i partition not HC WP group size " 1000ac9da0e0SDiego Santa Cruz "aligned\n", pidx+1); 1001ac9da0e0SDiego Santa Cruz return -EINVAL; 1002ac9da0e0SDiego Santa Cruz } 1003ac9da0e0SDiego Santa Cruz gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size; 1004ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) { 1005ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_GP(pidx); 1006ac9da0e0SDiego Santa Cruz tot_enh_size_mult += gp_size_mult[pidx]; 1007ac9da0e0SDiego Santa Cruz } 1008ac9da0e0SDiego Santa Cruz } 1009ac9da0e0SDiego Santa Cruz 1010ac9da0e0SDiego Santa Cruz if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) { 1011d8e3d420SJean-Jacques Hiblot pr_err("Card does not support enhanced attribute\n"); 1012ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1013ac9da0e0SDiego Santa Cruz } 1014ac9da0e0SDiego Santa Cruz 1015ac9da0e0SDiego Santa Cruz err = mmc_send_ext_csd(mmc, ext_csd); 1016ac9da0e0SDiego Santa Cruz if (err) 1017ac9da0e0SDiego Santa Cruz return err; 1018ac9da0e0SDiego Santa Cruz 1019ac9da0e0SDiego Santa Cruz max_enh_size_mult = 1020ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) + 1021ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) + 1022ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]; 1023ac9da0e0SDiego Santa Cruz if (tot_enh_size_mult > max_enh_size_mult) { 1024d8e3d420SJean-Jacques Hiblot pr_err("Total enhanced size exceeds maximum (%u > %u)\n", 1025ac9da0e0SDiego Santa Cruz tot_enh_size_mult, max_enh_size_mult); 1026ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1027ac9da0e0SDiego Santa Cruz } 1028ac9da0e0SDiego Santa Cruz 10298dda5b0eSDiego Santa Cruz /* The default value of EXT_CSD_WR_REL_SET is device 10308dda5b0eSDiego Santa Cruz * dependent, the values can only be changed if the 10318dda5b0eSDiego Santa Cruz * EXT_CSD_HS_CTRL_REL bit is set. The values can be 10328dda5b0eSDiego Santa Cruz * changed only once and before partitioning is completed. */ 10338dda5b0eSDiego Santa Cruz wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 10348dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_change) { 10358dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_set) 10368dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_USR; 10378dda5b0eSDiego Santa Cruz else 10388dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR; 10398dda5b0eSDiego Santa Cruz } 10408dda5b0eSDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 10418dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_change) { 10428dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_set) 10438dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx); 10448dda5b0eSDiego Santa Cruz else 10458dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx); 10468dda5b0eSDiego Santa Cruz } 10478dda5b0eSDiego Santa Cruz } 10488dda5b0eSDiego Santa Cruz 10498dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] && 10508dda5b0eSDiego Santa Cruz !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) { 10518dda5b0eSDiego Santa Cruz puts("Card does not support host controlled partition write " 10528dda5b0eSDiego Santa Cruz "reliability settings\n"); 10538dda5b0eSDiego Santa Cruz return -EMEDIUMTYPE; 10548dda5b0eSDiego Santa Cruz } 10558dda5b0eSDiego Santa Cruz 1056ac9da0e0SDiego Santa Cruz if (ext_csd[EXT_CSD_PARTITION_SETTING] & 1057ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED) { 1058d8e3d420SJean-Jacques Hiblot pr_err("Card already partitioned\n"); 1059ac9da0e0SDiego Santa Cruz return -EPERM; 1060ac9da0e0SDiego Santa Cruz } 1061ac9da0e0SDiego Santa Cruz 1062ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_CHECK) 1063ac9da0e0SDiego Santa Cruz return 0; 1064ac9da0e0SDiego Santa Cruz 1065ac9da0e0SDiego Santa Cruz /* Partitioning requires high-capacity size definitions */ 1066ac9da0e0SDiego Santa Cruz if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) { 1067ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1068ac9da0e0SDiego Santa Cruz EXT_CSD_ERASE_GROUP_DEF, 1); 1069ac9da0e0SDiego Santa Cruz 1070ac9da0e0SDiego Santa Cruz if (err) 1071ac9da0e0SDiego Santa Cruz return err; 1072ac9da0e0SDiego Santa Cruz 1073ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 1074ac9da0e0SDiego Santa Cruz 1075ac9da0e0SDiego Santa Cruz /* update erase group size to be high-capacity */ 1076ac9da0e0SDiego Santa Cruz mmc->erase_grp_size = 1077ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 1078ac9da0e0SDiego Santa Cruz 1079ac9da0e0SDiego Santa Cruz } 1080ac9da0e0SDiego Santa Cruz 1081ac9da0e0SDiego Santa Cruz /* all OK, write the configuration */ 1082ac9da0e0SDiego Santa Cruz for (i = 0; i < 4; i++) { 1083ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1084ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_START_ADDR+i, 1085ac9da0e0SDiego Santa Cruz (enh_start_addr >> (i*8)) & 0xFF); 1086ac9da0e0SDiego Santa Cruz if (err) 1087ac9da0e0SDiego Santa Cruz return err; 1088ac9da0e0SDiego Santa Cruz } 1089ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 1090ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1091ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_SIZE_MULT+i, 1092ac9da0e0SDiego Santa Cruz (enh_size_mult >> (i*8)) & 0xFF); 1093ac9da0e0SDiego Santa Cruz if (err) 1094ac9da0e0SDiego Santa Cruz return err; 1095ac9da0e0SDiego Santa Cruz } 1096ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 1097ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 1098ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1099ac9da0e0SDiego Santa Cruz EXT_CSD_GP_SIZE_MULT+pidx*3+i, 1100ac9da0e0SDiego Santa Cruz (gp_size_mult[pidx] >> (i*8)) & 0xFF); 1101ac9da0e0SDiego Santa Cruz if (err) 1102ac9da0e0SDiego Santa Cruz return err; 1103ac9da0e0SDiego Santa Cruz } 1104ac9da0e0SDiego Santa Cruz } 1105ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1106ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs); 1107ac9da0e0SDiego Santa Cruz if (err) 1108ac9da0e0SDiego Santa Cruz return err; 1109ac9da0e0SDiego Santa Cruz 1110ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_SET) 1111ac9da0e0SDiego Santa Cruz return 0; 1112ac9da0e0SDiego Santa Cruz 11138dda5b0eSDiego Santa Cruz /* The WR_REL_SET is a write-once register but shall be 11148dda5b0eSDiego Santa Cruz * written before setting PART_SETTING_COMPLETED. As it is 11158dda5b0eSDiego Santa Cruz * write-once we can only write it when completing the 11168dda5b0eSDiego Santa Cruz * partitioning. */ 11178dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) { 11188dda5b0eSDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 11198dda5b0eSDiego Santa Cruz EXT_CSD_WR_REL_SET, wr_rel_set); 11208dda5b0eSDiego Santa Cruz if (err) 11218dda5b0eSDiego Santa Cruz return err; 11228dda5b0eSDiego Santa Cruz } 11238dda5b0eSDiego Santa Cruz 1124ac9da0e0SDiego Santa Cruz /* Setting PART_SETTING_COMPLETED confirms the partition 1125ac9da0e0SDiego Santa Cruz * configuration but it only becomes effective after power 1126ac9da0e0SDiego Santa Cruz * cycle, so we do not adjust the partition related settings 1127ac9da0e0SDiego Santa Cruz * in the mmc struct. */ 1128ac9da0e0SDiego Santa Cruz 1129ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1130ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING, 1131ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 1132ac9da0e0SDiego Santa Cruz if (err) 1133ac9da0e0SDiego Santa Cruz return err; 1134ac9da0e0SDiego Santa Cruz 1135ac9da0e0SDiego Santa Cruz return 0; 1136ac9da0e0SDiego Santa Cruz } 1137cf17789eSJean-Jacques Hiblot #endif 1138ac9da0e0SDiego Santa Cruz 1139e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 114048972d90SThierry Reding int mmc_getcd(struct mmc *mmc) 114148972d90SThierry Reding { 114248972d90SThierry Reding int cd; 114348972d90SThierry Reding 114448972d90SThierry Reding cd = board_mmc_getcd(mmc); 114548972d90SThierry Reding 1146d4e1da4eSPeter Korsgaard if (cd < 0) { 114793bfd616SPantelis Antoniou if (mmc->cfg->ops->getcd) 114893bfd616SPantelis Antoniou cd = mmc->cfg->ops->getcd(mmc); 1149d4e1da4eSPeter Korsgaard else 1150d4e1da4eSPeter Korsgaard cd = 1; 1151d4e1da4eSPeter Korsgaard } 115248972d90SThierry Reding 115348972d90SThierry Reding return cd; 115448972d90SThierry Reding } 11558ca51e51SSimon Glass #endif 115648972d90SThierry Reding 1157fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) 1158272cc70bSAndy Fleming { 1159272cc70bSAndy Fleming struct mmc_cmd cmd; 1160272cc70bSAndy Fleming struct mmc_data data; 1161272cc70bSAndy Fleming 1162272cc70bSAndy Fleming /* Switch the frequency */ 1163272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC; 1164272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1165272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff; 1166272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4)); 1167272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4); 1168272cc70bSAndy Fleming 1169272cc70bSAndy Fleming data.dest = (char *)resp; 1170272cc70bSAndy Fleming data.blocksize = 64; 1171272cc70bSAndy Fleming data.blocks = 1; 1172272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1173272cc70bSAndy Fleming 1174272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 1175272cc70bSAndy Fleming } 1176272cc70bSAndy Fleming 1177272cc70bSAndy Fleming 1178d0c221feSJean-Jacques Hiblot static int sd_get_capabilities(struct mmc *mmc) 1179272cc70bSAndy Fleming { 1180272cc70bSAndy Fleming int err; 1181272cc70bSAndy Fleming struct mmc_cmd cmd; 118218e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2); 118318e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16); 1184272cc70bSAndy Fleming struct mmc_data data; 1185272cc70bSAndy Fleming int timeout; 1186f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1187c10b85d6SJean-Jacques Hiblot u32 sd3_bus_mode; 1188f99c2efeSJean-Jacques Hiblot #endif 1189272cc70bSAndy Fleming 119000e446faSJean-Jacques Hiblot mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(SD_LEGACY); 1191272cc70bSAndy Fleming 1192d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 1193d52ebf10SThomas Chou return 0; 1194d52ebf10SThomas Chou 1195272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */ 1196272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 1197272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1198272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1199272cc70bSAndy Fleming 1200272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1201272cc70bSAndy Fleming 1202272cc70bSAndy Fleming if (err) 1203272cc70bSAndy Fleming return err; 1204272cc70bSAndy Fleming 1205272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR; 1206272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1207272cc70bSAndy Fleming cmd.cmdarg = 0; 1208272cc70bSAndy Fleming 1209272cc70bSAndy Fleming timeout = 3; 1210272cc70bSAndy Fleming 1211272cc70bSAndy Fleming retry_scr: 1212f781dd38SAnton staaf data.dest = (char *)scr; 1213272cc70bSAndy Fleming data.blocksize = 8; 1214272cc70bSAndy Fleming data.blocks = 1; 1215272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1216272cc70bSAndy Fleming 1217272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 1218272cc70bSAndy Fleming 1219272cc70bSAndy Fleming if (err) { 1220272cc70bSAndy Fleming if (timeout--) 1221272cc70bSAndy Fleming goto retry_scr; 1222272cc70bSAndy Fleming 1223272cc70bSAndy Fleming return err; 1224272cc70bSAndy Fleming } 1225272cc70bSAndy Fleming 12264e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]); 12274e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]); 1228272cc70bSAndy Fleming 1229272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) { 1230272cc70bSAndy Fleming case 0: 1231272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1232272cc70bSAndy Fleming break; 1233272cc70bSAndy Fleming case 1: 1234272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10; 1235272cc70bSAndy Fleming break; 1236272cc70bSAndy Fleming case 2: 1237272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 12381741c64dSJaehoon Chung if ((mmc->scr[0] >> 15) & 0x1) 12391741c64dSJaehoon Chung mmc->version = SD_VERSION_3; 1240272cc70bSAndy Fleming break; 1241272cc70bSAndy Fleming default: 1242272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1243272cc70bSAndy Fleming break; 1244272cc70bSAndy Fleming } 1245272cc70bSAndy Fleming 1246b44c7083SAlagu Sankar if (mmc->scr[0] & SD_DATA_4BIT) 1247b44c7083SAlagu Sankar mmc->card_caps |= MMC_MODE_4BIT; 1248b44c7083SAlagu Sankar 1249272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */ 1250272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0) 1251272cc70bSAndy Fleming return 0; 1252272cc70bSAndy Fleming 1253272cc70bSAndy Fleming timeout = 4; 1254272cc70bSAndy Fleming while (timeout--) { 1255272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, 1256f781dd38SAnton staaf (u8 *)switch_status); 1257272cc70bSAndy Fleming 1258272cc70bSAndy Fleming if (err) 1259272cc70bSAndy Fleming return err; 1260272cc70bSAndy Fleming 1261272cc70bSAndy Fleming /* The high-speed function is busy. Try again */ 12624e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) 1263272cc70bSAndy Fleming break; 1264272cc70bSAndy Fleming } 1265272cc70bSAndy Fleming 1266272cc70bSAndy Fleming /* If high-speed isn't supported, we return */ 1267d0c221feSJean-Jacques Hiblot if (__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED) 1268d0c221feSJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(SD_HS); 1269272cc70bSAndy Fleming 1270f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1271c10b85d6SJean-Jacques Hiblot /* Version before 3.0 don't support UHS modes */ 1272c10b85d6SJean-Jacques Hiblot if (mmc->version < SD_VERSION_3) 1273c10b85d6SJean-Jacques Hiblot return 0; 1274c10b85d6SJean-Jacques Hiblot 1275c10b85d6SJean-Jacques Hiblot sd3_bus_mode = __be32_to_cpu(switch_status[3]) >> 16 & 0x1f; 1276c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR104) 1277c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR104); 1278c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR50) 1279c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR50); 1280c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR25) 1281c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR25); 1282c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR12) 1283c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR12); 1284c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_DDR50) 1285c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_DDR50); 1286f99c2efeSJean-Jacques Hiblot #endif 1287c10b85d6SJean-Jacques Hiblot 12882c3fbf4cSMacpaul Lin return 0; 1289d0c221feSJean-Jacques Hiblot } 1290d0c221feSJean-Jacques Hiblot 1291d0c221feSJean-Jacques Hiblot static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode) 1292d0c221feSJean-Jacques Hiblot { 1293d0c221feSJean-Jacques Hiblot int err; 1294d0c221feSJean-Jacques Hiblot 1295d0c221feSJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16); 1296c10b85d6SJean-Jacques Hiblot int speed; 12972c3fbf4cSMacpaul Lin 1298c10b85d6SJean-Jacques Hiblot switch (mode) { 1299c10b85d6SJean-Jacques Hiblot case SD_LEGACY: 1300c10b85d6SJean-Jacques Hiblot speed = UHS_SDR12_BUS_SPEED; 1301c10b85d6SJean-Jacques Hiblot break; 1302c10b85d6SJean-Jacques Hiblot case SD_HS: 1303baef2070SJean-Jacques Hiblot speed = HIGH_SPEED_BUS_SPEED; 1304baef2070SJean-Jacques Hiblot break; 1305baef2070SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1306baef2070SJean-Jacques Hiblot case UHS_SDR12: 1307baef2070SJean-Jacques Hiblot speed = UHS_SDR12_BUS_SPEED; 1308baef2070SJean-Jacques Hiblot break; 1309c10b85d6SJean-Jacques Hiblot case UHS_SDR25: 1310c10b85d6SJean-Jacques Hiblot speed = UHS_SDR25_BUS_SPEED; 1311c10b85d6SJean-Jacques Hiblot break; 1312c10b85d6SJean-Jacques Hiblot case UHS_SDR50: 1313c10b85d6SJean-Jacques Hiblot speed = UHS_SDR50_BUS_SPEED; 1314c10b85d6SJean-Jacques Hiblot break; 1315c10b85d6SJean-Jacques Hiblot case UHS_DDR50: 1316c10b85d6SJean-Jacques Hiblot speed = UHS_DDR50_BUS_SPEED; 1317c10b85d6SJean-Jacques Hiblot break; 1318c10b85d6SJean-Jacques Hiblot case UHS_SDR104: 1319c10b85d6SJean-Jacques Hiblot speed = UHS_SDR104_BUS_SPEED; 1320c10b85d6SJean-Jacques Hiblot break; 1321baef2070SJean-Jacques Hiblot #endif 1322c10b85d6SJean-Jacques Hiblot default: 1323c10b85d6SJean-Jacques Hiblot return -EINVAL; 1324c10b85d6SJean-Jacques Hiblot } 1325c10b85d6SJean-Jacques Hiblot 1326c10b85d6SJean-Jacques Hiblot err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, speed, (u8 *)switch_status); 1327272cc70bSAndy Fleming if (err) 1328272cc70bSAndy Fleming return err; 1329272cc70bSAndy Fleming 1330a0276f3eSJean-Jacques Hiblot if (((__be32_to_cpu(switch_status[4]) >> 24) & 0xF) != speed) 1331d0c221feSJean-Jacques Hiblot return -ENOTSUPP; 1332d0c221feSJean-Jacques Hiblot 1333d0c221feSJean-Jacques Hiblot return 0; 1334d0c221feSJean-Jacques Hiblot } 1335d0c221feSJean-Jacques Hiblot 1336ec360e64SMarek Vasut static int sd_select_bus_width(struct mmc *mmc, int w) 1337d0c221feSJean-Jacques Hiblot { 1338d0c221feSJean-Jacques Hiblot int err; 1339d0c221feSJean-Jacques Hiblot struct mmc_cmd cmd; 1340d0c221feSJean-Jacques Hiblot 1341d0c221feSJean-Jacques Hiblot if ((w != 4) && (w != 1)) 1342d0c221feSJean-Jacques Hiblot return -EINVAL; 1343d0c221feSJean-Jacques Hiblot 1344d0c221feSJean-Jacques Hiblot cmd.cmdidx = MMC_CMD_APP_CMD; 1345d0c221feSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 1346d0c221feSJean-Jacques Hiblot cmd.cmdarg = mmc->rca << 16; 1347d0c221feSJean-Jacques Hiblot 1348d0c221feSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 1349d0c221feSJean-Jacques Hiblot if (err) 1350d0c221feSJean-Jacques Hiblot return err; 1351d0c221feSJean-Jacques Hiblot 1352d0c221feSJean-Jacques Hiblot cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; 1353d0c221feSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 1354d0c221feSJean-Jacques Hiblot if (w == 4) 1355d0c221feSJean-Jacques Hiblot cmd.cmdarg = 2; 1356d0c221feSJean-Jacques Hiblot else if (w == 1) 1357d0c221feSJean-Jacques Hiblot cmd.cmdarg = 0; 1358d0c221feSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 1359d0c221feSJean-Jacques Hiblot if (err) 1360d0c221feSJean-Jacques Hiblot return err; 1361272cc70bSAndy Fleming 1362272cc70bSAndy Fleming return 0; 1363272cc70bSAndy Fleming } 1364272cc70bSAndy Fleming 13655b2e72f3SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE) 13663697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc) 13673697e599SPeng Fan { 13685b2e72f3SJean-Jacques Hiblot static const unsigned int sd_au_size[] = { 13695b2e72f3SJean-Jacques Hiblot 0, SZ_16K / 512, SZ_32K / 512, 13705b2e72f3SJean-Jacques Hiblot SZ_64K / 512, SZ_128K / 512, SZ_256K / 512, 13715b2e72f3SJean-Jacques Hiblot SZ_512K / 512, SZ_1M / 512, SZ_2M / 512, 13725b2e72f3SJean-Jacques Hiblot SZ_4M / 512, SZ_8M / 512, (SZ_8M + SZ_4M) / 512, 13735b2e72f3SJean-Jacques Hiblot SZ_16M / 512, (SZ_16M + SZ_8M) / 512, SZ_32M / 512, 13745b2e72f3SJean-Jacques Hiblot SZ_64M / 512, 13755b2e72f3SJean-Jacques Hiblot }; 13763697e599SPeng Fan int err, i; 13773697e599SPeng Fan struct mmc_cmd cmd; 13783697e599SPeng Fan ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16); 13793697e599SPeng Fan struct mmc_data data; 13803697e599SPeng Fan int timeout = 3; 13813697e599SPeng Fan unsigned int au, eo, et, es; 13823697e599SPeng Fan 13833697e599SPeng Fan cmd.cmdidx = MMC_CMD_APP_CMD; 13843697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 13853697e599SPeng Fan cmd.cmdarg = mmc->rca << 16; 13863697e599SPeng Fan 13873697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, NULL); 13883697e599SPeng Fan if (err) 13893697e599SPeng Fan return err; 13903697e599SPeng Fan 13913697e599SPeng Fan cmd.cmdidx = SD_CMD_APP_SD_STATUS; 13923697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 13933697e599SPeng Fan cmd.cmdarg = 0; 13943697e599SPeng Fan 13953697e599SPeng Fan retry_ssr: 13963697e599SPeng Fan data.dest = (char *)ssr; 13973697e599SPeng Fan data.blocksize = 64; 13983697e599SPeng Fan data.blocks = 1; 13993697e599SPeng Fan data.flags = MMC_DATA_READ; 14003697e599SPeng Fan 14013697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, &data); 14023697e599SPeng Fan if (err) { 14033697e599SPeng Fan if (timeout--) 14043697e599SPeng Fan goto retry_ssr; 14053697e599SPeng Fan 14063697e599SPeng Fan return err; 14073697e599SPeng Fan } 14083697e599SPeng Fan 14093697e599SPeng Fan for (i = 0; i < 16; i++) 14103697e599SPeng Fan ssr[i] = be32_to_cpu(ssr[i]); 14113697e599SPeng Fan 14123697e599SPeng Fan au = (ssr[2] >> 12) & 0xF; 14133697e599SPeng Fan if ((au <= 9) || (mmc->version == SD_VERSION_3)) { 14143697e599SPeng Fan mmc->ssr.au = sd_au_size[au]; 14153697e599SPeng Fan es = (ssr[3] >> 24) & 0xFF; 14163697e599SPeng Fan es |= (ssr[2] & 0xFF) << 8; 14173697e599SPeng Fan et = (ssr[3] >> 18) & 0x3F; 14183697e599SPeng Fan if (es && et) { 14193697e599SPeng Fan eo = (ssr[3] >> 16) & 0x3; 14203697e599SPeng Fan mmc->ssr.erase_timeout = (et * 1000) / es; 14213697e599SPeng Fan mmc->ssr.erase_offset = eo * 1000; 14223697e599SPeng Fan } 14233697e599SPeng Fan } else { 1424d4d64889SMasahiro Yamada pr_debug("Invalid Allocation Unit Size.\n"); 14253697e599SPeng Fan } 14263697e599SPeng Fan 14273697e599SPeng Fan return 0; 14283697e599SPeng Fan } 14295b2e72f3SJean-Jacques Hiblot #endif 1430272cc70bSAndy Fleming /* frequency bases */ 1431272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */ 14325f837c2cSMike Frysinger static const int fbase[] = { 1433272cc70bSAndy Fleming 10000, 1434272cc70bSAndy Fleming 100000, 1435272cc70bSAndy Fleming 1000000, 1436272cc70bSAndy Fleming 10000000, 1437272cc70bSAndy Fleming }; 1438272cc70bSAndy Fleming 1439272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice 1440272cc70bSAndy Fleming * to platforms without floating point. 1441272cc70bSAndy Fleming */ 144261fe076fSSimon Glass static const u8 multipliers[] = { 1443272cc70bSAndy Fleming 0, /* reserved */ 1444272cc70bSAndy Fleming 10, 1445272cc70bSAndy Fleming 12, 1446272cc70bSAndy Fleming 13, 1447272cc70bSAndy Fleming 15, 1448272cc70bSAndy Fleming 20, 1449272cc70bSAndy Fleming 25, 1450272cc70bSAndy Fleming 30, 1451272cc70bSAndy Fleming 35, 1452272cc70bSAndy Fleming 40, 1453272cc70bSAndy Fleming 45, 1454272cc70bSAndy Fleming 50, 1455272cc70bSAndy Fleming 55, 1456272cc70bSAndy Fleming 60, 1457272cc70bSAndy Fleming 70, 1458272cc70bSAndy Fleming 80, 1459272cc70bSAndy Fleming }; 1460272cc70bSAndy Fleming 1461d0c221feSJean-Jacques Hiblot static inline int bus_width(uint cap) 1462d0c221feSJean-Jacques Hiblot { 1463d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_8BIT) 1464d0c221feSJean-Jacques Hiblot return 8; 1465d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_4BIT) 1466d0c221feSJean-Jacques Hiblot return 4; 1467d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_1BIT) 1468d0c221feSJean-Jacques Hiblot return 1; 1469d8e3d420SJean-Jacques Hiblot pr_warn("invalid bus witdh capability 0x%x\n", cap); 1470d0c221feSJean-Jacques Hiblot return 0; 1471d0c221feSJean-Jacques Hiblot } 1472d0c221feSJean-Jacques Hiblot 1473e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 1474f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 1475ec841209SKishon Vijay Abraham I static int mmc_execute_tuning(struct mmc *mmc, uint opcode) 1476ec841209SKishon Vijay Abraham I { 1477ec841209SKishon Vijay Abraham I return -ENOTSUPP; 1478ec841209SKishon Vijay Abraham I } 1479f99c2efeSJean-Jacques Hiblot #endif 1480ec841209SKishon Vijay Abraham I 1481318a7a57SJean-Jacques Hiblot static void mmc_send_init_stream(struct mmc *mmc) 1482318a7a57SJean-Jacques Hiblot { 1483318a7a57SJean-Jacques Hiblot } 1484318a7a57SJean-Jacques Hiblot 14852a4d212fSKishon Vijay Abraham I static int mmc_set_ios(struct mmc *mmc) 1486272cc70bSAndy Fleming { 14872a4d212fSKishon Vijay Abraham I int ret = 0; 14882a4d212fSKishon Vijay Abraham I 148993bfd616SPantelis Antoniou if (mmc->cfg->ops->set_ios) 14902a4d212fSKishon Vijay Abraham I ret = mmc->cfg->ops->set_ios(mmc); 14912a4d212fSKishon Vijay Abraham I 14922a4d212fSKishon Vijay Abraham I return ret; 1493272cc70bSAndy Fleming } 14948ca51e51SSimon Glass #endif 1495272cc70bSAndy Fleming 149635f67820SKishon Vijay Abraham I int mmc_set_clock(struct mmc *mmc, uint clock, bool disable) 1497272cc70bSAndy Fleming { 1498c0fafe64SJaehoon Chung if (!disable) { 149993bfd616SPantelis Antoniou if (clock > mmc->cfg->f_max) 150093bfd616SPantelis Antoniou clock = mmc->cfg->f_max; 1501272cc70bSAndy Fleming 150293bfd616SPantelis Antoniou if (clock < mmc->cfg->f_min) 150393bfd616SPantelis Antoniou clock = mmc->cfg->f_min; 15049546eb92SJaehoon Chung } 1505272cc70bSAndy Fleming 1506272cc70bSAndy Fleming mmc->clock = clock; 150735f67820SKishon Vijay Abraham I mmc->clk_disable = disable; 1508272cc70bSAndy Fleming 1509d2faadb5SJaehoon Chung debug("clock is %s (%dHz)\n", disable ? "disabled" : "enabled", clock); 1510d2faadb5SJaehoon Chung 15112a4d212fSKishon Vijay Abraham I return mmc_set_ios(mmc); 1512272cc70bSAndy Fleming } 1513272cc70bSAndy Fleming 15142a4d212fSKishon Vijay Abraham I static int mmc_set_bus_width(struct mmc *mmc, uint width) 1515272cc70bSAndy Fleming { 1516272cc70bSAndy Fleming mmc->bus_width = width; 1517272cc70bSAndy Fleming 15182a4d212fSKishon Vijay Abraham I return mmc_set_ios(mmc); 1519272cc70bSAndy Fleming } 1520272cc70bSAndy Fleming 15214c9d2aaaSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG) 15224c9d2aaaSJean-Jacques Hiblot /* 15234c9d2aaaSJean-Jacques Hiblot * helper function to display the capabilities in a human 15244c9d2aaaSJean-Jacques Hiblot * friendly manner. The capabilities include bus width and 15254c9d2aaaSJean-Jacques Hiblot * supported modes. 15264c9d2aaaSJean-Jacques Hiblot */ 15274c9d2aaaSJean-Jacques Hiblot void mmc_dump_capabilities(const char *text, uint caps) 15284c9d2aaaSJean-Jacques Hiblot { 15294c9d2aaaSJean-Jacques Hiblot enum bus_mode mode; 15304c9d2aaaSJean-Jacques Hiblot 1531d4d64889SMasahiro Yamada pr_debug("%s: widths [", text); 15324c9d2aaaSJean-Jacques Hiblot if (caps & MMC_MODE_8BIT) 1533d4d64889SMasahiro Yamada pr_debug("8, "); 15344c9d2aaaSJean-Jacques Hiblot if (caps & MMC_MODE_4BIT) 1535d4d64889SMasahiro Yamada pr_debug("4, "); 1536d0c221feSJean-Jacques Hiblot if (caps & MMC_MODE_1BIT) 1537d4d64889SMasahiro Yamada pr_debug("1, "); 1538d4d64889SMasahiro Yamada pr_debug("\b\b] modes ["); 15394c9d2aaaSJean-Jacques Hiblot for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++) 15404c9d2aaaSJean-Jacques Hiblot if (MMC_CAP(mode) & caps) 1541d4d64889SMasahiro Yamada pr_debug("%s, ", mmc_mode_name(mode)); 1542d4d64889SMasahiro Yamada pr_debug("\b\b]\n"); 15434c9d2aaaSJean-Jacques Hiblot } 15444c9d2aaaSJean-Jacques Hiblot #endif 15454c9d2aaaSJean-Jacques Hiblot 1546d0c221feSJean-Jacques Hiblot struct mode_width_tuning { 1547d0c221feSJean-Jacques Hiblot enum bus_mode mode; 1548d0c221feSJean-Jacques Hiblot uint widths; 1549f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 1550634d4849SKishon Vijay Abraham I uint tuning; 1551f99c2efeSJean-Jacques Hiblot #endif 1552d0c221feSJean-Jacques Hiblot }; 1553d0c221feSJean-Jacques Hiblot 1554f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE) 1555bc1e3272SJean-Jacques Hiblot int mmc_voltage_to_mv(enum mmc_voltage voltage) 1556bc1e3272SJean-Jacques Hiblot { 1557bc1e3272SJean-Jacques Hiblot switch (voltage) { 1558bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_000: return 0; 1559bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_330: return 3300; 1560bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_180: return 1800; 1561bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_120: return 1200; 1562bc1e3272SJean-Jacques Hiblot } 1563bc1e3272SJean-Jacques Hiblot return -EINVAL; 1564bc1e3272SJean-Jacques Hiblot } 1565bc1e3272SJean-Jacques Hiblot 1566aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage) 1567aff5d3c8SKishon Vijay Abraham I { 1568bc1e3272SJean-Jacques Hiblot int err; 1569bc1e3272SJean-Jacques Hiblot 1570bc1e3272SJean-Jacques Hiblot if (mmc->signal_voltage == signal_voltage) 1571bc1e3272SJean-Jacques Hiblot return 0; 1572bc1e3272SJean-Jacques Hiblot 1573aff5d3c8SKishon Vijay Abraham I mmc->signal_voltage = signal_voltage; 1574bc1e3272SJean-Jacques Hiblot err = mmc_set_ios(mmc); 1575bc1e3272SJean-Jacques Hiblot if (err) 1576d4d64889SMasahiro Yamada pr_debug("unable to set voltage (err %d)\n", err); 1577bc1e3272SJean-Jacques Hiblot 1578bc1e3272SJean-Jacques Hiblot return err; 1579aff5d3c8SKishon Vijay Abraham I } 1580f99c2efeSJean-Jacques Hiblot #else 1581f99c2efeSJean-Jacques Hiblot static inline int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage) 1582f99c2efeSJean-Jacques Hiblot { 1583f99c2efeSJean-Jacques Hiblot return 0; 1584f99c2efeSJean-Jacques Hiblot } 1585f99c2efeSJean-Jacques Hiblot #endif 1586aff5d3c8SKishon Vijay Abraham I 1587d0c221feSJean-Jacques Hiblot static const struct mode_width_tuning sd_modes_by_pref[] = { 1588f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1589f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 1590d0c221feSJean-Jacques Hiblot { 1591c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR104, 1592c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1593c10b85d6SJean-Jacques Hiblot .tuning = MMC_CMD_SEND_TUNING_BLOCK 1594c10b85d6SJean-Jacques Hiblot }, 1595f99c2efeSJean-Jacques Hiblot #endif 1596c10b85d6SJean-Jacques Hiblot { 1597c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR50, 1598c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1599c10b85d6SJean-Jacques Hiblot }, 1600c10b85d6SJean-Jacques Hiblot { 1601c10b85d6SJean-Jacques Hiblot .mode = UHS_DDR50, 1602c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1603c10b85d6SJean-Jacques Hiblot }, 1604c10b85d6SJean-Jacques Hiblot { 1605c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR25, 1606c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1607c10b85d6SJean-Jacques Hiblot }, 1608f99c2efeSJean-Jacques Hiblot #endif 1609c10b85d6SJean-Jacques Hiblot { 1610d0c221feSJean-Jacques Hiblot .mode = SD_HS, 1611d0c221feSJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1612d0c221feSJean-Jacques Hiblot }, 1613f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1614d0c221feSJean-Jacques Hiblot { 1615c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR12, 1616c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1617c10b85d6SJean-Jacques Hiblot }, 1618f99c2efeSJean-Jacques Hiblot #endif 1619c10b85d6SJean-Jacques Hiblot { 1620d0c221feSJean-Jacques Hiblot .mode = SD_LEGACY, 1621d0c221feSJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1622d0c221feSJean-Jacques Hiblot } 1623d0c221feSJean-Jacques Hiblot }; 1624d0c221feSJean-Jacques Hiblot 1625d0c221feSJean-Jacques Hiblot #define for_each_sd_mode_by_pref(caps, mwt) \ 1626d0c221feSJean-Jacques Hiblot for (mwt = sd_modes_by_pref;\ 1627d0c221feSJean-Jacques Hiblot mwt < sd_modes_by_pref + ARRAY_SIZE(sd_modes_by_pref);\ 1628d0c221feSJean-Jacques Hiblot mwt++) \ 1629d0c221feSJean-Jacques Hiblot if (caps & MMC_CAP(mwt->mode)) 1630d0c221feSJean-Jacques Hiblot 163101298da3SJean-Jacques Hiblot static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps) 16328ac8a263SJean-Jacques Hiblot { 16338ac8a263SJean-Jacques Hiblot int err; 1634d0c221feSJean-Jacques Hiblot uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT}; 1635d0c221feSJean-Jacques Hiblot const struct mode_width_tuning *mwt; 1636f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1637c10b85d6SJean-Jacques Hiblot bool uhs_en = (mmc->ocr & OCR_S18R) ? true : false; 1638f99c2efeSJean-Jacques Hiblot #else 1639f99c2efeSJean-Jacques Hiblot bool uhs_en = false; 1640f99c2efeSJean-Jacques Hiblot #endif 1641c10b85d6SJean-Jacques Hiblot uint caps; 1642c10b85d6SJean-Jacques Hiblot 164352d241dfSJean-Jacques Hiblot #ifdef DEBUG 164452d241dfSJean-Jacques Hiblot mmc_dump_capabilities("sd card", card_caps); 16451da8eb59SJean-Jacques Hiblot mmc_dump_capabilities("host", mmc->host_caps); 164652d241dfSJean-Jacques Hiblot #endif 16478ac8a263SJean-Jacques Hiblot 16488ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */ 16491da8eb59SJean-Jacques Hiblot caps = card_caps & mmc->host_caps; 16508ac8a263SJean-Jacques Hiblot 1651c10b85d6SJean-Jacques Hiblot if (!uhs_en) 1652c10b85d6SJean-Jacques Hiblot caps &= ~UHS_CAPS; 1653c10b85d6SJean-Jacques Hiblot 1654c10b85d6SJean-Jacques Hiblot for_each_sd_mode_by_pref(caps, mwt) { 1655d0c221feSJean-Jacques Hiblot uint *w; 16568ac8a263SJean-Jacques Hiblot 1657d0c221feSJean-Jacques Hiblot for (w = widths; w < widths + ARRAY_SIZE(widths); w++) { 1658c10b85d6SJean-Jacques Hiblot if (*w & caps & mwt->widths) { 1659d4d64889SMasahiro Yamada pr_debug("trying mode %s width %d (at %d MHz)\n", 1660d0c221feSJean-Jacques Hiblot mmc_mode_name(mwt->mode), 1661d0c221feSJean-Jacques Hiblot bus_width(*w), 1662d0c221feSJean-Jacques Hiblot mmc_mode2freq(mmc, mwt->mode) / 1000000); 1663d0c221feSJean-Jacques Hiblot 1664d0c221feSJean-Jacques Hiblot /* configure the bus width (card + host) */ 1665d0c221feSJean-Jacques Hiblot err = sd_select_bus_width(mmc, bus_width(*w)); 16668ac8a263SJean-Jacques Hiblot if (err) 1667d0c221feSJean-Jacques Hiblot goto error; 1668d0c221feSJean-Jacques Hiblot mmc_set_bus_width(mmc, bus_width(*w)); 16698ac8a263SJean-Jacques Hiblot 1670d0c221feSJean-Jacques Hiblot /* configure the bus mode (card) */ 1671d0c221feSJean-Jacques Hiblot err = sd_set_card_speed(mmc, mwt->mode); 16728ac8a263SJean-Jacques Hiblot if (err) 1673d0c221feSJean-Jacques Hiblot goto error; 16748ac8a263SJean-Jacques Hiblot 1675d0c221feSJean-Jacques Hiblot /* configure the bus mode (host) */ 1676d0c221feSJean-Jacques Hiblot mmc_select_mode(mmc, mwt->mode); 167765117182SJaehoon Chung mmc_set_clock(mmc, mmc->tran_speed, 167865117182SJaehoon Chung MMC_CLK_ENABLE); 16798ac8a263SJean-Jacques Hiblot 1680f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 1681c10b85d6SJean-Jacques Hiblot /* execute tuning if needed */ 1682c10b85d6SJean-Jacques Hiblot if (mwt->tuning && !mmc_host_is_spi(mmc)) { 1683c10b85d6SJean-Jacques Hiblot err = mmc_execute_tuning(mmc, 1684c10b85d6SJean-Jacques Hiblot mwt->tuning); 1685c10b85d6SJean-Jacques Hiblot if (err) { 1686d4d64889SMasahiro Yamada pr_debug("tuning failed\n"); 1687c10b85d6SJean-Jacques Hiblot goto error; 1688c10b85d6SJean-Jacques Hiblot } 1689c10b85d6SJean-Jacques Hiblot } 1690f99c2efeSJean-Jacques Hiblot #endif 1691c10b85d6SJean-Jacques Hiblot 16925b2e72f3SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE) 16938ac8a263SJean-Jacques Hiblot err = sd_read_ssr(mmc); 16940a4c2b09SPeng Fan if (err) 16955b2e72f3SJean-Jacques Hiblot pr_warn("unable to read ssr\n"); 16965b2e72f3SJean-Jacques Hiblot #endif 16975b2e72f3SJean-Jacques Hiblot if (!err) 16988ac8a263SJean-Jacques Hiblot return 0; 1699d0c221feSJean-Jacques Hiblot 1700d0c221feSJean-Jacques Hiblot error: 1701d0c221feSJean-Jacques Hiblot /* revert to a safer bus speed */ 1702d0c221feSJean-Jacques Hiblot mmc_select_mode(mmc, SD_LEGACY); 170365117182SJaehoon Chung mmc_set_clock(mmc, mmc->tran_speed, 170465117182SJaehoon Chung MMC_CLK_ENABLE); 1705d0c221feSJean-Jacques Hiblot } 1706d0c221feSJean-Jacques Hiblot } 1707d0c221feSJean-Jacques Hiblot } 1708d0c221feSJean-Jacques Hiblot 1709d4d64889SMasahiro Yamada pr_err("unable to select a mode\n"); 1710d0c221feSJean-Jacques Hiblot return -ENOTSUPP; 17118ac8a263SJean-Jacques Hiblot } 17128ac8a263SJean-Jacques Hiblot 17137382e691SJean-Jacques Hiblot /* 17147382e691SJean-Jacques Hiblot * read the compare the part of ext csd that is constant. 17157382e691SJean-Jacques Hiblot * This can be used to check that the transfer is working 17167382e691SJean-Jacques Hiblot * as expected. 17177382e691SJean-Jacques Hiblot */ 17187382e691SJean-Jacques Hiblot static int mmc_read_and_compare_ext_csd(struct mmc *mmc) 17197382e691SJean-Jacques Hiblot { 17207382e691SJean-Jacques Hiblot int err; 17217382e691SJean-Jacques Hiblot const u8 *ext_csd = mmc->ext_csd; 17227382e691SJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 17237382e691SJean-Jacques Hiblot 17241de06b9fSJean-Jacques Hiblot if (mmc->version < MMC_VERSION_4) 17251de06b9fSJean-Jacques Hiblot return 0; 17261de06b9fSJean-Jacques Hiblot 17277382e691SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, test_csd); 17287382e691SJean-Jacques Hiblot if (err) 17297382e691SJean-Jacques Hiblot return err; 17307382e691SJean-Jacques Hiblot 17317382e691SJean-Jacques Hiblot /* Only compare read only fields */ 17327382e691SJean-Jacques Hiblot if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] 17337382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_PARTITIONING_SUPPORT] && 17347382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_WP_GRP_SIZE] 17357382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_WP_GRP_SIZE] && 17367382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_REV] 17377382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_REV] && 17387382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 17397382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] && 17407382e691SJean-Jacques Hiblot memcmp(&ext_csd[EXT_CSD_SEC_CNT], 17417382e691SJean-Jacques Hiblot &test_csd[EXT_CSD_SEC_CNT], 4) == 0) 17427382e691SJean-Jacques Hiblot return 0; 17437382e691SJean-Jacques Hiblot 17447382e691SJean-Jacques Hiblot return -EBADMSG; 17457382e691SJean-Jacques Hiblot } 17467382e691SJean-Jacques Hiblot 1747f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE) 1748bc1e3272SJean-Jacques Hiblot static int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode, 1749bc1e3272SJean-Jacques Hiblot uint32_t allowed_mask) 1750bc1e3272SJean-Jacques Hiblot { 1751bc1e3272SJean-Jacques Hiblot u32 card_mask = 0; 1752bc1e3272SJean-Jacques Hiblot 1753bc1e3272SJean-Jacques Hiblot switch (mode) { 1754bc1e3272SJean-Jacques Hiblot case MMC_HS_200: 1755bc1e3272SJean-Jacques Hiblot if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_8V) 1756bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_180; 1757bc1e3272SJean-Jacques Hiblot if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_2V) 1758bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_120; 1759bc1e3272SJean-Jacques Hiblot break; 1760bc1e3272SJean-Jacques Hiblot case MMC_DDR_52: 1761bc1e3272SJean-Jacques Hiblot if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V) 1762bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_330 | 1763bc1e3272SJean-Jacques Hiblot MMC_SIGNAL_VOLTAGE_180; 1764bc1e3272SJean-Jacques Hiblot if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_2V) 1765bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_120; 1766bc1e3272SJean-Jacques Hiblot break; 1767bc1e3272SJean-Jacques Hiblot default: 1768bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_330; 1769bc1e3272SJean-Jacques Hiblot break; 1770bc1e3272SJean-Jacques Hiblot } 1771bc1e3272SJean-Jacques Hiblot 1772bc1e3272SJean-Jacques Hiblot while (card_mask & allowed_mask) { 1773bc1e3272SJean-Jacques Hiblot enum mmc_voltage best_match; 1774bc1e3272SJean-Jacques Hiblot 1775bc1e3272SJean-Jacques Hiblot best_match = 1 << (ffs(card_mask & allowed_mask) - 1); 1776bc1e3272SJean-Jacques Hiblot if (!mmc_set_signal_voltage(mmc, best_match)) 1777bc1e3272SJean-Jacques Hiblot return 0; 1778bc1e3272SJean-Jacques Hiblot 1779bc1e3272SJean-Jacques Hiblot allowed_mask &= ~best_match; 1780bc1e3272SJean-Jacques Hiblot } 1781bc1e3272SJean-Jacques Hiblot 1782bc1e3272SJean-Jacques Hiblot return -ENOTSUPP; 1783bc1e3272SJean-Jacques Hiblot } 1784f99c2efeSJean-Jacques Hiblot #else 1785f99c2efeSJean-Jacques Hiblot static inline int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode, 1786f99c2efeSJean-Jacques Hiblot uint32_t allowed_mask) 1787f99c2efeSJean-Jacques Hiblot { 1788f99c2efeSJean-Jacques Hiblot return 0; 1789f99c2efeSJean-Jacques Hiblot } 1790f99c2efeSJean-Jacques Hiblot #endif 1791bc1e3272SJean-Jacques Hiblot 17923862b854SJean-Jacques Hiblot static const struct mode_width_tuning mmc_modes_by_pref[] = { 1793f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) 17948ac8a263SJean-Jacques Hiblot { 17953862b854SJean-Jacques Hiblot .mode = MMC_HS_200, 17963862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT, 1797634d4849SKishon Vijay Abraham I .tuning = MMC_CMD_SEND_TUNING_BLOCK_HS200 17983862b854SJean-Jacques Hiblot }, 1799f99c2efeSJean-Jacques Hiblot #endif 18003862b854SJean-Jacques Hiblot { 18013862b854SJean-Jacques Hiblot .mode = MMC_DDR_52, 18023862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT, 18033862b854SJean-Jacques Hiblot }, 18043862b854SJean-Jacques Hiblot { 18053862b854SJean-Jacques Hiblot .mode = MMC_HS_52, 18063862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 18073862b854SJean-Jacques Hiblot }, 18083862b854SJean-Jacques Hiblot { 18093862b854SJean-Jacques Hiblot .mode = MMC_HS, 18103862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 18113862b854SJean-Jacques Hiblot }, 18123862b854SJean-Jacques Hiblot { 18133862b854SJean-Jacques Hiblot .mode = MMC_LEGACY, 18143862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 18153862b854SJean-Jacques Hiblot } 18168ac8a263SJean-Jacques Hiblot }; 18178ac8a263SJean-Jacques Hiblot 18183862b854SJean-Jacques Hiblot #define for_each_mmc_mode_by_pref(caps, mwt) \ 18193862b854SJean-Jacques Hiblot for (mwt = mmc_modes_by_pref;\ 18203862b854SJean-Jacques Hiblot mwt < mmc_modes_by_pref + ARRAY_SIZE(mmc_modes_by_pref);\ 18213862b854SJean-Jacques Hiblot mwt++) \ 18223862b854SJean-Jacques Hiblot if (caps & MMC_CAP(mwt->mode)) 18233862b854SJean-Jacques Hiblot 18243862b854SJean-Jacques Hiblot static const struct ext_csd_bus_width { 18253862b854SJean-Jacques Hiblot uint cap; 18263862b854SJean-Jacques Hiblot bool is_ddr; 18273862b854SJean-Jacques Hiblot uint ext_csd_bits; 18283862b854SJean-Jacques Hiblot } ext_csd_bus_width[] = { 18293862b854SJean-Jacques Hiblot {MMC_MODE_8BIT, true, EXT_CSD_DDR_BUS_WIDTH_8}, 18303862b854SJean-Jacques Hiblot {MMC_MODE_4BIT, true, EXT_CSD_DDR_BUS_WIDTH_4}, 18313862b854SJean-Jacques Hiblot {MMC_MODE_8BIT, false, EXT_CSD_BUS_WIDTH_8}, 18323862b854SJean-Jacques Hiblot {MMC_MODE_4BIT, false, EXT_CSD_BUS_WIDTH_4}, 18333862b854SJean-Jacques Hiblot {MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1}, 18343862b854SJean-Jacques Hiblot }; 18353862b854SJean-Jacques Hiblot 18363862b854SJean-Jacques Hiblot #define for_each_supported_width(caps, ddr, ecbv) \ 18373862b854SJean-Jacques Hiblot for (ecbv = ext_csd_bus_width;\ 18383862b854SJean-Jacques Hiblot ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\ 18393862b854SJean-Jacques Hiblot ecbv++) \ 18403862b854SJean-Jacques Hiblot if ((ddr == ecbv->is_ddr) && (caps & ecbv->cap)) 18413862b854SJean-Jacques Hiblot 184201298da3SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps) 18433862b854SJean-Jacques Hiblot { 18443862b854SJean-Jacques Hiblot int err; 18453862b854SJean-Jacques Hiblot const struct mode_width_tuning *mwt; 18463862b854SJean-Jacques Hiblot const struct ext_csd_bus_width *ecbw; 18473862b854SJean-Jacques Hiblot 184852d241dfSJean-Jacques Hiblot #ifdef DEBUG 184952d241dfSJean-Jacques Hiblot mmc_dump_capabilities("mmc", card_caps); 18501da8eb59SJean-Jacques Hiblot mmc_dump_capabilities("host", mmc->host_caps); 185152d241dfSJean-Jacques Hiblot #endif 185252d241dfSJean-Jacques Hiblot 18538ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */ 18541da8eb59SJean-Jacques Hiblot card_caps &= mmc->host_caps; 18558ac8a263SJean-Jacques Hiblot 18568ac8a263SJean-Jacques Hiblot /* Only version 4 of MMC supports wider bus widths */ 18578ac8a263SJean-Jacques Hiblot if (mmc->version < MMC_VERSION_4) 18588ac8a263SJean-Jacques Hiblot return 0; 18598ac8a263SJean-Jacques Hiblot 1860dfda9d88SJean-Jacques Hiblot if (!mmc->ext_csd) { 1861d4d64889SMasahiro Yamada pr_debug("No ext_csd found!\n"); /* this should enver happen */ 1862dfda9d88SJean-Jacques Hiblot return -ENOTSUPP; 1863dfda9d88SJean-Jacques Hiblot } 1864dfda9d88SJean-Jacques Hiblot 186565117182SJaehoon Chung mmc_set_clock(mmc, mmc->legacy_speed, MMC_CLK_ENABLE); 186601298da3SJean-Jacques Hiblot 186701298da3SJean-Jacques Hiblot for_each_mmc_mode_by_pref(card_caps, mwt) { 186801298da3SJean-Jacques Hiblot for_each_supported_width(card_caps & mwt->widths, 18693862b854SJean-Jacques Hiblot mmc_is_mode_ddr(mwt->mode), ecbw) { 1870bc1e3272SJean-Jacques Hiblot enum mmc_voltage old_voltage; 1871d4d64889SMasahiro Yamada pr_debug("trying mode %s width %d (at %d MHz)\n", 18723862b854SJean-Jacques Hiblot mmc_mode_name(mwt->mode), 18733862b854SJean-Jacques Hiblot bus_width(ecbw->cap), 18743862b854SJean-Jacques Hiblot mmc_mode2freq(mmc, mwt->mode) / 1000000); 1875bc1e3272SJean-Jacques Hiblot old_voltage = mmc->signal_voltage; 1876bc1e3272SJean-Jacques Hiblot err = mmc_set_lowest_voltage(mmc, mwt->mode, 1877bc1e3272SJean-Jacques Hiblot MMC_ALL_SIGNAL_VOLTAGE); 1878bc1e3272SJean-Jacques Hiblot if (err) 1879bc1e3272SJean-Jacques Hiblot continue; 1880bc1e3272SJean-Jacques Hiblot 18813862b854SJean-Jacques Hiblot /* configure the bus width (card + host) */ 18823862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 18833862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, 18843862b854SJean-Jacques Hiblot ecbw->ext_csd_bits & ~EXT_CSD_DDR_FLAG); 18853862b854SJean-Jacques Hiblot if (err) 18863862b854SJean-Jacques Hiblot goto error; 18873862b854SJean-Jacques Hiblot mmc_set_bus_width(mmc, bus_width(ecbw->cap)); 18883862b854SJean-Jacques Hiblot 18893862b854SJean-Jacques Hiblot /* configure the bus speed (card) */ 18903862b854SJean-Jacques Hiblot err = mmc_set_card_speed(mmc, mwt->mode); 18913862b854SJean-Jacques Hiblot if (err) 18923862b854SJean-Jacques Hiblot goto error; 18933862b854SJean-Jacques Hiblot 18948ac8a263SJean-Jacques Hiblot /* 18953862b854SJean-Jacques Hiblot * configure the bus width AND the ddr mode (card) 18963862b854SJean-Jacques Hiblot * The host side will be taken care of in the next step 18978ac8a263SJean-Jacques Hiblot */ 18983862b854SJean-Jacques Hiblot if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) { 18993862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 19003862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, 19013862b854SJean-Jacques Hiblot ecbw->ext_csd_bits); 19023862b854SJean-Jacques Hiblot if (err) 19033862b854SJean-Jacques Hiblot goto error; 19048ac8a263SJean-Jacques Hiblot } 19058ac8a263SJean-Jacques Hiblot 19063862b854SJean-Jacques Hiblot /* configure the bus mode (host) */ 19073862b854SJean-Jacques Hiblot mmc_select_mode(mmc, mwt->mode); 190865117182SJaehoon Chung mmc_set_clock(mmc, mmc->tran_speed, MMC_CLK_ENABLE); 1909f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 19108ac8a263SJean-Jacques Hiblot 1911634d4849SKishon Vijay Abraham I /* execute tuning if needed */ 1912634d4849SKishon Vijay Abraham I if (mwt->tuning) { 1913634d4849SKishon Vijay Abraham I err = mmc_execute_tuning(mmc, mwt->tuning); 1914634d4849SKishon Vijay Abraham I if (err) { 1915d4d64889SMasahiro Yamada pr_debug("tuning failed\n"); 1916634d4849SKishon Vijay Abraham I goto error; 1917634d4849SKishon Vijay Abraham I } 1918634d4849SKishon Vijay Abraham I } 1919f99c2efeSJean-Jacques Hiblot #endif 1920634d4849SKishon Vijay Abraham I 19213862b854SJean-Jacques Hiblot /* do a transfer to check the configuration */ 19227382e691SJean-Jacques Hiblot err = mmc_read_and_compare_ext_csd(mmc); 19237382e691SJean-Jacques Hiblot if (!err) 19243862b854SJean-Jacques Hiblot return 0; 19253862b854SJean-Jacques Hiblot error: 1926bc1e3272SJean-Jacques Hiblot mmc_set_signal_voltage(mmc, old_voltage); 19273862b854SJean-Jacques Hiblot /* if an error occured, revert to a safer bus mode */ 19283862b854SJean-Jacques Hiblot mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 19293862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1); 19303862b854SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_LEGACY); 19313862b854SJean-Jacques Hiblot mmc_set_bus_width(mmc, 1); 19323862b854SJean-Jacques Hiblot } 19338ac8a263SJean-Jacques Hiblot } 19348ac8a263SJean-Jacques Hiblot 1935d8e3d420SJean-Jacques Hiblot pr_err("unable to select a mode\n"); 19368ac8a263SJean-Jacques Hiblot 19373862b854SJean-Jacques Hiblot return -ENOTSUPP; 19388ac8a263SJean-Jacques Hiblot } 19398ac8a263SJean-Jacques Hiblot 1940dfda9d88SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc) 1941c744b6f6SJean-Jacques Hiblot { 1942c744b6f6SJean-Jacques Hiblot int err, i; 1943c744b6f6SJean-Jacques Hiblot u64 capacity; 1944c744b6f6SJean-Jacques Hiblot bool has_parts = false; 1945c744b6f6SJean-Jacques Hiblot bool part_completed; 194658a6fb7bSJean-Jacques Hiblot static const u32 mmc_versions[] = { 194758a6fb7bSJean-Jacques Hiblot MMC_VERSION_4, 194858a6fb7bSJean-Jacques Hiblot MMC_VERSION_4_1, 194958a6fb7bSJean-Jacques Hiblot MMC_VERSION_4_2, 195058a6fb7bSJean-Jacques Hiblot MMC_VERSION_4_3, 1951ace1bed3SJean-Jacques Hiblot MMC_VERSION_4_4, 195258a6fb7bSJean-Jacques Hiblot MMC_VERSION_4_41, 195358a6fb7bSJean-Jacques Hiblot MMC_VERSION_4_5, 195458a6fb7bSJean-Jacques Hiblot MMC_VERSION_5_0, 195558a6fb7bSJean-Jacques Hiblot MMC_VERSION_5_1 195658a6fb7bSJean-Jacques Hiblot }; 195758a6fb7bSJean-Jacques Hiblot 1958f7d5dffcSJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 1959c744b6f6SJean-Jacques Hiblot 1960c744b6f6SJean-Jacques Hiblot if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4)) 1961c744b6f6SJean-Jacques Hiblot return 0; 1962c744b6f6SJean-Jacques Hiblot 1963c744b6f6SJean-Jacques Hiblot /* check ext_csd version and capacity */ 1964c744b6f6SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, ext_csd); 1965c744b6f6SJean-Jacques Hiblot if (err) 1966f7d5dffcSJean-Jacques Hiblot goto error; 1967f7d5dffcSJean-Jacques Hiblot 1968f7d5dffcSJean-Jacques Hiblot /* store the ext csd for future reference */ 1969f7d5dffcSJean-Jacques Hiblot if (!mmc->ext_csd) 1970f7d5dffcSJean-Jacques Hiblot mmc->ext_csd = malloc(MMC_MAX_BLOCK_LEN); 1971f7d5dffcSJean-Jacques Hiblot if (!mmc->ext_csd) 1972f7d5dffcSJean-Jacques Hiblot return -ENOMEM; 1973f7d5dffcSJean-Jacques Hiblot memcpy(mmc->ext_csd, ext_csd, MMC_MAX_BLOCK_LEN); 1974f7d5dffcSJean-Jacques Hiblot 197576584e33SAlexander Kochetkov if (ext_csd[EXT_CSD_REV] >= ARRAY_SIZE(mmc_versions)) 197658a6fb7bSJean-Jacques Hiblot return -EINVAL; 197758a6fb7bSJean-Jacques Hiblot 197858a6fb7bSJean-Jacques Hiblot mmc->version = mmc_versions[ext_csd[EXT_CSD_REV]]; 197958a6fb7bSJean-Jacques Hiblot 198058a6fb7bSJean-Jacques Hiblot if (mmc->version >= MMC_VERSION_4_2) { 1981c744b6f6SJean-Jacques Hiblot /* 1982c744b6f6SJean-Jacques Hiblot * According to the JEDEC Standard, the value of 1983c744b6f6SJean-Jacques Hiblot * ext_csd's capacity is valid if the value is more 1984c744b6f6SJean-Jacques Hiblot * than 2GB 1985c744b6f6SJean-Jacques Hiblot */ 1986c744b6f6SJean-Jacques Hiblot capacity = ext_csd[EXT_CSD_SEC_CNT] << 0 1987c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 1988c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 1989c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; 1990c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN; 1991c744b6f6SJean-Jacques Hiblot if ((capacity >> 20) > 2 * 1024) 1992c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity; 1993c744b6f6SJean-Jacques Hiblot } 1994c744b6f6SJean-Jacques Hiblot 1995c744b6f6SJean-Jacques Hiblot /* The partition data may be non-zero but it is only 1996c744b6f6SJean-Jacques Hiblot * effective if PARTITION_SETTING_COMPLETED is set in 1997c744b6f6SJean-Jacques Hiblot * EXT_CSD, so ignore any data if this bit is not set, 1998c744b6f6SJean-Jacques Hiblot * except for enabling the high-capacity group size 1999c744b6f6SJean-Jacques Hiblot * definition (see below). 2000c744b6f6SJean-Jacques Hiblot */ 2001c744b6f6SJean-Jacques Hiblot part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] & 2002c744b6f6SJean-Jacques Hiblot EXT_CSD_PARTITION_SETTING_COMPLETED); 2003c744b6f6SJean-Jacques Hiblot 2004c744b6f6SJean-Jacques Hiblot /* store the partition info of emmc */ 2005c744b6f6SJean-Jacques Hiblot mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT]; 2006c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || 2007c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_BOOT_MULT]) 2008c744b6f6SJean-Jacques Hiblot mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; 2009c744b6f6SJean-Jacques Hiblot if (part_completed && 2010c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT)) 2011c744b6f6SJean-Jacques Hiblot mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]; 2012c744b6f6SJean-Jacques Hiblot 2013c744b6f6SJean-Jacques Hiblot mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17; 2014c744b6f6SJean-Jacques Hiblot 2015c744b6f6SJean-Jacques Hiblot mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17; 2016c744b6f6SJean-Jacques Hiblot 2017c744b6f6SJean-Jacques Hiblot for (i = 0; i < 4; i++) { 2018c744b6f6SJean-Jacques Hiblot int idx = EXT_CSD_GP_SIZE_MULT + i * 3; 2019c744b6f6SJean-Jacques Hiblot uint mult = (ext_csd[idx + 2] << 16) + 2020c744b6f6SJean-Jacques Hiblot (ext_csd[idx + 1] << 8) + ext_csd[idx]; 2021c744b6f6SJean-Jacques Hiblot if (mult) 2022c744b6f6SJean-Jacques Hiblot has_parts = true; 2023c744b6f6SJean-Jacques Hiblot if (!part_completed) 2024c744b6f6SJean-Jacques Hiblot continue; 2025c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] = mult; 2026c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= 2027c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 2028c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 2029c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] <<= 19; 2030c744b6f6SJean-Jacques Hiblot } 2031c744b6f6SJean-Jacques Hiblot 2032173c06dfSJean-Jacques Hiblot #ifndef CONFIG_SPL_BUILD 2033c744b6f6SJean-Jacques Hiblot if (part_completed) { 2034c744b6f6SJean-Jacques Hiblot mmc->enh_user_size = 2035c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) + 2036c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) + 2037c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_SIZE_MULT]; 2038c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 2039c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 2040c744b6f6SJean-Jacques Hiblot mmc->enh_user_size <<= 19; 2041c744b6f6SJean-Jacques Hiblot mmc->enh_user_start = 2042c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) + 2043c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) + 2044c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) + 2045c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_START_ADDR]; 2046c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity) 2047c744b6f6SJean-Jacques Hiblot mmc->enh_user_start <<= 9; 2048c744b6f6SJean-Jacques Hiblot } 2049173c06dfSJean-Jacques Hiblot #endif 2050c744b6f6SJean-Jacques Hiblot 2051c744b6f6SJean-Jacques Hiblot /* 2052c744b6f6SJean-Jacques Hiblot * Host needs to enable ERASE_GRP_DEF bit if device is 2053c744b6f6SJean-Jacques Hiblot * partitioned. This bit will be lost every time after a reset 2054c744b6f6SJean-Jacques Hiblot * or power off. This will affect erase size. 2055c744b6f6SJean-Jacques Hiblot */ 2056c744b6f6SJean-Jacques Hiblot if (part_completed) 2057c744b6f6SJean-Jacques Hiblot has_parts = true; 2058c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) && 2059c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) 2060c744b6f6SJean-Jacques Hiblot has_parts = true; 2061c744b6f6SJean-Jacques Hiblot if (has_parts) { 2062c744b6f6SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 2063c744b6f6SJean-Jacques Hiblot EXT_CSD_ERASE_GROUP_DEF, 1); 2064c744b6f6SJean-Jacques Hiblot 2065c744b6f6SJean-Jacques Hiblot if (err) 2066f7d5dffcSJean-Jacques Hiblot goto error; 2067c744b6f6SJean-Jacques Hiblot 2068c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 2069c744b6f6SJean-Jacques Hiblot } 2070c744b6f6SJean-Jacques Hiblot 2071c744b6f6SJean-Jacques Hiblot if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) { 2072e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE) 2073c744b6f6SJean-Jacques Hiblot /* Read out group size from ext_csd */ 2074c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = 2075c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 2076e6fa5a54SJean-Jacques Hiblot #endif 2077c744b6f6SJean-Jacques Hiblot /* 2078c744b6f6SJean-Jacques Hiblot * if high capacity and partition setting completed 2079c744b6f6SJean-Jacques Hiblot * SEC_COUNT is valid even if it is smaller than 2 GiB 2080c744b6f6SJean-Jacques Hiblot * JEDEC Standard JESD84-B45, 6.2.4 2081c744b6f6SJean-Jacques Hiblot */ 2082c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity && part_completed) { 2083c744b6f6SJean-Jacques Hiblot capacity = (ext_csd[EXT_CSD_SEC_CNT]) | 2084c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) | 2085c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) | 2086c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 3] << 24); 2087c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN; 2088c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity; 2089c744b6f6SJean-Jacques Hiblot } 2090e6fa5a54SJean-Jacques Hiblot } 2091e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE) 2092e6fa5a54SJean-Jacques Hiblot else { 2093c744b6f6SJean-Jacques Hiblot /* Calculate the group size from the csd value. */ 2094c744b6f6SJean-Jacques Hiblot int erase_gsz, erase_gmul; 2095c744b6f6SJean-Jacques Hiblot 2096c744b6f6SJean-Jacques Hiblot erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; 2097c744b6f6SJean-Jacques Hiblot erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; 2098c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = (erase_gsz + 1) 2099c744b6f6SJean-Jacques Hiblot * (erase_gmul + 1); 2100c744b6f6SJean-Jacques Hiblot } 2101e6fa5a54SJean-Jacques Hiblot #endif 2102b7a6e2c9SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING) 2103c744b6f6SJean-Jacques Hiblot mmc->hc_wp_grp_size = 1024 2104c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 2105c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 2106b7a6e2c9SJean-Jacques Hiblot #endif 2107c744b6f6SJean-Jacques Hiblot 2108c744b6f6SJean-Jacques Hiblot mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 2109c744b6f6SJean-Jacques Hiblot 2110c744b6f6SJean-Jacques Hiblot return 0; 2111f7d5dffcSJean-Jacques Hiblot error: 2112f7d5dffcSJean-Jacques Hiblot if (mmc->ext_csd) { 2113f7d5dffcSJean-Jacques Hiblot free(mmc->ext_csd); 2114f7d5dffcSJean-Jacques Hiblot mmc->ext_csd = NULL; 2115f7d5dffcSJean-Jacques Hiblot } 2116f7d5dffcSJean-Jacques Hiblot return err; 2117c744b6f6SJean-Jacques Hiblot } 2118c744b6f6SJean-Jacques Hiblot 2119fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc) 2120272cc70bSAndy Fleming { 2121f866a46dSStephen Warren int err, i; 2122272cc70bSAndy Fleming uint mult, freq; 2123c744b6f6SJean-Jacques Hiblot u64 cmult, csize; 2124272cc70bSAndy Fleming struct mmc_cmd cmd; 2125c40fdca6SSimon Glass struct blk_desc *bdesc; 2126272cc70bSAndy Fleming 2127d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON 2128d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ 2129d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; 2130d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R1; 2131d52ebf10SThomas Chou cmd.cmdarg = 1; 2132d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 2133d52ebf10SThomas Chou if (err) 2134d52ebf10SThomas Chou return err; 2135d52ebf10SThomas Chou } 2136d52ebf10SThomas Chou #endif 2137d52ebf10SThomas Chou 2138272cc70bSAndy Fleming /* Put the Card in Identify Mode */ 2139d52ebf10SThomas Chou cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : 2140d52ebf10SThomas Chou MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ 2141272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 2142272cc70bSAndy Fleming cmd.cmdarg = 0; 2143272cc70bSAndy Fleming 2144272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2145272cc70bSAndy Fleming 214683dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS 214783dc4227SKishon Vijay Abraham I if (err && (mmc->quirks & MMC_QUIRK_RETRY_SEND_CID)) { 214883dc4227SKishon Vijay Abraham I int retries = 4; 214983dc4227SKishon Vijay Abraham I /* 215083dc4227SKishon Vijay Abraham I * It has been seen that SEND_CID may fail on the first 215183dc4227SKishon Vijay Abraham I * attempt, let's try a few more time 215283dc4227SKishon Vijay Abraham I */ 215383dc4227SKishon Vijay Abraham I do { 215483dc4227SKishon Vijay Abraham I err = mmc_send_cmd(mmc, &cmd, NULL); 215583dc4227SKishon Vijay Abraham I if (!err) 215683dc4227SKishon Vijay Abraham I break; 215783dc4227SKishon Vijay Abraham I } while (retries--); 215883dc4227SKishon Vijay Abraham I } 215983dc4227SKishon Vijay Abraham I #endif 216083dc4227SKishon Vijay Abraham I 2161272cc70bSAndy Fleming if (err) 2162272cc70bSAndy Fleming return err; 2163272cc70bSAndy Fleming 2164272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16); 2165272cc70bSAndy Fleming 2166272cc70bSAndy Fleming /* 2167272cc70bSAndy Fleming * For MMC cards, set the Relative Address. 2168272cc70bSAndy Fleming * For SD cards, get the Relatvie Address. 2169272cc70bSAndy Fleming * This also puts the cards into Standby State 2170272cc70bSAndy Fleming */ 2171d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 2172272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; 2173272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 2174272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6; 2175272cc70bSAndy Fleming 2176272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2177272cc70bSAndy Fleming 2178272cc70bSAndy Fleming if (err) 2179272cc70bSAndy Fleming return err; 2180272cc70bSAndy Fleming 2181272cc70bSAndy Fleming if (IS_SD(mmc)) 2182998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff; 2183d52ebf10SThomas Chou } 2184272cc70bSAndy Fleming 2185272cc70bSAndy Fleming /* Get the Card-Specific Data */ 2186272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD; 2187272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 2188272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 2189272cc70bSAndy Fleming 2190272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2191272cc70bSAndy Fleming 2192272cc70bSAndy Fleming if (err) 2193272cc70bSAndy Fleming return err; 2194272cc70bSAndy Fleming 2195998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0]; 2196998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1]; 2197998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2]; 2198998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3]; 2199272cc70bSAndy Fleming 2200272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) { 22010b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf; 2202272cc70bSAndy Fleming 2203272cc70bSAndy Fleming switch (version) { 2204272cc70bSAndy Fleming case 0: 2205272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 2206272cc70bSAndy Fleming break; 2207272cc70bSAndy Fleming case 1: 2208272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4; 2209272cc70bSAndy Fleming break; 2210272cc70bSAndy Fleming case 2: 2211272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2; 2212272cc70bSAndy Fleming break; 2213272cc70bSAndy Fleming case 3: 2214272cc70bSAndy Fleming mmc->version = MMC_VERSION_3; 2215272cc70bSAndy Fleming break; 2216272cc70bSAndy Fleming case 4: 2217272cc70bSAndy Fleming mmc->version = MMC_VERSION_4; 2218272cc70bSAndy Fleming break; 2219272cc70bSAndy Fleming default: 2220272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 2221272cc70bSAndy Fleming break; 2222272cc70bSAndy Fleming } 2223272cc70bSAndy Fleming } 2224272cc70bSAndy Fleming 2225272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */ 22260b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)]; 22270b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; 2228272cc70bSAndy Fleming 222935f9e196SJean-Jacques Hiblot mmc->legacy_speed = freq * mult; 223035f9e196SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_LEGACY); 2231272cc70bSAndy Fleming 2232ab71188cSMarkus Niebel mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); 2233998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); 2234e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE) 2235272cc70bSAndy Fleming 2236272cc70bSAndy Fleming if (IS_SD(mmc)) 2237272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len; 2238272cc70bSAndy Fleming else 2239998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); 2240e6fa5a54SJean-Jacques Hiblot #endif 2241272cc70bSAndy Fleming 2242272cc70bSAndy Fleming if (mmc->high_capacity) { 2243272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16 2244272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16; 2245272cc70bSAndy Fleming cmult = 8; 2246272cc70bSAndy Fleming } else { 2247272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2 2248272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30; 2249272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15; 2250272cc70bSAndy Fleming } 2251272cc70bSAndy Fleming 2252f866a46dSStephen Warren mmc->capacity_user = (csize + 1) << (cmult + 2); 2253f866a46dSStephen Warren mmc->capacity_user *= mmc->read_bl_len; 2254f866a46dSStephen Warren mmc->capacity_boot = 0; 2255f866a46dSStephen Warren mmc->capacity_rpmb = 0; 2256f866a46dSStephen Warren for (i = 0; i < 4; i++) 2257f866a46dSStephen Warren mmc->capacity_gp[i] = 0; 2258272cc70bSAndy Fleming 22598bfa195eSSimon Glass if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN) 22608bfa195eSSimon Glass mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 2261272cc70bSAndy Fleming 2262e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE) 22638bfa195eSSimon Glass if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) 22648bfa195eSSimon Glass mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 2265e6fa5a54SJean-Jacques Hiblot #endif 2266272cc70bSAndy Fleming 2267ab71188cSMarkus Niebel if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) { 2268ab71188cSMarkus Niebel cmd.cmdidx = MMC_CMD_SET_DSR; 2269ab71188cSMarkus Niebel cmd.cmdarg = (mmc->dsr & 0xffff) << 16; 2270ab71188cSMarkus Niebel cmd.resp_type = MMC_RSP_NONE; 2271ab71188cSMarkus Niebel if (mmc_send_cmd(mmc, &cmd, NULL)) 2272d8e3d420SJean-Jacques Hiblot pr_warn("MMC: SET_DSR failed\n"); 2273ab71188cSMarkus Niebel } 2274ab71188cSMarkus Niebel 2275272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */ 2276d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 2277272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD; 2278fe8f7066SAjay Bhargav cmd.resp_type = MMC_RSP_R1; 2279272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 2280272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2281272cc70bSAndy Fleming 2282272cc70bSAndy Fleming if (err) 2283272cc70bSAndy Fleming return err; 2284d52ebf10SThomas Chou } 2285272cc70bSAndy Fleming 2286e6f99a56SLei Wen /* 2287e6f99a56SLei Wen * For SD, its erase group is always one sector 2288e6f99a56SLei Wen */ 2289e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE) 2290e6f99a56SLei Wen mmc->erase_grp_size = 1; 2291e6fa5a54SJean-Jacques Hiblot #endif 2292bc897b1dSLei Wen mmc->part_config = MMCPART_NOAVAILABLE; 2293c744b6f6SJean-Jacques Hiblot 2294dfda9d88SJean-Jacques Hiblot err = mmc_startup_v4(mmc); 22959cf199ebSDiego Santa Cruz if (err) 22969cf199ebSDiego Santa Cruz return err; 2297f866a46dSStephen Warren 2298c40fdca6SSimon Glass err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart); 2299f866a46dSStephen Warren if (err) 2300f866a46dSStephen Warren return err; 2301d23e2c09SSukumar Ghorai 230201298da3SJean-Jacques Hiblot if (IS_SD(mmc)) { 230301298da3SJean-Jacques Hiblot err = sd_get_capabilities(mmc); 230401298da3SJean-Jacques Hiblot if (err) 230501298da3SJean-Jacques Hiblot return err; 230601298da3SJean-Jacques Hiblot err = sd_select_mode_and_width(mmc, mmc->card_caps); 230701298da3SJean-Jacques Hiblot } else { 230801298da3SJean-Jacques Hiblot err = mmc_get_capabilities(mmc); 230901298da3SJean-Jacques Hiblot if (err) 231001298da3SJean-Jacques Hiblot return err; 231101298da3SJean-Jacques Hiblot mmc_select_mode_and_width(mmc, mmc->card_caps); 231201298da3SJean-Jacques Hiblot } 2313272cc70bSAndy Fleming 2314272cc70bSAndy Fleming if (err) 2315272cc70bSAndy Fleming return err; 2316272cc70bSAndy Fleming 231701298da3SJean-Jacques Hiblot mmc->best_mode = mmc->selected_mode; 2318272cc70bSAndy Fleming 23195af8f45cSAndrew Gabbasov /* Fix the block length for DDR mode */ 23205af8f45cSAndrew Gabbasov if (mmc->ddr_mode) { 23215af8f45cSAndrew Gabbasov mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 2322e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE) 23235af8f45cSAndrew Gabbasov mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 2324e6fa5a54SJean-Jacques Hiblot #endif 23255af8f45cSAndrew Gabbasov } 23265af8f45cSAndrew Gabbasov 2327272cc70bSAndy Fleming /* fill in device description */ 2328c40fdca6SSimon Glass bdesc = mmc_get_blk_desc(mmc); 2329c40fdca6SSimon Glass bdesc->lun = 0; 2330c40fdca6SSimon Glass bdesc->hwpart = 0; 2331c40fdca6SSimon Glass bdesc->type = 0; 2332c40fdca6SSimon Glass bdesc->blksz = mmc->read_bl_len; 2333c40fdca6SSimon Glass bdesc->log2blksz = LOG2(bdesc->blksz); 2334c40fdca6SSimon Glass bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len); 2335fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \ 2336fc011f64SSjoerd Simons (defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \ 2337fc011f64SSjoerd Simons !defined(CONFIG_USE_TINY_PRINTF)) 2338c40fdca6SSimon Glass sprintf(bdesc->vendor, "Man %06x Snr %04x%04x", 2339babce5f6STaylor Hutt mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), 2340babce5f6STaylor Hutt (mmc->cid[3] >> 16) & 0xffff); 2341c40fdca6SSimon Glass sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff, 23420b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 2343babce5f6STaylor Hutt (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff, 2344babce5f6STaylor Hutt (mmc->cid[2] >> 24) & 0xff); 2345c40fdca6SSimon Glass sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf, 2346babce5f6STaylor Hutt (mmc->cid[2] >> 16) & 0xf); 234756196826SPaul Burton #else 2348c40fdca6SSimon Glass bdesc->vendor[0] = 0; 2349c40fdca6SSimon Glass bdesc->product[0] = 0; 2350c40fdca6SSimon Glass bdesc->revision[0] = 0; 235156196826SPaul Burton #endif 2352122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT) 2353c40fdca6SSimon Glass part_init(bdesc); 2354122efd43SMikhail Kshevetskiy #endif 2355272cc70bSAndy Fleming 2356272cc70bSAndy Fleming return 0; 2357272cc70bSAndy Fleming } 2358272cc70bSAndy Fleming 2359fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc) 2360272cc70bSAndy Fleming { 2361272cc70bSAndy Fleming struct mmc_cmd cmd; 2362272cc70bSAndy Fleming int err; 2363272cc70bSAndy Fleming 2364272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND; 2365272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ 236693bfd616SPantelis Antoniou cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa; 2367272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7; 2368272cc70bSAndy Fleming 2369272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2370272cc70bSAndy Fleming 2371272cc70bSAndy Fleming if (err) 2372272cc70bSAndy Fleming return err; 2373272cc70bSAndy Fleming 2374998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa) 2375915ffa52SJaehoon Chung return -EOPNOTSUPP; 2376272cc70bSAndy Fleming else 2377272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 2378272cc70bSAndy Fleming 2379272cc70bSAndy Fleming return 0; 2380272cc70bSAndy Fleming } 2381272cc70bSAndy Fleming 2382c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 238395de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */ 238495de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void) 238595de9ab2SPaul Kocialkowski { 238695de9ab2SPaul Kocialkowski } 238705cbeb7cSSimon Glass #endif 238895de9ab2SPaul Kocialkowski 23892051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc) 23902051aefeSPeng Fan { 2391c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 239206ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR) 23932051aefeSPeng Fan int ret; 23942051aefeSPeng Fan 23952051aefeSPeng Fan ret = device_get_supply_regulator(mmc->dev, "vmmc-supply", 239606ec045fSJean-Jacques Hiblot &mmc->vmmc_supply); 239706ec045fSJean-Jacques Hiblot if (ret) 2398d4d64889SMasahiro Yamada pr_debug("%s: No vmmc supply\n", mmc->dev->name); 23992051aefeSPeng Fan 240006ec045fSJean-Jacques Hiblot ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply", 240106ec045fSJean-Jacques Hiblot &mmc->vqmmc_supply); 240206ec045fSJean-Jacques Hiblot if (ret) 2403d4d64889SMasahiro Yamada pr_debug("%s: No vqmmc supply\n", mmc->dev->name); 24042051aefeSPeng Fan #endif 240505cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */ 240605cbeb7cSSimon Glass /* 240705cbeb7cSSimon Glass * Driver model should use a regulator, as above, rather than calling 240805cbeb7cSSimon Glass * out to board code. 240905cbeb7cSSimon Glass */ 241005cbeb7cSSimon Glass board_mmc_power_init(); 241105cbeb7cSSimon Glass #endif 24122051aefeSPeng Fan return 0; 24132051aefeSPeng Fan } 24142051aefeSPeng Fan 2415fb7c3bebSKishon Vijay Abraham I /* 2416fb7c3bebSKishon Vijay Abraham I * put the host in the initial state: 2417fb7c3bebSKishon Vijay Abraham I * - turn on Vdd (card power supply) 2418fb7c3bebSKishon Vijay Abraham I * - configure the bus width and clock to minimal values 2419fb7c3bebSKishon Vijay Abraham I */ 2420fb7c3bebSKishon Vijay Abraham I static void mmc_set_initial_state(struct mmc *mmc) 2421fb7c3bebSKishon Vijay Abraham I { 2422fb7c3bebSKishon Vijay Abraham I int err; 2423fb7c3bebSKishon Vijay Abraham I 2424fb7c3bebSKishon Vijay Abraham I /* First try to set 3.3V. If it fails set to 1.8V */ 2425fb7c3bebSKishon Vijay Abraham I err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_330); 2426fb7c3bebSKishon Vijay Abraham I if (err != 0) 2427fb7c3bebSKishon Vijay Abraham I err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_180); 2428fb7c3bebSKishon Vijay Abraham I if (err != 0) 2429d8e3d420SJean-Jacques Hiblot pr_warn("mmc: failed to set signal voltage\n"); 2430fb7c3bebSKishon Vijay Abraham I 2431fb7c3bebSKishon Vijay Abraham I mmc_select_mode(mmc, MMC_LEGACY); 2432fb7c3bebSKishon Vijay Abraham I mmc_set_bus_width(mmc, 1); 243365117182SJaehoon Chung mmc_set_clock(mmc, 0, MMC_CLK_ENABLE); 2434fb7c3bebSKishon Vijay Abraham I } 2435fb7c3bebSKishon Vijay Abraham I 2436fb7c3bebSKishon Vijay Abraham I static int mmc_power_on(struct mmc *mmc) 2437fb7c3bebSKishon Vijay Abraham I { 2438fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR) 2439fb7c3bebSKishon Vijay Abraham I if (mmc->vmmc_supply) { 2440fb7c3bebSKishon Vijay Abraham I int ret = regulator_set_enable(mmc->vmmc_supply, true); 2441fb7c3bebSKishon Vijay Abraham I 2442fb7c3bebSKishon Vijay Abraham I if (ret) { 2443fb7c3bebSKishon Vijay Abraham I puts("Error enabling VMMC supply\n"); 2444fb7c3bebSKishon Vijay Abraham I return ret; 2445fb7c3bebSKishon Vijay Abraham I } 2446fb7c3bebSKishon Vijay Abraham I } 2447fb7c3bebSKishon Vijay Abraham I #endif 2448fb7c3bebSKishon Vijay Abraham I return 0; 2449fb7c3bebSKishon Vijay Abraham I } 2450fb7c3bebSKishon Vijay Abraham I 2451fb7c3bebSKishon Vijay Abraham I static int mmc_power_off(struct mmc *mmc) 2452fb7c3bebSKishon Vijay Abraham I { 245365117182SJaehoon Chung mmc_set_clock(mmc, 0, MMC_CLK_DISABLE); 2454fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR) 2455fb7c3bebSKishon Vijay Abraham I if (mmc->vmmc_supply) { 2456fb7c3bebSKishon Vijay Abraham I int ret = regulator_set_enable(mmc->vmmc_supply, false); 2457fb7c3bebSKishon Vijay Abraham I 2458fb7c3bebSKishon Vijay Abraham I if (ret) { 2459d4d64889SMasahiro Yamada pr_debug("Error disabling VMMC supply\n"); 2460fb7c3bebSKishon Vijay Abraham I return ret; 2461fb7c3bebSKishon Vijay Abraham I } 2462fb7c3bebSKishon Vijay Abraham I } 2463fb7c3bebSKishon Vijay Abraham I #endif 2464fb7c3bebSKishon Vijay Abraham I return 0; 2465fb7c3bebSKishon Vijay Abraham I } 2466fb7c3bebSKishon Vijay Abraham I 2467fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc) 2468fb7c3bebSKishon Vijay Abraham I { 2469fb7c3bebSKishon Vijay Abraham I int ret; 2470fb7c3bebSKishon Vijay Abraham I 2471fb7c3bebSKishon Vijay Abraham I ret = mmc_power_off(mmc); 2472fb7c3bebSKishon Vijay Abraham I if (ret) 2473fb7c3bebSKishon Vijay Abraham I return ret; 2474fb7c3bebSKishon Vijay Abraham I /* 2475fb7c3bebSKishon Vijay Abraham I * SD spec recommends at least 1ms of delay. Let's wait for 2ms 2476fb7c3bebSKishon Vijay Abraham I * to be on the safer side. 2477fb7c3bebSKishon Vijay Abraham I */ 2478fb7c3bebSKishon Vijay Abraham I udelay(2000); 2479fb7c3bebSKishon Vijay Abraham I return mmc_power_on(mmc); 2480fb7c3bebSKishon Vijay Abraham I } 2481fb7c3bebSKishon Vijay Abraham I 2482e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc) 2483272cc70bSAndy Fleming { 24848ca51e51SSimon Glass bool no_card; 2485c10b85d6SJean-Jacques Hiblot bool uhs_en = supports_uhs(mmc->cfg->host_caps); 2486afd5932bSMacpaul Lin int err; 2487272cc70bSAndy Fleming 24881da8eb59SJean-Jacques Hiblot /* 24891da8eb59SJean-Jacques Hiblot * all hosts are capable of 1 bit bus-width and able to use the legacy 24901da8eb59SJean-Jacques Hiblot * timings. 24911da8eb59SJean-Jacques Hiblot */ 24921da8eb59SJean-Jacques Hiblot mmc->host_caps = mmc->cfg->host_caps | MMC_CAP(SD_LEGACY) | 24931da8eb59SJean-Jacques Hiblot MMC_CAP(MMC_LEGACY) | MMC_MODE_1BIT; 249404a2ea24SJean-Jacques Hiblot 24952f516e4aSJun Nie #if !defined(CONFIG_MMC_BROKEN_CD) 2496ab769f22SPantelis Antoniou /* we pretend there's no card when init is NULL */ 24978ca51e51SSimon Glass no_card = mmc_getcd(mmc) == 0; 24982f516e4aSJun Nie #else 24992f516e4aSJun Nie no_card = 0; 25002f516e4aSJun Nie #endif 2501e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 25028ca51e51SSimon Glass no_card = no_card || (mmc->cfg->ops->init == NULL); 25038ca51e51SSimon Glass #endif 25048ca51e51SSimon Glass if (no_card) { 250548972d90SThierry Reding mmc->has_init = 0; 250656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2507d4d64889SMasahiro Yamada pr_err("MMC: no card present\n"); 250856196826SPaul Burton #endif 2509915ffa52SJaehoon Chung return -ENOMEDIUM; 251048972d90SThierry Reding } 251148972d90SThierry Reding 2512bc897b1dSLei Wen if (mmc->has_init) 2513bc897b1dSLei Wen return 0; 2514bc897b1dSLei Wen 25155a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 25165a8dbdc6SYangbo Lu mmc_adapter_card_type_ident(); 25175a8dbdc6SYangbo Lu #endif 25182051aefeSPeng Fan err = mmc_power_init(mmc); 25192051aefeSPeng Fan if (err) 25202051aefeSPeng Fan return err; 252195de9ab2SPaul Kocialkowski 252283dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS 252383dc4227SKishon Vijay Abraham I mmc->quirks = MMC_QUIRK_RETRY_SET_BLOCKLEN | 252483dc4227SKishon Vijay Abraham I MMC_QUIRK_RETRY_SEND_CID; 252583dc4227SKishon Vijay Abraham I #endif 252683dc4227SKishon Vijay Abraham I 252704a2ea24SJean-Jacques Hiblot err = mmc_power_cycle(mmc); 252804a2ea24SJean-Jacques Hiblot if (err) { 252904a2ea24SJean-Jacques Hiblot /* 253004a2ea24SJean-Jacques Hiblot * if power cycling is not supported, we should not try 253104a2ea24SJean-Jacques Hiblot * to use the UHS modes, because we wouldn't be able to 253204a2ea24SJean-Jacques Hiblot * recover from an error during the UHS initialization. 253304a2ea24SJean-Jacques Hiblot */ 2534d4d64889SMasahiro Yamada pr_debug("Unable to do a full power cycle. Disabling the UHS modes for safety\n"); 253504a2ea24SJean-Jacques Hiblot uhs_en = false; 253604a2ea24SJean-Jacques Hiblot mmc->host_caps &= ~UHS_CAPS; 2537fb7c3bebSKishon Vijay Abraham I err = mmc_power_on(mmc); 253804a2ea24SJean-Jacques Hiblot } 2539fb7c3bebSKishon Vijay Abraham I if (err) 2540fb7c3bebSKishon Vijay Abraham I return err; 2541fb7c3bebSKishon Vijay Abraham I 2542e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 25438ca51e51SSimon Glass /* The device has already been probed ready for use */ 25448ca51e51SSimon Glass #else 2545ab769f22SPantelis Antoniou /* made sure it's not NULL earlier */ 254693bfd616SPantelis Antoniou err = mmc->cfg->ops->init(mmc); 2547272cc70bSAndy Fleming if (err) 2548272cc70bSAndy Fleming return err; 25498ca51e51SSimon Glass #endif 2550786e8f81SAndrew Gabbasov mmc->ddr_mode = 0; 2551aff5d3c8SKishon Vijay Abraham I 2552c10b85d6SJean-Jacques Hiblot retry: 2553fb7c3bebSKishon Vijay Abraham I mmc_set_initial_state(mmc); 2554318a7a57SJean-Jacques Hiblot mmc_send_init_stream(mmc); 2555318a7a57SJean-Jacques Hiblot 2556272cc70bSAndy Fleming /* Reset the Card */ 2557272cc70bSAndy Fleming err = mmc_go_idle(mmc); 2558272cc70bSAndy Fleming 2559272cc70bSAndy Fleming if (err) 2560272cc70bSAndy Fleming return err; 2561272cc70bSAndy Fleming 2562bc897b1dSLei Wen /* The internal partition reset to user partition(0) at every CMD0*/ 2563c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->hwpart = 0; 2564bc897b1dSLei Wen 2565272cc70bSAndy Fleming /* Test for SD version 2 */ 2566272cc70bSAndy Fleming err = mmc_send_if_cond(mmc); 2567272cc70bSAndy Fleming 2568272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */ 2569c10b85d6SJean-Jacques Hiblot err = sd_send_op_cond(mmc, uhs_en); 2570c10b85d6SJean-Jacques Hiblot if (err && uhs_en) { 2571c10b85d6SJean-Jacques Hiblot uhs_en = false; 2572c10b85d6SJean-Jacques Hiblot mmc_power_cycle(mmc); 2573c10b85d6SJean-Jacques Hiblot goto retry; 2574c10b85d6SJean-Jacques Hiblot } 2575272cc70bSAndy Fleming 2576272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */ 2577915ffa52SJaehoon Chung if (err == -ETIMEDOUT) { 2578272cc70bSAndy Fleming err = mmc_send_op_cond(mmc); 2579272cc70bSAndy Fleming 2580bd47c135SAndrew Gabbasov if (err) { 258156196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2582d8e3d420SJean-Jacques Hiblot pr_err("Card did not respond to voltage select!\n"); 258356196826SPaul Burton #endif 2584915ffa52SJaehoon Chung return -EOPNOTSUPP; 2585272cc70bSAndy Fleming } 2586272cc70bSAndy Fleming } 2587272cc70bSAndy Fleming 2588bd47c135SAndrew Gabbasov if (!err) 2589e9550449SChe-Liang Chiou mmc->init_in_progress = 1; 2590e9550449SChe-Liang Chiou 2591e9550449SChe-Liang Chiou return err; 2592e9550449SChe-Liang Chiou } 2593e9550449SChe-Liang Chiou 2594e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc) 2595e9550449SChe-Liang Chiou { 2596e9550449SChe-Liang Chiou int err = 0; 2597e9550449SChe-Liang Chiou 2598bd47c135SAndrew Gabbasov mmc->init_in_progress = 0; 2599e9550449SChe-Liang Chiou if (mmc->op_cond_pending) 2600e9550449SChe-Liang Chiou err = mmc_complete_op_cond(mmc); 2601e9550449SChe-Liang Chiou 2602e9550449SChe-Liang Chiou if (!err) 2603bc897b1dSLei Wen err = mmc_startup(mmc); 2604bc897b1dSLei Wen if (err) 2605bc897b1dSLei Wen mmc->has_init = 0; 2606bc897b1dSLei Wen else 2607bc897b1dSLei Wen mmc->has_init = 1; 2608e9550449SChe-Liang Chiou return err; 2609e9550449SChe-Liang Chiou } 2610e9550449SChe-Liang Chiou 2611e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc) 2612e9550449SChe-Liang Chiou { 2613bd47c135SAndrew Gabbasov int err = 0; 2614*36332b6eSVipul Kumar __maybe_unused ulong start; 2615c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 261633fb211dSSimon Glass struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev); 2617e9550449SChe-Liang Chiou 261833fb211dSSimon Glass upriv->mmc = mmc; 261933fb211dSSimon Glass #endif 2620e9550449SChe-Liang Chiou if (mmc->has_init) 2621e9550449SChe-Liang Chiou return 0; 2622d803fea5SMateusz Zalega 2623d803fea5SMateusz Zalega start = get_timer(0); 2624d803fea5SMateusz Zalega 2625e9550449SChe-Liang Chiou if (!mmc->init_in_progress) 2626e9550449SChe-Liang Chiou err = mmc_start_init(mmc); 2627e9550449SChe-Liang Chiou 2628bd47c135SAndrew Gabbasov if (!err) 2629e9550449SChe-Liang Chiou err = mmc_complete_init(mmc); 2630919b4858SJagan Teki if (err) 2631d4d64889SMasahiro Yamada pr_info("%s: %d, time %lu\n", __func__, err, get_timer(start)); 2632919b4858SJagan Teki 2633bc897b1dSLei Wen return err; 2634272cc70bSAndy Fleming } 2635272cc70bSAndy Fleming 2636ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val) 2637ab71188cSMarkus Niebel { 2638ab71188cSMarkus Niebel mmc->dsr = val; 2639ab71188cSMarkus Niebel return 0; 2640ab71188cSMarkus Niebel } 2641ab71188cSMarkus Niebel 2642cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */ 2643cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis) 2644272cc70bSAndy Fleming { 2645272cc70bSAndy Fleming return -1; 2646272cc70bSAndy Fleming } 2647272cc70bSAndy Fleming 2648cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */ 2649cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis) 2650cee9ab7cSJeroen Hofstee { 2651cee9ab7cSJeroen Hofstee return -1; 2652cee9ab7cSJeroen Hofstee } 2653272cc70bSAndy Fleming 2654e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit) 2655e9550449SChe-Liang Chiou { 2656e9550449SChe-Liang Chiou mmc->preinit = preinit; 2657e9550449SChe-Liang Chiou } 2658e9550449SChe-Liang Chiou 26598a856db2SFaiz Abbas #if CONFIG_IS_ENABLED(DM_MMC) 26608e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 26618e3332e2SSjoerd Simons { 26624a1db6d8SSimon Glass int ret, i; 26638e3332e2SSjoerd Simons struct uclass *uc; 26644a1db6d8SSimon Glass struct udevice *dev; 26658e3332e2SSjoerd Simons 26668e3332e2SSjoerd Simons ret = uclass_get(UCLASS_MMC, &uc); 26678e3332e2SSjoerd Simons if (ret) 26688e3332e2SSjoerd Simons return ret; 26698e3332e2SSjoerd Simons 26704a1db6d8SSimon Glass /* 26714a1db6d8SSimon Glass * Try to add them in sequence order. Really with driver model we 26724a1db6d8SSimon Glass * should allow holes, but the current MMC list does not allow that. 26734a1db6d8SSimon Glass * So if we request 0, 1, 3 we will get 0, 1, 2. 26744a1db6d8SSimon Glass */ 26754a1db6d8SSimon Glass for (i = 0; ; i++) { 26764a1db6d8SSimon Glass ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev); 26774a1db6d8SSimon Glass if (ret == -ENODEV) 26784a1db6d8SSimon Glass break; 26794a1db6d8SSimon Glass } 26804a1db6d8SSimon Glass uclass_foreach_dev(dev, uc) { 26814a1db6d8SSimon Glass ret = device_probe(dev); 26828e3332e2SSjoerd Simons if (ret) 2683d8e3d420SJean-Jacques Hiblot pr_err("%s - probe failed: %d\n", dev->name, ret); 26848e3332e2SSjoerd Simons } 26858e3332e2SSjoerd Simons 26868e3332e2SSjoerd Simons return 0; 26878e3332e2SSjoerd Simons } 26888e3332e2SSjoerd Simons #else 26898e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 26908e3332e2SSjoerd Simons { 26918e3332e2SSjoerd Simons if (board_mmc_init(bis) < 0) 26928e3332e2SSjoerd Simons cpu_mmc_init(bis); 26938e3332e2SSjoerd Simons 26948e3332e2SSjoerd Simons return 0; 26958e3332e2SSjoerd Simons } 26968e3332e2SSjoerd Simons #endif 2697e9550449SChe-Liang Chiou 2698272cc70bSAndy Fleming int mmc_initialize(bd_t *bis) 2699272cc70bSAndy Fleming { 27001b26bab1SDaniel Kochmański static int initialized = 0; 27018e3332e2SSjoerd Simons int ret; 27021b26bab1SDaniel Kochmański if (initialized) /* Avoid initializing mmc multiple times */ 27031b26bab1SDaniel Kochmański return 0; 27041b26bab1SDaniel Kochmański initialized = 1; 27051b26bab1SDaniel Kochmański 2706c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK) 2707b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY) 2708c40fdca6SSimon Glass mmc_list_init(); 2709c40fdca6SSimon Glass #endif 2710b5b838f1SMarek Vasut #endif 27118e3332e2SSjoerd Simons ret = mmc_probe(bis); 27128e3332e2SSjoerd Simons if (ret) 27138e3332e2SSjoerd Simons return ret; 2714272cc70bSAndy Fleming 2715bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD 2716272cc70bSAndy Fleming print_mmc_devices(','); 2717bb0dc108SYing Zhang #endif 2718272cc70bSAndy Fleming 2719c40fdca6SSimon Glass mmc_do_preinit(); 2720272cc70bSAndy Fleming return 0; 2721272cc70bSAndy Fleming } 2722cd3d4880STomas Melin 2723cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE 2724cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc) 2725cd3d4880STomas Melin { 2726cd3d4880STomas Melin int err; 2727cd3d4880STomas Melin ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 2728cd3d4880STomas Melin 2729cd3d4880STomas Melin err = mmc_send_ext_csd(mmc, ext_csd); 2730cd3d4880STomas Melin if (err) { 2731cd3d4880STomas Melin puts("Could not get ext_csd register values\n"); 2732cd3d4880STomas Melin return err; 2733cd3d4880STomas Melin } 2734cd3d4880STomas Melin 2735cd3d4880STomas Melin if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) { 2736cd3d4880STomas Melin puts("Background operations not supported on device\n"); 2737cd3d4880STomas Melin return -EMEDIUMTYPE; 2738cd3d4880STomas Melin } 2739cd3d4880STomas Melin 2740cd3d4880STomas Melin if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) { 2741cd3d4880STomas Melin puts("Background operations already enabled\n"); 2742cd3d4880STomas Melin return 0; 2743cd3d4880STomas Melin } 2744cd3d4880STomas Melin 2745cd3d4880STomas Melin err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1); 2746cd3d4880STomas Melin if (err) { 2747cd3d4880STomas Melin puts("Failed to enable manual background operations\n"); 2748cd3d4880STomas Melin return err; 2749cd3d4880STomas Melin } 2750cd3d4880STomas Melin 2751cd3d4880STomas Melin puts("Enabled manual background operations\n"); 2752cd3d4880STomas Melin 2753cd3d4880STomas Melin return 0; 2754cd3d4880STomas Melin } 2755cd3d4880STomas Melin #endif 2756