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); 26*62d77ceaSMarek 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)", 15035f9e196SJean-Jacques Hiblot }; 15135f9e196SJean-Jacques Hiblot 15235f9e196SJean-Jacques Hiblot if (mode >= MMC_MODES_END) 15335f9e196SJean-Jacques Hiblot return "Unknown mode"; 15435f9e196SJean-Jacques Hiblot else 15535f9e196SJean-Jacques Hiblot return names[mode]; 15635f9e196SJean-Jacques Hiblot } 15735f9e196SJean-Jacques Hiblot #endif 15835f9e196SJean-Jacques Hiblot 15905038576SJean-Jacques Hiblot static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode) 16005038576SJean-Jacques Hiblot { 16105038576SJean-Jacques Hiblot static const int freqs[] = { 1621b313aa3SJaehoon Chung [MMC_LEGACY] = 25000000, 16305038576SJean-Jacques Hiblot [SD_LEGACY] = 25000000, 16405038576SJean-Jacques Hiblot [MMC_HS] = 26000000, 16505038576SJean-Jacques Hiblot [SD_HS] = 50000000, 1661b313aa3SJaehoon Chung [MMC_HS_52] = 52000000, 1671b313aa3SJaehoon Chung [MMC_DDR_52] = 52000000, 16805038576SJean-Jacques Hiblot [UHS_SDR12] = 25000000, 16905038576SJean-Jacques Hiblot [UHS_SDR25] = 50000000, 17005038576SJean-Jacques Hiblot [UHS_SDR50] = 100000000, 17105038576SJean-Jacques Hiblot [UHS_DDR50] = 50000000, 172f99c2efeSJean-Jacques Hiblot [UHS_SDR104] = 208000000, 17305038576SJean-Jacques Hiblot [MMC_HS_200] = 200000000, 17405038576SJean-Jacques Hiblot }; 17505038576SJean-Jacques Hiblot 17605038576SJean-Jacques Hiblot if (mode == MMC_LEGACY) 17705038576SJean-Jacques Hiblot return mmc->legacy_speed; 17805038576SJean-Jacques Hiblot else if (mode >= MMC_MODES_END) 17905038576SJean-Jacques Hiblot return 0; 18005038576SJean-Jacques Hiblot else 18105038576SJean-Jacques Hiblot return freqs[mode]; 18205038576SJean-Jacques Hiblot } 18305038576SJean-Jacques Hiblot 18435f9e196SJean-Jacques Hiblot static int mmc_select_mode(struct mmc *mmc, enum bus_mode mode) 18535f9e196SJean-Jacques Hiblot { 18635f9e196SJean-Jacques Hiblot mmc->selected_mode = mode; 18705038576SJean-Jacques Hiblot mmc->tran_speed = mmc_mode2freq(mmc, mode); 1883862b854SJean-Jacques Hiblot mmc->ddr_mode = mmc_is_mode_ddr(mode); 189d4d64889SMasahiro Yamada pr_debug("selecting mode %s (freq : %d MHz)\n", mmc_mode_name(mode), 19035f9e196SJean-Jacques Hiblot mmc->tran_speed / 1000000); 19135f9e196SJean-Jacques Hiblot return 0; 19235f9e196SJean-Jacques Hiblot } 19335f9e196SJean-Jacques Hiblot 194e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 195c0c76ebaSSimon Glass int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data) 196c0c76ebaSSimon Glass { 197c0c76ebaSSimon Glass int ret; 198c0c76ebaSSimon Glass 199c0c76ebaSSimon Glass mmmc_trace_before_send(mmc, cmd); 200c0c76ebaSSimon Glass ret = mmc->cfg->ops->send_cmd(mmc, cmd, data); 201c0c76ebaSSimon Glass mmmc_trace_after_send(mmc, cmd, ret); 202c0c76ebaSSimon Glass 2038635ff9eSMarek Vasut return ret; 204272cc70bSAndy Fleming } 2058ca51e51SSimon Glass #endif 206272cc70bSAndy Fleming 207da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout) 2085d4fc8d9SRaffaele Recalcati { 2095d4fc8d9SRaffaele Recalcati struct mmc_cmd cmd; 210d617c426SJan Kloetzke int err, retries = 5; 2115d4fc8d9SRaffaele Recalcati 2125d4fc8d9SRaffaele Recalcati cmd.cmdidx = MMC_CMD_SEND_STATUS; 2135d4fc8d9SRaffaele Recalcati cmd.resp_type = MMC_RSP_R1; 214aaf3d41aSMarek Vasut if (!mmc_host_is_spi(mmc)) 215aaf3d41aSMarek Vasut cmd.cmdarg = mmc->rca << 16; 2165d4fc8d9SRaffaele Recalcati 2171677eef4SAndrew Gabbasov while (1) { 2185d4fc8d9SRaffaele Recalcati err = mmc_send_cmd(mmc, &cmd, NULL); 219d617c426SJan Kloetzke if (!err) { 220d617c426SJan Kloetzke if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) && 221d617c426SJan Kloetzke (cmd.response[0] & MMC_STATUS_CURR_STATE) != 222d617c426SJan Kloetzke MMC_STATE_PRG) 2235d4fc8d9SRaffaele Recalcati break; 224d0c221feSJean-Jacques Hiblot 225d0c221feSJean-Jacques Hiblot if (cmd.response[0] & MMC_STATUS_MASK) { 22656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 227d8e3d420SJean-Jacques Hiblot pr_err("Status Error: 0x%08X\n", 228d617c426SJan Kloetzke cmd.response[0]); 22956196826SPaul Burton #endif 230915ffa52SJaehoon Chung return -ECOMM; 231d617c426SJan Kloetzke } 232d617c426SJan Kloetzke } else if (--retries < 0) 233d617c426SJan Kloetzke return err; 2345d4fc8d9SRaffaele Recalcati 2351677eef4SAndrew Gabbasov if (timeout-- <= 0) 2361677eef4SAndrew Gabbasov break; 2375d4fc8d9SRaffaele Recalcati 2381677eef4SAndrew Gabbasov udelay(1000); 2391677eef4SAndrew Gabbasov } 2405d4fc8d9SRaffaele Recalcati 241c0c76ebaSSimon Glass mmc_trace_state(mmc, &cmd); 2425b0c942fSJongman Heo if (timeout <= 0) { 24356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 244d8e3d420SJean-Jacques Hiblot pr_err("Timeout waiting card ready\n"); 24556196826SPaul Burton #endif 246915ffa52SJaehoon Chung return -ETIMEDOUT; 2475d4fc8d9SRaffaele Recalcati } 2485d4fc8d9SRaffaele Recalcati 2495d4fc8d9SRaffaele Recalcati return 0; 2505d4fc8d9SRaffaele Recalcati } 2515d4fc8d9SRaffaele Recalcati 252da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len) 253272cc70bSAndy Fleming { 254272cc70bSAndy Fleming struct mmc_cmd cmd; 25583dc4227SKishon Vijay Abraham I int err; 256272cc70bSAndy Fleming 257786e8f81SAndrew Gabbasov if (mmc->ddr_mode) 258d22e3d46SJaehoon Chung return 0; 259d22e3d46SJaehoon Chung 260272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SET_BLOCKLEN; 261272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 262272cc70bSAndy Fleming cmd.cmdarg = len; 263272cc70bSAndy Fleming 26483dc4227SKishon Vijay Abraham I err = mmc_send_cmd(mmc, &cmd, NULL); 26583dc4227SKishon Vijay Abraham I 26683dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS 26783dc4227SKishon Vijay Abraham I if (err && (mmc->quirks & MMC_QUIRK_RETRY_SET_BLOCKLEN)) { 26883dc4227SKishon Vijay Abraham I int retries = 4; 26983dc4227SKishon Vijay Abraham I /* 27083dc4227SKishon Vijay Abraham I * It has been seen that SET_BLOCKLEN may fail on the first 27183dc4227SKishon Vijay Abraham I * attempt, let's try a few more time 27283dc4227SKishon Vijay Abraham I */ 27383dc4227SKishon Vijay Abraham I do { 27483dc4227SKishon Vijay Abraham I err = mmc_send_cmd(mmc, &cmd, NULL); 27583dc4227SKishon Vijay Abraham I if (!err) 27683dc4227SKishon Vijay Abraham I break; 27783dc4227SKishon Vijay Abraham I } while (retries--); 27883dc4227SKishon Vijay Abraham I } 27983dc4227SKishon Vijay Abraham I #endif 28083dc4227SKishon Vijay Abraham I 28183dc4227SKishon Vijay Abraham I return err; 282272cc70bSAndy Fleming } 283272cc70bSAndy Fleming 284f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 2859815e3baSJean-Jacques Hiblot static const u8 tuning_blk_pattern_4bit[] = { 2869815e3baSJean-Jacques Hiblot 0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc, 2879815e3baSJean-Jacques Hiblot 0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef, 2889815e3baSJean-Jacques Hiblot 0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb, 2899815e3baSJean-Jacques Hiblot 0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef, 2909815e3baSJean-Jacques Hiblot 0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c, 2919815e3baSJean-Jacques Hiblot 0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee, 2929815e3baSJean-Jacques Hiblot 0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff, 2939815e3baSJean-Jacques Hiblot 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde, 2949815e3baSJean-Jacques Hiblot }; 2959815e3baSJean-Jacques Hiblot 2969815e3baSJean-Jacques Hiblot static const u8 tuning_blk_pattern_8bit[] = { 2979815e3baSJean-Jacques Hiblot 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 2989815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc, 2999815e3baSJean-Jacques Hiblot 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff, 3009815e3baSJean-Jacques Hiblot 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff, 3019815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd, 3029815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb, 3039815e3baSJean-Jacques Hiblot 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff, 3049815e3baSJean-Jacques Hiblot 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff, 3059815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 3069815e3baSJean-Jacques Hiblot 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 3079815e3baSJean-Jacques Hiblot 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 3089815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 3099815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 3109815e3baSJean-Jacques Hiblot 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 3119815e3baSJean-Jacques Hiblot 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 3129815e3baSJean-Jacques Hiblot 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 3139815e3baSJean-Jacques Hiblot }; 3149815e3baSJean-Jacques Hiblot 3159815e3baSJean-Jacques Hiblot int mmc_send_tuning(struct mmc *mmc, u32 opcode, int *cmd_error) 3169815e3baSJean-Jacques Hiblot { 3179815e3baSJean-Jacques Hiblot struct mmc_cmd cmd; 3189815e3baSJean-Jacques Hiblot struct mmc_data data; 3199815e3baSJean-Jacques Hiblot const u8 *tuning_block_pattern; 3209815e3baSJean-Jacques Hiblot int size, err; 3219815e3baSJean-Jacques Hiblot 3229815e3baSJean-Jacques Hiblot if (mmc->bus_width == 8) { 3239815e3baSJean-Jacques Hiblot tuning_block_pattern = tuning_blk_pattern_8bit; 3249815e3baSJean-Jacques Hiblot size = sizeof(tuning_blk_pattern_8bit); 3259815e3baSJean-Jacques Hiblot } else if (mmc->bus_width == 4) { 3269815e3baSJean-Jacques Hiblot tuning_block_pattern = tuning_blk_pattern_4bit; 3279815e3baSJean-Jacques Hiblot size = sizeof(tuning_blk_pattern_4bit); 3289815e3baSJean-Jacques Hiblot } else { 3299815e3baSJean-Jacques Hiblot return -EINVAL; 3309815e3baSJean-Jacques Hiblot } 3319815e3baSJean-Jacques Hiblot 3329815e3baSJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, data_buf, size); 3339815e3baSJean-Jacques Hiblot 3349815e3baSJean-Jacques Hiblot cmd.cmdidx = opcode; 3359815e3baSJean-Jacques Hiblot cmd.cmdarg = 0; 3369815e3baSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 3379815e3baSJean-Jacques Hiblot 3389815e3baSJean-Jacques Hiblot data.dest = (void *)data_buf; 3399815e3baSJean-Jacques Hiblot data.blocks = 1; 3409815e3baSJean-Jacques Hiblot data.blocksize = size; 3419815e3baSJean-Jacques Hiblot data.flags = MMC_DATA_READ; 3429815e3baSJean-Jacques Hiblot 3439815e3baSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, &data); 3449815e3baSJean-Jacques Hiblot if (err) 3459815e3baSJean-Jacques Hiblot return err; 3469815e3baSJean-Jacques Hiblot 3479815e3baSJean-Jacques Hiblot if (memcmp(data_buf, tuning_block_pattern, size)) 3489815e3baSJean-Jacques Hiblot return -EIO; 3499815e3baSJean-Jacques Hiblot 3509815e3baSJean-Jacques Hiblot return 0; 3519815e3baSJean-Jacques Hiblot } 352f99c2efeSJean-Jacques Hiblot #endif 3539815e3baSJean-Jacques Hiblot 354ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start, 355fdbb873eSKim Phillips lbaint_t blkcnt) 356272cc70bSAndy Fleming { 357272cc70bSAndy Fleming struct mmc_cmd cmd; 358272cc70bSAndy Fleming struct mmc_data data; 359272cc70bSAndy Fleming 3604a1a06bcSAlagu Sankar if (blkcnt > 1) 3614a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; 3624a1a06bcSAlagu Sankar else 363272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK; 364272cc70bSAndy Fleming 365272cc70bSAndy Fleming if (mmc->high_capacity) 3664a1a06bcSAlagu Sankar cmd.cmdarg = start; 367272cc70bSAndy Fleming else 3684a1a06bcSAlagu Sankar cmd.cmdarg = start * mmc->read_bl_len; 369272cc70bSAndy Fleming 370272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 371272cc70bSAndy Fleming 372272cc70bSAndy Fleming data.dest = dst; 3734a1a06bcSAlagu Sankar data.blocks = blkcnt; 374272cc70bSAndy Fleming data.blocksize = mmc->read_bl_len; 375272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 376272cc70bSAndy Fleming 3774a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, &data)) 3784a1a06bcSAlagu Sankar return 0; 3794a1a06bcSAlagu Sankar 3804a1a06bcSAlagu Sankar if (blkcnt > 1) { 3814a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION; 3824a1a06bcSAlagu Sankar cmd.cmdarg = 0; 3834a1a06bcSAlagu Sankar cmd.resp_type = MMC_RSP_R1b; 3844a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, NULL)) { 38556196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 386d8e3d420SJean-Jacques Hiblot pr_err("mmc fail to send stop cmd\n"); 38756196826SPaul Burton #endif 3884a1a06bcSAlagu Sankar return 0; 3894a1a06bcSAlagu Sankar } 390272cc70bSAndy Fleming } 391272cc70bSAndy Fleming 3924a1a06bcSAlagu Sankar return blkcnt; 393272cc70bSAndy Fleming } 394272cc70bSAndy Fleming 395c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK) 3967dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst) 39733fb211dSSimon Glass #else 3987dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt, 3997dba0b93SSimon Glass void *dst) 40033fb211dSSimon Glass #endif 401272cc70bSAndy Fleming { 402c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK) 40333fb211dSSimon Glass struct blk_desc *block_dev = dev_get_uclass_platdata(dev); 40433fb211dSSimon Glass #endif 405bcce53d0SSimon Glass int dev_num = block_dev->devnum; 406873cc1d7SStephen Warren int err; 4074a1a06bcSAlagu Sankar lbaint_t cur, blocks_todo = blkcnt; 408272cc70bSAndy Fleming 4094a1a06bcSAlagu Sankar if (blkcnt == 0) 4104a1a06bcSAlagu Sankar return 0; 4114a1a06bcSAlagu Sankar 4124a1a06bcSAlagu Sankar struct mmc *mmc = find_mmc_device(dev_num); 413272cc70bSAndy Fleming if (!mmc) 414272cc70bSAndy Fleming return 0; 415272cc70bSAndy Fleming 416b5b838f1SMarek Vasut if (CONFIG_IS_ENABLED(MMC_TINY)) 417b5b838f1SMarek Vasut err = mmc_switch_part(mmc, block_dev->hwpart); 418b5b838f1SMarek Vasut else 41969f45cd5SSimon Glass err = blk_dselect_hwpart(block_dev, block_dev->hwpart); 420b5b838f1SMarek Vasut 421873cc1d7SStephen Warren if (err < 0) 422873cc1d7SStephen Warren return 0; 423873cc1d7SStephen Warren 424c40fdca6SSimon Glass if ((start + blkcnt) > block_dev->lba) { 42556196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 426d8e3d420SJean-Jacques Hiblot pr_err("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n", 427c40fdca6SSimon Glass start + blkcnt, block_dev->lba); 42856196826SPaul Burton #endif 429d2bf29e3SLei Wen return 0; 430d2bf29e3SLei Wen } 431272cc70bSAndy Fleming 43211692991SSimon Glass if (mmc_set_blocklen(mmc, mmc->read_bl_len)) { 433d4d64889SMasahiro Yamada pr_debug("%s: Failed to set blocklen\n", __func__); 434272cc70bSAndy Fleming return 0; 43511692991SSimon Glass } 436272cc70bSAndy Fleming 4374a1a06bcSAlagu Sankar do { 43893bfd616SPantelis Antoniou cur = (blocks_todo > mmc->cfg->b_max) ? 43993bfd616SPantelis Antoniou mmc->cfg->b_max : blocks_todo; 44011692991SSimon Glass if (mmc_read_blocks(mmc, dst, start, cur) != cur) { 441d4d64889SMasahiro Yamada pr_debug("%s: Failed to read blocks\n", __func__); 4424a1a06bcSAlagu Sankar return 0; 44311692991SSimon Glass } 4444a1a06bcSAlagu Sankar blocks_todo -= cur; 4454a1a06bcSAlagu Sankar start += cur; 4464a1a06bcSAlagu Sankar dst += cur * mmc->read_bl_len; 4474a1a06bcSAlagu Sankar } while (blocks_todo > 0); 448272cc70bSAndy Fleming 449272cc70bSAndy Fleming return blkcnt; 450272cc70bSAndy Fleming } 451272cc70bSAndy Fleming 452fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc) 453272cc70bSAndy Fleming { 454272cc70bSAndy Fleming struct mmc_cmd cmd; 455272cc70bSAndy Fleming int err; 456272cc70bSAndy Fleming 457272cc70bSAndy Fleming udelay(1000); 458272cc70bSAndy Fleming 459272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_GO_IDLE_STATE; 460272cc70bSAndy Fleming cmd.cmdarg = 0; 461272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_NONE; 462272cc70bSAndy Fleming 463272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 464272cc70bSAndy Fleming 465272cc70bSAndy Fleming if (err) 466272cc70bSAndy Fleming return err; 467272cc70bSAndy Fleming 468272cc70bSAndy Fleming udelay(2000); 469272cc70bSAndy Fleming 470272cc70bSAndy Fleming return 0; 471272cc70bSAndy Fleming } 472272cc70bSAndy Fleming 473f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 474c10b85d6SJean-Jacques Hiblot static int mmc_switch_voltage(struct mmc *mmc, int signal_voltage) 475c10b85d6SJean-Jacques Hiblot { 476c10b85d6SJean-Jacques Hiblot struct mmc_cmd cmd; 477c10b85d6SJean-Jacques Hiblot int err = 0; 478c10b85d6SJean-Jacques Hiblot 479c10b85d6SJean-Jacques Hiblot /* 480c10b85d6SJean-Jacques Hiblot * Send CMD11 only if the request is to switch the card to 481c10b85d6SJean-Jacques Hiblot * 1.8V signalling. 482c10b85d6SJean-Jacques Hiblot */ 483c10b85d6SJean-Jacques Hiblot if (signal_voltage == MMC_SIGNAL_VOLTAGE_330) 484c10b85d6SJean-Jacques Hiblot return mmc_set_signal_voltage(mmc, signal_voltage); 485c10b85d6SJean-Jacques Hiblot 486c10b85d6SJean-Jacques Hiblot cmd.cmdidx = SD_CMD_SWITCH_UHS18V; 487c10b85d6SJean-Jacques Hiblot cmd.cmdarg = 0; 488c10b85d6SJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 489c10b85d6SJean-Jacques Hiblot 490c10b85d6SJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 491c10b85d6SJean-Jacques Hiblot if (err) 492c10b85d6SJean-Jacques Hiblot return err; 493c10b85d6SJean-Jacques Hiblot 494c10b85d6SJean-Jacques Hiblot if (!mmc_host_is_spi(mmc) && (cmd.response[0] & MMC_STATUS_ERROR)) 495c10b85d6SJean-Jacques Hiblot return -EIO; 496c10b85d6SJean-Jacques Hiblot 497c10b85d6SJean-Jacques Hiblot /* 498c10b85d6SJean-Jacques Hiblot * The card should drive cmd and dat[0:3] low immediately 499c10b85d6SJean-Jacques Hiblot * after the response of cmd11, but wait 100 us to be sure 500c10b85d6SJean-Jacques Hiblot */ 501c10b85d6SJean-Jacques Hiblot err = mmc_wait_dat0(mmc, 0, 100); 502c10b85d6SJean-Jacques Hiblot if (err == -ENOSYS) 503c10b85d6SJean-Jacques Hiblot udelay(100); 504c10b85d6SJean-Jacques Hiblot else if (err) 505c10b85d6SJean-Jacques Hiblot return -ETIMEDOUT; 506c10b85d6SJean-Jacques Hiblot 507c10b85d6SJean-Jacques Hiblot /* 508c10b85d6SJean-Jacques Hiblot * During a signal voltage level switch, the clock must be gated 509c10b85d6SJean-Jacques Hiblot * for 5 ms according to the SD spec 510c10b85d6SJean-Jacques Hiblot */ 51165117182SJaehoon Chung mmc_set_clock(mmc, mmc->clock, MMC_CLK_DISABLE); 512c10b85d6SJean-Jacques Hiblot 513c10b85d6SJean-Jacques Hiblot err = mmc_set_signal_voltage(mmc, signal_voltage); 514c10b85d6SJean-Jacques Hiblot if (err) 515c10b85d6SJean-Jacques Hiblot return err; 516c10b85d6SJean-Jacques Hiblot 517c10b85d6SJean-Jacques Hiblot /* Keep clock gated for at least 10 ms, though spec only says 5 ms */ 518c10b85d6SJean-Jacques Hiblot mdelay(10); 51965117182SJaehoon Chung mmc_set_clock(mmc, mmc->clock, MMC_CLK_ENABLE); 520c10b85d6SJean-Jacques Hiblot 521c10b85d6SJean-Jacques Hiblot /* 522c10b85d6SJean-Jacques Hiblot * Failure to switch is indicated by the card holding 523c10b85d6SJean-Jacques Hiblot * dat[0:3] low. Wait for at least 1 ms according to spec 524c10b85d6SJean-Jacques Hiblot */ 525c10b85d6SJean-Jacques Hiblot err = mmc_wait_dat0(mmc, 1, 1000); 526c10b85d6SJean-Jacques Hiblot if (err == -ENOSYS) 527c10b85d6SJean-Jacques Hiblot udelay(1000); 528c10b85d6SJean-Jacques Hiblot else if (err) 529c10b85d6SJean-Jacques Hiblot return -ETIMEDOUT; 530c10b85d6SJean-Jacques Hiblot 531c10b85d6SJean-Jacques Hiblot return 0; 532c10b85d6SJean-Jacques Hiblot } 533f99c2efeSJean-Jacques Hiblot #endif 534c10b85d6SJean-Jacques Hiblot 535c10b85d6SJean-Jacques Hiblot static int sd_send_op_cond(struct mmc *mmc, bool uhs_en) 536272cc70bSAndy Fleming { 537272cc70bSAndy Fleming int timeout = 1000; 538272cc70bSAndy Fleming int err; 539272cc70bSAndy Fleming struct mmc_cmd cmd; 540272cc70bSAndy Fleming 5411677eef4SAndrew Gabbasov while (1) { 542272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 543272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 544272cc70bSAndy Fleming cmd.cmdarg = 0; 545272cc70bSAndy Fleming 546272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 547272cc70bSAndy Fleming 548272cc70bSAndy Fleming if (err) 549272cc70bSAndy Fleming return err; 550272cc70bSAndy Fleming 551272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_OP_COND; 552272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R3; 553250de12bSStefano Babic 554250de12bSStefano Babic /* 555250de12bSStefano Babic * Most cards do not answer if some reserved bits 556250de12bSStefano Babic * in the ocr are set. However, Some controller 557250de12bSStefano Babic * can set bit 7 (reserved for low voltages), but 558250de12bSStefano Babic * how to manage low voltages SD card is not yet 559250de12bSStefano Babic * specified. 560250de12bSStefano Babic */ 561d52ebf10SThomas Chou cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 : 56293bfd616SPantelis Antoniou (mmc->cfg->voltages & 0xff8000); 563272cc70bSAndy Fleming 564272cc70bSAndy Fleming if (mmc->version == SD_VERSION_2) 565272cc70bSAndy Fleming cmd.cmdarg |= OCR_HCS; 566272cc70bSAndy Fleming 567c10b85d6SJean-Jacques Hiblot if (uhs_en) 568c10b85d6SJean-Jacques Hiblot cmd.cmdarg |= OCR_S18R; 569c10b85d6SJean-Jacques Hiblot 570272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 571272cc70bSAndy Fleming 572272cc70bSAndy Fleming if (err) 573272cc70bSAndy Fleming return err; 574272cc70bSAndy Fleming 5751677eef4SAndrew Gabbasov if (cmd.response[0] & OCR_BUSY) 5761677eef4SAndrew Gabbasov break; 577272cc70bSAndy Fleming 5781677eef4SAndrew Gabbasov if (timeout-- <= 0) 579915ffa52SJaehoon Chung return -EOPNOTSUPP; 580272cc70bSAndy Fleming 5811677eef4SAndrew Gabbasov udelay(1000); 5821677eef4SAndrew Gabbasov } 5831677eef4SAndrew Gabbasov 584272cc70bSAndy Fleming if (mmc->version != SD_VERSION_2) 585272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 586272cc70bSAndy Fleming 587d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 588d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 589d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 590d52ebf10SThomas Chou cmd.cmdarg = 0; 591d52ebf10SThomas Chou 592d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 593d52ebf10SThomas Chou 594d52ebf10SThomas Chou if (err) 595d52ebf10SThomas Chou return err; 596d52ebf10SThomas Chou } 597d52ebf10SThomas Chou 598998be3ddSRabin Vincent mmc->ocr = cmd.response[0]; 599272cc70bSAndy Fleming 600f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 601c10b85d6SJean-Jacques Hiblot if (uhs_en && !(mmc_host_is_spi(mmc)) && (cmd.response[0] & 0x41000000) 602c10b85d6SJean-Jacques Hiblot == 0x41000000) { 603c10b85d6SJean-Jacques Hiblot err = mmc_switch_voltage(mmc, MMC_SIGNAL_VOLTAGE_180); 604c10b85d6SJean-Jacques Hiblot if (err) 605c10b85d6SJean-Jacques Hiblot return err; 606c10b85d6SJean-Jacques Hiblot } 607f99c2efeSJean-Jacques Hiblot #endif 608c10b85d6SJean-Jacques Hiblot 609272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 610272cc70bSAndy Fleming mmc->rca = 0; 611272cc70bSAndy Fleming 612272cc70bSAndy Fleming return 0; 613272cc70bSAndy Fleming } 614272cc70bSAndy Fleming 6155289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg) 616272cc70bSAndy Fleming { 6175289b535SAndrew Gabbasov struct mmc_cmd cmd; 618272cc70bSAndy Fleming int err; 619272cc70bSAndy Fleming 6205289b535SAndrew Gabbasov cmd.cmdidx = MMC_CMD_SEND_OP_COND; 6215289b535SAndrew Gabbasov cmd.resp_type = MMC_RSP_R3; 6225289b535SAndrew Gabbasov cmd.cmdarg = 0; 6235a20397bSRob Herring if (use_arg && !mmc_host_is_spi(mmc)) 6245a20397bSRob Herring cmd.cmdarg = OCR_HCS | 62593bfd616SPantelis Antoniou (mmc->cfg->voltages & 626a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_VOLTAGE_MASK)) | 627a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_ACCESS_MODE); 628e9550449SChe-Liang Chiou 6295289b535SAndrew Gabbasov err = mmc_send_cmd(mmc, &cmd, NULL); 630e9550449SChe-Liang Chiou if (err) 631e9550449SChe-Liang Chiou return err; 6325289b535SAndrew Gabbasov mmc->ocr = cmd.response[0]; 633e9550449SChe-Liang Chiou return 0; 634e9550449SChe-Liang Chiou } 635e9550449SChe-Liang Chiou 636750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc) 637e9550449SChe-Liang Chiou { 638e9550449SChe-Liang Chiou int err, i; 639e9550449SChe-Liang Chiou 640272cc70bSAndy Fleming /* Some cards seem to need this */ 641272cc70bSAndy Fleming mmc_go_idle(mmc); 642272cc70bSAndy Fleming 64331cacbabSRaffaele Recalcati /* Asking to the card its capabilities */ 644e9550449SChe-Liang Chiou for (i = 0; i < 2; i++) { 6455289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, i != 0); 64631cacbabSRaffaele Recalcati if (err) 64731cacbabSRaffaele Recalcati return err; 64831cacbabSRaffaele Recalcati 649e9550449SChe-Liang Chiou /* exit if not busy (flag seems to be inverted) */ 650a626c8d4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 651bd47c135SAndrew Gabbasov break; 652e9550449SChe-Liang Chiou } 653bd47c135SAndrew Gabbasov mmc->op_cond_pending = 1; 654bd47c135SAndrew Gabbasov return 0; 655e9550449SChe-Liang Chiou } 65631cacbabSRaffaele Recalcati 657750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc) 658e9550449SChe-Liang Chiou { 659e9550449SChe-Liang Chiou struct mmc_cmd cmd; 660e9550449SChe-Liang Chiou int timeout = 1000; 66136332b6eSVipul Kumar ulong start; 662e9550449SChe-Liang Chiou int err; 663e9550449SChe-Liang Chiou 664e9550449SChe-Liang Chiou mmc->op_cond_pending = 0; 665cc17c01fSAndrew Gabbasov if (!(mmc->ocr & OCR_BUSY)) { 666d188b113SYangbo Lu /* Some cards seem to need this */ 667d188b113SYangbo Lu mmc_go_idle(mmc); 668d188b113SYangbo Lu 669e9550449SChe-Liang Chiou start = get_timer(0); 6701677eef4SAndrew Gabbasov while (1) { 6715289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, 1); 672272cc70bSAndy Fleming if (err) 673272cc70bSAndy Fleming return err; 6741677eef4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY) 6751677eef4SAndrew Gabbasov break; 676e9550449SChe-Liang Chiou if (get_timer(start) > timeout) 677915ffa52SJaehoon Chung return -EOPNOTSUPP; 678e9550449SChe-Liang Chiou udelay(100); 6791677eef4SAndrew Gabbasov } 680cc17c01fSAndrew Gabbasov } 681272cc70bSAndy Fleming 682d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */ 683d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR; 684d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3; 685d52ebf10SThomas Chou cmd.cmdarg = 0; 686d52ebf10SThomas Chou 687d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 688d52ebf10SThomas Chou 689d52ebf10SThomas Chou if (err) 690d52ebf10SThomas Chou return err; 691a626c8d4SAndrew Gabbasov 692a626c8d4SAndrew Gabbasov mmc->ocr = cmd.response[0]; 693d52ebf10SThomas Chou } 694d52ebf10SThomas Chou 695272cc70bSAndy Fleming mmc->version = MMC_VERSION_UNKNOWN; 696272cc70bSAndy Fleming 697272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS); 698def816a2SStephen Warren mmc->rca = 1; 699272cc70bSAndy Fleming 700272cc70bSAndy Fleming return 0; 701272cc70bSAndy Fleming } 702272cc70bSAndy Fleming 703272cc70bSAndy Fleming 704fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd) 705272cc70bSAndy Fleming { 706272cc70bSAndy Fleming struct mmc_cmd cmd; 707272cc70bSAndy Fleming struct mmc_data data; 708272cc70bSAndy Fleming int err; 709272cc70bSAndy Fleming 710272cc70bSAndy Fleming /* Get the Card Status Register */ 711272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_EXT_CSD; 712272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 713272cc70bSAndy Fleming cmd.cmdarg = 0; 714272cc70bSAndy Fleming 715cdfd1ac6SYoshihiro Shimoda data.dest = (char *)ext_csd; 716272cc70bSAndy Fleming data.blocks = 1; 7178bfa195eSSimon Glass data.blocksize = MMC_MAX_BLOCK_LEN; 718272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 719272cc70bSAndy Fleming 720272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 721272cc70bSAndy Fleming 722272cc70bSAndy Fleming return err; 723272cc70bSAndy Fleming } 724272cc70bSAndy Fleming 725c40704f4SSimon Glass int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value) 726272cc70bSAndy Fleming { 727272cc70bSAndy Fleming struct mmc_cmd cmd; 7285d4fc8d9SRaffaele Recalcati int timeout = 1000; 729a9003dc6SMaxime Ripard int retries = 3; 7305d4fc8d9SRaffaele Recalcati int ret; 731272cc70bSAndy Fleming 732272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SWITCH; 733272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b; 734272cc70bSAndy Fleming cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) | 735272cc70bSAndy Fleming (index << 16) | 736272cc70bSAndy Fleming (value << 8); 737272cc70bSAndy Fleming 738a9003dc6SMaxime Ripard while (retries > 0) { 7395d4fc8d9SRaffaele Recalcati ret = mmc_send_cmd(mmc, &cmd, NULL); 7405d4fc8d9SRaffaele Recalcati 7415d4fc8d9SRaffaele Recalcati /* Waiting for the ready status */ 742a9003dc6SMaxime Ripard if (!ret) { 74393ad0d18SJan Kloetzke ret = mmc_send_status(mmc, timeout); 744a9003dc6SMaxime Ripard return ret; 745a9003dc6SMaxime Ripard } 746a9003dc6SMaxime Ripard 747a9003dc6SMaxime Ripard retries--; 748a9003dc6SMaxime Ripard } 7495d4fc8d9SRaffaele Recalcati 7505d4fc8d9SRaffaele Recalcati return ret; 7515d4fc8d9SRaffaele Recalcati 752272cc70bSAndy Fleming } 753272cc70bSAndy Fleming 754*62d77ceaSMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY) 7553862b854SJean-Jacques Hiblot static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode) 756272cc70bSAndy Fleming { 757272cc70bSAndy Fleming int err; 7583862b854SJean-Jacques Hiblot int speed_bits; 7593862b854SJean-Jacques Hiblot 7603862b854SJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 7613862b854SJean-Jacques Hiblot 7623862b854SJean-Jacques Hiblot switch (mode) { 7633862b854SJean-Jacques Hiblot case MMC_HS: 7643862b854SJean-Jacques Hiblot case MMC_HS_52: 7653862b854SJean-Jacques Hiblot case MMC_DDR_52: 7663862b854SJean-Jacques Hiblot speed_bits = EXT_CSD_TIMING_HS; 767634d4849SKishon Vijay Abraham I break; 768baef2070SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) 769634d4849SKishon Vijay Abraham I case MMC_HS_200: 770634d4849SKishon Vijay Abraham I speed_bits = EXT_CSD_TIMING_HS200; 771634d4849SKishon Vijay Abraham I break; 772baef2070SJean-Jacques Hiblot #endif 7733862b854SJean-Jacques Hiblot case MMC_LEGACY: 7743862b854SJean-Jacques Hiblot speed_bits = EXT_CSD_TIMING_LEGACY; 7753862b854SJean-Jacques Hiblot break; 7763862b854SJean-Jacques Hiblot default: 7773862b854SJean-Jacques Hiblot return -EINVAL; 7783862b854SJean-Jacques Hiblot } 7793862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 7803862b854SJean-Jacques Hiblot speed_bits); 7813862b854SJean-Jacques Hiblot if (err) 7823862b854SJean-Jacques Hiblot return err; 7833862b854SJean-Jacques Hiblot 7843862b854SJean-Jacques Hiblot if ((mode == MMC_HS) || (mode == MMC_HS_52)) { 7853862b854SJean-Jacques Hiblot /* Now check to see that it worked */ 7863862b854SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, test_csd); 7873862b854SJean-Jacques Hiblot if (err) 7883862b854SJean-Jacques Hiblot return err; 7893862b854SJean-Jacques Hiblot 7903862b854SJean-Jacques Hiblot /* No high-speed support */ 7913862b854SJean-Jacques Hiblot if (!test_csd[EXT_CSD_HS_TIMING]) 7923862b854SJean-Jacques Hiblot return -ENOTSUPP; 7933862b854SJean-Jacques Hiblot } 7943862b854SJean-Jacques Hiblot 7953862b854SJean-Jacques Hiblot return 0; 7963862b854SJean-Jacques Hiblot } 7973862b854SJean-Jacques Hiblot 7983862b854SJean-Jacques Hiblot static int mmc_get_capabilities(struct mmc *mmc) 7993862b854SJean-Jacques Hiblot { 8003862b854SJean-Jacques Hiblot u8 *ext_csd = mmc->ext_csd; 8013862b854SJean-Jacques Hiblot char cardtype; 802272cc70bSAndy Fleming 80300e446faSJean-Jacques Hiblot mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(MMC_LEGACY); 804272cc70bSAndy Fleming 805d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 806d52ebf10SThomas Chou return 0; 807d52ebf10SThomas Chou 808272cc70bSAndy Fleming /* Only version 4 supports high-speed */ 809272cc70bSAndy Fleming if (mmc->version < MMC_VERSION_4) 810272cc70bSAndy Fleming return 0; 811272cc70bSAndy Fleming 8123862b854SJean-Jacques Hiblot if (!ext_csd) { 813d8e3d420SJean-Jacques Hiblot pr_err("No ext_csd found!\n"); /* this should enver happen */ 8143862b854SJean-Jacques Hiblot return -ENOTSUPP; 8153862b854SJean-Jacques Hiblot } 8163862b854SJean-Jacques Hiblot 817fc5b32fbSAndrew Gabbasov mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; 818fc5b32fbSAndrew Gabbasov 819634d4849SKishon Vijay Abraham I cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0x3f; 820bc1e3272SJean-Jacques Hiblot mmc->cardtype = cardtype; 821272cc70bSAndy Fleming 822baef2070SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) 823634d4849SKishon Vijay Abraham I if (cardtype & (EXT_CSD_CARD_TYPE_HS200_1_2V | 824634d4849SKishon Vijay Abraham I EXT_CSD_CARD_TYPE_HS200_1_8V)) { 825634d4849SKishon Vijay Abraham I mmc->card_caps |= MMC_MODE_HS200; 826634d4849SKishon Vijay Abraham I } 827baef2070SJean-Jacques Hiblot #endif 828d22e3d46SJaehoon Chung if (cardtype & EXT_CSD_CARD_TYPE_52) { 8293862b854SJean-Jacques Hiblot if (cardtype & EXT_CSD_CARD_TYPE_DDR_52) 830d22e3d46SJaehoon Chung mmc->card_caps |= MMC_MODE_DDR_52MHz; 8313862b854SJean-Jacques Hiblot mmc->card_caps |= MMC_MODE_HS_52MHz; 832d22e3d46SJaehoon Chung } 8333862b854SJean-Jacques Hiblot if (cardtype & EXT_CSD_CARD_TYPE_26) 8343862b854SJean-Jacques Hiblot mmc->card_caps |= MMC_MODE_HS; 835272cc70bSAndy Fleming 836272cc70bSAndy Fleming return 0; 837272cc70bSAndy Fleming } 838*62d77ceaSMarek Vasut #endif 839272cc70bSAndy Fleming 840f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num) 841f866a46dSStephen Warren { 842f866a46dSStephen Warren switch (part_num) { 843f866a46dSStephen Warren case 0: 844f866a46dSStephen Warren mmc->capacity = mmc->capacity_user; 845f866a46dSStephen Warren break; 846f866a46dSStephen Warren case 1: 847f866a46dSStephen Warren case 2: 848f866a46dSStephen Warren mmc->capacity = mmc->capacity_boot; 849f866a46dSStephen Warren break; 850f866a46dSStephen Warren case 3: 851f866a46dSStephen Warren mmc->capacity = mmc->capacity_rpmb; 852f866a46dSStephen Warren break; 853f866a46dSStephen Warren case 4: 854f866a46dSStephen Warren case 5: 855f866a46dSStephen Warren case 6: 856f866a46dSStephen Warren case 7: 857f866a46dSStephen Warren mmc->capacity = mmc->capacity_gp[part_num - 4]; 858f866a46dSStephen Warren break; 859f866a46dSStephen Warren default: 860f866a46dSStephen Warren return -1; 861f866a46dSStephen Warren } 862f866a46dSStephen Warren 863c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len); 864f866a46dSStephen Warren 865f866a46dSStephen Warren return 0; 866f866a46dSStephen Warren } 867f866a46dSStephen Warren 868f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) 86901298da3SJean-Jacques Hiblot static int mmc_boot_part_access_chk(struct mmc *mmc, unsigned int part_num) 87001298da3SJean-Jacques Hiblot { 87101298da3SJean-Jacques Hiblot int forbidden = 0; 87201298da3SJean-Jacques Hiblot bool change = false; 87301298da3SJean-Jacques Hiblot 87401298da3SJean-Jacques Hiblot if (part_num & PART_ACCESS_MASK) 87501298da3SJean-Jacques Hiblot forbidden = MMC_CAP(MMC_HS_200); 87601298da3SJean-Jacques Hiblot 87701298da3SJean-Jacques Hiblot if (MMC_CAP(mmc->selected_mode) & forbidden) { 878d4d64889SMasahiro Yamada pr_debug("selected mode (%s) is forbidden for part %d\n", 87901298da3SJean-Jacques Hiblot mmc_mode_name(mmc->selected_mode), part_num); 88001298da3SJean-Jacques Hiblot change = true; 88101298da3SJean-Jacques Hiblot } else if (mmc->selected_mode != mmc->best_mode) { 882d4d64889SMasahiro Yamada pr_debug("selected mode is not optimal\n"); 88301298da3SJean-Jacques Hiblot change = true; 88401298da3SJean-Jacques Hiblot } 88501298da3SJean-Jacques Hiblot 88601298da3SJean-Jacques Hiblot if (change) 88701298da3SJean-Jacques Hiblot return mmc_select_mode_and_width(mmc, 88801298da3SJean-Jacques Hiblot mmc->card_caps & ~forbidden); 88901298da3SJean-Jacques Hiblot 89001298da3SJean-Jacques Hiblot return 0; 89101298da3SJean-Jacques Hiblot } 892f99c2efeSJean-Jacques Hiblot #else 893f99c2efeSJean-Jacques Hiblot static inline int mmc_boot_part_access_chk(struct mmc *mmc, 894f99c2efeSJean-Jacques Hiblot unsigned int part_num) 895f99c2efeSJean-Jacques Hiblot { 896f99c2efeSJean-Jacques Hiblot return 0; 897f99c2efeSJean-Jacques Hiblot } 898f99c2efeSJean-Jacques Hiblot #endif 89901298da3SJean-Jacques Hiblot 9007dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num) 901bc897b1dSLei Wen { 902f866a46dSStephen Warren int ret; 903bc897b1dSLei Wen 90401298da3SJean-Jacques Hiblot ret = mmc_boot_part_access_chk(mmc, part_num); 90501298da3SJean-Jacques Hiblot if (ret) 90601298da3SJean-Jacques Hiblot return ret; 90701298da3SJean-Jacques Hiblot 908f866a46dSStephen Warren ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF, 909bc897b1dSLei Wen (mmc->part_config & ~PART_ACCESS_MASK) 910bc897b1dSLei Wen | (part_num & PART_ACCESS_MASK)); 911f866a46dSStephen Warren 9126dc93e70SPeter Bigot /* 9136dc93e70SPeter Bigot * Set the capacity if the switch succeeded or was intended 9146dc93e70SPeter Bigot * to return to representing the raw device. 9156dc93e70SPeter Bigot */ 916873cc1d7SStephen Warren if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) { 9176dc93e70SPeter Bigot ret = mmc_set_capacity(mmc, part_num); 918fdbb139fSSimon Glass mmc_get_blk_desc(mmc)->hwpart = part_num; 919873cc1d7SStephen Warren } 9206dc93e70SPeter Bigot 9216dc93e70SPeter Bigot return ret; 922bc897b1dSLei Wen } 923bc897b1dSLei Wen 924cf17789eSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING) 925ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc, 926ac9da0e0SDiego Santa Cruz const struct mmc_hwpart_conf *conf, 927ac9da0e0SDiego Santa Cruz enum mmc_hwpart_conf_mode mode) 928ac9da0e0SDiego Santa Cruz { 929ac9da0e0SDiego Santa Cruz u8 part_attrs = 0; 930ac9da0e0SDiego Santa Cruz u32 enh_size_mult; 931ac9da0e0SDiego Santa Cruz u32 enh_start_addr; 932ac9da0e0SDiego Santa Cruz u32 gp_size_mult[4]; 933ac9da0e0SDiego Santa Cruz u32 max_enh_size_mult; 934ac9da0e0SDiego Santa Cruz u32 tot_enh_size_mult = 0; 9358dda5b0eSDiego Santa Cruz u8 wr_rel_set; 936ac9da0e0SDiego Santa Cruz int i, pidx, err; 937ac9da0e0SDiego Santa Cruz ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 938ac9da0e0SDiego Santa Cruz 939ac9da0e0SDiego Santa Cruz if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE) 940ac9da0e0SDiego Santa Cruz return -EINVAL; 941ac9da0e0SDiego Santa Cruz 942ac9da0e0SDiego Santa Cruz if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) { 943d8e3d420SJean-Jacques Hiblot pr_err("eMMC >= 4.4 required for enhanced user data area\n"); 944ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 945ac9da0e0SDiego Santa Cruz } 946ac9da0e0SDiego Santa Cruz 947ac9da0e0SDiego Santa Cruz if (!(mmc->part_support & PART_SUPPORT)) { 948d8e3d420SJean-Jacques Hiblot pr_err("Card does not support partitioning\n"); 949ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 950ac9da0e0SDiego Santa Cruz } 951ac9da0e0SDiego Santa Cruz 952ac9da0e0SDiego Santa Cruz if (!mmc->hc_wp_grp_size) { 953d8e3d420SJean-Jacques Hiblot pr_err("Card does not define HC WP group size\n"); 954ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 955ac9da0e0SDiego Santa Cruz } 956ac9da0e0SDiego Santa Cruz 957ac9da0e0SDiego Santa Cruz /* check partition alignment and total enhanced size */ 958ac9da0e0SDiego Santa Cruz if (conf->user.enh_size) { 959ac9da0e0SDiego Santa Cruz if (conf->user.enh_size % mmc->hc_wp_grp_size || 960ac9da0e0SDiego Santa Cruz conf->user.enh_start % mmc->hc_wp_grp_size) { 961d8e3d420SJean-Jacques Hiblot pr_err("User data enhanced area not HC WP group " 962ac9da0e0SDiego Santa Cruz "size aligned\n"); 963ac9da0e0SDiego Santa Cruz return -EINVAL; 964ac9da0e0SDiego Santa Cruz } 965ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_USR; 966ac9da0e0SDiego Santa Cruz enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size; 967ac9da0e0SDiego Santa Cruz if (mmc->high_capacity) { 968ac9da0e0SDiego Santa Cruz enh_start_addr = conf->user.enh_start; 969ac9da0e0SDiego Santa Cruz } else { 970ac9da0e0SDiego Santa Cruz enh_start_addr = (conf->user.enh_start << 9); 971ac9da0e0SDiego Santa Cruz } 972ac9da0e0SDiego Santa Cruz } else { 973ac9da0e0SDiego Santa Cruz enh_size_mult = 0; 974ac9da0e0SDiego Santa Cruz enh_start_addr = 0; 975ac9da0e0SDiego Santa Cruz } 976ac9da0e0SDiego Santa Cruz tot_enh_size_mult += enh_size_mult; 977ac9da0e0SDiego Santa Cruz 978ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 979ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) { 980d8e3d420SJean-Jacques Hiblot pr_err("GP%i partition not HC WP group size " 981ac9da0e0SDiego Santa Cruz "aligned\n", pidx+1); 982ac9da0e0SDiego Santa Cruz return -EINVAL; 983ac9da0e0SDiego Santa Cruz } 984ac9da0e0SDiego Santa Cruz gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size; 985ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) { 986ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_GP(pidx); 987ac9da0e0SDiego Santa Cruz tot_enh_size_mult += gp_size_mult[pidx]; 988ac9da0e0SDiego Santa Cruz } 989ac9da0e0SDiego Santa Cruz } 990ac9da0e0SDiego Santa Cruz 991ac9da0e0SDiego Santa Cruz if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) { 992d8e3d420SJean-Jacques Hiblot pr_err("Card does not support enhanced attribute\n"); 993ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 994ac9da0e0SDiego Santa Cruz } 995ac9da0e0SDiego Santa Cruz 996ac9da0e0SDiego Santa Cruz err = mmc_send_ext_csd(mmc, ext_csd); 997ac9da0e0SDiego Santa Cruz if (err) 998ac9da0e0SDiego Santa Cruz return err; 999ac9da0e0SDiego Santa Cruz 1000ac9da0e0SDiego Santa Cruz max_enh_size_mult = 1001ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) + 1002ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) + 1003ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT]; 1004ac9da0e0SDiego Santa Cruz if (tot_enh_size_mult > max_enh_size_mult) { 1005d8e3d420SJean-Jacques Hiblot pr_err("Total enhanced size exceeds maximum (%u > %u)\n", 1006ac9da0e0SDiego Santa Cruz tot_enh_size_mult, max_enh_size_mult); 1007ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE; 1008ac9da0e0SDiego Santa Cruz } 1009ac9da0e0SDiego Santa Cruz 10108dda5b0eSDiego Santa Cruz /* The default value of EXT_CSD_WR_REL_SET is device 10118dda5b0eSDiego Santa Cruz * dependent, the values can only be changed if the 10128dda5b0eSDiego Santa Cruz * EXT_CSD_HS_CTRL_REL bit is set. The values can be 10138dda5b0eSDiego Santa Cruz * changed only once and before partitioning is completed. */ 10148dda5b0eSDiego Santa Cruz wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 10158dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_change) { 10168dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_set) 10178dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_USR; 10188dda5b0eSDiego Santa Cruz else 10198dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR; 10208dda5b0eSDiego Santa Cruz } 10218dda5b0eSDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 10228dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_change) { 10238dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_set) 10248dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx); 10258dda5b0eSDiego Santa Cruz else 10268dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx); 10278dda5b0eSDiego Santa Cruz } 10288dda5b0eSDiego Santa Cruz } 10298dda5b0eSDiego Santa Cruz 10308dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] && 10318dda5b0eSDiego Santa Cruz !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) { 10328dda5b0eSDiego Santa Cruz puts("Card does not support host controlled partition write " 10338dda5b0eSDiego Santa Cruz "reliability settings\n"); 10348dda5b0eSDiego Santa Cruz return -EMEDIUMTYPE; 10358dda5b0eSDiego Santa Cruz } 10368dda5b0eSDiego Santa Cruz 1037ac9da0e0SDiego Santa Cruz if (ext_csd[EXT_CSD_PARTITION_SETTING] & 1038ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED) { 1039d8e3d420SJean-Jacques Hiblot pr_err("Card already partitioned\n"); 1040ac9da0e0SDiego Santa Cruz return -EPERM; 1041ac9da0e0SDiego Santa Cruz } 1042ac9da0e0SDiego Santa Cruz 1043ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_CHECK) 1044ac9da0e0SDiego Santa Cruz return 0; 1045ac9da0e0SDiego Santa Cruz 1046ac9da0e0SDiego Santa Cruz /* Partitioning requires high-capacity size definitions */ 1047ac9da0e0SDiego Santa Cruz if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) { 1048ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1049ac9da0e0SDiego Santa Cruz EXT_CSD_ERASE_GROUP_DEF, 1); 1050ac9da0e0SDiego Santa Cruz 1051ac9da0e0SDiego Santa Cruz if (err) 1052ac9da0e0SDiego Santa Cruz return err; 1053ac9da0e0SDiego Santa Cruz 1054ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 1055ac9da0e0SDiego Santa Cruz 1056ac9da0e0SDiego Santa Cruz /* update erase group size to be high-capacity */ 1057ac9da0e0SDiego Santa Cruz mmc->erase_grp_size = 1058ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 1059ac9da0e0SDiego Santa Cruz 1060ac9da0e0SDiego Santa Cruz } 1061ac9da0e0SDiego Santa Cruz 1062ac9da0e0SDiego Santa Cruz /* all OK, write the configuration */ 1063ac9da0e0SDiego Santa Cruz for (i = 0; i < 4; i++) { 1064ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1065ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_START_ADDR+i, 1066ac9da0e0SDiego Santa Cruz (enh_start_addr >> (i*8)) & 0xFF); 1067ac9da0e0SDiego Santa Cruz if (err) 1068ac9da0e0SDiego Santa Cruz return err; 1069ac9da0e0SDiego Santa Cruz } 1070ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 1071ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1072ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_SIZE_MULT+i, 1073ac9da0e0SDiego Santa Cruz (enh_size_mult >> (i*8)) & 0xFF); 1074ac9da0e0SDiego Santa Cruz if (err) 1075ac9da0e0SDiego Santa Cruz return err; 1076ac9da0e0SDiego Santa Cruz } 1077ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) { 1078ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) { 1079ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1080ac9da0e0SDiego Santa Cruz EXT_CSD_GP_SIZE_MULT+pidx*3+i, 1081ac9da0e0SDiego Santa Cruz (gp_size_mult[pidx] >> (i*8)) & 0xFF); 1082ac9da0e0SDiego Santa Cruz if (err) 1083ac9da0e0SDiego Santa Cruz return err; 1084ac9da0e0SDiego Santa Cruz } 1085ac9da0e0SDiego Santa Cruz } 1086ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1087ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs); 1088ac9da0e0SDiego Santa Cruz if (err) 1089ac9da0e0SDiego Santa Cruz return err; 1090ac9da0e0SDiego Santa Cruz 1091ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_SET) 1092ac9da0e0SDiego Santa Cruz return 0; 1093ac9da0e0SDiego Santa Cruz 10948dda5b0eSDiego Santa Cruz /* The WR_REL_SET is a write-once register but shall be 10958dda5b0eSDiego Santa Cruz * written before setting PART_SETTING_COMPLETED. As it is 10968dda5b0eSDiego Santa Cruz * write-once we can only write it when completing the 10978dda5b0eSDiego Santa Cruz * partitioning. */ 10988dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) { 10998dda5b0eSDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 11008dda5b0eSDiego Santa Cruz EXT_CSD_WR_REL_SET, wr_rel_set); 11018dda5b0eSDiego Santa Cruz if (err) 11028dda5b0eSDiego Santa Cruz return err; 11038dda5b0eSDiego Santa Cruz } 11048dda5b0eSDiego Santa Cruz 1105ac9da0e0SDiego Santa Cruz /* Setting PART_SETTING_COMPLETED confirms the partition 1106ac9da0e0SDiego Santa Cruz * configuration but it only becomes effective after power 1107ac9da0e0SDiego Santa Cruz * cycle, so we do not adjust the partition related settings 1108ac9da0e0SDiego Santa Cruz * in the mmc struct. */ 1109ac9da0e0SDiego Santa Cruz 1110ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 1111ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING, 1112ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED); 1113ac9da0e0SDiego Santa Cruz if (err) 1114ac9da0e0SDiego Santa Cruz return err; 1115ac9da0e0SDiego Santa Cruz 1116ac9da0e0SDiego Santa Cruz return 0; 1117ac9da0e0SDiego Santa Cruz } 1118cf17789eSJean-Jacques Hiblot #endif 1119ac9da0e0SDiego Santa Cruz 1120e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 112148972d90SThierry Reding int mmc_getcd(struct mmc *mmc) 112248972d90SThierry Reding { 112348972d90SThierry Reding int cd; 112448972d90SThierry Reding 112548972d90SThierry Reding cd = board_mmc_getcd(mmc); 112648972d90SThierry Reding 1127d4e1da4eSPeter Korsgaard if (cd < 0) { 112893bfd616SPantelis Antoniou if (mmc->cfg->ops->getcd) 112993bfd616SPantelis Antoniou cd = mmc->cfg->ops->getcd(mmc); 1130d4e1da4eSPeter Korsgaard else 1131d4e1da4eSPeter Korsgaard cd = 1; 1132d4e1da4eSPeter Korsgaard } 113348972d90SThierry Reding 113448972d90SThierry Reding return cd; 113548972d90SThierry Reding } 11368ca51e51SSimon Glass #endif 113748972d90SThierry Reding 1138*62d77ceaSMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY) 1139fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp) 1140272cc70bSAndy Fleming { 1141272cc70bSAndy Fleming struct mmc_cmd cmd; 1142272cc70bSAndy Fleming struct mmc_data data; 1143272cc70bSAndy Fleming 1144272cc70bSAndy Fleming /* Switch the frequency */ 1145272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC; 1146272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1147272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff; 1148272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4)); 1149272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4); 1150272cc70bSAndy Fleming 1151272cc70bSAndy Fleming data.dest = (char *)resp; 1152272cc70bSAndy Fleming data.blocksize = 64; 1153272cc70bSAndy Fleming data.blocks = 1; 1154272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1155272cc70bSAndy Fleming 1156272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data); 1157272cc70bSAndy Fleming } 1158272cc70bSAndy Fleming 1159d0c221feSJean-Jacques Hiblot static int sd_get_capabilities(struct mmc *mmc) 1160272cc70bSAndy Fleming { 1161272cc70bSAndy Fleming int err; 1162272cc70bSAndy Fleming struct mmc_cmd cmd; 116318e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2); 116418e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16); 1165272cc70bSAndy Fleming struct mmc_data data; 1166272cc70bSAndy Fleming int timeout; 1167f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1168c10b85d6SJean-Jacques Hiblot u32 sd3_bus_mode; 1169f99c2efeSJean-Jacques Hiblot #endif 1170272cc70bSAndy Fleming 117100e446faSJean-Jacques Hiblot mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(SD_LEGACY); 1172272cc70bSAndy Fleming 1173d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) 1174d52ebf10SThomas Chou return 0; 1175d52ebf10SThomas Chou 1176272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */ 1177272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD; 1178272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1179272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 1180272cc70bSAndy Fleming 1181272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 1182272cc70bSAndy Fleming 1183272cc70bSAndy Fleming if (err) 1184272cc70bSAndy Fleming return err; 1185272cc70bSAndy Fleming 1186272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR; 1187272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1; 1188272cc70bSAndy Fleming cmd.cmdarg = 0; 1189272cc70bSAndy Fleming 1190272cc70bSAndy Fleming timeout = 3; 1191272cc70bSAndy Fleming 1192272cc70bSAndy Fleming retry_scr: 1193f781dd38SAnton staaf data.dest = (char *)scr; 1194272cc70bSAndy Fleming data.blocksize = 8; 1195272cc70bSAndy Fleming data.blocks = 1; 1196272cc70bSAndy Fleming data.flags = MMC_DATA_READ; 1197272cc70bSAndy Fleming 1198272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data); 1199272cc70bSAndy Fleming 1200272cc70bSAndy Fleming if (err) { 1201272cc70bSAndy Fleming if (timeout--) 1202272cc70bSAndy Fleming goto retry_scr; 1203272cc70bSAndy Fleming 1204272cc70bSAndy Fleming return err; 1205272cc70bSAndy Fleming } 1206272cc70bSAndy Fleming 12074e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]); 12084e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]); 1209272cc70bSAndy Fleming 1210272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) { 1211272cc70bSAndy Fleming case 0: 1212272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1213272cc70bSAndy Fleming break; 1214272cc70bSAndy Fleming case 1: 1215272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10; 1216272cc70bSAndy Fleming break; 1217272cc70bSAndy Fleming case 2: 1218272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 12191741c64dSJaehoon Chung if ((mmc->scr[0] >> 15) & 0x1) 12201741c64dSJaehoon Chung mmc->version = SD_VERSION_3; 1221272cc70bSAndy Fleming break; 1222272cc70bSAndy Fleming default: 1223272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0; 1224272cc70bSAndy Fleming break; 1225272cc70bSAndy Fleming } 1226272cc70bSAndy Fleming 1227b44c7083SAlagu Sankar if (mmc->scr[0] & SD_DATA_4BIT) 1228b44c7083SAlagu Sankar mmc->card_caps |= MMC_MODE_4BIT; 1229b44c7083SAlagu Sankar 1230272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */ 1231272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0) 1232272cc70bSAndy Fleming return 0; 1233272cc70bSAndy Fleming 1234272cc70bSAndy Fleming timeout = 4; 1235272cc70bSAndy Fleming while (timeout--) { 1236272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1, 1237f781dd38SAnton staaf (u8 *)switch_status); 1238272cc70bSAndy Fleming 1239272cc70bSAndy Fleming if (err) 1240272cc70bSAndy Fleming return err; 1241272cc70bSAndy Fleming 1242272cc70bSAndy Fleming /* The high-speed function is busy. Try again */ 12434e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY)) 1244272cc70bSAndy Fleming break; 1245272cc70bSAndy Fleming } 1246272cc70bSAndy Fleming 1247272cc70bSAndy Fleming /* If high-speed isn't supported, we return */ 1248d0c221feSJean-Jacques Hiblot if (__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED) 1249d0c221feSJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(SD_HS); 1250272cc70bSAndy Fleming 1251f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1252c10b85d6SJean-Jacques Hiblot /* Version before 3.0 don't support UHS modes */ 1253c10b85d6SJean-Jacques Hiblot if (mmc->version < SD_VERSION_3) 1254c10b85d6SJean-Jacques Hiblot return 0; 1255c10b85d6SJean-Jacques Hiblot 1256c10b85d6SJean-Jacques Hiblot sd3_bus_mode = __be32_to_cpu(switch_status[3]) >> 16 & 0x1f; 1257c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR104) 1258c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR104); 1259c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR50) 1260c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR50); 1261c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR25) 1262c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR25); 1263c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR12) 1264c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR12); 1265c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_DDR50) 1266c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_DDR50); 1267f99c2efeSJean-Jacques Hiblot #endif 1268c10b85d6SJean-Jacques Hiblot 12692c3fbf4cSMacpaul Lin return 0; 1270d0c221feSJean-Jacques Hiblot } 1271d0c221feSJean-Jacques Hiblot 1272d0c221feSJean-Jacques Hiblot static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode) 1273d0c221feSJean-Jacques Hiblot { 1274d0c221feSJean-Jacques Hiblot int err; 1275d0c221feSJean-Jacques Hiblot 1276d0c221feSJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16); 1277c10b85d6SJean-Jacques Hiblot int speed; 12782c3fbf4cSMacpaul Lin 1279c10b85d6SJean-Jacques Hiblot switch (mode) { 1280c10b85d6SJean-Jacques Hiblot case SD_LEGACY: 1281c10b85d6SJean-Jacques Hiblot speed = UHS_SDR12_BUS_SPEED; 1282c10b85d6SJean-Jacques Hiblot break; 1283c10b85d6SJean-Jacques Hiblot case SD_HS: 1284baef2070SJean-Jacques Hiblot speed = HIGH_SPEED_BUS_SPEED; 1285baef2070SJean-Jacques Hiblot break; 1286baef2070SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1287baef2070SJean-Jacques Hiblot case UHS_SDR12: 1288baef2070SJean-Jacques Hiblot speed = UHS_SDR12_BUS_SPEED; 1289baef2070SJean-Jacques Hiblot break; 1290c10b85d6SJean-Jacques Hiblot case UHS_SDR25: 1291c10b85d6SJean-Jacques Hiblot speed = UHS_SDR25_BUS_SPEED; 1292c10b85d6SJean-Jacques Hiblot break; 1293c10b85d6SJean-Jacques Hiblot case UHS_SDR50: 1294c10b85d6SJean-Jacques Hiblot speed = UHS_SDR50_BUS_SPEED; 1295c10b85d6SJean-Jacques Hiblot break; 1296c10b85d6SJean-Jacques Hiblot case UHS_DDR50: 1297c10b85d6SJean-Jacques Hiblot speed = UHS_DDR50_BUS_SPEED; 1298c10b85d6SJean-Jacques Hiblot break; 1299c10b85d6SJean-Jacques Hiblot case UHS_SDR104: 1300c10b85d6SJean-Jacques Hiblot speed = UHS_SDR104_BUS_SPEED; 1301c10b85d6SJean-Jacques Hiblot break; 1302baef2070SJean-Jacques Hiblot #endif 1303c10b85d6SJean-Jacques Hiblot default: 1304c10b85d6SJean-Jacques Hiblot return -EINVAL; 1305c10b85d6SJean-Jacques Hiblot } 1306c10b85d6SJean-Jacques Hiblot 1307c10b85d6SJean-Jacques Hiblot err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, speed, (u8 *)switch_status); 1308272cc70bSAndy Fleming if (err) 1309272cc70bSAndy Fleming return err; 1310272cc70bSAndy Fleming 1311a0276f3eSJean-Jacques Hiblot if (((__be32_to_cpu(switch_status[4]) >> 24) & 0xF) != speed) 1312d0c221feSJean-Jacques Hiblot return -ENOTSUPP; 1313d0c221feSJean-Jacques Hiblot 1314d0c221feSJean-Jacques Hiblot return 0; 1315d0c221feSJean-Jacques Hiblot } 1316d0c221feSJean-Jacques Hiblot 1317ec360e64SMarek Vasut static int sd_select_bus_width(struct mmc *mmc, int w) 1318d0c221feSJean-Jacques Hiblot { 1319d0c221feSJean-Jacques Hiblot int err; 1320d0c221feSJean-Jacques Hiblot struct mmc_cmd cmd; 1321d0c221feSJean-Jacques Hiblot 1322d0c221feSJean-Jacques Hiblot if ((w != 4) && (w != 1)) 1323d0c221feSJean-Jacques Hiblot return -EINVAL; 1324d0c221feSJean-Jacques Hiblot 1325d0c221feSJean-Jacques Hiblot cmd.cmdidx = MMC_CMD_APP_CMD; 1326d0c221feSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 1327d0c221feSJean-Jacques Hiblot cmd.cmdarg = mmc->rca << 16; 1328d0c221feSJean-Jacques Hiblot 1329d0c221feSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 1330d0c221feSJean-Jacques Hiblot if (err) 1331d0c221feSJean-Jacques Hiblot return err; 1332d0c221feSJean-Jacques Hiblot 1333d0c221feSJean-Jacques Hiblot cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH; 1334d0c221feSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1; 1335d0c221feSJean-Jacques Hiblot if (w == 4) 1336d0c221feSJean-Jacques Hiblot cmd.cmdarg = 2; 1337d0c221feSJean-Jacques Hiblot else if (w == 1) 1338d0c221feSJean-Jacques Hiblot cmd.cmdarg = 0; 1339d0c221feSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL); 1340d0c221feSJean-Jacques Hiblot if (err) 1341d0c221feSJean-Jacques Hiblot return err; 1342272cc70bSAndy Fleming 1343272cc70bSAndy Fleming return 0; 1344272cc70bSAndy Fleming } 1345*62d77ceaSMarek Vasut #endif 1346272cc70bSAndy Fleming 13475b2e72f3SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE) 13483697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc) 13493697e599SPeng Fan { 13505b2e72f3SJean-Jacques Hiblot static const unsigned int sd_au_size[] = { 13515b2e72f3SJean-Jacques Hiblot 0, SZ_16K / 512, SZ_32K / 512, 13525b2e72f3SJean-Jacques Hiblot SZ_64K / 512, SZ_128K / 512, SZ_256K / 512, 13535b2e72f3SJean-Jacques Hiblot SZ_512K / 512, SZ_1M / 512, SZ_2M / 512, 13545b2e72f3SJean-Jacques Hiblot SZ_4M / 512, SZ_8M / 512, (SZ_8M + SZ_4M) / 512, 13555b2e72f3SJean-Jacques Hiblot SZ_16M / 512, (SZ_16M + SZ_8M) / 512, SZ_32M / 512, 13565b2e72f3SJean-Jacques Hiblot SZ_64M / 512, 13575b2e72f3SJean-Jacques Hiblot }; 13583697e599SPeng Fan int err, i; 13593697e599SPeng Fan struct mmc_cmd cmd; 13603697e599SPeng Fan ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16); 13613697e599SPeng Fan struct mmc_data data; 13623697e599SPeng Fan int timeout = 3; 13633697e599SPeng Fan unsigned int au, eo, et, es; 13643697e599SPeng Fan 13653697e599SPeng Fan cmd.cmdidx = MMC_CMD_APP_CMD; 13663697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 13673697e599SPeng Fan cmd.cmdarg = mmc->rca << 16; 13683697e599SPeng Fan 13693697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, NULL); 13703697e599SPeng Fan if (err) 13713697e599SPeng Fan return err; 13723697e599SPeng Fan 13733697e599SPeng Fan cmd.cmdidx = SD_CMD_APP_SD_STATUS; 13743697e599SPeng Fan cmd.resp_type = MMC_RSP_R1; 13753697e599SPeng Fan cmd.cmdarg = 0; 13763697e599SPeng Fan 13773697e599SPeng Fan retry_ssr: 13783697e599SPeng Fan data.dest = (char *)ssr; 13793697e599SPeng Fan data.blocksize = 64; 13803697e599SPeng Fan data.blocks = 1; 13813697e599SPeng Fan data.flags = MMC_DATA_READ; 13823697e599SPeng Fan 13833697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, &data); 13843697e599SPeng Fan if (err) { 13853697e599SPeng Fan if (timeout--) 13863697e599SPeng Fan goto retry_ssr; 13873697e599SPeng Fan 13883697e599SPeng Fan return err; 13893697e599SPeng Fan } 13903697e599SPeng Fan 13913697e599SPeng Fan for (i = 0; i < 16; i++) 13923697e599SPeng Fan ssr[i] = be32_to_cpu(ssr[i]); 13933697e599SPeng Fan 13943697e599SPeng Fan au = (ssr[2] >> 12) & 0xF; 13953697e599SPeng Fan if ((au <= 9) || (mmc->version == SD_VERSION_3)) { 13963697e599SPeng Fan mmc->ssr.au = sd_au_size[au]; 13973697e599SPeng Fan es = (ssr[3] >> 24) & 0xFF; 13983697e599SPeng Fan es |= (ssr[2] & 0xFF) << 8; 13993697e599SPeng Fan et = (ssr[3] >> 18) & 0x3F; 14003697e599SPeng Fan if (es && et) { 14013697e599SPeng Fan eo = (ssr[3] >> 16) & 0x3; 14023697e599SPeng Fan mmc->ssr.erase_timeout = (et * 1000) / es; 14033697e599SPeng Fan mmc->ssr.erase_offset = eo * 1000; 14043697e599SPeng Fan } 14053697e599SPeng Fan } else { 1406d4d64889SMasahiro Yamada pr_debug("Invalid Allocation Unit Size.\n"); 14073697e599SPeng Fan } 14083697e599SPeng Fan 14093697e599SPeng Fan return 0; 14103697e599SPeng Fan } 14115b2e72f3SJean-Jacques Hiblot #endif 1412272cc70bSAndy Fleming /* frequency bases */ 1413272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */ 14145f837c2cSMike Frysinger static const int fbase[] = { 1415272cc70bSAndy Fleming 10000, 1416272cc70bSAndy Fleming 100000, 1417272cc70bSAndy Fleming 1000000, 1418272cc70bSAndy Fleming 10000000, 1419272cc70bSAndy Fleming }; 1420272cc70bSAndy Fleming 1421272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice 1422272cc70bSAndy Fleming * to platforms without floating point. 1423272cc70bSAndy Fleming */ 142461fe076fSSimon Glass static const u8 multipliers[] = { 1425272cc70bSAndy Fleming 0, /* reserved */ 1426272cc70bSAndy Fleming 10, 1427272cc70bSAndy Fleming 12, 1428272cc70bSAndy Fleming 13, 1429272cc70bSAndy Fleming 15, 1430272cc70bSAndy Fleming 20, 1431272cc70bSAndy Fleming 25, 1432272cc70bSAndy Fleming 30, 1433272cc70bSAndy Fleming 35, 1434272cc70bSAndy Fleming 40, 1435272cc70bSAndy Fleming 45, 1436272cc70bSAndy Fleming 50, 1437272cc70bSAndy Fleming 55, 1438272cc70bSAndy Fleming 60, 1439272cc70bSAndy Fleming 70, 1440272cc70bSAndy Fleming 80, 1441272cc70bSAndy Fleming }; 1442272cc70bSAndy Fleming 1443d0c221feSJean-Jacques Hiblot static inline int bus_width(uint cap) 1444d0c221feSJean-Jacques Hiblot { 1445d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_8BIT) 1446d0c221feSJean-Jacques Hiblot return 8; 1447d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_4BIT) 1448d0c221feSJean-Jacques Hiblot return 4; 1449d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_1BIT) 1450d0c221feSJean-Jacques Hiblot return 1; 1451d8e3d420SJean-Jacques Hiblot pr_warn("invalid bus witdh capability 0x%x\n", cap); 1452d0c221feSJean-Jacques Hiblot return 0; 1453d0c221feSJean-Jacques Hiblot } 1454d0c221feSJean-Jacques Hiblot 1455e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 1456f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 1457ec841209SKishon Vijay Abraham I static int mmc_execute_tuning(struct mmc *mmc, uint opcode) 1458ec841209SKishon Vijay Abraham I { 1459ec841209SKishon Vijay Abraham I return -ENOTSUPP; 1460ec841209SKishon Vijay Abraham I } 1461f99c2efeSJean-Jacques Hiblot #endif 1462ec841209SKishon Vijay Abraham I 1463318a7a57SJean-Jacques Hiblot static void mmc_send_init_stream(struct mmc *mmc) 1464318a7a57SJean-Jacques Hiblot { 1465318a7a57SJean-Jacques Hiblot } 1466318a7a57SJean-Jacques Hiblot 14672a4d212fSKishon Vijay Abraham I static int mmc_set_ios(struct mmc *mmc) 1468272cc70bSAndy Fleming { 14692a4d212fSKishon Vijay Abraham I int ret = 0; 14702a4d212fSKishon Vijay Abraham I 147193bfd616SPantelis Antoniou if (mmc->cfg->ops->set_ios) 14722a4d212fSKishon Vijay Abraham I ret = mmc->cfg->ops->set_ios(mmc); 14732a4d212fSKishon Vijay Abraham I 14742a4d212fSKishon Vijay Abraham I return ret; 1475272cc70bSAndy Fleming } 14768ca51e51SSimon Glass #endif 1477272cc70bSAndy Fleming 147835f67820SKishon Vijay Abraham I int mmc_set_clock(struct mmc *mmc, uint clock, bool disable) 1479272cc70bSAndy Fleming { 1480c0fafe64SJaehoon Chung if (!disable) { 148193bfd616SPantelis Antoniou if (clock > mmc->cfg->f_max) 148293bfd616SPantelis Antoniou clock = mmc->cfg->f_max; 1483272cc70bSAndy Fleming 148493bfd616SPantelis Antoniou if (clock < mmc->cfg->f_min) 148593bfd616SPantelis Antoniou clock = mmc->cfg->f_min; 14869546eb92SJaehoon Chung } 1487272cc70bSAndy Fleming 1488272cc70bSAndy Fleming mmc->clock = clock; 148935f67820SKishon Vijay Abraham I mmc->clk_disable = disable; 1490272cc70bSAndy Fleming 1491d2faadb5SJaehoon Chung debug("clock is %s (%dHz)\n", disable ? "disabled" : "enabled", clock); 1492d2faadb5SJaehoon Chung 14932a4d212fSKishon Vijay Abraham I return mmc_set_ios(mmc); 1494272cc70bSAndy Fleming } 1495272cc70bSAndy Fleming 14962a4d212fSKishon Vijay Abraham I static int mmc_set_bus_width(struct mmc *mmc, uint width) 1497272cc70bSAndy Fleming { 1498272cc70bSAndy Fleming mmc->bus_width = width; 1499272cc70bSAndy Fleming 15002a4d212fSKishon Vijay Abraham I return mmc_set_ios(mmc); 1501272cc70bSAndy Fleming } 1502272cc70bSAndy Fleming 15034c9d2aaaSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG) 15044c9d2aaaSJean-Jacques Hiblot /* 15054c9d2aaaSJean-Jacques Hiblot * helper function to display the capabilities in a human 15064c9d2aaaSJean-Jacques Hiblot * friendly manner. The capabilities include bus width and 15074c9d2aaaSJean-Jacques Hiblot * supported modes. 15084c9d2aaaSJean-Jacques Hiblot */ 15094c9d2aaaSJean-Jacques Hiblot void mmc_dump_capabilities(const char *text, uint caps) 15104c9d2aaaSJean-Jacques Hiblot { 15114c9d2aaaSJean-Jacques Hiblot enum bus_mode mode; 15124c9d2aaaSJean-Jacques Hiblot 1513d4d64889SMasahiro Yamada pr_debug("%s: widths [", text); 15144c9d2aaaSJean-Jacques Hiblot if (caps & MMC_MODE_8BIT) 1515d4d64889SMasahiro Yamada pr_debug("8, "); 15164c9d2aaaSJean-Jacques Hiblot if (caps & MMC_MODE_4BIT) 1517d4d64889SMasahiro Yamada pr_debug("4, "); 1518d0c221feSJean-Jacques Hiblot if (caps & MMC_MODE_1BIT) 1519d4d64889SMasahiro Yamada pr_debug("1, "); 1520d4d64889SMasahiro Yamada pr_debug("\b\b] modes ["); 15214c9d2aaaSJean-Jacques Hiblot for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++) 15224c9d2aaaSJean-Jacques Hiblot if (MMC_CAP(mode) & caps) 1523d4d64889SMasahiro Yamada pr_debug("%s, ", mmc_mode_name(mode)); 1524d4d64889SMasahiro Yamada pr_debug("\b\b]\n"); 15254c9d2aaaSJean-Jacques Hiblot } 15264c9d2aaaSJean-Jacques Hiblot #endif 15274c9d2aaaSJean-Jacques Hiblot 1528d0c221feSJean-Jacques Hiblot struct mode_width_tuning { 1529d0c221feSJean-Jacques Hiblot enum bus_mode mode; 1530d0c221feSJean-Jacques Hiblot uint widths; 1531f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 1532634d4849SKishon Vijay Abraham I uint tuning; 1533f99c2efeSJean-Jacques Hiblot #endif 1534d0c221feSJean-Jacques Hiblot }; 1535d0c221feSJean-Jacques Hiblot 1536f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE) 1537bc1e3272SJean-Jacques Hiblot int mmc_voltage_to_mv(enum mmc_voltage voltage) 1538bc1e3272SJean-Jacques Hiblot { 1539bc1e3272SJean-Jacques Hiblot switch (voltage) { 1540bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_000: return 0; 1541bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_330: return 3300; 1542bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_180: return 1800; 1543bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_120: return 1200; 1544bc1e3272SJean-Jacques Hiblot } 1545bc1e3272SJean-Jacques Hiblot return -EINVAL; 1546bc1e3272SJean-Jacques Hiblot } 1547bc1e3272SJean-Jacques Hiblot 1548aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage) 1549aff5d3c8SKishon Vijay Abraham I { 1550bc1e3272SJean-Jacques Hiblot int err; 1551bc1e3272SJean-Jacques Hiblot 1552bc1e3272SJean-Jacques Hiblot if (mmc->signal_voltage == signal_voltage) 1553bc1e3272SJean-Jacques Hiblot return 0; 1554bc1e3272SJean-Jacques Hiblot 1555aff5d3c8SKishon Vijay Abraham I mmc->signal_voltage = signal_voltage; 1556bc1e3272SJean-Jacques Hiblot err = mmc_set_ios(mmc); 1557bc1e3272SJean-Jacques Hiblot if (err) 1558d4d64889SMasahiro Yamada pr_debug("unable to set voltage (err %d)\n", err); 1559bc1e3272SJean-Jacques Hiblot 1560bc1e3272SJean-Jacques Hiblot return err; 1561aff5d3c8SKishon Vijay Abraham I } 1562f99c2efeSJean-Jacques Hiblot #else 1563f99c2efeSJean-Jacques Hiblot static inline int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage) 1564f99c2efeSJean-Jacques Hiblot { 1565f99c2efeSJean-Jacques Hiblot return 0; 1566f99c2efeSJean-Jacques Hiblot } 1567f99c2efeSJean-Jacques Hiblot #endif 1568aff5d3c8SKishon Vijay Abraham I 1569*62d77ceaSMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY) 1570d0c221feSJean-Jacques Hiblot static const struct mode_width_tuning sd_modes_by_pref[] = { 1571f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1572f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 1573d0c221feSJean-Jacques Hiblot { 1574c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR104, 1575c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1576c10b85d6SJean-Jacques Hiblot .tuning = MMC_CMD_SEND_TUNING_BLOCK 1577c10b85d6SJean-Jacques Hiblot }, 1578f99c2efeSJean-Jacques Hiblot #endif 1579c10b85d6SJean-Jacques Hiblot { 1580c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR50, 1581c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1582c10b85d6SJean-Jacques Hiblot }, 1583c10b85d6SJean-Jacques Hiblot { 1584c10b85d6SJean-Jacques Hiblot .mode = UHS_DDR50, 1585c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1586c10b85d6SJean-Jacques Hiblot }, 1587c10b85d6SJean-Jacques Hiblot { 1588c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR25, 1589c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1590c10b85d6SJean-Jacques Hiblot }, 1591f99c2efeSJean-Jacques Hiblot #endif 1592c10b85d6SJean-Jacques Hiblot { 1593d0c221feSJean-Jacques Hiblot .mode = SD_HS, 1594d0c221feSJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1595d0c221feSJean-Jacques Hiblot }, 1596f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1597d0c221feSJean-Jacques Hiblot { 1598c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR12, 1599c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1600c10b85d6SJean-Jacques Hiblot }, 1601f99c2efeSJean-Jacques Hiblot #endif 1602c10b85d6SJean-Jacques Hiblot { 1603d0c221feSJean-Jacques Hiblot .mode = SD_LEGACY, 1604d0c221feSJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT, 1605d0c221feSJean-Jacques Hiblot } 1606d0c221feSJean-Jacques Hiblot }; 1607d0c221feSJean-Jacques Hiblot 1608d0c221feSJean-Jacques Hiblot #define for_each_sd_mode_by_pref(caps, mwt) \ 1609d0c221feSJean-Jacques Hiblot for (mwt = sd_modes_by_pref;\ 1610d0c221feSJean-Jacques Hiblot mwt < sd_modes_by_pref + ARRAY_SIZE(sd_modes_by_pref);\ 1611d0c221feSJean-Jacques Hiblot mwt++) \ 1612d0c221feSJean-Jacques Hiblot if (caps & MMC_CAP(mwt->mode)) 1613d0c221feSJean-Jacques Hiblot 161401298da3SJean-Jacques Hiblot static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps) 16158ac8a263SJean-Jacques Hiblot { 16168ac8a263SJean-Jacques Hiblot int err; 1617d0c221feSJean-Jacques Hiblot uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT}; 1618d0c221feSJean-Jacques Hiblot const struct mode_width_tuning *mwt; 1619f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) 1620c10b85d6SJean-Jacques Hiblot bool uhs_en = (mmc->ocr & OCR_S18R) ? true : false; 1621f99c2efeSJean-Jacques Hiblot #else 1622f99c2efeSJean-Jacques Hiblot bool uhs_en = false; 1623f99c2efeSJean-Jacques Hiblot #endif 1624c10b85d6SJean-Jacques Hiblot uint caps; 1625c10b85d6SJean-Jacques Hiblot 162652d241dfSJean-Jacques Hiblot #ifdef DEBUG 162752d241dfSJean-Jacques Hiblot mmc_dump_capabilities("sd card", card_caps); 16281da8eb59SJean-Jacques Hiblot mmc_dump_capabilities("host", mmc->host_caps); 162952d241dfSJean-Jacques Hiblot #endif 16308ac8a263SJean-Jacques Hiblot 16318ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */ 16321da8eb59SJean-Jacques Hiblot caps = card_caps & mmc->host_caps; 16338ac8a263SJean-Jacques Hiblot 1634c10b85d6SJean-Jacques Hiblot if (!uhs_en) 1635c10b85d6SJean-Jacques Hiblot caps &= ~UHS_CAPS; 1636c10b85d6SJean-Jacques Hiblot 1637c10b85d6SJean-Jacques Hiblot for_each_sd_mode_by_pref(caps, mwt) { 1638d0c221feSJean-Jacques Hiblot uint *w; 16398ac8a263SJean-Jacques Hiblot 1640d0c221feSJean-Jacques Hiblot for (w = widths; w < widths + ARRAY_SIZE(widths); w++) { 1641c10b85d6SJean-Jacques Hiblot if (*w & caps & mwt->widths) { 1642d4d64889SMasahiro Yamada pr_debug("trying mode %s width %d (at %d MHz)\n", 1643d0c221feSJean-Jacques Hiblot mmc_mode_name(mwt->mode), 1644d0c221feSJean-Jacques Hiblot bus_width(*w), 1645d0c221feSJean-Jacques Hiblot mmc_mode2freq(mmc, mwt->mode) / 1000000); 1646d0c221feSJean-Jacques Hiblot 1647d0c221feSJean-Jacques Hiblot /* configure the bus width (card + host) */ 1648d0c221feSJean-Jacques Hiblot err = sd_select_bus_width(mmc, bus_width(*w)); 16498ac8a263SJean-Jacques Hiblot if (err) 1650d0c221feSJean-Jacques Hiblot goto error; 1651d0c221feSJean-Jacques Hiblot mmc_set_bus_width(mmc, bus_width(*w)); 16528ac8a263SJean-Jacques Hiblot 1653d0c221feSJean-Jacques Hiblot /* configure the bus mode (card) */ 1654d0c221feSJean-Jacques Hiblot err = sd_set_card_speed(mmc, mwt->mode); 16558ac8a263SJean-Jacques Hiblot if (err) 1656d0c221feSJean-Jacques Hiblot goto error; 16578ac8a263SJean-Jacques Hiblot 1658d0c221feSJean-Jacques Hiblot /* configure the bus mode (host) */ 1659d0c221feSJean-Jacques Hiblot mmc_select_mode(mmc, mwt->mode); 166065117182SJaehoon Chung mmc_set_clock(mmc, mmc->tran_speed, 166165117182SJaehoon Chung MMC_CLK_ENABLE); 16628ac8a263SJean-Jacques Hiblot 1663f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 1664c10b85d6SJean-Jacques Hiblot /* execute tuning if needed */ 1665c10b85d6SJean-Jacques Hiblot if (mwt->tuning && !mmc_host_is_spi(mmc)) { 1666c10b85d6SJean-Jacques Hiblot err = mmc_execute_tuning(mmc, 1667c10b85d6SJean-Jacques Hiblot mwt->tuning); 1668c10b85d6SJean-Jacques Hiblot if (err) { 1669d4d64889SMasahiro Yamada pr_debug("tuning failed\n"); 1670c10b85d6SJean-Jacques Hiblot goto error; 1671c10b85d6SJean-Jacques Hiblot } 1672c10b85d6SJean-Jacques Hiblot } 1673f99c2efeSJean-Jacques Hiblot #endif 1674c10b85d6SJean-Jacques Hiblot 16755b2e72f3SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE) 16768ac8a263SJean-Jacques Hiblot err = sd_read_ssr(mmc); 16770a4c2b09SPeng Fan if (err) 16785b2e72f3SJean-Jacques Hiblot pr_warn("unable to read ssr\n"); 16795b2e72f3SJean-Jacques Hiblot #endif 16805b2e72f3SJean-Jacques Hiblot if (!err) 16818ac8a263SJean-Jacques Hiblot return 0; 1682d0c221feSJean-Jacques Hiblot 1683d0c221feSJean-Jacques Hiblot error: 1684d0c221feSJean-Jacques Hiblot /* revert to a safer bus speed */ 1685d0c221feSJean-Jacques Hiblot mmc_select_mode(mmc, SD_LEGACY); 168665117182SJaehoon Chung mmc_set_clock(mmc, mmc->tran_speed, 168765117182SJaehoon Chung MMC_CLK_ENABLE); 1688d0c221feSJean-Jacques Hiblot } 1689d0c221feSJean-Jacques Hiblot } 1690d0c221feSJean-Jacques Hiblot } 1691d0c221feSJean-Jacques Hiblot 1692d4d64889SMasahiro Yamada pr_err("unable to select a mode\n"); 1693d0c221feSJean-Jacques Hiblot return -ENOTSUPP; 16948ac8a263SJean-Jacques Hiblot } 16958ac8a263SJean-Jacques Hiblot 16967382e691SJean-Jacques Hiblot /* 16977382e691SJean-Jacques Hiblot * read the compare the part of ext csd that is constant. 16987382e691SJean-Jacques Hiblot * This can be used to check that the transfer is working 16997382e691SJean-Jacques Hiblot * as expected. 17007382e691SJean-Jacques Hiblot */ 17017382e691SJean-Jacques Hiblot static int mmc_read_and_compare_ext_csd(struct mmc *mmc) 17027382e691SJean-Jacques Hiblot { 17037382e691SJean-Jacques Hiblot int err; 17047382e691SJean-Jacques Hiblot const u8 *ext_csd = mmc->ext_csd; 17057382e691SJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN); 17067382e691SJean-Jacques Hiblot 17071de06b9fSJean-Jacques Hiblot if (mmc->version < MMC_VERSION_4) 17081de06b9fSJean-Jacques Hiblot return 0; 17091de06b9fSJean-Jacques Hiblot 17107382e691SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, test_csd); 17117382e691SJean-Jacques Hiblot if (err) 17127382e691SJean-Jacques Hiblot return err; 17137382e691SJean-Jacques Hiblot 17147382e691SJean-Jacques Hiblot /* Only compare read only fields */ 17157382e691SJean-Jacques Hiblot if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] 17167382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_PARTITIONING_SUPPORT] && 17177382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_WP_GRP_SIZE] 17187382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_WP_GRP_SIZE] && 17197382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_REV] 17207382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_REV] && 17217382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 17227382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] && 17237382e691SJean-Jacques Hiblot memcmp(&ext_csd[EXT_CSD_SEC_CNT], 17247382e691SJean-Jacques Hiblot &test_csd[EXT_CSD_SEC_CNT], 4) == 0) 17257382e691SJean-Jacques Hiblot return 0; 17267382e691SJean-Jacques Hiblot 17277382e691SJean-Jacques Hiblot return -EBADMSG; 17287382e691SJean-Jacques Hiblot } 17297382e691SJean-Jacques Hiblot 1730f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE) 1731bc1e3272SJean-Jacques Hiblot static int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode, 1732bc1e3272SJean-Jacques Hiblot uint32_t allowed_mask) 1733bc1e3272SJean-Jacques Hiblot { 1734bc1e3272SJean-Jacques Hiblot u32 card_mask = 0; 1735bc1e3272SJean-Jacques Hiblot 1736bc1e3272SJean-Jacques Hiblot switch (mode) { 1737bc1e3272SJean-Jacques Hiblot case MMC_HS_200: 1738bc1e3272SJean-Jacques Hiblot if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_8V) 1739bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_180; 1740bc1e3272SJean-Jacques Hiblot if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_2V) 1741bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_120; 1742bc1e3272SJean-Jacques Hiblot break; 1743bc1e3272SJean-Jacques Hiblot case MMC_DDR_52: 1744bc1e3272SJean-Jacques Hiblot if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V) 1745bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_330 | 1746bc1e3272SJean-Jacques Hiblot MMC_SIGNAL_VOLTAGE_180; 1747bc1e3272SJean-Jacques Hiblot if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_2V) 1748bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_120; 1749bc1e3272SJean-Jacques Hiblot break; 1750bc1e3272SJean-Jacques Hiblot default: 1751bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_330; 1752bc1e3272SJean-Jacques Hiblot break; 1753bc1e3272SJean-Jacques Hiblot } 1754bc1e3272SJean-Jacques Hiblot 1755bc1e3272SJean-Jacques Hiblot while (card_mask & allowed_mask) { 1756bc1e3272SJean-Jacques Hiblot enum mmc_voltage best_match; 1757bc1e3272SJean-Jacques Hiblot 1758bc1e3272SJean-Jacques Hiblot best_match = 1 << (ffs(card_mask & allowed_mask) - 1); 1759bc1e3272SJean-Jacques Hiblot if (!mmc_set_signal_voltage(mmc, best_match)) 1760bc1e3272SJean-Jacques Hiblot return 0; 1761bc1e3272SJean-Jacques Hiblot 1762bc1e3272SJean-Jacques Hiblot allowed_mask &= ~best_match; 1763bc1e3272SJean-Jacques Hiblot } 1764bc1e3272SJean-Jacques Hiblot 1765bc1e3272SJean-Jacques Hiblot return -ENOTSUPP; 1766bc1e3272SJean-Jacques Hiblot } 1767f99c2efeSJean-Jacques Hiblot #else 1768f99c2efeSJean-Jacques Hiblot static inline int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode, 1769f99c2efeSJean-Jacques Hiblot uint32_t allowed_mask) 1770f99c2efeSJean-Jacques Hiblot { 1771f99c2efeSJean-Jacques Hiblot return 0; 1772f99c2efeSJean-Jacques Hiblot } 1773f99c2efeSJean-Jacques Hiblot #endif 1774bc1e3272SJean-Jacques Hiblot 17753862b854SJean-Jacques Hiblot static const struct mode_width_tuning mmc_modes_by_pref[] = { 1776f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) 17778ac8a263SJean-Jacques Hiblot { 17783862b854SJean-Jacques Hiblot .mode = MMC_HS_200, 17793862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT, 1780634d4849SKishon Vijay Abraham I .tuning = MMC_CMD_SEND_TUNING_BLOCK_HS200 17813862b854SJean-Jacques Hiblot }, 1782f99c2efeSJean-Jacques Hiblot #endif 17833862b854SJean-Jacques Hiblot { 17843862b854SJean-Jacques Hiblot .mode = MMC_DDR_52, 17853862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT, 17863862b854SJean-Jacques Hiblot }, 17873862b854SJean-Jacques Hiblot { 17883862b854SJean-Jacques Hiblot .mode = MMC_HS_52, 17893862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 17903862b854SJean-Jacques Hiblot }, 17913862b854SJean-Jacques Hiblot { 17923862b854SJean-Jacques Hiblot .mode = MMC_HS, 17933862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 17943862b854SJean-Jacques Hiblot }, 17953862b854SJean-Jacques Hiblot { 17963862b854SJean-Jacques Hiblot .mode = MMC_LEGACY, 17973862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT, 17983862b854SJean-Jacques Hiblot } 17998ac8a263SJean-Jacques Hiblot }; 18008ac8a263SJean-Jacques Hiblot 18013862b854SJean-Jacques Hiblot #define for_each_mmc_mode_by_pref(caps, mwt) \ 18023862b854SJean-Jacques Hiblot for (mwt = mmc_modes_by_pref;\ 18033862b854SJean-Jacques Hiblot mwt < mmc_modes_by_pref + ARRAY_SIZE(mmc_modes_by_pref);\ 18043862b854SJean-Jacques Hiblot mwt++) \ 18053862b854SJean-Jacques Hiblot if (caps & MMC_CAP(mwt->mode)) 18063862b854SJean-Jacques Hiblot 18073862b854SJean-Jacques Hiblot static const struct ext_csd_bus_width { 18083862b854SJean-Jacques Hiblot uint cap; 18093862b854SJean-Jacques Hiblot bool is_ddr; 18103862b854SJean-Jacques Hiblot uint ext_csd_bits; 18113862b854SJean-Jacques Hiblot } ext_csd_bus_width[] = { 18123862b854SJean-Jacques Hiblot {MMC_MODE_8BIT, true, EXT_CSD_DDR_BUS_WIDTH_8}, 18133862b854SJean-Jacques Hiblot {MMC_MODE_4BIT, true, EXT_CSD_DDR_BUS_WIDTH_4}, 18143862b854SJean-Jacques Hiblot {MMC_MODE_8BIT, false, EXT_CSD_BUS_WIDTH_8}, 18153862b854SJean-Jacques Hiblot {MMC_MODE_4BIT, false, EXT_CSD_BUS_WIDTH_4}, 18163862b854SJean-Jacques Hiblot {MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1}, 18173862b854SJean-Jacques Hiblot }; 18183862b854SJean-Jacques Hiblot 18193862b854SJean-Jacques Hiblot #define for_each_supported_width(caps, ddr, ecbv) \ 18203862b854SJean-Jacques Hiblot for (ecbv = ext_csd_bus_width;\ 18213862b854SJean-Jacques Hiblot ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\ 18223862b854SJean-Jacques Hiblot ecbv++) \ 18233862b854SJean-Jacques Hiblot if ((ddr == ecbv->is_ddr) && (caps & ecbv->cap)) 18243862b854SJean-Jacques Hiblot 182501298da3SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps) 18263862b854SJean-Jacques Hiblot { 18273862b854SJean-Jacques Hiblot int err; 18283862b854SJean-Jacques Hiblot const struct mode_width_tuning *mwt; 18293862b854SJean-Jacques Hiblot const struct ext_csd_bus_width *ecbw; 18303862b854SJean-Jacques Hiblot 183152d241dfSJean-Jacques Hiblot #ifdef DEBUG 183252d241dfSJean-Jacques Hiblot mmc_dump_capabilities("mmc", card_caps); 18331da8eb59SJean-Jacques Hiblot mmc_dump_capabilities("host", mmc->host_caps); 183452d241dfSJean-Jacques Hiblot #endif 183552d241dfSJean-Jacques Hiblot 18368ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */ 18371da8eb59SJean-Jacques Hiblot card_caps &= mmc->host_caps; 18388ac8a263SJean-Jacques Hiblot 18398ac8a263SJean-Jacques Hiblot /* Only version 4 of MMC supports wider bus widths */ 18408ac8a263SJean-Jacques Hiblot if (mmc->version < MMC_VERSION_4) 18418ac8a263SJean-Jacques Hiblot return 0; 18428ac8a263SJean-Jacques Hiblot 1843dfda9d88SJean-Jacques Hiblot if (!mmc->ext_csd) { 1844d4d64889SMasahiro Yamada pr_debug("No ext_csd found!\n"); /* this should enver happen */ 1845dfda9d88SJean-Jacques Hiblot return -ENOTSUPP; 1846dfda9d88SJean-Jacques Hiblot } 1847dfda9d88SJean-Jacques Hiblot 184865117182SJaehoon Chung mmc_set_clock(mmc, mmc->legacy_speed, MMC_CLK_ENABLE); 184901298da3SJean-Jacques Hiblot 185001298da3SJean-Jacques Hiblot for_each_mmc_mode_by_pref(card_caps, mwt) { 185101298da3SJean-Jacques Hiblot for_each_supported_width(card_caps & mwt->widths, 18523862b854SJean-Jacques Hiblot mmc_is_mode_ddr(mwt->mode), ecbw) { 1853bc1e3272SJean-Jacques Hiblot enum mmc_voltage old_voltage; 1854d4d64889SMasahiro Yamada pr_debug("trying mode %s width %d (at %d MHz)\n", 18553862b854SJean-Jacques Hiblot mmc_mode_name(mwt->mode), 18563862b854SJean-Jacques Hiblot bus_width(ecbw->cap), 18573862b854SJean-Jacques Hiblot mmc_mode2freq(mmc, mwt->mode) / 1000000); 1858bc1e3272SJean-Jacques Hiblot old_voltage = mmc->signal_voltage; 1859bc1e3272SJean-Jacques Hiblot err = mmc_set_lowest_voltage(mmc, mwt->mode, 1860bc1e3272SJean-Jacques Hiblot MMC_ALL_SIGNAL_VOLTAGE); 1861bc1e3272SJean-Jacques Hiblot if (err) 1862bc1e3272SJean-Jacques Hiblot continue; 1863bc1e3272SJean-Jacques Hiblot 18643862b854SJean-Jacques Hiblot /* configure the bus width (card + host) */ 18653862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 18663862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, 18673862b854SJean-Jacques Hiblot ecbw->ext_csd_bits & ~EXT_CSD_DDR_FLAG); 18683862b854SJean-Jacques Hiblot if (err) 18693862b854SJean-Jacques Hiblot goto error; 18703862b854SJean-Jacques Hiblot mmc_set_bus_width(mmc, bus_width(ecbw->cap)); 18713862b854SJean-Jacques Hiblot 18723862b854SJean-Jacques Hiblot /* configure the bus speed (card) */ 18733862b854SJean-Jacques Hiblot err = mmc_set_card_speed(mmc, mwt->mode); 18743862b854SJean-Jacques Hiblot if (err) 18753862b854SJean-Jacques Hiblot goto error; 18763862b854SJean-Jacques Hiblot 18778ac8a263SJean-Jacques Hiblot /* 18783862b854SJean-Jacques Hiblot * configure the bus width AND the ddr mode (card) 18793862b854SJean-Jacques Hiblot * The host side will be taken care of in the next step 18808ac8a263SJean-Jacques Hiblot */ 18813862b854SJean-Jacques Hiblot if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) { 18823862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 18833862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, 18843862b854SJean-Jacques Hiblot ecbw->ext_csd_bits); 18853862b854SJean-Jacques Hiblot if (err) 18863862b854SJean-Jacques Hiblot goto error; 18878ac8a263SJean-Jacques Hiblot } 18888ac8a263SJean-Jacques Hiblot 18893862b854SJean-Jacques Hiblot /* configure the bus mode (host) */ 18903862b854SJean-Jacques Hiblot mmc_select_mode(mmc, mwt->mode); 189165117182SJaehoon Chung mmc_set_clock(mmc, mmc->tran_speed, MMC_CLK_ENABLE); 1892f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING 18938ac8a263SJean-Jacques Hiblot 1894634d4849SKishon Vijay Abraham I /* execute tuning if needed */ 1895634d4849SKishon Vijay Abraham I if (mwt->tuning) { 1896634d4849SKishon Vijay Abraham I err = mmc_execute_tuning(mmc, mwt->tuning); 1897634d4849SKishon Vijay Abraham I if (err) { 1898d4d64889SMasahiro Yamada pr_debug("tuning failed\n"); 1899634d4849SKishon Vijay Abraham I goto error; 1900634d4849SKishon Vijay Abraham I } 1901634d4849SKishon Vijay Abraham I } 1902f99c2efeSJean-Jacques Hiblot #endif 1903634d4849SKishon Vijay Abraham I 19043862b854SJean-Jacques Hiblot /* do a transfer to check the configuration */ 19057382e691SJean-Jacques Hiblot err = mmc_read_and_compare_ext_csd(mmc); 19067382e691SJean-Jacques Hiblot if (!err) 19073862b854SJean-Jacques Hiblot return 0; 19083862b854SJean-Jacques Hiblot error: 1909bc1e3272SJean-Jacques Hiblot mmc_set_signal_voltage(mmc, old_voltage); 19103862b854SJean-Jacques Hiblot /* if an error occured, revert to a safer bus mode */ 19113862b854SJean-Jacques Hiblot mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 19123862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1); 19133862b854SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_LEGACY); 19143862b854SJean-Jacques Hiblot mmc_set_bus_width(mmc, 1); 19153862b854SJean-Jacques Hiblot } 19168ac8a263SJean-Jacques Hiblot } 19178ac8a263SJean-Jacques Hiblot 1918d8e3d420SJean-Jacques Hiblot pr_err("unable to select a mode\n"); 19198ac8a263SJean-Jacques Hiblot 19203862b854SJean-Jacques Hiblot return -ENOTSUPP; 19218ac8a263SJean-Jacques Hiblot } 1922*62d77ceaSMarek Vasut #endif 1923*62d77ceaSMarek Vasut 1924*62d77ceaSMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY) 1925*62d77ceaSMarek Vasut DEFINE_CACHE_ALIGN_BUFFER(u8, ext_csd_bkup, MMC_MAX_BLOCK_LEN); 1926*62d77ceaSMarek Vasut #endif 19278ac8a263SJean-Jacques Hiblot 1928dfda9d88SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc) 1929c744b6f6SJean-Jacques Hiblot { 1930c744b6f6SJean-Jacques Hiblot int err, i; 1931c744b6f6SJean-Jacques Hiblot u64 capacity; 1932c744b6f6SJean-Jacques Hiblot bool has_parts = false; 1933c744b6f6SJean-Jacques Hiblot bool part_completed; 193458a6fb7bSJean-Jacques Hiblot static const u32 mmc_versions[] = { 193558a6fb7bSJean-Jacques Hiblot MMC_VERSION_4, 193658a6fb7bSJean-Jacques Hiblot MMC_VERSION_4_1, 193758a6fb7bSJean-Jacques Hiblot MMC_VERSION_4_2, 193858a6fb7bSJean-Jacques Hiblot MMC_VERSION_4_3, 1939ace1bed3SJean-Jacques Hiblot MMC_VERSION_4_4, 194058a6fb7bSJean-Jacques Hiblot MMC_VERSION_4_41, 194158a6fb7bSJean-Jacques Hiblot MMC_VERSION_4_5, 194258a6fb7bSJean-Jacques Hiblot MMC_VERSION_5_0, 194358a6fb7bSJean-Jacques Hiblot MMC_VERSION_5_1 194458a6fb7bSJean-Jacques Hiblot }; 194558a6fb7bSJean-Jacques Hiblot 1946*62d77ceaSMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY) 1947*62d77ceaSMarek Vasut u8 *ext_csd = ext_csd_bkup; 1948*62d77ceaSMarek Vasut 1949*62d77ceaSMarek Vasut if (IS_SD(mmc) || mmc->version < MMC_VERSION_4) 1950*62d77ceaSMarek Vasut return 0; 1951*62d77ceaSMarek Vasut 1952*62d77ceaSMarek Vasut if (!mmc->ext_csd) 1953*62d77ceaSMarek Vasut memset(ext_csd_bkup, 0, sizeof(ext_csd_bkup)); 1954*62d77ceaSMarek Vasut 1955*62d77ceaSMarek Vasut err = mmc_send_ext_csd(mmc, ext_csd); 1956*62d77ceaSMarek Vasut if (err) 1957*62d77ceaSMarek Vasut goto error; 1958*62d77ceaSMarek Vasut 1959*62d77ceaSMarek Vasut /* store the ext csd for future reference */ 1960*62d77ceaSMarek Vasut if (!mmc->ext_csd) 1961*62d77ceaSMarek Vasut mmc->ext_csd = ext_csd; 1962*62d77ceaSMarek Vasut #else 1963f7d5dffcSJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 1964c744b6f6SJean-Jacques Hiblot 1965c744b6f6SJean-Jacques Hiblot if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4)) 1966c744b6f6SJean-Jacques Hiblot return 0; 1967c744b6f6SJean-Jacques Hiblot 1968c744b6f6SJean-Jacques Hiblot /* check ext_csd version and capacity */ 1969c744b6f6SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, ext_csd); 1970c744b6f6SJean-Jacques Hiblot if (err) 1971f7d5dffcSJean-Jacques Hiblot goto error; 1972f7d5dffcSJean-Jacques Hiblot 1973f7d5dffcSJean-Jacques Hiblot /* store the ext csd for future reference */ 1974f7d5dffcSJean-Jacques Hiblot if (!mmc->ext_csd) 1975f7d5dffcSJean-Jacques Hiblot mmc->ext_csd = malloc(MMC_MAX_BLOCK_LEN); 1976f7d5dffcSJean-Jacques Hiblot if (!mmc->ext_csd) 1977f7d5dffcSJean-Jacques Hiblot return -ENOMEM; 1978f7d5dffcSJean-Jacques Hiblot memcpy(mmc->ext_csd, ext_csd, MMC_MAX_BLOCK_LEN); 1979*62d77ceaSMarek Vasut #endif 198076584e33SAlexander Kochetkov if (ext_csd[EXT_CSD_REV] >= ARRAY_SIZE(mmc_versions)) 198158a6fb7bSJean-Jacques Hiblot return -EINVAL; 198258a6fb7bSJean-Jacques Hiblot 198358a6fb7bSJean-Jacques Hiblot mmc->version = mmc_versions[ext_csd[EXT_CSD_REV]]; 198458a6fb7bSJean-Jacques Hiblot 198558a6fb7bSJean-Jacques Hiblot if (mmc->version >= MMC_VERSION_4_2) { 1986c744b6f6SJean-Jacques Hiblot /* 1987c744b6f6SJean-Jacques Hiblot * According to the JEDEC Standard, the value of 1988c744b6f6SJean-Jacques Hiblot * ext_csd's capacity is valid if the value is more 1989c744b6f6SJean-Jacques Hiblot * than 2GB 1990c744b6f6SJean-Jacques Hiblot */ 1991c744b6f6SJean-Jacques Hiblot capacity = ext_csd[EXT_CSD_SEC_CNT] << 0 1992c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 1] << 8 1993c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 2] << 16 1994c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 3] << 24; 1995c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN; 1996c744b6f6SJean-Jacques Hiblot if ((capacity >> 20) > 2 * 1024) 1997c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity; 1998c744b6f6SJean-Jacques Hiblot } 1999c744b6f6SJean-Jacques Hiblot 2000c744b6f6SJean-Jacques Hiblot /* The partition data may be non-zero but it is only 2001c744b6f6SJean-Jacques Hiblot * effective if PARTITION_SETTING_COMPLETED is set in 2002c744b6f6SJean-Jacques Hiblot * EXT_CSD, so ignore any data if this bit is not set, 2003c744b6f6SJean-Jacques Hiblot * except for enabling the high-capacity group size 2004c744b6f6SJean-Jacques Hiblot * definition (see below). 2005c744b6f6SJean-Jacques Hiblot */ 2006c744b6f6SJean-Jacques Hiblot part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] & 2007c744b6f6SJean-Jacques Hiblot EXT_CSD_PARTITION_SETTING_COMPLETED); 2008c744b6f6SJean-Jacques Hiblot 2009c744b6f6SJean-Jacques Hiblot /* store the partition info of emmc */ 2010c744b6f6SJean-Jacques Hiblot mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT]; 2011c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) || 2012c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_BOOT_MULT]) 2013c744b6f6SJean-Jacques Hiblot mmc->part_config = ext_csd[EXT_CSD_PART_CONF]; 2014c744b6f6SJean-Jacques Hiblot if (part_completed && 2015c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT)) 2016c744b6f6SJean-Jacques Hiblot mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE]; 2017c744b6f6SJean-Jacques Hiblot 2018c744b6f6SJean-Jacques Hiblot mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17; 2019c744b6f6SJean-Jacques Hiblot 2020c744b6f6SJean-Jacques Hiblot mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17; 2021c744b6f6SJean-Jacques Hiblot 2022c744b6f6SJean-Jacques Hiblot for (i = 0; i < 4; i++) { 2023c744b6f6SJean-Jacques Hiblot int idx = EXT_CSD_GP_SIZE_MULT + i * 3; 2024c744b6f6SJean-Jacques Hiblot uint mult = (ext_csd[idx + 2] << 16) + 2025c744b6f6SJean-Jacques Hiblot (ext_csd[idx + 1] << 8) + ext_csd[idx]; 2026c744b6f6SJean-Jacques Hiblot if (mult) 2027c744b6f6SJean-Jacques Hiblot has_parts = true; 2028c744b6f6SJean-Jacques Hiblot if (!part_completed) 2029c744b6f6SJean-Jacques Hiblot continue; 2030c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] = mult; 2031c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= 2032c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 2033c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 2034c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] <<= 19; 2035c744b6f6SJean-Jacques Hiblot } 2036c744b6f6SJean-Jacques Hiblot 2037173c06dfSJean-Jacques Hiblot #ifndef CONFIG_SPL_BUILD 2038c744b6f6SJean-Jacques Hiblot if (part_completed) { 2039c744b6f6SJean-Jacques Hiblot mmc->enh_user_size = 2040c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) + 2041c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) + 2042c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_SIZE_MULT]; 2043c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]; 2044c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 2045c744b6f6SJean-Jacques Hiblot mmc->enh_user_size <<= 19; 2046c744b6f6SJean-Jacques Hiblot mmc->enh_user_start = 2047c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) + 2048c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) + 2049c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) + 2050c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_START_ADDR]; 2051c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity) 2052c744b6f6SJean-Jacques Hiblot mmc->enh_user_start <<= 9; 2053c744b6f6SJean-Jacques Hiblot } 2054173c06dfSJean-Jacques Hiblot #endif 2055c744b6f6SJean-Jacques Hiblot 2056c744b6f6SJean-Jacques Hiblot /* 2057c744b6f6SJean-Jacques Hiblot * Host needs to enable ERASE_GRP_DEF bit if device is 2058c744b6f6SJean-Jacques Hiblot * partitioned. This bit will be lost every time after a reset 2059c744b6f6SJean-Jacques Hiblot * or power off. This will affect erase size. 2060c744b6f6SJean-Jacques Hiblot */ 2061c744b6f6SJean-Jacques Hiblot if (part_completed) 2062c744b6f6SJean-Jacques Hiblot has_parts = true; 2063c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) && 2064c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB)) 2065c744b6f6SJean-Jacques Hiblot has_parts = true; 2066c744b6f6SJean-Jacques Hiblot if (has_parts) { 2067c744b6f6SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, 2068c744b6f6SJean-Jacques Hiblot EXT_CSD_ERASE_GROUP_DEF, 1); 2069c744b6f6SJean-Jacques Hiblot 2070c744b6f6SJean-Jacques Hiblot if (err) 2071f7d5dffcSJean-Jacques Hiblot goto error; 2072c744b6f6SJean-Jacques Hiblot 2073c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1; 2074c744b6f6SJean-Jacques Hiblot } 2075c744b6f6SJean-Jacques Hiblot 2076c744b6f6SJean-Jacques Hiblot if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) { 2077e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE) 2078c744b6f6SJean-Jacques Hiblot /* Read out group size from ext_csd */ 2079c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = 2080c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024; 2081e6fa5a54SJean-Jacques Hiblot #endif 2082c744b6f6SJean-Jacques Hiblot /* 2083c744b6f6SJean-Jacques Hiblot * if high capacity and partition setting completed 2084c744b6f6SJean-Jacques Hiblot * SEC_COUNT is valid even if it is smaller than 2 GiB 2085c744b6f6SJean-Jacques Hiblot * JEDEC Standard JESD84-B45, 6.2.4 2086c744b6f6SJean-Jacques Hiblot */ 2087c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity && part_completed) { 2088c744b6f6SJean-Jacques Hiblot capacity = (ext_csd[EXT_CSD_SEC_CNT]) | 2089c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) | 2090c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) | 2091c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 3] << 24); 2092c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN; 2093c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity; 2094c744b6f6SJean-Jacques Hiblot } 2095e6fa5a54SJean-Jacques Hiblot } 2096e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE) 2097e6fa5a54SJean-Jacques Hiblot else { 2098c744b6f6SJean-Jacques Hiblot /* Calculate the group size from the csd value. */ 2099c744b6f6SJean-Jacques Hiblot int erase_gsz, erase_gmul; 2100c744b6f6SJean-Jacques Hiblot 2101c744b6f6SJean-Jacques Hiblot erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10; 2102c744b6f6SJean-Jacques Hiblot erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5; 2103c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = (erase_gsz + 1) 2104c744b6f6SJean-Jacques Hiblot * (erase_gmul + 1); 2105c744b6f6SJean-Jacques Hiblot } 2106e6fa5a54SJean-Jacques Hiblot #endif 2107b7a6e2c9SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING) 2108c744b6f6SJean-Jacques Hiblot mmc->hc_wp_grp_size = 1024 2109c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] 2110c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_WP_GRP_SIZE]; 2111b7a6e2c9SJean-Jacques Hiblot #endif 2112c744b6f6SJean-Jacques Hiblot 2113c744b6f6SJean-Jacques Hiblot mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET]; 2114c744b6f6SJean-Jacques Hiblot 2115c744b6f6SJean-Jacques Hiblot return 0; 2116f7d5dffcSJean-Jacques Hiblot error: 2117f7d5dffcSJean-Jacques Hiblot if (mmc->ext_csd) { 2118*62d77ceaSMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY) 2119f7d5dffcSJean-Jacques Hiblot free(mmc->ext_csd); 2120*62d77ceaSMarek Vasut #endif 2121f7d5dffcSJean-Jacques Hiblot mmc->ext_csd = NULL; 2122f7d5dffcSJean-Jacques Hiblot } 2123f7d5dffcSJean-Jacques Hiblot return err; 2124c744b6f6SJean-Jacques Hiblot } 2125c744b6f6SJean-Jacques Hiblot 2126fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc) 2127272cc70bSAndy Fleming { 2128f866a46dSStephen Warren int err, i; 2129272cc70bSAndy Fleming uint mult, freq; 2130c744b6f6SJean-Jacques Hiblot u64 cmult, csize; 2131272cc70bSAndy Fleming struct mmc_cmd cmd; 2132c40fdca6SSimon Glass struct blk_desc *bdesc; 2133272cc70bSAndy Fleming 2134d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON 2135d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */ 2136d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF; 2137d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R1; 2138d52ebf10SThomas Chou cmd.cmdarg = 1; 2139d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL); 2140d52ebf10SThomas Chou if (err) 2141d52ebf10SThomas Chou return err; 2142d52ebf10SThomas Chou } 2143d52ebf10SThomas Chou #endif 2144d52ebf10SThomas Chou 2145272cc70bSAndy Fleming /* Put the Card in Identify Mode */ 2146d52ebf10SThomas Chou cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID : 2147d52ebf10SThomas Chou MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */ 2148272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 2149272cc70bSAndy Fleming cmd.cmdarg = 0; 2150272cc70bSAndy Fleming 2151272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2152272cc70bSAndy Fleming 215383dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS 215483dc4227SKishon Vijay Abraham I if (err && (mmc->quirks & MMC_QUIRK_RETRY_SEND_CID)) { 215583dc4227SKishon Vijay Abraham I int retries = 4; 215683dc4227SKishon Vijay Abraham I /* 215783dc4227SKishon Vijay Abraham I * It has been seen that SEND_CID may fail on the first 215883dc4227SKishon Vijay Abraham I * attempt, let's try a few more time 215983dc4227SKishon Vijay Abraham I */ 216083dc4227SKishon Vijay Abraham I do { 216183dc4227SKishon Vijay Abraham I err = mmc_send_cmd(mmc, &cmd, NULL); 216283dc4227SKishon Vijay Abraham I if (!err) 216383dc4227SKishon Vijay Abraham I break; 216483dc4227SKishon Vijay Abraham I } while (retries--); 216583dc4227SKishon Vijay Abraham I } 216683dc4227SKishon Vijay Abraham I #endif 216783dc4227SKishon Vijay Abraham I 2168272cc70bSAndy Fleming if (err) 2169272cc70bSAndy Fleming return err; 2170272cc70bSAndy Fleming 2171272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16); 2172272cc70bSAndy Fleming 2173272cc70bSAndy Fleming /* 2174272cc70bSAndy Fleming * For MMC cards, set the Relative Address. 2175272cc70bSAndy Fleming * For SD cards, get the Relatvie Address. 2176272cc70bSAndy Fleming * This also puts the cards into Standby State 2177272cc70bSAndy Fleming */ 2178d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 2179272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR; 2180272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 2181272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6; 2182272cc70bSAndy Fleming 2183272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2184272cc70bSAndy Fleming 2185272cc70bSAndy Fleming if (err) 2186272cc70bSAndy Fleming return err; 2187272cc70bSAndy Fleming 2188272cc70bSAndy Fleming if (IS_SD(mmc)) 2189998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff; 2190d52ebf10SThomas Chou } 2191272cc70bSAndy Fleming 2192272cc70bSAndy Fleming /* Get the Card-Specific Data */ 2193272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD; 2194272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2; 2195272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 2196272cc70bSAndy Fleming 2197272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2198272cc70bSAndy Fleming 2199272cc70bSAndy Fleming if (err) 2200272cc70bSAndy Fleming return err; 2201272cc70bSAndy Fleming 2202998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0]; 2203998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1]; 2204998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2]; 2205998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3]; 2206272cc70bSAndy Fleming 2207272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) { 22080b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf; 2209272cc70bSAndy Fleming 2210272cc70bSAndy Fleming switch (version) { 2211272cc70bSAndy Fleming case 0: 2212272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 2213272cc70bSAndy Fleming break; 2214272cc70bSAndy Fleming case 1: 2215272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4; 2216272cc70bSAndy Fleming break; 2217272cc70bSAndy Fleming case 2: 2218272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2; 2219272cc70bSAndy Fleming break; 2220272cc70bSAndy Fleming case 3: 2221272cc70bSAndy Fleming mmc->version = MMC_VERSION_3; 2222272cc70bSAndy Fleming break; 2223272cc70bSAndy Fleming case 4: 2224272cc70bSAndy Fleming mmc->version = MMC_VERSION_4; 2225272cc70bSAndy Fleming break; 2226272cc70bSAndy Fleming default: 2227272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2; 2228272cc70bSAndy Fleming break; 2229272cc70bSAndy Fleming } 2230272cc70bSAndy Fleming } 2231272cc70bSAndy Fleming 2232272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */ 22330b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)]; 22340b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)]; 2235272cc70bSAndy Fleming 223635f9e196SJean-Jacques Hiblot mmc->legacy_speed = freq * mult; 223735f9e196SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_LEGACY); 2238272cc70bSAndy Fleming 2239ab71188cSMarkus Niebel mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1); 2240998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf); 2241e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE) 2242272cc70bSAndy Fleming 2243272cc70bSAndy Fleming if (IS_SD(mmc)) 2244272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len; 2245272cc70bSAndy Fleming else 2246998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf); 2247e6fa5a54SJean-Jacques Hiblot #endif 2248272cc70bSAndy Fleming 2249272cc70bSAndy Fleming if (mmc->high_capacity) { 2250272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16 2251272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16; 2252272cc70bSAndy Fleming cmult = 8; 2253272cc70bSAndy Fleming } else { 2254272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2 2255272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30; 2256272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15; 2257272cc70bSAndy Fleming } 2258272cc70bSAndy Fleming 2259f866a46dSStephen Warren mmc->capacity_user = (csize + 1) << (cmult + 2); 2260f866a46dSStephen Warren mmc->capacity_user *= mmc->read_bl_len; 2261f866a46dSStephen Warren mmc->capacity_boot = 0; 2262f866a46dSStephen Warren mmc->capacity_rpmb = 0; 2263f866a46dSStephen Warren for (i = 0; i < 4; i++) 2264f866a46dSStephen Warren mmc->capacity_gp[i] = 0; 2265272cc70bSAndy Fleming 22668bfa195eSSimon Glass if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN) 22678bfa195eSSimon Glass mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 2268272cc70bSAndy Fleming 2269e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE) 22708bfa195eSSimon Glass if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN) 22718bfa195eSSimon Glass mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 2272e6fa5a54SJean-Jacques Hiblot #endif 2273272cc70bSAndy Fleming 2274ab71188cSMarkus Niebel if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) { 2275ab71188cSMarkus Niebel cmd.cmdidx = MMC_CMD_SET_DSR; 2276ab71188cSMarkus Niebel cmd.cmdarg = (mmc->dsr & 0xffff) << 16; 2277ab71188cSMarkus Niebel cmd.resp_type = MMC_RSP_NONE; 2278ab71188cSMarkus Niebel if (mmc_send_cmd(mmc, &cmd, NULL)) 2279d8e3d420SJean-Jacques Hiblot pr_warn("MMC: SET_DSR failed\n"); 2280ab71188cSMarkus Niebel } 2281ab71188cSMarkus Niebel 2282272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */ 2283d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */ 2284272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD; 2285fe8f7066SAjay Bhargav cmd.resp_type = MMC_RSP_R1; 2286272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16; 2287272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2288272cc70bSAndy Fleming 2289272cc70bSAndy Fleming if (err) 2290272cc70bSAndy Fleming return err; 2291d52ebf10SThomas Chou } 2292272cc70bSAndy Fleming 2293e6f99a56SLei Wen /* 2294e6f99a56SLei Wen * For SD, its erase group is always one sector 2295e6f99a56SLei Wen */ 2296e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE) 2297e6f99a56SLei Wen mmc->erase_grp_size = 1; 2298e6fa5a54SJean-Jacques Hiblot #endif 2299bc897b1dSLei Wen mmc->part_config = MMCPART_NOAVAILABLE; 2300c744b6f6SJean-Jacques Hiblot 2301dfda9d88SJean-Jacques Hiblot err = mmc_startup_v4(mmc); 23029cf199ebSDiego Santa Cruz if (err) 23039cf199ebSDiego Santa Cruz return err; 2304f866a46dSStephen Warren 2305c40fdca6SSimon Glass err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart); 2306f866a46dSStephen Warren if (err) 2307f866a46dSStephen Warren return err; 2308d23e2c09SSukumar Ghorai 2309*62d77ceaSMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY) 2310*62d77ceaSMarek Vasut mmc_set_clock(mmc, mmc->legacy_speed, false); 2311*62d77ceaSMarek Vasut mmc_select_mode(mmc, IS_SD(mmc) ? SD_LEGACY : MMC_LEGACY); 2312*62d77ceaSMarek Vasut mmc_set_bus_width(mmc, 1); 2313*62d77ceaSMarek Vasut #else 231401298da3SJean-Jacques Hiblot if (IS_SD(mmc)) { 231501298da3SJean-Jacques Hiblot err = sd_get_capabilities(mmc); 231601298da3SJean-Jacques Hiblot if (err) 231701298da3SJean-Jacques Hiblot return err; 231801298da3SJean-Jacques Hiblot err = sd_select_mode_and_width(mmc, mmc->card_caps); 231901298da3SJean-Jacques Hiblot } else { 232001298da3SJean-Jacques Hiblot err = mmc_get_capabilities(mmc); 232101298da3SJean-Jacques Hiblot if (err) 232201298da3SJean-Jacques Hiblot return err; 232301298da3SJean-Jacques Hiblot mmc_select_mode_and_width(mmc, mmc->card_caps); 232401298da3SJean-Jacques Hiblot } 2325*62d77ceaSMarek Vasut #endif 2326272cc70bSAndy Fleming if (err) 2327272cc70bSAndy Fleming return err; 2328272cc70bSAndy Fleming 232901298da3SJean-Jacques Hiblot mmc->best_mode = mmc->selected_mode; 2330272cc70bSAndy Fleming 23315af8f45cSAndrew Gabbasov /* Fix the block length for DDR mode */ 23325af8f45cSAndrew Gabbasov if (mmc->ddr_mode) { 23335af8f45cSAndrew Gabbasov mmc->read_bl_len = MMC_MAX_BLOCK_LEN; 2334e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE) 23355af8f45cSAndrew Gabbasov mmc->write_bl_len = MMC_MAX_BLOCK_LEN; 2336e6fa5a54SJean-Jacques Hiblot #endif 23375af8f45cSAndrew Gabbasov } 23385af8f45cSAndrew Gabbasov 2339272cc70bSAndy Fleming /* fill in device description */ 2340c40fdca6SSimon Glass bdesc = mmc_get_blk_desc(mmc); 2341c40fdca6SSimon Glass bdesc->lun = 0; 2342c40fdca6SSimon Glass bdesc->hwpart = 0; 2343c40fdca6SSimon Glass bdesc->type = 0; 2344c40fdca6SSimon Glass bdesc->blksz = mmc->read_bl_len; 2345c40fdca6SSimon Glass bdesc->log2blksz = LOG2(bdesc->blksz); 2346c40fdca6SSimon Glass bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len); 2347fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \ 2348fc011f64SSjoerd Simons (defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \ 2349fc011f64SSjoerd Simons !defined(CONFIG_USE_TINY_PRINTF)) 2350c40fdca6SSimon Glass sprintf(bdesc->vendor, "Man %06x Snr %04x%04x", 2351babce5f6STaylor Hutt mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff), 2352babce5f6STaylor Hutt (mmc->cid[3] >> 16) & 0xffff); 2353c40fdca6SSimon Glass sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff, 23540b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff, 2355babce5f6STaylor Hutt (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff, 2356babce5f6STaylor Hutt (mmc->cid[2] >> 24) & 0xff); 2357c40fdca6SSimon Glass sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf, 2358babce5f6STaylor Hutt (mmc->cid[2] >> 16) & 0xf); 235956196826SPaul Burton #else 2360c40fdca6SSimon Glass bdesc->vendor[0] = 0; 2361c40fdca6SSimon Glass bdesc->product[0] = 0; 2362c40fdca6SSimon Glass bdesc->revision[0] = 0; 236356196826SPaul Burton #endif 2364122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT) 2365c40fdca6SSimon Glass part_init(bdesc); 2366122efd43SMikhail Kshevetskiy #endif 2367272cc70bSAndy Fleming 2368272cc70bSAndy Fleming return 0; 2369272cc70bSAndy Fleming } 2370272cc70bSAndy Fleming 2371fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc) 2372272cc70bSAndy Fleming { 2373272cc70bSAndy Fleming struct mmc_cmd cmd; 2374272cc70bSAndy Fleming int err; 2375272cc70bSAndy Fleming 2376272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND; 2377272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */ 237893bfd616SPantelis Antoniou cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa; 2379272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7; 2380272cc70bSAndy Fleming 2381272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL); 2382272cc70bSAndy Fleming 2383272cc70bSAndy Fleming if (err) 2384272cc70bSAndy Fleming return err; 2385272cc70bSAndy Fleming 2386998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa) 2387915ffa52SJaehoon Chung return -EOPNOTSUPP; 2388272cc70bSAndy Fleming else 2389272cc70bSAndy Fleming mmc->version = SD_VERSION_2; 2390272cc70bSAndy Fleming 2391272cc70bSAndy Fleming return 0; 2392272cc70bSAndy Fleming } 2393272cc70bSAndy Fleming 2394c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 239595de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */ 239695de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void) 239795de9ab2SPaul Kocialkowski { 239895de9ab2SPaul Kocialkowski } 239905cbeb7cSSimon Glass #endif 240095de9ab2SPaul Kocialkowski 24012051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc) 24022051aefeSPeng Fan { 2403c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 240406ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR) 24052051aefeSPeng Fan int ret; 24062051aefeSPeng Fan 24072051aefeSPeng Fan ret = device_get_supply_regulator(mmc->dev, "vmmc-supply", 240806ec045fSJean-Jacques Hiblot &mmc->vmmc_supply); 240906ec045fSJean-Jacques Hiblot if (ret) 2410d4d64889SMasahiro Yamada pr_debug("%s: No vmmc supply\n", mmc->dev->name); 24112051aefeSPeng Fan 241206ec045fSJean-Jacques Hiblot ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply", 241306ec045fSJean-Jacques Hiblot &mmc->vqmmc_supply); 241406ec045fSJean-Jacques Hiblot if (ret) 2415d4d64889SMasahiro Yamada pr_debug("%s: No vqmmc supply\n", mmc->dev->name); 24162051aefeSPeng Fan #endif 241705cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */ 241805cbeb7cSSimon Glass /* 241905cbeb7cSSimon Glass * Driver model should use a regulator, as above, rather than calling 242005cbeb7cSSimon Glass * out to board code. 242105cbeb7cSSimon Glass */ 242205cbeb7cSSimon Glass board_mmc_power_init(); 242305cbeb7cSSimon Glass #endif 24242051aefeSPeng Fan return 0; 24252051aefeSPeng Fan } 24262051aefeSPeng Fan 2427fb7c3bebSKishon Vijay Abraham I /* 2428fb7c3bebSKishon Vijay Abraham I * put the host in the initial state: 2429fb7c3bebSKishon Vijay Abraham I * - turn on Vdd (card power supply) 2430fb7c3bebSKishon Vijay Abraham I * - configure the bus width and clock to minimal values 2431fb7c3bebSKishon Vijay Abraham I */ 2432fb7c3bebSKishon Vijay Abraham I static void mmc_set_initial_state(struct mmc *mmc) 2433fb7c3bebSKishon Vijay Abraham I { 2434fb7c3bebSKishon Vijay Abraham I int err; 2435fb7c3bebSKishon Vijay Abraham I 2436fb7c3bebSKishon Vijay Abraham I /* First try to set 3.3V. If it fails set to 1.8V */ 2437fb7c3bebSKishon Vijay Abraham I err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_330); 2438fb7c3bebSKishon Vijay Abraham I if (err != 0) 2439fb7c3bebSKishon Vijay Abraham I err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_180); 2440fb7c3bebSKishon Vijay Abraham I if (err != 0) 2441d8e3d420SJean-Jacques Hiblot pr_warn("mmc: failed to set signal voltage\n"); 2442fb7c3bebSKishon Vijay Abraham I 2443fb7c3bebSKishon Vijay Abraham I mmc_select_mode(mmc, MMC_LEGACY); 2444fb7c3bebSKishon Vijay Abraham I mmc_set_bus_width(mmc, 1); 244565117182SJaehoon Chung mmc_set_clock(mmc, 0, MMC_CLK_ENABLE); 2446fb7c3bebSKishon Vijay Abraham I } 2447fb7c3bebSKishon Vijay Abraham I 2448fb7c3bebSKishon Vijay Abraham I static int mmc_power_on(struct mmc *mmc) 2449fb7c3bebSKishon Vijay Abraham I { 2450fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR) 2451fb7c3bebSKishon Vijay Abraham I if (mmc->vmmc_supply) { 2452fb7c3bebSKishon Vijay Abraham I int ret = regulator_set_enable(mmc->vmmc_supply, true); 2453fb7c3bebSKishon Vijay Abraham I 2454fb7c3bebSKishon Vijay Abraham I if (ret) { 2455fb7c3bebSKishon Vijay Abraham I puts("Error enabling VMMC supply\n"); 2456fb7c3bebSKishon Vijay Abraham I return ret; 2457fb7c3bebSKishon Vijay Abraham I } 2458fb7c3bebSKishon Vijay Abraham I } 2459fb7c3bebSKishon Vijay Abraham I #endif 2460fb7c3bebSKishon Vijay Abraham I return 0; 2461fb7c3bebSKishon Vijay Abraham I } 2462fb7c3bebSKishon Vijay Abraham I 2463fb7c3bebSKishon Vijay Abraham I static int mmc_power_off(struct mmc *mmc) 2464fb7c3bebSKishon Vijay Abraham I { 246565117182SJaehoon Chung mmc_set_clock(mmc, 0, MMC_CLK_DISABLE); 2466fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR) 2467fb7c3bebSKishon Vijay Abraham I if (mmc->vmmc_supply) { 2468fb7c3bebSKishon Vijay Abraham I int ret = regulator_set_enable(mmc->vmmc_supply, false); 2469fb7c3bebSKishon Vijay Abraham I 2470fb7c3bebSKishon Vijay Abraham I if (ret) { 2471d4d64889SMasahiro Yamada pr_debug("Error disabling VMMC supply\n"); 2472fb7c3bebSKishon Vijay Abraham I return ret; 2473fb7c3bebSKishon Vijay Abraham I } 2474fb7c3bebSKishon Vijay Abraham I } 2475fb7c3bebSKishon Vijay Abraham I #endif 2476fb7c3bebSKishon Vijay Abraham I return 0; 2477fb7c3bebSKishon Vijay Abraham I } 2478fb7c3bebSKishon Vijay Abraham I 2479fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc) 2480fb7c3bebSKishon Vijay Abraham I { 2481fb7c3bebSKishon Vijay Abraham I int ret; 2482fb7c3bebSKishon Vijay Abraham I 2483fb7c3bebSKishon Vijay Abraham I ret = mmc_power_off(mmc); 2484fb7c3bebSKishon Vijay Abraham I if (ret) 2485fb7c3bebSKishon Vijay Abraham I return ret; 2486fb7c3bebSKishon Vijay Abraham I /* 2487fb7c3bebSKishon Vijay Abraham I * SD spec recommends at least 1ms of delay. Let's wait for 2ms 2488fb7c3bebSKishon Vijay Abraham I * to be on the safer side. 2489fb7c3bebSKishon Vijay Abraham I */ 2490fb7c3bebSKishon Vijay Abraham I udelay(2000); 2491fb7c3bebSKishon Vijay Abraham I return mmc_power_on(mmc); 2492fb7c3bebSKishon Vijay Abraham I } 2493fb7c3bebSKishon Vijay Abraham I 2494e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc) 2495272cc70bSAndy Fleming { 24968ca51e51SSimon Glass bool no_card; 2497c10b85d6SJean-Jacques Hiblot bool uhs_en = supports_uhs(mmc->cfg->host_caps); 2498afd5932bSMacpaul Lin int err; 2499272cc70bSAndy Fleming 25001da8eb59SJean-Jacques Hiblot /* 25011da8eb59SJean-Jacques Hiblot * all hosts are capable of 1 bit bus-width and able to use the legacy 25021da8eb59SJean-Jacques Hiblot * timings. 25031da8eb59SJean-Jacques Hiblot */ 25041da8eb59SJean-Jacques Hiblot mmc->host_caps = mmc->cfg->host_caps | MMC_CAP(SD_LEGACY) | 25051da8eb59SJean-Jacques Hiblot MMC_CAP(MMC_LEGACY) | MMC_MODE_1BIT; 250604a2ea24SJean-Jacques Hiblot 25072f516e4aSJun Nie #if !defined(CONFIG_MMC_BROKEN_CD) 2508ab769f22SPantelis Antoniou /* we pretend there's no card when init is NULL */ 25098ca51e51SSimon Glass no_card = mmc_getcd(mmc) == 0; 25102f516e4aSJun Nie #else 25112f516e4aSJun Nie no_card = 0; 25122f516e4aSJun Nie #endif 2513e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC) 25148ca51e51SSimon Glass no_card = no_card || (mmc->cfg->ops->init == NULL); 25158ca51e51SSimon Glass #endif 25168ca51e51SSimon Glass if (no_card) { 251748972d90SThierry Reding mmc->has_init = 0; 251856196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2519d4d64889SMasahiro Yamada pr_err("MMC: no card present\n"); 252056196826SPaul Burton #endif 2521915ffa52SJaehoon Chung return -ENOMEDIUM; 252248972d90SThierry Reding } 252348972d90SThierry Reding 2524bc897b1dSLei Wen if (mmc->has_init) 2525bc897b1dSLei Wen return 0; 2526bc897b1dSLei Wen 25275a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT 25285a8dbdc6SYangbo Lu mmc_adapter_card_type_ident(); 25295a8dbdc6SYangbo Lu #endif 25302051aefeSPeng Fan err = mmc_power_init(mmc); 25312051aefeSPeng Fan if (err) 25322051aefeSPeng Fan return err; 253395de9ab2SPaul Kocialkowski 253483dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS 253583dc4227SKishon Vijay Abraham I mmc->quirks = MMC_QUIRK_RETRY_SET_BLOCKLEN | 253683dc4227SKishon Vijay Abraham I MMC_QUIRK_RETRY_SEND_CID; 253783dc4227SKishon Vijay Abraham I #endif 253883dc4227SKishon Vijay Abraham I 253904a2ea24SJean-Jacques Hiblot err = mmc_power_cycle(mmc); 254004a2ea24SJean-Jacques Hiblot if (err) { 254104a2ea24SJean-Jacques Hiblot /* 254204a2ea24SJean-Jacques Hiblot * if power cycling is not supported, we should not try 254304a2ea24SJean-Jacques Hiblot * to use the UHS modes, because we wouldn't be able to 254404a2ea24SJean-Jacques Hiblot * recover from an error during the UHS initialization. 254504a2ea24SJean-Jacques Hiblot */ 2546d4d64889SMasahiro Yamada pr_debug("Unable to do a full power cycle. Disabling the UHS modes for safety\n"); 254704a2ea24SJean-Jacques Hiblot uhs_en = false; 254804a2ea24SJean-Jacques Hiblot mmc->host_caps &= ~UHS_CAPS; 2549fb7c3bebSKishon Vijay Abraham I err = mmc_power_on(mmc); 255004a2ea24SJean-Jacques Hiblot } 2551fb7c3bebSKishon Vijay Abraham I if (err) 2552fb7c3bebSKishon Vijay Abraham I return err; 2553fb7c3bebSKishon Vijay Abraham I 2554e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 25558ca51e51SSimon Glass /* The device has already been probed ready for use */ 25568ca51e51SSimon Glass #else 2557ab769f22SPantelis Antoniou /* made sure it's not NULL earlier */ 255893bfd616SPantelis Antoniou err = mmc->cfg->ops->init(mmc); 2559272cc70bSAndy Fleming if (err) 2560272cc70bSAndy Fleming return err; 25618ca51e51SSimon Glass #endif 2562786e8f81SAndrew Gabbasov mmc->ddr_mode = 0; 2563aff5d3c8SKishon Vijay Abraham I 2564c10b85d6SJean-Jacques Hiblot retry: 2565fb7c3bebSKishon Vijay Abraham I mmc_set_initial_state(mmc); 2566318a7a57SJean-Jacques Hiblot mmc_send_init_stream(mmc); 2567318a7a57SJean-Jacques Hiblot 2568272cc70bSAndy Fleming /* Reset the Card */ 2569272cc70bSAndy Fleming err = mmc_go_idle(mmc); 2570272cc70bSAndy Fleming 2571272cc70bSAndy Fleming if (err) 2572272cc70bSAndy Fleming return err; 2573272cc70bSAndy Fleming 2574bc897b1dSLei Wen /* The internal partition reset to user partition(0) at every CMD0*/ 2575c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->hwpart = 0; 2576bc897b1dSLei Wen 2577272cc70bSAndy Fleming /* Test for SD version 2 */ 2578272cc70bSAndy Fleming err = mmc_send_if_cond(mmc); 2579272cc70bSAndy Fleming 2580272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */ 2581c10b85d6SJean-Jacques Hiblot err = sd_send_op_cond(mmc, uhs_en); 2582c10b85d6SJean-Jacques Hiblot if (err && uhs_en) { 2583c10b85d6SJean-Jacques Hiblot uhs_en = false; 2584c10b85d6SJean-Jacques Hiblot mmc_power_cycle(mmc); 2585c10b85d6SJean-Jacques Hiblot goto retry; 2586c10b85d6SJean-Jacques Hiblot } 2587272cc70bSAndy Fleming 2588272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */ 2589915ffa52SJaehoon Chung if (err == -ETIMEDOUT) { 2590272cc70bSAndy Fleming err = mmc_send_op_cond(mmc); 2591272cc70bSAndy Fleming 2592bd47c135SAndrew Gabbasov if (err) { 259356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT) 2594d8e3d420SJean-Jacques Hiblot pr_err("Card did not respond to voltage select!\n"); 259556196826SPaul Burton #endif 2596915ffa52SJaehoon Chung return -EOPNOTSUPP; 2597272cc70bSAndy Fleming } 2598272cc70bSAndy Fleming } 2599272cc70bSAndy Fleming 2600bd47c135SAndrew Gabbasov if (!err) 2601e9550449SChe-Liang Chiou mmc->init_in_progress = 1; 2602e9550449SChe-Liang Chiou 2603e9550449SChe-Liang Chiou return err; 2604e9550449SChe-Liang Chiou } 2605e9550449SChe-Liang Chiou 2606e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc) 2607e9550449SChe-Liang Chiou { 2608e9550449SChe-Liang Chiou int err = 0; 2609e9550449SChe-Liang Chiou 2610bd47c135SAndrew Gabbasov mmc->init_in_progress = 0; 2611e9550449SChe-Liang Chiou if (mmc->op_cond_pending) 2612e9550449SChe-Liang Chiou err = mmc_complete_op_cond(mmc); 2613e9550449SChe-Liang Chiou 2614e9550449SChe-Liang Chiou if (!err) 2615bc897b1dSLei Wen err = mmc_startup(mmc); 2616bc897b1dSLei Wen if (err) 2617bc897b1dSLei Wen mmc->has_init = 0; 2618bc897b1dSLei Wen else 2619bc897b1dSLei Wen mmc->has_init = 1; 2620e9550449SChe-Liang Chiou return err; 2621e9550449SChe-Liang Chiou } 2622e9550449SChe-Liang Chiou 2623e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc) 2624e9550449SChe-Liang Chiou { 2625bd47c135SAndrew Gabbasov int err = 0; 262636332b6eSVipul Kumar __maybe_unused ulong start; 2627c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) 262833fb211dSSimon Glass struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev); 2629e9550449SChe-Liang Chiou 263033fb211dSSimon Glass upriv->mmc = mmc; 263133fb211dSSimon Glass #endif 2632e9550449SChe-Liang Chiou if (mmc->has_init) 2633e9550449SChe-Liang Chiou return 0; 2634d803fea5SMateusz Zalega 2635d803fea5SMateusz Zalega start = get_timer(0); 2636d803fea5SMateusz Zalega 2637e9550449SChe-Liang Chiou if (!mmc->init_in_progress) 2638e9550449SChe-Liang Chiou err = mmc_start_init(mmc); 2639e9550449SChe-Liang Chiou 2640bd47c135SAndrew Gabbasov if (!err) 2641e9550449SChe-Liang Chiou err = mmc_complete_init(mmc); 2642919b4858SJagan Teki if (err) 2643d4d64889SMasahiro Yamada pr_info("%s: %d, time %lu\n", __func__, err, get_timer(start)); 2644919b4858SJagan Teki 2645bc897b1dSLei Wen return err; 2646272cc70bSAndy Fleming } 2647272cc70bSAndy Fleming 2648ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val) 2649ab71188cSMarkus Niebel { 2650ab71188cSMarkus Niebel mmc->dsr = val; 2651ab71188cSMarkus Niebel return 0; 2652ab71188cSMarkus Niebel } 2653ab71188cSMarkus Niebel 2654cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */ 2655cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis) 2656272cc70bSAndy Fleming { 2657272cc70bSAndy Fleming return -1; 2658272cc70bSAndy Fleming } 2659272cc70bSAndy Fleming 2660cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */ 2661cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis) 2662cee9ab7cSJeroen Hofstee { 2663cee9ab7cSJeroen Hofstee return -1; 2664cee9ab7cSJeroen Hofstee } 2665272cc70bSAndy Fleming 2666e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit) 2667e9550449SChe-Liang Chiou { 2668e9550449SChe-Liang Chiou mmc->preinit = preinit; 2669e9550449SChe-Liang Chiou } 2670e9550449SChe-Liang Chiou 26718a856db2SFaiz Abbas #if CONFIG_IS_ENABLED(DM_MMC) 26728e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 26738e3332e2SSjoerd Simons { 26744a1db6d8SSimon Glass int ret, i; 26758e3332e2SSjoerd Simons struct uclass *uc; 26764a1db6d8SSimon Glass struct udevice *dev; 26778e3332e2SSjoerd Simons 26788e3332e2SSjoerd Simons ret = uclass_get(UCLASS_MMC, &uc); 26798e3332e2SSjoerd Simons if (ret) 26808e3332e2SSjoerd Simons return ret; 26818e3332e2SSjoerd Simons 26824a1db6d8SSimon Glass /* 26834a1db6d8SSimon Glass * Try to add them in sequence order. Really with driver model we 26844a1db6d8SSimon Glass * should allow holes, but the current MMC list does not allow that. 26854a1db6d8SSimon Glass * So if we request 0, 1, 3 we will get 0, 1, 2. 26864a1db6d8SSimon Glass */ 26874a1db6d8SSimon Glass for (i = 0; ; i++) { 26884a1db6d8SSimon Glass ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev); 26894a1db6d8SSimon Glass if (ret == -ENODEV) 26904a1db6d8SSimon Glass break; 26914a1db6d8SSimon Glass } 26924a1db6d8SSimon Glass uclass_foreach_dev(dev, uc) { 26934a1db6d8SSimon Glass ret = device_probe(dev); 26948e3332e2SSjoerd Simons if (ret) 2695d8e3d420SJean-Jacques Hiblot pr_err("%s - probe failed: %d\n", dev->name, ret); 26968e3332e2SSjoerd Simons } 26978e3332e2SSjoerd Simons 26988e3332e2SSjoerd Simons return 0; 26998e3332e2SSjoerd Simons } 27008e3332e2SSjoerd Simons #else 27018e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis) 27028e3332e2SSjoerd Simons { 27038e3332e2SSjoerd Simons if (board_mmc_init(bis) < 0) 27048e3332e2SSjoerd Simons cpu_mmc_init(bis); 27058e3332e2SSjoerd Simons 27068e3332e2SSjoerd Simons return 0; 27078e3332e2SSjoerd Simons } 27088e3332e2SSjoerd Simons #endif 2709e9550449SChe-Liang Chiou 2710272cc70bSAndy Fleming int mmc_initialize(bd_t *bis) 2711272cc70bSAndy Fleming { 27121b26bab1SDaniel Kochmański static int initialized = 0; 27138e3332e2SSjoerd Simons int ret; 27141b26bab1SDaniel Kochmański if (initialized) /* Avoid initializing mmc multiple times */ 27151b26bab1SDaniel Kochmański return 0; 27161b26bab1SDaniel Kochmański initialized = 1; 27171b26bab1SDaniel Kochmański 2718c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK) 2719b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY) 2720c40fdca6SSimon Glass mmc_list_init(); 2721c40fdca6SSimon Glass #endif 2722b5b838f1SMarek Vasut #endif 27238e3332e2SSjoerd Simons ret = mmc_probe(bis); 27248e3332e2SSjoerd Simons if (ret) 27258e3332e2SSjoerd Simons return ret; 2726272cc70bSAndy Fleming 2727bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD 2728272cc70bSAndy Fleming print_mmc_devices(','); 2729bb0dc108SYing Zhang #endif 2730272cc70bSAndy Fleming 2731c40fdca6SSimon Glass mmc_do_preinit(); 2732272cc70bSAndy Fleming return 0; 2733272cc70bSAndy Fleming } 2734cd3d4880STomas Melin 2735cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE 2736cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc) 2737cd3d4880STomas Melin { 2738cd3d4880STomas Melin int err; 2739cd3d4880STomas Melin ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN); 2740cd3d4880STomas Melin 2741cd3d4880STomas Melin err = mmc_send_ext_csd(mmc, ext_csd); 2742cd3d4880STomas Melin if (err) { 2743cd3d4880STomas Melin puts("Could not get ext_csd register values\n"); 2744cd3d4880STomas Melin return err; 2745cd3d4880STomas Melin } 2746cd3d4880STomas Melin 2747cd3d4880STomas Melin if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) { 2748cd3d4880STomas Melin puts("Background operations not supported on device\n"); 2749cd3d4880STomas Melin return -EMEDIUMTYPE; 2750cd3d4880STomas Melin } 2751cd3d4880STomas Melin 2752cd3d4880STomas Melin if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) { 2753cd3d4880STomas Melin puts("Background operations already enabled\n"); 2754cd3d4880STomas Melin return 0; 2755cd3d4880STomas Melin } 2756cd3d4880STomas Melin 2757cd3d4880STomas Melin err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1); 2758cd3d4880STomas Melin if (err) { 2759cd3d4880STomas Melin puts("Failed to enable manual background operations\n"); 2760cd3d4880STomas Melin return err; 2761cd3d4880STomas Melin } 2762cd3d4880STomas Melin 2763cd3d4880STomas Melin puts("Enabled manual background operations\n"); 2764cd3d4880STomas Melin 2765cd3d4880STomas Melin return 0; 2766cd3d4880STomas Melin } 2767cd3d4880STomas Melin #endif 2768