183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2272cc70bSAndy Fleming /*
3272cc70bSAndy Fleming * Copyright 2008, Freescale Semiconductor, Inc
4272cc70bSAndy Fleming * Andy Fleming
5272cc70bSAndy Fleming *
6272cc70bSAndy Fleming * Based vaguely on the Linux code
7272cc70bSAndy Fleming */
8272cc70bSAndy Fleming
9272cc70bSAndy Fleming #include <config.h>
10272cc70bSAndy Fleming #include <common.h>
11272cc70bSAndy Fleming #include <command.h>
128e3332e2SSjoerd Simons #include <dm.h>
138e3332e2SSjoerd Simons #include <dm/device-internal.h>
14d4622df3SStephen Warren #include <errno.h>
15272cc70bSAndy Fleming #include <mmc.h>
16272cc70bSAndy Fleming #include <part.h>
172051aefeSPeng Fan #include <power/regulator.h>
18272cc70bSAndy Fleming #include <malloc.h>
19cf92e05cSSimon Glass #include <memalign.h>
20272cc70bSAndy Fleming #include <linux/list.h>
219b1f942cSRabin Vincent #include <div64.h>
22da61fa5fSPaul Burton #include "mmc_private.h"
23272cc70bSAndy Fleming
24aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage);
25fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc);
2662d77ceaSMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY)
2701298da3SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps);
28b5b838f1SMarek Vasut #endif
29b5b838f1SMarek Vasut
30e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
31c10b85d6SJean-Jacques Hiblot
32f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
mmc_wait_dat0(struct mmc * mmc,int state,int timeout)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
board_mmc_getwp(struct mmc * mmc)39750121c3SJeroen Hofstee __weak int board_mmc_getwp(struct mmc *mmc)
40d23d8d7eSNikita Kiryanov {
41d23d8d7eSNikita Kiryanov return -1;
42d23d8d7eSNikita Kiryanov }
43d23d8d7eSNikita Kiryanov
mmc_getwp(struct mmc * mmc)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
board_mmc_getcd(struct mmc * mmc)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
mmmc_trace_before_send(struct mmc * mmc,struct mmc_cmd * cmd)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);
707d5ccb1aSMarek Vasut printf("\t\tARG\t\t\t 0x%08x\n", cmd->cmdarg);
71c0c76ebaSSimon Glass }
72c0c76ebaSSimon Glass
mmmc_trace_after_send(struct mmc * mmc,struct mmc_cmd * cmd,int ret)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:
867d5ccb1aSMarek Vasut 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:
907d5ccb1aSMarek Vasut printf("\t\tMMC_RSP_R1b\t\t 0x%08x \n",
915db2fe3aSRaffaele Recalcati cmd->response[0]);
925db2fe3aSRaffaele Recalcati break;
935db2fe3aSRaffaele Recalcati case MMC_RSP_R2:
947d5ccb1aSMarek Vasut printf("\t\tMMC_RSP_R2\t\t 0x%08x \n",
955db2fe3aSRaffaele Recalcati cmd->response[0]);
967d5ccb1aSMarek Vasut printf("\t\t \t\t 0x%08x \n",
975db2fe3aSRaffaele Recalcati cmd->response[1]);
987d5ccb1aSMarek Vasut printf("\t\t \t\t 0x%08x \n",
995db2fe3aSRaffaele Recalcati cmd->response[2]);
1007d5ccb1aSMarek Vasut 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++)
1107d5ccb1aSMarek Vasut printf("%02x ", *ptr--);
1115db2fe3aSRaffaele Recalcati printf("\n");
1125db2fe3aSRaffaele Recalcati }
1135db2fe3aSRaffaele Recalcati break;
1145db2fe3aSRaffaele Recalcati case MMC_RSP_R3:
1157d5ccb1aSMarek Vasut 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
mmc_trace_state(struct mmc * mmc,struct mmc_cmd * cmd)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)
mmc_mode_name(enum bus_mode mode)13535f9e196SJean-Jacques Hiblot const char *mmc_mode_name(enum bus_mode mode)
13635f9e196SJean-Jacques Hiblot {
13735f9e196SJean-Jacques Hiblot static const char *const names[] = {
13835f9e196SJean-Jacques Hiblot [MMC_LEGACY] = "MMC legacy",
13935f9e196SJean-Jacques Hiblot [SD_LEGACY] = "SD Legacy",
14035f9e196SJean-Jacques Hiblot [MMC_HS] = "MMC High Speed (26MHz)",
14135f9e196SJean-Jacques Hiblot [SD_HS] = "SD High Speed (50MHz)",
14235f9e196SJean-Jacques Hiblot [UHS_SDR12] = "UHS SDR12 (25MHz)",
14335f9e196SJean-Jacques Hiblot [UHS_SDR25] = "UHS SDR25 (50MHz)",
14435f9e196SJean-Jacques Hiblot [UHS_SDR50] = "UHS SDR50 (100MHz)",
14535f9e196SJean-Jacques Hiblot [UHS_SDR104] = "UHS SDR104 (208MHz)",
14635f9e196SJean-Jacques Hiblot [UHS_DDR50] = "UHS DDR50 (50MHz)",
14735f9e196SJean-Jacques Hiblot [MMC_HS_52] = "MMC High Speed (52MHz)",
14835f9e196SJean-Jacques Hiblot [MMC_DDR_52] = "MMC DDR52 (52MHz)",
14935f9e196SJean-Jacques Hiblot [MMC_HS_200] = "HS200 (200MHz)",
1503dd2626fSPeng Fan [MMC_HS_400] = "HS400 (200MHz)",
15135f9e196SJean-Jacques Hiblot };
15235f9e196SJean-Jacques Hiblot
15335f9e196SJean-Jacques Hiblot if (mode >= MMC_MODES_END)
15435f9e196SJean-Jacques Hiblot return "Unknown mode";
15535f9e196SJean-Jacques Hiblot else
15635f9e196SJean-Jacques Hiblot return names[mode];
15735f9e196SJean-Jacques Hiblot }
15835f9e196SJean-Jacques Hiblot #endif
15935f9e196SJean-Jacques Hiblot
mmc_mode2freq(struct mmc * mmc,enum bus_mode mode)16005038576SJean-Jacques Hiblot static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode)
16105038576SJean-Jacques Hiblot {
16205038576SJean-Jacques Hiblot static const int freqs[] = {
1631b313aa3SJaehoon Chung [MMC_LEGACY] = 25000000,
16405038576SJean-Jacques Hiblot [SD_LEGACY] = 25000000,
16505038576SJean-Jacques Hiblot [MMC_HS] = 26000000,
16605038576SJean-Jacques Hiblot [SD_HS] = 50000000,
1671b313aa3SJaehoon Chung [MMC_HS_52] = 52000000,
1681b313aa3SJaehoon Chung [MMC_DDR_52] = 52000000,
16905038576SJean-Jacques Hiblot [UHS_SDR12] = 25000000,
17005038576SJean-Jacques Hiblot [UHS_SDR25] = 50000000,
17105038576SJean-Jacques Hiblot [UHS_SDR50] = 100000000,
17205038576SJean-Jacques Hiblot [UHS_DDR50] = 50000000,
173f99c2efeSJean-Jacques Hiblot [UHS_SDR104] = 208000000,
17405038576SJean-Jacques Hiblot [MMC_HS_200] = 200000000,
1753dd2626fSPeng Fan [MMC_HS_400] = 200000000,
17605038576SJean-Jacques Hiblot };
17705038576SJean-Jacques Hiblot
17805038576SJean-Jacques Hiblot if (mode == MMC_LEGACY)
17905038576SJean-Jacques Hiblot return mmc->legacy_speed;
18005038576SJean-Jacques Hiblot else if (mode >= MMC_MODES_END)
18105038576SJean-Jacques Hiblot return 0;
18205038576SJean-Jacques Hiblot else
18305038576SJean-Jacques Hiblot return freqs[mode];
18405038576SJean-Jacques Hiblot }
18505038576SJean-Jacques Hiblot
mmc_select_mode(struct mmc * mmc,enum bus_mode mode)18635f9e196SJean-Jacques Hiblot static int mmc_select_mode(struct mmc *mmc, enum bus_mode mode)
18735f9e196SJean-Jacques Hiblot {
18835f9e196SJean-Jacques Hiblot mmc->selected_mode = mode;
18905038576SJean-Jacques Hiblot mmc->tran_speed = mmc_mode2freq(mmc, mode);
1903862b854SJean-Jacques Hiblot mmc->ddr_mode = mmc_is_mode_ddr(mode);
191d4d64889SMasahiro Yamada pr_debug("selecting mode %s (freq : %d MHz)\n", mmc_mode_name(mode),
19235f9e196SJean-Jacques Hiblot mmc->tran_speed / 1000000);
19335f9e196SJean-Jacques Hiblot return 0;
19435f9e196SJean-Jacques Hiblot }
19535f9e196SJean-Jacques Hiblot
196e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
mmc_send_cmd(struct mmc * mmc,struct mmc_cmd * cmd,struct mmc_data * data)197c0c76ebaSSimon Glass int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
198c0c76ebaSSimon Glass {
199c0c76ebaSSimon Glass int ret;
200c0c76ebaSSimon Glass
201c0c76ebaSSimon Glass mmmc_trace_before_send(mmc, cmd);
202c0c76ebaSSimon Glass ret = mmc->cfg->ops->send_cmd(mmc, cmd, data);
203c0c76ebaSSimon Glass mmmc_trace_after_send(mmc, cmd, ret);
204c0c76ebaSSimon Glass
2058635ff9eSMarek Vasut return ret;
206272cc70bSAndy Fleming }
2078ca51e51SSimon Glass #endif
208272cc70bSAndy Fleming
mmc_send_status(struct mmc * mmc,int timeout)209da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout)
2105d4fc8d9SRaffaele Recalcati {
2115d4fc8d9SRaffaele Recalcati struct mmc_cmd cmd;
212d617c426SJan Kloetzke int err, retries = 5;
2135d4fc8d9SRaffaele Recalcati
2145d4fc8d9SRaffaele Recalcati cmd.cmdidx = MMC_CMD_SEND_STATUS;
2155d4fc8d9SRaffaele Recalcati cmd.resp_type = MMC_RSP_R1;
216aaf3d41aSMarek Vasut if (!mmc_host_is_spi(mmc))
217aaf3d41aSMarek Vasut cmd.cmdarg = mmc->rca << 16;
2185d4fc8d9SRaffaele Recalcati
2191677eef4SAndrew Gabbasov while (1) {
2205d4fc8d9SRaffaele Recalcati err = mmc_send_cmd(mmc, &cmd, NULL);
221d617c426SJan Kloetzke if (!err) {
222d617c426SJan Kloetzke if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) &&
223d617c426SJan Kloetzke (cmd.response[0] & MMC_STATUS_CURR_STATE) !=
224d617c426SJan Kloetzke MMC_STATE_PRG)
2255d4fc8d9SRaffaele Recalcati break;
226d0c221feSJean-Jacques Hiblot
227d0c221feSJean-Jacques Hiblot if (cmd.response[0] & MMC_STATUS_MASK) {
22856196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2297d5ccb1aSMarek Vasut pr_err("Status Error: 0x%08x\n",
230d617c426SJan Kloetzke cmd.response[0]);
23156196826SPaul Burton #endif
232915ffa52SJaehoon Chung return -ECOMM;
233d617c426SJan Kloetzke }
234d617c426SJan Kloetzke } else if (--retries < 0)
235d617c426SJan Kloetzke return err;
2365d4fc8d9SRaffaele Recalcati
2371677eef4SAndrew Gabbasov if (timeout-- <= 0)
2381677eef4SAndrew Gabbasov break;
2395d4fc8d9SRaffaele Recalcati
2401677eef4SAndrew Gabbasov udelay(1000);
2411677eef4SAndrew Gabbasov }
2425d4fc8d9SRaffaele Recalcati
243c0c76ebaSSimon Glass mmc_trace_state(mmc, &cmd);
2445b0c942fSJongman Heo if (timeout <= 0) {
24556196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
246d8e3d420SJean-Jacques Hiblot pr_err("Timeout waiting card ready\n");
24756196826SPaul Burton #endif
248915ffa52SJaehoon Chung return -ETIMEDOUT;
2495d4fc8d9SRaffaele Recalcati }
2505d4fc8d9SRaffaele Recalcati
2515d4fc8d9SRaffaele Recalcati return 0;
2525d4fc8d9SRaffaele Recalcati }
2535d4fc8d9SRaffaele Recalcati
mmc_set_blocklen(struct mmc * mmc,int len)254da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len)
255272cc70bSAndy Fleming {
256272cc70bSAndy Fleming struct mmc_cmd cmd;
25783dc4227SKishon Vijay Abraham I int err;
258272cc70bSAndy Fleming
259786e8f81SAndrew Gabbasov if (mmc->ddr_mode)
260d22e3d46SJaehoon Chung return 0;
261d22e3d46SJaehoon Chung
262272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
263272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1;
264272cc70bSAndy Fleming cmd.cmdarg = len;
265272cc70bSAndy Fleming
26683dc4227SKishon Vijay Abraham I err = mmc_send_cmd(mmc, &cmd, NULL);
26783dc4227SKishon Vijay Abraham I
26883dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS
26983dc4227SKishon Vijay Abraham I if (err && (mmc->quirks & MMC_QUIRK_RETRY_SET_BLOCKLEN)) {
27083dc4227SKishon Vijay Abraham I int retries = 4;
27183dc4227SKishon Vijay Abraham I /*
27283dc4227SKishon Vijay Abraham I * It has been seen that SET_BLOCKLEN may fail on the first
27383dc4227SKishon Vijay Abraham I * attempt, let's try a few more time
27483dc4227SKishon Vijay Abraham I */
27583dc4227SKishon Vijay Abraham I do {
27683dc4227SKishon Vijay Abraham I err = mmc_send_cmd(mmc, &cmd, NULL);
27783dc4227SKishon Vijay Abraham I if (!err)
27883dc4227SKishon Vijay Abraham I break;
27983dc4227SKishon Vijay Abraham I } while (retries--);
28083dc4227SKishon Vijay Abraham I }
28183dc4227SKishon Vijay Abraham I #endif
28283dc4227SKishon Vijay Abraham I
28383dc4227SKishon Vijay Abraham I return err;
284272cc70bSAndy Fleming }
285272cc70bSAndy Fleming
286f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
2879815e3baSJean-Jacques Hiblot static const u8 tuning_blk_pattern_4bit[] = {
2889815e3baSJean-Jacques Hiblot 0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
2899815e3baSJean-Jacques Hiblot 0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
2909815e3baSJean-Jacques Hiblot 0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
2919815e3baSJean-Jacques Hiblot 0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
2929815e3baSJean-Jacques Hiblot 0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
2939815e3baSJean-Jacques Hiblot 0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
2949815e3baSJean-Jacques Hiblot 0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
2959815e3baSJean-Jacques Hiblot 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
2969815e3baSJean-Jacques Hiblot };
2979815e3baSJean-Jacques Hiblot
2989815e3baSJean-Jacques Hiblot static const u8 tuning_blk_pattern_8bit[] = {
2999815e3baSJean-Jacques Hiblot 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
3009815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
3019815e3baSJean-Jacques Hiblot 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
3029815e3baSJean-Jacques Hiblot 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
3039815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
3049815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
3059815e3baSJean-Jacques Hiblot 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
3069815e3baSJean-Jacques Hiblot 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
3079815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
3089815e3baSJean-Jacques Hiblot 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
3099815e3baSJean-Jacques Hiblot 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
3109815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
3119815e3baSJean-Jacques Hiblot 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
3129815e3baSJean-Jacques Hiblot 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
3139815e3baSJean-Jacques Hiblot 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
3149815e3baSJean-Jacques Hiblot 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
3159815e3baSJean-Jacques Hiblot };
3169815e3baSJean-Jacques Hiblot
mmc_send_tuning(struct mmc * mmc,u32 opcode,int * cmd_error)3179815e3baSJean-Jacques Hiblot int mmc_send_tuning(struct mmc *mmc, u32 opcode, int *cmd_error)
3189815e3baSJean-Jacques Hiblot {
3199815e3baSJean-Jacques Hiblot struct mmc_cmd cmd;
3209815e3baSJean-Jacques Hiblot struct mmc_data data;
3219815e3baSJean-Jacques Hiblot const u8 *tuning_block_pattern;
3229815e3baSJean-Jacques Hiblot int size, err;
3239815e3baSJean-Jacques Hiblot
3249815e3baSJean-Jacques Hiblot if (mmc->bus_width == 8) {
3259815e3baSJean-Jacques Hiblot tuning_block_pattern = tuning_blk_pattern_8bit;
3269815e3baSJean-Jacques Hiblot size = sizeof(tuning_blk_pattern_8bit);
3279815e3baSJean-Jacques Hiblot } else if (mmc->bus_width == 4) {
3289815e3baSJean-Jacques Hiblot tuning_block_pattern = tuning_blk_pattern_4bit;
3299815e3baSJean-Jacques Hiblot size = sizeof(tuning_blk_pattern_4bit);
3309815e3baSJean-Jacques Hiblot } else {
3319815e3baSJean-Jacques Hiblot return -EINVAL;
3329815e3baSJean-Jacques Hiblot }
3339815e3baSJean-Jacques Hiblot
3349815e3baSJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, data_buf, size);
3359815e3baSJean-Jacques Hiblot
3369815e3baSJean-Jacques Hiblot cmd.cmdidx = opcode;
3379815e3baSJean-Jacques Hiblot cmd.cmdarg = 0;
3389815e3baSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1;
3399815e3baSJean-Jacques Hiblot
3409815e3baSJean-Jacques Hiblot data.dest = (void *)data_buf;
3419815e3baSJean-Jacques Hiblot data.blocks = 1;
3429815e3baSJean-Jacques Hiblot data.blocksize = size;
3439815e3baSJean-Jacques Hiblot data.flags = MMC_DATA_READ;
3449815e3baSJean-Jacques Hiblot
3459815e3baSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, &data);
3469815e3baSJean-Jacques Hiblot if (err)
3479815e3baSJean-Jacques Hiblot return err;
3489815e3baSJean-Jacques Hiblot
3499815e3baSJean-Jacques Hiblot if (memcmp(data_buf, tuning_block_pattern, size))
3509815e3baSJean-Jacques Hiblot return -EIO;
3519815e3baSJean-Jacques Hiblot
3529815e3baSJean-Jacques Hiblot return 0;
3539815e3baSJean-Jacques Hiblot }
354f99c2efeSJean-Jacques Hiblot #endif
3559815e3baSJean-Jacques Hiblot
mmc_read_blocks(struct mmc * mmc,void * dst,lbaint_t start,lbaint_t blkcnt)356ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
357fdbb873eSKim Phillips lbaint_t blkcnt)
358272cc70bSAndy Fleming {
359272cc70bSAndy Fleming struct mmc_cmd cmd;
360272cc70bSAndy Fleming struct mmc_data data;
361272cc70bSAndy Fleming
3624a1a06bcSAlagu Sankar if (blkcnt > 1)
3634a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
3644a1a06bcSAlagu Sankar else
365272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
366272cc70bSAndy Fleming
367272cc70bSAndy Fleming if (mmc->high_capacity)
3684a1a06bcSAlagu Sankar cmd.cmdarg = start;
369272cc70bSAndy Fleming else
3704a1a06bcSAlagu Sankar cmd.cmdarg = start * mmc->read_bl_len;
371272cc70bSAndy Fleming
372272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1;
373272cc70bSAndy Fleming
374272cc70bSAndy Fleming data.dest = dst;
3754a1a06bcSAlagu Sankar data.blocks = blkcnt;
376272cc70bSAndy Fleming data.blocksize = mmc->read_bl_len;
377272cc70bSAndy Fleming data.flags = MMC_DATA_READ;
378272cc70bSAndy Fleming
3794a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, &data))
3804a1a06bcSAlagu Sankar return 0;
3814a1a06bcSAlagu Sankar
3824a1a06bcSAlagu Sankar if (blkcnt > 1) {
3834a1a06bcSAlagu Sankar cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
3844a1a06bcSAlagu Sankar cmd.cmdarg = 0;
3854a1a06bcSAlagu Sankar cmd.resp_type = MMC_RSP_R1b;
3864a1a06bcSAlagu Sankar if (mmc_send_cmd(mmc, &cmd, NULL)) {
38756196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
388d8e3d420SJean-Jacques Hiblot pr_err("mmc fail to send stop cmd\n");
38956196826SPaul Burton #endif
3904a1a06bcSAlagu Sankar return 0;
3914a1a06bcSAlagu Sankar }
392272cc70bSAndy Fleming }
393272cc70bSAndy Fleming
3944a1a06bcSAlagu Sankar return blkcnt;
395272cc70bSAndy Fleming }
396272cc70bSAndy Fleming
397c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
mmc_bread(struct udevice * dev,lbaint_t start,lbaint_t blkcnt,void * dst)3987dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst)
39933fb211dSSimon Glass #else
4007dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
4017dba0b93SSimon Glass void *dst)
40233fb211dSSimon Glass #endif
403272cc70bSAndy Fleming {
404c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
40533fb211dSSimon Glass struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
40633fb211dSSimon Glass #endif
407bcce53d0SSimon Glass int dev_num = block_dev->devnum;
408873cc1d7SStephen Warren int err;
4094a1a06bcSAlagu Sankar lbaint_t cur, blocks_todo = blkcnt;
410272cc70bSAndy Fleming
4114a1a06bcSAlagu Sankar if (blkcnt == 0)
4124a1a06bcSAlagu Sankar return 0;
4134a1a06bcSAlagu Sankar
4144a1a06bcSAlagu Sankar struct mmc *mmc = find_mmc_device(dev_num);
415272cc70bSAndy Fleming if (!mmc)
416272cc70bSAndy Fleming return 0;
417272cc70bSAndy Fleming
418b5b838f1SMarek Vasut if (CONFIG_IS_ENABLED(MMC_TINY))
419b5b838f1SMarek Vasut err = mmc_switch_part(mmc, block_dev->hwpart);
420b5b838f1SMarek Vasut else
42169f45cd5SSimon Glass err = blk_dselect_hwpart(block_dev, block_dev->hwpart);
422b5b838f1SMarek Vasut
423873cc1d7SStephen Warren if (err < 0)
424873cc1d7SStephen Warren return 0;
425873cc1d7SStephen Warren
426c40fdca6SSimon Glass if ((start + blkcnt) > block_dev->lba) {
42756196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
428d8e3d420SJean-Jacques Hiblot pr_err("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
429c40fdca6SSimon Glass start + blkcnt, block_dev->lba);
43056196826SPaul Burton #endif
431d2bf29e3SLei Wen return 0;
432d2bf29e3SLei Wen }
433272cc70bSAndy Fleming
43411692991SSimon Glass if (mmc_set_blocklen(mmc, mmc->read_bl_len)) {
435d4d64889SMasahiro Yamada pr_debug("%s: Failed to set blocklen\n", __func__);
436272cc70bSAndy Fleming return 0;
43711692991SSimon Glass }
438272cc70bSAndy Fleming
4394a1a06bcSAlagu Sankar do {
44093bfd616SPantelis Antoniou cur = (blocks_todo > mmc->cfg->b_max) ?
44193bfd616SPantelis Antoniou mmc->cfg->b_max : blocks_todo;
44211692991SSimon Glass if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
443d4d64889SMasahiro Yamada pr_debug("%s: Failed to read blocks\n", __func__);
4444a1a06bcSAlagu Sankar return 0;
44511692991SSimon Glass }
4464a1a06bcSAlagu Sankar blocks_todo -= cur;
4474a1a06bcSAlagu Sankar start += cur;
4484a1a06bcSAlagu Sankar dst += cur * mmc->read_bl_len;
4494a1a06bcSAlagu Sankar } while (blocks_todo > 0);
450272cc70bSAndy Fleming
451272cc70bSAndy Fleming return blkcnt;
452272cc70bSAndy Fleming }
453272cc70bSAndy Fleming
mmc_go_idle(struct mmc * mmc)454fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc)
455272cc70bSAndy Fleming {
456272cc70bSAndy Fleming struct mmc_cmd cmd;
457272cc70bSAndy Fleming int err;
458272cc70bSAndy Fleming
459272cc70bSAndy Fleming udelay(1000);
460272cc70bSAndy Fleming
461272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
462272cc70bSAndy Fleming cmd.cmdarg = 0;
463272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_NONE;
464272cc70bSAndy Fleming
465272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL);
466272cc70bSAndy Fleming
467272cc70bSAndy Fleming if (err)
468272cc70bSAndy Fleming return err;
469272cc70bSAndy Fleming
470272cc70bSAndy Fleming udelay(2000);
471272cc70bSAndy Fleming
472272cc70bSAndy Fleming return 0;
473272cc70bSAndy Fleming }
474272cc70bSAndy Fleming
475f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
mmc_switch_voltage(struct mmc * mmc,int signal_voltage)476c10b85d6SJean-Jacques Hiblot static int mmc_switch_voltage(struct mmc *mmc, int signal_voltage)
477c10b85d6SJean-Jacques Hiblot {
478c10b85d6SJean-Jacques Hiblot struct mmc_cmd cmd;
479c10b85d6SJean-Jacques Hiblot int err = 0;
480c10b85d6SJean-Jacques Hiblot
481c10b85d6SJean-Jacques Hiblot /*
482c10b85d6SJean-Jacques Hiblot * Send CMD11 only if the request is to switch the card to
483c10b85d6SJean-Jacques Hiblot * 1.8V signalling.
484c10b85d6SJean-Jacques Hiblot */
485c10b85d6SJean-Jacques Hiblot if (signal_voltage == MMC_SIGNAL_VOLTAGE_330)
486c10b85d6SJean-Jacques Hiblot return mmc_set_signal_voltage(mmc, signal_voltage);
487c10b85d6SJean-Jacques Hiblot
488c10b85d6SJean-Jacques Hiblot cmd.cmdidx = SD_CMD_SWITCH_UHS18V;
489c10b85d6SJean-Jacques Hiblot cmd.cmdarg = 0;
490c10b85d6SJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1;
491c10b85d6SJean-Jacques Hiblot
492c10b85d6SJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL);
493c10b85d6SJean-Jacques Hiblot if (err)
494c10b85d6SJean-Jacques Hiblot return err;
495c10b85d6SJean-Jacques Hiblot
496c10b85d6SJean-Jacques Hiblot if (!mmc_host_is_spi(mmc) && (cmd.response[0] & MMC_STATUS_ERROR))
497c10b85d6SJean-Jacques Hiblot return -EIO;
498c10b85d6SJean-Jacques Hiblot
499c10b85d6SJean-Jacques Hiblot /*
500c10b85d6SJean-Jacques Hiblot * The card should drive cmd and dat[0:3] low immediately
501c10b85d6SJean-Jacques Hiblot * after the response of cmd11, but wait 100 us to be sure
502c10b85d6SJean-Jacques Hiblot */
503c10b85d6SJean-Jacques Hiblot err = mmc_wait_dat0(mmc, 0, 100);
504c10b85d6SJean-Jacques Hiblot if (err == -ENOSYS)
505c10b85d6SJean-Jacques Hiblot udelay(100);
506c10b85d6SJean-Jacques Hiblot else if (err)
507c10b85d6SJean-Jacques Hiblot return -ETIMEDOUT;
508c10b85d6SJean-Jacques Hiblot
509c10b85d6SJean-Jacques Hiblot /*
510c10b85d6SJean-Jacques Hiblot * During a signal voltage level switch, the clock must be gated
511c10b85d6SJean-Jacques Hiblot * for 5 ms according to the SD spec
512c10b85d6SJean-Jacques Hiblot */
51365117182SJaehoon Chung mmc_set_clock(mmc, mmc->clock, MMC_CLK_DISABLE);
514c10b85d6SJean-Jacques Hiblot
515c10b85d6SJean-Jacques Hiblot err = mmc_set_signal_voltage(mmc, signal_voltage);
516c10b85d6SJean-Jacques Hiblot if (err)
517c10b85d6SJean-Jacques Hiblot return err;
518c10b85d6SJean-Jacques Hiblot
519c10b85d6SJean-Jacques Hiblot /* Keep clock gated for at least 10 ms, though spec only says 5 ms */
520c10b85d6SJean-Jacques Hiblot mdelay(10);
52165117182SJaehoon Chung mmc_set_clock(mmc, mmc->clock, MMC_CLK_ENABLE);
522c10b85d6SJean-Jacques Hiblot
523c10b85d6SJean-Jacques Hiblot /*
524c10b85d6SJean-Jacques Hiblot * Failure to switch is indicated by the card holding
525c10b85d6SJean-Jacques Hiblot * dat[0:3] low. Wait for at least 1 ms according to spec
526c10b85d6SJean-Jacques Hiblot */
527c10b85d6SJean-Jacques Hiblot err = mmc_wait_dat0(mmc, 1, 1000);
528c10b85d6SJean-Jacques Hiblot if (err == -ENOSYS)
529c10b85d6SJean-Jacques Hiblot udelay(1000);
530c10b85d6SJean-Jacques Hiblot else if (err)
531c10b85d6SJean-Jacques Hiblot return -ETIMEDOUT;
532c10b85d6SJean-Jacques Hiblot
533c10b85d6SJean-Jacques Hiblot return 0;
534c10b85d6SJean-Jacques Hiblot }
535f99c2efeSJean-Jacques Hiblot #endif
536c10b85d6SJean-Jacques Hiblot
sd_send_op_cond(struct mmc * mmc,bool uhs_en)537c10b85d6SJean-Jacques Hiblot static int sd_send_op_cond(struct mmc *mmc, bool uhs_en)
538272cc70bSAndy Fleming {
539272cc70bSAndy Fleming int timeout = 1000;
540272cc70bSAndy Fleming int err;
541272cc70bSAndy Fleming struct mmc_cmd cmd;
542272cc70bSAndy Fleming
5431677eef4SAndrew Gabbasov while (1) {
544272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD;
545272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1;
546272cc70bSAndy Fleming cmd.cmdarg = 0;
547272cc70bSAndy Fleming
548272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL);
549272cc70bSAndy Fleming
550272cc70bSAndy Fleming if (err)
551272cc70bSAndy Fleming return err;
552272cc70bSAndy Fleming
553272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
554272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R3;
555250de12bSStefano Babic
556250de12bSStefano Babic /*
557250de12bSStefano Babic * Most cards do not answer if some reserved bits
558250de12bSStefano Babic * in the ocr are set. However, Some controller
559250de12bSStefano Babic * can set bit 7 (reserved for low voltages), but
560250de12bSStefano Babic * how to manage low voltages SD card is not yet
561250de12bSStefano Babic * specified.
562250de12bSStefano Babic */
563d52ebf10SThomas Chou cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
56493bfd616SPantelis Antoniou (mmc->cfg->voltages & 0xff8000);
565272cc70bSAndy Fleming
566272cc70bSAndy Fleming if (mmc->version == SD_VERSION_2)
567272cc70bSAndy Fleming cmd.cmdarg |= OCR_HCS;
568272cc70bSAndy Fleming
569c10b85d6SJean-Jacques Hiblot if (uhs_en)
570c10b85d6SJean-Jacques Hiblot cmd.cmdarg |= OCR_S18R;
571c10b85d6SJean-Jacques Hiblot
572272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL);
573272cc70bSAndy Fleming
574272cc70bSAndy Fleming if (err)
575272cc70bSAndy Fleming return err;
576272cc70bSAndy Fleming
5771677eef4SAndrew Gabbasov if (cmd.response[0] & OCR_BUSY)
5781677eef4SAndrew Gabbasov break;
579272cc70bSAndy Fleming
5801677eef4SAndrew Gabbasov if (timeout-- <= 0)
581915ffa52SJaehoon Chung return -EOPNOTSUPP;
582272cc70bSAndy Fleming
5831677eef4SAndrew Gabbasov udelay(1000);
5841677eef4SAndrew Gabbasov }
5851677eef4SAndrew Gabbasov
586272cc70bSAndy Fleming if (mmc->version != SD_VERSION_2)
587272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0;
588272cc70bSAndy Fleming
589d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
590d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
591d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3;
592d52ebf10SThomas Chou cmd.cmdarg = 0;
593d52ebf10SThomas Chou
594d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL);
595d52ebf10SThomas Chou
596d52ebf10SThomas Chou if (err)
597d52ebf10SThomas Chou return err;
598d52ebf10SThomas Chou }
599d52ebf10SThomas Chou
600998be3ddSRabin Vincent mmc->ocr = cmd.response[0];
601272cc70bSAndy Fleming
602f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
603c10b85d6SJean-Jacques Hiblot if (uhs_en && !(mmc_host_is_spi(mmc)) && (cmd.response[0] & 0x41000000)
604c10b85d6SJean-Jacques Hiblot == 0x41000000) {
605c10b85d6SJean-Jacques Hiblot err = mmc_switch_voltage(mmc, MMC_SIGNAL_VOLTAGE_180);
606c10b85d6SJean-Jacques Hiblot if (err)
607c10b85d6SJean-Jacques Hiblot return err;
608c10b85d6SJean-Jacques Hiblot }
609f99c2efeSJean-Jacques Hiblot #endif
610c10b85d6SJean-Jacques Hiblot
611272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
612272cc70bSAndy Fleming mmc->rca = 0;
613272cc70bSAndy Fleming
614272cc70bSAndy Fleming return 0;
615272cc70bSAndy Fleming }
616272cc70bSAndy Fleming
mmc_send_op_cond_iter(struct mmc * mmc,int use_arg)6175289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg)
618272cc70bSAndy Fleming {
6195289b535SAndrew Gabbasov struct mmc_cmd cmd;
620272cc70bSAndy Fleming int err;
621272cc70bSAndy Fleming
6225289b535SAndrew Gabbasov cmd.cmdidx = MMC_CMD_SEND_OP_COND;
6235289b535SAndrew Gabbasov cmd.resp_type = MMC_RSP_R3;
6245289b535SAndrew Gabbasov cmd.cmdarg = 0;
6255a20397bSRob Herring if (use_arg && !mmc_host_is_spi(mmc))
6265a20397bSRob Herring cmd.cmdarg = OCR_HCS |
62793bfd616SPantelis Antoniou (mmc->cfg->voltages &
628a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_VOLTAGE_MASK)) |
629a626c8d4SAndrew Gabbasov (mmc->ocr & OCR_ACCESS_MODE);
630e9550449SChe-Liang Chiou
6315289b535SAndrew Gabbasov err = mmc_send_cmd(mmc, &cmd, NULL);
632e9550449SChe-Liang Chiou if (err)
633e9550449SChe-Liang Chiou return err;
6345289b535SAndrew Gabbasov mmc->ocr = cmd.response[0];
635e9550449SChe-Liang Chiou return 0;
636e9550449SChe-Liang Chiou }
637e9550449SChe-Liang Chiou
mmc_send_op_cond(struct mmc * mmc)638750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc)
639e9550449SChe-Liang Chiou {
640e9550449SChe-Liang Chiou int err, i;
641e9550449SChe-Liang Chiou
642272cc70bSAndy Fleming /* Some cards seem to need this */
643272cc70bSAndy Fleming mmc_go_idle(mmc);
644272cc70bSAndy Fleming
64531cacbabSRaffaele Recalcati /* Asking to the card its capabilities */
646e9550449SChe-Liang Chiou for (i = 0; i < 2; i++) {
6475289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, i != 0);
64831cacbabSRaffaele Recalcati if (err)
64931cacbabSRaffaele Recalcati return err;
65031cacbabSRaffaele Recalcati
651e9550449SChe-Liang Chiou /* exit if not busy (flag seems to be inverted) */
652a626c8d4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY)
653bd47c135SAndrew Gabbasov break;
654e9550449SChe-Liang Chiou }
655bd47c135SAndrew Gabbasov mmc->op_cond_pending = 1;
656bd47c135SAndrew Gabbasov return 0;
657e9550449SChe-Liang Chiou }
65831cacbabSRaffaele Recalcati
mmc_complete_op_cond(struct mmc * mmc)659750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc)
660e9550449SChe-Liang Chiou {
661e9550449SChe-Liang Chiou struct mmc_cmd cmd;
662e9550449SChe-Liang Chiou int timeout = 1000;
66336332b6eSVipul Kumar ulong start;
664e9550449SChe-Liang Chiou int err;
665e9550449SChe-Liang Chiou
666e9550449SChe-Liang Chiou mmc->op_cond_pending = 0;
667cc17c01fSAndrew Gabbasov if (!(mmc->ocr & OCR_BUSY)) {
668d188b113SYangbo Lu /* Some cards seem to need this */
669d188b113SYangbo Lu mmc_go_idle(mmc);
670d188b113SYangbo Lu
671e9550449SChe-Liang Chiou start = get_timer(0);
6721677eef4SAndrew Gabbasov while (1) {
6735289b535SAndrew Gabbasov err = mmc_send_op_cond_iter(mmc, 1);
674272cc70bSAndy Fleming if (err)
675272cc70bSAndy Fleming return err;
6761677eef4SAndrew Gabbasov if (mmc->ocr & OCR_BUSY)
6771677eef4SAndrew Gabbasov break;
678e9550449SChe-Liang Chiou if (get_timer(start) > timeout)
679915ffa52SJaehoon Chung return -EOPNOTSUPP;
680e9550449SChe-Liang Chiou udelay(100);
6811677eef4SAndrew Gabbasov }
682cc17c01fSAndrew Gabbasov }
683272cc70bSAndy Fleming
684d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
685d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
686d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R3;
687d52ebf10SThomas Chou cmd.cmdarg = 0;
688d52ebf10SThomas Chou
689d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL);
690d52ebf10SThomas Chou
691d52ebf10SThomas Chou if (err)
692d52ebf10SThomas Chou return err;
693a626c8d4SAndrew Gabbasov
694a626c8d4SAndrew Gabbasov mmc->ocr = cmd.response[0];
695d52ebf10SThomas Chou }
696d52ebf10SThomas Chou
697272cc70bSAndy Fleming mmc->version = MMC_VERSION_UNKNOWN;
698272cc70bSAndy Fleming
699272cc70bSAndy Fleming mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
700def816a2SStephen Warren mmc->rca = 1;
701272cc70bSAndy Fleming
702272cc70bSAndy Fleming return 0;
703272cc70bSAndy Fleming }
704272cc70bSAndy Fleming
705272cc70bSAndy Fleming
mmc_send_ext_csd(struct mmc * mmc,u8 * ext_csd)706fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
707272cc70bSAndy Fleming {
708272cc70bSAndy Fleming struct mmc_cmd cmd;
709272cc70bSAndy Fleming struct mmc_data data;
710272cc70bSAndy Fleming int err;
711272cc70bSAndy Fleming
712272cc70bSAndy Fleming /* Get the Card Status Register */
713272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
714272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1;
715272cc70bSAndy Fleming cmd.cmdarg = 0;
716272cc70bSAndy Fleming
717cdfd1ac6SYoshihiro Shimoda data.dest = (char *)ext_csd;
718272cc70bSAndy Fleming data.blocks = 1;
7198bfa195eSSimon Glass data.blocksize = MMC_MAX_BLOCK_LEN;
720272cc70bSAndy Fleming data.flags = MMC_DATA_READ;
721272cc70bSAndy Fleming
722272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data);
723272cc70bSAndy Fleming
724272cc70bSAndy Fleming return err;
725272cc70bSAndy Fleming }
726272cc70bSAndy Fleming
__mmc_switch(struct mmc * mmc,u8 set,u8 index,u8 value,bool send_status)7276892550cSMarek Vasut static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value,
7286892550cSMarek Vasut bool send_status)
729272cc70bSAndy Fleming {
730272cc70bSAndy Fleming struct mmc_cmd cmd;
7315d4fc8d9SRaffaele Recalcati int timeout = 1000;
732a9003dc6SMaxime Ripard int retries = 3;
7335d4fc8d9SRaffaele Recalcati int ret;
734272cc70bSAndy Fleming
735272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SWITCH;
736272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1b;
737272cc70bSAndy Fleming cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
738272cc70bSAndy Fleming (index << 16) |
739272cc70bSAndy Fleming (value << 8);
740272cc70bSAndy Fleming
741a9003dc6SMaxime Ripard while (retries > 0) {
7425d4fc8d9SRaffaele Recalcati ret = mmc_send_cmd(mmc, &cmd, NULL);
7435d4fc8d9SRaffaele Recalcati
7446892550cSMarek Vasut if (ret) {
745a9003dc6SMaxime Ripard retries--;
7466892550cSMarek Vasut continue;
7476892550cSMarek Vasut }
7486892550cSMarek Vasut
7496892550cSMarek Vasut if (!send_status) {
7506892550cSMarek Vasut mdelay(50);
7516892550cSMarek Vasut return 0;
7526892550cSMarek Vasut }
7536892550cSMarek Vasut
7546892550cSMarek Vasut /* Waiting for the ready status */
7556892550cSMarek Vasut return mmc_send_status(mmc, timeout);
756a9003dc6SMaxime Ripard }
7575d4fc8d9SRaffaele Recalcati
7585d4fc8d9SRaffaele Recalcati return ret;
7595d4fc8d9SRaffaele Recalcati
760272cc70bSAndy Fleming }
761272cc70bSAndy Fleming
mmc_switch(struct mmc * mmc,u8 set,u8 index,u8 value)7626892550cSMarek Vasut int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
7636892550cSMarek Vasut {
7646892550cSMarek Vasut return __mmc_switch(mmc, set, index, value, true);
7656892550cSMarek Vasut }
7666892550cSMarek Vasut
76762d77ceaSMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY)
mmc_set_card_speed(struct mmc * mmc,enum bus_mode mode,bool hsdowngrade)768b9a2a0e2SMarek Vasut static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode,
769b9a2a0e2SMarek Vasut bool hsdowngrade)
770272cc70bSAndy Fleming {
771272cc70bSAndy Fleming int err;
7723862b854SJean-Jacques Hiblot int speed_bits;
7733862b854SJean-Jacques Hiblot
7743862b854SJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
7753862b854SJean-Jacques Hiblot
7763862b854SJean-Jacques Hiblot switch (mode) {
7773862b854SJean-Jacques Hiblot case MMC_HS:
7783862b854SJean-Jacques Hiblot case MMC_HS_52:
7793862b854SJean-Jacques Hiblot case MMC_DDR_52:
7803862b854SJean-Jacques Hiblot speed_bits = EXT_CSD_TIMING_HS;
781634d4849SKishon Vijay Abraham I break;
782baef2070SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
783634d4849SKishon Vijay Abraham I case MMC_HS_200:
784634d4849SKishon Vijay Abraham I speed_bits = EXT_CSD_TIMING_HS200;
785634d4849SKishon Vijay Abraham I break;
786baef2070SJean-Jacques Hiblot #endif
7873dd2626fSPeng Fan #if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
7883dd2626fSPeng Fan case MMC_HS_400:
7893dd2626fSPeng Fan speed_bits = EXT_CSD_TIMING_HS400;
7903dd2626fSPeng Fan break;
7913dd2626fSPeng Fan #endif
7923862b854SJean-Jacques Hiblot case MMC_LEGACY:
7933862b854SJean-Jacques Hiblot speed_bits = EXT_CSD_TIMING_LEGACY;
7943862b854SJean-Jacques Hiblot break;
7953862b854SJean-Jacques Hiblot default:
7963862b854SJean-Jacques Hiblot return -EINVAL;
7973862b854SJean-Jacques Hiblot }
7986892550cSMarek Vasut
7996892550cSMarek Vasut err = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
8006892550cSMarek Vasut speed_bits, !hsdowngrade);
8013862b854SJean-Jacques Hiblot if (err)
8023862b854SJean-Jacques Hiblot return err;
8033862b854SJean-Jacques Hiblot
804b9a2a0e2SMarek Vasut #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \
805b9a2a0e2SMarek Vasut CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
806b9a2a0e2SMarek Vasut /*
807b9a2a0e2SMarek Vasut * In case the eMMC is in HS200/HS400 mode and we are downgrading
808b9a2a0e2SMarek Vasut * to HS mode, the card clock are still running much faster than
809b9a2a0e2SMarek Vasut * the supported HS mode clock, so we can not reliably read out
810b9a2a0e2SMarek Vasut * Extended CSD. Reconfigure the controller to run at HS mode.
811b9a2a0e2SMarek Vasut */
812b9a2a0e2SMarek Vasut if (hsdowngrade) {
813b9a2a0e2SMarek Vasut mmc_select_mode(mmc, MMC_HS);
814b9a2a0e2SMarek Vasut mmc_set_clock(mmc, mmc_mode2freq(mmc, MMC_HS), false);
815b9a2a0e2SMarek Vasut }
816b9a2a0e2SMarek Vasut #endif
817b9a2a0e2SMarek Vasut
8183862b854SJean-Jacques Hiblot if ((mode == MMC_HS) || (mode == MMC_HS_52)) {
8193862b854SJean-Jacques Hiblot /* Now check to see that it worked */
8203862b854SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, test_csd);
8213862b854SJean-Jacques Hiblot if (err)
8223862b854SJean-Jacques Hiblot return err;
8233862b854SJean-Jacques Hiblot
8243862b854SJean-Jacques Hiblot /* No high-speed support */
8253862b854SJean-Jacques Hiblot if (!test_csd[EXT_CSD_HS_TIMING])
8263862b854SJean-Jacques Hiblot return -ENOTSUPP;
8273862b854SJean-Jacques Hiblot }
8283862b854SJean-Jacques Hiblot
8293862b854SJean-Jacques Hiblot return 0;
8303862b854SJean-Jacques Hiblot }
8313862b854SJean-Jacques Hiblot
mmc_get_capabilities(struct mmc * mmc)8323862b854SJean-Jacques Hiblot static int mmc_get_capabilities(struct mmc *mmc)
8333862b854SJean-Jacques Hiblot {
8343862b854SJean-Jacques Hiblot u8 *ext_csd = mmc->ext_csd;
8353862b854SJean-Jacques Hiblot char cardtype;
836272cc70bSAndy Fleming
83700e446faSJean-Jacques Hiblot mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(MMC_LEGACY);
838272cc70bSAndy Fleming
839d52ebf10SThomas Chou if (mmc_host_is_spi(mmc))
840d52ebf10SThomas Chou return 0;
841d52ebf10SThomas Chou
842272cc70bSAndy Fleming /* Only version 4 supports high-speed */
843272cc70bSAndy Fleming if (mmc->version < MMC_VERSION_4)
844272cc70bSAndy Fleming return 0;
845272cc70bSAndy Fleming
8463862b854SJean-Jacques Hiblot if (!ext_csd) {
847d8e3d420SJean-Jacques Hiblot pr_err("No ext_csd found!\n"); /* this should enver happen */
8483862b854SJean-Jacques Hiblot return -ENOTSUPP;
8493862b854SJean-Jacques Hiblot }
8503862b854SJean-Jacques Hiblot
851fc5b32fbSAndrew Gabbasov mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
852fc5b32fbSAndrew Gabbasov
8533dd2626fSPeng Fan cardtype = ext_csd[EXT_CSD_CARD_TYPE];
854bc1e3272SJean-Jacques Hiblot mmc->cardtype = cardtype;
855272cc70bSAndy Fleming
856baef2070SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
857634d4849SKishon Vijay Abraham I if (cardtype & (EXT_CSD_CARD_TYPE_HS200_1_2V |
858634d4849SKishon Vijay Abraham I EXT_CSD_CARD_TYPE_HS200_1_8V)) {
859634d4849SKishon Vijay Abraham I mmc->card_caps |= MMC_MODE_HS200;
860634d4849SKishon Vijay Abraham I }
861baef2070SJean-Jacques Hiblot #endif
8623dd2626fSPeng Fan #if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
8633dd2626fSPeng Fan if (cardtype & (EXT_CSD_CARD_TYPE_HS400_1_2V |
8643dd2626fSPeng Fan EXT_CSD_CARD_TYPE_HS400_1_8V)) {
8653dd2626fSPeng Fan mmc->card_caps |= MMC_MODE_HS400;
8663dd2626fSPeng Fan }
8673dd2626fSPeng Fan #endif
868d22e3d46SJaehoon Chung if (cardtype & EXT_CSD_CARD_TYPE_52) {
8693862b854SJean-Jacques Hiblot if (cardtype & EXT_CSD_CARD_TYPE_DDR_52)
870d22e3d46SJaehoon Chung mmc->card_caps |= MMC_MODE_DDR_52MHz;
8713862b854SJean-Jacques Hiblot mmc->card_caps |= MMC_MODE_HS_52MHz;
872d22e3d46SJaehoon Chung }
8733862b854SJean-Jacques Hiblot if (cardtype & EXT_CSD_CARD_TYPE_26)
8743862b854SJean-Jacques Hiblot mmc->card_caps |= MMC_MODE_HS;
875272cc70bSAndy Fleming
876272cc70bSAndy Fleming return 0;
877272cc70bSAndy Fleming }
87862d77ceaSMarek Vasut #endif
879272cc70bSAndy Fleming
mmc_set_capacity(struct mmc * mmc,int part_num)880f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num)
881f866a46dSStephen Warren {
882f866a46dSStephen Warren switch (part_num) {
883f866a46dSStephen Warren case 0:
884f866a46dSStephen Warren mmc->capacity = mmc->capacity_user;
885f866a46dSStephen Warren break;
886f866a46dSStephen Warren case 1:
887f866a46dSStephen Warren case 2:
888f866a46dSStephen Warren mmc->capacity = mmc->capacity_boot;
889f866a46dSStephen Warren break;
890f866a46dSStephen Warren case 3:
891f866a46dSStephen Warren mmc->capacity = mmc->capacity_rpmb;
892f866a46dSStephen Warren break;
893f866a46dSStephen Warren case 4:
894f866a46dSStephen Warren case 5:
895f866a46dSStephen Warren case 6:
896f866a46dSStephen Warren case 7:
897f866a46dSStephen Warren mmc->capacity = mmc->capacity_gp[part_num - 4];
898f866a46dSStephen Warren break;
899f866a46dSStephen Warren default:
900f866a46dSStephen Warren return -1;
901f866a46dSStephen Warren }
902f866a46dSStephen Warren
903c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len);
904f866a46dSStephen Warren
905f866a46dSStephen Warren return 0;
906f866a46dSStephen Warren }
907f866a46dSStephen Warren
908f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
mmc_boot_part_access_chk(struct mmc * mmc,unsigned int part_num)90901298da3SJean-Jacques Hiblot static int mmc_boot_part_access_chk(struct mmc *mmc, unsigned int part_num)
91001298da3SJean-Jacques Hiblot {
91101298da3SJean-Jacques Hiblot int forbidden = 0;
91201298da3SJean-Jacques Hiblot bool change = false;
91301298da3SJean-Jacques Hiblot
91401298da3SJean-Jacques Hiblot if (part_num & PART_ACCESS_MASK)
91501298da3SJean-Jacques Hiblot forbidden = MMC_CAP(MMC_HS_200);
91601298da3SJean-Jacques Hiblot
91701298da3SJean-Jacques Hiblot if (MMC_CAP(mmc->selected_mode) & forbidden) {
918d4d64889SMasahiro Yamada pr_debug("selected mode (%s) is forbidden for part %d\n",
91901298da3SJean-Jacques Hiblot mmc_mode_name(mmc->selected_mode), part_num);
92001298da3SJean-Jacques Hiblot change = true;
92101298da3SJean-Jacques Hiblot } else if (mmc->selected_mode != mmc->best_mode) {
922d4d64889SMasahiro Yamada pr_debug("selected mode is not optimal\n");
92301298da3SJean-Jacques Hiblot change = true;
92401298da3SJean-Jacques Hiblot }
92501298da3SJean-Jacques Hiblot
92601298da3SJean-Jacques Hiblot if (change)
92701298da3SJean-Jacques Hiblot return mmc_select_mode_and_width(mmc,
92801298da3SJean-Jacques Hiblot mmc->card_caps & ~forbidden);
92901298da3SJean-Jacques Hiblot
93001298da3SJean-Jacques Hiblot return 0;
93101298da3SJean-Jacques Hiblot }
932f99c2efeSJean-Jacques Hiblot #else
mmc_boot_part_access_chk(struct mmc * mmc,unsigned int part_num)933f99c2efeSJean-Jacques Hiblot static inline int mmc_boot_part_access_chk(struct mmc *mmc,
934f99c2efeSJean-Jacques Hiblot unsigned int part_num)
935f99c2efeSJean-Jacques Hiblot {
936f99c2efeSJean-Jacques Hiblot return 0;
937f99c2efeSJean-Jacques Hiblot }
938f99c2efeSJean-Jacques Hiblot #endif
93901298da3SJean-Jacques Hiblot
mmc_switch_part(struct mmc * mmc,unsigned int part_num)9407dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num)
941bc897b1dSLei Wen {
942f866a46dSStephen Warren int ret;
943bc897b1dSLei Wen
94401298da3SJean-Jacques Hiblot ret = mmc_boot_part_access_chk(mmc, part_num);
94501298da3SJean-Jacques Hiblot if (ret)
94601298da3SJean-Jacques Hiblot return ret;
94701298da3SJean-Jacques Hiblot
948f866a46dSStephen Warren ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
949bc897b1dSLei Wen (mmc->part_config & ~PART_ACCESS_MASK)
950bc897b1dSLei Wen | (part_num & PART_ACCESS_MASK));
951f866a46dSStephen Warren
9526dc93e70SPeter Bigot /*
9536dc93e70SPeter Bigot * Set the capacity if the switch succeeded or was intended
9546dc93e70SPeter Bigot * to return to representing the raw device.
9556dc93e70SPeter Bigot */
956873cc1d7SStephen Warren if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) {
9576dc93e70SPeter Bigot ret = mmc_set_capacity(mmc, part_num);
958fdbb139fSSimon Glass mmc_get_blk_desc(mmc)->hwpart = part_num;
959873cc1d7SStephen Warren }
9606dc93e70SPeter Bigot
9616dc93e70SPeter Bigot return ret;
962bc897b1dSLei Wen }
963bc897b1dSLei Wen
964cf17789eSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING)
mmc_hwpart_config(struct mmc * mmc,const struct mmc_hwpart_conf * conf,enum mmc_hwpart_conf_mode mode)965ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc,
966ac9da0e0SDiego Santa Cruz const struct mmc_hwpart_conf *conf,
967ac9da0e0SDiego Santa Cruz enum mmc_hwpart_conf_mode mode)
968ac9da0e0SDiego Santa Cruz {
969ac9da0e0SDiego Santa Cruz u8 part_attrs = 0;
970ac9da0e0SDiego Santa Cruz u32 enh_size_mult;
971ac9da0e0SDiego Santa Cruz u32 enh_start_addr;
972ac9da0e0SDiego Santa Cruz u32 gp_size_mult[4];
973ac9da0e0SDiego Santa Cruz u32 max_enh_size_mult;
974ac9da0e0SDiego Santa Cruz u32 tot_enh_size_mult = 0;
9758dda5b0eSDiego Santa Cruz u8 wr_rel_set;
976ac9da0e0SDiego Santa Cruz int i, pidx, err;
977ac9da0e0SDiego Santa Cruz ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
978ac9da0e0SDiego Santa Cruz
979ac9da0e0SDiego Santa Cruz if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE)
980ac9da0e0SDiego Santa Cruz return -EINVAL;
981ac9da0e0SDiego Santa Cruz
982ac9da0e0SDiego Santa Cruz if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) {
983d8e3d420SJean-Jacques Hiblot pr_err("eMMC >= 4.4 required for enhanced user data area\n");
984ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE;
985ac9da0e0SDiego Santa Cruz }
986ac9da0e0SDiego Santa Cruz
987ac9da0e0SDiego Santa Cruz if (!(mmc->part_support & PART_SUPPORT)) {
988d8e3d420SJean-Jacques Hiblot pr_err("Card does not support partitioning\n");
989ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE;
990ac9da0e0SDiego Santa Cruz }
991ac9da0e0SDiego Santa Cruz
992ac9da0e0SDiego Santa Cruz if (!mmc->hc_wp_grp_size) {
993d8e3d420SJean-Jacques Hiblot pr_err("Card does not define HC WP group size\n");
994ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE;
995ac9da0e0SDiego Santa Cruz }
996ac9da0e0SDiego Santa Cruz
997ac9da0e0SDiego Santa Cruz /* check partition alignment and total enhanced size */
998ac9da0e0SDiego Santa Cruz if (conf->user.enh_size) {
999ac9da0e0SDiego Santa Cruz if (conf->user.enh_size % mmc->hc_wp_grp_size ||
1000ac9da0e0SDiego Santa Cruz conf->user.enh_start % mmc->hc_wp_grp_size) {
1001d8e3d420SJean-Jacques Hiblot pr_err("User data enhanced area not HC WP group "
1002ac9da0e0SDiego Santa Cruz "size aligned\n");
1003ac9da0e0SDiego Santa Cruz return -EINVAL;
1004ac9da0e0SDiego Santa Cruz }
1005ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_USR;
1006ac9da0e0SDiego Santa Cruz enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size;
1007ac9da0e0SDiego Santa Cruz if (mmc->high_capacity) {
1008ac9da0e0SDiego Santa Cruz enh_start_addr = conf->user.enh_start;
1009ac9da0e0SDiego Santa Cruz } else {
1010ac9da0e0SDiego Santa Cruz enh_start_addr = (conf->user.enh_start << 9);
1011ac9da0e0SDiego Santa Cruz }
1012ac9da0e0SDiego Santa Cruz } else {
1013ac9da0e0SDiego Santa Cruz enh_size_mult = 0;
1014ac9da0e0SDiego Santa Cruz enh_start_addr = 0;
1015ac9da0e0SDiego Santa Cruz }
1016ac9da0e0SDiego Santa Cruz tot_enh_size_mult += enh_size_mult;
1017ac9da0e0SDiego Santa Cruz
1018ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) {
1019ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) {
1020d8e3d420SJean-Jacques Hiblot pr_err("GP%i partition not HC WP group size "
1021ac9da0e0SDiego Santa Cruz "aligned\n", pidx+1);
1022ac9da0e0SDiego Santa Cruz return -EINVAL;
1023ac9da0e0SDiego Santa Cruz }
1024ac9da0e0SDiego Santa Cruz gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size;
1025ac9da0e0SDiego Santa Cruz if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) {
1026ac9da0e0SDiego Santa Cruz part_attrs |= EXT_CSD_ENH_GP(pidx);
1027ac9da0e0SDiego Santa Cruz tot_enh_size_mult += gp_size_mult[pidx];
1028ac9da0e0SDiego Santa Cruz }
1029ac9da0e0SDiego Santa Cruz }
1030ac9da0e0SDiego Santa Cruz
1031ac9da0e0SDiego Santa Cruz if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) {
1032d8e3d420SJean-Jacques Hiblot pr_err("Card does not support enhanced attribute\n");
1033ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE;
1034ac9da0e0SDiego Santa Cruz }
1035ac9da0e0SDiego Santa Cruz
1036ac9da0e0SDiego Santa Cruz err = mmc_send_ext_csd(mmc, ext_csd);
1037ac9da0e0SDiego Santa Cruz if (err)
1038ac9da0e0SDiego Santa Cruz return err;
1039ac9da0e0SDiego Santa Cruz
1040ac9da0e0SDiego Santa Cruz max_enh_size_mult =
1041ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) +
1042ac9da0e0SDiego Santa Cruz (ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) +
1043ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT];
1044ac9da0e0SDiego Santa Cruz if (tot_enh_size_mult > max_enh_size_mult) {
1045d8e3d420SJean-Jacques Hiblot pr_err("Total enhanced size exceeds maximum (%u > %u)\n",
1046ac9da0e0SDiego Santa Cruz tot_enh_size_mult, max_enh_size_mult);
1047ac9da0e0SDiego Santa Cruz return -EMEDIUMTYPE;
1048ac9da0e0SDiego Santa Cruz }
1049ac9da0e0SDiego Santa Cruz
10508dda5b0eSDiego Santa Cruz /* The default value of EXT_CSD_WR_REL_SET is device
10518dda5b0eSDiego Santa Cruz * dependent, the values can only be changed if the
10528dda5b0eSDiego Santa Cruz * EXT_CSD_HS_CTRL_REL bit is set. The values can be
10538dda5b0eSDiego Santa Cruz * changed only once and before partitioning is completed. */
10548dda5b0eSDiego Santa Cruz wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
10558dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_change) {
10568dda5b0eSDiego Santa Cruz if (conf->user.wr_rel_set)
10578dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_USR;
10588dda5b0eSDiego Santa Cruz else
10598dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR;
10608dda5b0eSDiego Santa Cruz }
10618dda5b0eSDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) {
10628dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_change) {
10638dda5b0eSDiego Santa Cruz if (conf->gp_part[pidx].wr_rel_set)
10648dda5b0eSDiego Santa Cruz wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx);
10658dda5b0eSDiego Santa Cruz else
10668dda5b0eSDiego Santa Cruz wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx);
10678dda5b0eSDiego Santa Cruz }
10688dda5b0eSDiego Santa Cruz }
10698dda5b0eSDiego Santa Cruz
10708dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] &&
10718dda5b0eSDiego Santa Cruz !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) {
10728dda5b0eSDiego Santa Cruz puts("Card does not support host controlled partition write "
10738dda5b0eSDiego Santa Cruz "reliability settings\n");
10748dda5b0eSDiego Santa Cruz return -EMEDIUMTYPE;
10758dda5b0eSDiego Santa Cruz }
10768dda5b0eSDiego Santa Cruz
1077ac9da0e0SDiego Santa Cruz if (ext_csd[EXT_CSD_PARTITION_SETTING] &
1078ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED) {
1079d8e3d420SJean-Jacques Hiblot pr_err("Card already partitioned\n");
1080ac9da0e0SDiego Santa Cruz return -EPERM;
1081ac9da0e0SDiego Santa Cruz }
1082ac9da0e0SDiego Santa Cruz
1083ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_CHECK)
1084ac9da0e0SDiego Santa Cruz return 0;
1085ac9da0e0SDiego Santa Cruz
1086ac9da0e0SDiego Santa Cruz /* Partitioning requires high-capacity size definitions */
1087ac9da0e0SDiego Santa Cruz if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) {
1088ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1089ac9da0e0SDiego Santa Cruz EXT_CSD_ERASE_GROUP_DEF, 1);
1090ac9da0e0SDiego Santa Cruz
1091ac9da0e0SDiego Santa Cruz if (err)
1092ac9da0e0SDiego Santa Cruz return err;
1093ac9da0e0SDiego Santa Cruz
1094ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1095ac9da0e0SDiego Santa Cruz
1096ac9da0e0SDiego Santa Cruz /* update erase group size to be high-capacity */
1097ac9da0e0SDiego Santa Cruz mmc->erase_grp_size =
1098ac9da0e0SDiego Santa Cruz ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1099ac9da0e0SDiego Santa Cruz
1100ac9da0e0SDiego Santa Cruz }
1101ac9da0e0SDiego Santa Cruz
1102ac9da0e0SDiego Santa Cruz /* all OK, write the configuration */
1103ac9da0e0SDiego Santa Cruz for (i = 0; i < 4; i++) {
1104ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1105ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_START_ADDR+i,
1106ac9da0e0SDiego Santa Cruz (enh_start_addr >> (i*8)) & 0xFF);
1107ac9da0e0SDiego Santa Cruz if (err)
1108ac9da0e0SDiego Santa Cruz return err;
1109ac9da0e0SDiego Santa Cruz }
1110ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) {
1111ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1112ac9da0e0SDiego Santa Cruz EXT_CSD_ENH_SIZE_MULT+i,
1113ac9da0e0SDiego Santa Cruz (enh_size_mult >> (i*8)) & 0xFF);
1114ac9da0e0SDiego Santa Cruz if (err)
1115ac9da0e0SDiego Santa Cruz return err;
1116ac9da0e0SDiego Santa Cruz }
1117ac9da0e0SDiego Santa Cruz for (pidx = 0; pidx < 4; pidx++) {
1118ac9da0e0SDiego Santa Cruz for (i = 0; i < 3; i++) {
1119ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1120ac9da0e0SDiego Santa Cruz EXT_CSD_GP_SIZE_MULT+pidx*3+i,
1121ac9da0e0SDiego Santa Cruz (gp_size_mult[pidx] >> (i*8)) & 0xFF);
1122ac9da0e0SDiego Santa Cruz if (err)
1123ac9da0e0SDiego Santa Cruz return err;
1124ac9da0e0SDiego Santa Cruz }
1125ac9da0e0SDiego Santa Cruz }
1126ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1127ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs);
1128ac9da0e0SDiego Santa Cruz if (err)
1129ac9da0e0SDiego Santa Cruz return err;
1130ac9da0e0SDiego Santa Cruz
1131ac9da0e0SDiego Santa Cruz if (mode == MMC_HWPART_CONF_SET)
1132ac9da0e0SDiego Santa Cruz return 0;
1133ac9da0e0SDiego Santa Cruz
11348dda5b0eSDiego Santa Cruz /* The WR_REL_SET is a write-once register but shall be
11358dda5b0eSDiego Santa Cruz * written before setting PART_SETTING_COMPLETED. As it is
11368dda5b0eSDiego Santa Cruz * write-once we can only write it when completing the
11378dda5b0eSDiego Santa Cruz * partitioning. */
11388dda5b0eSDiego Santa Cruz if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) {
11398dda5b0eSDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
11408dda5b0eSDiego Santa Cruz EXT_CSD_WR_REL_SET, wr_rel_set);
11418dda5b0eSDiego Santa Cruz if (err)
11428dda5b0eSDiego Santa Cruz return err;
11438dda5b0eSDiego Santa Cruz }
11448dda5b0eSDiego Santa Cruz
1145ac9da0e0SDiego Santa Cruz /* Setting PART_SETTING_COMPLETED confirms the partition
1146ac9da0e0SDiego Santa Cruz * configuration but it only becomes effective after power
1147ac9da0e0SDiego Santa Cruz * cycle, so we do not adjust the partition related settings
1148ac9da0e0SDiego Santa Cruz * in the mmc struct. */
1149ac9da0e0SDiego Santa Cruz
1150ac9da0e0SDiego Santa Cruz err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1151ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING,
1152ac9da0e0SDiego Santa Cruz EXT_CSD_PARTITION_SETTING_COMPLETED);
1153ac9da0e0SDiego Santa Cruz if (err)
1154ac9da0e0SDiego Santa Cruz return err;
1155ac9da0e0SDiego Santa Cruz
1156ac9da0e0SDiego Santa Cruz return 0;
1157ac9da0e0SDiego Santa Cruz }
1158cf17789eSJean-Jacques Hiblot #endif
1159ac9da0e0SDiego Santa Cruz
1160e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
mmc_getcd(struct mmc * mmc)116148972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
116248972d90SThierry Reding {
116348972d90SThierry Reding int cd;
116448972d90SThierry Reding
116548972d90SThierry Reding cd = board_mmc_getcd(mmc);
116648972d90SThierry Reding
1167d4e1da4eSPeter Korsgaard if (cd < 0) {
116893bfd616SPantelis Antoniou if (mmc->cfg->ops->getcd)
116993bfd616SPantelis Antoniou cd = mmc->cfg->ops->getcd(mmc);
1170d4e1da4eSPeter Korsgaard else
1171d4e1da4eSPeter Korsgaard cd = 1;
1172d4e1da4eSPeter Korsgaard }
117348972d90SThierry Reding
117448972d90SThierry Reding return cd;
117548972d90SThierry Reding }
11768ca51e51SSimon Glass #endif
117748972d90SThierry Reding
117862d77ceaSMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY)
sd_switch(struct mmc * mmc,int mode,int group,u8 value,u8 * resp)1179fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
1180272cc70bSAndy Fleming {
1181272cc70bSAndy Fleming struct mmc_cmd cmd;
1182272cc70bSAndy Fleming struct mmc_data data;
1183272cc70bSAndy Fleming
1184272cc70bSAndy Fleming /* Switch the frequency */
1185272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SWITCH_FUNC;
1186272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1;
1187272cc70bSAndy Fleming cmd.cmdarg = (mode << 31) | 0xffffff;
1188272cc70bSAndy Fleming cmd.cmdarg &= ~(0xf << (group * 4));
1189272cc70bSAndy Fleming cmd.cmdarg |= value << (group * 4);
1190272cc70bSAndy Fleming
1191272cc70bSAndy Fleming data.dest = (char *)resp;
1192272cc70bSAndy Fleming data.blocksize = 64;
1193272cc70bSAndy Fleming data.blocks = 1;
1194272cc70bSAndy Fleming data.flags = MMC_DATA_READ;
1195272cc70bSAndy Fleming
1196272cc70bSAndy Fleming return mmc_send_cmd(mmc, &cmd, &data);
1197272cc70bSAndy Fleming }
1198272cc70bSAndy Fleming
sd_get_capabilities(struct mmc * mmc)1199d0c221feSJean-Jacques Hiblot static int sd_get_capabilities(struct mmc *mmc)
1200272cc70bSAndy Fleming {
1201272cc70bSAndy Fleming int err;
1202272cc70bSAndy Fleming struct mmc_cmd cmd;
120318e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2);
120418e7c8f6SSuniel Mahesh ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16);
1205272cc70bSAndy Fleming struct mmc_data data;
1206272cc70bSAndy Fleming int timeout;
1207f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1208c10b85d6SJean-Jacques Hiblot u32 sd3_bus_mode;
1209f99c2efeSJean-Jacques Hiblot #endif
1210272cc70bSAndy Fleming
121100e446faSJean-Jacques Hiblot mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(SD_LEGACY);
1212272cc70bSAndy Fleming
1213d52ebf10SThomas Chou if (mmc_host_is_spi(mmc))
1214d52ebf10SThomas Chou return 0;
1215d52ebf10SThomas Chou
1216272cc70bSAndy Fleming /* Read the SCR to find out if this card supports higher speeds */
1217272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_APP_CMD;
1218272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1;
1219272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16;
1220272cc70bSAndy Fleming
1221272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL);
1222272cc70bSAndy Fleming
1223272cc70bSAndy Fleming if (err)
1224272cc70bSAndy Fleming return err;
1225272cc70bSAndy Fleming
1226272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_APP_SEND_SCR;
1227272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R1;
1228272cc70bSAndy Fleming cmd.cmdarg = 0;
1229272cc70bSAndy Fleming
1230272cc70bSAndy Fleming timeout = 3;
1231272cc70bSAndy Fleming
1232272cc70bSAndy Fleming retry_scr:
1233f781dd38SAnton staaf data.dest = (char *)scr;
1234272cc70bSAndy Fleming data.blocksize = 8;
1235272cc70bSAndy Fleming data.blocks = 1;
1236272cc70bSAndy Fleming data.flags = MMC_DATA_READ;
1237272cc70bSAndy Fleming
1238272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, &data);
1239272cc70bSAndy Fleming
1240272cc70bSAndy Fleming if (err) {
1241272cc70bSAndy Fleming if (timeout--)
1242272cc70bSAndy Fleming goto retry_scr;
1243272cc70bSAndy Fleming
1244272cc70bSAndy Fleming return err;
1245272cc70bSAndy Fleming }
1246272cc70bSAndy Fleming
12474e3d89baSYauhen Kharuzhy mmc->scr[0] = __be32_to_cpu(scr[0]);
12484e3d89baSYauhen Kharuzhy mmc->scr[1] = __be32_to_cpu(scr[1]);
1249272cc70bSAndy Fleming
1250272cc70bSAndy Fleming switch ((mmc->scr[0] >> 24) & 0xf) {
1251272cc70bSAndy Fleming case 0:
1252272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0;
1253272cc70bSAndy Fleming break;
1254272cc70bSAndy Fleming case 1:
1255272cc70bSAndy Fleming mmc->version = SD_VERSION_1_10;
1256272cc70bSAndy Fleming break;
1257272cc70bSAndy Fleming case 2:
1258272cc70bSAndy Fleming mmc->version = SD_VERSION_2;
12591741c64dSJaehoon Chung if ((mmc->scr[0] >> 15) & 0x1)
12601741c64dSJaehoon Chung mmc->version = SD_VERSION_3;
1261272cc70bSAndy Fleming break;
1262272cc70bSAndy Fleming default:
1263272cc70bSAndy Fleming mmc->version = SD_VERSION_1_0;
1264272cc70bSAndy Fleming break;
1265272cc70bSAndy Fleming }
1266272cc70bSAndy Fleming
1267b44c7083SAlagu Sankar if (mmc->scr[0] & SD_DATA_4BIT)
1268b44c7083SAlagu Sankar mmc->card_caps |= MMC_MODE_4BIT;
1269b44c7083SAlagu Sankar
1270272cc70bSAndy Fleming /* Version 1.0 doesn't support switching */
1271272cc70bSAndy Fleming if (mmc->version == SD_VERSION_1_0)
1272272cc70bSAndy Fleming return 0;
1273272cc70bSAndy Fleming
1274272cc70bSAndy Fleming timeout = 4;
1275272cc70bSAndy Fleming while (timeout--) {
1276272cc70bSAndy Fleming err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
1277f781dd38SAnton staaf (u8 *)switch_status);
1278272cc70bSAndy Fleming
1279272cc70bSAndy Fleming if (err)
1280272cc70bSAndy Fleming return err;
1281272cc70bSAndy Fleming
1282272cc70bSAndy Fleming /* The high-speed function is busy. Try again */
12834e3d89baSYauhen Kharuzhy if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
1284272cc70bSAndy Fleming break;
1285272cc70bSAndy Fleming }
1286272cc70bSAndy Fleming
1287272cc70bSAndy Fleming /* If high-speed isn't supported, we return */
1288d0c221feSJean-Jacques Hiblot if (__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)
1289d0c221feSJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(SD_HS);
1290272cc70bSAndy Fleming
1291f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1292c10b85d6SJean-Jacques Hiblot /* Version before 3.0 don't support UHS modes */
1293c10b85d6SJean-Jacques Hiblot if (mmc->version < SD_VERSION_3)
1294c10b85d6SJean-Jacques Hiblot return 0;
1295c10b85d6SJean-Jacques Hiblot
1296c10b85d6SJean-Jacques Hiblot sd3_bus_mode = __be32_to_cpu(switch_status[3]) >> 16 & 0x1f;
1297c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR104)
1298c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR104);
1299c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR50)
1300c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR50);
1301c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR25)
1302c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR25);
1303c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_SDR12)
1304c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_SDR12);
1305c10b85d6SJean-Jacques Hiblot if (sd3_bus_mode & SD_MODE_UHS_DDR50)
1306c10b85d6SJean-Jacques Hiblot mmc->card_caps |= MMC_CAP(UHS_DDR50);
1307f99c2efeSJean-Jacques Hiblot #endif
1308c10b85d6SJean-Jacques Hiblot
13092c3fbf4cSMacpaul Lin return 0;
1310d0c221feSJean-Jacques Hiblot }
1311d0c221feSJean-Jacques Hiblot
sd_set_card_speed(struct mmc * mmc,enum bus_mode mode)1312d0c221feSJean-Jacques Hiblot static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode)
1313d0c221feSJean-Jacques Hiblot {
1314d0c221feSJean-Jacques Hiblot int err;
1315d0c221feSJean-Jacques Hiblot
1316d0c221feSJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
1317c10b85d6SJean-Jacques Hiblot int speed;
13182c3fbf4cSMacpaul Lin
1319cf345760SMarek Vasut /* SD version 1.00 and 1.01 does not support CMD 6 */
1320cf345760SMarek Vasut if (mmc->version == SD_VERSION_1_0)
1321cf345760SMarek Vasut return 0;
1322cf345760SMarek Vasut
1323c10b85d6SJean-Jacques Hiblot switch (mode) {
1324c10b85d6SJean-Jacques Hiblot case SD_LEGACY:
1325c10b85d6SJean-Jacques Hiblot speed = UHS_SDR12_BUS_SPEED;
1326c10b85d6SJean-Jacques Hiblot break;
1327c10b85d6SJean-Jacques Hiblot case SD_HS:
1328baef2070SJean-Jacques Hiblot speed = HIGH_SPEED_BUS_SPEED;
1329baef2070SJean-Jacques Hiblot break;
1330baef2070SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1331baef2070SJean-Jacques Hiblot case UHS_SDR12:
1332baef2070SJean-Jacques Hiblot speed = UHS_SDR12_BUS_SPEED;
1333baef2070SJean-Jacques Hiblot break;
1334c10b85d6SJean-Jacques Hiblot case UHS_SDR25:
1335c10b85d6SJean-Jacques Hiblot speed = UHS_SDR25_BUS_SPEED;
1336c10b85d6SJean-Jacques Hiblot break;
1337c10b85d6SJean-Jacques Hiblot case UHS_SDR50:
1338c10b85d6SJean-Jacques Hiblot speed = UHS_SDR50_BUS_SPEED;
1339c10b85d6SJean-Jacques Hiblot break;
1340c10b85d6SJean-Jacques Hiblot case UHS_DDR50:
1341c10b85d6SJean-Jacques Hiblot speed = UHS_DDR50_BUS_SPEED;
1342c10b85d6SJean-Jacques Hiblot break;
1343c10b85d6SJean-Jacques Hiblot case UHS_SDR104:
1344c10b85d6SJean-Jacques Hiblot speed = UHS_SDR104_BUS_SPEED;
1345c10b85d6SJean-Jacques Hiblot break;
1346baef2070SJean-Jacques Hiblot #endif
1347c10b85d6SJean-Jacques Hiblot default:
1348c10b85d6SJean-Jacques Hiblot return -EINVAL;
1349c10b85d6SJean-Jacques Hiblot }
1350c10b85d6SJean-Jacques Hiblot
1351c10b85d6SJean-Jacques Hiblot err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, speed, (u8 *)switch_status);
1352272cc70bSAndy Fleming if (err)
1353272cc70bSAndy Fleming return err;
1354272cc70bSAndy Fleming
1355a0276f3eSJean-Jacques Hiblot if (((__be32_to_cpu(switch_status[4]) >> 24) & 0xF) != speed)
1356d0c221feSJean-Jacques Hiblot return -ENOTSUPP;
1357d0c221feSJean-Jacques Hiblot
1358d0c221feSJean-Jacques Hiblot return 0;
1359d0c221feSJean-Jacques Hiblot }
1360d0c221feSJean-Jacques Hiblot
sd_select_bus_width(struct mmc * mmc,int w)1361ec360e64SMarek Vasut static int sd_select_bus_width(struct mmc *mmc, int w)
1362d0c221feSJean-Jacques Hiblot {
1363d0c221feSJean-Jacques Hiblot int err;
1364d0c221feSJean-Jacques Hiblot struct mmc_cmd cmd;
1365d0c221feSJean-Jacques Hiblot
1366d0c221feSJean-Jacques Hiblot if ((w != 4) && (w != 1))
1367d0c221feSJean-Jacques Hiblot return -EINVAL;
1368d0c221feSJean-Jacques Hiblot
1369d0c221feSJean-Jacques Hiblot cmd.cmdidx = MMC_CMD_APP_CMD;
1370d0c221feSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1;
1371d0c221feSJean-Jacques Hiblot cmd.cmdarg = mmc->rca << 16;
1372d0c221feSJean-Jacques Hiblot
1373d0c221feSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL);
1374d0c221feSJean-Jacques Hiblot if (err)
1375d0c221feSJean-Jacques Hiblot return err;
1376d0c221feSJean-Jacques Hiblot
1377d0c221feSJean-Jacques Hiblot cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
1378d0c221feSJean-Jacques Hiblot cmd.resp_type = MMC_RSP_R1;
1379d0c221feSJean-Jacques Hiblot if (w == 4)
1380d0c221feSJean-Jacques Hiblot cmd.cmdarg = 2;
1381d0c221feSJean-Jacques Hiblot else if (w == 1)
1382d0c221feSJean-Jacques Hiblot cmd.cmdarg = 0;
1383d0c221feSJean-Jacques Hiblot err = mmc_send_cmd(mmc, &cmd, NULL);
1384d0c221feSJean-Jacques Hiblot if (err)
1385d0c221feSJean-Jacques Hiblot return err;
1386272cc70bSAndy Fleming
1387272cc70bSAndy Fleming return 0;
1388272cc70bSAndy Fleming }
138962d77ceaSMarek Vasut #endif
1390272cc70bSAndy Fleming
13915b2e72f3SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE)
sd_read_ssr(struct mmc * mmc)13923697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc)
13933697e599SPeng Fan {
13945b2e72f3SJean-Jacques Hiblot static const unsigned int sd_au_size[] = {
13955b2e72f3SJean-Jacques Hiblot 0, SZ_16K / 512, SZ_32K / 512,
13965b2e72f3SJean-Jacques Hiblot SZ_64K / 512, SZ_128K / 512, SZ_256K / 512,
13975b2e72f3SJean-Jacques Hiblot SZ_512K / 512, SZ_1M / 512, SZ_2M / 512,
13985b2e72f3SJean-Jacques Hiblot SZ_4M / 512, SZ_8M / 512, (SZ_8M + SZ_4M) / 512,
13995b2e72f3SJean-Jacques Hiblot SZ_16M / 512, (SZ_16M + SZ_8M) / 512, SZ_32M / 512,
14005b2e72f3SJean-Jacques Hiblot SZ_64M / 512,
14015b2e72f3SJean-Jacques Hiblot };
14023697e599SPeng Fan int err, i;
14033697e599SPeng Fan struct mmc_cmd cmd;
14043697e599SPeng Fan ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16);
14053697e599SPeng Fan struct mmc_data data;
14063697e599SPeng Fan int timeout = 3;
14073697e599SPeng Fan unsigned int au, eo, et, es;
14083697e599SPeng Fan
14093697e599SPeng Fan cmd.cmdidx = MMC_CMD_APP_CMD;
14103697e599SPeng Fan cmd.resp_type = MMC_RSP_R1;
14113697e599SPeng Fan cmd.cmdarg = mmc->rca << 16;
14123697e599SPeng Fan
14133697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, NULL);
14143697e599SPeng Fan if (err)
14153697e599SPeng Fan return err;
14163697e599SPeng Fan
14173697e599SPeng Fan cmd.cmdidx = SD_CMD_APP_SD_STATUS;
14183697e599SPeng Fan cmd.resp_type = MMC_RSP_R1;
14193697e599SPeng Fan cmd.cmdarg = 0;
14203697e599SPeng Fan
14213697e599SPeng Fan retry_ssr:
14223697e599SPeng Fan data.dest = (char *)ssr;
14233697e599SPeng Fan data.blocksize = 64;
14243697e599SPeng Fan data.blocks = 1;
14253697e599SPeng Fan data.flags = MMC_DATA_READ;
14263697e599SPeng Fan
14273697e599SPeng Fan err = mmc_send_cmd(mmc, &cmd, &data);
14283697e599SPeng Fan if (err) {
14293697e599SPeng Fan if (timeout--)
14303697e599SPeng Fan goto retry_ssr;
14313697e599SPeng Fan
14323697e599SPeng Fan return err;
14333697e599SPeng Fan }
14343697e599SPeng Fan
14353697e599SPeng Fan for (i = 0; i < 16; i++)
14363697e599SPeng Fan ssr[i] = be32_to_cpu(ssr[i]);
14373697e599SPeng Fan
14383697e599SPeng Fan au = (ssr[2] >> 12) & 0xF;
14393697e599SPeng Fan if ((au <= 9) || (mmc->version == SD_VERSION_3)) {
14403697e599SPeng Fan mmc->ssr.au = sd_au_size[au];
14413697e599SPeng Fan es = (ssr[3] >> 24) & 0xFF;
14423697e599SPeng Fan es |= (ssr[2] & 0xFF) << 8;
14433697e599SPeng Fan et = (ssr[3] >> 18) & 0x3F;
14443697e599SPeng Fan if (es && et) {
14453697e599SPeng Fan eo = (ssr[3] >> 16) & 0x3;
14463697e599SPeng Fan mmc->ssr.erase_timeout = (et * 1000) / es;
14473697e599SPeng Fan mmc->ssr.erase_offset = eo * 1000;
14483697e599SPeng Fan }
14493697e599SPeng Fan } else {
1450d4d64889SMasahiro Yamada pr_debug("Invalid Allocation Unit Size.\n");
14513697e599SPeng Fan }
14523697e599SPeng Fan
14533697e599SPeng Fan return 0;
14543697e599SPeng Fan }
14555b2e72f3SJean-Jacques Hiblot #endif
1456272cc70bSAndy Fleming /* frequency bases */
1457272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
14585f837c2cSMike Frysinger static const int fbase[] = {
1459272cc70bSAndy Fleming 10000,
1460272cc70bSAndy Fleming 100000,
1461272cc70bSAndy Fleming 1000000,
1462272cc70bSAndy Fleming 10000000,
1463272cc70bSAndy Fleming };
1464272cc70bSAndy Fleming
1465272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED. Multiplied by 10 to be nice
1466272cc70bSAndy Fleming * to platforms without floating point.
1467272cc70bSAndy Fleming */
146861fe076fSSimon Glass static const u8 multipliers[] = {
1469272cc70bSAndy Fleming 0, /* reserved */
1470272cc70bSAndy Fleming 10,
1471272cc70bSAndy Fleming 12,
1472272cc70bSAndy Fleming 13,
1473272cc70bSAndy Fleming 15,
1474272cc70bSAndy Fleming 20,
1475272cc70bSAndy Fleming 25,
1476272cc70bSAndy Fleming 30,
1477272cc70bSAndy Fleming 35,
1478272cc70bSAndy Fleming 40,
1479272cc70bSAndy Fleming 45,
1480272cc70bSAndy Fleming 50,
1481272cc70bSAndy Fleming 55,
1482272cc70bSAndy Fleming 60,
1483272cc70bSAndy Fleming 70,
1484272cc70bSAndy Fleming 80,
1485272cc70bSAndy Fleming };
1486272cc70bSAndy Fleming
bus_width(uint cap)1487d0c221feSJean-Jacques Hiblot static inline int bus_width(uint cap)
1488d0c221feSJean-Jacques Hiblot {
1489d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_8BIT)
1490d0c221feSJean-Jacques Hiblot return 8;
1491d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_4BIT)
1492d0c221feSJean-Jacques Hiblot return 4;
1493d0c221feSJean-Jacques Hiblot if (cap == MMC_MODE_1BIT)
1494d0c221feSJean-Jacques Hiblot return 1;
1495d8e3d420SJean-Jacques Hiblot pr_warn("invalid bus witdh capability 0x%x\n", cap);
1496d0c221feSJean-Jacques Hiblot return 0;
1497d0c221feSJean-Jacques Hiblot }
1498d0c221feSJean-Jacques Hiblot
1499e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
1500f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
mmc_execute_tuning(struct mmc * mmc,uint opcode)1501ec841209SKishon Vijay Abraham I static int mmc_execute_tuning(struct mmc *mmc, uint opcode)
1502ec841209SKishon Vijay Abraham I {
1503ec841209SKishon Vijay Abraham I return -ENOTSUPP;
1504ec841209SKishon Vijay Abraham I }
1505f99c2efeSJean-Jacques Hiblot #endif
1506ec841209SKishon Vijay Abraham I
mmc_send_init_stream(struct mmc * mmc)1507318a7a57SJean-Jacques Hiblot static void mmc_send_init_stream(struct mmc *mmc)
1508318a7a57SJean-Jacques Hiblot {
1509318a7a57SJean-Jacques Hiblot }
1510318a7a57SJean-Jacques Hiblot
mmc_set_ios(struct mmc * mmc)15112a4d212fSKishon Vijay Abraham I static int mmc_set_ios(struct mmc *mmc)
1512272cc70bSAndy Fleming {
15132a4d212fSKishon Vijay Abraham I int ret = 0;
15142a4d212fSKishon Vijay Abraham I
151593bfd616SPantelis Antoniou if (mmc->cfg->ops->set_ios)
15162a4d212fSKishon Vijay Abraham I ret = mmc->cfg->ops->set_ios(mmc);
15172a4d212fSKishon Vijay Abraham I
15182a4d212fSKishon Vijay Abraham I return ret;
1519272cc70bSAndy Fleming }
15208ca51e51SSimon Glass #endif
1521272cc70bSAndy Fleming
mmc_set_clock(struct mmc * mmc,uint clock,bool disable)152235f67820SKishon Vijay Abraham I int mmc_set_clock(struct mmc *mmc, uint clock, bool disable)
1523272cc70bSAndy Fleming {
1524c0fafe64SJaehoon Chung if (!disable) {
152593bfd616SPantelis Antoniou if (clock > mmc->cfg->f_max)
152693bfd616SPantelis Antoniou clock = mmc->cfg->f_max;
1527272cc70bSAndy Fleming
152893bfd616SPantelis Antoniou if (clock < mmc->cfg->f_min)
152993bfd616SPantelis Antoniou clock = mmc->cfg->f_min;
15309546eb92SJaehoon Chung }
1531272cc70bSAndy Fleming
1532272cc70bSAndy Fleming mmc->clock = clock;
153335f67820SKishon Vijay Abraham I mmc->clk_disable = disable;
1534272cc70bSAndy Fleming
1535d2faadb5SJaehoon Chung debug("clock is %s (%dHz)\n", disable ? "disabled" : "enabled", clock);
1536d2faadb5SJaehoon Chung
15372a4d212fSKishon Vijay Abraham I return mmc_set_ios(mmc);
1538272cc70bSAndy Fleming }
1539272cc70bSAndy Fleming
mmc_set_bus_width(struct mmc * mmc,uint width)15402a4d212fSKishon Vijay Abraham I static int mmc_set_bus_width(struct mmc *mmc, uint width)
1541272cc70bSAndy Fleming {
1542272cc70bSAndy Fleming mmc->bus_width = width;
1543272cc70bSAndy Fleming
15442a4d212fSKishon Vijay Abraham I return mmc_set_ios(mmc);
1545272cc70bSAndy Fleming }
1546272cc70bSAndy Fleming
15474c9d2aaaSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG)
15484c9d2aaaSJean-Jacques Hiblot /*
15494c9d2aaaSJean-Jacques Hiblot * helper function to display the capabilities in a human
15504c9d2aaaSJean-Jacques Hiblot * friendly manner. The capabilities include bus width and
15514c9d2aaaSJean-Jacques Hiblot * supported modes.
15524c9d2aaaSJean-Jacques Hiblot */
mmc_dump_capabilities(const char * text,uint caps)15534c9d2aaaSJean-Jacques Hiblot void mmc_dump_capabilities(const char *text, uint caps)
15544c9d2aaaSJean-Jacques Hiblot {
15554c9d2aaaSJean-Jacques Hiblot enum bus_mode mode;
15564c9d2aaaSJean-Jacques Hiblot
1557d4d64889SMasahiro Yamada pr_debug("%s: widths [", text);
15584c9d2aaaSJean-Jacques Hiblot if (caps & MMC_MODE_8BIT)
1559d4d64889SMasahiro Yamada pr_debug("8, ");
15604c9d2aaaSJean-Jacques Hiblot if (caps & MMC_MODE_4BIT)
1561d4d64889SMasahiro Yamada pr_debug("4, ");
1562d0c221feSJean-Jacques Hiblot if (caps & MMC_MODE_1BIT)
1563d4d64889SMasahiro Yamada pr_debug("1, ");
1564d4d64889SMasahiro Yamada pr_debug("\b\b] modes [");
15654c9d2aaaSJean-Jacques Hiblot for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++)
15664c9d2aaaSJean-Jacques Hiblot if (MMC_CAP(mode) & caps)
1567d4d64889SMasahiro Yamada pr_debug("%s, ", mmc_mode_name(mode));
1568d4d64889SMasahiro Yamada pr_debug("\b\b]\n");
15694c9d2aaaSJean-Jacques Hiblot }
15704c9d2aaaSJean-Jacques Hiblot #endif
15714c9d2aaaSJean-Jacques Hiblot
1572d0c221feSJean-Jacques Hiblot struct mode_width_tuning {
1573d0c221feSJean-Jacques Hiblot enum bus_mode mode;
1574d0c221feSJean-Jacques Hiblot uint widths;
1575f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
1576634d4849SKishon Vijay Abraham I uint tuning;
1577f99c2efeSJean-Jacques Hiblot #endif
1578d0c221feSJean-Jacques Hiblot };
1579d0c221feSJean-Jacques Hiblot
1580f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE)
mmc_voltage_to_mv(enum mmc_voltage voltage)1581bc1e3272SJean-Jacques Hiblot int mmc_voltage_to_mv(enum mmc_voltage voltage)
1582bc1e3272SJean-Jacques Hiblot {
1583bc1e3272SJean-Jacques Hiblot switch (voltage) {
1584bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_000: return 0;
1585bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_330: return 3300;
1586bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_180: return 1800;
1587bc1e3272SJean-Jacques Hiblot case MMC_SIGNAL_VOLTAGE_120: return 1200;
1588bc1e3272SJean-Jacques Hiblot }
1589bc1e3272SJean-Jacques Hiblot return -EINVAL;
1590bc1e3272SJean-Jacques Hiblot }
1591bc1e3272SJean-Jacques Hiblot
mmc_set_signal_voltage(struct mmc * mmc,uint signal_voltage)1592aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage)
1593aff5d3c8SKishon Vijay Abraham I {
1594bc1e3272SJean-Jacques Hiblot int err;
1595bc1e3272SJean-Jacques Hiblot
1596bc1e3272SJean-Jacques Hiblot if (mmc->signal_voltage == signal_voltage)
1597bc1e3272SJean-Jacques Hiblot return 0;
1598bc1e3272SJean-Jacques Hiblot
1599aff5d3c8SKishon Vijay Abraham I mmc->signal_voltage = signal_voltage;
1600bc1e3272SJean-Jacques Hiblot err = mmc_set_ios(mmc);
1601bc1e3272SJean-Jacques Hiblot if (err)
1602d4d64889SMasahiro Yamada pr_debug("unable to set voltage (err %d)\n", err);
1603bc1e3272SJean-Jacques Hiblot
1604bc1e3272SJean-Jacques Hiblot return err;
1605aff5d3c8SKishon Vijay Abraham I }
1606f99c2efeSJean-Jacques Hiblot #else
mmc_set_signal_voltage(struct mmc * mmc,uint signal_voltage)1607f99c2efeSJean-Jacques Hiblot static inline int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage)
1608f99c2efeSJean-Jacques Hiblot {
1609f99c2efeSJean-Jacques Hiblot return 0;
1610f99c2efeSJean-Jacques Hiblot }
1611f99c2efeSJean-Jacques Hiblot #endif
1612aff5d3c8SKishon Vijay Abraham I
161362d77ceaSMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY)
1614d0c221feSJean-Jacques Hiblot static const struct mode_width_tuning sd_modes_by_pref[] = {
1615f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1616f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
1617d0c221feSJean-Jacques Hiblot {
1618c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR104,
1619c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1620c10b85d6SJean-Jacques Hiblot .tuning = MMC_CMD_SEND_TUNING_BLOCK
1621c10b85d6SJean-Jacques Hiblot },
1622f99c2efeSJean-Jacques Hiblot #endif
1623c10b85d6SJean-Jacques Hiblot {
1624c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR50,
1625c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1626c10b85d6SJean-Jacques Hiblot },
1627c10b85d6SJean-Jacques Hiblot {
1628c10b85d6SJean-Jacques Hiblot .mode = UHS_DDR50,
1629c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1630c10b85d6SJean-Jacques Hiblot },
1631c10b85d6SJean-Jacques Hiblot {
1632c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR25,
1633c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1634c10b85d6SJean-Jacques Hiblot },
1635f99c2efeSJean-Jacques Hiblot #endif
1636c10b85d6SJean-Jacques Hiblot {
1637d0c221feSJean-Jacques Hiblot .mode = SD_HS,
1638d0c221feSJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1639d0c221feSJean-Jacques Hiblot },
1640f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1641d0c221feSJean-Jacques Hiblot {
1642c10b85d6SJean-Jacques Hiblot .mode = UHS_SDR12,
1643c10b85d6SJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1644c10b85d6SJean-Jacques Hiblot },
1645f99c2efeSJean-Jacques Hiblot #endif
1646c10b85d6SJean-Jacques Hiblot {
1647d0c221feSJean-Jacques Hiblot .mode = SD_LEGACY,
1648d0c221feSJean-Jacques Hiblot .widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1649d0c221feSJean-Jacques Hiblot }
1650d0c221feSJean-Jacques Hiblot };
1651d0c221feSJean-Jacques Hiblot
1652d0c221feSJean-Jacques Hiblot #define for_each_sd_mode_by_pref(caps, mwt) \
1653d0c221feSJean-Jacques Hiblot for (mwt = sd_modes_by_pref;\
1654d0c221feSJean-Jacques Hiblot mwt < sd_modes_by_pref + ARRAY_SIZE(sd_modes_by_pref);\
1655d0c221feSJean-Jacques Hiblot mwt++) \
1656d0c221feSJean-Jacques Hiblot if (caps & MMC_CAP(mwt->mode))
1657d0c221feSJean-Jacques Hiblot
sd_select_mode_and_width(struct mmc * mmc,uint card_caps)165801298da3SJean-Jacques Hiblot static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps)
16598ac8a263SJean-Jacques Hiblot {
16608ac8a263SJean-Jacques Hiblot int err;
1661d0c221feSJean-Jacques Hiblot uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT};
1662d0c221feSJean-Jacques Hiblot const struct mode_width_tuning *mwt;
1663f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1664c10b85d6SJean-Jacques Hiblot bool uhs_en = (mmc->ocr & OCR_S18R) ? true : false;
1665f99c2efeSJean-Jacques Hiblot #else
1666f99c2efeSJean-Jacques Hiblot bool uhs_en = false;
1667f99c2efeSJean-Jacques Hiblot #endif
1668c10b85d6SJean-Jacques Hiblot uint caps;
1669c10b85d6SJean-Jacques Hiblot
167052d241dfSJean-Jacques Hiblot #ifdef DEBUG
167152d241dfSJean-Jacques Hiblot mmc_dump_capabilities("sd card", card_caps);
16721da8eb59SJean-Jacques Hiblot mmc_dump_capabilities("host", mmc->host_caps);
167352d241dfSJean-Jacques Hiblot #endif
16748ac8a263SJean-Jacques Hiblot
16758ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */
16761da8eb59SJean-Jacques Hiblot caps = card_caps & mmc->host_caps;
16778ac8a263SJean-Jacques Hiblot
1678c10b85d6SJean-Jacques Hiblot if (!uhs_en)
1679c10b85d6SJean-Jacques Hiblot caps &= ~UHS_CAPS;
1680c10b85d6SJean-Jacques Hiblot
1681c10b85d6SJean-Jacques Hiblot for_each_sd_mode_by_pref(caps, mwt) {
1682d0c221feSJean-Jacques Hiblot uint *w;
16838ac8a263SJean-Jacques Hiblot
1684d0c221feSJean-Jacques Hiblot for (w = widths; w < widths + ARRAY_SIZE(widths); w++) {
1685c10b85d6SJean-Jacques Hiblot if (*w & caps & mwt->widths) {
1686d4d64889SMasahiro Yamada pr_debug("trying mode %s width %d (at %d MHz)\n",
1687d0c221feSJean-Jacques Hiblot mmc_mode_name(mwt->mode),
1688d0c221feSJean-Jacques Hiblot bus_width(*w),
1689d0c221feSJean-Jacques Hiblot mmc_mode2freq(mmc, mwt->mode) / 1000000);
1690d0c221feSJean-Jacques Hiblot
1691d0c221feSJean-Jacques Hiblot /* configure the bus width (card + host) */
1692d0c221feSJean-Jacques Hiblot err = sd_select_bus_width(mmc, bus_width(*w));
16938ac8a263SJean-Jacques Hiblot if (err)
1694d0c221feSJean-Jacques Hiblot goto error;
1695d0c221feSJean-Jacques Hiblot mmc_set_bus_width(mmc, bus_width(*w));
16968ac8a263SJean-Jacques Hiblot
1697d0c221feSJean-Jacques Hiblot /* configure the bus mode (card) */
1698d0c221feSJean-Jacques Hiblot err = sd_set_card_speed(mmc, mwt->mode);
16998ac8a263SJean-Jacques Hiblot if (err)
1700d0c221feSJean-Jacques Hiblot goto error;
17018ac8a263SJean-Jacques Hiblot
1702d0c221feSJean-Jacques Hiblot /* configure the bus mode (host) */
1703d0c221feSJean-Jacques Hiblot mmc_select_mode(mmc, mwt->mode);
170465117182SJaehoon Chung mmc_set_clock(mmc, mmc->tran_speed,
170565117182SJaehoon Chung MMC_CLK_ENABLE);
17068ac8a263SJean-Jacques Hiblot
1707f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
1708c10b85d6SJean-Jacques Hiblot /* execute tuning if needed */
1709c10b85d6SJean-Jacques Hiblot if (mwt->tuning && !mmc_host_is_spi(mmc)) {
1710c10b85d6SJean-Jacques Hiblot err = mmc_execute_tuning(mmc,
1711c10b85d6SJean-Jacques Hiblot mwt->tuning);
1712c10b85d6SJean-Jacques Hiblot if (err) {
1713d4d64889SMasahiro Yamada pr_debug("tuning failed\n");
1714c10b85d6SJean-Jacques Hiblot goto error;
1715c10b85d6SJean-Jacques Hiblot }
1716c10b85d6SJean-Jacques Hiblot }
1717f99c2efeSJean-Jacques Hiblot #endif
1718c10b85d6SJean-Jacques Hiblot
17195b2e72f3SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE)
17208ac8a263SJean-Jacques Hiblot err = sd_read_ssr(mmc);
17210a4c2b09SPeng Fan if (err)
17225b2e72f3SJean-Jacques Hiblot pr_warn("unable to read ssr\n");
17235b2e72f3SJean-Jacques Hiblot #endif
17245b2e72f3SJean-Jacques Hiblot if (!err)
17258ac8a263SJean-Jacques Hiblot return 0;
1726d0c221feSJean-Jacques Hiblot
1727d0c221feSJean-Jacques Hiblot error:
1728d0c221feSJean-Jacques Hiblot /* revert to a safer bus speed */
1729d0c221feSJean-Jacques Hiblot mmc_select_mode(mmc, SD_LEGACY);
173065117182SJaehoon Chung mmc_set_clock(mmc, mmc->tran_speed,
173165117182SJaehoon Chung MMC_CLK_ENABLE);
1732d0c221feSJean-Jacques Hiblot }
1733d0c221feSJean-Jacques Hiblot }
1734d0c221feSJean-Jacques Hiblot }
1735d0c221feSJean-Jacques Hiblot
1736d4d64889SMasahiro Yamada pr_err("unable to select a mode\n");
1737d0c221feSJean-Jacques Hiblot return -ENOTSUPP;
17388ac8a263SJean-Jacques Hiblot }
17398ac8a263SJean-Jacques Hiblot
17407382e691SJean-Jacques Hiblot /*
17417382e691SJean-Jacques Hiblot * read the compare the part of ext csd that is constant.
17427382e691SJean-Jacques Hiblot * This can be used to check that the transfer is working
17437382e691SJean-Jacques Hiblot * as expected.
17447382e691SJean-Jacques Hiblot */
mmc_read_and_compare_ext_csd(struct mmc * mmc)17457382e691SJean-Jacques Hiblot static int mmc_read_and_compare_ext_csd(struct mmc *mmc)
17467382e691SJean-Jacques Hiblot {
17477382e691SJean-Jacques Hiblot int err;
17487382e691SJean-Jacques Hiblot const u8 *ext_csd = mmc->ext_csd;
17497382e691SJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
17507382e691SJean-Jacques Hiblot
17511de06b9fSJean-Jacques Hiblot if (mmc->version < MMC_VERSION_4)
17521de06b9fSJean-Jacques Hiblot return 0;
17531de06b9fSJean-Jacques Hiblot
17547382e691SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, test_csd);
17557382e691SJean-Jacques Hiblot if (err)
17567382e691SJean-Jacques Hiblot return err;
17577382e691SJean-Jacques Hiblot
17587382e691SJean-Jacques Hiblot /* Only compare read only fields */
17597382e691SJean-Jacques Hiblot if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT]
17607382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_PARTITIONING_SUPPORT] &&
17617382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_WP_GRP_SIZE]
17627382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_WP_GRP_SIZE] &&
17637382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_REV]
17647382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_REV] &&
17657382e691SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
17667382e691SJean-Jacques Hiblot == test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] &&
17677382e691SJean-Jacques Hiblot memcmp(&ext_csd[EXT_CSD_SEC_CNT],
17687382e691SJean-Jacques Hiblot &test_csd[EXT_CSD_SEC_CNT], 4) == 0)
17697382e691SJean-Jacques Hiblot return 0;
17707382e691SJean-Jacques Hiblot
17717382e691SJean-Jacques Hiblot return -EBADMSG;
17727382e691SJean-Jacques Hiblot }
17737382e691SJean-Jacques Hiblot
1774f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE)
mmc_set_lowest_voltage(struct mmc * mmc,enum bus_mode mode,uint32_t allowed_mask)1775bc1e3272SJean-Jacques Hiblot static int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,
1776bc1e3272SJean-Jacques Hiblot uint32_t allowed_mask)
1777bc1e3272SJean-Jacques Hiblot {
1778bc1e3272SJean-Jacques Hiblot u32 card_mask = 0;
1779bc1e3272SJean-Jacques Hiblot
1780bc1e3272SJean-Jacques Hiblot switch (mode) {
17813dd2626fSPeng Fan case MMC_HS_400:
1782bc1e3272SJean-Jacques Hiblot case MMC_HS_200:
17833dd2626fSPeng Fan if (mmc->cardtype & (EXT_CSD_CARD_TYPE_HS200_1_8V |
17843dd2626fSPeng Fan EXT_CSD_CARD_TYPE_HS400_1_8V))
1785bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_180;
17863dd2626fSPeng Fan if (mmc->cardtype & (EXT_CSD_CARD_TYPE_HS200_1_2V |
17873dd2626fSPeng Fan EXT_CSD_CARD_TYPE_HS400_1_2V))
1788bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_120;
1789bc1e3272SJean-Jacques Hiblot break;
1790bc1e3272SJean-Jacques Hiblot case MMC_DDR_52:
1791bc1e3272SJean-Jacques Hiblot if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V)
1792bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_330 |
1793bc1e3272SJean-Jacques Hiblot MMC_SIGNAL_VOLTAGE_180;
1794bc1e3272SJean-Jacques Hiblot if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_2V)
1795bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_120;
1796bc1e3272SJean-Jacques Hiblot break;
1797bc1e3272SJean-Jacques Hiblot default:
1798bc1e3272SJean-Jacques Hiblot card_mask |= MMC_SIGNAL_VOLTAGE_330;
1799bc1e3272SJean-Jacques Hiblot break;
1800bc1e3272SJean-Jacques Hiblot }
1801bc1e3272SJean-Jacques Hiblot
1802bc1e3272SJean-Jacques Hiblot while (card_mask & allowed_mask) {
1803bc1e3272SJean-Jacques Hiblot enum mmc_voltage best_match;
1804bc1e3272SJean-Jacques Hiblot
1805bc1e3272SJean-Jacques Hiblot best_match = 1 << (ffs(card_mask & allowed_mask) - 1);
1806bc1e3272SJean-Jacques Hiblot if (!mmc_set_signal_voltage(mmc, best_match))
1807bc1e3272SJean-Jacques Hiblot return 0;
1808bc1e3272SJean-Jacques Hiblot
1809bc1e3272SJean-Jacques Hiblot allowed_mask &= ~best_match;
1810bc1e3272SJean-Jacques Hiblot }
1811bc1e3272SJean-Jacques Hiblot
1812bc1e3272SJean-Jacques Hiblot return -ENOTSUPP;
1813bc1e3272SJean-Jacques Hiblot }
1814f99c2efeSJean-Jacques Hiblot #else
mmc_set_lowest_voltage(struct mmc * mmc,enum bus_mode mode,uint32_t allowed_mask)1815f99c2efeSJean-Jacques Hiblot static inline int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,
1816f99c2efeSJean-Jacques Hiblot uint32_t allowed_mask)
1817f99c2efeSJean-Jacques Hiblot {
1818f99c2efeSJean-Jacques Hiblot return 0;
1819f99c2efeSJean-Jacques Hiblot }
1820f99c2efeSJean-Jacques Hiblot #endif
1821bc1e3272SJean-Jacques Hiblot
18223862b854SJean-Jacques Hiblot static const struct mode_width_tuning mmc_modes_by_pref[] = {
18233dd2626fSPeng Fan #if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
18243dd2626fSPeng Fan {
18253dd2626fSPeng Fan .mode = MMC_HS_400,
18263dd2626fSPeng Fan .widths = MMC_MODE_8BIT,
18273dd2626fSPeng Fan .tuning = MMC_CMD_SEND_TUNING_BLOCK_HS200
18283dd2626fSPeng Fan },
18293dd2626fSPeng Fan #endif
1830f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
18318ac8a263SJean-Jacques Hiblot {
18323862b854SJean-Jacques Hiblot .mode = MMC_HS_200,
18333862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
1834634d4849SKishon Vijay Abraham I .tuning = MMC_CMD_SEND_TUNING_BLOCK_HS200
18353862b854SJean-Jacques Hiblot },
1836f99c2efeSJean-Jacques Hiblot #endif
18373862b854SJean-Jacques Hiblot {
18383862b854SJean-Jacques Hiblot .mode = MMC_DDR_52,
18393862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
18403862b854SJean-Jacques Hiblot },
18413862b854SJean-Jacques Hiblot {
18423862b854SJean-Jacques Hiblot .mode = MMC_HS_52,
18433862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
18443862b854SJean-Jacques Hiblot },
18453862b854SJean-Jacques Hiblot {
18463862b854SJean-Jacques Hiblot .mode = MMC_HS,
18473862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
18483862b854SJean-Jacques Hiblot },
18493862b854SJean-Jacques Hiblot {
18503862b854SJean-Jacques Hiblot .mode = MMC_LEGACY,
18513862b854SJean-Jacques Hiblot .widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
18523862b854SJean-Jacques Hiblot }
18538ac8a263SJean-Jacques Hiblot };
18548ac8a263SJean-Jacques Hiblot
18553862b854SJean-Jacques Hiblot #define for_each_mmc_mode_by_pref(caps, mwt) \
18563862b854SJean-Jacques Hiblot for (mwt = mmc_modes_by_pref;\
18573862b854SJean-Jacques Hiblot mwt < mmc_modes_by_pref + ARRAY_SIZE(mmc_modes_by_pref);\
18583862b854SJean-Jacques Hiblot mwt++) \
18593862b854SJean-Jacques Hiblot if (caps & MMC_CAP(mwt->mode))
18603862b854SJean-Jacques Hiblot
18613862b854SJean-Jacques Hiblot static const struct ext_csd_bus_width {
18623862b854SJean-Jacques Hiblot uint cap;
18633862b854SJean-Jacques Hiblot bool is_ddr;
18643862b854SJean-Jacques Hiblot uint ext_csd_bits;
18653862b854SJean-Jacques Hiblot } ext_csd_bus_width[] = {
18663862b854SJean-Jacques Hiblot {MMC_MODE_8BIT, true, EXT_CSD_DDR_BUS_WIDTH_8},
18673862b854SJean-Jacques Hiblot {MMC_MODE_4BIT, true, EXT_CSD_DDR_BUS_WIDTH_4},
18683862b854SJean-Jacques Hiblot {MMC_MODE_8BIT, false, EXT_CSD_BUS_WIDTH_8},
18693862b854SJean-Jacques Hiblot {MMC_MODE_4BIT, false, EXT_CSD_BUS_WIDTH_4},
18703862b854SJean-Jacques Hiblot {MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1},
18713862b854SJean-Jacques Hiblot };
18723862b854SJean-Jacques Hiblot
18733dd2626fSPeng Fan #if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
mmc_select_hs400(struct mmc * mmc)18743dd2626fSPeng Fan static int mmc_select_hs400(struct mmc *mmc)
18753dd2626fSPeng Fan {
18763dd2626fSPeng Fan int err;
18773dd2626fSPeng Fan
18783dd2626fSPeng Fan /* Set timing to HS200 for tuning */
1879b9a2a0e2SMarek Vasut err = mmc_set_card_speed(mmc, MMC_HS_200, false);
18803dd2626fSPeng Fan if (err)
18813dd2626fSPeng Fan return err;
18823dd2626fSPeng Fan
18833dd2626fSPeng Fan /* configure the bus mode (host) */
18843dd2626fSPeng Fan mmc_select_mode(mmc, MMC_HS_200);
18853dd2626fSPeng Fan mmc_set_clock(mmc, mmc->tran_speed, false);
18863dd2626fSPeng Fan
18873dd2626fSPeng Fan /* execute tuning if needed */
18883dd2626fSPeng Fan err = mmc_execute_tuning(mmc, MMC_CMD_SEND_TUNING_BLOCK_HS200);
18893dd2626fSPeng Fan if (err) {
18903dd2626fSPeng Fan debug("tuning failed\n");
18913dd2626fSPeng Fan return err;
18923dd2626fSPeng Fan }
18933dd2626fSPeng Fan
18943dd2626fSPeng Fan /* Set back to HS */
1895*5cf12031SBOUGH CHEN mmc_set_card_speed(mmc, MMC_HS, true);
18963dd2626fSPeng Fan
18973dd2626fSPeng Fan err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH,
18983dd2626fSPeng Fan EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_FLAG);
18993dd2626fSPeng Fan if (err)
19003dd2626fSPeng Fan return err;
19013dd2626fSPeng Fan
1902b9a2a0e2SMarek Vasut err = mmc_set_card_speed(mmc, MMC_HS_400, false);
19033dd2626fSPeng Fan if (err)
19043dd2626fSPeng Fan return err;
19053dd2626fSPeng Fan
19063dd2626fSPeng Fan mmc_select_mode(mmc, MMC_HS_400);
19073dd2626fSPeng Fan err = mmc_set_clock(mmc, mmc->tran_speed, false);
19083dd2626fSPeng Fan if (err)
19093dd2626fSPeng Fan return err;
19103dd2626fSPeng Fan
19113dd2626fSPeng Fan return 0;
19123dd2626fSPeng Fan }
19133dd2626fSPeng Fan #else
mmc_select_hs400(struct mmc * mmc)19143dd2626fSPeng Fan static int mmc_select_hs400(struct mmc *mmc)
19153dd2626fSPeng Fan {
19163dd2626fSPeng Fan return -ENOTSUPP;
19173dd2626fSPeng Fan }
19183dd2626fSPeng Fan #endif
19193dd2626fSPeng Fan
19203862b854SJean-Jacques Hiblot #define for_each_supported_width(caps, ddr, ecbv) \
19213862b854SJean-Jacques Hiblot for (ecbv = ext_csd_bus_width;\
19223862b854SJean-Jacques Hiblot ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\
19233862b854SJean-Jacques Hiblot ecbv++) \
19243862b854SJean-Jacques Hiblot if ((ddr == ecbv->is_ddr) && (caps & ecbv->cap))
19253862b854SJean-Jacques Hiblot
mmc_select_mode_and_width(struct mmc * mmc,uint card_caps)192601298da3SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
19273862b854SJean-Jacques Hiblot {
19283862b854SJean-Jacques Hiblot int err;
19293862b854SJean-Jacques Hiblot const struct mode_width_tuning *mwt;
19303862b854SJean-Jacques Hiblot const struct ext_csd_bus_width *ecbw;
19313862b854SJean-Jacques Hiblot
193252d241dfSJean-Jacques Hiblot #ifdef DEBUG
193352d241dfSJean-Jacques Hiblot mmc_dump_capabilities("mmc", card_caps);
19341da8eb59SJean-Jacques Hiblot mmc_dump_capabilities("host", mmc->host_caps);
193552d241dfSJean-Jacques Hiblot #endif
193652d241dfSJean-Jacques Hiblot
19378ac8a263SJean-Jacques Hiblot /* Restrict card's capabilities by what the host can do */
19381da8eb59SJean-Jacques Hiblot card_caps &= mmc->host_caps;
19398ac8a263SJean-Jacques Hiblot
19408ac8a263SJean-Jacques Hiblot /* Only version 4 of MMC supports wider bus widths */
19418ac8a263SJean-Jacques Hiblot if (mmc->version < MMC_VERSION_4)
19428ac8a263SJean-Jacques Hiblot return 0;
19438ac8a263SJean-Jacques Hiblot
1944dfda9d88SJean-Jacques Hiblot if (!mmc->ext_csd) {
1945d4d64889SMasahiro Yamada pr_debug("No ext_csd found!\n"); /* this should enver happen */
1946dfda9d88SJean-Jacques Hiblot return -ENOTSUPP;
1947dfda9d88SJean-Jacques Hiblot }
1948dfda9d88SJean-Jacques Hiblot
1949b9a2a0e2SMarek Vasut #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \
1950b9a2a0e2SMarek Vasut CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
1951b9a2a0e2SMarek Vasut /*
1952b9a2a0e2SMarek Vasut * In case the eMMC is in HS200/HS400 mode, downgrade to HS mode
1953b9a2a0e2SMarek Vasut * before doing anything else, since a transition from either of
1954b9a2a0e2SMarek Vasut * the HS200/HS400 mode directly to legacy mode is not supported.
1955b9a2a0e2SMarek Vasut */
1956b9a2a0e2SMarek Vasut if (mmc->selected_mode == MMC_HS_200 ||
1957b9a2a0e2SMarek Vasut mmc->selected_mode == MMC_HS_400)
1958b9a2a0e2SMarek Vasut mmc_set_card_speed(mmc, MMC_HS, true);
1959b9a2a0e2SMarek Vasut else
1960b9a2a0e2SMarek Vasut #endif
196165117182SJaehoon Chung mmc_set_clock(mmc, mmc->legacy_speed, MMC_CLK_ENABLE);
196201298da3SJean-Jacques Hiblot
196301298da3SJean-Jacques Hiblot for_each_mmc_mode_by_pref(card_caps, mwt) {
196401298da3SJean-Jacques Hiblot for_each_supported_width(card_caps & mwt->widths,
19653862b854SJean-Jacques Hiblot mmc_is_mode_ddr(mwt->mode), ecbw) {
1966bc1e3272SJean-Jacques Hiblot enum mmc_voltage old_voltage;
1967d4d64889SMasahiro Yamada pr_debug("trying mode %s width %d (at %d MHz)\n",
19683862b854SJean-Jacques Hiblot mmc_mode_name(mwt->mode),
19693862b854SJean-Jacques Hiblot bus_width(ecbw->cap),
19703862b854SJean-Jacques Hiblot mmc_mode2freq(mmc, mwt->mode) / 1000000);
1971bc1e3272SJean-Jacques Hiblot old_voltage = mmc->signal_voltage;
1972bc1e3272SJean-Jacques Hiblot err = mmc_set_lowest_voltage(mmc, mwt->mode,
1973bc1e3272SJean-Jacques Hiblot MMC_ALL_SIGNAL_VOLTAGE);
1974bc1e3272SJean-Jacques Hiblot if (err)
1975bc1e3272SJean-Jacques Hiblot continue;
1976bc1e3272SJean-Jacques Hiblot
19773862b854SJean-Jacques Hiblot /* configure the bus width (card + host) */
19783862b854SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
19793862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH,
19803862b854SJean-Jacques Hiblot ecbw->ext_csd_bits & ~EXT_CSD_DDR_FLAG);
19813862b854SJean-Jacques Hiblot if (err)
19823862b854SJean-Jacques Hiblot goto error;
19833862b854SJean-Jacques Hiblot mmc_set_bus_width(mmc, bus_width(ecbw->cap));
19843862b854SJean-Jacques Hiblot
19853dd2626fSPeng Fan if (mwt->mode == MMC_HS_400) {
19863dd2626fSPeng Fan err = mmc_select_hs400(mmc);
19873dd2626fSPeng Fan if (err) {
19883dd2626fSPeng Fan printf("Select HS400 failed %d\n", err);
19893dd2626fSPeng Fan goto error;
19903dd2626fSPeng Fan }
19913dd2626fSPeng Fan } else {
19923862b854SJean-Jacques Hiblot /* configure the bus speed (card) */
1993b9a2a0e2SMarek Vasut err = mmc_set_card_speed(mmc, mwt->mode, false);
19943862b854SJean-Jacques Hiblot if (err)
19953862b854SJean-Jacques Hiblot goto error;
19963862b854SJean-Jacques Hiblot
19978ac8a263SJean-Jacques Hiblot /*
19983dd2626fSPeng Fan * configure the bus width AND the ddr mode
19993dd2626fSPeng Fan * (card). The host side will be taken care
20003dd2626fSPeng Fan * of in the next step
20018ac8a263SJean-Jacques Hiblot */
20023862b854SJean-Jacques Hiblot if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) {
20033dd2626fSPeng Fan err = mmc_switch(mmc,
20043dd2626fSPeng Fan EXT_CSD_CMD_SET_NORMAL,
20053862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH,
20063862b854SJean-Jacques Hiblot ecbw->ext_csd_bits);
20073862b854SJean-Jacques Hiblot if (err)
20083862b854SJean-Jacques Hiblot goto error;
20098ac8a263SJean-Jacques Hiblot }
20108ac8a263SJean-Jacques Hiblot
20113862b854SJean-Jacques Hiblot /* configure the bus mode (host) */
20123862b854SJean-Jacques Hiblot mmc_select_mode(mmc, mwt->mode);
20133dd2626fSPeng Fan mmc_set_clock(mmc, mmc->tran_speed,
20143dd2626fSPeng Fan MMC_CLK_ENABLE);
2015f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
20168ac8a263SJean-Jacques Hiblot
2017634d4849SKishon Vijay Abraham I /* execute tuning if needed */
2018634d4849SKishon Vijay Abraham I if (mwt->tuning) {
20193dd2626fSPeng Fan err = mmc_execute_tuning(mmc,
20203dd2626fSPeng Fan mwt->tuning);
2021634d4849SKishon Vijay Abraham I if (err) {
2022d4d64889SMasahiro Yamada pr_debug("tuning failed\n");
2023634d4849SKishon Vijay Abraham I goto error;
2024634d4849SKishon Vijay Abraham I }
2025634d4849SKishon Vijay Abraham I }
2026f99c2efeSJean-Jacques Hiblot #endif
20273dd2626fSPeng Fan }
2028634d4849SKishon Vijay Abraham I
20293862b854SJean-Jacques Hiblot /* do a transfer to check the configuration */
20307382e691SJean-Jacques Hiblot err = mmc_read_and_compare_ext_csd(mmc);
20317382e691SJean-Jacques Hiblot if (!err)
20323862b854SJean-Jacques Hiblot return 0;
20333862b854SJean-Jacques Hiblot error:
2034bc1e3272SJean-Jacques Hiblot mmc_set_signal_voltage(mmc, old_voltage);
20353862b854SJean-Jacques Hiblot /* if an error occured, revert to a safer bus mode */
20363862b854SJean-Jacques Hiblot mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
20373862b854SJean-Jacques Hiblot EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1);
20383862b854SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_LEGACY);
20393862b854SJean-Jacques Hiblot mmc_set_bus_width(mmc, 1);
20403862b854SJean-Jacques Hiblot }
20418ac8a263SJean-Jacques Hiblot }
20428ac8a263SJean-Jacques Hiblot
2043d8e3d420SJean-Jacques Hiblot pr_err("unable to select a mode\n");
20448ac8a263SJean-Jacques Hiblot
20453862b854SJean-Jacques Hiblot return -ENOTSUPP;
20468ac8a263SJean-Jacques Hiblot }
204762d77ceaSMarek Vasut #endif
204862d77ceaSMarek Vasut
204962d77ceaSMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY)
205062d77ceaSMarek Vasut DEFINE_CACHE_ALIGN_BUFFER(u8, ext_csd_bkup, MMC_MAX_BLOCK_LEN);
205162d77ceaSMarek Vasut #endif
20528ac8a263SJean-Jacques Hiblot
mmc_startup_v4(struct mmc * mmc)2053dfda9d88SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc)
2054c744b6f6SJean-Jacques Hiblot {
2055c744b6f6SJean-Jacques Hiblot int err, i;
2056c744b6f6SJean-Jacques Hiblot u64 capacity;
2057c744b6f6SJean-Jacques Hiblot bool has_parts = false;
2058c744b6f6SJean-Jacques Hiblot bool part_completed;
205958a6fb7bSJean-Jacques Hiblot static const u32 mmc_versions[] = {
206058a6fb7bSJean-Jacques Hiblot MMC_VERSION_4,
206158a6fb7bSJean-Jacques Hiblot MMC_VERSION_4_1,
206258a6fb7bSJean-Jacques Hiblot MMC_VERSION_4_2,
206358a6fb7bSJean-Jacques Hiblot MMC_VERSION_4_3,
2064ace1bed3SJean-Jacques Hiblot MMC_VERSION_4_4,
206558a6fb7bSJean-Jacques Hiblot MMC_VERSION_4_41,
206658a6fb7bSJean-Jacques Hiblot MMC_VERSION_4_5,
206758a6fb7bSJean-Jacques Hiblot MMC_VERSION_5_0,
206858a6fb7bSJean-Jacques Hiblot MMC_VERSION_5_1
206958a6fb7bSJean-Jacques Hiblot };
207058a6fb7bSJean-Jacques Hiblot
207162d77ceaSMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY)
207262d77ceaSMarek Vasut u8 *ext_csd = ext_csd_bkup;
207362d77ceaSMarek Vasut
207462d77ceaSMarek Vasut if (IS_SD(mmc) || mmc->version < MMC_VERSION_4)
207562d77ceaSMarek Vasut return 0;
207662d77ceaSMarek Vasut
207762d77ceaSMarek Vasut if (!mmc->ext_csd)
207862d77ceaSMarek Vasut memset(ext_csd_bkup, 0, sizeof(ext_csd_bkup));
207962d77ceaSMarek Vasut
208062d77ceaSMarek Vasut err = mmc_send_ext_csd(mmc, ext_csd);
208162d77ceaSMarek Vasut if (err)
208262d77ceaSMarek Vasut goto error;
208362d77ceaSMarek Vasut
208462d77ceaSMarek Vasut /* store the ext csd for future reference */
208562d77ceaSMarek Vasut if (!mmc->ext_csd)
208662d77ceaSMarek Vasut mmc->ext_csd = ext_csd;
208762d77ceaSMarek Vasut #else
2088f7d5dffcSJean-Jacques Hiblot ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
2089c744b6f6SJean-Jacques Hiblot
2090c744b6f6SJean-Jacques Hiblot if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4))
2091c744b6f6SJean-Jacques Hiblot return 0;
2092c744b6f6SJean-Jacques Hiblot
2093c744b6f6SJean-Jacques Hiblot /* check ext_csd version and capacity */
2094c744b6f6SJean-Jacques Hiblot err = mmc_send_ext_csd(mmc, ext_csd);
2095c744b6f6SJean-Jacques Hiblot if (err)
2096f7d5dffcSJean-Jacques Hiblot goto error;
2097f7d5dffcSJean-Jacques Hiblot
2098f7d5dffcSJean-Jacques Hiblot /* store the ext csd for future reference */
2099f7d5dffcSJean-Jacques Hiblot if (!mmc->ext_csd)
2100f7d5dffcSJean-Jacques Hiblot mmc->ext_csd = malloc(MMC_MAX_BLOCK_LEN);
2101f7d5dffcSJean-Jacques Hiblot if (!mmc->ext_csd)
2102f7d5dffcSJean-Jacques Hiblot return -ENOMEM;
2103f7d5dffcSJean-Jacques Hiblot memcpy(mmc->ext_csd, ext_csd, MMC_MAX_BLOCK_LEN);
210462d77ceaSMarek Vasut #endif
210576584e33SAlexander Kochetkov if (ext_csd[EXT_CSD_REV] >= ARRAY_SIZE(mmc_versions))
210658a6fb7bSJean-Jacques Hiblot return -EINVAL;
210758a6fb7bSJean-Jacques Hiblot
210858a6fb7bSJean-Jacques Hiblot mmc->version = mmc_versions[ext_csd[EXT_CSD_REV]];
210958a6fb7bSJean-Jacques Hiblot
211058a6fb7bSJean-Jacques Hiblot if (mmc->version >= MMC_VERSION_4_2) {
2111c744b6f6SJean-Jacques Hiblot /*
2112c744b6f6SJean-Jacques Hiblot * According to the JEDEC Standard, the value of
2113c744b6f6SJean-Jacques Hiblot * ext_csd's capacity is valid if the value is more
2114c744b6f6SJean-Jacques Hiblot * than 2GB
2115c744b6f6SJean-Jacques Hiblot */
2116c744b6f6SJean-Jacques Hiblot capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
2117c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 1] << 8
2118c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 2] << 16
2119c744b6f6SJean-Jacques Hiblot | ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
2120c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN;
2121c744b6f6SJean-Jacques Hiblot if ((capacity >> 20) > 2 * 1024)
2122c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity;
2123c744b6f6SJean-Jacques Hiblot }
2124c744b6f6SJean-Jacques Hiblot
2125c744b6f6SJean-Jacques Hiblot /* The partition data may be non-zero but it is only
2126c744b6f6SJean-Jacques Hiblot * effective if PARTITION_SETTING_COMPLETED is set in
2127c744b6f6SJean-Jacques Hiblot * EXT_CSD, so ignore any data if this bit is not set,
2128c744b6f6SJean-Jacques Hiblot * except for enabling the high-capacity group size
2129c744b6f6SJean-Jacques Hiblot * definition (see below).
2130c744b6f6SJean-Jacques Hiblot */
2131c744b6f6SJean-Jacques Hiblot part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
2132c744b6f6SJean-Jacques Hiblot EXT_CSD_PARTITION_SETTING_COMPLETED);
2133c744b6f6SJean-Jacques Hiblot
2134c744b6f6SJean-Jacques Hiblot /* store the partition info of emmc */
2135c744b6f6SJean-Jacques Hiblot mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
2136c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
2137c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_BOOT_MULT])
2138c744b6f6SJean-Jacques Hiblot mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
2139c744b6f6SJean-Jacques Hiblot if (part_completed &&
2140c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
2141c744b6f6SJean-Jacques Hiblot mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
2142c744b6f6SJean-Jacques Hiblot
2143c744b6f6SJean-Jacques Hiblot mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
2144c744b6f6SJean-Jacques Hiblot
2145c744b6f6SJean-Jacques Hiblot mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
2146c744b6f6SJean-Jacques Hiblot
2147c744b6f6SJean-Jacques Hiblot for (i = 0; i < 4; i++) {
2148c744b6f6SJean-Jacques Hiblot int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
2149c744b6f6SJean-Jacques Hiblot uint mult = (ext_csd[idx + 2] << 16) +
2150c744b6f6SJean-Jacques Hiblot (ext_csd[idx + 1] << 8) + ext_csd[idx];
2151c744b6f6SJean-Jacques Hiblot if (mult)
2152c744b6f6SJean-Jacques Hiblot has_parts = true;
2153c744b6f6SJean-Jacques Hiblot if (!part_completed)
2154c744b6f6SJean-Jacques Hiblot continue;
2155c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] = mult;
2156c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *=
2157c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
2158c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
2159c744b6f6SJean-Jacques Hiblot mmc->capacity_gp[i] <<= 19;
2160c744b6f6SJean-Jacques Hiblot }
2161c744b6f6SJean-Jacques Hiblot
2162173c06dfSJean-Jacques Hiblot #ifndef CONFIG_SPL_BUILD
2163c744b6f6SJean-Jacques Hiblot if (part_completed) {
2164c744b6f6SJean-Jacques Hiblot mmc->enh_user_size =
2165c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) +
2166c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) +
2167c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_SIZE_MULT];
2168c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
2169c744b6f6SJean-Jacques Hiblot mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
2170c744b6f6SJean-Jacques Hiblot mmc->enh_user_size <<= 19;
2171c744b6f6SJean-Jacques Hiblot mmc->enh_user_start =
2172c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) +
2173c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) +
2174c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) +
2175c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ENH_START_ADDR];
2176c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity)
2177c744b6f6SJean-Jacques Hiblot mmc->enh_user_start <<= 9;
2178c744b6f6SJean-Jacques Hiblot }
2179173c06dfSJean-Jacques Hiblot #endif
2180c744b6f6SJean-Jacques Hiblot
2181c744b6f6SJean-Jacques Hiblot /*
2182c744b6f6SJean-Jacques Hiblot * Host needs to enable ERASE_GRP_DEF bit if device is
2183c744b6f6SJean-Jacques Hiblot * partitioned. This bit will be lost every time after a reset
2184c744b6f6SJean-Jacques Hiblot * or power off. This will affect erase size.
2185c744b6f6SJean-Jacques Hiblot */
2186c744b6f6SJean-Jacques Hiblot if (part_completed)
2187c744b6f6SJean-Jacques Hiblot has_parts = true;
2188c744b6f6SJean-Jacques Hiblot if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
2189c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
2190c744b6f6SJean-Jacques Hiblot has_parts = true;
2191c744b6f6SJean-Jacques Hiblot if (has_parts) {
2192c744b6f6SJean-Jacques Hiblot err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
2193c744b6f6SJean-Jacques Hiblot EXT_CSD_ERASE_GROUP_DEF, 1);
2194c744b6f6SJean-Jacques Hiblot
2195c744b6f6SJean-Jacques Hiblot if (err)
2196f7d5dffcSJean-Jacques Hiblot goto error;
2197c744b6f6SJean-Jacques Hiblot
2198c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
2199c744b6f6SJean-Jacques Hiblot }
2200c744b6f6SJean-Jacques Hiblot
2201c744b6f6SJean-Jacques Hiblot if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
2202e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE)
2203c744b6f6SJean-Jacques Hiblot /* Read out group size from ext_csd */
2204c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size =
2205c744b6f6SJean-Jacques Hiblot ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
2206e6fa5a54SJean-Jacques Hiblot #endif
2207c744b6f6SJean-Jacques Hiblot /*
2208c744b6f6SJean-Jacques Hiblot * if high capacity and partition setting completed
2209c744b6f6SJean-Jacques Hiblot * SEC_COUNT is valid even if it is smaller than 2 GiB
2210c744b6f6SJean-Jacques Hiblot * JEDEC Standard JESD84-B45, 6.2.4
2211c744b6f6SJean-Jacques Hiblot */
2212c744b6f6SJean-Jacques Hiblot if (mmc->high_capacity && part_completed) {
2213c744b6f6SJean-Jacques Hiblot capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
2214c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
2215c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
2216c744b6f6SJean-Jacques Hiblot (ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
2217c744b6f6SJean-Jacques Hiblot capacity *= MMC_MAX_BLOCK_LEN;
2218c744b6f6SJean-Jacques Hiblot mmc->capacity_user = capacity;
2219c744b6f6SJean-Jacques Hiblot }
2220e6fa5a54SJean-Jacques Hiblot }
2221e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE)
2222e6fa5a54SJean-Jacques Hiblot else {
2223c744b6f6SJean-Jacques Hiblot /* Calculate the group size from the csd value. */
2224c744b6f6SJean-Jacques Hiblot int erase_gsz, erase_gmul;
2225c744b6f6SJean-Jacques Hiblot
2226c744b6f6SJean-Jacques Hiblot erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
2227c744b6f6SJean-Jacques Hiblot erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
2228c744b6f6SJean-Jacques Hiblot mmc->erase_grp_size = (erase_gsz + 1)
2229c744b6f6SJean-Jacques Hiblot * (erase_gmul + 1);
2230c744b6f6SJean-Jacques Hiblot }
2231e6fa5a54SJean-Jacques Hiblot #endif
2232b7a6e2c9SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING)
2233c744b6f6SJean-Jacques Hiblot mmc->hc_wp_grp_size = 1024
2234c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
2235c744b6f6SJean-Jacques Hiblot * ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
2236b7a6e2c9SJean-Jacques Hiblot #endif
2237c744b6f6SJean-Jacques Hiblot
2238c744b6f6SJean-Jacques Hiblot mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
2239c744b6f6SJean-Jacques Hiblot
2240c744b6f6SJean-Jacques Hiblot return 0;
2241f7d5dffcSJean-Jacques Hiblot error:
2242f7d5dffcSJean-Jacques Hiblot if (mmc->ext_csd) {
224362d77ceaSMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY)
2244f7d5dffcSJean-Jacques Hiblot free(mmc->ext_csd);
224562d77ceaSMarek Vasut #endif
2246f7d5dffcSJean-Jacques Hiblot mmc->ext_csd = NULL;
2247f7d5dffcSJean-Jacques Hiblot }
2248f7d5dffcSJean-Jacques Hiblot return err;
2249c744b6f6SJean-Jacques Hiblot }
2250c744b6f6SJean-Jacques Hiblot
mmc_startup(struct mmc * mmc)2251fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc)
2252272cc70bSAndy Fleming {
2253f866a46dSStephen Warren int err, i;
2254272cc70bSAndy Fleming uint mult, freq;
2255c744b6f6SJean-Jacques Hiblot u64 cmult, csize;
2256272cc70bSAndy Fleming struct mmc_cmd cmd;
2257c40fdca6SSimon Glass struct blk_desc *bdesc;
2258272cc70bSAndy Fleming
2259d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
2260d52ebf10SThomas Chou if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
2261d52ebf10SThomas Chou cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
2262d52ebf10SThomas Chou cmd.resp_type = MMC_RSP_R1;
2263d52ebf10SThomas Chou cmd.cmdarg = 1;
2264d52ebf10SThomas Chou err = mmc_send_cmd(mmc, &cmd, NULL);
2265d52ebf10SThomas Chou if (err)
2266d52ebf10SThomas Chou return err;
2267d52ebf10SThomas Chou }
2268d52ebf10SThomas Chou #endif
2269d52ebf10SThomas Chou
2270272cc70bSAndy Fleming /* Put the Card in Identify Mode */
2271d52ebf10SThomas Chou cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
2272d52ebf10SThomas Chou MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
2273272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2;
2274272cc70bSAndy Fleming cmd.cmdarg = 0;
2275272cc70bSAndy Fleming
2276272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL);
2277272cc70bSAndy Fleming
227883dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS
227983dc4227SKishon Vijay Abraham I if (err && (mmc->quirks & MMC_QUIRK_RETRY_SEND_CID)) {
228083dc4227SKishon Vijay Abraham I int retries = 4;
228183dc4227SKishon Vijay Abraham I /*
228283dc4227SKishon Vijay Abraham I * It has been seen that SEND_CID may fail on the first
228383dc4227SKishon Vijay Abraham I * attempt, let's try a few more time
228483dc4227SKishon Vijay Abraham I */
228583dc4227SKishon Vijay Abraham I do {
228683dc4227SKishon Vijay Abraham I err = mmc_send_cmd(mmc, &cmd, NULL);
228783dc4227SKishon Vijay Abraham I if (!err)
228883dc4227SKishon Vijay Abraham I break;
228983dc4227SKishon Vijay Abraham I } while (retries--);
229083dc4227SKishon Vijay Abraham I }
229183dc4227SKishon Vijay Abraham I #endif
229283dc4227SKishon Vijay Abraham I
2293272cc70bSAndy Fleming if (err)
2294272cc70bSAndy Fleming return err;
2295272cc70bSAndy Fleming
2296272cc70bSAndy Fleming memcpy(mmc->cid, cmd.response, 16);
2297272cc70bSAndy Fleming
2298272cc70bSAndy Fleming /*
2299272cc70bSAndy Fleming * For MMC cards, set the Relative Address.
2300272cc70bSAndy Fleming * For SD cards, get the Relatvie Address.
2301272cc70bSAndy Fleming * This also puts the cards into Standby State
2302272cc70bSAndy Fleming */
2303d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
2304272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
2305272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16;
2306272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R6;
2307272cc70bSAndy Fleming
2308272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL);
2309272cc70bSAndy Fleming
2310272cc70bSAndy Fleming if (err)
2311272cc70bSAndy Fleming return err;
2312272cc70bSAndy Fleming
2313272cc70bSAndy Fleming if (IS_SD(mmc))
2314998be3ddSRabin Vincent mmc->rca = (cmd.response[0] >> 16) & 0xffff;
2315d52ebf10SThomas Chou }
2316272cc70bSAndy Fleming
2317272cc70bSAndy Fleming /* Get the Card-Specific Data */
2318272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SEND_CSD;
2319272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R2;
2320272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16;
2321272cc70bSAndy Fleming
2322272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL);
2323272cc70bSAndy Fleming
2324272cc70bSAndy Fleming if (err)
2325272cc70bSAndy Fleming return err;
2326272cc70bSAndy Fleming
2327998be3ddSRabin Vincent mmc->csd[0] = cmd.response[0];
2328998be3ddSRabin Vincent mmc->csd[1] = cmd.response[1];
2329998be3ddSRabin Vincent mmc->csd[2] = cmd.response[2];
2330998be3ddSRabin Vincent mmc->csd[3] = cmd.response[3];
2331272cc70bSAndy Fleming
2332272cc70bSAndy Fleming if (mmc->version == MMC_VERSION_UNKNOWN) {
23330b453ffeSRabin Vincent int version = (cmd.response[0] >> 26) & 0xf;
2334272cc70bSAndy Fleming
2335272cc70bSAndy Fleming switch (version) {
2336272cc70bSAndy Fleming case 0:
2337272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2;
2338272cc70bSAndy Fleming break;
2339272cc70bSAndy Fleming case 1:
2340272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_4;
2341272cc70bSAndy Fleming break;
2342272cc70bSAndy Fleming case 2:
2343272cc70bSAndy Fleming mmc->version = MMC_VERSION_2_2;
2344272cc70bSAndy Fleming break;
2345272cc70bSAndy Fleming case 3:
2346272cc70bSAndy Fleming mmc->version = MMC_VERSION_3;
2347272cc70bSAndy Fleming break;
2348272cc70bSAndy Fleming case 4:
2349272cc70bSAndy Fleming mmc->version = MMC_VERSION_4;
2350272cc70bSAndy Fleming break;
2351272cc70bSAndy Fleming default:
2352272cc70bSAndy Fleming mmc->version = MMC_VERSION_1_2;
2353272cc70bSAndy Fleming break;
2354272cc70bSAndy Fleming }
2355272cc70bSAndy Fleming }
2356272cc70bSAndy Fleming
2357272cc70bSAndy Fleming /* divide frequency by 10, since the mults are 10x bigger */
23580b453ffeSRabin Vincent freq = fbase[(cmd.response[0] & 0x7)];
23590b453ffeSRabin Vincent mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
2360272cc70bSAndy Fleming
236135f9e196SJean-Jacques Hiblot mmc->legacy_speed = freq * mult;
236235f9e196SJean-Jacques Hiblot mmc_select_mode(mmc, MMC_LEGACY);
2363272cc70bSAndy Fleming
2364ab71188cSMarkus Niebel mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
2365998be3ddSRabin Vincent mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
2366e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE)
2367272cc70bSAndy Fleming
2368272cc70bSAndy Fleming if (IS_SD(mmc))
2369272cc70bSAndy Fleming mmc->write_bl_len = mmc->read_bl_len;
2370272cc70bSAndy Fleming else
2371998be3ddSRabin Vincent mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
2372e6fa5a54SJean-Jacques Hiblot #endif
2373272cc70bSAndy Fleming
2374272cc70bSAndy Fleming if (mmc->high_capacity) {
2375272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3f) << 16
2376272cc70bSAndy Fleming | (mmc->csd[2] & 0xffff0000) >> 16;
2377272cc70bSAndy Fleming cmult = 8;
2378272cc70bSAndy Fleming } else {
2379272cc70bSAndy Fleming csize = (mmc->csd[1] & 0x3ff) << 2
2380272cc70bSAndy Fleming | (mmc->csd[2] & 0xc0000000) >> 30;
2381272cc70bSAndy Fleming cmult = (mmc->csd[2] & 0x00038000) >> 15;
2382272cc70bSAndy Fleming }
2383272cc70bSAndy Fleming
2384f866a46dSStephen Warren mmc->capacity_user = (csize + 1) << (cmult + 2);
2385f866a46dSStephen Warren mmc->capacity_user *= mmc->read_bl_len;
2386f866a46dSStephen Warren mmc->capacity_boot = 0;
2387f866a46dSStephen Warren mmc->capacity_rpmb = 0;
2388f866a46dSStephen Warren for (i = 0; i < 4; i++)
2389f866a46dSStephen Warren mmc->capacity_gp[i] = 0;
2390272cc70bSAndy Fleming
23918bfa195eSSimon Glass if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
23928bfa195eSSimon Glass mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
2393272cc70bSAndy Fleming
2394e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE)
23958bfa195eSSimon Glass if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
23968bfa195eSSimon Glass mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
2397e6fa5a54SJean-Jacques Hiblot #endif
2398272cc70bSAndy Fleming
2399ab71188cSMarkus Niebel if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
2400ab71188cSMarkus Niebel cmd.cmdidx = MMC_CMD_SET_DSR;
2401ab71188cSMarkus Niebel cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
2402ab71188cSMarkus Niebel cmd.resp_type = MMC_RSP_NONE;
2403ab71188cSMarkus Niebel if (mmc_send_cmd(mmc, &cmd, NULL))
2404d8e3d420SJean-Jacques Hiblot pr_warn("MMC: SET_DSR failed\n");
2405ab71188cSMarkus Niebel }
2406ab71188cSMarkus Niebel
2407272cc70bSAndy Fleming /* Select the card, and put it into Transfer Mode */
2408d52ebf10SThomas Chou if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
2409272cc70bSAndy Fleming cmd.cmdidx = MMC_CMD_SELECT_CARD;
2410fe8f7066SAjay Bhargav cmd.resp_type = MMC_RSP_R1;
2411272cc70bSAndy Fleming cmd.cmdarg = mmc->rca << 16;
2412272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL);
2413272cc70bSAndy Fleming
2414272cc70bSAndy Fleming if (err)
2415272cc70bSAndy Fleming return err;
2416d52ebf10SThomas Chou }
2417272cc70bSAndy Fleming
2418e6f99a56SLei Wen /*
2419e6f99a56SLei Wen * For SD, its erase group is always one sector
2420e6f99a56SLei Wen */
2421e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE)
2422e6f99a56SLei Wen mmc->erase_grp_size = 1;
2423e6fa5a54SJean-Jacques Hiblot #endif
2424bc897b1dSLei Wen mmc->part_config = MMCPART_NOAVAILABLE;
2425c744b6f6SJean-Jacques Hiblot
2426dfda9d88SJean-Jacques Hiblot err = mmc_startup_v4(mmc);
24279cf199ebSDiego Santa Cruz if (err)
24289cf199ebSDiego Santa Cruz return err;
2429f866a46dSStephen Warren
2430c40fdca6SSimon Glass err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart);
2431f866a46dSStephen Warren if (err)
2432f866a46dSStephen Warren return err;
2433d23e2c09SSukumar Ghorai
243462d77ceaSMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY)
243562d77ceaSMarek Vasut mmc_set_clock(mmc, mmc->legacy_speed, false);
243662d77ceaSMarek Vasut mmc_select_mode(mmc, IS_SD(mmc) ? SD_LEGACY : MMC_LEGACY);
243762d77ceaSMarek Vasut mmc_set_bus_width(mmc, 1);
243862d77ceaSMarek Vasut #else
243901298da3SJean-Jacques Hiblot if (IS_SD(mmc)) {
244001298da3SJean-Jacques Hiblot err = sd_get_capabilities(mmc);
244101298da3SJean-Jacques Hiblot if (err)
244201298da3SJean-Jacques Hiblot return err;
244301298da3SJean-Jacques Hiblot err = sd_select_mode_and_width(mmc, mmc->card_caps);
244401298da3SJean-Jacques Hiblot } else {
244501298da3SJean-Jacques Hiblot err = mmc_get_capabilities(mmc);
244601298da3SJean-Jacques Hiblot if (err)
244701298da3SJean-Jacques Hiblot return err;
244801298da3SJean-Jacques Hiblot mmc_select_mode_and_width(mmc, mmc->card_caps);
244901298da3SJean-Jacques Hiblot }
245062d77ceaSMarek Vasut #endif
2451272cc70bSAndy Fleming if (err)
2452272cc70bSAndy Fleming return err;
2453272cc70bSAndy Fleming
245401298da3SJean-Jacques Hiblot mmc->best_mode = mmc->selected_mode;
2455272cc70bSAndy Fleming
24565af8f45cSAndrew Gabbasov /* Fix the block length for DDR mode */
24575af8f45cSAndrew Gabbasov if (mmc->ddr_mode) {
24585af8f45cSAndrew Gabbasov mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
2459e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE)
24605af8f45cSAndrew Gabbasov mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
2461e6fa5a54SJean-Jacques Hiblot #endif
24625af8f45cSAndrew Gabbasov }
24635af8f45cSAndrew Gabbasov
2464272cc70bSAndy Fleming /* fill in device description */
2465c40fdca6SSimon Glass bdesc = mmc_get_blk_desc(mmc);
2466c40fdca6SSimon Glass bdesc->lun = 0;
2467c40fdca6SSimon Glass bdesc->hwpart = 0;
2468c40fdca6SSimon Glass bdesc->type = 0;
2469c40fdca6SSimon Glass bdesc->blksz = mmc->read_bl_len;
2470c40fdca6SSimon Glass bdesc->log2blksz = LOG2(bdesc->blksz);
2471c40fdca6SSimon Glass bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len);
2472fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \
2473fc011f64SSjoerd Simons (defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \
2474fc011f64SSjoerd Simons !defined(CONFIG_USE_TINY_PRINTF))
2475c40fdca6SSimon Glass sprintf(bdesc->vendor, "Man %06x Snr %04x%04x",
2476babce5f6STaylor Hutt mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
2477babce5f6STaylor Hutt (mmc->cid[3] >> 16) & 0xffff);
2478c40fdca6SSimon Glass sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
24790b453ffeSRabin Vincent (mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
2480babce5f6STaylor Hutt (mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
2481babce5f6STaylor Hutt (mmc->cid[2] >> 24) & 0xff);
2482c40fdca6SSimon Glass sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
2483babce5f6STaylor Hutt (mmc->cid[2] >> 16) & 0xf);
248456196826SPaul Burton #else
2485c40fdca6SSimon Glass bdesc->vendor[0] = 0;
2486c40fdca6SSimon Glass bdesc->product[0] = 0;
2487c40fdca6SSimon Glass bdesc->revision[0] = 0;
248856196826SPaul Burton #endif
2489272cc70bSAndy Fleming
2490eef05fd3SAndre Przywara #if !defined(CONFIG_DM_MMC) && (!defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT))
2491eef05fd3SAndre Przywara part_init(bdesc);
2492eef05fd3SAndre Przywara #endif
2493eef05fd3SAndre Przywara
2494272cc70bSAndy Fleming return 0;
2495272cc70bSAndy Fleming }
2496272cc70bSAndy Fleming
mmc_send_if_cond(struct mmc * mmc)2497fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc)
2498272cc70bSAndy Fleming {
2499272cc70bSAndy Fleming struct mmc_cmd cmd;
2500272cc70bSAndy Fleming int err;
2501272cc70bSAndy Fleming
2502272cc70bSAndy Fleming cmd.cmdidx = SD_CMD_SEND_IF_COND;
2503272cc70bSAndy Fleming /* We set the bit if the host supports voltages between 2.7 and 3.6 V */
250493bfd616SPantelis Antoniou cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa;
2505272cc70bSAndy Fleming cmd.resp_type = MMC_RSP_R7;
2506272cc70bSAndy Fleming
2507272cc70bSAndy Fleming err = mmc_send_cmd(mmc, &cmd, NULL);
2508272cc70bSAndy Fleming
2509272cc70bSAndy Fleming if (err)
2510272cc70bSAndy Fleming return err;
2511272cc70bSAndy Fleming
2512998be3ddSRabin Vincent if ((cmd.response[0] & 0xff) != 0xaa)
2513915ffa52SJaehoon Chung return -EOPNOTSUPP;
2514272cc70bSAndy Fleming else
2515272cc70bSAndy Fleming mmc->version = SD_VERSION_2;
2516272cc70bSAndy Fleming
2517272cc70bSAndy Fleming return 0;
2518272cc70bSAndy Fleming }
2519272cc70bSAndy Fleming
2520c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
252195de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */
board_mmc_power_init(void)252295de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void)
252395de9ab2SPaul Kocialkowski {
252495de9ab2SPaul Kocialkowski }
252505cbeb7cSSimon Glass #endif
252695de9ab2SPaul Kocialkowski
mmc_power_init(struct mmc * mmc)25272051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc)
25282051aefeSPeng Fan {
2529c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
253006ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR)
25312051aefeSPeng Fan int ret;
25322051aefeSPeng Fan
25332051aefeSPeng Fan ret = device_get_supply_regulator(mmc->dev, "vmmc-supply",
253406ec045fSJean-Jacques Hiblot &mmc->vmmc_supply);
253506ec045fSJean-Jacques Hiblot if (ret)
2536d4d64889SMasahiro Yamada pr_debug("%s: No vmmc supply\n", mmc->dev->name);
25372051aefeSPeng Fan
253806ec045fSJean-Jacques Hiblot ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply",
253906ec045fSJean-Jacques Hiblot &mmc->vqmmc_supply);
254006ec045fSJean-Jacques Hiblot if (ret)
2541d4d64889SMasahiro Yamada pr_debug("%s: No vqmmc supply\n", mmc->dev->name);
25422051aefeSPeng Fan #endif
254305cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */
254405cbeb7cSSimon Glass /*
254505cbeb7cSSimon Glass * Driver model should use a regulator, as above, rather than calling
254605cbeb7cSSimon Glass * out to board code.
254705cbeb7cSSimon Glass */
254805cbeb7cSSimon Glass board_mmc_power_init();
254905cbeb7cSSimon Glass #endif
25502051aefeSPeng Fan return 0;
25512051aefeSPeng Fan }
25522051aefeSPeng Fan
2553fb7c3bebSKishon Vijay Abraham I /*
2554fb7c3bebSKishon Vijay Abraham I * put the host in the initial state:
2555fb7c3bebSKishon Vijay Abraham I * - turn on Vdd (card power supply)
2556fb7c3bebSKishon Vijay Abraham I * - configure the bus width and clock to minimal values
2557fb7c3bebSKishon Vijay Abraham I */
mmc_set_initial_state(struct mmc * mmc)2558fb7c3bebSKishon Vijay Abraham I static void mmc_set_initial_state(struct mmc *mmc)
2559fb7c3bebSKishon Vijay Abraham I {
2560fb7c3bebSKishon Vijay Abraham I int err;
2561fb7c3bebSKishon Vijay Abraham I
2562fb7c3bebSKishon Vijay Abraham I /* First try to set 3.3V. If it fails set to 1.8V */
2563fb7c3bebSKishon Vijay Abraham I err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_330);
2564fb7c3bebSKishon Vijay Abraham I if (err != 0)
2565fb7c3bebSKishon Vijay Abraham I err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_180);
2566fb7c3bebSKishon Vijay Abraham I if (err != 0)
2567d8e3d420SJean-Jacques Hiblot pr_warn("mmc: failed to set signal voltage\n");
2568fb7c3bebSKishon Vijay Abraham I
2569fb7c3bebSKishon Vijay Abraham I mmc_select_mode(mmc, MMC_LEGACY);
2570fb7c3bebSKishon Vijay Abraham I mmc_set_bus_width(mmc, 1);
257165117182SJaehoon Chung mmc_set_clock(mmc, 0, MMC_CLK_ENABLE);
2572fb7c3bebSKishon Vijay Abraham I }
2573fb7c3bebSKishon Vijay Abraham I
mmc_power_on(struct mmc * mmc)2574fb7c3bebSKishon Vijay Abraham I static int mmc_power_on(struct mmc *mmc)
2575fb7c3bebSKishon Vijay Abraham I {
2576fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR)
2577fb7c3bebSKishon Vijay Abraham I if (mmc->vmmc_supply) {
2578fb7c3bebSKishon Vijay Abraham I int ret = regulator_set_enable(mmc->vmmc_supply, true);
2579fb7c3bebSKishon Vijay Abraham I
2580fb7c3bebSKishon Vijay Abraham I if (ret) {
2581fb7c3bebSKishon Vijay Abraham I puts("Error enabling VMMC supply\n");
2582fb7c3bebSKishon Vijay Abraham I return ret;
2583fb7c3bebSKishon Vijay Abraham I }
2584fb7c3bebSKishon Vijay Abraham I }
2585fb7c3bebSKishon Vijay Abraham I #endif
2586fb7c3bebSKishon Vijay Abraham I return 0;
2587fb7c3bebSKishon Vijay Abraham I }
2588fb7c3bebSKishon Vijay Abraham I
mmc_power_off(struct mmc * mmc)2589fb7c3bebSKishon Vijay Abraham I static int mmc_power_off(struct mmc *mmc)
2590fb7c3bebSKishon Vijay Abraham I {
259165117182SJaehoon Chung mmc_set_clock(mmc, 0, MMC_CLK_DISABLE);
2592fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR)
2593fb7c3bebSKishon Vijay Abraham I if (mmc->vmmc_supply) {
2594fb7c3bebSKishon Vijay Abraham I int ret = regulator_set_enable(mmc->vmmc_supply, false);
2595fb7c3bebSKishon Vijay Abraham I
2596fb7c3bebSKishon Vijay Abraham I if (ret) {
2597d4d64889SMasahiro Yamada pr_debug("Error disabling VMMC supply\n");
2598fb7c3bebSKishon Vijay Abraham I return ret;
2599fb7c3bebSKishon Vijay Abraham I }
2600fb7c3bebSKishon Vijay Abraham I }
2601fb7c3bebSKishon Vijay Abraham I #endif
2602fb7c3bebSKishon Vijay Abraham I return 0;
2603fb7c3bebSKishon Vijay Abraham I }
2604fb7c3bebSKishon Vijay Abraham I
mmc_power_cycle(struct mmc * mmc)2605fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc)
2606fb7c3bebSKishon Vijay Abraham I {
2607fb7c3bebSKishon Vijay Abraham I int ret;
2608fb7c3bebSKishon Vijay Abraham I
2609fb7c3bebSKishon Vijay Abraham I ret = mmc_power_off(mmc);
2610fb7c3bebSKishon Vijay Abraham I if (ret)
2611fb7c3bebSKishon Vijay Abraham I return ret;
2612fb7c3bebSKishon Vijay Abraham I /*
2613fb7c3bebSKishon Vijay Abraham I * SD spec recommends at least 1ms of delay. Let's wait for 2ms
2614fb7c3bebSKishon Vijay Abraham I * to be on the safer side.
2615fb7c3bebSKishon Vijay Abraham I */
2616fb7c3bebSKishon Vijay Abraham I udelay(2000);
2617fb7c3bebSKishon Vijay Abraham I return mmc_power_on(mmc);
2618fb7c3bebSKishon Vijay Abraham I }
2619fb7c3bebSKishon Vijay Abraham I
mmc_get_op_cond(struct mmc * mmc)26206c09eba5SJon Nettleton int mmc_get_op_cond(struct mmc *mmc)
2621272cc70bSAndy Fleming {
2622c10b85d6SJean-Jacques Hiblot bool uhs_en = supports_uhs(mmc->cfg->host_caps);
2623afd5932bSMacpaul Lin int err;
2624272cc70bSAndy Fleming
2625bc897b1dSLei Wen if (mmc->has_init)
2626bc897b1dSLei Wen return 0;
2627bc897b1dSLei Wen
26285a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
26295a8dbdc6SYangbo Lu mmc_adapter_card_type_ident();
26305a8dbdc6SYangbo Lu #endif
26312051aefeSPeng Fan err = mmc_power_init(mmc);
26322051aefeSPeng Fan if (err)
26332051aefeSPeng Fan return err;
263495de9ab2SPaul Kocialkowski
263583dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS
263683dc4227SKishon Vijay Abraham I mmc->quirks = MMC_QUIRK_RETRY_SET_BLOCKLEN |
263783dc4227SKishon Vijay Abraham I MMC_QUIRK_RETRY_SEND_CID;
263883dc4227SKishon Vijay Abraham I #endif
263983dc4227SKishon Vijay Abraham I
264004a2ea24SJean-Jacques Hiblot err = mmc_power_cycle(mmc);
264104a2ea24SJean-Jacques Hiblot if (err) {
264204a2ea24SJean-Jacques Hiblot /*
264304a2ea24SJean-Jacques Hiblot * if power cycling is not supported, we should not try
264404a2ea24SJean-Jacques Hiblot * to use the UHS modes, because we wouldn't be able to
264504a2ea24SJean-Jacques Hiblot * recover from an error during the UHS initialization.
264604a2ea24SJean-Jacques Hiblot */
2647d4d64889SMasahiro Yamada pr_debug("Unable to do a full power cycle. Disabling the UHS modes for safety\n");
264804a2ea24SJean-Jacques Hiblot uhs_en = false;
264904a2ea24SJean-Jacques Hiblot mmc->host_caps &= ~UHS_CAPS;
2650fb7c3bebSKishon Vijay Abraham I err = mmc_power_on(mmc);
265104a2ea24SJean-Jacques Hiblot }
2652fb7c3bebSKishon Vijay Abraham I if (err)
2653fb7c3bebSKishon Vijay Abraham I return err;
2654fb7c3bebSKishon Vijay Abraham I
2655e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
26568ca51e51SSimon Glass /* The device has already been probed ready for use */
26578ca51e51SSimon Glass #else
2658ab769f22SPantelis Antoniou /* made sure it's not NULL earlier */
265993bfd616SPantelis Antoniou err = mmc->cfg->ops->init(mmc);
2660272cc70bSAndy Fleming if (err)
2661272cc70bSAndy Fleming return err;
26628ca51e51SSimon Glass #endif
2663786e8f81SAndrew Gabbasov mmc->ddr_mode = 0;
2664aff5d3c8SKishon Vijay Abraham I
2665c10b85d6SJean-Jacques Hiblot retry:
2666fb7c3bebSKishon Vijay Abraham I mmc_set_initial_state(mmc);
2667318a7a57SJean-Jacques Hiblot mmc_send_init_stream(mmc);
2668318a7a57SJean-Jacques Hiblot
2669272cc70bSAndy Fleming /* Reset the Card */
2670272cc70bSAndy Fleming err = mmc_go_idle(mmc);
2671272cc70bSAndy Fleming
2672272cc70bSAndy Fleming if (err)
2673272cc70bSAndy Fleming return err;
2674272cc70bSAndy Fleming
2675bc897b1dSLei Wen /* The internal partition reset to user partition(0) at every CMD0*/
2676c40fdca6SSimon Glass mmc_get_blk_desc(mmc)->hwpart = 0;
2677bc897b1dSLei Wen
2678272cc70bSAndy Fleming /* Test for SD version 2 */
2679272cc70bSAndy Fleming err = mmc_send_if_cond(mmc);
2680272cc70bSAndy Fleming
2681272cc70bSAndy Fleming /* Now try to get the SD card's operating condition */
2682c10b85d6SJean-Jacques Hiblot err = sd_send_op_cond(mmc, uhs_en);
2683c10b85d6SJean-Jacques Hiblot if (err && uhs_en) {
2684c10b85d6SJean-Jacques Hiblot uhs_en = false;
2685c10b85d6SJean-Jacques Hiblot mmc_power_cycle(mmc);
2686c10b85d6SJean-Jacques Hiblot goto retry;
2687c10b85d6SJean-Jacques Hiblot }
2688272cc70bSAndy Fleming
2689272cc70bSAndy Fleming /* If the command timed out, we check for an MMC card */
2690915ffa52SJaehoon Chung if (err == -ETIMEDOUT) {
2691272cc70bSAndy Fleming err = mmc_send_op_cond(mmc);
2692272cc70bSAndy Fleming
2693bd47c135SAndrew Gabbasov if (err) {
269456196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2695d8e3d420SJean-Jacques Hiblot pr_err("Card did not respond to voltage select!\n");
269656196826SPaul Burton #endif
2697915ffa52SJaehoon Chung return -EOPNOTSUPP;
2698272cc70bSAndy Fleming }
2699272cc70bSAndy Fleming }
2700272cc70bSAndy Fleming
27016c09eba5SJon Nettleton return err;
27026c09eba5SJon Nettleton }
27036c09eba5SJon Nettleton
mmc_start_init(struct mmc * mmc)27046c09eba5SJon Nettleton int mmc_start_init(struct mmc *mmc)
27056c09eba5SJon Nettleton {
27066c09eba5SJon Nettleton bool no_card;
27076c09eba5SJon Nettleton int err = 0;
27086c09eba5SJon Nettleton
27096c09eba5SJon Nettleton /*
27106c09eba5SJon Nettleton * all hosts are capable of 1 bit bus-width and able to use the legacy
27116c09eba5SJon Nettleton * timings.
27126c09eba5SJon Nettleton */
27136c09eba5SJon Nettleton mmc->host_caps = mmc->cfg->host_caps | MMC_CAP(SD_LEGACY) |
27146c09eba5SJon Nettleton MMC_CAP(MMC_LEGACY) | MMC_MODE_1BIT;
27156c09eba5SJon Nettleton
27166c09eba5SJon Nettleton #if !defined(CONFIG_MMC_BROKEN_CD)
27176c09eba5SJon Nettleton /* we pretend there's no card when init is NULL */
27186c09eba5SJon Nettleton no_card = mmc_getcd(mmc) == 0;
27196c09eba5SJon Nettleton #else
27206c09eba5SJon Nettleton no_card = 0;
27216c09eba5SJon Nettleton #endif
27226c09eba5SJon Nettleton #if !CONFIG_IS_ENABLED(DM_MMC)
27236c09eba5SJon Nettleton no_card = no_card || (mmc->cfg->ops->init == NULL);
27246c09eba5SJon Nettleton #endif
27256c09eba5SJon Nettleton if (no_card) {
27266c09eba5SJon Nettleton mmc->has_init = 0;
27276c09eba5SJon Nettleton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
27286c09eba5SJon Nettleton pr_err("MMC: no card present\n");
27296c09eba5SJon Nettleton #endif
27306c09eba5SJon Nettleton return -ENOMEDIUM;
27316c09eba5SJon Nettleton }
27326c09eba5SJon Nettleton
27336c09eba5SJon Nettleton err = mmc_get_op_cond(mmc);
27346c09eba5SJon Nettleton
2735bd47c135SAndrew Gabbasov if (!err)
2736e9550449SChe-Liang Chiou mmc->init_in_progress = 1;
2737e9550449SChe-Liang Chiou
2738e9550449SChe-Liang Chiou return err;
2739e9550449SChe-Liang Chiou }
2740e9550449SChe-Liang Chiou
mmc_complete_init(struct mmc * mmc)2741e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc)
2742e9550449SChe-Liang Chiou {
2743e9550449SChe-Liang Chiou int err = 0;
2744e9550449SChe-Liang Chiou
2745bd47c135SAndrew Gabbasov mmc->init_in_progress = 0;
2746e9550449SChe-Liang Chiou if (mmc->op_cond_pending)
2747e9550449SChe-Liang Chiou err = mmc_complete_op_cond(mmc);
2748e9550449SChe-Liang Chiou
2749e9550449SChe-Liang Chiou if (!err)
2750bc897b1dSLei Wen err = mmc_startup(mmc);
2751bc897b1dSLei Wen if (err)
2752bc897b1dSLei Wen mmc->has_init = 0;
2753bc897b1dSLei Wen else
2754bc897b1dSLei Wen mmc->has_init = 1;
2755e9550449SChe-Liang Chiou return err;
2756e9550449SChe-Liang Chiou }
2757e9550449SChe-Liang Chiou
mmc_init(struct mmc * mmc)2758e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc)
2759e9550449SChe-Liang Chiou {
2760bd47c135SAndrew Gabbasov int err = 0;
276136332b6eSVipul Kumar __maybe_unused ulong start;
2762c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
276333fb211dSSimon Glass struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev);
2764e9550449SChe-Liang Chiou
276533fb211dSSimon Glass upriv->mmc = mmc;
276633fb211dSSimon Glass #endif
2767e9550449SChe-Liang Chiou if (mmc->has_init)
2768e9550449SChe-Liang Chiou return 0;
2769d803fea5SMateusz Zalega
2770d803fea5SMateusz Zalega start = get_timer(0);
2771d803fea5SMateusz Zalega
2772e9550449SChe-Liang Chiou if (!mmc->init_in_progress)
2773e9550449SChe-Liang Chiou err = mmc_start_init(mmc);
2774e9550449SChe-Liang Chiou
2775bd47c135SAndrew Gabbasov if (!err)
2776e9550449SChe-Liang Chiou err = mmc_complete_init(mmc);
2777919b4858SJagan Teki if (err)
2778d4d64889SMasahiro Yamada pr_info("%s: %d, time %lu\n", __func__, err, get_timer(start));
2779919b4858SJagan Teki
2780bc897b1dSLei Wen return err;
2781272cc70bSAndy Fleming }
2782272cc70bSAndy Fleming
2783fceea992SMarek Vasut #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT) || \
2784fceea992SMarek Vasut CONFIG_IS_ENABLED(MMC_HS200_SUPPORT) || \
2785fceea992SMarek Vasut CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
mmc_deinit(struct mmc * mmc)2786fceea992SMarek Vasut int mmc_deinit(struct mmc *mmc)
2787fceea992SMarek Vasut {
2788fceea992SMarek Vasut u32 caps_filtered;
2789fceea992SMarek Vasut
2790fceea992SMarek Vasut if (!mmc->has_init)
2791fceea992SMarek Vasut return 0;
2792fceea992SMarek Vasut
2793fceea992SMarek Vasut if (IS_SD(mmc)) {
2794fceea992SMarek Vasut caps_filtered = mmc->card_caps &
2795fceea992SMarek Vasut ~(MMC_CAP(UHS_SDR12) | MMC_CAP(UHS_SDR25) |
2796fceea992SMarek Vasut MMC_CAP(UHS_SDR50) | MMC_CAP(UHS_DDR50) |
2797fceea992SMarek Vasut MMC_CAP(UHS_SDR104));
2798fceea992SMarek Vasut
2799fceea992SMarek Vasut return sd_select_mode_and_width(mmc, caps_filtered);
2800fceea992SMarek Vasut } else {
2801fceea992SMarek Vasut caps_filtered = mmc->card_caps &
2802fceea992SMarek Vasut ~(MMC_CAP(MMC_HS_200) | MMC_CAP(MMC_HS_400));
2803fceea992SMarek Vasut
2804fceea992SMarek Vasut return mmc_select_mode_and_width(mmc, caps_filtered);
2805fceea992SMarek Vasut }
2806fceea992SMarek Vasut }
2807fceea992SMarek Vasut #endif
2808fceea992SMarek Vasut
mmc_set_dsr(struct mmc * mmc,u16 val)2809ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val)
2810ab71188cSMarkus Niebel {
2811ab71188cSMarkus Niebel mmc->dsr = val;
2812ab71188cSMarkus Niebel return 0;
2813ab71188cSMarkus Niebel }
2814ab71188cSMarkus Niebel
2815cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */
cpu_mmc_init(bd_t * bis)2816cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis)
2817272cc70bSAndy Fleming {
2818272cc70bSAndy Fleming return -1;
2819272cc70bSAndy Fleming }
2820272cc70bSAndy Fleming
2821cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */
board_mmc_init(bd_t * bis)2822cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis)
2823cee9ab7cSJeroen Hofstee {
2824cee9ab7cSJeroen Hofstee return -1;
2825cee9ab7cSJeroen Hofstee }
2826272cc70bSAndy Fleming
mmc_set_preinit(struct mmc * mmc,int preinit)2827e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit)
2828e9550449SChe-Liang Chiou {
2829e9550449SChe-Liang Chiou mmc->preinit = preinit;
2830e9550449SChe-Liang Chiou }
2831e9550449SChe-Liang Chiou
28328a856db2SFaiz Abbas #if CONFIG_IS_ENABLED(DM_MMC)
mmc_probe(bd_t * bis)28338e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
28348e3332e2SSjoerd Simons {
28354a1db6d8SSimon Glass int ret, i;
28368e3332e2SSjoerd Simons struct uclass *uc;
28374a1db6d8SSimon Glass struct udevice *dev;
28388e3332e2SSjoerd Simons
28398e3332e2SSjoerd Simons ret = uclass_get(UCLASS_MMC, &uc);
28408e3332e2SSjoerd Simons if (ret)
28418e3332e2SSjoerd Simons return ret;
28428e3332e2SSjoerd Simons
28434a1db6d8SSimon Glass /*
28444a1db6d8SSimon Glass * Try to add them in sequence order. Really with driver model we
28454a1db6d8SSimon Glass * should allow holes, but the current MMC list does not allow that.
28464a1db6d8SSimon Glass * So if we request 0, 1, 3 we will get 0, 1, 2.
28474a1db6d8SSimon Glass */
28484a1db6d8SSimon Glass for (i = 0; ; i++) {
28494a1db6d8SSimon Glass ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev);
28504a1db6d8SSimon Glass if (ret == -ENODEV)
28514a1db6d8SSimon Glass break;
28524a1db6d8SSimon Glass }
28534a1db6d8SSimon Glass uclass_foreach_dev(dev, uc) {
28544a1db6d8SSimon Glass ret = device_probe(dev);
28558e3332e2SSjoerd Simons if (ret)
2856d8e3d420SJean-Jacques Hiblot pr_err("%s - probe failed: %d\n", dev->name, ret);
28578e3332e2SSjoerd Simons }
28588e3332e2SSjoerd Simons
28598e3332e2SSjoerd Simons return 0;
28608e3332e2SSjoerd Simons }
28618e3332e2SSjoerd Simons #else
mmc_probe(bd_t * bis)28628e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
28638e3332e2SSjoerd Simons {
28648e3332e2SSjoerd Simons if (board_mmc_init(bis) < 0)
28658e3332e2SSjoerd Simons cpu_mmc_init(bis);
28668e3332e2SSjoerd Simons
28678e3332e2SSjoerd Simons return 0;
28688e3332e2SSjoerd Simons }
28698e3332e2SSjoerd Simons #endif
2870e9550449SChe-Liang Chiou
mmc_initialize(bd_t * bis)2871272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
2872272cc70bSAndy Fleming {
28731b26bab1SDaniel Kochmański static int initialized = 0;
28748e3332e2SSjoerd Simons int ret;
28751b26bab1SDaniel Kochmański if (initialized) /* Avoid initializing mmc multiple times */
28761b26bab1SDaniel Kochmański return 0;
28771b26bab1SDaniel Kochmański initialized = 1;
28781b26bab1SDaniel Kochmański
2879c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK)
2880b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY)
2881c40fdca6SSimon Glass mmc_list_init();
2882c40fdca6SSimon Glass #endif
2883b5b838f1SMarek Vasut #endif
28848e3332e2SSjoerd Simons ret = mmc_probe(bis);
28858e3332e2SSjoerd Simons if (ret)
28868e3332e2SSjoerd Simons return ret;
2887272cc70bSAndy Fleming
2888bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD
2889272cc70bSAndy Fleming print_mmc_devices(',');
2890bb0dc108SYing Zhang #endif
2891272cc70bSAndy Fleming
2892c40fdca6SSimon Glass mmc_do_preinit();
2893272cc70bSAndy Fleming return 0;
2894272cc70bSAndy Fleming }
2895cd3d4880STomas Melin
2896cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE
mmc_set_bkops_enable(struct mmc * mmc)2897cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc)
2898cd3d4880STomas Melin {
2899cd3d4880STomas Melin int err;
2900cd3d4880STomas Melin ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
2901cd3d4880STomas Melin
2902cd3d4880STomas Melin err = mmc_send_ext_csd(mmc, ext_csd);
2903cd3d4880STomas Melin if (err) {
2904cd3d4880STomas Melin puts("Could not get ext_csd register values\n");
2905cd3d4880STomas Melin return err;
2906cd3d4880STomas Melin }
2907cd3d4880STomas Melin
2908cd3d4880STomas Melin if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) {
2909cd3d4880STomas Melin puts("Background operations not supported on device\n");
2910cd3d4880STomas Melin return -EMEDIUMTYPE;
2911cd3d4880STomas Melin }
2912cd3d4880STomas Melin
2913cd3d4880STomas Melin if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) {
2914cd3d4880STomas Melin puts("Background operations already enabled\n");
2915cd3d4880STomas Melin return 0;
2916cd3d4880STomas Melin }
2917cd3d4880STomas Melin
2918cd3d4880STomas Melin err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1);
2919cd3d4880STomas Melin if (err) {
2920cd3d4880STomas Melin puts("Failed to enable manual background operations\n");
2921cd3d4880STomas Melin return err;
2922cd3d4880STomas Melin }
2923cd3d4880STomas Melin
2924cd3d4880STomas Melin puts("Enabled manual background operations\n");
2925cd3d4880STomas Melin
2926cd3d4880STomas Melin return 0;
2927cd3d4880STomas Melin }
2928cd3d4880STomas Melin #endif
2929