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); 2662d77ceaSMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY) 2701298da3SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps); 28b5b838f1SMarek Vasut #endif 29b5b838f1SMarek Vasut 30e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 31c10b85d6SJean-Jacques Hiblot 32f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 33c10b85d6SJean-Jacques Hiblot static int mmc_wait_dat0(struct mmc *mmc, int state, int timeout) 34c10b85d6SJean-Jacques Hiblot { 35c10b85d6SJean-Jacques Hiblot return -ENOSYS; 36c10b85d6SJean-Jacques Hiblot } 37f99c2efeSJean-Jacques Hiblot #endif 38c10b85d6SJean-Jacques Hiblot 39750121c3SJeroen Hofstee __weak int board_mmc_getwp(struct mmc *mmc) 40d23d8d7eSNikita Kiryanov { 41d23d8d7eSNikita Kiryanov return -1; 42d23d8d7eSNikita Kiryanov } 43d23d8d7eSNikita Kiryanov 44d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc) 45d23d8d7eSNikita Kiryanov { 46d23d8d7eSNikita Kiryanov int wp; 47d23d8d7eSNikita Kiryanov 48d23d8d7eSNikita Kiryanov wp = board_mmc_getwp(mmc); 49d23d8d7eSNikita Kiryanov 50d4e1da4eSPeter Korsgaard if (wp < 0) { 5193bfd616SPantelis Antoniou if (mmc->cfg->ops->getwp) 5293bfd616SPantelis Antoniou wp = mmc->cfg->ops->getwp(mmc); 53d4e1da4eSPeter Korsgaard else 54d4e1da4eSPeter Korsgaard wp = 0; 55d4e1da4eSPeter Korsgaard } 56d23d8d7eSNikita Kiryanov 57d23d8d7eSNikita Kiryanov return wp; 58d23d8d7eSNikita Kiryanov } 59d23d8d7eSNikita Kiryanov 60cee9ab7cSJeroen Hofstee __weak int board_mmc_getcd(struct mmc *mmc) 61cee9ab7cSJeroen Hofstee { 6211fdade2SStefano Babic return -1; 6311fdade2SStefano Babic } 648ca51e51SSimon Glass #endif 6511fdade2SStefano Babic 668635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE 67c0c76ebaSSimon Glass void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd) 68c0c76ebaSSimon Glass { 69c0c76ebaSSimon Glass printf("CMD_SEND:%d\n", cmd->cmdidx); 70c0c76ebaSSimon Glass printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg); 71c0c76ebaSSimon Glass } 72c0c76ebaSSimon Glass 73c0c76ebaSSimon Glass void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret) 74c0c76ebaSSimon Glass { 755db2fe3aSRaffaele Recalcati int i; 765db2fe3aSRaffaele Recalcati u8 *ptr; 775db2fe3aSRaffaele Recalcati 787863ce58SBin Meng if (ret) { 797863ce58SBin Meng printf("\t\tRET\t\t\t %d\n", ret); 807863ce58SBin Meng } else { 815db2fe3aSRaffaele Recalcati switch (cmd->resp_type) { 825db2fe3aSRaffaele Recalcati case MMC_RSP_NONE: 835db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_NONE\n"); 845db2fe3aSRaffaele Recalcati break; 855db2fe3aSRaffaele Recalcati case MMC_RSP_R1: 865db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n", 875db2fe3aSRaffaele Recalcati cmd->response[0]); 885db2fe3aSRaffaele Recalcati break; 895db2fe3aSRaffaele Recalcati case MMC_RSP_R1b: 905db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n", 915db2fe3aSRaffaele Recalcati cmd->response[0]); 925db2fe3aSRaffaele Recalcati break; 935db2fe3aSRaffaele Recalcati case MMC_RSP_R2: 945db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R2\t\t 0x%08X \n", 955db2fe3aSRaffaele Recalcati cmd->response[0]); 965db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 975db2fe3aSRaffaele Recalcati cmd->response[1]); 985db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 995db2fe3aSRaffaele Recalcati cmd->response[2]); 1005db2fe3aSRaffaele Recalcati printf("\t\t \t\t 0x%08X \n", 1015db2fe3aSRaffaele Recalcati cmd->response[3]); 1025db2fe3aSRaffaele Recalcati printf("\n"); 1035db2fe3aSRaffaele Recalcati printf("\t\t\t\t\tDUMPING DATA\n"); 1045db2fe3aSRaffaele Recalcati for (i = 0; i < 4; i++) { 1055db2fe3aSRaffaele Recalcati int j; 1065db2fe3aSRaffaele Recalcati printf("\t\t\t\t\t%03d - ", i*4); 107146bec79SDirk Behme ptr = (u8 *)&cmd->response[i]; 1085db2fe3aSRaffaele Recalcati ptr += 3; 1095db2fe3aSRaffaele Recalcati for (j = 0; j < 4; j++) 1105db2fe3aSRaffaele Recalcati printf("%02X ", *ptr--); 1115db2fe3aSRaffaele Recalcati printf("\n"); 1125db2fe3aSRaffaele Recalcati } 1135db2fe3aSRaffaele Recalcati break; 1145db2fe3aSRaffaele Recalcati case MMC_RSP_R3: 1155db2fe3aSRaffaele Recalcati printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n", 1165db2fe3aSRaffaele Recalcati cmd->response[0]); 1175db2fe3aSRaffaele Recalcati break; 1185db2fe3aSRaffaele Recalcati default: 1195db2fe3aSRaffaele Recalcati printf("\t\tERROR MMC rsp not supported\n"); 1205db2fe3aSRaffaele Recalcati break; 1215db2fe3aSRaffaele Recalcati } 1227863ce58SBin Meng } 123c0c76ebaSSimon Glass } 124c0c76ebaSSimon Glass 125c0c76ebaSSimon Glass void mmc_trace_state(struct mmc *mmc, struct mmc_cmd *cmd) 126c0c76ebaSSimon Glass { 127c0c76ebaSSimon Glass int status; 128c0c76ebaSSimon Glass 129c0c76ebaSSimon Glass status = (cmd->response[0] & MMC_STATUS_CURR_STATE) >> 9; 130c0c76ebaSSimon Glass printf("CURR STATE:%d\n", status); 131c0c76ebaSSimon Glass } 1325db2fe3aSRaffaele Recalcati #endif 133c0c76ebaSSimon Glass 13435f9e196SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG) 13535f9e196SJean-Jacques Hiblot const char *mmc_mode_name(enum bus_mode mode) 13635f9e196SJean-Jacques Hiblot { 13735f9e196SJean-Jacques Hiblot static const char *const names[] = { 13835f9e196SJean-Jacques Hiblot [MMC_LEGACY] = "MMC legacy", 13935f9e196SJean-Jacques Hiblot [SD_LEGACY] = "SD Legacy", 14035f9e196SJean-Jacques Hiblot [MMC_HS] = "MMC High Speed (26MHz)", 14135f9e196SJean-Jacques Hiblot [SD_HS] = "SD High Speed (50MHz)", 14235f9e196SJean-Jacques Hiblot [UHS_SDR12] = "UHS SDR12 (25MHz)", 14335f9e196SJean-Jacques Hiblot [UHS_SDR25] = "UHS SDR25 (50MHz)", 14435f9e196SJean-Jacques Hiblot [UHS_SDR50] = "UHS SDR50 (100MHz)", 14535f9e196SJean-Jacques Hiblot [UHS_SDR104] = "UHS SDR104 (208MHz)", 14635f9e196SJean-Jacques Hiblot [UHS_DDR50] = "UHS DDR50 (50MHz)", 14735f9e196SJean-Jacques Hiblot [MMC_HS_52] = "MMC High Speed (52MHz)", 14835f9e196SJean-Jacques Hiblot [MMC_DDR_52] = "MMC DDR52 (52MHz)", 14935f9e196SJean-Jacques Hiblot [MMC_HS_200] = "HS200 (200MHz)", 1503dd2626fSPeng Fan [MMC_HS_400] = "HS400 (200MHz)", 15135f9e196SJean-Jacques Hiblot }; 15235f9e196SJean-Jacques Hiblot 15335f9e196SJean-Jacques Hiblot if (mode >= MMC_MODES_END) 15435f9e196SJean-Jacques Hiblot return "Unknown mode"; 15535f9e196SJean-Jacques Hiblot else 15635f9e196SJean-Jacques Hiblot return names[mode]; 15735f9e196SJean-Jacques Hiblot } 15835f9e196SJean-Jacques Hiblot #endif 15935f9e196SJean-Jacques Hiblot 16005038576SJean-Jacques Hiblot static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode) 16105038576SJean-Jacques Hiblot { 16205038576SJean-Jacques Hiblot static const int freqs[] = { 1631b313aa3SJaehoon Chung [MMC_LEGACY] = 25000000, 16405038576SJean-Jacques Hiblot [SD_LEGACY] = 25000000, 16505038576SJean-Jacques Hiblot [MMC_HS] = 26000000, 16605038576SJean-Jacques Hiblot [SD_HS] = 50000000, 1671b313aa3SJaehoon Chung [MMC_HS_52] = 52000000, 1681b313aa3SJaehoon Chung [MMC_DDR_52] = 52000000, 16905038576SJean-Jacques Hiblot [UHS_SDR12] = 25000000, 17005038576SJean-Jacques Hiblot [UHS_SDR25] = 50000000, 17105038576SJean-Jacques Hiblot [UHS_SDR50] = 100000000, 17205038576SJean-Jacques Hiblot [UHS_DDR50] = 50000000, 173f99c2efeSJean-Jacques Hiblot [UHS_SDR104] = 208000000, 17405038576SJean-Jacques Hiblot [MMC_HS_200] = 200000000, 1753dd2626fSPeng Fan [MMC_HS_400] = 200000000, 17605038576SJean-Jacques Hiblot }; 17705038576SJean-Jacques Hiblot 17805038576SJean-Jacques Hiblot if (mode == MMC_LEGACY) 17905038576SJean-Jacques Hiblot return mmc->legacy_speed; 18005038576SJean-Jacques Hiblot else if (mode >= MMC_MODES_END) 18105038576SJean-Jacques Hiblot return 0; 18205038576SJean-Jacques Hiblot else 18305038576SJean-Jacques Hiblot return freqs[mode]; 18405038576SJean-Jacques Hiblot } 18505038576SJean-Jacques Hiblot 18635f9e196SJean-Jacques Hiblot static int mmc_select_mode(struct mmc *mmc, enum bus_mode mode) 18735f9e196SJean-Jacques Hiblot { 18835f9e196SJean-Jacques Hiblot mmc->selected_mode = mode; 18905038576SJean-Jacques Hiblot mmc->tran_speed = mmc_mode2freq(mmc, mode); 1903862b854SJean-Jacques Hiblot mmc->ddr_mode = mmc_is_mode_ddr(mode); 191d4d64889SMasahiro Yamada pr_debug("selecting mode %s (freq : %d MHz)\n", mmc_mode_name(mode), 19235f9e196SJean-Jacques Hiblot mmc->tran_speed / 1000000); 19335f9e196SJean-Jacques Hiblot return 0; 19435f9e196SJean-Jacques Hiblot } 19535f9e196SJean-Jacques Hiblot 196e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 197c0c76ebaSSimon Glass int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) 198c0c76ebaSSimon Glass { 199c0c76ebaSSimon Glass int ret; 200c0c76ebaSSimon Glass 201c0c76ebaSSimon Glass mmmc_trace_before_send(mmc, cmd); 202c0c76ebaSSimon Glass ret = mmc->cfg->ops->send_cmd(mmc, cmd, data); 203c0c76ebaSSimon Glass mmmc_trace_after_send(mmc, cmd, ret); 204c0c76ebaSSimon Glass 2058635ff9eSMarek Vasut return ret; 206272cc70bSAndy Fleming } 2078ca51e51SSimon Glass #endif 208272cc70bSAndy Fleming 209da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout) 2105d4fc8d9SRaffaele Recalcati { 2115d4fc8d9SRaffaele Recalcati struct mmc_cmd cmd; 212d617c426SJan Kloetzke int err, retries = 5; 2135d4fc8d9SRaffaele Recalcati 2145d4fc8d9SRaffaele Recalcati cmd.cmdidx = MMC_CMD_SEND_STATUS; 2155d4fc8d9SRaffaele Recalcati cmd.resp_type = MMC_RSP_R1; 216aaf3d41aSMarek Vasut if (!mmc_host_is_spi(mmc)) 217aaf3d41aSMarek Vasut cmd.cmdarg = mmc->rca << 16; 2185d4fc8d9SRaffaele Recalcati 2191677eef4SAndrew Gabbasov while (1) { 2205d4fc8d9SRaffaele Recalcati err = mmc_send_cmd(mmc, &cmd, NULL); 221d617c426SJan Kloetzke if (!err) { 222d617c426SJan Kloetzke if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) && 223d617c426SJan Kloetzke (cmd.response[0] & MMC_STATUS_CURR_STATE) != 224d617c426SJan Kloetzke MMC_STATE_PRG) 2255d4fc8d9SRaffaele Recalcati break; 226d0c221feSJean-Jacques Hiblot 227d0c221feSJean-Jacques Hiblot if (cmd.response[0] & MMC_STATUS_MASK) { 22856196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 229d8e3d420SJean-Jacques Hiblot pr_err("Status Error: 0x%08X\n", 230d617c426SJan Kloetzke cmd.response[0]); 23156196826SPaul Burton #endif 232915ffa52SJaehoon Chung return -ECOMM; 233d617c426SJan Kloetzke } 234d617c426SJan Kloetzke } else if (--retries < 0) 235d617c426SJan Kloetzke return err; 2365d4fc8d9SRaffaele Recalcati 2371677eef4SAndrew Gabbasov if (timeout-- <= 0) 2381677eef4SAndrew Gabbasov break; 2395d4fc8d9SRaffaele Recalcati 2401677eef4SAndrew Gabbasov udelay(1000); 2411677eef4SAndrew Gabbasov } 2425d4fc8d9SRaffaele Recalcati 243c0c76ebaSSimon Glass mmc_trace_state(mmc, &cmd); 2445b0c942fSJongman Heo if (timeout <= 0) { 24556196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 246d8e3d420SJean-Jacques Hiblot pr_err("Timeout waiting card ready\n"); 24756196826SPaul Burton #endif 248915ffa52SJaehoon Chung return -ETIMEDOUT; 2495d4fc8d9SRaffaele Recalcati } 2505d4fc8d9SRaffaele Recalcati 2515d4fc8d9SRaffaele Recalcati return 0; 2525d4fc8d9SRaffaele Recalcati } 2535d4fc8d9SRaffaele Recalcati 254da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len) 255272cc70bSAndy Fleming { 256272cc70bSAndy Fleming struct mmc_cmd cmd; 25783dc4227SKishon Vijay Abraham I int err; 258272cc70bSAndy Fleming 259786e8f81SAndrew Gabbasov if (mmc->ddr_mode) 260d22e3d46SJaehoon Chung return 0; 261d22e3d46SJaehoon Chung 262272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SET_BLOCKLEN; 263272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 264272cc70bSAndy Fleming cmd.cmdarg = len; 265272cc70bSAndy Fleming 26683dc4227SKishon Vijay Abraham I err = mmc_send_cmd(mmc, &cmd, NULL); 26783dc4227SKishon Vijay Abraham I 26883dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS 26983dc4227SKishon Vijay Abraham I if (err && (mmc->quirks & MMC_QUIRK_RETRY_SET_BLOCKLEN)) { 27083dc4227SKishon Vijay Abraham I int retries = 4; 27183dc4227SKishon Vijay Abraham I /* 27283dc4227SKishon Vijay Abraham I * It has been seen that SET_BLOCKLEN may fail on the first 27383dc4227SKishon Vijay Abraham I * attempt, let's try a few more time 27483dc4227SKishon Vijay Abraham I */ 27583dc4227SKishon Vijay Abraham I do { 27683dc4227SKishon Vijay Abraham I err = mmc_send_cmd(mmc, &cmd, NULL); 27783dc4227SKishon Vijay Abraham I if (!err) 27883dc4227SKishon Vijay Abraham I break; 27983dc4227SKishon Vijay Abraham I } while (retries--); 28083dc4227SKishon Vijay Abraham I } 28183dc4227SKishon Vijay Abraham I #endif 28283dc4227SKishon Vijay Abraham I 28383dc4227SKishon Vijay Abraham I return err; 284272cc70bSAndy Fleming } 285272cc70bSAndy Fleming 286f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 2879815e3baSJean-Jacques Hiblot static const u8 tuning_blk_pattern_4bit[] = { 2889815e3baSJean-Jacques Hiblot 0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc, 2899815e3baSJean-Jacques Hiblot 0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef, 2909815e3baSJean-Jacques Hiblot 0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb, 2919815e3baSJean-Jacques Hiblot 0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef, 2929815e3baSJean-Jacques Hiblot 0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c, 2939815e3baSJean-Jacques Hiblot 0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee, 2949815e3baSJean-Jacques Hiblot 0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff, 2959815e3baSJean-Jacques Hiblot 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde, 2969815e3baSJean-Jacques Hiblot }; 2979815e3baSJean-Jacques Hiblot 2989815e3baSJean-Jacques Hiblot static const u8 tuning_blk_pattern_8bit[] = { 2999815e3baSJean-Jacques Hiblot 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 3009815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc, 3019815e3baSJean-Jacques Hiblot 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff, 3029815e3baSJean-Jacques Hiblot 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff, 3039815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd, 3049815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, 3059815e3baSJean-Jacques Hiblot 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff, 3069815e3baSJean-Jacques Hiblot 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff, 3079815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 3089815e3baSJean-Jacques Hiblot 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 3099815e3baSJean-Jacques Hiblot 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 3109815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 3119815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 3129815e3baSJean-Jacques Hiblot 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 3139815e3baSJean-Jacques Hiblot 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 3149815e3baSJean-Jacques Hiblot 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 3159815e3baSJean-Jacques Hiblot }; 3169815e3baSJean-Jacques Hiblot 3179815e3baSJean-Jacques Hiblot int mmc_send_tuning(struct mmc *mmc, u32 opcode, int *cmd_error) 3189815e3baSJean-Jacques Hiblot { 3199815e3baSJean-Jacques Hiblot struct mmc_cmd cmd; 3209815e3baSJean-Jacques Hiblot struct mmc_data data; 3219815e3baSJean-Jacques Hiblot const u8 *tuning_block_pattern; 3229815e3baSJean-Jacques Hiblot int size, err; 3239815e3baSJean-Jacques Hiblot 3249815e3baSJean-Jacques Hiblot if (mmc->bus_width == 8) { 3259815e3baSJean-Jacques Hiblot tuning_block_pattern = tuning_blk_pattern_8bit; 3269815e3baSJean-Jacques Hiblot size = sizeof(tuning_blk_pattern_8bit); 3279815e3baSJean-Jacques Hiblot } else if (mmc->bus_width == 4) { 3289815e3baSJean-Jacques Hiblot tuning_block_pattern = tuning_blk_pattern_4bit; 3299815e3baSJean-Jacques Hiblot size = sizeof(tuning_blk_pattern_4bit); 3309815e3baSJean-Jacques Hiblot } else { 3319815e3baSJean-Jacques Hiblot return -EINVAL; 3329815e3baSJean-Jacques Hiblot } 3339815e3baSJean-Jacques Hiblot 3349815e3baSJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, data_buf, size); 3359815e3baSJean-Jacques Hiblot 3369815e3baSJean-Jacques Hiblot cmd.cmdidx = opcode; 3379815e3baSJean-Jacques Hiblot cmd.cmdarg = 0; 3389815e3baSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 3399815e3baSJean-Jacques Hiblot 3409815e3baSJean-Jacques Hiblot data.dest = (void *)data_buf; 3419815e3baSJean-Jacques Hiblot data.blocks = 1; 3429815e3baSJean-Jacques Hiblot data.blocksize = size; 3439815e3baSJean-Jacques Hiblot data.flags = MMC_DATA_READ; 3449815e3baSJean-Jacques Hiblot 3459815e3baSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, &data); 3469815e3baSJean-Jacques Hiblot if (err) 3479815e3baSJean-Jacques Hiblot return err; 3489815e3baSJean-Jacques Hiblot 3499815e3baSJean-Jacques Hiblot if (memcmp(data_buf, tuning_block_pattern, size)) 3509815e3baSJean-Jacques Hiblot return -EIO; 3519815e3baSJean-Jacques Hiblot 3529815e3baSJean-Jacques Hiblot return 0; 3539815e3baSJean-Jacques Hiblot } 354f99c2efeSJean-Jacques Hiblot #endif 3559815e3baSJean-Jacques Hiblot 356ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start, 357fdbb873eSKim Phillips lbaint_t blkcnt) 358272cc70bSAndy Fleming { 359272cc70bSAndy Fleming struct mmc_cmd cmd; 360272cc70bSAndy Fleming struct mmc_data data; 361272cc70bSAndy Fleming 3624a1a06bcSAlagu Sankar if (blkcnt > 1) 3634a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; 3644a1a06bcSAlagu Sankar else 365272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; 366272cc70bSAndy Fleming 367272cc70bSAndy Fleming if (mmc->high_capacity) 3684a1a06bcSAlagu Sankar cmd.cmdarg = start; 369272cc70bSAndy Fleming else 3704a1a06bcSAlagu Sankar cmd.cmdarg = start * mmc->read_bl_len; 371272cc70bSAndy Fleming 372272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 373272cc70bSAndy Fleming 374272cc70bSAndy Fleming data.dest = dst; 3754a1a06bcSAlagu Sankar data.blocks = blkcnt; 376272cc70bSAndy Fleming data.blocksize = mmc->read_bl_len; 377272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 378272cc70bSAndy Fleming 3794a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, &data)) 3804a1a06bcSAlagu Sankar return 0; 3814a1a06bcSAlagu Sankar 3824a1a06bcSAlagu Sankar if (blkcnt > 1) { 3834a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; 3844a1a06bcSAlagu Sankar cmd.cmdarg = 0; 3854a1a06bcSAlagu Sankar cmd.resp_type = MMC_RSP_R1b; 3864a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, NULL)) { 38756196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 388d8e3d420SJean-Jacques Hiblot pr_err("mmc fail to send stop cmd\n"); 38956196826SPaul Burton #endif 3904a1a06bcSAlagu Sankar return 0; 3914a1a06bcSAlagu Sankar } 392272cc70bSAndy Fleming } 393272cc70bSAndy Fleming 3944a1a06bcSAlagu Sankar return blkcnt; 395272cc70bSAndy Fleming } 396272cc70bSAndy Fleming 397c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK) 3987dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst) 39933fb211dSSimon Glass #else 4007dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, 4017dba0b93SSimon Glass void *dst) 40233fb211dSSimon Glass #endif 403272cc70bSAndy Fleming { 404c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK) 40533fb211dSSimon Glass struct blk_desc *block_dev = dev_get_uclass_platdata(dev); 40633fb211dSSimon Glass #endif 407bcce53d0SSimon Glass int dev_num = block_dev->devnum; 408873cc1d7SStephen Warren int err; 4094a1a06bcSAlagu Sankar lbaint_t cur, blocks_todo = blkcnt; 410272cc70bSAndy Fleming 4114a1a06bcSAlagu Sankar if (blkcnt == 0) 4124a1a06bcSAlagu Sankar return 0; 4134a1a06bcSAlagu Sankar 4144a1a06bcSAlagu Sankar struct mmc *mmc = find_mmc_device(dev_num); 415272cc70bSAndy Fleming if (!mmc) 416272cc70bSAndy Fleming return 0; 417272cc70bSAndy Fleming 418b5b838f1SMarek Vasut if (CONFIG_IS_ENABLED(MMC_TINY)) 419b5b838f1SMarek Vasut err = mmc_switch_part(mmc, block_dev->hwpart); 420b5b838f1SMarek Vasut else 42169f45cd5SSimon Glass err = blk_dselect_hwpart(block_dev, block_dev->hwpart); 422b5b838f1SMarek Vasut 423873cc1d7SStephen Warren if (err < 0) 424873cc1d7SStephen Warren return 0; 425873cc1d7SStephen Warren 426c40fdca6SSimon Glass if ((start + blkcnt) > block_dev->lba) { 42756196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 428d8e3d420SJean-Jacques Hiblot pr_err("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", 429c40fdca6SSimon Glass start + blkcnt, block_dev->lba); 43056196826SPaul Burton #endif 431d2bf29e3SLei Wen return 0; 432d2bf29e3SLei Wen } 433272cc70bSAndy Fleming 43411692991SSimon Glass if (mmc_set_blocklen(mmc, mmc->read_bl_len)) { 435d4d64889SMasahiro Yamada pr_debug("%s: Failed to set blocklen\n", __func__); 436272cc70bSAndy Fleming return 0; 43711692991SSimon Glass } 438272cc70bSAndy Fleming 4394a1a06bcSAlagu Sankar do { 44093bfd616SPantelis Antoniou cur = (blocks_todo > mmc->cfg->b_max) ? 44193bfd616SPantelis Antoniou mmc->cfg->b_max : blocks_todo; 44211692991SSimon Glass if (mmc_read_blocks(mmc, dst, start, cur) != cur) { 443d4d64889SMasahiro Yamada pr_debug("%s: Failed to read blocks\n", __func__); 4444a1a06bcSAlagu Sankar return 0; 44511692991SSimon Glass } 4464a1a06bcSAlagu Sankar blocks_todo -= cur; 4474a1a06bcSAlagu Sankar start += cur; 4484a1a06bcSAlagu Sankar dst += cur * mmc->read_bl_len; 4494a1a06bcSAlagu Sankar } while (blocks_todo > 0); 450272cc70bSAndy Fleming 451272cc70bSAndy Fleming return blkcnt; 452272cc70bSAndy Fleming } 453272cc70bSAndy Fleming 454fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc) 455272cc70bSAndy Fleming { 456272cc70bSAndy Fleming struct mmc_cmd cmd; 457272cc70bSAndy Fleming int err; 458272cc70bSAndy Fleming 459272cc70bSAndy Fleming udelay(1000); 460272cc70bSAndy Fleming 461272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_GO_IDLE_STATE; 462272cc70bSAndy Fleming cmd.cmdarg = 0; 463272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_NONE; 464272cc70bSAndy Fleming 465272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 466272cc70bSAndy Fleming 467272cc70bSAndy Fleming if (err) 468272cc70bSAndy Fleming return err; 469272cc70bSAndy Fleming 470272cc70bSAndy Fleming udelay(2000); 471272cc70bSAndy Fleming 472272cc70bSAndy Fleming return 0; 473272cc70bSAndy Fleming } 474272cc70bSAndy Fleming 475f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 476c10b85d6SJean-Jacques Hiblot static int mmc_switch_voltage(struct mmc *mmc, int signal_voltage) 477c10b85d6SJean-Jacques Hiblot { 478c10b85d6SJean-Jacques Hiblot struct mmc_cmd cmd; 479c10b85d6SJean-Jacques Hiblot int err = 0; 480c10b85d6SJean-Jacques Hiblot 481c10b85d6SJean-Jacques Hiblot /* 482c10b85d6SJean-Jacques Hiblot * Send CMD11 only if the request is to switch the card to 483c10b85d6SJean-Jacques Hiblot * 1.8V signalling. 484c10b85d6SJean-Jacques Hiblot */ 485c10b85d6SJean-Jacques Hiblot if (signal_voltage == MMC_SIGNAL_VOLTAGE_330) 486c10b85d6SJean-Jacques Hiblot return mmc_set_signal_voltage(mmc, signal_voltage); 487c10b85d6SJean-Jacques Hiblot 488c10b85d6SJean-Jacques Hiblot cmd.cmdidx = SD_CMD_SWITCH_UHS18V; 489c10b85d6SJean-Jacques Hiblot cmd.cmdarg = 0; 490c10b85d6SJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 491c10b85d6SJean-Jacques Hiblot 492c10b85d6SJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 493c10b85d6SJean-Jacques Hiblot if (err) 494c10b85d6SJean-Jacques Hiblot return err; 495c10b85d6SJean-Jacques Hiblot 496c10b85d6SJean-Jacques Hiblot if (!mmc_host_is_spi(mmc) && (cmd.response[0] & MMC_STATUS_ERROR)) 497c10b85d6SJean-Jacques Hiblot return -EIO; 498c10b85d6SJean-Jacques Hiblot 499c10b85d6SJean-Jacques Hiblot /* 500c10b85d6SJean-Jacques Hiblot * The card should drive cmd and dat[0:3] low immediately 501c10b85d6SJean-Jacques Hiblot * after the response of cmd11, but wait 100 us to be sure 502c10b85d6SJean-Jacques Hiblot */ 503c10b85d6SJean-Jacques Hiblot err = mmc_wait_dat0(mmc, 0, 100); 504c10b85d6SJean-Jacques Hiblot if (err == -ENOSYS) 505c10b85d6SJean-Jacques Hiblot udelay(100); 506c10b85d6SJean-Jacques Hiblot else if (err) 507c10b85d6SJean-Jacques Hiblot return -ETIMEDOUT; 508c10b85d6SJean-Jacques Hiblot 509c10b85d6SJean-Jacques Hiblot /* 510c10b85d6SJean-Jacques Hiblot * During a signal voltage level switch, the clock must be gated 511c10b85d6SJean-Jacques Hiblot * for 5 ms according to the SD spec 512c10b85d6SJean-Jacques Hiblot */ 51365117182SJaehoon Chung mmc_set_clock(mmc, mmc->clock, MMC_CLK_DISABLE); 514c10b85d6SJean-Jacques Hiblot 515c10b85d6SJean-Jacques Hiblot err = mmc_set_signal_voltage(mmc, signal_voltage); 516c10b85d6SJean-Jacques Hiblot if (err) 517c10b85d6SJean-Jacques Hiblot return err; 518c10b85d6SJean-Jacques Hiblot 519c10b85d6SJean-Jacques Hiblot /* Keep clock gated for at least 10 ms, though spec only says 5 ms */ 520c10b85d6SJean-Jacques Hiblot mdelay(10); 52165117182SJaehoon Chung mmc_set_clock(mmc, mmc->clock, MMC_CLK_ENABLE); 522c10b85d6SJean-Jacques Hiblot 523c10b85d6SJean-Jacques Hiblot /* 524c10b85d6SJean-Jacques Hiblot * Failure to switch is indicated by the card holding 525c10b85d6SJean-Jacques Hiblot * dat[0:3] low. Wait for at least 1 ms according to spec 526c10b85d6SJean-Jacques Hiblot */ 527c10b85d6SJean-Jacques Hiblot err = mmc_wait_dat0(mmc, 1, 1000); 528c10b85d6SJean-Jacques Hiblot if (err == -ENOSYS) 529c10b85d6SJean-Jacques Hiblot udelay(1000); 530c10b85d6SJean-Jacques Hiblot else if (err) 531c10b85d6SJean-Jacques Hiblot return -ETIMEDOUT; 532c10b85d6SJean-Jacques Hiblot 533c10b85d6SJean-Jacques Hiblot return 0; 534c10b85d6SJean-Jacques Hiblot } 535f99c2efeSJean-Jacques Hiblot #endif 536c10b85d6SJean-Jacques Hiblot 537c10b85d6SJean-Jacques Hiblot static int sd_send_op_cond(struct mmc *mmc, bool uhs_en) 538272cc70bSAndy Fleming { 539272cc70bSAndy Fleming int timeout = 1000; 540272cc70bSAndy Fleming int err; 541272cc70bSAndy Fleming struct mmc_cmd cmd; 542272cc70bSAndy Fleming 5431677eef4SAndrew Gabbasov while (1) { 544272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 545272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 546272cc70bSAndy Fleming cmd.cmdarg = 0; 547272cc70bSAndy Fleming 548272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 549272cc70bSAndy Fleming 550272cc70bSAndy Fleming if (err) 551272cc70bSAndy Fleming return err; 552272cc70bSAndy Fleming 553272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_OP_COND; 554272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R3; 555250de12bSStefano Babic 556250de12bSStefano Babic /* 557250de12bSStefano Babic * Most cards do not answer if some reserved bits 558250de12bSStefano Babic * in the ocr are set. However, Some controller 559250de12bSStefano Babic * can set bit 7 (reserved for low voltages), but 560250de12bSStefano Babic * how to manage low voltages SD card is not yet 561250de12bSStefano Babic * specified. 562250de12bSStefano Babic */ 563d52ebf10SThomas Chou cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 : 56493bfd616SPantelis Antoniou (mmc->cfg->voltages & 0xff8000); 565272cc70bSAndy Fleming 566272cc70bSAndy Fleming if (mmc->version == SD_VERSION_2) 567272cc70bSAndy Fleming cmd.cmdarg |= OCR_HCS; 568272cc70bSAndy Fleming 569c10b85d6SJean-Jacques Hiblot if (uhs_en) 570c10b85d6SJean-Jacques Hiblot cmd.cmdarg |= OCR_S18R; 571c10b85d6SJean-Jacques Hiblot 572272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 573272cc70bSAndy Fleming 574272cc70bSAndy Fleming if (err) 575272cc70bSAndy Fleming return err; 576272cc70bSAndy Fleming 5771677eef4SAndrew Gabbasov if (cmd.response[0] & OCR_BUSY) 5781677eef4SAndrew Gabbasov break; 579272cc70bSAndy Fleming 5801677eef4SAndrew Gabbasov if (timeout-- <= 0) 581915ffa52SJaehoon Chung return -EOPNOTSUPP; 582272cc70bSAndy Fleming 5831677eef4SAndrew Gabbasov udelay(1000); 5841677eef4SAndrew Gabbasov } 5851677eef4SAndrew Gabbasov 586272cc70bSAndy Fleming if (mmc->version != SD_VERSION_2) 587272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 588272cc70bSAndy Fleming 589d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 590d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 591d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 592d52ebf10SThomas Chou cmd.cmdarg = 0; 593d52ebf10SThomas Chou 594d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 595d52ebf10SThomas Chou 596d52ebf10SThomas Chou if (err) 597d52ebf10SThomas Chou return err; 598d52ebf10SThomas Chou } 599d52ebf10SThomas Chou 600998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 601272cc70bSAndy Fleming 602f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 603c10b85d6SJean-Jacques Hiblot if (uhs_en && !(mmc_host_is_spi(mmc)) && (cmd.response[0] & 0x41000000) 604c10b85d6SJean-Jacques Hiblot == 0x41000000) { 605c10b85d6SJean-Jacques Hiblot err = mmc_switch_voltage(mmc, MMC_SIGNAL_VOLTAGE_180); 606c10b85d6SJean-Jacques Hiblot if (err) 607c10b85d6SJean-Jacques Hiblot return err; 608c10b85d6SJean-Jacques Hiblot } 609f99c2efeSJean-Jacques Hiblot #endif 610c10b85d6SJean-Jacques Hiblot 611272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 612272cc70bSAndy Fleming mmc->rca = 0; 613272cc70bSAndy Fleming 614272cc70bSAndy Fleming return 0; 615272cc70bSAndy Fleming } 616272cc70bSAndy Fleming 6175289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg) 618272cc70bSAndy Fleming { 6195289b535SAndrew Gabbasov struct mmc_cmd cmd; 620272cc70bSAndy Fleming int err; 621272cc70bSAndy Fleming 6225289b535SAndrew Gabbasov cmd.cmdidx = MMC_CMD_SEND_OP_COND; 6235289b535SAndrew Gabbasov cmd.resp_type = MMC_RSP_R3; 6245289b535SAndrew Gabbasov cmd.cmdarg = 0; 6255a20397bSRob Herring if (use_arg && !mmc_host_is_spi(mmc)) 6265a20397bSRob Herring cmd.cmdarg = OCR_HCS | 62793bfd616SPantelis Antoniou (mmc->cfg->voltages & 628a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_VOLTAGE_MASK)) | 629a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_ACCESS_MODE); 630e9550449SChe-Liang Chiou 6315289b535SAndrew Gabbasov err = mmc_send_cmd(mmc, &cmd, NULL); 632e9550449SChe-Liang Chiou if (err) 633e9550449SChe-Liang Chiou return err; 6345289b535SAndrew Gabbasov mmc->ocr = cmd.response[0]; 635e9550449SChe-Liang Chiou return 0; 636e9550449SChe-Liang Chiou } 637e9550449SChe-Liang Chiou 638750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc) 639e9550449SChe-Liang Chiou { 640e9550449SChe-Liang Chiou int err, i; 641e9550449SChe-Liang Chiou 642272cc70bSAndy Fleming /* Some cards seem to need this */ 643272cc70bSAndy Fleming mmc_go_idle(mmc); 644272cc70bSAndy Fleming 64531cacbabSRaffaele Recalcati /* Asking to the card its capabilities */ 646e9550449SChe-Liang Chiou for (i = 0; i < 2; i++) { 6475289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, i != 0); 64831cacbabSRaffaele Recalcati if (err) 64931cacbabSRaffaele Recalcati return err; 65031cacbabSRaffaele Recalcati 651e9550449SChe-Liang Chiou /* exit if not busy (flag seems to be inverted) */ 652a626c8d4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 653bd47c135SAndrew Gabbasov break; 654e9550449SChe-Liang Chiou } 655bd47c135SAndrew Gabbasov mmc->op_cond_pending = 1; 656bd47c135SAndrew Gabbasov return 0; 657e9550449SChe-Liang Chiou } 65831cacbabSRaffaele Recalcati 659750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc) 660e9550449SChe-Liang Chiou { 661e9550449SChe-Liang Chiou struct mmc_cmd cmd; 662e9550449SChe-Liang Chiou int timeout = 1000; 66336332b6eSVipul Kumar ulong start; 664e9550449SChe-Liang Chiou int err; 665e9550449SChe-Liang Chiou 666e9550449SChe-Liang Chiou mmc->op_cond_pending = 0; 667cc17c01fSAndrew Gabbasov if (!(mmc->ocr & OCR_BUSY)) { 668d188b113SYangbo Lu /* Some cards seem to need this */ 669d188b113SYangbo Lu mmc_go_idle(mmc); 670d188b113SYangbo Lu 671e9550449SChe-Liang Chiou start = get_timer(0); 6721677eef4SAndrew Gabbasov while (1) { 6735289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, 1); 674272cc70bSAndy Fleming if (err) 675272cc70bSAndy Fleming return err; 6761677eef4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 6771677eef4SAndrew Gabbasov break; 678e9550449SChe-Liang Chiou if (get_timer(start) > timeout) 679915ffa52SJaehoon Chung return -EOPNOTSUPP; 680e9550449SChe-Liang Chiou udelay(100); 6811677eef4SAndrew Gabbasov } 682cc17c01fSAndrew Gabbasov } 683272cc70bSAndy Fleming 684d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 685d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 686d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 687d52ebf10SThomas Chou cmd.cmdarg = 0; 688d52ebf10SThomas Chou 689d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 690d52ebf10SThomas Chou 691d52ebf10SThomas Chou if (err) 692d52ebf10SThomas Chou return err; 693a626c8d4SAndrew Gabbasov 694a626c8d4SAndrew Gabbasov mmc->ocr = cmd.response[0]; 695d52ebf10SThomas Chou } 696d52ebf10SThomas Chou 697272cc70bSAndy Fleming mmc->version = MMC_VERSION_UNKNOWN; 698272cc70bSAndy Fleming 699272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 700def816a2SStephen Warren mmc->rca = 1; 701272cc70bSAndy Fleming 702272cc70bSAndy Fleming return 0; 703272cc70bSAndy Fleming } 704272cc70bSAndy Fleming 705272cc70bSAndy Fleming 706fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) 707272cc70bSAndy Fleming { 708272cc70bSAndy Fleming struct mmc_cmd cmd; 709272cc70bSAndy Fleming struct mmc_data data; 710272cc70bSAndy Fleming int err; 711272cc70bSAndy Fleming 712272cc70bSAndy Fleming /* Get the Card Status Register */ 713272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_EXT_CSD; 714272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 715272cc70bSAndy Fleming cmd.cmdarg = 0; 716272cc70bSAndy Fleming 717cdfd1ac6SYoshihiro Shimoda data.dest = (char *)ext_csd; 718272cc70bSAndy Fleming data.blocks = 1; 7198bfa195eSSimon Glass data.blocksize = MMC_MAX_BLOCK_LEN; 720272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 721272cc70bSAndy Fleming 722272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 723272cc70bSAndy Fleming 724272cc70bSAndy Fleming return err; 725272cc70bSAndy Fleming } 726272cc70bSAndy Fleming 727c40704f4SSimon Glass int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) 728272cc70bSAndy Fleming { 729272cc70bSAndy Fleming struct mmc_cmd cmd; 7305d4fc8d9SRaffaele Recalcati int timeout = 1000; 731a9003dc6SMaxime Ripard int retries = 3; 7325d4fc8d9SRaffaele Recalcati int ret; 733272cc70bSAndy Fleming 734272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SWITCH; 735272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 736272cc70bSAndy Fleming cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 737272cc70bSAndy Fleming (index << 16) | 738272cc70bSAndy Fleming (value << 8); 739272cc70bSAndy Fleming 740a9003dc6SMaxime Ripard while (retries > 0) { 7415d4fc8d9SRaffaele Recalcati ret = mmc_send_cmd(mmc, &cmd, NULL); 7425d4fc8d9SRaffaele Recalcati 7435d4fc8d9SRaffaele Recalcati /* Waiting for the ready status */ 744a9003dc6SMaxime Ripard if (!ret) { 74593ad0d18SJan Kloetzke ret = mmc_send_status(mmc, timeout); 746a9003dc6SMaxime Ripard return ret; 747a9003dc6SMaxime Ripard } 748a9003dc6SMaxime Ripard 749a9003dc6SMaxime Ripard retries--; 750a9003dc6SMaxime Ripard } 7515d4fc8d9SRaffaele Recalcati 7525d4fc8d9SRaffaele Recalcati return ret; 7535d4fc8d9SRaffaele Recalcati 754272cc70bSAndy Fleming } 755272cc70bSAndy Fleming 75662d77ceaSMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY) 757*b9a2a0e2SMarek Vasut static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode, 758*b9a2a0e2SMarek Vasut bool hsdowngrade) 759272cc70bSAndy Fleming { 760272cc70bSAndy Fleming int err; 7613862b854SJean-Jacques Hiblot int speed_bits; 7623862b854SJean-Jacques Hiblot 7633862b854SJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 7643862b854SJean-Jacques Hiblot 7653862b854SJean-Jacques Hiblot switch (mode) { 7663862b854SJean-Jacques Hiblot case MMC_HS: 7673862b854SJean-Jacques Hiblot case MMC_HS_52: 7683862b854SJean-Jacques Hiblot case MMC_DDR_52: 7693862b854SJean-Jacques Hiblot speed_bits = EXT_CSD_TIMING_HS; 770634d4849SKishon Vijay Abraham I break; 771baef2070SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) 772634d4849SKishon Vijay Abraham I case MMC_HS_200: 773634d4849SKishon Vijay Abraham I speed_bits = EXT_CSD_TIMING_HS200; 774634d4849SKishon Vijay Abraham I break; 775baef2070SJean-Jacques Hiblot #endif 7763dd2626fSPeng Fan #if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) 7773dd2626fSPeng Fan case MMC_HS_400: 7783dd2626fSPeng Fan speed_bits = EXT_CSD_TIMING_HS400; 7793dd2626fSPeng Fan break; 7803dd2626fSPeng Fan #endif 7813862b854SJean-Jacques Hiblot case MMC_LEGACY: 7823862b854SJean-Jacques Hiblot speed_bits = EXT_CSD_TIMING_LEGACY; 7833862b854SJean-Jacques Hiblot break; 7843862b854SJean-Jacques Hiblot default: 7853862b854SJean-Jacques Hiblot return -EINVAL; 7863862b854SJean-Jacques Hiblot } 7873862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 7883862b854SJean-Jacques Hiblot speed_bits); 7893862b854SJean-Jacques Hiblot if (err) 7903862b854SJean-Jacques Hiblot return err; 7913862b854SJean-Jacques Hiblot 792*b9a2a0e2SMarek Vasut #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \ 793*b9a2a0e2SMarek Vasut CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) 794*b9a2a0e2SMarek Vasut /* 795*b9a2a0e2SMarek Vasut * In case the eMMC is in HS200/HS400 mode and we are downgrading 796*b9a2a0e2SMarek Vasut * to HS mode, the card clock are still running much faster than 797*b9a2a0e2SMarek Vasut * the supported HS mode clock, so we can not reliably read out 798*b9a2a0e2SMarek Vasut * Extended CSD. Reconfigure the controller to run at HS mode. 799*b9a2a0e2SMarek Vasut */ 800*b9a2a0e2SMarek Vasut if (hsdowngrade) { 801*b9a2a0e2SMarek Vasut mmc_select_mode(mmc, MMC_HS); 802*b9a2a0e2SMarek Vasut mmc_set_clock(mmc, mmc_mode2freq(mmc, MMC_HS), false); 803*b9a2a0e2SMarek Vasut } 804*b9a2a0e2SMarek Vasut #endif 805*b9a2a0e2SMarek Vasut 8063862b854SJean-Jacques Hiblot if ((mode == MMC_HS) || (mode == MMC_HS_52)) { 8073862b854SJean-Jacques Hiblot /* Now check to see that it worked */ 8083862b854SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, test_csd); 8093862b854SJean-Jacques Hiblot if (err) 8103862b854SJean-Jacques Hiblot return err; 8113862b854SJean-Jacques Hiblot 8123862b854SJean-Jacques Hiblot /* No high-speed support */ 8133862b854SJean-Jacques Hiblot if (!test_csd[EXT_CSD_HS_TIMING]) 8143862b854SJean-Jacques Hiblot return -ENOTSUPP; 8153862b854SJean-Jacques Hiblot } 8163862b854SJean-Jacques Hiblot 8173862b854SJean-Jacques Hiblot return 0; 8183862b854SJean-Jacques Hiblot } 8193862b854SJean-Jacques Hiblot 8203862b854SJean-Jacques Hiblot static int mmc_get_capabilities(struct mmc *mmc) 8213862b854SJean-Jacques Hiblot { 8223862b854SJean-Jacques Hiblot u8 *ext_csd = mmc->ext_csd; 8233862b854SJean-Jacques Hiblot char cardtype; 824272cc70bSAndy Fleming 82500e446faSJean-Jacques Hiblot mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(MMC_LEGACY); 826272cc70bSAndy Fleming 827d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 828d52ebf10SThomas Chou return 0; 829d52ebf10SThomas Chou 830272cc70bSAndy Fleming /* Only version 4 supports high-speed */ 831272cc70bSAndy Fleming if (mmc->version < MMC_VERSION_4) 832272cc70bSAndy Fleming return 0; 833272cc70bSAndy Fleming 8343862b854SJean-Jacques Hiblot if (!ext_csd) { 835d8e3d420SJean-Jacques Hiblot pr_err("No ext_csd found!\n"); /* this should enver happen */ 8363862b854SJean-Jacques Hiblot return -ENOTSUPP; 8373862b854SJean-Jacques Hiblot } 8383862b854SJean-Jacques Hiblot 839fc5b32fbSAndrew Gabbasov mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; 840fc5b32fbSAndrew Gabbasov 8413dd2626fSPeng Fan cardtype = ext_csd[EXT_CSD_CARD_TYPE]; 842bc1e3272SJean-Jacques Hiblot mmc->cardtype = cardtype; 843272cc70bSAndy Fleming 844baef2070SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) 845634d4849SKishon Vijay Abraham I if (cardtype & (EXT_CSD_CARD_TYPE_HS200_1_2V | 846634d4849SKishon Vijay Abraham I EXT_CSD_CARD_TYPE_HS200_1_8V)) { 847634d4849SKishon Vijay Abraham I mmc->card_caps |= MMC_MODE_HS200; 848634d4849SKishon Vijay Abraham I } 849baef2070SJean-Jacques Hiblot #endif 8503dd2626fSPeng Fan #if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) 8513dd2626fSPeng Fan if (cardtype & (EXT_CSD_CARD_TYPE_HS400_1_2V | 8523dd2626fSPeng Fan EXT_CSD_CARD_TYPE_HS400_1_8V)) { 8533dd2626fSPeng Fan mmc->card_caps |= MMC_MODE_HS400; 8543dd2626fSPeng Fan } 8553dd2626fSPeng Fan #endif 856d22e3d46SJaehoon Chung if (cardtype & EXT_CSD_CARD_TYPE_52) { 8573862b854SJean-Jacques Hiblot if (cardtype & EXT_CSD_CARD_TYPE_DDR_52) 858d22e3d46SJaehoon Chung mmc->card_caps |= MMC_MODE_DDR_52MHz; 8593862b854SJean-Jacques Hiblot mmc->card_caps |= MMC_MODE_HS_52MHz; 860d22e3d46SJaehoon Chung } 8613862b854SJean-Jacques Hiblot if (cardtype & EXT_CSD_CARD_TYPE_26) 8623862b854SJean-Jacques Hiblot mmc->card_caps |= MMC_MODE_HS; 863272cc70bSAndy Fleming 864272cc70bSAndy Fleming return 0; 865272cc70bSAndy Fleming } 86662d77ceaSMarek Vasut #endif 867272cc70bSAndy Fleming 868f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num) 869f866a46dSStephen Warren { 870f866a46dSStephen Warren switch (part_num) { 871f866a46dSStephen Warren case 0: 872f866a46dSStephen Warren mmc->capacity = mmc->capacity_user; 873f866a46dSStephen Warren break; 874f866a46dSStephen Warren case 1: 875f866a46dSStephen Warren case 2: 876f866a46dSStephen Warren mmc->capacity = mmc->capacity_boot; 877f866a46dSStephen Warren break; 878f866a46dSStephen Warren case 3: 879f866a46dSStephen Warren mmc->capacity = mmc->capacity_rpmb; 880f866a46dSStephen Warren break; 881f866a46dSStephen Warren case 4: 882f866a46dSStephen Warren case 5: 883f866a46dSStephen Warren case 6: 884f866a46dSStephen Warren case 7: 885f866a46dSStephen Warren mmc->capacity = mmc->capacity_gp[part_num - 4]; 886f866a46dSStephen Warren break; 887f866a46dSStephen Warren default: 888f866a46dSStephen Warren return -1; 889f866a46dSStephen Warren } 890f866a46dSStephen Warren 891c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len); 892f866a46dSStephen Warren 893f866a46dSStephen Warren return 0; 894f866a46dSStephen Warren } 895f866a46dSStephen Warren 896f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) 89701298da3SJean-Jacques Hiblot static int mmc_boot_part_access_chk(struct mmc *mmc, unsigned int part_num) 89801298da3SJean-Jacques Hiblot { 89901298da3SJean-Jacques Hiblot int forbidden = 0; 90001298da3SJean-Jacques Hiblot bool change = false; 90101298da3SJean-Jacques Hiblot 90201298da3SJean-Jacques Hiblot if (part_num & PART_ACCESS_MASK) 90301298da3SJean-Jacques Hiblot forbidden = MMC_CAP(MMC_HS_200); 90401298da3SJean-Jacques Hiblot 90501298da3SJean-Jacques Hiblot if (MMC_CAP(mmc->selected_mode) & forbidden) { 906d4d64889SMasahiro Yamada pr_debug("selected mode (%s) is forbidden for part %d\n", 90701298da3SJean-Jacques Hiblot mmc_mode_name(mmc->selected_mode), part_num); 90801298da3SJean-Jacques Hiblot change = true; 90901298da3SJean-Jacques Hiblot } else if (mmc->selected_mode != mmc->best_mode) { 910d4d64889SMasahiro Yamada pr_debug("selected mode is not optimal\n"); 91101298da3SJean-Jacques Hiblot change = true; 91201298da3SJean-Jacques Hiblot } 91301298da3SJean-Jacques Hiblot 91401298da3SJean-Jacques Hiblot if (change) 91501298da3SJean-Jacques Hiblot return mmc_select_mode_and_width(mmc, 91601298da3SJean-Jacques Hiblot mmc->card_caps & ~forbidden); 91701298da3SJean-Jacques Hiblot 91801298da3SJean-Jacques Hiblot return 0; 91901298da3SJean-Jacques Hiblot } 920f99c2efeSJean-Jacques Hiblot #else 921f99c2efeSJean-Jacques Hiblot static inline int mmc_boot_part_access_chk(struct mmc *mmc, 922f99c2efeSJean-Jacques Hiblot unsigned int part_num) 923f99c2efeSJean-Jacques Hiblot { 924f99c2efeSJean-Jacques Hiblot return 0; 925f99c2efeSJean-Jacques Hiblot } 926f99c2efeSJean-Jacques Hiblot #endif 92701298da3SJean-Jacques Hiblot 9287dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num) 929bc897b1dSLei Wen { 930f866a46dSStephen Warren int ret; 931bc897b1dSLei Wen 93201298da3SJean-Jacques Hiblot ret = mmc_boot_part_access_chk(mmc, part_num); 93301298da3SJean-Jacques Hiblot if (ret) 93401298da3SJean-Jacques Hiblot return ret; 93501298da3SJean-Jacques Hiblot 936f866a46dSStephen Warren ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 937bc897b1dSLei Wen (mmc->part_config & ~PART_ACCESS_MASK) 938bc897b1dSLei Wen | (part_num & PART_ACCESS_MASK)); 939f866a46dSStephen Warren 9406dc93e70SPeter Bigot /* 9416dc93e70SPeter Bigot * Set the capacity if the switch succeeded or was intended 9426dc93e70SPeter Bigot * to return to representing the raw device. 9436dc93e70SPeter Bigot */ 944873cc1d7SStephen Warren if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) { 9456dc93e70SPeter Bigot ret = mmc_set_capacity(mmc, part_num); 946fdbb139fSSimon Glass mmc_get_blk_desc(mmc)->hwpart = part_num; 947873cc1d7SStephen Warren } 9486dc93e70SPeter Bigot 9496dc93e70SPeter Bigot return ret; 950bc897b1dSLei Wen } 951bc897b1dSLei Wen 952cf17789eSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING) 953ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc, 954ac9da0e0SDiego Santa Cruz const struct mmc_hwpart_conf *conf, 955ac9da0e0SDiego Santa Cruz enum mmc_hwpart_conf_mode mode) 956ac9da0e0SDiego Santa Cruz { 957ac9da0e0SDiego Santa Cruz u8 part_attrs = 0; 958ac9da0e0SDiego Santa Cruz u32 enh_size_mult; 959ac9da0e0SDiego Santa Cruz u32 enh_start_addr; 960ac9da0e0SDiego Santa Cruz u32 gp_size_mult[4]; 961ac9da0e0SDiego Santa Cruz u32 max_enh_size_mult; 962ac9da0e0SDiego Santa Cruz u32 tot_enh_size_mult = 0; 9638dda5b0eSDiego Santa Cruz u8 wr_rel_set; 964ac9da0e0SDiego Santa Cruz int i, pidx, err; 965ac9da0e0SDiego Santa Cruz ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 966ac9da0e0SDiego Santa Cruz 967ac9da0e0SDiego Santa Cruz if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE) 968ac9da0e0SDiego Santa Cruz return -EINVAL; 969ac9da0e0SDiego Santa Cruz 970ac9da0e0SDiego Santa Cruz if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) { 971d8e3d420SJean-Jacques Hiblot pr_err("eMMC >= 4.4 required for enhanced user data area\n"); 972ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 973ac9da0e0SDiego Santa Cruz } 974ac9da0e0SDiego Santa Cruz 975ac9da0e0SDiego Santa Cruz if (!(mmc->part_support & PART_SUPPORT)) { 976d8e3d420SJean-Jacques Hiblot pr_err("Card does not support partitioning\n"); 977ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 978ac9da0e0SDiego Santa Cruz } 979ac9da0e0SDiego Santa Cruz 980ac9da0e0SDiego Santa Cruz if (!mmc->hc_wp_grp_size) { 981d8e3d420SJean-Jacques Hiblot pr_err("Card does not define HC WP group size\n"); 982ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 983ac9da0e0SDiego Santa Cruz } 984ac9da0e0SDiego Santa Cruz 985ac9da0e0SDiego Santa Cruz /* check partition alignment and total enhanced size */ 986ac9da0e0SDiego Santa Cruz if (conf->user.enh_size) { 987ac9da0e0SDiego Santa Cruz if (conf->user.enh_size % mmc->hc_wp_grp_size || 988ac9da0e0SDiego Santa Cruz conf->user.enh_start % mmc->hc_wp_grp_size) { 989d8e3d420SJean-Jacques Hiblot pr_err("User data enhanced area not HC WP group " 990ac9da0e0SDiego Santa Cruz "size aligned\n"); 991ac9da0e0SDiego Santa Cruz return -EINVAL; 992ac9da0e0SDiego Santa Cruz } 993ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_USR; 994ac9da0e0SDiego Santa Cruz enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size; 995ac9da0e0SDiego Santa Cruz if (mmc->high_capacity) { 996ac9da0e0SDiego Santa Cruz enh_start_addr = conf->user.enh_start; 997ac9da0e0SDiego Santa Cruz } else { 998ac9da0e0SDiego Santa Cruz enh_start_addr = (conf->user.enh_start << 9); 999ac9da0e0SDiego Santa Cruz } 1000ac9da0e0SDiego Santa Cruz } else { 1001ac9da0e0SDiego Santa Cruz enh_size_mult = 0; 1002ac9da0e0SDiego Santa Cruz enh_start_addr = 0; 1003ac9da0e0SDiego Santa Cruz } 1004ac9da0e0SDiego Santa Cruz tot_enh_size_mult += enh_size_mult; 1005ac9da0e0SDiego Santa Cruz 1006ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 1007ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) { 1008d8e3d420SJean-Jacques Hiblot pr_err("GP%i partition not HC WP group size " 1009ac9da0e0SDiego Santa Cruz "aligned\n", pidx+1); 1010ac9da0e0SDiego Santa Cruz return -EINVAL; 1011ac9da0e0SDiego Santa Cruz } 1012ac9da0e0SDiego Santa Cruz gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size; 1013ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) { 1014ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_GP(pidx); 1015ac9da0e0SDiego Santa Cruz tot_enh_size_mult += gp_size_mult[pidx]; 1016ac9da0e0SDiego Santa Cruz } 1017ac9da0e0SDiego Santa Cruz } 1018ac9da0e0SDiego Santa Cruz 1019ac9da0e0SDiego Santa Cruz if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) { 1020d8e3d420SJean-Jacques Hiblot pr_err("Card does not support enhanced attribute\n"); 1021ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1022ac9da0e0SDiego Santa Cruz } 1023ac9da0e0SDiego Santa Cruz 1024ac9da0e0SDiego Santa Cruz err = mmc_send_ext_csd(mmc, ext_csd); 1025ac9da0e0SDiego Santa Cruz if (err) 1026ac9da0e0SDiego Santa Cruz return err; 1027ac9da0e0SDiego Santa Cruz 1028ac9da0e0SDiego Santa Cruz max_enh_size_mult = 1029ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) + 1030ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) + 1031ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]; 1032ac9da0e0SDiego Santa Cruz if (tot_enh_size_mult > max_enh_size_mult) { 1033d8e3d420SJean-Jacques Hiblot pr_err("Total enhanced size exceeds maximum (%u > %u)\n", 1034ac9da0e0SDiego Santa Cruz tot_enh_size_mult, max_enh_size_mult); 1035ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1036ac9da0e0SDiego Santa Cruz } 1037ac9da0e0SDiego Santa Cruz 10388dda5b0eSDiego Santa Cruz /* The default value of EXT_CSD_WR_REL_SET is device 10398dda5b0eSDiego Santa Cruz * dependent, the values can only be changed if the 10408dda5b0eSDiego Santa Cruz * EXT_CSD_HS_CTRL_REL bit is set. The values can be 10418dda5b0eSDiego Santa Cruz * changed only once and before partitioning is completed. */ 10428dda5b0eSDiego Santa Cruz wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 10438dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_change) { 10448dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_set) 10458dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_USR; 10468dda5b0eSDiego Santa Cruz else 10478dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR; 10488dda5b0eSDiego Santa Cruz } 10498dda5b0eSDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 10508dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_change) { 10518dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_set) 10528dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx); 10538dda5b0eSDiego Santa Cruz else 10548dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx); 10558dda5b0eSDiego Santa Cruz } 10568dda5b0eSDiego Santa Cruz } 10578dda5b0eSDiego Santa Cruz 10588dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] && 10598dda5b0eSDiego Santa Cruz !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) { 10608dda5b0eSDiego Santa Cruz puts("Card does not support host controlled partition write " 10618dda5b0eSDiego Santa Cruz "reliability settings\n"); 10628dda5b0eSDiego Santa Cruz return -EMEDIUMTYPE; 10638dda5b0eSDiego Santa Cruz } 10648dda5b0eSDiego Santa Cruz 1065ac9da0e0SDiego Santa Cruz if (ext_csd[EXT_CSD_PARTITION_SETTING] & 1066ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED) { 1067d8e3d420SJean-Jacques Hiblot pr_err("Card already partitioned\n"); 1068ac9da0e0SDiego Santa Cruz return -EPERM; 1069ac9da0e0SDiego Santa Cruz } 1070ac9da0e0SDiego Santa Cruz 1071ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_CHECK) 1072ac9da0e0SDiego Santa Cruz return 0; 1073ac9da0e0SDiego Santa Cruz 1074ac9da0e0SDiego Santa Cruz /* Partitioning requires high-capacity size definitions */ 1075ac9da0e0SDiego Santa Cruz if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) { 1076ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1077ac9da0e0SDiego Santa Cruz EXT_CSD_ERASE_GROUP_DEF, 1); 1078ac9da0e0SDiego Santa Cruz 1079ac9da0e0SDiego Santa Cruz if (err) 1080ac9da0e0SDiego Santa Cruz return err; 1081ac9da0e0SDiego Santa Cruz 1082ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 1083ac9da0e0SDiego Santa Cruz 1084ac9da0e0SDiego Santa Cruz /* update erase group size to be high-capacity */ 1085ac9da0e0SDiego Santa Cruz mmc->erase_grp_size = 1086ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 1087ac9da0e0SDiego Santa Cruz 1088ac9da0e0SDiego Santa Cruz } 1089ac9da0e0SDiego Santa Cruz 1090ac9da0e0SDiego Santa Cruz /* all OK, write the configuration */ 1091ac9da0e0SDiego Santa Cruz for (i = 0; i < 4; i++) { 1092ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1093ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_START_ADDR+i, 1094ac9da0e0SDiego Santa Cruz (enh_start_addr >> (i*8)) & 0xFF); 1095ac9da0e0SDiego Santa Cruz if (err) 1096ac9da0e0SDiego Santa Cruz return err; 1097ac9da0e0SDiego Santa Cruz } 1098ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 1099ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1100ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_SIZE_MULT+i, 1101ac9da0e0SDiego Santa Cruz (enh_size_mult >> (i*8)) & 0xFF); 1102ac9da0e0SDiego Santa Cruz if (err) 1103ac9da0e0SDiego Santa Cruz return err; 1104ac9da0e0SDiego Santa Cruz } 1105ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 1106ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 1107ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1108ac9da0e0SDiego Santa Cruz EXT_CSD_GP_SIZE_MULT+pidx*3+i, 1109ac9da0e0SDiego Santa Cruz (gp_size_mult[pidx] >> (i*8)) & 0xFF); 1110ac9da0e0SDiego Santa Cruz if (err) 1111ac9da0e0SDiego Santa Cruz return err; 1112ac9da0e0SDiego Santa Cruz } 1113ac9da0e0SDiego Santa Cruz } 1114ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1115ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs); 1116ac9da0e0SDiego Santa Cruz if (err) 1117ac9da0e0SDiego Santa Cruz return err; 1118ac9da0e0SDiego Santa Cruz 1119ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_SET) 1120ac9da0e0SDiego Santa Cruz return 0; 1121ac9da0e0SDiego Santa Cruz 11228dda5b0eSDiego Santa Cruz /* The WR_REL_SET is a write-once register but shall be 11238dda5b0eSDiego Santa Cruz * written before setting PART_SETTING_COMPLETED. As it is 11248dda5b0eSDiego Santa Cruz * write-once we can only write it when completing the 11258dda5b0eSDiego Santa Cruz * partitioning. */ 11268dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) { 11278dda5b0eSDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 11288dda5b0eSDiego Santa Cruz EXT_CSD_WR_REL_SET, wr_rel_set); 11298dda5b0eSDiego Santa Cruz if (err) 11308dda5b0eSDiego Santa Cruz return err; 11318dda5b0eSDiego Santa Cruz } 11328dda5b0eSDiego Santa Cruz 1133ac9da0e0SDiego Santa Cruz /* Setting PART_SETTING_COMPLETED confirms the partition 1134ac9da0e0SDiego Santa Cruz * configuration but it only becomes effective after power 1135ac9da0e0SDiego Santa Cruz * cycle, so we do not adjust the partition related settings 1136ac9da0e0SDiego Santa Cruz * in the mmc struct. */ 1137ac9da0e0SDiego Santa Cruz 1138ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1139ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING, 1140ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 1141ac9da0e0SDiego Santa Cruz if (err) 1142ac9da0e0SDiego Santa Cruz return err; 1143ac9da0e0SDiego Santa Cruz 1144ac9da0e0SDiego Santa Cruz return 0; 1145ac9da0e0SDiego Santa Cruz } 1146cf17789eSJean-Jacques Hiblot #endif 1147ac9da0e0SDiego Santa Cruz 1148e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 114948972d90SThierry Reding int mmc_getcd(struct mmc *mmc) 115048972d90SThierry Reding { 115148972d90SThierry Reding int cd; 115248972d90SThierry Reding 115348972d90SThierry Reding cd = board_mmc_getcd(mmc); 115448972d90SThierry Reding 1155d4e1da4eSPeter Korsgaard if (cd < 0) { 115693bfd616SPantelis Antoniou if (mmc->cfg->ops->getcd) 115793bfd616SPantelis Antoniou cd = mmc->cfg->ops->getcd(mmc); 1158d4e1da4eSPeter Korsgaard else 1159d4e1da4eSPeter Korsgaard cd = 1; 1160d4e1da4eSPeter Korsgaard } 116148972d90SThierry Reding 116248972d90SThierry Reding return cd; 116348972d90SThierry Reding } 11648ca51e51SSimon Glass #endif 116548972d90SThierry Reding 116662d77ceaSMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY) 1167fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) 1168272cc70bSAndy Fleming { 1169272cc70bSAndy Fleming struct mmc_cmd cmd; 1170272cc70bSAndy Fleming struct mmc_data data; 1171272cc70bSAndy Fleming 1172272cc70bSAndy Fleming /* Switch the frequency */ 1173272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC; 1174272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1175272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff; 1176272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4)); 1177272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4); 1178272cc70bSAndy Fleming 1179272cc70bSAndy Fleming data.dest = (char *)resp; 1180272cc70bSAndy Fleming data.blocksize = 64; 1181272cc70bSAndy Fleming data.blocks = 1; 1182272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1183272cc70bSAndy Fleming 1184272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 1185272cc70bSAndy Fleming } 1186272cc70bSAndy Fleming 1187d0c221feSJean-Jacques Hiblot static int sd_get_capabilities(struct mmc *mmc) 1188272cc70bSAndy Fleming { 1189272cc70bSAndy Fleming int err; 1190272cc70bSAndy Fleming struct mmc_cmd cmd; 119118e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2); 119218e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16); 1193272cc70bSAndy Fleming struct mmc_data data; 1194272cc70bSAndy Fleming int timeout; 1195f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1196c10b85d6SJean-Jacques Hiblot u32 sd3_bus_mode; 1197f99c2efeSJean-Jacques Hiblot #endif 1198272cc70bSAndy Fleming 119900e446faSJean-Jacques Hiblot mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(SD_LEGACY); 1200272cc70bSAndy Fleming 1201d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 1202d52ebf10SThomas Chou return 0; 1203d52ebf10SThomas Chou 1204272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */ 1205272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 1206272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1207272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1208272cc70bSAndy Fleming 1209272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1210272cc70bSAndy Fleming 1211272cc70bSAndy Fleming if (err) 1212272cc70bSAndy Fleming return err; 1213272cc70bSAndy Fleming 1214272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR; 1215272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1216272cc70bSAndy Fleming cmd.cmdarg = 0; 1217272cc70bSAndy Fleming 1218272cc70bSAndy Fleming timeout = 3; 1219272cc70bSAndy Fleming 1220272cc70bSAndy Fleming retry_scr: 1221f781dd38SAnton staaf data.dest = (char *)scr; 1222272cc70bSAndy Fleming data.blocksize = 8; 1223272cc70bSAndy Fleming data.blocks = 1; 1224272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1225272cc70bSAndy Fleming 1226272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 1227272cc70bSAndy Fleming 1228272cc70bSAndy Fleming if (err) { 1229272cc70bSAndy Fleming if (timeout--) 1230272cc70bSAndy Fleming goto retry_scr; 1231272cc70bSAndy Fleming 1232272cc70bSAndy Fleming return err; 1233272cc70bSAndy Fleming } 1234272cc70bSAndy Fleming 12354e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]); 12364e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]); 1237272cc70bSAndy Fleming 1238272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) { 1239272cc70bSAndy Fleming case 0: 1240272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1241272cc70bSAndy Fleming break; 1242272cc70bSAndy Fleming case 1: 1243272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10; 1244272cc70bSAndy Fleming break; 1245272cc70bSAndy Fleming case 2: 1246272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 12471741c64dSJaehoon Chung if ((mmc->scr[0] >> 15) & 0x1) 12481741c64dSJaehoon Chung mmc->version = SD_VERSION_3; 1249272cc70bSAndy Fleming break; 1250272cc70bSAndy Fleming default: 1251272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1252272cc70bSAndy Fleming break; 1253272cc70bSAndy Fleming } 1254272cc70bSAndy Fleming 1255b44c7083SAlagu Sankar if (mmc->scr[0] & SD_DATA_4BIT) 1256b44c7083SAlagu Sankar mmc->card_caps |= MMC_MODE_4BIT; 1257b44c7083SAlagu Sankar 1258272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */ 1259272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0) 1260272cc70bSAndy Fleming return 0; 1261272cc70bSAndy Fleming 1262272cc70bSAndy Fleming timeout = 4; 1263272cc70bSAndy Fleming while (timeout--) { 1264272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, 1265f781dd38SAnton staaf (u8 *)switch_status); 1266272cc70bSAndy Fleming 1267272cc70bSAndy Fleming if (err) 1268272cc70bSAndy Fleming return err; 1269272cc70bSAndy Fleming 1270272cc70bSAndy Fleming /* The high-speed function is busy. Try again */ 12714e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) 1272272cc70bSAndy Fleming break; 1273272cc70bSAndy Fleming } 1274272cc70bSAndy Fleming 1275272cc70bSAndy Fleming /* If high-speed isn't supported, we return */ 1276d0c221feSJean-Jacques Hiblot if (__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED) 1277d0c221feSJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(SD_HS); 1278272cc70bSAndy Fleming 1279f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1280c10b85d6SJean-Jacques Hiblot /* Version before 3.0 don't support UHS modes */ 1281c10b85d6SJean-Jacques Hiblot if (mmc->version < SD_VERSION_3) 1282c10b85d6SJean-Jacques Hiblot return 0; 1283c10b85d6SJean-Jacques Hiblot 1284c10b85d6SJean-Jacques Hiblot sd3_bus_mode = __be32_to_cpu(switch_status[3]) >> 16 & 0x1f; 1285c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR104) 1286c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR104); 1287c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR50) 1288c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR50); 1289c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR25) 1290c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR25); 1291c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR12) 1292c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR12); 1293c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_DDR50) 1294c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_DDR50); 1295f99c2efeSJean-Jacques Hiblot #endif 1296c10b85d6SJean-Jacques Hiblot 12972c3fbf4cSMacpaul Lin return 0; 1298d0c221feSJean-Jacques Hiblot } 1299d0c221feSJean-Jacques Hiblot 1300d0c221feSJean-Jacques Hiblot static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode) 1301d0c221feSJean-Jacques Hiblot { 1302d0c221feSJean-Jacques Hiblot int err; 1303d0c221feSJean-Jacques Hiblot 1304d0c221feSJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16); 1305c10b85d6SJean-Jacques Hiblot int speed; 13062c3fbf4cSMacpaul Lin 1307cf345760SMarek Vasut /* SD version 1.00 and 1.01 does not support CMD 6 */ 1308cf345760SMarek Vasut if (mmc->version == SD_VERSION_1_0) 1309cf345760SMarek Vasut return 0; 1310cf345760SMarek Vasut 1311c10b85d6SJean-Jacques Hiblot switch (mode) { 1312c10b85d6SJean-Jacques Hiblot case SD_LEGACY: 1313c10b85d6SJean-Jacques Hiblot speed = UHS_SDR12_BUS_SPEED; 1314c10b85d6SJean-Jacques Hiblot break; 1315c10b85d6SJean-Jacques Hiblot case SD_HS: 1316baef2070SJean-Jacques Hiblot speed = HIGH_SPEED_BUS_SPEED; 1317baef2070SJean-Jacques Hiblot break; 1318baef2070SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1319baef2070SJean-Jacques Hiblot case UHS_SDR12: 1320baef2070SJean-Jacques Hiblot speed = UHS_SDR12_BUS_SPEED; 1321baef2070SJean-Jacques Hiblot break; 1322c10b85d6SJean-Jacques Hiblot case UHS_SDR25: 1323c10b85d6SJean-Jacques Hiblot speed = UHS_SDR25_BUS_SPEED; 1324c10b85d6SJean-Jacques Hiblot break; 1325c10b85d6SJean-Jacques Hiblot case UHS_SDR50: 1326c10b85d6SJean-Jacques Hiblot speed = UHS_SDR50_BUS_SPEED; 1327c10b85d6SJean-Jacques Hiblot break; 1328c10b85d6SJean-Jacques Hiblot case UHS_DDR50: 1329c10b85d6SJean-Jacques Hiblot speed = UHS_DDR50_BUS_SPEED; 1330c10b85d6SJean-Jacques Hiblot break; 1331c10b85d6SJean-Jacques Hiblot case UHS_SDR104: 1332c10b85d6SJean-Jacques Hiblot speed = UHS_SDR104_BUS_SPEED; 1333c10b85d6SJean-Jacques Hiblot break; 1334baef2070SJean-Jacques Hiblot #endif 1335c10b85d6SJean-Jacques Hiblot default: 1336c10b85d6SJean-Jacques Hiblot return -EINVAL; 1337c10b85d6SJean-Jacques Hiblot } 1338c10b85d6SJean-Jacques Hiblot 1339c10b85d6SJean-Jacques Hiblot err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, speed, (u8 *)switch_status); 1340272cc70bSAndy Fleming if (err) 1341272cc70bSAndy Fleming return err; 1342272cc70bSAndy Fleming 1343a0276f3eSJean-Jacques Hiblot if (((__be32_to_cpu(switch_status[4]) >> 24) & 0xF) != speed) 1344d0c221feSJean-Jacques Hiblot return -ENOTSUPP; 1345d0c221feSJean-Jacques Hiblot 1346d0c221feSJean-Jacques Hiblot return 0; 1347d0c221feSJean-Jacques Hiblot } 1348d0c221feSJean-Jacques Hiblot 1349ec360e64SMarek Vasut static int sd_select_bus_width(struct mmc *mmc, int w) 1350d0c221feSJean-Jacques Hiblot { 1351d0c221feSJean-Jacques Hiblot int err; 1352d0c221feSJean-Jacques Hiblot struct mmc_cmd cmd; 1353d0c221feSJean-Jacques Hiblot 1354d0c221feSJean-Jacques Hiblot if ((w != 4) && (w != 1)) 1355d0c221feSJean-Jacques Hiblot return -EINVAL; 1356d0c221feSJean-Jacques Hiblot 1357d0c221feSJean-Jacques Hiblot cmd.cmdidx = MMC_CMD_APP_CMD; 1358d0c221feSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 1359d0c221feSJean-Jacques Hiblot cmd.cmdarg = mmc->rca << 16; 1360d0c221feSJean-Jacques Hiblot 1361d0c221feSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 1362d0c221feSJean-Jacques Hiblot if (err) 1363d0c221feSJean-Jacques Hiblot return err; 1364d0c221feSJean-Jacques Hiblot 1365d0c221feSJean-Jacques Hiblot cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; 1366d0c221feSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 1367d0c221feSJean-Jacques Hiblot if (w == 4) 1368d0c221feSJean-Jacques Hiblot cmd.cmdarg = 2; 1369d0c221feSJean-Jacques Hiblot else if (w == 1) 1370d0c221feSJean-Jacques Hiblot cmd.cmdarg = 0; 1371d0c221feSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 1372d0c221feSJean-Jacques Hiblot if (err) 1373d0c221feSJean-Jacques Hiblot return err; 1374272cc70bSAndy Fleming 1375272cc70bSAndy Fleming return 0; 1376272cc70bSAndy Fleming } 137762d77ceaSMarek Vasut #endif 1378272cc70bSAndy Fleming 13795b2e72f3SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE) 13803697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc) 13813697e599SPeng Fan { 13825b2e72f3SJean-Jacques Hiblot static const unsigned int sd_au_size[] = { 13835b2e72f3SJean-Jacques Hiblot 0, SZ_16K / 512, SZ_32K / 512, 13845b2e72f3SJean-Jacques Hiblot SZ_64K / 512, SZ_128K / 512, SZ_256K / 512, 13855b2e72f3SJean-Jacques Hiblot SZ_512K / 512, SZ_1M / 512, SZ_2M / 512, 13865b2e72f3SJean-Jacques Hiblot SZ_4M / 512, SZ_8M / 512, (SZ_8M + SZ_4M) / 512, 13875b2e72f3SJean-Jacques Hiblot SZ_16M / 512, (SZ_16M + SZ_8M) / 512, SZ_32M / 512, 13885b2e72f3SJean-Jacques Hiblot SZ_64M / 512, 13895b2e72f3SJean-Jacques Hiblot }; 13903697e599SPeng Fan int err, i; 13913697e599SPeng Fan struct mmc_cmd cmd; 13923697e599SPeng Fan ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16); 13933697e599SPeng Fan struct mmc_data data; 13943697e599SPeng Fan int timeout = 3; 13953697e599SPeng Fan unsigned int au, eo, et, es; 13963697e599SPeng Fan 13973697e599SPeng Fan cmd.cmdidx = MMC_CMD_APP_CMD; 13983697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 13993697e599SPeng Fan cmd.cmdarg = mmc->rca << 16; 14003697e599SPeng Fan 14013697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, NULL); 14023697e599SPeng Fan if (err) 14033697e599SPeng Fan return err; 14043697e599SPeng Fan 14053697e599SPeng Fan cmd.cmdidx = SD_CMD_APP_SD_STATUS; 14063697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 14073697e599SPeng Fan cmd.cmdarg = 0; 14083697e599SPeng Fan 14093697e599SPeng Fan retry_ssr: 14103697e599SPeng Fan data.dest = (char *)ssr; 14113697e599SPeng Fan data.blocksize = 64; 14123697e599SPeng Fan data.blocks = 1; 14133697e599SPeng Fan data.flags = MMC_DATA_READ; 14143697e599SPeng Fan 14153697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, &data); 14163697e599SPeng Fan if (err) { 14173697e599SPeng Fan if (timeout--) 14183697e599SPeng Fan goto retry_ssr; 14193697e599SPeng Fan 14203697e599SPeng Fan return err; 14213697e599SPeng Fan } 14223697e599SPeng Fan 14233697e599SPeng Fan for (i = 0; i < 16; i++) 14243697e599SPeng Fan ssr[i] = be32_to_cpu(ssr[i]); 14253697e599SPeng Fan 14263697e599SPeng Fan au = (ssr[2] >> 12) & 0xF; 14273697e599SPeng Fan if ((au <= 9) || (mmc->version == SD_VERSION_3)) { 14283697e599SPeng Fan mmc->ssr.au = sd_au_size[au]; 14293697e599SPeng Fan es = (ssr[3] >> 24) & 0xFF; 14303697e599SPeng Fan es |= (ssr[2] & 0xFF) << 8; 14313697e599SPeng Fan et = (ssr[3] >> 18) & 0x3F; 14323697e599SPeng Fan if (es && et) { 14333697e599SPeng Fan eo = (ssr[3] >> 16) & 0x3; 14343697e599SPeng Fan mmc->ssr.erase_timeout = (et * 1000) / es; 14353697e599SPeng Fan mmc->ssr.erase_offset = eo * 1000; 14363697e599SPeng Fan } 14373697e599SPeng Fan } else { 1438d4d64889SMasahiro Yamada pr_debug("Invalid Allocation Unit Size.\n"); 14393697e599SPeng Fan } 14403697e599SPeng Fan 14413697e599SPeng Fan return 0; 14423697e599SPeng Fan } 14435b2e72f3SJean-Jacques Hiblot #endif 1444272cc70bSAndy Fleming /* frequency bases */ 1445272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */ 14465f837c2cSMike Frysinger static const int fbase[] = { 1447272cc70bSAndy Fleming 10000, 1448272cc70bSAndy Fleming 100000, 1449272cc70bSAndy Fleming 1000000, 1450272cc70bSAndy Fleming 10000000, 1451272cc70bSAndy Fleming }; 1452272cc70bSAndy Fleming 1453272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice 1454272cc70bSAndy Fleming * to platforms without floating point. 1455272cc70bSAndy Fleming */ 145661fe076fSSimon Glass static const u8 multipliers[] = { 1457272cc70bSAndy Fleming 0, /* reserved */ 1458272cc70bSAndy Fleming 10, 1459272cc70bSAndy Fleming 12, 1460272cc70bSAndy Fleming 13, 1461272cc70bSAndy Fleming 15, 1462272cc70bSAndy Fleming 20, 1463272cc70bSAndy Fleming 25, 1464272cc70bSAndy Fleming 30, 1465272cc70bSAndy Fleming 35, 1466272cc70bSAndy Fleming 40, 1467272cc70bSAndy Fleming 45, 1468272cc70bSAndy Fleming 50, 1469272cc70bSAndy Fleming 55, 1470272cc70bSAndy Fleming 60, 1471272cc70bSAndy Fleming 70, 1472272cc70bSAndy Fleming 80, 1473272cc70bSAndy Fleming }; 1474272cc70bSAndy Fleming 1475d0c221feSJean-Jacques Hiblot static inline int bus_width(uint cap) 1476d0c221feSJean-Jacques Hiblot { 1477d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_8BIT) 1478d0c221feSJean-Jacques Hiblot return 8; 1479d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_4BIT) 1480d0c221feSJean-Jacques Hiblot return 4; 1481d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_1BIT) 1482d0c221feSJean-Jacques Hiblot return 1; 1483d8e3d420SJean-Jacques Hiblot pr_warn("invalid bus witdh capability 0x%x\n", cap); 1484d0c221feSJean-Jacques Hiblot return 0; 1485d0c221feSJean-Jacques Hiblot } 1486d0c221feSJean-Jacques Hiblot 1487e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 1488f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 1489ec841209SKishon Vijay Abraham I static int mmc_execute_tuning(struct mmc *mmc, uint opcode) 1490ec841209SKishon Vijay Abraham I { 1491ec841209SKishon Vijay Abraham I return -ENOTSUPP; 1492ec841209SKishon Vijay Abraham I } 1493f99c2efeSJean-Jacques Hiblot #endif 1494ec841209SKishon Vijay Abraham I 1495318a7a57SJean-Jacques Hiblot static void mmc_send_init_stream(struct mmc *mmc) 1496318a7a57SJean-Jacques Hiblot { 1497318a7a57SJean-Jacques Hiblot } 1498318a7a57SJean-Jacques Hiblot 14992a4d212fSKishon Vijay Abraham I static int mmc_set_ios(struct mmc *mmc) 1500272cc70bSAndy Fleming { 15012a4d212fSKishon Vijay Abraham I int ret = 0; 15022a4d212fSKishon Vijay Abraham I 150393bfd616SPantelis Antoniou if (mmc->cfg->ops->set_ios) 15042a4d212fSKishon Vijay Abraham I ret = mmc->cfg->ops->set_ios(mmc); 15052a4d212fSKishon Vijay Abraham I 15062a4d212fSKishon Vijay Abraham I return ret; 1507272cc70bSAndy Fleming } 15088ca51e51SSimon Glass #endif 1509272cc70bSAndy Fleming 151035f67820SKishon Vijay Abraham I int mmc_set_clock(struct mmc *mmc, uint clock, bool disable) 1511272cc70bSAndy Fleming { 1512c0fafe64SJaehoon Chung if (!disable) { 151393bfd616SPantelis Antoniou if (clock > mmc->cfg->f_max) 151493bfd616SPantelis Antoniou clock = mmc->cfg->f_max; 1515272cc70bSAndy Fleming 151693bfd616SPantelis Antoniou if (clock < mmc->cfg->f_min) 151793bfd616SPantelis Antoniou clock = mmc->cfg->f_min; 15189546eb92SJaehoon Chung } 1519272cc70bSAndy Fleming 1520272cc70bSAndy Fleming mmc->clock = clock; 152135f67820SKishon Vijay Abraham I mmc->clk_disable = disable; 1522272cc70bSAndy Fleming 1523d2faadb5SJaehoon Chung debug("clock is %s (%dHz)\n", disable ? "disabled" : "enabled", clock); 1524d2faadb5SJaehoon Chung 15252a4d212fSKishon Vijay Abraham I return mmc_set_ios(mmc); 1526272cc70bSAndy Fleming } 1527272cc70bSAndy Fleming 15282a4d212fSKishon Vijay Abraham I static int mmc_set_bus_width(struct mmc *mmc, uint width) 1529272cc70bSAndy Fleming { 1530272cc70bSAndy Fleming mmc->bus_width = width; 1531272cc70bSAndy Fleming 15322a4d212fSKishon Vijay Abraham I return mmc_set_ios(mmc); 1533272cc70bSAndy Fleming } 1534272cc70bSAndy Fleming 15354c9d2aaaSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG) 15364c9d2aaaSJean-Jacques Hiblot /* 15374c9d2aaaSJean-Jacques Hiblot * helper function to display the capabilities in a human 15384c9d2aaaSJean-Jacques Hiblot * friendly manner. The capabilities include bus width and 15394c9d2aaaSJean-Jacques Hiblot * supported modes. 15404c9d2aaaSJean-Jacques Hiblot */ 15414c9d2aaaSJean-Jacques Hiblot void mmc_dump_capabilities(const char *text, uint caps) 15424c9d2aaaSJean-Jacques Hiblot { 15434c9d2aaaSJean-Jacques Hiblot enum bus_mode mode; 15444c9d2aaaSJean-Jacques Hiblot 1545d4d64889SMasahiro Yamada pr_debug("%s: widths [", text); 15464c9d2aaaSJean-Jacques Hiblot if (caps & MMC_MODE_8BIT) 1547d4d64889SMasahiro Yamada pr_debug("8, "); 15484c9d2aaaSJean-Jacques Hiblot if (caps & MMC_MODE_4BIT) 1549d4d64889SMasahiro Yamada pr_debug("4, "); 1550d0c221feSJean-Jacques Hiblot if (caps & MMC_MODE_1BIT) 1551d4d64889SMasahiro Yamada pr_debug("1, "); 1552d4d64889SMasahiro Yamada pr_debug("\b\b] modes ["); 15534c9d2aaaSJean-Jacques Hiblot for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++) 15544c9d2aaaSJean-Jacques Hiblot if (MMC_CAP(mode) & caps) 1555d4d64889SMasahiro Yamada pr_debug("%s, ", mmc_mode_name(mode)); 1556d4d64889SMasahiro Yamada pr_debug("\b\b]\n"); 15574c9d2aaaSJean-Jacques Hiblot } 15584c9d2aaaSJean-Jacques Hiblot #endif 15594c9d2aaaSJean-Jacques Hiblot 1560d0c221feSJean-Jacques Hiblot struct mode_width_tuning { 1561d0c221feSJean-Jacques Hiblot enum bus_mode mode; 1562d0c221feSJean-Jacques Hiblot uint widths; 1563f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 1564634d4849SKishon Vijay Abraham I uint tuning; 1565f99c2efeSJean-Jacques Hiblot #endif 1566d0c221feSJean-Jacques Hiblot }; 1567d0c221feSJean-Jacques Hiblot 1568f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE) 1569bc1e3272SJean-Jacques Hiblot int mmc_voltage_to_mv(enum mmc_voltage voltage) 1570bc1e3272SJean-Jacques Hiblot { 1571bc1e3272SJean-Jacques Hiblot switch (voltage) { 1572bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_000: return 0; 1573bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_330: return 3300; 1574bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_180: return 1800; 1575bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_120: return 1200; 1576bc1e3272SJean-Jacques Hiblot } 1577bc1e3272SJean-Jacques Hiblot return -EINVAL; 1578bc1e3272SJean-Jacques Hiblot } 1579bc1e3272SJean-Jacques Hiblot 1580aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage) 1581aff5d3c8SKishon Vijay Abraham I { 1582bc1e3272SJean-Jacques Hiblot int err; 1583bc1e3272SJean-Jacques Hiblot 1584bc1e3272SJean-Jacques Hiblot if (mmc->signal_voltage == signal_voltage) 1585bc1e3272SJean-Jacques Hiblot return 0; 1586bc1e3272SJean-Jacques Hiblot 1587aff5d3c8SKishon Vijay Abraham I mmc->signal_voltage = signal_voltage; 1588bc1e3272SJean-Jacques Hiblot err = mmc_set_ios(mmc); 1589bc1e3272SJean-Jacques Hiblot if (err) 1590d4d64889SMasahiro Yamada pr_debug("unable to set voltage (err %d)\n", err); 1591bc1e3272SJean-Jacques Hiblot 1592bc1e3272SJean-Jacques Hiblot return err; 1593aff5d3c8SKishon Vijay Abraham I } 1594f99c2efeSJean-Jacques Hiblot #else 1595f99c2efeSJean-Jacques Hiblot static inline int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage) 1596f99c2efeSJean-Jacques Hiblot { 1597f99c2efeSJean-Jacques Hiblot return 0; 1598f99c2efeSJean-Jacques Hiblot } 1599f99c2efeSJean-Jacques Hiblot #endif 1600aff5d3c8SKishon Vijay Abraham I 160162d77ceaSMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY) 1602d0c221feSJean-Jacques Hiblot static const struct mode_width_tuning sd_modes_by_pref[] = { 1603f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1604f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 1605d0c221feSJean-Jacques Hiblot { 1606c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR104, 1607c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1608c10b85d6SJean-Jacques Hiblot .tuning = MMC_CMD_SEND_TUNING_BLOCK 1609c10b85d6SJean-Jacques Hiblot }, 1610f99c2efeSJean-Jacques Hiblot #endif 1611c10b85d6SJean-Jacques Hiblot { 1612c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR50, 1613c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1614c10b85d6SJean-Jacques Hiblot }, 1615c10b85d6SJean-Jacques Hiblot { 1616c10b85d6SJean-Jacques Hiblot .mode = UHS_DDR50, 1617c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1618c10b85d6SJean-Jacques Hiblot }, 1619c10b85d6SJean-Jacques Hiblot { 1620c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR25, 1621c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1622c10b85d6SJean-Jacques Hiblot }, 1623f99c2efeSJean-Jacques Hiblot #endif 1624c10b85d6SJean-Jacques Hiblot { 1625d0c221feSJean-Jacques Hiblot .mode = SD_HS, 1626d0c221feSJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1627d0c221feSJean-Jacques Hiblot }, 1628f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1629d0c221feSJean-Jacques Hiblot { 1630c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR12, 1631c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1632c10b85d6SJean-Jacques Hiblot }, 1633f99c2efeSJean-Jacques Hiblot #endif 1634c10b85d6SJean-Jacques Hiblot { 1635d0c221feSJean-Jacques Hiblot .mode = SD_LEGACY, 1636d0c221feSJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1637d0c221feSJean-Jacques Hiblot } 1638d0c221feSJean-Jacques Hiblot }; 1639d0c221feSJean-Jacques Hiblot 1640d0c221feSJean-Jacques Hiblot #define for_each_sd_mode_by_pref(caps, mwt) \ 1641d0c221feSJean-Jacques Hiblot for (mwt = sd_modes_by_pref;\ 1642d0c221feSJean-Jacques Hiblot mwt < sd_modes_by_pref + ARRAY_SIZE(sd_modes_by_pref);\ 1643d0c221feSJean-Jacques Hiblot mwt++) \ 1644d0c221feSJean-Jacques Hiblot if (caps & MMC_CAP(mwt->mode)) 1645d0c221feSJean-Jacques Hiblot 164601298da3SJean-Jacques Hiblot static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps) 16478ac8a263SJean-Jacques Hiblot { 16488ac8a263SJean-Jacques Hiblot int err; 1649d0c221feSJean-Jacques Hiblot uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT}; 1650d0c221feSJean-Jacques Hiblot const struct mode_width_tuning *mwt; 1651f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1652c10b85d6SJean-Jacques Hiblot bool uhs_en = (mmc->ocr & OCR_S18R) ? true : false; 1653f99c2efeSJean-Jacques Hiblot #else 1654f99c2efeSJean-Jacques Hiblot bool uhs_en = false; 1655f99c2efeSJean-Jacques Hiblot #endif 1656c10b85d6SJean-Jacques Hiblot uint caps; 1657c10b85d6SJean-Jacques Hiblot 165852d241dfSJean-Jacques Hiblot #ifdef DEBUG 165952d241dfSJean-Jacques Hiblot mmc_dump_capabilities("sd card", card_caps); 16601da8eb59SJean-Jacques Hiblot mmc_dump_capabilities("host", mmc->host_caps); 166152d241dfSJean-Jacques Hiblot #endif 16628ac8a263SJean-Jacques Hiblot 16638ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */ 16641da8eb59SJean-Jacques Hiblot caps = card_caps & mmc->host_caps; 16658ac8a263SJean-Jacques Hiblot 1666c10b85d6SJean-Jacques Hiblot if (!uhs_en) 1667c10b85d6SJean-Jacques Hiblot caps &= ~UHS_CAPS; 1668c10b85d6SJean-Jacques Hiblot 1669c10b85d6SJean-Jacques Hiblot for_each_sd_mode_by_pref(caps, mwt) { 1670d0c221feSJean-Jacques Hiblot uint *w; 16718ac8a263SJean-Jacques Hiblot 1672d0c221feSJean-Jacques Hiblot for (w = widths; w < widths + ARRAY_SIZE(widths); w++) { 1673c10b85d6SJean-Jacques Hiblot if (*w & caps & mwt->widths) { 1674d4d64889SMasahiro Yamada pr_debug("trying mode %s width %d (at %d MHz)\n", 1675d0c221feSJean-Jacques Hiblot mmc_mode_name(mwt->mode), 1676d0c221feSJean-Jacques Hiblot bus_width(*w), 1677d0c221feSJean-Jacques Hiblot mmc_mode2freq(mmc, mwt->mode) / 1000000); 1678d0c221feSJean-Jacques Hiblot 1679d0c221feSJean-Jacques Hiblot /* configure the bus width (card + host) */ 1680d0c221feSJean-Jacques Hiblot err = sd_select_bus_width(mmc, bus_width(*w)); 16818ac8a263SJean-Jacques Hiblot if (err) 1682d0c221feSJean-Jacques Hiblot goto error; 1683d0c221feSJean-Jacques Hiblot mmc_set_bus_width(mmc, bus_width(*w)); 16848ac8a263SJean-Jacques Hiblot 1685d0c221feSJean-Jacques Hiblot /* configure the bus mode (card) */ 1686d0c221feSJean-Jacques Hiblot err = sd_set_card_speed(mmc, mwt->mode); 16878ac8a263SJean-Jacques Hiblot if (err) 1688d0c221feSJean-Jacques Hiblot goto error; 16898ac8a263SJean-Jacques Hiblot 1690d0c221feSJean-Jacques Hiblot /* configure the bus mode (host) */ 1691d0c221feSJean-Jacques Hiblot mmc_select_mode(mmc, mwt->mode); 169265117182SJaehoon Chung mmc_set_clock(mmc, mmc->tran_speed, 169365117182SJaehoon Chung MMC_CLK_ENABLE); 16948ac8a263SJean-Jacques Hiblot 1695f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 1696c10b85d6SJean-Jacques Hiblot /* execute tuning if needed */ 1697c10b85d6SJean-Jacques Hiblot if (mwt->tuning && !mmc_host_is_spi(mmc)) { 1698c10b85d6SJean-Jacques Hiblot err = mmc_execute_tuning(mmc, 1699c10b85d6SJean-Jacques Hiblot mwt->tuning); 1700c10b85d6SJean-Jacques Hiblot if (err) { 1701d4d64889SMasahiro Yamada pr_debug("tuning failed\n"); 1702c10b85d6SJean-Jacques Hiblot goto error; 1703c10b85d6SJean-Jacques Hiblot } 1704c10b85d6SJean-Jacques Hiblot } 1705f99c2efeSJean-Jacques Hiblot #endif 1706c10b85d6SJean-Jacques Hiblot 17075b2e72f3SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE) 17088ac8a263SJean-Jacques Hiblot err = sd_read_ssr(mmc); 17090a4c2b09SPeng Fan if (err) 17105b2e72f3SJean-Jacques Hiblot pr_warn("unable to read ssr\n"); 17115b2e72f3SJean-Jacques Hiblot #endif 17125b2e72f3SJean-Jacques Hiblot if (!err) 17138ac8a263SJean-Jacques Hiblot return 0; 1714d0c221feSJean-Jacques Hiblot 1715d0c221feSJean-Jacques Hiblot error: 1716d0c221feSJean-Jacques Hiblot /* revert to a safer bus speed */ 1717d0c221feSJean-Jacques Hiblot mmc_select_mode(mmc, SD_LEGACY); 171865117182SJaehoon Chung mmc_set_clock(mmc, mmc->tran_speed, 171965117182SJaehoon Chung MMC_CLK_ENABLE); 1720d0c221feSJean-Jacques Hiblot } 1721d0c221feSJean-Jacques Hiblot } 1722d0c221feSJean-Jacques Hiblot } 1723d0c221feSJean-Jacques Hiblot 1724d4d64889SMasahiro Yamada pr_err("unable to select a mode\n"); 1725d0c221feSJean-Jacques Hiblot return -ENOTSUPP; 17268ac8a263SJean-Jacques Hiblot } 17278ac8a263SJean-Jacques Hiblot 17287382e691SJean-Jacques Hiblot /* 17297382e691SJean-Jacques Hiblot * read the compare the part of ext csd that is constant. 17307382e691SJean-Jacques Hiblot * This can be used to check that the transfer is working 17317382e691SJean-Jacques Hiblot * as expected. 17327382e691SJean-Jacques Hiblot */ 17337382e691SJean-Jacques Hiblot static int mmc_read_and_compare_ext_csd(struct mmc *mmc) 17347382e691SJean-Jacques Hiblot { 17357382e691SJean-Jacques Hiblot int err; 17367382e691SJean-Jacques Hiblot const u8 *ext_csd = mmc->ext_csd; 17377382e691SJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 17387382e691SJean-Jacques Hiblot 17391de06b9fSJean-Jacques Hiblot if (mmc->version < MMC_VERSION_4) 17401de06b9fSJean-Jacques Hiblot return 0; 17411de06b9fSJean-Jacques Hiblot 17427382e691SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, test_csd); 17437382e691SJean-Jacques Hiblot if (err) 17447382e691SJean-Jacques Hiblot return err; 17457382e691SJean-Jacques Hiblot 17467382e691SJean-Jacques Hiblot /* Only compare read only fields */ 17477382e691SJean-Jacques Hiblot if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] 17487382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_PARTITIONING_SUPPORT] && 17497382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_WP_GRP_SIZE] 17507382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_WP_GRP_SIZE] && 17517382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_REV] 17527382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_REV] && 17537382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 17547382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] && 17557382e691SJean-Jacques Hiblot memcmp(&ext_csd[EXT_CSD_SEC_CNT], 17567382e691SJean-Jacques Hiblot &test_csd[EXT_CSD_SEC_CNT], 4) == 0) 17577382e691SJean-Jacques Hiblot return 0; 17587382e691SJean-Jacques Hiblot 17597382e691SJean-Jacques Hiblot return -EBADMSG; 17607382e691SJean-Jacques Hiblot } 17617382e691SJean-Jacques Hiblot 1762f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE) 1763bc1e3272SJean-Jacques Hiblot static int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode, 1764bc1e3272SJean-Jacques Hiblot uint32_t allowed_mask) 1765bc1e3272SJean-Jacques Hiblot { 1766bc1e3272SJean-Jacques Hiblot u32 card_mask = 0; 1767bc1e3272SJean-Jacques Hiblot 1768bc1e3272SJean-Jacques Hiblot switch (mode) { 17693dd2626fSPeng Fan case MMC_HS_400: 1770bc1e3272SJean-Jacques Hiblot case MMC_HS_200: 17713dd2626fSPeng Fan if (mmc->cardtype & (EXT_CSD_CARD_TYPE_HS200_1_8V | 17723dd2626fSPeng Fan EXT_CSD_CARD_TYPE_HS400_1_8V)) 1773bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_180; 17743dd2626fSPeng Fan if (mmc->cardtype & (EXT_CSD_CARD_TYPE_HS200_1_2V | 17753dd2626fSPeng Fan EXT_CSD_CARD_TYPE_HS400_1_2V)) 1776bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_120; 1777bc1e3272SJean-Jacques Hiblot break; 1778bc1e3272SJean-Jacques Hiblot case MMC_DDR_52: 1779bc1e3272SJean-Jacques Hiblot if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V) 1780bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_330 | 1781bc1e3272SJean-Jacques Hiblot MMC_SIGNAL_VOLTAGE_180; 1782bc1e3272SJean-Jacques Hiblot if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_2V) 1783bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_120; 1784bc1e3272SJean-Jacques Hiblot break; 1785bc1e3272SJean-Jacques Hiblot default: 1786bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_330; 1787bc1e3272SJean-Jacques Hiblot break; 1788bc1e3272SJean-Jacques Hiblot } 1789bc1e3272SJean-Jacques Hiblot 1790bc1e3272SJean-Jacques Hiblot while (card_mask & allowed_mask) { 1791bc1e3272SJean-Jacques Hiblot enum mmc_voltage best_match; 1792bc1e3272SJean-Jacques Hiblot 1793bc1e3272SJean-Jacques Hiblot best_match = 1 << (ffs(card_mask & allowed_mask) - 1); 1794bc1e3272SJean-Jacques Hiblot if (!mmc_set_signal_voltage(mmc, best_match)) 1795bc1e3272SJean-Jacques Hiblot return 0; 1796bc1e3272SJean-Jacques Hiblot 1797bc1e3272SJean-Jacques Hiblot allowed_mask &= ~best_match; 1798bc1e3272SJean-Jacques Hiblot } 1799bc1e3272SJean-Jacques Hiblot 1800bc1e3272SJean-Jacques Hiblot return -ENOTSUPP; 1801bc1e3272SJean-Jacques Hiblot } 1802f99c2efeSJean-Jacques Hiblot #else 1803f99c2efeSJean-Jacques Hiblot static inline int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode, 1804f99c2efeSJean-Jacques Hiblot uint32_t allowed_mask) 1805f99c2efeSJean-Jacques Hiblot { 1806f99c2efeSJean-Jacques Hiblot return 0; 1807f99c2efeSJean-Jacques Hiblot } 1808f99c2efeSJean-Jacques Hiblot #endif 1809bc1e3272SJean-Jacques Hiblot 18103862b854SJean-Jacques Hiblot static const struct mode_width_tuning mmc_modes_by_pref[] = { 18113dd2626fSPeng Fan #if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) 18123dd2626fSPeng Fan { 18133dd2626fSPeng Fan .mode = MMC_HS_400, 18143dd2626fSPeng Fan .widths = MMC_MODE_8BIT, 18153dd2626fSPeng Fan .tuning = MMC_CMD_SEND_TUNING_BLOCK_HS200 18163dd2626fSPeng Fan }, 18173dd2626fSPeng Fan #endif 1818f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) 18198ac8a263SJean-Jacques Hiblot { 18203862b854SJean-Jacques Hiblot .mode = MMC_HS_200, 18213862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT, 1822634d4849SKishon Vijay Abraham I .tuning = MMC_CMD_SEND_TUNING_BLOCK_HS200 18233862b854SJean-Jacques Hiblot }, 1824f99c2efeSJean-Jacques Hiblot #endif 18253862b854SJean-Jacques Hiblot { 18263862b854SJean-Jacques Hiblot .mode = MMC_DDR_52, 18273862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT, 18283862b854SJean-Jacques Hiblot }, 18293862b854SJean-Jacques Hiblot { 18303862b854SJean-Jacques Hiblot .mode = MMC_HS_52, 18313862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 18323862b854SJean-Jacques Hiblot }, 18333862b854SJean-Jacques Hiblot { 18343862b854SJean-Jacques Hiblot .mode = MMC_HS, 18353862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 18363862b854SJean-Jacques Hiblot }, 18373862b854SJean-Jacques Hiblot { 18383862b854SJean-Jacques Hiblot .mode = MMC_LEGACY, 18393862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 18403862b854SJean-Jacques Hiblot } 18418ac8a263SJean-Jacques Hiblot }; 18428ac8a263SJean-Jacques Hiblot 18433862b854SJean-Jacques Hiblot #define for_each_mmc_mode_by_pref(caps, mwt) \ 18443862b854SJean-Jacques Hiblot for (mwt = mmc_modes_by_pref;\ 18453862b854SJean-Jacques Hiblot mwt < mmc_modes_by_pref + ARRAY_SIZE(mmc_modes_by_pref);\ 18463862b854SJean-Jacques Hiblot mwt++) \ 18473862b854SJean-Jacques Hiblot if (caps & MMC_CAP(mwt->mode)) 18483862b854SJean-Jacques Hiblot 18493862b854SJean-Jacques Hiblot static const struct ext_csd_bus_width { 18503862b854SJean-Jacques Hiblot uint cap; 18513862b854SJean-Jacques Hiblot bool is_ddr; 18523862b854SJean-Jacques Hiblot uint ext_csd_bits; 18533862b854SJean-Jacques Hiblot } ext_csd_bus_width[] = { 18543862b854SJean-Jacques Hiblot {MMC_MODE_8BIT, true, EXT_CSD_DDR_BUS_WIDTH_8}, 18553862b854SJean-Jacques Hiblot {MMC_MODE_4BIT, true, EXT_CSD_DDR_BUS_WIDTH_4}, 18563862b854SJean-Jacques Hiblot {MMC_MODE_8BIT, false, EXT_CSD_BUS_WIDTH_8}, 18573862b854SJean-Jacques Hiblot {MMC_MODE_4BIT, false, EXT_CSD_BUS_WIDTH_4}, 18583862b854SJean-Jacques Hiblot {MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1}, 18593862b854SJean-Jacques Hiblot }; 18603862b854SJean-Jacques Hiblot 18613dd2626fSPeng Fan #if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) 18623dd2626fSPeng Fan static int mmc_select_hs400(struct mmc *mmc) 18633dd2626fSPeng Fan { 18643dd2626fSPeng Fan int err; 18653dd2626fSPeng Fan 18663dd2626fSPeng Fan /* Set timing to HS200 for tuning */ 1867*b9a2a0e2SMarek Vasut err = mmc_set_card_speed(mmc, MMC_HS_200, false); 18683dd2626fSPeng Fan if (err) 18693dd2626fSPeng Fan return err; 18703dd2626fSPeng Fan 18713dd2626fSPeng Fan /* configure the bus mode (host) */ 18723dd2626fSPeng Fan mmc_select_mode(mmc, MMC_HS_200); 18733dd2626fSPeng Fan mmc_set_clock(mmc, mmc->tran_speed, false); 18743dd2626fSPeng Fan 18753dd2626fSPeng Fan /* execute tuning if needed */ 18763dd2626fSPeng Fan err = mmc_execute_tuning(mmc, MMC_CMD_SEND_TUNING_BLOCK_HS200); 18773dd2626fSPeng Fan if (err) { 18783dd2626fSPeng Fan debug("tuning failed\n"); 18793dd2626fSPeng Fan return err; 18803dd2626fSPeng Fan } 18813dd2626fSPeng Fan 18823dd2626fSPeng Fan /* Set back to HS */ 1883*b9a2a0e2SMarek Vasut mmc_set_card_speed(mmc, MMC_HS, false); 18843dd2626fSPeng Fan mmc_set_clock(mmc, mmc_mode2freq(mmc, MMC_HS), false); 18853dd2626fSPeng Fan 18863dd2626fSPeng Fan err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH, 18873dd2626fSPeng Fan EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_FLAG); 18883dd2626fSPeng Fan if (err) 18893dd2626fSPeng Fan return err; 18903dd2626fSPeng Fan 1891*b9a2a0e2SMarek Vasut err = mmc_set_card_speed(mmc, MMC_HS_400, false); 18923dd2626fSPeng Fan if (err) 18933dd2626fSPeng Fan return err; 18943dd2626fSPeng Fan 18953dd2626fSPeng Fan mmc_select_mode(mmc, MMC_HS_400); 18963dd2626fSPeng Fan err = mmc_set_clock(mmc, mmc->tran_speed, false); 18973dd2626fSPeng Fan if (err) 18983dd2626fSPeng Fan return err; 18993dd2626fSPeng Fan 19003dd2626fSPeng Fan return 0; 19013dd2626fSPeng Fan } 19023dd2626fSPeng Fan #else 19033dd2626fSPeng Fan static int mmc_select_hs400(struct mmc *mmc) 19043dd2626fSPeng Fan { 19053dd2626fSPeng Fan return -ENOTSUPP; 19063dd2626fSPeng Fan } 19073dd2626fSPeng Fan #endif 19083dd2626fSPeng Fan 19093862b854SJean-Jacques Hiblot #define for_each_supported_width(caps, ddr, ecbv) \ 19103862b854SJean-Jacques Hiblot for (ecbv = ext_csd_bus_width;\ 19113862b854SJean-Jacques Hiblot ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\ 19123862b854SJean-Jacques Hiblot ecbv++) \ 19133862b854SJean-Jacques Hiblot if ((ddr == ecbv->is_ddr) && (caps & ecbv->cap)) 19143862b854SJean-Jacques Hiblot 191501298da3SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps) 19163862b854SJean-Jacques Hiblot { 19173862b854SJean-Jacques Hiblot int err; 19183862b854SJean-Jacques Hiblot const struct mode_width_tuning *mwt; 19193862b854SJean-Jacques Hiblot const struct ext_csd_bus_width *ecbw; 19203862b854SJean-Jacques Hiblot 192152d241dfSJean-Jacques Hiblot #ifdef DEBUG 192252d241dfSJean-Jacques Hiblot mmc_dump_capabilities("mmc", card_caps); 19231da8eb59SJean-Jacques Hiblot mmc_dump_capabilities("host", mmc->host_caps); 192452d241dfSJean-Jacques Hiblot #endif 192552d241dfSJean-Jacques Hiblot 19268ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */ 19271da8eb59SJean-Jacques Hiblot card_caps &= mmc->host_caps; 19288ac8a263SJean-Jacques Hiblot 19298ac8a263SJean-Jacques Hiblot /* Only version 4 of MMC supports wider bus widths */ 19308ac8a263SJean-Jacques Hiblot if (mmc->version < MMC_VERSION_4) 19318ac8a263SJean-Jacques Hiblot return 0; 19328ac8a263SJean-Jacques Hiblot 1933dfda9d88SJean-Jacques Hiblot if (!mmc->ext_csd) { 1934d4d64889SMasahiro Yamada pr_debug("No ext_csd found!\n"); /* this should enver happen */ 1935dfda9d88SJean-Jacques Hiblot return -ENOTSUPP; 1936dfda9d88SJean-Jacques Hiblot } 1937dfda9d88SJean-Jacques Hiblot 1938*b9a2a0e2SMarek Vasut #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \ 1939*b9a2a0e2SMarek Vasut CONFIG_IS_ENABLED(MMC_HS400_SUPPORT) 1940*b9a2a0e2SMarek Vasut /* 1941*b9a2a0e2SMarek Vasut * In case the eMMC is in HS200/HS400 mode, downgrade to HS mode 1942*b9a2a0e2SMarek Vasut * before doing anything else, since a transition from either of 1943*b9a2a0e2SMarek Vasut * the HS200/HS400 mode directly to legacy mode is not supported. 1944*b9a2a0e2SMarek Vasut */ 1945*b9a2a0e2SMarek Vasut if (mmc->selected_mode == MMC_HS_200 || 1946*b9a2a0e2SMarek Vasut mmc->selected_mode == MMC_HS_400) 1947*b9a2a0e2SMarek Vasut mmc_set_card_speed(mmc, MMC_HS, true); 1948*b9a2a0e2SMarek Vasut else 1949*b9a2a0e2SMarek Vasut #endif 195065117182SJaehoon Chung mmc_set_clock(mmc, mmc->legacy_speed, MMC_CLK_ENABLE); 195101298da3SJean-Jacques Hiblot 195201298da3SJean-Jacques Hiblot for_each_mmc_mode_by_pref(card_caps, mwt) { 195301298da3SJean-Jacques Hiblot for_each_supported_width(card_caps & mwt->widths, 19543862b854SJean-Jacques Hiblot mmc_is_mode_ddr(mwt->mode), ecbw) { 1955bc1e3272SJean-Jacques Hiblot enum mmc_voltage old_voltage; 1956d4d64889SMasahiro Yamada pr_debug("trying mode %s width %d (at %d MHz)\n", 19573862b854SJean-Jacques Hiblot mmc_mode_name(mwt->mode), 19583862b854SJean-Jacques Hiblot bus_width(ecbw->cap), 19593862b854SJean-Jacques Hiblot mmc_mode2freq(mmc, mwt->mode) / 1000000); 1960bc1e3272SJean-Jacques Hiblot old_voltage = mmc->signal_voltage; 1961bc1e3272SJean-Jacques Hiblot err = mmc_set_lowest_voltage(mmc, mwt->mode, 1962bc1e3272SJean-Jacques Hiblot MMC_ALL_SIGNAL_VOLTAGE); 1963bc1e3272SJean-Jacques Hiblot if (err) 1964bc1e3272SJean-Jacques Hiblot continue; 1965bc1e3272SJean-Jacques Hiblot 19663862b854SJean-Jacques Hiblot /* configure the bus width (card + host) */ 19673862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 19683862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, 19693862b854SJean-Jacques Hiblot ecbw->ext_csd_bits & ~EXT_CSD_DDR_FLAG); 19703862b854SJean-Jacques Hiblot if (err) 19713862b854SJean-Jacques Hiblot goto error; 19723862b854SJean-Jacques Hiblot mmc_set_bus_width(mmc, bus_width(ecbw->cap)); 19733862b854SJean-Jacques Hiblot 19743dd2626fSPeng Fan if (mwt->mode == MMC_HS_400) { 19753dd2626fSPeng Fan err = mmc_select_hs400(mmc); 19763dd2626fSPeng Fan if (err) { 19773dd2626fSPeng Fan printf("Select HS400 failed %d\n", err); 19783dd2626fSPeng Fan goto error; 19793dd2626fSPeng Fan } 19803dd2626fSPeng Fan } else { 19813862b854SJean-Jacques Hiblot /* configure the bus speed (card) */ 1982*b9a2a0e2SMarek Vasut err = mmc_set_card_speed(mmc, mwt->mode, false); 19833862b854SJean-Jacques Hiblot if (err) 19843862b854SJean-Jacques Hiblot goto error; 19853862b854SJean-Jacques Hiblot 19868ac8a263SJean-Jacques Hiblot /* 19873dd2626fSPeng Fan * configure the bus width AND the ddr mode 19883dd2626fSPeng Fan * (card). The host side will be taken care 19893dd2626fSPeng Fan * of in the next step 19908ac8a263SJean-Jacques Hiblot */ 19913862b854SJean-Jacques Hiblot if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) { 19923dd2626fSPeng Fan err = mmc_switch(mmc, 19933dd2626fSPeng Fan EXT_CSD_CMD_SET_NORMAL, 19943862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, 19953862b854SJean-Jacques Hiblot ecbw->ext_csd_bits); 19963862b854SJean-Jacques Hiblot if (err) 19973862b854SJean-Jacques Hiblot goto error; 19988ac8a263SJean-Jacques Hiblot } 19998ac8a263SJean-Jacques Hiblot 20003862b854SJean-Jacques Hiblot /* configure the bus mode (host) */ 20013862b854SJean-Jacques Hiblot mmc_select_mode(mmc, mwt->mode); 20023dd2626fSPeng Fan mmc_set_clock(mmc, mmc->tran_speed, 20033dd2626fSPeng Fan MMC_CLK_ENABLE); 2004f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 20058ac8a263SJean-Jacques Hiblot 2006634d4849SKishon Vijay Abraham I /* execute tuning if needed */ 2007634d4849SKishon Vijay Abraham I if (mwt->tuning) { 20083dd2626fSPeng Fan err = mmc_execute_tuning(mmc, 20093dd2626fSPeng Fan mwt->tuning); 2010634d4849SKishon Vijay Abraham I if (err) { 2011d4d64889SMasahiro Yamada pr_debug("tuning failed\n"); 2012634d4849SKishon Vijay Abraham I goto error; 2013634d4849SKishon Vijay Abraham I } 2014634d4849SKishon Vijay Abraham I } 2015f99c2efeSJean-Jacques Hiblot #endif 20163dd2626fSPeng Fan } 2017634d4849SKishon Vijay Abraham I 20183862b854SJean-Jacques Hiblot /* do a transfer to check the configuration */ 20197382e691SJean-Jacques Hiblot err = mmc_read_and_compare_ext_csd(mmc); 20207382e691SJean-Jacques Hiblot if (!err) 20213862b854SJean-Jacques Hiblot return 0; 20223862b854SJean-Jacques Hiblot error: 2023bc1e3272SJean-Jacques Hiblot mmc_set_signal_voltage(mmc, old_voltage); 20243862b854SJean-Jacques Hiblot /* if an error occured, revert to a safer bus mode */ 20253862b854SJean-Jacques Hiblot mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 20263862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1); 20273862b854SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_LEGACY); 20283862b854SJean-Jacques Hiblot mmc_set_bus_width(mmc, 1); 20293862b854SJean-Jacques Hiblot } 20308ac8a263SJean-Jacques Hiblot } 20318ac8a263SJean-Jacques Hiblot 2032d8e3d420SJean-Jacques Hiblot pr_err("unable to select a mode\n"); 20338ac8a263SJean-Jacques Hiblot 20343862b854SJean-Jacques Hiblot return -ENOTSUPP; 20358ac8a263SJean-Jacques Hiblot } 203662d77ceaSMarek Vasut #endif 203762d77ceaSMarek Vasut 203862d77ceaSMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY) 203962d77ceaSMarek Vasut DEFINE_CACHE_ALIGN_BUFFER(u8, ext_csd_bkup, MMC_MAX_BLOCK_LEN); 204062d77ceaSMarek Vasut #endif 20418ac8a263SJean-Jacques Hiblot 2042dfda9d88SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc) 2043c744b6f6SJean-Jacques Hiblot { 2044c744b6f6SJean-Jacques Hiblot int err, i; 2045c744b6f6SJean-Jacques Hiblot u64 capacity; 2046c744b6f6SJean-Jacques Hiblot bool has_parts = false; 2047c744b6f6SJean-Jacques Hiblot bool part_completed; 204858a6fb7bSJean-Jacques Hiblot static const u32 mmc_versions[] = { 204958a6fb7bSJean-Jacques Hiblot MMC_VERSION_4, 205058a6fb7bSJean-Jacques Hiblot MMC_VERSION_4_1, 205158a6fb7bSJean-Jacques Hiblot MMC_VERSION_4_2, 205258a6fb7bSJean-Jacques Hiblot MMC_VERSION_4_3, 2053ace1bed3SJean-Jacques Hiblot MMC_VERSION_4_4, 205458a6fb7bSJean-Jacques Hiblot MMC_VERSION_4_41, 205558a6fb7bSJean-Jacques Hiblot MMC_VERSION_4_5, 205658a6fb7bSJean-Jacques Hiblot MMC_VERSION_5_0, 205758a6fb7bSJean-Jacques Hiblot MMC_VERSION_5_1 205858a6fb7bSJean-Jacques Hiblot }; 205958a6fb7bSJean-Jacques Hiblot 206062d77ceaSMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY) 206162d77ceaSMarek Vasut u8 *ext_csd = ext_csd_bkup; 206262d77ceaSMarek Vasut 206362d77ceaSMarek Vasut if (IS_SD(mmc) || mmc->version < MMC_VERSION_4) 206462d77ceaSMarek Vasut return 0; 206562d77ceaSMarek Vasut 206662d77ceaSMarek Vasut if (!mmc->ext_csd) 206762d77ceaSMarek Vasut memset(ext_csd_bkup, 0, sizeof(ext_csd_bkup)); 206862d77ceaSMarek Vasut 206962d77ceaSMarek Vasut err = mmc_send_ext_csd(mmc, ext_csd); 207062d77ceaSMarek Vasut if (err) 207162d77ceaSMarek Vasut goto error; 207262d77ceaSMarek Vasut 207362d77ceaSMarek Vasut /* store the ext csd for future reference */ 207462d77ceaSMarek Vasut if (!mmc->ext_csd) 207562d77ceaSMarek Vasut mmc->ext_csd = ext_csd; 207662d77ceaSMarek Vasut #else 2077f7d5dffcSJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 2078c744b6f6SJean-Jacques Hiblot 2079c744b6f6SJean-Jacques Hiblot if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4)) 2080c744b6f6SJean-Jacques Hiblot return 0; 2081c744b6f6SJean-Jacques Hiblot 2082c744b6f6SJean-Jacques Hiblot /* check ext_csd version and capacity */ 2083c744b6f6SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, ext_csd); 2084c744b6f6SJean-Jacques Hiblot if (err) 2085f7d5dffcSJean-Jacques Hiblot goto error; 2086f7d5dffcSJean-Jacques Hiblot 2087f7d5dffcSJean-Jacques Hiblot /* store the ext csd for future reference */ 2088f7d5dffcSJean-Jacques Hiblot if (!mmc->ext_csd) 2089f7d5dffcSJean-Jacques Hiblot mmc->ext_csd = malloc(MMC_MAX_BLOCK_LEN); 2090f7d5dffcSJean-Jacques Hiblot if (!mmc->ext_csd) 2091f7d5dffcSJean-Jacques Hiblot return -ENOMEM; 2092f7d5dffcSJean-Jacques Hiblot memcpy(mmc->ext_csd, ext_csd, MMC_MAX_BLOCK_LEN); 209362d77ceaSMarek Vasut #endif 209476584e33SAlexander Kochetkov if (ext_csd[EXT_CSD_REV] >= ARRAY_SIZE(mmc_versions)) 209558a6fb7bSJean-Jacques Hiblot return -EINVAL; 209658a6fb7bSJean-Jacques Hiblot 209758a6fb7bSJean-Jacques Hiblot mmc->version = mmc_versions[ext_csd[EXT_CSD_REV]]; 209858a6fb7bSJean-Jacques Hiblot 209958a6fb7bSJean-Jacques Hiblot if (mmc->version >= MMC_VERSION_4_2) { 2100c744b6f6SJean-Jacques Hiblot /* 2101c744b6f6SJean-Jacques Hiblot * According to the JEDEC Standard, the value of 2102c744b6f6SJean-Jacques Hiblot * ext_csd's capacity is valid if the value is more 2103c744b6f6SJean-Jacques Hiblot * than 2GB 2104c744b6f6SJean-Jacques Hiblot */ 2105c744b6f6SJean-Jacques Hiblot capacity = ext_csd[EXT_CSD_SEC_CNT] << 0 2106c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 2107c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 2108c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; 2109c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN; 2110c744b6f6SJean-Jacques Hiblot if ((capacity >> 20) > 2 * 1024) 2111c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity; 2112c744b6f6SJean-Jacques Hiblot } 2113c744b6f6SJean-Jacques Hiblot 2114c744b6f6SJean-Jacques Hiblot /* The partition data may be non-zero but it is only 2115c744b6f6SJean-Jacques Hiblot * effective if PARTITION_SETTING_COMPLETED is set in 2116c744b6f6SJean-Jacques Hiblot * EXT_CSD, so ignore any data if this bit is not set, 2117c744b6f6SJean-Jacques Hiblot * except for enabling the high-capacity group size 2118c744b6f6SJean-Jacques Hiblot * definition (see below). 2119c744b6f6SJean-Jacques Hiblot */ 2120c744b6f6SJean-Jacques Hiblot part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] & 2121c744b6f6SJean-Jacques Hiblot EXT_CSD_PARTITION_SETTING_COMPLETED); 2122c744b6f6SJean-Jacques Hiblot 2123c744b6f6SJean-Jacques Hiblot /* store the partition info of emmc */ 2124c744b6f6SJean-Jacques Hiblot mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT]; 2125c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || 2126c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_BOOT_MULT]) 2127c744b6f6SJean-Jacques Hiblot mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; 2128c744b6f6SJean-Jacques Hiblot if (part_completed && 2129c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT)) 2130c744b6f6SJean-Jacques Hiblot mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]; 2131c744b6f6SJean-Jacques Hiblot 2132c744b6f6SJean-Jacques Hiblot mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17; 2133c744b6f6SJean-Jacques Hiblot 2134c744b6f6SJean-Jacques Hiblot mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17; 2135c744b6f6SJean-Jacques Hiblot 2136c744b6f6SJean-Jacques Hiblot for (i = 0; i < 4; i++) { 2137c744b6f6SJean-Jacques Hiblot int idx = EXT_CSD_GP_SIZE_MULT + i * 3; 2138c744b6f6SJean-Jacques Hiblot uint mult = (ext_csd[idx + 2] << 16) + 2139c744b6f6SJean-Jacques Hiblot (ext_csd[idx + 1] << 8) + ext_csd[idx]; 2140c744b6f6SJean-Jacques Hiblot if (mult) 2141c744b6f6SJean-Jacques Hiblot has_parts = true; 2142c744b6f6SJean-Jacques Hiblot if (!part_completed) 2143c744b6f6SJean-Jacques Hiblot continue; 2144c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] = mult; 2145c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= 2146c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 2147c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 2148c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] <<= 19; 2149c744b6f6SJean-Jacques Hiblot } 2150c744b6f6SJean-Jacques Hiblot 2151173c06dfSJean-Jacques Hiblot #ifndef CONFIG_SPL_BUILD 2152c744b6f6SJean-Jacques Hiblot if (part_completed) { 2153c744b6f6SJean-Jacques Hiblot mmc->enh_user_size = 2154c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) + 2155c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) + 2156c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_SIZE_MULT]; 2157c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 2158c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 2159c744b6f6SJean-Jacques Hiblot mmc->enh_user_size <<= 19; 2160c744b6f6SJean-Jacques Hiblot mmc->enh_user_start = 2161c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) + 2162c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) + 2163c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) + 2164c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_START_ADDR]; 2165c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity) 2166c744b6f6SJean-Jacques Hiblot mmc->enh_user_start <<= 9; 2167c744b6f6SJean-Jacques Hiblot } 2168173c06dfSJean-Jacques Hiblot #endif 2169c744b6f6SJean-Jacques Hiblot 2170c744b6f6SJean-Jacques Hiblot /* 2171c744b6f6SJean-Jacques Hiblot * Host needs to enable ERASE_GRP_DEF bit if device is 2172c744b6f6SJean-Jacques Hiblot * partitioned. This bit will be lost every time after a reset 2173c744b6f6SJean-Jacques Hiblot * or power off. This will affect erase size. 2174c744b6f6SJean-Jacques Hiblot */ 2175c744b6f6SJean-Jacques Hiblot if (part_completed) 2176c744b6f6SJean-Jacques Hiblot has_parts = true; 2177c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) && 2178c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) 2179c744b6f6SJean-Jacques Hiblot has_parts = true; 2180c744b6f6SJean-Jacques Hiblot if (has_parts) { 2181c744b6f6SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 2182c744b6f6SJean-Jacques Hiblot EXT_CSD_ERASE_GROUP_DEF, 1); 2183c744b6f6SJean-Jacques Hiblot 2184c744b6f6SJean-Jacques Hiblot if (err) 2185f7d5dffcSJean-Jacques Hiblot goto error; 2186c744b6f6SJean-Jacques Hiblot 2187c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 2188c744b6f6SJean-Jacques Hiblot } 2189c744b6f6SJean-Jacques Hiblot 2190c744b6f6SJean-Jacques Hiblot if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) { 2191e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE) 2192c744b6f6SJean-Jacques Hiblot /* Read out group size from ext_csd */ 2193c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = 2194c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 2195e6fa5a54SJean-Jacques Hiblot #endif 2196c744b6f6SJean-Jacques Hiblot /* 2197c744b6f6SJean-Jacques Hiblot * if high capacity and partition setting completed 2198c744b6f6SJean-Jacques Hiblot * SEC_COUNT is valid even if it is smaller than 2 GiB 2199c744b6f6SJean-Jacques Hiblot * JEDEC Standard JESD84-B45, 6.2.4 2200c744b6f6SJean-Jacques Hiblot */ 2201c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity && part_completed) { 2202c744b6f6SJean-Jacques Hiblot capacity = (ext_csd[EXT_CSD_SEC_CNT]) | 2203c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) | 2204c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) | 2205c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 3] << 24); 2206c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN; 2207c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity; 2208c744b6f6SJean-Jacques Hiblot } 2209e6fa5a54SJean-Jacques Hiblot } 2210e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE) 2211e6fa5a54SJean-Jacques Hiblot else { 2212c744b6f6SJean-Jacques Hiblot /* Calculate the group size from the csd value. */ 2213c744b6f6SJean-Jacques Hiblot int erase_gsz, erase_gmul; 2214c744b6f6SJean-Jacques Hiblot 2215c744b6f6SJean-Jacques Hiblot erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; 2216c744b6f6SJean-Jacques Hiblot erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; 2217c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = (erase_gsz + 1) 2218c744b6f6SJean-Jacques Hiblot * (erase_gmul + 1); 2219c744b6f6SJean-Jacques Hiblot } 2220e6fa5a54SJean-Jacques Hiblot #endif 2221b7a6e2c9SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING) 2222c744b6f6SJean-Jacques Hiblot mmc->hc_wp_grp_size = 1024 2223c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 2224c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 2225b7a6e2c9SJean-Jacques Hiblot #endif 2226c744b6f6SJean-Jacques Hiblot 2227c744b6f6SJean-Jacques Hiblot mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 2228c744b6f6SJean-Jacques Hiblot 2229c744b6f6SJean-Jacques Hiblot return 0; 2230f7d5dffcSJean-Jacques Hiblot error: 2231f7d5dffcSJean-Jacques Hiblot if (mmc->ext_csd) { 223262d77ceaSMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY) 2233f7d5dffcSJean-Jacques Hiblot free(mmc->ext_csd); 223462d77ceaSMarek Vasut #endif 2235f7d5dffcSJean-Jacques Hiblot mmc->ext_csd = NULL; 2236f7d5dffcSJean-Jacques Hiblot } 2237f7d5dffcSJean-Jacques Hiblot return err; 2238c744b6f6SJean-Jacques Hiblot } 2239c744b6f6SJean-Jacques Hiblot 2240fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc) 2241272cc70bSAndy Fleming { 2242f866a46dSStephen Warren int err, i; 2243272cc70bSAndy Fleming uint mult, freq; 2244c744b6f6SJean-Jacques Hiblot u64 cmult, csize; 2245272cc70bSAndy Fleming struct mmc_cmd cmd; 2246c40fdca6SSimon Glass struct blk_desc *bdesc; 2247272cc70bSAndy Fleming 2248d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON 2249d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ 2250d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; 2251d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R1; 2252d52ebf10SThomas Chou cmd.cmdarg = 1; 2253d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 2254d52ebf10SThomas Chou if (err) 2255d52ebf10SThomas Chou return err; 2256d52ebf10SThomas Chou } 2257d52ebf10SThomas Chou #endif 2258d52ebf10SThomas Chou 2259272cc70bSAndy Fleming /* Put the Card in Identify Mode */ 2260d52ebf10SThomas Chou cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : 2261d52ebf10SThomas Chou MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ 2262272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 2263272cc70bSAndy Fleming cmd.cmdarg = 0; 2264272cc70bSAndy Fleming 2265272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2266272cc70bSAndy Fleming 226783dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS 226883dc4227SKishon Vijay Abraham I if (err && (mmc->quirks & MMC_QUIRK_RETRY_SEND_CID)) { 226983dc4227SKishon Vijay Abraham I int retries = 4; 227083dc4227SKishon Vijay Abraham I /* 227183dc4227SKishon Vijay Abraham I * It has been seen that SEND_CID may fail on the first 227283dc4227SKishon Vijay Abraham I * attempt, let's try a few more time 227383dc4227SKishon Vijay Abraham I */ 227483dc4227SKishon Vijay Abraham I do { 227583dc4227SKishon Vijay Abraham I err = mmc_send_cmd(mmc, &cmd, NULL); 227683dc4227SKishon Vijay Abraham I if (!err) 227783dc4227SKishon Vijay Abraham I break; 227883dc4227SKishon Vijay Abraham I } while (retries--); 227983dc4227SKishon Vijay Abraham I } 228083dc4227SKishon Vijay Abraham I #endif 228183dc4227SKishon Vijay Abraham I 2282272cc70bSAndy Fleming if (err) 2283272cc70bSAndy Fleming return err; 2284272cc70bSAndy Fleming 2285272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16); 2286272cc70bSAndy Fleming 2287272cc70bSAndy Fleming /* 2288272cc70bSAndy Fleming * For MMC cards, set the Relative Address. 2289272cc70bSAndy Fleming * For SD cards, get the Relatvie Address. 2290272cc70bSAndy Fleming * This also puts the cards into Standby State 2291272cc70bSAndy Fleming */ 2292d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 2293272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; 2294272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 2295272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6; 2296272cc70bSAndy Fleming 2297272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2298272cc70bSAndy Fleming 2299272cc70bSAndy Fleming if (err) 2300272cc70bSAndy Fleming return err; 2301272cc70bSAndy Fleming 2302272cc70bSAndy Fleming if (IS_SD(mmc)) 2303998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff; 2304d52ebf10SThomas Chou } 2305272cc70bSAndy Fleming 2306272cc70bSAndy Fleming /* Get the Card-Specific Data */ 2307272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD; 2308272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 2309272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 2310272cc70bSAndy Fleming 2311272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2312272cc70bSAndy Fleming 2313272cc70bSAndy Fleming if (err) 2314272cc70bSAndy Fleming return err; 2315272cc70bSAndy Fleming 2316998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0]; 2317998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1]; 2318998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2]; 2319998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3]; 2320272cc70bSAndy Fleming 2321272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) { 23220b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf; 2323272cc70bSAndy Fleming 2324272cc70bSAndy Fleming switch (version) { 2325272cc70bSAndy Fleming case 0: 2326272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 2327272cc70bSAndy Fleming break; 2328272cc70bSAndy Fleming case 1: 2329272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4; 2330272cc70bSAndy Fleming break; 2331272cc70bSAndy Fleming case 2: 2332272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2; 2333272cc70bSAndy Fleming break; 2334272cc70bSAndy Fleming case 3: 2335272cc70bSAndy Fleming mmc->version = MMC_VERSION_3; 2336272cc70bSAndy Fleming break; 2337272cc70bSAndy Fleming case 4: 2338272cc70bSAndy Fleming mmc->version = MMC_VERSION_4; 2339272cc70bSAndy Fleming break; 2340272cc70bSAndy Fleming default: 2341272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 2342272cc70bSAndy Fleming break; 2343272cc70bSAndy Fleming } 2344272cc70bSAndy Fleming } 2345272cc70bSAndy Fleming 2346272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */ 23470b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)]; 23480b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; 2349272cc70bSAndy Fleming 235035f9e196SJean-Jacques Hiblot mmc->legacy_speed = freq * mult; 235135f9e196SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_LEGACY); 2352272cc70bSAndy Fleming 2353ab71188cSMarkus Niebel mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); 2354998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); 2355e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE) 2356272cc70bSAndy Fleming 2357272cc70bSAndy Fleming if (IS_SD(mmc)) 2358272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len; 2359272cc70bSAndy Fleming else 2360998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); 2361e6fa5a54SJean-Jacques Hiblot #endif 2362272cc70bSAndy Fleming 2363272cc70bSAndy Fleming if (mmc->high_capacity) { 2364272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16 2365272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16; 2366272cc70bSAndy Fleming cmult = 8; 2367272cc70bSAndy Fleming } else { 2368272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2 2369272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30; 2370272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15; 2371272cc70bSAndy Fleming } 2372272cc70bSAndy Fleming 2373f866a46dSStephen Warren mmc->capacity_user = (csize + 1) << (cmult + 2); 2374f866a46dSStephen Warren mmc->capacity_user *= mmc->read_bl_len; 2375f866a46dSStephen Warren mmc->capacity_boot = 0; 2376f866a46dSStephen Warren mmc->capacity_rpmb = 0; 2377f866a46dSStephen Warren for (i = 0; i < 4; i++) 2378f866a46dSStephen Warren mmc->capacity_gp[i] = 0; 2379272cc70bSAndy Fleming 23808bfa195eSSimon Glass if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN) 23818bfa195eSSimon Glass mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 2382272cc70bSAndy Fleming 2383e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE) 23848bfa195eSSimon Glass if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) 23858bfa195eSSimon Glass mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 2386e6fa5a54SJean-Jacques Hiblot #endif 2387272cc70bSAndy Fleming 2388ab71188cSMarkus Niebel if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) { 2389ab71188cSMarkus Niebel cmd.cmdidx = MMC_CMD_SET_DSR; 2390ab71188cSMarkus Niebel cmd.cmdarg = (mmc->dsr & 0xffff) << 16; 2391ab71188cSMarkus Niebel cmd.resp_type = MMC_RSP_NONE; 2392ab71188cSMarkus Niebel if (mmc_send_cmd(mmc, &cmd, NULL)) 2393d8e3d420SJean-Jacques Hiblot pr_warn("MMC: SET_DSR failed\n"); 2394ab71188cSMarkus Niebel } 2395ab71188cSMarkus Niebel 2396272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */ 2397d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 2398272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD; 2399fe8f7066SAjay Bhargav cmd.resp_type = MMC_RSP_R1; 2400272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 2401272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2402272cc70bSAndy Fleming 2403272cc70bSAndy Fleming if (err) 2404272cc70bSAndy Fleming return err; 2405d52ebf10SThomas Chou } 2406272cc70bSAndy Fleming 2407e6f99a56SLei Wen /* 2408e6f99a56SLei Wen * For SD, its erase group is always one sector 2409e6f99a56SLei Wen */ 2410e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE) 2411e6f99a56SLei Wen mmc->erase_grp_size = 1; 2412e6fa5a54SJean-Jacques Hiblot #endif 2413bc897b1dSLei Wen mmc->part_config = MMCPART_NOAVAILABLE; 2414c744b6f6SJean-Jacques Hiblot 2415dfda9d88SJean-Jacques Hiblot err = mmc_startup_v4(mmc); 24169cf199ebSDiego Santa Cruz if (err) 24179cf199ebSDiego Santa Cruz return err; 2418f866a46dSStephen Warren 2419c40fdca6SSimon Glass err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart); 2420f866a46dSStephen Warren if (err) 2421f866a46dSStephen Warren return err; 2422d23e2c09SSukumar Ghorai 242362d77ceaSMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY) 242462d77ceaSMarek Vasut mmc_set_clock(mmc, mmc->legacy_speed, false); 242562d77ceaSMarek Vasut mmc_select_mode(mmc, IS_SD(mmc) ? SD_LEGACY : MMC_LEGACY); 242662d77ceaSMarek Vasut mmc_set_bus_width(mmc, 1); 242762d77ceaSMarek Vasut #else 242801298da3SJean-Jacques Hiblot if (IS_SD(mmc)) { 242901298da3SJean-Jacques Hiblot err = sd_get_capabilities(mmc); 243001298da3SJean-Jacques Hiblot if (err) 243101298da3SJean-Jacques Hiblot return err; 243201298da3SJean-Jacques Hiblot err = sd_select_mode_and_width(mmc, mmc->card_caps); 243301298da3SJean-Jacques Hiblot } else { 243401298da3SJean-Jacques Hiblot err = mmc_get_capabilities(mmc); 243501298da3SJean-Jacques Hiblot if (err) 243601298da3SJean-Jacques Hiblot return err; 243701298da3SJean-Jacques Hiblot mmc_select_mode_and_width(mmc, mmc->card_caps); 243801298da3SJean-Jacques Hiblot } 243962d77ceaSMarek Vasut #endif 2440272cc70bSAndy Fleming if (err) 2441272cc70bSAndy Fleming return err; 2442272cc70bSAndy Fleming 244301298da3SJean-Jacques Hiblot mmc->best_mode = mmc->selected_mode; 2444272cc70bSAndy Fleming 24455af8f45cSAndrew Gabbasov /* Fix the block length for DDR mode */ 24465af8f45cSAndrew Gabbasov if (mmc->ddr_mode) { 24475af8f45cSAndrew Gabbasov mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 2448e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE) 24495af8f45cSAndrew Gabbasov mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 2450e6fa5a54SJean-Jacques Hiblot #endif 24515af8f45cSAndrew Gabbasov } 24525af8f45cSAndrew Gabbasov 2453272cc70bSAndy Fleming /* fill in device description */ 2454c40fdca6SSimon Glass bdesc = mmc_get_blk_desc(mmc); 2455c40fdca6SSimon Glass bdesc->lun = 0; 2456c40fdca6SSimon Glass bdesc->hwpart = 0; 2457c40fdca6SSimon Glass bdesc->type = 0; 2458c40fdca6SSimon Glass bdesc->blksz = mmc->read_bl_len; 2459c40fdca6SSimon Glass bdesc->log2blksz = LOG2(bdesc->blksz); 2460c40fdca6SSimon Glass bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len); 2461fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \ 2462fc011f64SSjoerd Simons (defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \ 2463fc011f64SSjoerd Simons !defined(CONFIG_USE_TINY_PRINTF)) 2464c40fdca6SSimon Glass sprintf(bdesc->vendor, "Man %06x Snr %04x%04x", 2465babce5f6STaylor Hutt mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), 2466babce5f6STaylor Hutt (mmc->cid[3] >> 16) & 0xffff); 2467c40fdca6SSimon Glass sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff, 24680b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 2469babce5f6STaylor Hutt (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff, 2470babce5f6STaylor Hutt (mmc->cid[2] >> 24) & 0xff); 2471c40fdca6SSimon Glass sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf, 2472babce5f6STaylor Hutt (mmc->cid[2] >> 16) & 0xf); 247356196826SPaul Burton #else 2474c40fdca6SSimon Glass bdesc->vendor[0] = 0; 2475c40fdca6SSimon Glass bdesc->product[0] = 0; 2476c40fdca6SSimon Glass bdesc->revision[0] = 0; 247756196826SPaul Burton #endif 2478272cc70bSAndy Fleming 2479eef05fd3SAndre Przywara #if !defined(CONFIG_DM_MMC) && (!defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)) 2480eef05fd3SAndre Przywara part_init(bdesc); 2481eef05fd3SAndre Przywara #endif 2482eef05fd3SAndre Przywara 2483272cc70bSAndy Fleming return 0; 2484272cc70bSAndy Fleming } 2485272cc70bSAndy Fleming 2486fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc) 2487272cc70bSAndy Fleming { 2488272cc70bSAndy Fleming struct mmc_cmd cmd; 2489272cc70bSAndy Fleming int err; 2490272cc70bSAndy Fleming 2491272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND; 2492272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ 249393bfd616SPantelis Antoniou cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa; 2494272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7; 2495272cc70bSAndy Fleming 2496272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2497272cc70bSAndy Fleming 2498272cc70bSAndy Fleming if (err) 2499272cc70bSAndy Fleming return err; 2500272cc70bSAndy Fleming 2501998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa) 2502915ffa52SJaehoon Chung return -EOPNOTSUPP; 2503272cc70bSAndy Fleming else 2504272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 2505272cc70bSAndy Fleming 2506272cc70bSAndy Fleming return 0; 2507272cc70bSAndy Fleming } 2508272cc70bSAndy Fleming 2509c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 251095de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */ 251195de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void) 251295de9ab2SPaul Kocialkowski { 251395de9ab2SPaul Kocialkowski } 251405cbeb7cSSimon Glass #endif 251595de9ab2SPaul Kocialkowski 25162051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc) 25172051aefeSPeng Fan { 2518c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 251906ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR) 25202051aefeSPeng Fan int ret; 25212051aefeSPeng Fan 25222051aefeSPeng Fan ret = device_get_supply_regulator(mmc->dev, "vmmc-supply", 252306ec045fSJean-Jacques Hiblot &mmc->vmmc_supply); 252406ec045fSJean-Jacques Hiblot if (ret) 2525d4d64889SMasahiro Yamada pr_debug("%s: No vmmc supply\n", mmc->dev->name); 25262051aefeSPeng Fan 252706ec045fSJean-Jacques Hiblot ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply", 252806ec045fSJean-Jacques Hiblot &mmc->vqmmc_supply); 252906ec045fSJean-Jacques Hiblot if (ret) 2530d4d64889SMasahiro Yamada pr_debug("%s: No vqmmc supply\n", mmc->dev->name); 25312051aefeSPeng Fan #endif 253205cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */ 253305cbeb7cSSimon Glass /* 253405cbeb7cSSimon Glass * Driver model should use a regulator, as above, rather than calling 253505cbeb7cSSimon Glass * out to board code. 253605cbeb7cSSimon Glass */ 253705cbeb7cSSimon Glass board_mmc_power_init(); 253805cbeb7cSSimon Glass #endif 25392051aefeSPeng Fan return 0; 25402051aefeSPeng Fan } 25412051aefeSPeng Fan 2542fb7c3bebSKishon Vijay Abraham I /* 2543fb7c3bebSKishon Vijay Abraham I * put the host in the initial state: 2544fb7c3bebSKishon Vijay Abraham I * - turn on Vdd (card power supply) 2545fb7c3bebSKishon Vijay Abraham I * - configure the bus width and clock to minimal values 2546fb7c3bebSKishon Vijay Abraham I */ 2547fb7c3bebSKishon Vijay Abraham I static void mmc_set_initial_state(struct mmc *mmc) 2548fb7c3bebSKishon Vijay Abraham I { 2549fb7c3bebSKishon Vijay Abraham I int err; 2550fb7c3bebSKishon Vijay Abraham I 2551fb7c3bebSKishon Vijay Abraham I /* First try to set 3.3V. If it fails set to 1.8V */ 2552fb7c3bebSKishon Vijay Abraham I err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_330); 2553fb7c3bebSKishon Vijay Abraham I if (err != 0) 2554fb7c3bebSKishon Vijay Abraham I err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_180); 2555fb7c3bebSKishon Vijay Abraham I if (err != 0) 2556d8e3d420SJean-Jacques Hiblot pr_warn("mmc: failed to set signal voltage\n"); 2557fb7c3bebSKishon Vijay Abraham I 2558fb7c3bebSKishon Vijay Abraham I mmc_select_mode(mmc, MMC_LEGACY); 2559fb7c3bebSKishon Vijay Abraham I mmc_set_bus_width(mmc, 1); 256065117182SJaehoon Chung mmc_set_clock(mmc, 0, MMC_CLK_ENABLE); 2561fb7c3bebSKishon Vijay Abraham I } 2562fb7c3bebSKishon Vijay Abraham I 2563fb7c3bebSKishon Vijay Abraham I static int mmc_power_on(struct mmc *mmc) 2564fb7c3bebSKishon Vijay Abraham I { 2565fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR) 2566fb7c3bebSKishon Vijay Abraham I if (mmc->vmmc_supply) { 2567fb7c3bebSKishon Vijay Abraham I int ret = regulator_set_enable(mmc->vmmc_supply, true); 2568fb7c3bebSKishon Vijay Abraham I 2569fb7c3bebSKishon Vijay Abraham I if (ret) { 2570fb7c3bebSKishon Vijay Abraham I puts("Error enabling VMMC supply\n"); 2571fb7c3bebSKishon Vijay Abraham I return ret; 2572fb7c3bebSKishon Vijay Abraham I } 2573fb7c3bebSKishon Vijay Abraham I } 2574fb7c3bebSKishon Vijay Abraham I #endif 2575fb7c3bebSKishon Vijay Abraham I return 0; 2576fb7c3bebSKishon Vijay Abraham I } 2577fb7c3bebSKishon Vijay Abraham I 2578fb7c3bebSKishon Vijay Abraham I static int mmc_power_off(struct mmc *mmc) 2579fb7c3bebSKishon Vijay Abraham I { 258065117182SJaehoon Chung mmc_set_clock(mmc, 0, MMC_CLK_DISABLE); 2581fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR) 2582fb7c3bebSKishon Vijay Abraham I if (mmc->vmmc_supply) { 2583fb7c3bebSKishon Vijay Abraham I int ret = regulator_set_enable(mmc->vmmc_supply, false); 2584fb7c3bebSKishon Vijay Abraham I 2585fb7c3bebSKishon Vijay Abraham I if (ret) { 2586d4d64889SMasahiro Yamada pr_debug("Error disabling VMMC supply\n"); 2587fb7c3bebSKishon Vijay Abraham I return ret; 2588fb7c3bebSKishon Vijay Abraham I } 2589fb7c3bebSKishon Vijay Abraham I } 2590fb7c3bebSKishon Vijay Abraham I #endif 2591fb7c3bebSKishon Vijay Abraham I return 0; 2592fb7c3bebSKishon Vijay Abraham I } 2593fb7c3bebSKishon Vijay Abraham I 2594fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc) 2595fb7c3bebSKishon Vijay Abraham I { 2596fb7c3bebSKishon Vijay Abraham I int ret; 2597fb7c3bebSKishon Vijay Abraham I 2598fb7c3bebSKishon Vijay Abraham I ret = mmc_power_off(mmc); 2599fb7c3bebSKishon Vijay Abraham I if (ret) 2600fb7c3bebSKishon Vijay Abraham I return ret; 2601fb7c3bebSKishon Vijay Abraham I /* 2602fb7c3bebSKishon Vijay Abraham I * SD spec recommends at least 1ms of delay. Let's wait for 2ms 2603fb7c3bebSKishon Vijay Abraham I * to be on the safer side. 2604fb7c3bebSKishon Vijay Abraham I */ 2605fb7c3bebSKishon Vijay Abraham I udelay(2000); 2606fb7c3bebSKishon Vijay Abraham I return mmc_power_on(mmc); 2607fb7c3bebSKishon Vijay Abraham I } 2608fb7c3bebSKishon Vijay Abraham I 26096c09eba5SJon Nettleton int mmc_get_op_cond(struct mmc *mmc) 2610272cc70bSAndy Fleming { 2611c10b85d6SJean-Jacques Hiblot bool uhs_en = supports_uhs(mmc->cfg->host_caps); 2612afd5932bSMacpaul Lin int err; 2613272cc70bSAndy Fleming 2614bc897b1dSLei Wen if (mmc->has_init) 2615bc897b1dSLei Wen return 0; 2616bc897b1dSLei Wen 26175a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 26185a8dbdc6SYangbo Lu mmc_adapter_card_type_ident(); 26195a8dbdc6SYangbo Lu #endif 26202051aefeSPeng Fan err = mmc_power_init(mmc); 26212051aefeSPeng Fan if (err) 26222051aefeSPeng Fan return err; 262395de9ab2SPaul Kocialkowski 262483dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS 262583dc4227SKishon Vijay Abraham I mmc->quirks = MMC_QUIRK_RETRY_SET_BLOCKLEN | 262683dc4227SKishon Vijay Abraham I MMC_QUIRK_RETRY_SEND_CID; 262783dc4227SKishon Vijay Abraham I #endif 262883dc4227SKishon Vijay Abraham I 262904a2ea24SJean-Jacques Hiblot err = mmc_power_cycle(mmc); 263004a2ea24SJean-Jacques Hiblot if (err) { 263104a2ea24SJean-Jacques Hiblot /* 263204a2ea24SJean-Jacques Hiblot * if power cycling is not supported, we should not try 263304a2ea24SJean-Jacques Hiblot * to use the UHS modes, because we wouldn't be able to 263404a2ea24SJean-Jacques Hiblot * recover from an error during the UHS initialization. 263504a2ea24SJean-Jacques Hiblot */ 2636d4d64889SMasahiro Yamada pr_debug("Unable to do a full power cycle. Disabling the UHS modes for safety\n"); 263704a2ea24SJean-Jacques Hiblot uhs_en = false; 263804a2ea24SJean-Jacques Hiblot mmc->host_caps &= ~UHS_CAPS; 2639fb7c3bebSKishon Vijay Abraham I err = mmc_power_on(mmc); 264004a2ea24SJean-Jacques Hiblot } 2641fb7c3bebSKishon Vijay Abraham I if (err) 2642fb7c3bebSKishon Vijay Abraham I return err; 2643fb7c3bebSKishon Vijay Abraham I 2644e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 26458ca51e51SSimon Glass /* The device has already been probed ready for use */ 26468ca51e51SSimon Glass #else 2647ab769f22SPantelis Antoniou /* made sure it's not NULL earlier */ 264893bfd616SPantelis Antoniou err = mmc->cfg->ops->init(mmc); 2649272cc70bSAndy Fleming if (err) 2650272cc70bSAndy Fleming return err; 26518ca51e51SSimon Glass #endif 2652786e8f81SAndrew Gabbasov mmc->ddr_mode = 0; 2653aff5d3c8SKishon Vijay Abraham I 2654c10b85d6SJean-Jacques Hiblot retry: 2655fb7c3bebSKishon Vijay Abraham I mmc_set_initial_state(mmc); 2656318a7a57SJean-Jacques Hiblot mmc_send_init_stream(mmc); 2657318a7a57SJean-Jacques Hiblot 2658272cc70bSAndy Fleming /* Reset the Card */ 2659272cc70bSAndy Fleming err = mmc_go_idle(mmc); 2660272cc70bSAndy Fleming 2661272cc70bSAndy Fleming if (err) 2662272cc70bSAndy Fleming return err; 2663272cc70bSAndy Fleming 2664bc897b1dSLei Wen /* The internal partition reset to user partition(0) at every CMD0*/ 2665c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->hwpart = 0; 2666bc897b1dSLei Wen 2667272cc70bSAndy Fleming /* Test for SD version 2 */ 2668272cc70bSAndy Fleming err = mmc_send_if_cond(mmc); 2669272cc70bSAndy Fleming 2670272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */ 2671c10b85d6SJean-Jacques Hiblot err = sd_send_op_cond(mmc, uhs_en); 2672c10b85d6SJean-Jacques Hiblot if (err && uhs_en) { 2673c10b85d6SJean-Jacques Hiblot uhs_en = false; 2674c10b85d6SJean-Jacques Hiblot mmc_power_cycle(mmc); 2675c10b85d6SJean-Jacques Hiblot goto retry; 2676c10b85d6SJean-Jacques Hiblot } 2677272cc70bSAndy Fleming 2678272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */ 2679915ffa52SJaehoon Chung if (err == -ETIMEDOUT) { 2680272cc70bSAndy Fleming err = mmc_send_op_cond(mmc); 2681272cc70bSAndy Fleming 2682bd47c135SAndrew Gabbasov if (err) { 268356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2684d8e3d420SJean-Jacques Hiblot pr_err("Card did not respond to voltage select!\n"); 268556196826SPaul Burton #endif 2686915ffa52SJaehoon Chung return -EOPNOTSUPP; 2687272cc70bSAndy Fleming } 2688272cc70bSAndy Fleming } 2689272cc70bSAndy Fleming 26906c09eba5SJon Nettleton return err; 26916c09eba5SJon Nettleton } 26926c09eba5SJon Nettleton 26936c09eba5SJon Nettleton int mmc_start_init(struct mmc *mmc) 26946c09eba5SJon Nettleton { 26956c09eba5SJon Nettleton bool no_card; 26966c09eba5SJon Nettleton int err = 0; 26976c09eba5SJon Nettleton 26986c09eba5SJon Nettleton /* 26996c09eba5SJon Nettleton * all hosts are capable of 1 bit bus-width and able to use the legacy 27006c09eba5SJon Nettleton * timings. 27016c09eba5SJon Nettleton */ 27026c09eba5SJon Nettleton mmc->host_caps = mmc->cfg->host_caps | MMC_CAP(SD_LEGACY) | 27036c09eba5SJon Nettleton MMC_CAP(MMC_LEGACY) | MMC_MODE_1BIT; 27046c09eba5SJon Nettleton 27056c09eba5SJon Nettleton #if !defined(CONFIG_MMC_BROKEN_CD) 27066c09eba5SJon Nettleton /* we pretend there's no card when init is NULL */ 27076c09eba5SJon Nettleton no_card = mmc_getcd(mmc) == 0; 27086c09eba5SJon Nettleton #else 27096c09eba5SJon Nettleton no_card = 0; 27106c09eba5SJon Nettleton #endif 27116c09eba5SJon Nettleton #if !CONFIG_IS_ENABLED(DM_MMC) 27126c09eba5SJon Nettleton no_card = no_card || (mmc->cfg->ops->init == NULL); 27136c09eba5SJon Nettleton #endif 27146c09eba5SJon Nettleton if (no_card) { 27156c09eba5SJon Nettleton mmc->has_init = 0; 27166c09eba5SJon Nettleton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 27176c09eba5SJon Nettleton pr_err("MMC: no card present\n"); 27186c09eba5SJon Nettleton #endif 27196c09eba5SJon Nettleton return -ENOMEDIUM; 27206c09eba5SJon Nettleton } 27216c09eba5SJon Nettleton 27226c09eba5SJon Nettleton err = mmc_get_op_cond(mmc); 27236c09eba5SJon Nettleton 2724bd47c135SAndrew Gabbasov if (!err) 2725e9550449SChe-Liang Chiou mmc->init_in_progress = 1; 2726e9550449SChe-Liang Chiou 2727e9550449SChe-Liang Chiou return err; 2728e9550449SChe-Liang Chiou } 2729e9550449SChe-Liang Chiou 2730e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc) 2731e9550449SChe-Liang Chiou { 2732e9550449SChe-Liang Chiou int err = 0; 2733e9550449SChe-Liang Chiou 2734bd47c135SAndrew Gabbasov mmc->init_in_progress = 0; 2735e9550449SChe-Liang Chiou if (mmc->op_cond_pending) 2736e9550449SChe-Liang Chiou err = mmc_complete_op_cond(mmc); 2737e9550449SChe-Liang Chiou 2738e9550449SChe-Liang Chiou if (!err) 2739bc897b1dSLei Wen err = mmc_startup(mmc); 2740bc897b1dSLei Wen if (err) 2741bc897b1dSLei Wen mmc->has_init = 0; 2742bc897b1dSLei Wen else 2743bc897b1dSLei Wen mmc->has_init = 1; 2744e9550449SChe-Liang Chiou return err; 2745e9550449SChe-Liang Chiou } 2746e9550449SChe-Liang Chiou 2747e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc) 2748e9550449SChe-Liang Chiou { 2749bd47c135SAndrew Gabbasov int err = 0; 275036332b6eSVipul Kumar __maybe_unused ulong start; 2751c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 275233fb211dSSimon Glass struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev); 2753e9550449SChe-Liang Chiou 275433fb211dSSimon Glass upriv->mmc = mmc; 275533fb211dSSimon Glass #endif 2756e9550449SChe-Liang Chiou if (mmc->has_init) 2757e9550449SChe-Liang Chiou return 0; 2758d803fea5SMateusz Zalega 2759d803fea5SMateusz Zalega start = get_timer(0); 2760d803fea5SMateusz Zalega 2761e9550449SChe-Liang Chiou if (!mmc->init_in_progress) 2762e9550449SChe-Liang Chiou err = mmc_start_init(mmc); 2763e9550449SChe-Liang Chiou 2764bd47c135SAndrew Gabbasov if (!err) 2765e9550449SChe-Liang Chiou err = mmc_complete_init(mmc); 2766919b4858SJagan Teki if (err) 2767d4d64889SMasahiro Yamada pr_info("%s: %d, time %lu\n", __func__, err, get_timer(start)); 2768919b4858SJagan Teki 2769bc897b1dSLei Wen return err; 2770272cc70bSAndy Fleming } 2771272cc70bSAndy Fleming 2772ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val) 2773ab71188cSMarkus Niebel { 2774ab71188cSMarkus Niebel mmc->dsr = val; 2775ab71188cSMarkus Niebel return 0; 2776ab71188cSMarkus Niebel } 2777ab71188cSMarkus Niebel 2778cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */ 2779cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis) 2780272cc70bSAndy Fleming { 2781272cc70bSAndy Fleming return -1; 2782272cc70bSAndy Fleming } 2783272cc70bSAndy Fleming 2784cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */ 2785cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis) 2786cee9ab7cSJeroen Hofstee { 2787cee9ab7cSJeroen Hofstee return -1; 2788cee9ab7cSJeroen Hofstee } 2789272cc70bSAndy Fleming 2790e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit) 2791e9550449SChe-Liang Chiou { 2792e9550449SChe-Liang Chiou mmc->preinit = preinit; 2793e9550449SChe-Liang Chiou } 2794e9550449SChe-Liang Chiou 27958a856db2SFaiz Abbas #if CONFIG_IS_ENABLED(DM_MMC) 27968e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 27978e3332e2SSjoerd Simons { 27984a1db6d8SSimon Glass int ret, i; 27998e3332e2SSjoerd Simons struct uclass *uc; 28004a1db6d8SSimon Glass struct udevice *dev; 28018e3332e2SSjoerd Simons 28028e3332e2SSjoerd Simons ret = uclass_get(UCLASS_MMC, &uc); 28038e3332e2SSjoerd Simons if (ret) 28048e3332e2SSjoerd Simons return ret; 28058e3332e2SSjoerd Simons 28064a1db6d8SSimon Glass /* 28074a1db6d8SSimon Glass * Try to add them in sequence order. Really with driver model we 28084a1db6d8SSimon Glass * should allow holes, but the current MMC list does not allow that. 28094a1db6d8SSimon Glass * So if we request 0, 1, 3 we will get 0, 1, 2. 28104a1db6d8SSimon Glass */ 28114a1db6d8SSimon Glass for (i = 0; ; i++) { 28124a1db6d8SSimon Glass ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev); 28134a1db6d8SSimon Glass if (ret == -ENODEV) 28144a1db6d8SSimon Glass break; 28154a1db6d8SSimon Glass } 28164a1db6d8SSimon Glass uclass_foreach_dev(dev, uc) { 28174a1db6d8SSimon Glass ret = device_probe(dev); 28188e3332e2SSjoerd Simons if (ret) 2819d8e3d420SJean-Jacques Hiblot pr_err("%s - probe failed: %d\n", dev->name, ret); 28208e3332e2SSjoerd Simons } 28218e3332e2SSjoerd Simons 28228e3332e2SSjoerd Simons return 0; 28238e3332e2SSjoerd Simons } 28248e3332e2SSjoerd Simons #else 28258e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 28268e3332e2SSjoerd Simons { 28278e3332e2SSjoerd Simons if (board_mmc_init(bis) < 0) 28288e3332e2SSjoerd Simons cpu_mmc_init(bis); 28298e3332e2SSjoerd Simons 28308e3332e2SSjoerd Simons return 0; 28318e3332e2SSjoerd Simons } 28328e3332e2SSjoerd Simons #endif 2833e9550449SChe-Liang Chiou 2834272cc70bSAndy Fleming int mmc_initialize(bd_t *bis) 2835272cc70bSAndy Fleming { 28361b26bab1SDaniel Kochmański static int initialized = 0; 28378e3332e2SSjoerd Simons int ret; 28381b26bab1SDaniel Kochmański if (initialized) /* Avoid initializing mmc multiple times */ 28391b26bab1SDaniel Kochmański return 0; 28401b26bab1SDaniel Kochmański initialized = 1; 28411b26bab1SDaniel Kochmański 2842c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK) 2843b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY) 2844c40fdca6SSimon Glass mmc_list_init(); 2845c40fdca6SSimon Glass #endif 2846b5b838f1SMarek Vasut #endif 28478e3332e2SSjoerd Simons ret = mmc_probe(bis); 28488e3332e2SSjoerd Simons if (ret) 28498e3332e2SSjoerd Simons return ret; 2850272cc70bSAndy Fleming 2851bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD 2852272cc70bSAndy Fleming print_mmc_devices(','); 2853bb0dc108SYing Zhang #endif 2854272cc70bSAndy Fleming 2855c40fdca6SSimon Glass mmc_do_preinit(); 2856272cc70bSAndy Fleming return 0; 2857272cc70bSAndy Fleming } 2858cd3d4880STomas Melin 2859cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE 2860cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc) 2861cd3d4880STomas Melin { 2862cd3d4880STomas Melin int err; 2863cd3d4880STomas Melin ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 2864cd3d4880STomas Melin 2865cd3d4880STomas Melin err = mmc_send_ext_csd(mmc, ext_csd); 2866cd3d4880STomas Melin if (err) { 2867cd3d4880STomas Melin puts("Could not get ext_csd register values\n"); 2868cd3d4880STomas Melin return err; 2869cd3d4880STomas Melin } 2870cd3d4880STomas Melin 2871cd3d4880STomas Melin if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) { 2872cd3d4880STomas Melin puts("Background operations not supported on device\n"); 2873cd3d4880STomas Melin return -EMEDIUMTYPE; 2874cd3d4880STomas Melin } 2875cd3d4880STomas Melin 2876cd3d4880STomas Melin if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) { 2877cd3d4880STomas Melin puts("Background operations already enabled\n"); 2878cd3d4880STomas Melin return 0; 2879cd3d4880STomas Melin } 2880cd3d4880STomas Melin 2881cd3d4880STomas Melin err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1); 2882cd3d4880STomas Melin if (err) { 2883cd3d4880STomas Melin puts("Failed to enable manual background operations\n"); 2884cd3d4880STomas Melin return err; 2885cd3d4880STomas Melin } 2886cd3d4880STomas Melin 2887cd3d4880STomas Melin puts("Enabled manual background operations\n"); 2888cd3d4880STomas Melin 2889cd3d4880STomas Melin return 0; 2890cd3d4880STomas Melin } 2891cd3d4880STomas Melin #endif 2892