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