xref: /openbmc/u-boot/drivers/mmc/mmc.c (revision eef05fd3ba68220156f33ffe6a9e68e42a6a5b53)
183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2272cc70bSAndy Fleming /*
3272cc70bSAndy Fleming  * Copyright 2008, Freescale Semiconductor, Inc
4272cc70bSAndy Fleming  * Andy Fleming
5272cc70bSAndy Fleming  *
6272cc70bSAndy Fleming  * Based vaguely on the Linux code
7272cc70bSAndy Fleming  */
8272cc70bSAndy Fleming 
9272cc70bSAndy Fleming #include <config.h>
10272cc70bSAndy Fleming #include <common.h>
11272cc70bSAndy Fleming #include <command.h>
128e3332e2SSjoerd Simons #include <dm.h>
138e3332e2SSjoerd Simons #include <dm/device-internal.h>
14d4622df3SStephen Warren #include <errno.h>
15272cc70bSAndy Fleming #include <mmc.h>
16272cc70bSAndy Fleming #include <part.h>
172051aefeSPeng Fan #include <power/regulator.h>
18272cc70bSAndy Fleming #include <malloc.h>
19cf92e05cSSimon Glass #include <memalign.h>
20272cc70bSAndy Fleming #include <linux/list.h>
219b1f942cSRabin Vincent #include <div64.h>
22da61fa5fSPaul Burton #include "mmc_private.h"
23272cc70bSAndy Fleming 
24aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage);
25fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc);
2662d77ceaSMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY)
2701298da3SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps);
28b5b838f1SMarek Vasut #endif
29b5b838f1SMarek Vasut 
30e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
31c10b85d6SJean-Jacques Hiblot 
32f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
33c10b85d6SJean-Jacques Hiblot static int mmc_wait_dat0(struct mmc *mmc, int state, int timeout)
34c10b85d6SJean-Jacques Hiblot {
35c10b85d6SJean-Jacques Hiblot 	return -ENOSYS;
36c10b85d6SJean-Jacques Hiblot }
37f99c2efeSJean-Jacques Hiblot #endif
38c10b85d6SJean-Jacques Hiblot 
39750121c3SJeroen Hofstee __weak int board_mmc_getwp(struct mmc *mmc)
40d23d8d7eSNikita Kiryanov {
41d23d8d7eSNikita Kiryanov 	return -1;
42d23d8d7eSNikita Kiryanov }
43d23d8d7eSNikita Kiryanov 
44d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc)
45d23d8d7eSNikita Kiryanov {
46d23d8d7eSNikita Kiryanov 	int wp;
47d23d8d7eSNikita Kiryanov 
48d23d8d7eSNikita Kiryanov 	wp = board_mmc_getwp(mmc);
49d23d8d7eSNikita Kiryanov 
50d4e1da4eSPeter Korsgaard 	if (wp < 0) {
5193bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getwp)
5293bfd616SPantelis Antoniou 			wp = mmc->cfg->ops->getwp(mmc);
53d4e1da4eSPeter Korsgaard 		else
54d4e1da4eSPeter Korsgaard 			wp = 0;
55d4e1da4eSPeter Korsgaard 	}
56d23d8d7eSNikita Kiryanov 
57d23d8d7eSNikita Kiryanov 	return wp;
58d23d8d7eSNikita Kiryanov }
59d23d8d7eSNikita Kiryanov 
60cee9ab7cSJeroen Hofstee __weak int board_mmc_getcd(struct mmc *mmc)
61cee9ab7cSJeroen Hofstee {
6211fdade2SStefano Babic 	return -1;
6311fdade2SStefano Babic }
648ca51e51SSimon Glass #endif
6511fdade2SStefano Babic 
668635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE
67c0c76ebaSSimon Glass void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd)
68c0c76ebaSSimon Glass {
69c0c76ebaSSimon Glass 	printf("CMD_SEND:%d\n", cmd->cmdidx);
70c0c76ebaSSimon Glass 	printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg);
71c0c76ebaSSimon Glass }
72c0c76ebaSSimon Glass 
73c0c76ebaSSimon Glass void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret)
74c0c76ebaSSimon Glass {
755db2fe3aSRaffaele Recalcati 	int i;
765db2fe3aSRaffaele Recalcati 	u8 *ptr;
775db2fe3aSRaffaele Recalcati 
787863ce58SBin Meng 	if (ret) {
797863ce58SBin Meng 		printf("\t\tRET\t\t\t %d\n", ret);
807863ce58SBin Meng 	} else {
815db2fe3aSRaffaele Recalcati 		switch (cmd->resp_type) {
825db2fe3aSRaffaele Recalcati 		case MMC_RSP_NONE:
835db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_NONE\n");
845db2fe3aSRaffaele Recalcati 			break;
855db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1:
865db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n",
875db2fe3aSRaffaele Recalcati 				cmd->response[0]);
885db2fe3aSRaffaele Recalcati 			break;
895db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1b:
905db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n",
915db2fe3aSRaffaele Recalcati 				cmd->response[0]);
925db2fe3aSRaffaele Recalcati 			break;
935db2fe3aSRaffaele Recalcati 		case MMC_RSP_R2:
945db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R2\t\t 0x%08X \n",
955db2fe3aSRaffaele Recalcati 				cmd->response[0]);
965db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
975db2fe3aSRaffaele Recalcati 				cmd->response[1]);
985db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
995db2fe3aSRaffaele Recalcati 				cmd->response[2]);
1005db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1015db2fe3aSRaffaele Recalcati 				cmd->response[3]);
1025db2fe3aSRaffaele Recalcati 			printf("\n");
1035db2fe3aSRaffaele Recalcati 			printf("\t\t\t\t\tDUMPING DATA\n");
1045db2fe3aSRaffaele Recalcati 			for (i = 0; i < 4; i++) {
1055db2fe3aSRaffaele Recalcati 				int j;
1065db2fe3aSRaffaele Recalcati 				printf("\t\t\t\t\t%03d - ", i*4);
107146bec79SDirk Behme 				ptr = (u8 *)&cmd->response[i];
1085db2fe3aSRaffaele Recalcati 				ptr += 3;
1095db2fe3aSRaffaele Recalcati 				for (j = 0; j < 4; j++)
1105db2fe3aSRaffaele Recalcati 					printf("%02X ", *ptr--);
1115db2fe3aSRaffaele Recalcati 				printf("\n");
1125db2fe3aSRaffaele Recalcati 			}
1135db2fe3aSRaffaele Recalcati 			break;
1145db2fe3aSRaffaele Recalcati 		case MMC_RSP_R3:
1155db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n",
1165db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1175db2fe3aSRaffaele Recalcati 			break;
1185db2fe3aSRaffaele Recalcati 		default:
1195db2fe3aSRaffaele Recalcati 			printf("\t\tERROR MMC rsp not supported\n");
1205db2fe3aSRaffaele Recalcati 			break;
1215db2fe3aSRaffaele Recalcati 		}
1227863ce58SBin Meng 	}
123c0c76ebaSSimon Glass }
124c0c76ebaSSimon Glass 
125c0c76ebaSSimon Glass void mmc_trace_state(struct mmc *mmc, struct mmc_cmd *cmd)
126c0c76ebaSSimon Glass {
127c0c76ebaSSimon Glass 	int status;
128c0c76ebaSSimon Glass 
129c0c76ebaSSimon Glass 	status = (cmd->response[0] & MMC_STATUS_CURR_STATE) >> 9;
130c0c76ebaSSimon Glass 	printf("CURR STATE:%d\n", status);
131c0c76ebaSSimon Glass }
1325db2fe3aSRaffaele Recalcati #endif
133c0c76ebaSSimon Glass 
13435f9e196SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG)
13535f9e196SJean-Jacques Hiblot const char *mmc_mode_name(enum bus_mode mode)
13635f9e196SJean-Jacques Hiblot {
13735f9e196SJean-Jacques Hiblot 	static const char *const names[] = {
13835f9e196SJean-Jacques Hiblot 	      [MMC_LEGACY]	= "MMC legacy",
13935f9e196SJean-Jacques Hiblot 	      [SD_LEGACY]	= "SD Legacy",
14035f9e196SJean-Jacques Hiblot 	      [MMC_HS]		= "MMC High Speed (26MHz)",
14135f9e196SJean-Jacques Hiblot 	      [SD_HS]		= "SD High Speed (50MHz)",
14235f9e196SJean-Jacques Hiblot 	      [UHS_SDR12]	= "UHS SDR12 (25MHz)",
14335f9e196SJean-Jacques Hiblot 	      [UHS_SDR25]	= "UHS SDR25 (50MHz)",
14435f9e196SJean-Jacques Hiblot 	      [UHS_SDR50]	= "UHS SDR50 (100MHz)",
14535f9e196SJean-Jacques Hiblot 	      [UHS_SDR104]	= "UHS SDR104 (208MHz)",
14635f9e196SJean-Jacques Hiblot 	      [UHS_DDR50]	= "UHS DDR50 (50MHz)",
14735f9e196SJean-Jacques Hiblot 	      [MMC_HS_52]	= "MMC High Speed (52MHz)",
14835f9e196SJean-Jacques Hiblot 	      [MMC_DDR_52]	= "MMC DDR52 (52MHz)",
14935f9e196SJean-Jacques Hiblot 	      [MMC_HS_200]	= "HS200 (200MHz)",
1503dd2626fSPeng Fan 	      [MMC_HS_400]	= "HS400 (200MHz)",
15135f9e196SJean-Jacques Hiblot 	};
15235f9e196SJean-Jacques Hiblot 
15335f9e196SJean-Jacques Hiblot 	if (mode >= MMC_MODES_END)
15435f9e196SJean-Jacques Hiblot 		return "Unknown mode";
15535f9e196SJean-Jacques Hiblot 	else
15635f9e196SJean-Jacques Hiblot 		return names[mode];
15735f9e196SJean-Jacques Hiblot }
15835f9e196SJean-Jacques Hiblot #endif
15935f9e196SJean-Jacques Hiblot 
16005038576SJean-Jacques Hiblot static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode)
16105038576SJean-Jacques Hiblot {
16205038576SJean-Jacques Hiblot 	static const int freqs[] = {
1631b313aa3SJaehoon Chung 	      [MMC_LEGACY]	= 25000000,
16405038576SJean-Jacques Hiblot 	      [SD_LEGACY]	= 25000000,
16505038576SJean-Jacques Hiblot 	      [MMC_HS]		= 26000000,
16605038576SJean-Jacques Hiblot 	      [SD_HS]		= 50000000,
1671b313aa3SJaehoon Chung 	      [MMC_HS_52]	= 52000000,
1681b313aa3SJaehoon Chung 	      [MMC_DDR_52]	= 52000000,
16905038576SJean-Jacques Hiblot 	      [UHS_SDR12]	= 25000000,
17005038576SJean-Jacques Hiblot 	      [UHS_SDR25]	= 50000000,
17105038576SJean-Jacques Hiblot 	      [UHS_SDR50]	= 100000000,
17205038576SJean-Jacques Hiblot 	      [UHS_DDR50]	= 50000000,
173f99c2efeSJean-Jacques Hiblot 	      [UHS_SDR104]	= 208000000,
17405038576SJean-Jacques Hiblot 	      [MMC_HS_200]	= 200000000,
1753dd2626fSPeng Fan 	      [MMC_HS_400]	= 200000000,
17605038576SJean-Jacques Hiblot 	};
17705038576SJean-Jacques Hiblot 
17805038576SJean-Jacques Hiblot 	if (mode == MMC_LEGACY)
17905038576SJean-Jacques Hiblot 		return mmc->legacy_speed;
18005038576SJean-Jacques Hiblot 	else if (mode >= MMC_MODES_END)
18105038576SJean-Jacques Hiblot 		return 0;
18205038576SJean-Jacques Hiblot 	else
18305038576SJean-Jacques Hiblot 		return freqs[mode];
18405038576SJean-Jacques Hiblot }
18505038576SJean-Jacques Hiblot 
18635f9e196SJean-Jacques Hiblot static int mmc_select_mode(struct mmc *mmc, enum bus_mode mode)
18735f9e196SJean-Jacques Hiblot {
18835f9e196SJean-Jacques Hiblot 	mmc->selected_mode = mode;
18905038576SJean-Jacques Hiblot 	mmc->tran_speed = mmc_mode2freq(mmc, mode);
1903862b854SJean-Jacques Hiblot 	mmc->ddr_mode = mmc_is_mode_ddr(mode);
191d4d64889SMasahiro Yamada 	pr_debug("selecting mode %s (freq : %d MHz)\n", mmc_mode_name(mode),
19235f9e196SJean-Jacques Hiblot 		 mmc->tran_speed / 1000000);
19335f9e196SJean-Jacques Hiblot 	return 0;
19435f9e196SJean-Jacques Hiblot }
19535f9e196SJean-Jacques Hiblot 
196e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
197c0c76ebaSSimon Glass int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
198c0c76ebaSSimon Glass {
199c0c76ebaSSimon Glass 	int ret;
200c0c76ebaSSimon Glass 
201c0c76ebaSSimon Glass 	mmmc_trace_before_send(mmc, cmd);
202c0c76ebaSSimon Glass 	ret = mmc->cfg->ops->send_cmd(mmc, cmd, data);
203c0c76ebaSSimon Glass 	mmmc_trace_after_send(mmc, cmd, ret);
204c0c76ebaSSimon Glass 
2058635ff9eSMarek Vasut 	return ret;
206272cc70bSAndy Fleming }
2078ca51e51SSimon Glass #endif
208272cc70bSAndy Fleming 
209da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout)
2105d4fc8d9SRaffaele Recalcati {
2115d4fc8d9SRaffaele Recalcati 	struct mmc_cmd cmd;
212d617c426SJan Kloetzke 	int err, retries = 5;
2135d4fc8d9SRaffaele Recalcati 
2145d4fc8d9SRaffaele Recalcati 	cmd.cmdidx = MMC_CMD_SEND_STATUS;
2155d4fc8d9SRaffaele Recalcati 	cmd.resp_type = MMC_RSP_R1;
216aaf3d41aSMarek Vasut 	if (!mmc_host_is_spi(mmc))
217aaf3d41aSMarek Vasut 		cmd.cmdarg = mmc->rca << 16;
2185d4fc8d9SRaffaele Recalcati 
2191677eef4SAndrew Gabbasov 	while (1) {
2205d4fc8d9SRaffaele Recalcati 		err = mmc_send_cmd(mmc, &cmd, NULL);
221d617c426SJan Kloetzke 		if (!err) {
222d617c426SJan Kloetzke 			if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) &&
223d617c426SJan Kloetzke 			    (cmd.response[0] & MMC_STATUS_CURR_STATE) !=
224d617c426SJan Kloetzke 			     MMC_STATE_PRG)
2255d4fc8d9SRaffaele Recalcati 				break;
226d0c221feSJean-Jacques Hiblot 
227d0c221feSJean-Jacques Hiblot 			if (cmd.response[0] & MMC_STATUS_MASK) {
22856196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
229d8e3d420SJean-Jacques Hiblot 				pr_err("Status Error: 0x%08X\n",
230d617c426SJan Kloetzke 				       cmd.response[0]);
23156196826SPaul Burton #endif
232915ffa52SJaehoon Chung 				return -ECOMM;
233d617c426SJan Kloetzke 			}
234d617c426SJan Kloetzke 		} else if (--retries < 0)
235d617c426SJan Kloetzke 			return err;
2365d4fc8d9SRaffaele Recalcati 
2371677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
2381677eef4SAndrew Gabbasov 			break;
2395d4fc8d9SRaffaele Recalcati 
2401677eef4SAndrew Gabbasov 		udelay(1000);
2411677eef4SAndrew Gabbasov 	}
2425d4fc8d9SRaffaele Recalcati 
243c0c76ebaSSimon Glass 	mmc_trace_state(mmc, &cmd);
2445b0c942fSJongman Heo 	if (timeout <= 0) {
24556196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
246d8e3d420SJean-Jacques Hiblot 		pr_err("Timeout waiting card ready\n");
24756196826SPaul Burton #endif
248915ffa52SJaehoon Chung 		return -ETIMEDOUT;
2495d4fc8d9SRaffaele Recalcati 	}
2505d4fc8d9SRaffaele Recalcati 
2515d4fc8d9SRaffaele Recalcati 	return 0;
2525d4fc8d9SRaffaele Recalcati }
2535d4fc8d9SRaffaele Recalcati 
254da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len)
255272cc70bSAndy Fleming {
256272cc70bSAndy Fleming 	struct mmc_cmd cmd;
25783dc4227SKishon Vijay Abraham I 	int err;
258272cc70bSAndy Fleming 
259786e8f81SAndrew Gabbasov 	if (mmc->ddr_mode)
260d22e3d46SJaehoon Chung 		return 0;
261d22e3d46SJaehoon Chung 
262272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
263272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
264272cc70bSAndy Fleming 	cmd.cmdarg = len;
265272cc70bSAndy Fleming 
26683dc4227SKishon Vijay Abraham I 	err = mmc_send_cmd(mmc, &cmd, NULL);
26783dc4227SKishon Vijay Abraham I 
26883dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS
26983dc4227SKishon Vijay Abraham I 	if (err && (mmc->quirks & MMC_QUIRK_RETRY_SET_BLOCKLEN)) {
27083dc4227SKishon Vijay Abraham I 		int retries = 4;
27183dc4227SKishon Vijay Abraham I 		/*
27283dc4227SKishon Vijay Abraham I 		 * It has been seen that SET_BLOCKLEN may fail on the first
27383dc4227SKishon Vijay Abraham I 		 * attempt, let's try a few more time
27483dc4227SKishon Vijay Abraham I 		 */
27583dc4227SKishon Vijay Abraham I 		do {
27683dc4227SKishon Vijay Abraham I 			err = mmc_send_cmd(mmc, &cmd, NULL);
27783dc4227SKishon Vijay Abraham I 			if (!err)
27883dc4227SKishon Vijay Abraham I 				break;
27983dc4227SKishon Vijay Abraham I 		} while (retries--);
28083dc4227SKishon Vijay Abraham I 	}
28183dc4227SKishon Vijay Abraham I #endif
28283dc4227SKishon Vijay Abraham I 
28383dc4227SKishon Vijay Abraham I 	return err;
284272cc70bSAndy Fleming }
285272cc70bSAndy Fleming 
286f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
2879815e3baSJean-Jacques Hiblot static const u8 tuning_blk_pattern_4bit[] = {
2889815e3baSJean-Jacques Hiblot 	0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
2899815e3baSJean-Jacques Hiblot 	0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
2909815e3baSJean-Jacques Hiblot 	0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
2919815e3baSJean-Jacques Hiblot 	0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
2929815e3baSJean-Jacques Hiblot 	0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
2939815e3baSJean-Jacques Hiblot 	0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
2949815e3baSJean-Jacques Hiblot 	0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
2959815e3baSJean-Jacques Hiblot 	0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
2969815e3baSJean-Jacques Hiblot };
2979815e3baSJean-Jacques Hiblot 
2989815e3baSJean-Jacques Hiblot static const u8 tuning_blk_pattern_8bit[] = {
2999815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
3009815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
3019815e3baSJean-Jacques Hiblot 	0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
3029815e3baSJean-Jacques Hiblot 	0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
3039815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
3049815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
3059815e3baSJean-Jacques Hiblot 	0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
3069815e3baSJean-Jacques Hiblot 	0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
3079815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
3089815e3baSJean-Jacques Hiblot 	0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
3099815e3baSJean-Jacques Hiblot 	0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
3109815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
3119815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
3129815e3baSJean-Jacques Hiblot 	0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
3139815e3baSJean-Jacques Hiblot 	0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
3149815e3baSJean-Jacques Hiblot 	0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
3159815e3baSJean-Jacques Hiblot };
3169815e3baSJean-Jacques Hiblot 
3179815e3baSJean-Jacques Hiblot int mmc_send_tuning(struct mmc *mmc, u32 opcode, int *cmd_error)
3189815e3baSJean-Jacques Hiblot {
3199815e3baSJean-Jacques Hiblot 	struct mmc_cmd cmd;
3209815e3baSJean-Jacques Hiblot 	struct mmc_data data;
3219815e3baSJean-Jacques Hiblot 	const u8 *tuning_block_pattern;
3229815e3baSJean-Jacques Hiblot 	int size, err;
3239815e3baSJean-Jacques Hiblot 
3249815e3baSJean-Jacques Hiblot 	if (mmc->bus_width == 8) {
3259815e3baSJean-Jacques Hiblot 		tuning_block_pattern = tuning_blk_pattern_8bit;
3269815e3baSJean-Jacques Hiblot 		size = sizeof(tuning_blk_pattern_8bit);
3279815e3baSJean-Jacques Hiblot 	} else if (mmc->bus_width == 4) {
3289815e3baSJean-Jacques Hiblot 		tuning_block_pattern = tuning_blk_pattern_4bit;
3299815e3baSJean-Jacques Hiblot 		size = sizeof(tuning_blk_pattern_4bit);
3309815e3baSJean-Jacques Hiblot 	} else {
3319815e3baSJean-Jacques Hiblot 		return -EINVAL;
3329815e3baSJean-Jacques Hiblot 	}
3339815e3baSJean-Jacques Hiblot 
3349815e3baSJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, data_buf, size);
3359815e3baSJean-Jacques Hiblot 
3369815e3baSJean-Jacques Hiblot 	cmd.cmdidx = opcode;
3379815e3baSJean-Jacques Hiblot 	cmd.cmdarg = 0;
3389815e3baSJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
3399815e3baSJean-Jacques Hiblot 
3409815e3baSJean-Jacques Hiblot 	data.dest = (void *)data_buf;
3419815e3baSJean-Jacques Hiblot 	data.blocks = 1;
3429815e3baSJean-Jacques Hiblot 	data.blocksize = size;
3439815e3baSJean-Jacques Hiblot 	data.flags = MMC_DATA_READ;
3449815e3baSJean-Jacques Hiblot 
3459815e3baSJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, &data);
3469815e3baSJean-Jacques Hiblot 	if (err)
3479815e3baSJean-Jacques Hiblot 		return err;
3489815e3baSJean-Jacques Hiblot 
3499815e3baSJean-Jacques Hiblot 	if (memcmp(data_buf, tuning_block_pattern, size))
3509815e3baSJean-Jacques Hiblot 		return -EIO;
3519815e3baSJean-Jacques Hiblot 
3529815e3baSJean-Jacques Hiblot 	return 0;
3539815e3baSJean-Jacques Hiblot }
354f99c2efeSJean-Jacques Hiblot #endif
3559815e3baSJean-Jacques Hiblot 
356ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
357fdbb873eSKim Phillips 			   lbaint_t blkcnt)
358272cc70bSAndy Fleming {
359272cc70bSAndy Fleming 	struct mmc_cmd cmd;
360272cc70bSAndy Fleming 	struct mmc_data data;
361272cc70bSAndy Fleming 
3624a1a06bcSAlagu Sankar 	if (blkcnt > 1)
3634a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
3644a1a06bcSAlagu Sankar 	else
365272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
366272cc70bSAndy Fleming 
367272cc70bSAndy Fleming 	if (mmc->high_capacity)
3684a1a06bcSAlagu Sankar 		cmd.cmdarg = start;
369272cc70bSAndy Fleming 	else
3704a1a06bcSAlagu Sankar 		cmd.cmdarg = start * mmc->read_bl_len;
371272cc70bSAndy Fleming 
372272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
373272cc70bSAndy Fleming 
374272cc70bSAndy Fleming 	data.dest = dst;
3754a1a06bcSAlagu Sankar 	data.blocks = blkcnt;
376272cc70bSAndy Fleming 	data.blocksize = mmc->read_bl_len;
377272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
378272cc70bSAndy Fleming 
3794a1a06bcSAlagu Sankar 	if (mmc_send_cmd(mmc, &cmd, &data))
3804a1a06bcSAlagu Sankar 		return 0;
3814a1a06bcSAlagu Sankar 
3824a1a06bcSAlagu Sankar 	if (blkcnt > 1) {
3834a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
3844a1a06bcSAlagu Sankar 		cmd.cmdarg = 0;
3854a1a06bcSAlagu Sankar 		cmd.resp_type = MMC_RSP_R1b;
3864a1a06bcSAlagu Sankar 		if (mmc_send_cmd(mmc, &cmd, NULL)) {
38756196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
388d8e3d420SJean-Jacques Hiblot 			pr_err("mmc fail to send stop cmd\n");
38956196826SPaul Burton #endif
3904a1a06bcSAlagu Sankar 			return 0;
3914a1a06bcSAlagu Sankar 		}
392272cc70bSAndy Fleming 	}
393272cc70bSAndy Fleming 
3944a1a06bcSAlagu Sankar 	return blkcnt;
395272cc70bSAndy Fleming }
396272cc70bSAndy Fleming 
397c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
3987dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst)
39933fb211dSSimon Glass #else
4007dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
4017dba0b93SSimon Glass 		void *dst)
40233fb211dSSimon Glass #endif
403272cc70bSAndy Fleming {
404c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
40533fb211dSSimon Glass 	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
40633fb211dSSimon Glass #endif
407bcce53d0SSimon Glass 	int dev_num = block_dev->devnum;
408873cc1d7SStephen Warren 	int err;
4094a1a06bcSAlagu Sankar 	lbaint_t cur, blocks_todo = blkcnt;
410272cc70bSAndy Fleming 
4114a1a06bcSAlagu Sankar 	if (blkcnt == 0)
4124a1a06bcSAlagu Sankar 		return 0;
4134a1a06bcSAlagu Sankar 
4144a1a06bcSAlagu Sankar 	struct mmc *mmc = find_mmc_device(dev_num);
415272cc70bSAndy Fleming 	if (!mmc)
416272cc70bSAndy Fleming 		return 0;
417272cc70bSAndy Fleming 
418b5b838f1SMarek Vasut 	if (CONFIG_IS_ENABLED(MMC_TINY))
419b5b838f1SMarek Vasut 		err = mmc_switch_part(mmc, block_dev->hwpart);
420b5b838f1SMarek Vasut 	else
42169f45cd5SSimon Glass 		err = blk_dselect_hwpart(block_dev, block_dev->hwpart);
422b5b838f1SMarek Vasut 
423873cc1d7SStephen Warren 	if (err < 0)
424873cc1d7SStephen Warren 		return 0;
425873cc1d7SStephen Warren 
426c40fdca6SSimon Glass 	if ((start + blkcnt) > block_dev->lba) {
42756196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
428d8e3d420SJean-Jacques Hiblot 		pr_err("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
429c40fdca6SSimon Glass 		       start + blkcnt, block_dev->lba);
43056196826SPaul Burton #endif
431d2bf29e3SLei Wen 		return 0;
432d2bf29e3SLei Wen 	}
433272cc70bSAndy Fleming 
43411692991SSimon Glass 	if (mmc_set_blocklen(mmc, mmc->read_bl_len)) {
435d4d64889SMasahiro Yamada 		pr_debug("%s: Failed to set blocklen\n", __func__);
436272cc70bSAndy Fleming 		return 0;
43711692991SSimon Glass 	}
438272cc70bSAndy Fleming 
4394a1a06bcSAlagu Sankar 	do {
44093bfd616SPantelis Antoniou 		cur = (blocks_todo > mmc->cfg->b_max) ?
44193bfd616SPantelis Antoniou 			mmc->cfg->b_max : blocks_todo;
44211692991SSimon Glass 		if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
443d4d64889SMasahiro Yamada 			pr_debug("%s: Failed to read blocks\n", __func__);
4444a1a06bcSAlagu Sankar 			return 0;
44511692991SSimon Glass 		}
4464a1a06bcSAlagu Sankar 		blocks_todo -= cur;
4474a1a06bcSAlagu Sankar 		start += cur;
4484a1a06bcSAlagu Sankar 		dst += cur * mmc->read_bl_len;
4494a1a06bcSAlagu Sankar 	} while (blocks_todo > 0);
450272cc70bSAndy Fleming 
451272cc70bSAndy Fleming 	return blkcnt;
452272cc70bSAndy Fleming }
453272cc70bSAndy Fleming 
454fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc)
455272cc70bSAndy Fleming {
456272cc70bSAndy Fleming 	struct mmc_cmd cmd;
457272cc70bSAndy Fleming 	int err;
458272cc70bSAndy Fleming 
459272cc70bSAndy Fleming 	udelay(1000);
460272cc70bSAndy Fleming 
461272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
462272cc70bSAndy Fleming 	cmd.cmdarg = 0;
463272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_NONE;
464272cc70bSAndy Fleming 
465272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
466272cc70bSAndy Fleming 
467272cc70bSAndy Fleming 	if (err)
468272cc70bSAndy Fleming 		return err;
469272cc70bSAndy Fleming 
470272cc70bSAndy Fleming 	udelay(2000);
471272cc70bSAndy Fleming 
472272cc70bSAndy Fleming 	return 0;
473272cc70bSAndy Fleming }
474272cc70bSAndy Fleming 
475f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
476c10b85d6SJean-Jacques Hiblot static int mmc_switch_voltage(struct mmc *mmc, int signal_voltage)
477c10b85d6SJean-Jacques Hiblot {
478c10b85d6SJean-Jacques Hiblot 	struct mmc_cmd cmd;
479c10b85d6SJean-Jacques Hiblot 	int err = 0;
480c10b85d6SJean-Jacques Hiblot 
481c10b85d6SJean-Jacques Hiblot 	/*
482c10b85d6SJean-Jacques Hiblot 	 * Send CMD11 only if the request is to switch the card to
483c10b85d6SJean-Jacques Hiblot 	 * 1.8V signalling.
484c10b85d6SJean-Jacques Hiblot 	 */
485c10b85d6SJean-Jacques Hiblot 	if (signal_voltage == MMC_SIGNAL_VOLTAGE_330)
486c10b85d6SJean-Jacques Hiblot 		return mmc_set_signal_voltage(mmc, signal_voltage);
487c10b85d6SJean-Jacques Hiblot 
488c10b85d6SJean-Jacques Hiblot 	cmd.cmdidx = SD_CMD_SWITCH_UHS18V;
489c10b85d6SJean-Jacques Hiblot 	cmd.cmdarg = 0;
490c10b85d6SJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
491c10b85d6SJean-Jacques Hiblot 
492c10b85d6SJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
493c10b85d6SJean-Jacques Hiblot 	if (err)
494c10b85d6SJean-Jacques Hiblot 		return err;
495c10b85d6SJean-Jacques Hiblot 
496c10b85d6SJean-Jacques Hiblot 	if (!mmc_host_is_spi(mmc) && (cmd.response[0] & MMC_STATUS_ERROR))
497c10b85d6SJean-Jacques Hiblot 		return -EIO;
498c10b85d6SJean-Jacques Hiblot 
499c10b85d6SJean-Jacques Hiblot 	/*
500c10b85d6SJean-Jacques Hiblot 	 * The card should drive cmd and dat[0:3] low immediately
501c10b85d6SJean-Jacques Hiblot 	 * after the response of cmd11, but wait 100 us to be sure
502c10b85d6SJean-Jacques Hiblot 	 */
503c10b85d6SJean-Jacques Hiblot 	err = mmc_wait_dat0(mmc, 0, 100);
504c10b85d6SJean-Jacques Hiblot 	if (err == -ENOSYS)
505c10b85d6SJean-Jacques Hiblot 		udelay(100);
506c10b85d6SJean-Jacques Hiblot 	else if (err)
507c10b85d6SJean-Jacques Hiblot 		return -ETIMEDOUT;
508c10b85d6SJean-Jacques Hiblot 
509c10b85d6SJean-Jacques Hiblot 	/*
510c10b85d6SJean-Jacques Hiblot 	 * During a signal voltage level switch, the clock must be gated
511c10b85d6SJean-Jacques Hiblot 	 * for 5 ms according to the SD spec
512c10b85d6SJean-Jacques Hiblot 	 */
51365117182SJaehoon Chung 	mmc_set_clock(mmc, mmc->clock, MMC_CLK_DISABLE);
514c10b85d6SJean-Jacques Hiblot 
515c10b85d6SJean-Jacques Hiblot 	err = mmc_set_signal_voltage(mmc, signal_voltage);
516c10b85d6SJean-Jacques Hiblot 	if (err)
517c10b85d6SJean-Jacques Hiblot 		return err;
518c10b85d6SJean-Jacques Hiblot 
519c10b85d6SJean-Jacques Hiblot 	/* Keep clock gated for at least 10 ms, though spec only says 5 ms */
520c10b85d6SJean-Jacques Hiblot 	mdelay(10);
52165117182SJaehoon Chung 	mmc_set_clock(mmc, mmc->clock, MMC_CLK_ENABLE);
522c10b85d6SJean-Jacques Hiblot 
523c10b85d6SJean-Jacques Hiblot 	/*
524c10b85d6SJean-Jacques Hiblot 	 * Failure to switch is indicated by the card holding
525c10b85d6SJean-Jacques Hiblot 	 * dat[0:3] low. Wait for at least 1 ms according to spec
526c10b85d6SJean-Jacques Hiblot 	 */
527c10b85d6SJean-Jacques Hiblot 	err = mmc_wait_dat0(mmc, 1, 1000);
528c10b85d6SJean-Jacques Hiblot 	if (err == -ENOSYS)
529c10b85d6SJean-Jacques Hiblot 		udelay(1000);
530c10b85d6SJean-Jacques Hiblot 	else if (err)
531c10b85d6SJean-Jacques Hiblot 		return -ETIMEDOUT;
532c10b85d6SJean-Jacques Hiblot 
533c10b85d6SJean-Jacques Hiblot 	return 0;
534c10b85d6SJean-Jacques Hiblot }
535f99c2efeSJean-Jacques Hiblot #endif
536c10b85d6SJean-Jacques Hiblot 
537c10b85d6SJean-Jacques Hiblot static int sd_send_op_cond(struct mmc *mmc, bool uhs_en)
538272cc70bSAndy Fleming {
539272cc70bSAndy Fleming 	int timeout = 1000;
540272cc70bSAndy Fleming 	int err;
541272cc70bSAndy Fleming 	struct mmc_cmd cmd;
542272cc70bSAndy Fleming 
5431677eef4SAndrew Gabbasov 	while (1) {
544272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_APP_CMD;
545272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1;
546272cc70bSAndy Fleming 		cmd.cmdarg = 0;
547272cc70bSAndy Fleming 
548272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
549272cc70bSAndy Fleming 
550272cc70bSAndy Fleming 		if (err)
551272cc70bSAndy Fleming 			return err;
552272cc70bSAndy Fleming 
553272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
554272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
555250de12bSStefano Babic 
556250de12bSStefano Babic 		/*
557250de12bSStefano Babic 		 * Most cards do not answer if some reserved bits
558250de12bSStefano Babic 		 * in the ocr are set. However, Some controller
559250de12bSStefano Babic 		 * can set bit 7 (reserved for low voltages), but
560250de12bSStefano Babic 		 * how to manage low voltages SD card is not yet
561250de12bSStefano Babic 		 * specified.
562250de12bSStefano Babic 		 */
563d52ebf10SThomas Chou 		cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
56493bfd616SPantelis Antoniou 			(mmc->cfg->voltages & 0xff8000);
565272cc70bSAndy Fleming 
566272cc70bSAndy Fleming 		if (mmc->version == SD_VERSION_2)
567272cc70bSAndy Fleming 			cmd.cmdarg |= OCR_HCS;
568272cc70bSAndy Fleming 
569c10b85d6SJean-Jacques Hiblot 		if (uhs_en)
570c10b85d6SJean-Jacques Hiblot 			cmd.cmdarg |= OCR_S18R;
571c10b85d6SJean-Jacques Hiblot 
572272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
573272cc70bSAndy Fleming 
574272cc70bSAndy Fleming 		if (err)
575272cc70bSAndy Fleming 			return err;
576272cc70bSAndy Fleming 
5771677eef4SAndrew Gabbasov 		if (cmd.response[0] & OCR_BUSY)
5781677eef4SAndrew Gabbasov 			break;
579272cc70bSAndy Fleming 
5801677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
581915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
582272cc70bSAndy Fleming 
5831677eef4SAndrew Gabbasov 		udelay(1000);
5841677eef4SAndrew Gabbasov 	}
5851677eef4SAndrew Gabbasov 
586272cc70bSAndy Fleming 	if (mmc->version != SD_VERSION_2)
587272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
588272cc70bSAndy Fleming 
589d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
590d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
591d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
592d52ebf10SThomas Chou 		cmd.cmdarg = 0;
593d52ebf10SThomas Chou 
594d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
595d52ebf10SThomas Chou 
596d52ebf10SThomas Chou 		if (err)
597d52ebf10SThomas Chou 			return err;
598d52ebf10SThomas Chou 	}
599d52ebf10SThomas Chou 
600998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
601272cc70bSAndy Fleming 
602f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
603c10b85d6SJean-Jacques Hiblot 	if (uhs_en && !(mmc_host_is_spi(mmc)) && (cmd.response[0] & 0x41000000)
604c10b85d6SJean-Jacques Hiblot 	    == 0x41000000) {
605c10b85d6SJean-Jacques Hiblot 		err = mmc_switch_voltage(mmc, MMC_SIGNAL_VOLTAGE_180);
606c10b85d6SJean-Jacques Hiblot 		if (err)
607c10b85d6SJean-Jacques Hiblot 			return err;
608c10b85d6SJean-Jacques Hiblot 	}
609f99c2efeSJean-Jacques Hiblot #endif
610c10b85d6SJean-Jacques Hiblot 
611272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
612272cc70bSAndy Fleming 	mmc->rca = 0;
613272cc70bSAndy Fleming 
614272cc70bSAndy Fleming 	return 0;
615272cc70bSAndy Fleming }
616272cc70bSAndy Fleming 
6175289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg)
618272cc70bSAndy Fleming {
6195289b535SAndrew Gabbasov 	struct mmc_cmd cmd;
620272cc70bSAndy Fleming 	int err;
621272cc70bSAndy Fleming 
6225289b535SAndrew Gabbasov 	cmd.cmdidx = MMC_CMD_SEND_OP_COND;
6235289b535SAndrew Gabbasov 	cmd.resp_type = MMC_RSP_R3;
6245289b535SAndrew Gabbasov 	cmd.cmdarg = 0;
6255a20397bSRob Herring 	if (use_arg && !mmc_host_is_spi(mmc))
6265a20397bSRob Herring 		cmd.cmdarg = OCR_HCS |
62793bfd616SPantelis Antoniou 			(mmc->cfg->voltages &
628a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_VOLTAGE_MASK)) |
629a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_ACCESS_MODE);
630e9550449SChe-Liang Chiou 
6315289b535SAndrew Gabbasov 	err = mmc_send_cmd(mmc, &cmd, NULL);
632e9550449SChe-Liang Chiou 	if (err)
633e9550449SChe-Liang Chiou 		return err;
6345289b535SAndrew Gabbasov 	mmc->ocr = cmd.response[0];
635e9550449SChe-Liang Chiou 	return 0;
636e9550449SChe-Liang Chiou }
637e9550449SChe-Liang Chiou 
638750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc)
639e9550449SChe-Liang Chiou {
640e9550449SChe-Liang Chiou 	int err, i;
641e9550449SChe-Liang Chiou 
642272cc70bSAndy Fleming 	/* Some cards seem to need this */
643272cc70bSAndy Fleming 	mmc_go_idle(mmc);
644272cc70bSAndy Fleming 
64531cacbabSRaffaele Recalcati  	/* Asking to the card its capabilities */
646e9550449SChe-Liang Chiou 	for (i = 0; i < 2; i++) {
6475289b535SAndrew Gabbasov 		err = mmc_send_op_cond_iter(mmc, i != 0);
64831cacbabSRaffaele Recalcati 		if (err)
64931cacbabSRaffaele Recalcati 			return err;
65031cacbabSRaffaele Recalcati 
651e9550449SChe-Liang Chiou 		/* exit if not busy (flag seems to be inverted) */
652a626c8d4SAndrew Gabbasov 		if (mmc->ocr & OCR_BUSY)
653bd47c135SAndrew Gabbasov 			break;
654e9550449SChe-Liang Chiou 	}
655bd47c135SAndrew Gabbasov 	mmc->op_cond_pending = 1;
656bd47c135SAndrew Gabbasov 	return 0;
657e9550449SChe-Liang Chiou }
65831cacbabSRaffaele Recalcati 
659750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc)
660e9550449SChe-Liang Chiou {
661e9550449SChe-Liang Chiou 	struct mmc_cmd cmd;
662e9550449SChe-Liang Chiou 	int timeout = 1000;
66336332b6eSVipul Kumar 	ulong start;
664e9550449SChe-Liang Chiou 	int err;
665e9550449SChe-Liang Chiou 
666e9550449SChe-Liang Chiou 	mmc->op_cond_pending = 0;
667cc17c01fSAndrew Gabbasov 	if (!(mmc->ocr & OCR_BUSY)) {
668d188b113SYangbo Lu 		/* Some cards seem to need this */
669d188b113SYangbo Lu 		mmc_go_idle(mmc);
670d188b113SYangbo Lu 
671e9550449SChe-Liang Chiou 		start = get_timer(0);
6721677eef4SAndrew Gabbasov 		while (1) {
6735289b535SAndrew Gabbasov 			err = mmc_send_op_cond_iter(mmc, 1);
674272cc70bSAndy Fleming 			if (err)
675272cc70bSAndy Fleming 				return err;
6761677eef4SAndrew Gabbasov 			if (mmc->ocr & OCR_BUSY)
6771677eef4SAndrew Gabbasov 				break;
678e9550449SChe-Liang Chiou 			if (get_timer(start) > timeout)
679915ffa52SJaehoon Chung 				return -EOPNOTSUPP;
680e9550449SChe-Liang Chiou 			udelay(100);
6811677eef4SAndrew Gabbasov 		}
682cc17c01fSAndrew Gabbasov 	}
683272cc70bSAndy Fleming 
684d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
685d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
686d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
687d52ebf10SThomas Chou 		cmd.cmdarg = 0;
688d52ebf10SThomas Chou 
689d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
690d52ebf10SThomas Chou 
691d52ebf10SThomas Chou 		if (err)
692d52ebf10SThomas Chou 			return err;
693a626c8d4SAndrew Gabbasov 
694a626c8d4SAndrew Gabbasov 		mmc->ocr = cmd.response[0];
695d52ebf10SThomas Chou 	}
696d52ebf10SThomas Chou 
697272cc70bSAndy Fleming 	mmc->version = MMC_VERSION_UNKNOWN;
698272cc70bSAndy Fleming 
699272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
700def816a2SStephen Warren 	mmc->rca = 1;
701272cc70bSAndy Fleming 
702272cc70bSAndy Fleming 	return 0;
703272cc70bSAndy Fleming }
704272cc70bSAndy Fleming 
705272cc70bSAndy Fleming 
706fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
707272cc70bSAndy Fleming {
708272cc70bSAndy Fleming 	struct mmc_cmd cmd;
709272cc70bSAndy Fleming 	struct mmc_data data;
710272cc70bSAndy Fleming 	int err;
711272cc70bSAndy Fleming 
712272cc70bSAndy Fleming 	/* Get the Card Status Register */
713272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
714272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
715272cc70bSAndy Fleming 	cmd.cmdarg = 0;
716272cc70bSAndy Fleming 
717cdfd1ac6SYoshihiro Shimoda 	data.dest = (char *)ext_csd;
718272cc70bSAndy Fleming 	data.blocks = 1;
7198bfa195eSSimon Glass 	data.blocksize = MMC_MAX_BLOCK_LEN;
720272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
721272cc70bSAndy Fleming 
722272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
723272cc70bSAndy Fleming 
724272cc70bSAndy Fleming 	return err;
725272cc70bSAndy Fleming }
726272cc70bSAndy Fleming 
727c40704f4SSimon Glass int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
728272cc70bSAndy Fleming {
729272cc70bSAndy Fleming 	struct mmc_cmd cmd;
7305d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
731a9003dc6SMaxime Ripard 	int retries = 3;
7325d4fc8d9SRaffaele Recalcati 	int ret;
733272cc70bSAndy Fleming 
734272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SWITCH;
735272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1b;
736272cc70bSAndy Fleming 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
737272cc70bSAndy Fleming 				 (index << 16) |
738272cc70bSAndy Fleming 				 (value << 8);
739272cc70bSAndy Fleming 
740a9003dc6SMaxime Ripard 	while (retries > 0) {
7415d4fc8d9SRaffaele Recalcati 		ret = mmc_send_cmd(mmc, &cmd, NULL);
7425d4fc8d9SRaffaele Recalcati 
7435d4fc8d9SRaffaele Recalcati 		/* Waiting for the ready status */
744a9003dc6SMaxime Ripard 		if (!ret) {
74593ad0d18SJan Kloetzke 			ret = mmc_send_status(mmc, timeout);
746a9003dc6SMaxime Ripard 			return ret;
747a9003dc6SMaxime Ripard 		}
748a9003dc6SMaxime Ripard 
749a9003dc6SMaxime Ripard 		retries--;
750a9003dc6SMaxime Ripard 	}
7515d4fc8d9SRaffaele Recalcati 
7525d4fc8d9SRaffaele Recalcati 	return ret;
7535d4fc8d9SRaffaele Recalcati 
754272cc70bSAndy Fleming }
755272cc70bSAndy Fleming 
75662d77ceaSMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY)
7573862b854SJean-Jacques Hiblot static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode)
758272cc70bSAndy Fleming {
759272cc70bSAndy Fleming 	int err;
7603862b854SJean-Jacques Hiblot 	int speed_bits;
7613862b854SJean-Jacques Hiblot 
7623862b854SJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
7633862b854SJean-Jacques Hiblot 
7643862b854SJean-Jacques Hiblot 	switch (mode) {
7653862b854SJean-Jacques Hiblot 	case MMC_HS:
7663862b854SJean-Jacques Hiblot 	case MMC_HS_52:
7673862b854SJean-Jacques Hiblot 	case MMC_DDR_52:
7683862b854SJean-Jacques Hiblot 		speed_bits = EXT_CSD_TIMING_HS;
769634d4849SKishon Vijay Abraham I 		break;
770baef2070SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
771634d4849SKishon Vijay Abraham I 	case MMC_HS_200:
772634d4849SKishon Vijay Abraham I 		speed_bits = EXT_CSD_TIMING_HS200;
773634d4849SKishon Vijay Abraham I 		break;
774baef2070SJean-Jacques Hiblot #endif
7753dd2626fSPeng Fan #if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
7763dd2626fSPeng Fan 	case MMC_HS_400:
7773dd2626fSPeng Fan 		speed_bits = EXT_CSD_TIMING_HS400;
7783dd2626fSPeng Fan 		break;
7793dd2626fSPeng Fan #endif
7803862b854SJean-Jacques Hiblot 	case MMC_LEGACY:
7813862b854SJean-Jacques Hiblot 		speed_bits = EXT_CSD_TIMING_LEGACY;
7823862b854SJean-Jacques Hiblot 		break;
7833862b854SJean-Jacques Hiblot 	default:
7843862b854SJean-Jacques Hiblot 		return -EINVAL;
7853862b854SJean-Jacques Hiblot 	}
7863862b854SJean-Jacques Hiblot 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
7873862b854SJean-Jacques Hiblot 			 speed_bits);
7883862b854SJean-Jacques Hiblot 	if (err)
7893862b854SJean-Jacques Hiblot 		return err;
7903862b854SJean-Jacques Hiblot 
7913862b854SJean-Jacques Hiblot 	if ((mode == MMC_HS) || (mode == MMC_HS_52)) {
7923862b854SJean-Jacques Hiblot 		/* Now check to see that it worked */
7933862b854SJean-Jacques Hiblot 		err = mmc_send_ext_csd(mmc, test_csd);
7943862b854SJean-Jacques Hiblot 		if (err)
7953862b854SJean-Jacques Hiblot 			return err;
7963862b854SJean-Jacques Hiblot 
7973862b854SJean-Jacques Hiblot 		/* No high-speed support */
7983862b854SJean-Jacques Hiblot 		if (!test_csd[EXT_CSD_HS_TIMING])
7993862b854SJean-Jacques Hiblot 			return -ENOTSUPP;
8003862b854SJean-Jacques Hiblot 	}
8013862b854SJean-Jacques Hiblot 
8023862b854SJean-Jacques Hiblot 	return 0;
8033862b854SJean-Jacques Hiblot }
8043862b854SJean-Jacques Hiblot 
8053862b854SJean-Jacques Hiblot static int mmc_get_capabilities(struct mmc *mmc)
8063862b854SJean-Jacques Hiblot {
8073862b854SJean-Jacques Hiblot 	u8 *ext_csd = mmc->ext_csd;
8083862b854SJean-Jacques Hiblot 	char cardtype;
809272cc70bSAndy Fleming 
81000e446faSJean-Jacques Hiblot 	mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(MMC_LEGACY);
811272cc70bSAndy Fleming 
812d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
813d52ebf10SThomas Chou 		return 0;
814d52ebf10SThomas Chou 
815272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
816272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
817272cc70bSAndy Fleming 		return 0;
818272cc70bSAndy Fleming 
8193862b854SJean-Jacques Hiblot 	if (!ext_csd) {
820d8e3d420SJean-Jacques Hiblot 		pr_err("No ext_csd found!\n"); /* this should enver happen */
8213862b854SJean-Jacques Hiblot 		return -ENOTSUPP;
8223862b854SJean-Jacques Hiblot 	}
8233862b854SJean-Jacques Hiblot 
824fc5b32fbSAndrew Gabbasov 	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
825fc5b32fbSAndrew Gabbasov 
8263dd2626fSPeng Fan 	cardtype = ext_csd[EXT_CSD_CARD_TYPE];
827bc1e3272SJean-Jacques Hiblot 	mmc->cardtype = cardtype;
828272cc70bSAndy Fleming 
829baef2070SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
830634d4849SKishon Vijay Abraham I 	if (cardtype & (EXT_CSD_CARD_TYPE_HS200_1_2V |
831634d4849SKishon Vijay Abraham I 			EXT_CSD_CARD_TYPE_HS200_1_8V)) {
832634d4849SKishon Vijay Abraham I 		mmc->card_caps |= MMC_MODE_HS200;
833634d4849SKishon Vijay Abraham I 	}
834baef2070SJean-Jacques Hiblot #endif
8353dd2626fSPeng Fan #if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
8363dd2626fSPeng Fan 	if (cardtype & (EXT_CSD_CARD_TYPE_HS400_1_2V |
8373dd2626fSPeng Fan 			EXT_CSD_CARD_TYPE_HS400_1_8V)) {
8383dd2626fSPeng Fan 		mmc->card_caps |= MMC_MODE_HS400;
8393dd2626fSPeng Fan 	}
8403dd2626fSPeng Fan #endif
841d22e3d46SJaehoon Chung 	if (cardtype & EXT_CSD_CARD_TYPE_52) {
8423862b854SJean-Jacques Hiblot 		if (cardtype & EXT_CSD_CARD_TYPE_DDR_52)
843d22e3d46SJaehoon Chung 			mmc->card_caps |= MMC_MODE_DDR_52MHz;
8443862b854SJean-Jacques Hiblot 		mmc->card_caps |= MMC_MODE_HS_52MHz;
845d22e3d46SJaehoon Chung 	}
8463862b854SJean-Jacques Hiblot 	if (cardtype & EXT_CSD_CARD_TYPE_26)
8473862b854SJean-Jacques Hiblot 		mmc->card_caps |= MMC_MODE_HS;
848272cc70bSAndy Fleming 
849272cc70bSAndy Fleming 	return 0;
850272cc70bSAndy Fleming }
85162d77ceaSMarek Vasut #endif
852272cc70bSAndy Fleming 
853f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num)
854f866a46dSStephen Warren {
855f866a46dSStephen Warren 	switch (part_num) {
856f866a46dSStephen Warren 	case 0:
857f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_user;
858f866a46dSStephen Warren 		break;
859f866a46dSStephen Warren 	case 1:
860f866a46dSStephen Warren 	case 2:
861f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_boot;
862f866a46dSStephen Warren 		break;
863f866a46dSStephen Warren 	case 3:
864f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_rpmb;
865f866a46dSStephen Warren 		break;
866f866a46dSStephen Warren 	case 4:
867f866a46dSStephen Warren 	case 5:
868f866a46dSStephen Warren 	case 6:
869f866a46dSStephen Warren 	case 7:
870f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_gp[part_num - 4];
871f866a46dSStephen Warren 		break;
872f866a46dSStephen Warren 	default:
873f866a46dSStephen Warren 		return -1;
874f866a46dSStephen Warren 	}
875f866a46dSStephen Warren 
876c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len);
877f866a46dSStephen Warren 
878f866a46dSStephen Warren 	return 0;
879f866a46dSStephen Warren }
880f866a46dSStephen Warren 
881f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
88201298da3SJean-Jacques Hiblot static int mmc_boot_part_access_chk(struct mmc *mmc, unsigned int part_num)
88301298da3SJean-Jacques Hiblot {
88401298da3SJean-Jacques Hiblot 	int forbidden = 0;
88501298da3SJean-Jacques Hiblot 	bool change = false;
88601298da3SJean-Jacques Hiblot 
88701298da3SJean-Jacques Hiblot 	if (part_num & PART_ACCESS_MASK)
88801298da3SJean-Jacques Hiblot 		forbidden = MMC_CAP(MMC_HS_200);
88901298da3SJean-Jacques Hiblot 
89001298da3SJean-Jacques Hiblot 	if (MMC_CAP(mmc->selected_mode) & forbidden) {
891d4d64889SMasahiro Yamada 		pr_debug("selected mode (%s) is forbidden for part %d\n",
89201298da3SJean-Jacques Hiblot 			 mmc_mode_name(mmc->selected_mode), part_num);
89301298da3SJean-Jacques Hiblot 		change = true;
89401298da3SJean-Jacques Hiblot 	} else if (mmc->selected_mode != mmc->best_mode) {
895d4d64889SMasahiro Yamada 		pr_debug("selected mode is not optimal\n");
89601298da3SJean-Jacques Hiblot 		change = true;
89701298da3SJean-Jacques Hiblot 	}
89801298da3SJean-Jacques Hiblot 
89901298da3SJean-Jacques Hiblot 	if (change)
90001298da3SJean-Jacques Hiblot 		return mmc_select_mode_and_width(mmc,
90101298da3SJean-Jacques Hiblot 						 mmc->card_caps & ~forbidden);
90201298da3SJean-Jacques Hiblot 
90301298da3SJean-Jacques Hiblot 	return 0;
90401298da3SJean-Jacques Hiblot }
905f99c2efeSJean-Jacques Hiblot #else
906f99c2efeSJean-Jacques Hiblot static inline int mmc_boot_part_access_chk(struct mmc *mmc,
907f99c2efeSJean-Jacques Hiblot 					   unsigned int part_num)
908f99c2efeSJean-Jacques Hiblot {
909f99c2efeSJean-Jacques Hiblot 	return 0;
910f99c2efeSJean-Jacques Hiblot }
911f99c2efeSJean-Jacques Hiblot #endif
91201298da3SJean-Jacques Hiblot 
9137dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num)
914bc897b1dSLei Wen {
915f866a46dSStephen Warren 	int ret;
916bc897b1dSLei Wen 
91701298da3SJean-Jacques Hiblot 	ret = mmc_boot_part_access_chk(mmc, part_num);
91801298da3SJean-Jacques Hiblot 	if (ret)
91901298da3SJean-Jacques Hiblot 		return ret;
92001298da3SJean-Jacques Hiblot 
921f866a46dSStephen Warren 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
922bc897b1dSLei Wen 			 (mmc->part_config & ~PART_ACCESS_MASK)
923bc897b1dSLei Wen 			 | (part_num & PART_ACCESS_MASK));
924f866a46dSStephen Warren 
9256dc93e70SPeter Bigot 	/*
9266dc93e70SPeter Bigot 	 * Set the capacity if the switch succeeded or was intended
9276dc93e70SPeter Bigot 	 * to return to representing the raw device.
9286dc93e70SPeter Bigot 	 */
929873cc1d7SStephen Warren 	if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) {
9306dc93e70SPeter Bigot 		ret = mmc_set_capacity(mmc, part_num);
931fdbb139fSSimon Glass 		mmc_get_blk_desc(mmc)->hwpart = part_num;
932873cc1d7SStephen Warren 	}
9336dc93e70SPeter Bigot 
9346dc93e70SPeter Bigot 	return ret;
935bc897b1dSLei Wen }
936bc897b1dSLei Wen 
937cf17789eSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING)
938ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc,
939ac9da0e0SDiego Santa Cruz 		      const struct mmc_hwpart_conf *conf,
940ac9da0e0SDiego Santa Cruz 		      enum mmc_hwpart_conf_mode mode)
941ac9da0e0SDiego Santa Cruz {
942ac9da0e0SDiego Santa Cruz 	u8 part_attrs = 0;
943ac9da0e0SDiego Santa Cruz 	u32 enh_size_mult;
944ac9da0e0SDiego Santa Cruz 	u32 enh_start_addr;
945ac9da0e0SDiego Santa Cruz 	u32 gp_size_mult[4];
946ac9da0e0SDiego Santa Cruz 	u32 max_enh_size_mult;
947ac9da0e0SDiego Santa Cruz 	u32 tot_enh_size_mult = 0;
9488dda5b0eSDiego Santa Cruz 	u8 wr_rel_set;
949ac9da0e0SDiego Santa Cruz 	int i, pidx, err;
950ac9da0e0SDiego Santa Cruz 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
951ac9da0e0SDiego Santa Cruz 
952ac9da0e0SDiego Santa Cruz 	if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE)
953ac9da0e0SDiego Santa Cruz 		return -EINVAL;
954ac9da0e0SDiego Santa Cruz 
955ac9da0e0SDiego Santa Cruz 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) {
956d8e3d420SJean-Jacques Hiblot 		pr_err("eMMC >= 4.4 required for enhanced user data area\n");
957ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
958ac9da0e0SDiego Santa Cruz 	}
959ac9da0e0SDiego Santa Cruz 
960ac9da0e0SDiego Santa Cruz 	if (!(mmc->part_support & PART_SUPPORT)) {
961d8e3d420SJean-Jacques Hiblot 		pr_err("Card does not support partitioning\n");
962ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
963ac9da0e0SDiego Santa Cruz 	}
964ac9da0e0SDiego Santa Cruz 
965ac9da0e0SDiego Santa Cruz 	if (!mmc->hc_wp_grp_size) {
966d8e3d420SJean-Jacques Hiblot 		pr_err("Card does not define HC WP group size\n");
967ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
968ac9da0e0SDiego Santa Cruz 	}
969ac9da0e0SDiego Santa Cruz 
970ac9da0e0SDiego Santa Cruz 	/* check partition alignment and total enhanced size */
971ac9da0e0SDiego Santa Cruz 	if (conf->user.enh_size) {
972ac9da0e0SDiego Santa Cruz 		if (conf->user.enh_size % mmc->hc_wp_grp_size ||
973ac9da0e0SDiego Santa Cruz 		    conf->user.enh_start % mmc->hc_wp_grp_size) {
974d8e3d420SJean-Jacques Hiblot 			pr_err("User data enhanced area not HC WP group "
975ac9da0e0SDiego Santa Cruz 			       "size aligned\n");
976ac9da0e0SDiego Santa Cruz 			return -EINVAL;
977ac9da0e0SDiego Santa Cruz 		}
978ac9da0e0SDiego Santa Cruz 		part_attrs |= EXT_CSD_ENH_USR;
979ac9da0e0SDiego Santa Cruz 		enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size;
980ac9da0e0SDiego Santa Cruz 		if (mmc->high_capacity) {
981ac9da0e0SDiego Santa Cruz 			enh_start_addr = conf->user.enh_start;
982ac9da0e0SDiego Santa Cruz 		} else {
983ac9da0e0SDiego Santa Cruz 			enh_start_addr = (conf->user.enh_start << 9);
984ac9da0e0SDiego Santa Cruz 		}
985ac9da0e0SDiego Santa Cruz 	} else {
986ac9da0e0SDiego Santa Cruz 		enh_size_mult = 0;
987ac9da0e0SDiego Santa Cruz 		enh_start_addr = 0;
988ac9da0e0SDiego Santa Cruz 	}
989ac9da0e0SDiego Santa Cruz 	tot_enh_size_mult += enh_size_mult;
990ac9da0e0SDiego Santa Cruz 
991ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
992ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) {
993d8e3d420SJean-Jacques Hiblot 			pr_err("GP%i partition not HC WP group size "
994ac9da0e0SDiego Santa Cruz 			       "aligned\n", pidx+1);
995ac9da0e0SDiego Santa Cruz 			return -EINVAL;
996ac9da0e0SDiego Santa Cruz 		}
997ac9da0e0SDiego Santa Cruz 		gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size;
998ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) {
999ac9da0e0SDiego Santa Cruz 			part_attrs |= EXT_CSD_ENH_GP(pidx);
1000ac9da0e0SDiego Santa Cruz 			tot_enh_size_mult += gp_size_mult[pidx];
1001ac9da0e0SDiego Santa Cruz 		}
1002ac9da0e0SDiego Santa Cruz 	}
1003ac9da0e0SDiego Santa Cruz 
1004ac9da0e0SDiego Santa Cruz 	if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) {
1005d8e3d420SJean-Jacques Hiblot 		pr_err("Card does not support enhanced attribute\n");
1006ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1007ac9da0e0SDiego Santa Cruz 	}
1008ac9da0e0SDiego Santa Cruz 
1009ac9da0e0SDiego Santa Cruz 	err = mmc_send_ext_csd(mmc, ext_csd);
1010ac9da0e0SDiego Santa Cruz 	if (err)
1011ac9da0e0SDiego Santa Cruz 		return err;
1012ac9da0e0SDiego Santa Cruz 
1013ac9da0e0SDiego Santa Cruz 	max_enh_size_mult =
1014ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) +
1015ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) +
1016ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT];
1017ac9da0e0SDiego Santa Cruz 	if (tot_enh_size_mult > max_enh_size_mult) {
1018d8e3d420SJean-Jacques Hiblot 		pr_err("Total enhanced size exceeds maximum (%u > %u)\n",
1019ac9da0e0SDiego Santa Cruz 		       tot_enh_size_mult, max_enh_size_mult);
1020ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1021ac9da0e0SDiego Santa Cruz 	}
1022ac9da0e0SDiego Santa Cruz 
10238dda5b0eSDiego Santa Cruz 	/* The default value of EXT_CSD_WR_REL_SET is device
10248dda5b0eSDiego Santa Cruz 	 * dependent, the values can only be changed if the
10258dda5b0eSDiego Santa Cruz 	 * EXT_CSD_HS_CTRL_REL bit is set. The values can be
10268dda5b0eSDiego Santa Cruz 	 * changed only once and before partitioning is completed. */
10278dda5b0eSDiego Santa Cruz 	wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
10288dda5b0eSDiego Santa Cruz 	if (conf->user.wr_rel_change) {
10298dda5b0eSDiego Santa Cruz 		if (conf->user.wr_rel_set)
10308dda5b0eSDiego Santa Cruz 			wr_rel_set |= EXT_CSD_WR_DATA_REL_USR;
10318dda5b0eSDiego Santa Cruz 		else
10328dda5b0eSDiego Santa Cruz 			wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR;
10338dda5b0eSDiego Santa Cruz 	}
10348dda5b0eSDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
10358dda5b0eSDiego Santa Cruz 		if (conf->gp_part[pidx].wr_rel_change) {
10368dda5b0eSDiego Santa Cruz 			if (conf->gp_part[pidx].wr_rel_set)
10378dda5b0eSDiego Santa Cruz 				wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx);
10388dda5b0eSDiego Santa Cruz 			else
10398dda5b0eSDiego Santa Cruz 				wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx);
10408dda5b0eSDiego Santa Cruz 		}
10418dda5b0eSDiego Santa Cruz 	}
10428dda5b0eSDiego Santa Cruz 
10438dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] &&
10448dda5b0eSDiego Santa Cruz 	    !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) {
10458dda5b0eSDiego Santa Cruz 		puts("Card does not support host controlled partition write "
10468dda5b0eSDiego Santa Cruz 		     "reliability settings\n");
10478dda5b0eSDiego Santa Cruz 		return -EMEDIUMTYPE;
10488dda5b0eSDiego Santa Cruz 	}
10498dda5b0eSDiego Santa Cruz 
1050ac9da0e0SDiego Santa Cruz 	if (ext_csd[EXT_CSD_PARTITION_SETTING] &
1051ac9da0e0SDiego Santa Cruz 	    EXT_CSD_PARTITION_SETTING_COMPLETED) {
1052d8e3d420SJean-Jacques Hiblot 		pr_err("Card already partitioned\n");
1053ac9da0e0SDiego Santa Cruz 		return -EPERM;
1054ac9da0e0SDiego Santa Cruz 	}
1055ac9da0e0SDiego Santa Cruz 
1056ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_CHECK)
1057ac9da0e0SDiego Santa Cruz 		return 0;
1058ac9da0e0SDiego Santa Cruz 
1059ac9da0e0SDiego Santa Cruz 	/* Partitioning requires high-capacity size definitions */
1060ac9da0e0SDiego Santa Cruz 	if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) {
1061ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1062ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ERASE_GROUP_DEF, 1);
1063ac9da0e0SDiego Santa Cruz 
1064ac9da0e0SDiego Santa Cruz 		if (err)
1065ac9da0e0SDiego Santa Cruz 			return err;
1066ac9da0e0SDiego Santa Cruz 
1067ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1068ac9da0e0SDiego Santa Cruz 
1069ac9da0e0SDiego Santa Cruz 		/* update erase group size to be high-capacity */
1070ac9da0e0SDiego Santa Cruz 		mmc->erase_grp_size =
1071ac9da0e0SDiego Santa Cruz 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1072ac9da0e0SDiego Santa Cruz 
1073ac9da0e0SDiego Santa Cruz 	}
1074ac9da0e0SDiego Santa Cruz 
1075ac9da0e0SDiego Santa Cruz 	/* all OK, write the configuration */
1076ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 4; i++) {
1077ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1078ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_START_ADDR+i,
1079ac9da0e0SDiego Santa Cruz 				 (enh_start_addr >> (i*8)) & 0xFF);
1080ac9da0e0SDiego Santa Cruz 		if (err)
1081ac9da0e0SDiego Santa Cruz 			return err;
1082ac9da0e0SDiego Santa Cruz 	}
1083ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 3; i++) {
1084ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1085ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_SIZE_MULT+i,
1086ac9da0e0SDiego Santa Cruz 				 (enh_size_mult >> (i*8)) & 0xFF);
1087ac9da0e0SDiego Santa Cruz 		if (err)
1088ac9da0e0SDiego Santa Cruz 			return err;
1089ac9da0e0SDiego Santa Cruz 	}
1090ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
1091ac9da0e0SDiego Santa Cruz 		for (i = 0; i < 3; i++) {
1092ac9da0e0SDiego Santa Cruz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1093ac9da0e0SDiego Santa Cruz 					 EXT_CSD_GP_SIZE_MULT+pidx*3+i,
1094ac9da0e0SDiego Santa Cruz 					 (gp_size_mult[pidx] >> (i*8)) & 0xFF);
1095ac9da0e0SDiego Santa Cruz 			if (err)
1096ac9da0e0SDiego Santa Cruz 				return err;
1097ac9da0e0SDiego Santa Cruz 		}
1098ac9da0e0SDiego Santa Cruz 	}
1099ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1100ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs);
1101ac9da0e0SDiego Santa Cruz 	if (err)
1102ac9da0e0SDiego Santa Cruz 		return err;
1103ac9da0e0SDiego Santa Cruz 
1104ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_SET)
1105ac9da0e0SDiego Santa Cruz 		return 0;
1106ac9da0e0SDiego Santa Cruz 
11078dda5b0eSDiego Santa Cruz 	/* The WR_REL_SET is a write-once register but shall be
11088dda5b0eSDiego Santa Cruz 	 * written before setting PART_SETTING_COMPLETED. As it is
11098dda5b0eSDiego Santa Cruz 	 * write-once we can only write it when completing the
11108dda5b0eSDiego Santa Cruz 	 * partitioning. */
11118dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) {
11128dda5b0eSDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
11138dda5b0eSDiego Santa Cruz 				 EXT_CSD_WR_REL_SET, wr_rel_set);
11148dda5b0eSDiego Santa Cruz 		if (err)
11158dda5b0eSDiego Santa Cruz 			return err;
11168dda5b0eSDiego Santa Cruz 	}
11178dda5b0eSDiego Santa Cruz 
1118ac9da0e0SDiego Santa Cruz 	/* Setting PART_SETTING_COMPLETED confirms the partition
1119ac9da0e0SDiego Santa Cruz 	 * configuration but it only becomes effective after power
1120ac9da0e0SDiego Santa Cruz 	 * cycle, so we do not adjust the partition related settings
1121ac9da0e0SDiego Santa Cruz 	 * in the mmc struct. */
1122ac9da0e0SDiego Santa Cruz 
1123ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1124ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING,
1125ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING_COMPLETED);
1126ac9da0e0SDiego Santa Cruz 	if (err)
1127ac9da0e0SDiego Santa Cruz 		return err;
1128ac9da0e0SDiego Santa Cruz 
1129ac9da0e0SDiego Santa Cruz 	return 0;
1130ac9da0e0SDiego Santa Cruz }
1131cf17789eSJean-Jacques Hiblot #endif
1132ac9da0e0SDiego Santa Cruz 
1133e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
113448972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
113548972d90SThierry Reding {
113648972d90SThierry Reding 	int cd;
113748972d90SThierry Reding 
113848972d90SThierry Reding 	cd = board_mmc_getcd(mmc);
113948972d90SThierry Reding 
1140d4e1da4eSPeter Korsgaard 	if (cd < 0) {
114193bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getcd)
114293bfd616SPantelis Antoniou 			cd = mmc->cfg->ops->getcd(mmc);
1143d4e1da4eSPeter Korsgaard 		else
1144d4e1da4eSPeter Korsgaard 			cd = 1;
1145d4e1da4eSPeter Korsgaard 	}
114648972d90SThierry Reding 
114748972d90SThierry Reding 	return cd;
114848972d90SThierry Reding }
11498ca51e51SSimon Glass #endif
115048972d90SThierry Reding 
115162d77ceaSMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY)
1152fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
1153272cc70bSAndy Fleming {
1154272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1155272cc70bSAndy Fleming 	struct mmc_data data;
1156272cc70bSAndy Fleming 
1157272cc70bSAndy Fleming 	/* Switch the frequency */
1158272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
1159272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1160272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
1161272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
1162272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
1163272cc70bSAndy Fleming 
1164272cc70bSAndy Fleming 	data.dest = (char *)resp;
1165272cc70bSAndy Fleming 	data.blocksize = 64;
1166272cc70bSAndy Fleming 	data.blocks = 1;
1167272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
1168272cc70bSAndy Fleming 
1169272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
1170272cc70bSAndy Fleming }
1171272cc70bSAndy Fleming 
1172d0c221feSJean-Jacques Hiblot static int sd_get_capabilities(struct mmc *mmc)
1173272cc70bSAndy Fleming {
1174272cc70bSAndy Fleming 	int err;
1175272cc70bSAndy Fleming 	struct mmc_cmd cmd;
117618e7c8f6SSuniel Mahesh 	ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2);
117718e7c8f6SSuniel Mahesh 	ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16);
1178272cc70bSAndy Fleming 	struct mmc_data data;
1179272cc70bSAndy Fleming 	int timeout;
1180f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1181c10b85d6SJean-Jacques Hiblot 	u32 sd3_bus_mode;
1182f99c2efeSJean-Jacques Hiblot #endif
1183272cc70bSAndy Fleming 
118400e446faSJean-Jacques Hiblot 	mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(SD_LEGACY);
1185272cc70bSAndy Fleming 
1186d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
1187d52ebf10SThomas Chou 		return 0;
1188d52ebf10SThomas Chou 
1189272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
1190272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
1191272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1192272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1193272cc70bSAndy Fleming 
1194272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1195272cc70bSAndy Fleming 
1196272cc70bSAndy Fleming 	if (err)
1197272cc70bSAndy Fleming 		return err;
1198272cc70bSAndy Fleming 
1199272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
1200272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1201272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1202272cc70bSAndy Fleming 
1203272cc70bSAndy Fleming 	timeout = 3;
1204272cc70bSAndy Fleming 
1205272cc70bSAndy Fleming retry_scr:
1206f781dd38SAnton staaf 	data.dest = (char *)scr;
1207272cc70bSAndy Fleming 	data.blocksize = 8;
1208272cc70bSAndy Fleming 	data.blocks = 1;
1209272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
1210272cc70bSAndy Fleming 
1211272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
1212272cc70bSAndy Fleming 
1213272cc70bSAndy Fleming 	if (err) {
1214272cc70bSAndy Fleming 		if (timeout--)
1215272cc70bSAndy Fleming 			goto retry_scr;
1216272cc70bSAndy Fleming 
1217272cc70bSAndy Fleming 		return err;
1218272cc70bSAndy Fleming 	}
1219272cc70bSAndy Fleming 
12204e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
12214e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
1222272cc70bSAndy Fleming 
1223272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
1224272cc70bSAndy Fleming 	case 0:
1225272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1226272cc70bSAndy Fleming 		break;
1227272cc70bSAndy Fleming 	case 1:
1228272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_10;
1229272cc70bSAndy Fleming 		break;
1230272cc70bSAndy Fleming 	case 2:
1231272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
12321741c64dSJaehoon Chung 		if ((mmc->scr[0] >> 15) & 0x1)
12331741c64dSJaehoon Chung 			mmc->version = SD_VERSION_3;
1234272cc70bSAndy Fleming 		break;
1235272cc70bSAndy Fleming 	default:
1236272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1237272cc70bSAndy Fleming 		break;
1238272cc70bSAndy Fleming 	}
1239272cc70bSAndy Fleming 
1240b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
1241b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
1242b44c7083SAlagu Sankar 
1243272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
1244272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
1245272cc70bSAndy Fleming 		return 0;
1246272cc70bSAndy Fleming 
1247272cc70bSAndy Fleming 	timeout = 4;
1248272cc70bSAndy Fleming 	while (timeout--) {
1249272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
1250f781dd38SAnton staaf 				(u8 *)switch_status);
1251272cc70bSAndy Fleming 
1252272cc70bSAndy Fleming 		if (err)
1253272cc70bSAndy Fleming 			return err;
1254272cc70bSAndy Fleming 
1255272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
12564e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
1257272cc70bSAndy Fleming 			break;
1258272cc70bSAndy Fleming 	}
1259272cc70bSAndy Fleming 
1260272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
1261d0c221feSJean-Jacques Hiblot 	if (__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)
1262d0c221feSJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(SD_HS);
1263272cc70bSAndy Fleming 
1264f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1265c10b85d6SJean-Jacques Hiblot 	/* Version before 3.0 don't support UHS modes */
1266c10b85d6SJean-Jacques Hiblot 	if (mmc->version < SD_VERSION_3)
1267c10b85d6SJean-Jacques Hiblot 		return 0;
1268c10b85d6SJean-Jacques Hiblot 
1269c10b85d6SJean-Jacques Hiblot 	sd3_bus_mode = __be32_to_cpu(switch_status[3]) >> 16 & 0x1f;
1270c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR104)
1271c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR104);
1272c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR50)
1273c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR50);
1274c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR25)
1275c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR25);
1276c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR12)
1277c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR12);
1278c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_DDR50)
1279c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_DDR50);
1280f99c2efeSJean-Jacques Hiblot #endif
1281c10b85d6SJean-Jacques Hiblot 
12822c3fbf4cSMacpaul Lin 	return 0;
1283d0c221feSJean-Jacques Hiblot }
1284d0c221feSJean-Jacques Hiblot 
1285d0c221feSJean-Jacques Hiblot static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode)
1286d0c221feSJean-Jacques Hiblot {
1287d0c221feSJean-Jacques Hiblot 	int err;
1288d0c221feSJean-Jacques Hiblot 
1289d0c221feSJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
1290c10b85d6SJean-Jacques Hiblot 	int speed;
12912c3fbf4cSMacpaul Lin 
1292cf345760SMarek Vasut 	/* SD version 1.00 and 1.01 does not support CMD 6 */
1293cf345760SMarek Vasut 	if (mmc->version == SD_VERSION_1_0)
1294cf345760SMarek Vasut 		return 0;
1295cf345760SMarek Vasut 
1296c10b85d6SJean-Jacques Hiblot 	switch (mode) {
1297c10b85d6SJean-Jacques Hiblot 	case SD_LEGACY:
1298c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR12_BUS_SPEED;
1299c10b85d6SJean-Jacques Hiblot 		break;
1300c10b85d6SJean-Jacques Hiblot 	case SD_HS:
1301baef2070SJean-Jacques Hiblot 		speed = HIGH_SPEED_BUS_SPEED;
1302baef2070SJean-Jacques Hiblot 		break;
1303baef2070SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1304baef2070SJean-Jacques Hiblot 	case UHS_SDR12:
1305baef2070SJean-Jacques Hiblot 		speed = UHS_SDR12_BUS_SPEED;
1306baef2070SJean-Jacques Hiblot 		break;
1307c10b85d6SJean-Jacques Hiblot 	case UHS_SDR25:
1308c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR25_BUS_SPEED;
1309c10b85d6SJean-Jacques Hiblot 		break;
1310c10b85d6SJean-Jacques Hiblot 	case UHS_SDR50:
1311c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR50_BUS_SPEED;
1312c10b85d6SJean-Jacques Hiblot 		break;
1313c10b85d6SJean-Jacques Hiblot 	case UHS_DDR50:
1314c10b85d6SJean-Jacques Hiblot 		speed = UHS_DDR50_BUS_SPEED;
1315c10b85d6SJean-Jacques Hiblot 		break;
1316c10b85d6SJean-Jacques Hiblot 	case UHS_SDR104:
1317c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR104_BUS_SPEED;
1318c10b85d6SJean-Jacques Hiblot 		break;
1319baef2070SJean-Jacques Hiblot #endif
1320c10b85d6SJean-Jacques Hiblot 	default:
1321c10b85d6SJean-Jacques Hiblot 		return -EINVAL;
1322c10b85d6SJean-Jacques Hiblot 	}
1323c10b85d6SJean-Jacques Hiblot 
1324c10b85d6SJean-Jacques Hiblot 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, speed, (u8 *)switch_status);
1325272cc70bSAndy Fleming 	if (err)
1326272cc70bSAndy Fleming 		return err;
1327272cc70bSAndy Fleming 
1328a0276f3eSJean-Jacques Hiblot 	if (((__be32_to_cpu(switch_status[4]) >> 24) & 0xF) != speed)
1329d0c221feSJean-Jacques Hiblot 		return -ENOTSUPP;
1330d0c221feSJean-Jacques Hiblot 
1331d0c221feSJean-Jacques Hiblot 	return 0;
1332d0c221feSJean-Jacques Hiblot }
1333d0c221feSJean-Jacques Hiblot 
1334ec360e64SMarek Vasut static int sd_select_bus_width(struct mmc *mmc, int w)
1335d0c221feSJean-Jacques Hiblot {
1336d0c221feSJean-Jacques Hiblot 	int err;
1337d0c221feSJean-Jacques Hiblot 	struct mmc_cmd cmd;
1338d0c221feSJean-Jacques Hiblot 
1339d0c221feSJean-Jacques Hiblot 	if ((w != 4) && (w != 1))
1340d0c221feSJean-Jacques Hiblot 		return -EINVAL;
1341d0c221feSJean-Jacques Hiblot 
1342d0c221feSJean-Jacques Hiblot 	cmd.cmdidx = MMC_CMD_APP_CMD;
1343d0c221feSJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
1344d0c221feSJean-Jacques Hiblot 	cmd.cmdarg = mmc->rca << 16;
1345d0c221feSJean-Jacques Hiblot 
1346d0c221feSJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
1347d0c221feSJean-Jacques Hiblot 	if (err)
1348d0c221feSJean-Jacques Hiblot 		return err;
1349d0c221feSJean-Jacques Hiblot 
1350d0c221feSJean-Jacques Hiblot 	cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
1351d0c221feSJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
1352d0c221feSJean-Jacques Hiblot 	if (w == 4)
1353d0c221feSJean-Jacques Hiblot 		cmd.cmdarg = 2;
1354d0c221feSJean-Jacques Hiblot 	else if (w == 1)
1355d0c221feSJean-Jacques Hiblot 		cmd.cmdarg = 0;
1356d0c221feSJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
1357d0c221feSJean-Jacques Hiblot 	if (err)
1358d0c221feSJean-Jacques Hiblot 		return err;
1359272cc70bSAndy Fleming 
1360272cc70bSAndy Fleming 	return 0;
1361272cc70bSAndy Fleming }
136262d77ceaSMarek Vasut #endif
1363272cc70bSAndy Fleming 
13645b2e72f3SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE)
13653697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc)
13663697e599SPeng Fan {
13675b2e72f3SJean-Jacques Hiblot 	static const unsigned int sd_au_size[] = {
13685b2e72f3SJean-Jacques Hiblot 		0,		SZ_16K / 512,		SZ_32K / 512,
13695b2e72f3SJean-Jacques Hiblot 		SZ_64K / 512,	SZ_128K / 512,		SZ_256K / 512,
13705b2e72f3SJean-Jacques Hiblot 		SZ_512K / 512,	SZ_1M / 512,		SZ_2M / 512,
13715b2e72f3SJean-Jacques Hiblot 		SZ_4M / 512,	SZ_8M / 512,		(SZ_8M + SZ_4M) / 512,
13725b2e72f3SJean-Jacques Hiblot 		SZ_16M / 512,	(SZ_16M + SZ_8M) / 512,	SZ_32M / 512,
13735b2e72f3SJean-Jacques Hiblot 		SZ_64M / 512,
13745b2e72f3SJean-Jacques Hiblot 	};
13753697e599SPeng Fan 	int err, i;
13763697e599SPeng Fan 	struct mmc_cmd cmd;
13773697e599SPeng Fan 	ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16);
13783697e599SPeng Fan 	struct mmc_data data;
13793697e599SPeng Fan 	int timeout = 3;
13803697e599SPeng Fan 	unsigned int au, eo, et, es;
13813697e599SPeng Fan 
13823697e599SPeng Fan 	cmd.cmdidx = MMC_CMD_APP_CMD;
13833697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
13843697e599SPeng Fan 	cmd.cmdarg = mmc->rca << 16;
13853697e599SPeng Fan 
13863697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, NULL);
13873697e599SPeng Fan 	if (err)
13883697e599SPeng Fan 		return err;
13893697e599SPeng Fan 
13903697e599SPeng Fan 	cmd.cmdidx = SD_CMD_APP_SD_STATUS;
13913697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
13923697e599SPeng Fan 	cmd.cmdarg = 0;
13933697e599SPeng Fan 
13943697e599SPeng Fan retry_ssr:
13953697e599SPeng Fan 	data.dest = (char *)ssr;
13963697e599SPeng Fan 	data.blocksize = 64;
13973697e599SPeng Fan 	data.blocks = 1;
13983697e599SPeng Fan 	data.flags = MMC_DATA_READ;
13993697e599SPeng Fan 
14003697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, &data);
14013697e599SPeng Fan 	if (err) {
14023697e599SPeng Fan 		if (timeout--)
14033697e599SPeng Fan 			goto retry_ssr;
14043697e599SPeng Fan 
14053697e599SPeng Fan 		return err;
14063697e599SPeng Fan 	}
14073697e599SPeng Fan 
14083697e599SPeng Fan 	for (i = 0; i < 16; i++)
14093697e599SPeng Fan 		ssr[i] = be32_to_cpu(ssr[i]);
14103697e599SPeng Fan 
14113697e599SPeng Fan 	au = (ssr[2] >> 12) & 0xF;
14123697e599SPeng Fan 	if ((au <= 9) || (mmc->version == SD_VERSION_3)) {
14133697e599SPeng Fan 		mmc->ssr.au = sd_au_size[au];
14143697e599SPeng Fan 		es = (ssr[3] >> 24) & 0xFF;
14153697e599SPeng Fan 		es |= (ssr[2] & 0xFF) << 8;
14163697e599SPeng Fan 		et = (ssr[3] >> 18) & 0x3F;
14173697e599SPeng Fan 		if (es && et) {
14183697e599SPeng Fan 			eo = (ssr[3] >> 16) & 0x3;
14193697e599SPeng Fan 			mmc->ssr.erase_timeout = (et * 1000) / es;
14203697e599SPeng Fan 			mmc->ssr.erase_offset = eo * 1000;
14213697e599SPeng Fan 		}
14223697e599SPeng Fan 	} else {
1423d4d64889SMasahiro Yamada 		pr_debug("Invalid Allocation Unit Size.\n");
14243697e599SPeng Fan 	}
14253697e599SPeng Fan 
14263697e599SPeng Fan 	return 0;
14273697e599SPeng Fan }
14285b2e72f3SJean-Jacques Hiblot #endif
1429272cc70bSAndy Fleming /* frequency bases */
1430272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
14315f837c2cSMike Frysinger static const int fbase[] = {
1432272cc70bSAndy Fleming 	10000,
1433272cc70bSAndy Fleming 	100000,
1434272cc70bSAndy Fleming 	1000000,
1435272cc70bSAndy Fleming 	10000000,
1436272cc70bSAndy Fleming };
1437272cc70bSAndy Fleming 
1438272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
1439272cc70bSAndy Fleming  * to platforms without floating point.
1440272cc70bSAndy Fleming  */
144161fe076fSSimon Glass static const u8 multipliers[] = {
1442272cc70bSAndy Fleming 	0,	/* reserved */
1443272cc70bSAndy Fleming 	10,
1444272cc70bSAndy Fleming 	12,
1445272cc70bSAndy Fleming 	13,
1446272cc70bSAndy Fleming 	15,
1447272cc70bSAndy Fleming 	20,
1448272cc70bSAndy Fleming 	25,
1449272cc70bSAndy Fleming 	30,
1450272cc70bSAndy Fleming 	35,
1451272cc70bSAndy Fleming 	40,
1452272cc70bSAndy Fleming 	45,
1453272cc70bSAndy Fleming 	50,
1454272cc70bSAndy Fleming 	55,
1455272cc70bSAndy Fleming 	60,
1456272cc70bSAndy Fleming 	70,
1457272cc70bSAndy Fleming 	80,
1458272cc70bSAndy Fleming };
1459272cc70bSAndy Fleming 
1460d0c221feSJean-Jacques Hiblot static inline int bus_width(uint cap)
1461d0c221feSJean-Jacques Hiblot {
1462d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_8BIT)
1463d0c221feSJean-Jacques Hiblot 		return 8;
1464d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_4BIT)
1465d0c221feSJean-Jacques Hiblot 		return 4;
1466d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_1BIT)
1467d0c221feSJean-Jacques Hiblot 		return 1;
1468d8e3d420SJean-Jacques Hiblot 	pr_warn("invalid bus witdh capability 0x%x\n", cap);
1469d0c221feSJean-Jacques Hiblot 	return 0;
1470d0c221feSJean-Jacques Hiblot }
1471d0c221feSJean-Jacques Hiblot 
1472e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
1473f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
1474ec841209SKishon Vijay Abraham I static int mmc_execute_tuning(struct mmc *mmc, uint opcode)
1475ec841209SKishon Vijay Abraham I {
1476ec841209SKishon Vijay Abraham I 	return -ENOTSUPP;
1477ec841209SKishon Vijay Abraham I }
1478f99c2efeSJean-Jacques Hiblot #endif
1479ec841209SKishon Vijay Abraham I 
1480318a7a57SJean-Jacques Hiblot static void mmc_send_init_stream(struct mmc *mmc)
1481318a7a57SJean-Jacques Hiblot {
1482318a7a57SJean-Jacques Hiblot }
1483318a7a57SJean-Jacques Hiblot 
14842a4d212fSKishon Vijay Abraham I static int mmc_set_ios(struct mmc *mmc)
1485272cc70bSAndy Fleming {
14862a4d212fSKishon Vijay Abraham I 	int ret = 0;
14872a4d212fSKishon Vijay Abraham I 
148893bfd616SPantelis Antoniou 	if (mmc->cfg->ops->set_ios)
14892a4d212fSKishon Vijay Abraham I 		ret = mmc->cfg->ops->set_ios(mmc);
14902a4d212fSKishon Vijay Abraham I 
14912a4d212fSKishon Vijay Abraham I 	return ret;
1492272cc70bSAndy Fleming }
14938ca51e51SSimon Glass #endif
1494272cc70bSAndy Fleming 
149535f67820SKishon Vijay Abraham I int mmc_set_clock(struct mmc *mmc, uint clock, bool disable)
1496272cc70bSAndy Fleming {
1497c0fafe64SJaehoon Chung 	if (!disable) {
149893bfd616SPantelis Antoniou 		if (clock > mmc->cfg->f_max)
149993bfd616SPantelis Antoniou 			clock = mmc->cfg->f_max;
1500272cc70bSAndy Fleming 
150193bfd616SPantelis Antoniou 		if (clock < mmc->cfg->f_min)
150293bfd616SPantelis Antoniou 			clock = mmc->cfg->f_min;
15039546eb92SJaehoon Chung 	}
1504272cc70bSAndy Fleming 
1505272cc70bSAndy Fleming 	mmc->clock = clock;
150635f67820SKishon Vijay Abraham I 	mmc->clk_disable = disable;
1507272cc70bSAndy Fleming 
1508d2faadb5SJaehoon Chung 	debug("clock is %s (%dHz)\n", disable ? "disabled" : "enabled", clock);
1509d2faadb5SJaehoon Chung 
15102a4d212fSKishon Vijay Abraham I 	return mmc_set_ios(mmc);
1511272cc70bSAndy Fleming }
1512272cc70bSAndy Fleming 
15132a4d212fSKishon Vijay Abraham I static int mmc_set_bus_width(struct mmc *mmc, uint width)
1514272cc70bSAndy Fleming {
1515272cc70bSAndy Fleming 	mmc->bus_width = width;
1516272cc70bSAndy Fleming 
15172a4d212fSKishon Vijay Abraham I 	return mmc_set_ios(mmc);
1518272cc70bSAndy Fleming }
1519272cc70bSAndy Fleming 
15204c9d2aaaSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG)
15214c9d2aaaSJean-Jacques Hiblot /*
15224c9d2aaaSJean-Jacques Hiblot  * helper function to display the capabilities in a human
15234c9d2aaaSJean-Jacques Hiblot  * friendly manner. The capabilities include bus width and
15244c9d2aaaSJean-Jacques Hiblot  * supported modes.
15254c9d2aaaSJean-Jacques Hiblot  */
15264c9d2aaaSJean-Jacques Hiblot void mmc_dump_capabilities(const char *text, uint caps)
15274c9d2aaaSJean-Jacques Hiblot {
15284c9d2aaaSJean-Jacques Hiblot 	enum bus_mode mode;
15294c9d2aaaSJean-Jacques Hiblot 
1530d4d64889SMasahiro Yamada 	pr_debug("%s: widths [", text);
15314c9d2aaaSJean-Jacques Hiblot 	if (caps & MMC_MODE_8BIT)
1532d4d64889SMasahiro Yamada 		pr_debug("8, ");
15334c9d2aaaSJean-Jacques Hiblot 	if (caps & MMC_MODE_4BIT)
1534d4d64889SMasahiro Yamada 		pr_debug("4, ");
1535d0c221feSJean-Jacques Hiblot 	if (caps & MMC_MODE_1BIT)
1536d4d64889SMasahiro Yamada 		pr_debug("1, ");
1537d4d64889SMasahiro Yamada 	pr_debug("\b\b] modes [");
15384c9d2aaaSJean-Jacques Hiblot 	for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++)
15394c9d2aaaSJean-Jacques Hiblot 		if (MMC_CAP(mode) & caps)
1540d4d64889SMasahiro Yamada 			pr_debug("%s, ", mmc_mode_name(mode));
1541d4d64889SMasahiro Yamada 	pr_debug("\b\b]\n");
15424c9d2aaaSJean-Jacques Hiblot }
15434c9d2aaaSJean-Jacques Hiblot #endif
15444c9d2aaaSJean-Jacques Hiblot 
1545d0c221feSJean-Jacques Hiblot struct mode_width_tuning {
1546d0c221feSJean-Jacques Hiblot 	enum bus_mode mode;
1547d0c221feSJean-Jacques Hiblot 	uint widths;
1548f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
1549634d4849SKishon Vijay Abraham I 	uint tuning;
1550f99c2efeSJean-Jacques Hiblot #endif
1551d0c221feSJean-Jacques Hiblot };
1552d0c221feSJean-Jacques Hiblot 
1553f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE)
1554bc1e3272SJean-Jacques Hiblot int mmc_voltage_to_mv(enum mmc_voltage voltage)
1555bc1e3272SJean-Jacques Hiblot {
1556bc1e3272SJean-Jacques Hiblot 	switch (voltage) {
1557bc1e3272SJean-Jacques Hiblot 	case MMC_SIGNAL_VOLTAGE_000: return 0;
1558bc1e3272SJean-Jacques Hiblot 	case MMC_SIGNAL_VOLTAGE_330: return 3300;
1559bc1e3272SJean-Jacques Hiblot 	case MMC_SIGNAL_VOLTAGE_180: return 1800;
1560bc1e3272SJean-Jacques Hiblot 	case MMC_SIGNAL_VOLTAGE_120: return 1200;
1561bc1e3272SJean-Jacques Hiblot 	}
1562bc1e3272SJean-Jacques Hiblot 	return -EINVAL;
1563bc1e3272SJean-Jacques Hiblot }
1564bc1e3272SJean-Jacques Hiblot 
1565aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage)
1566aff5d3c8SKishon Vijay Abraham I {
1567bc1e3272SJean-Jacques Hiblot 	int err;
1568bc1e3272SJean-Jacques Hiblot 
1569bc1e3272SJean-Jacques Hiblot 	if (mmc->signal_voltage == signal_voltage)
1570bc1e3272SJean-Jacques Hiblot 		return 0;
1571bc1e3272SJean-Jacques Hiblot 
1572aff5d3c8SKishon Vijay Abraham I 	mmc->signal_voltage = signal_voltage;
1573bc1e3272SJean-Jacques Hiblot 	err = mmc_set_ios(mmc);
1574bc1e3272SJean-Jacques Hiblot 	if (err)
1575d4d64889SMasahiro Yamada 		pr_debug("unable to set voltage (err %d)\n", err);
1576bc1e3272SJean-Jacques Hiblot 
1577bc1e3272SJean-Jacques Hiblot 	return err;
1578aff5d3c8SKishon Vijay Abraham I }
1579f99c2efeSJean-Jacques Hiblot #else
1580f99c2efeSJean-Jacques Hiblot static inline int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage)
1581f99c2efeSJean-Jacques Hiblot {
1582f99c2efeSJean-Jacques Hiblot 	return 0;
1583f99c2efeSJean-Jacques Hiblot }
1584f99c2efeSJean-Jacques Hiblot #endif
1585aff5d3c8SKishon Vijay Abraham I 
158662d77ceaSMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY)
1587d0c221feSJean-Jacques Hiblot static const struct mode_width_tuning sd_modes_by_pref[] = {
1588f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1589f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
1590d0c221feSJean-Jacques Hiblot 	{
1591c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR104,
1592c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1593c10b85d6SJean-Jacques Hiblot 		.tuning = MMC_CMD_SEND_TUNING_BLOCK
1594c10b85d6SJean-Jacques Hiblot 	},
1595f99c2efeSJean-Jacques Hiblot #endif
1596c10b85d6SJean-Jacques Hiblot 	{
1597c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR50,
1598c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1599c10b85d6SJean-Jacques Hiblot 	},
1600c10b85d6SJean-Jacques Hiblot 	{
1601c10b85d6SJean-Jacques Hiblot 		.mode = UHS_DDR50,
1602c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1603c10b85d6SJean-Jacques Hiblot 	},
1604c10b85d6SJean-Jacques Hiblot 	{
1605c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR25,
1606c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1607c10b85d6SJean-Jacques Hiblot 	},
1608f99c2efeSJean-Jacques Hiblot #endif
1609c10b85d6SJean-Jacques Hiblot 	{
1610d0c221feSJean-Jacques Hiblot 		.mode = SD_HS,
1611d0c221feSJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1612d0c221feSJean-Jacques Hiblot 	},
1613f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1614d0c221feSJean-Jacques Hiblot 	{
1615c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR12,
1616c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1617c10b85d6SJean-Jacques Hiblot 	},
1618f99c2efeSJean-Jacques Hiblot #endif
1619c10b85d6SJean-Jacques Hiblot 	{
1620d0c221feSJean-Jacques Hiblot 		.mode = SD_LEGACY,
1621d0c221feSJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1622d0c221feSJean-Jacques Hiblot 	}
1623d0c221feSJean-Jacques Hiblot };
1624d0c221feSJean-Jacques Hiblot 
1625d0c221feSJean-Jacques Hiblot #define for_each_sd_mode_by_pref(caps, mwt) \
1626d0c221feSJean-Jacques Hiblot 	for (mwt = sd_modes_by_pref;\
1627d0c221feSJean-Jacques Hiblot 	     mwt < sd_modes_by_pref + ARRAY_SIZE(sd_modes_by_pref);\
1628d0c221feSJean-Jacques Hiblot 	     mwt++) \
1629d0c221feSJean-Jacques Hiblot 		if (caps & MMC_CAP(mwt->mode))
1630d0c221feSJean-Jacques Hiblot 
163101298da3SJean-Jacques Hiblot static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps)
16328ac8a263SJean-Jacques Hiblot {
16338ac8a263SJean-Jacques Hiblot 	int err;
1634d0c221feSJean-Jacques Hiblot 	uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT};
1635d0c221feSJean-Jacques Hiblot 	const struct mode_width_tuning *mwt;
1636f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1637c10b85d6SJean-Jacques Hiblot 	bool uhs_en = (mmc->ocr & OCR_S18R) ? true : false;
1638f99c2efeSJean-Jacques Hiblot #else
1639f99c2efeSJean-Jacques Hiblot 	bool uhs_en = false;
1640f99c2efeSJean-Jacques Hiblot #endif
1641c10b85d6SJean-Jacques Hiblot 	uint caps;
1642c10b85d6SJean-Jacques Hiblot 
164352d241dfSJean-Jacques Hiblot #ifdef DEBUG
164452d241dfSJean-Jacques Hiblot 	mmc_dump_capabilities("sd card", card_caps);
16451da8eb59SJean-Jacques Hiblot 	mmc_dump_capabilities("host", mmc->host_caps);
164652d241dfSJean-Jacques Hiblot #endif
16478ac8a263SJean-Jacques Hiblot 
16488ac8a263SJean-Jacques Hiblot 	/* Restrict card's capabilities by what the host can do */
16491da8eb59SJean-Jacques Hiblot 	caps = card_caps & mmc->host_caps;
16508ac8a263SJean-Jacques Hiblot 
1651c10b85d6SJean-Jacques Hiblot 	if (!uhs_en)
1652c10b85d6SJean-Jacques Hiblot 		caps &= ~UHS_CAPS;
1653c10b85d6SJean-Jacques Hiblot 
1654c10b85d6SJean-Jacques Hiblot 	for_each_sd_mode_by_pref(caps, mwt) {
1655d0c221feSJean-Jacques Hiblot 		uint *w;
16568ac8a263SJean-Jacques Hiblot 
1657d0c221feSJean-Jacques Hiblot 		for (w = widths; w < widths + ARRAY_SIZE(widths); w++) {
1658c10b85d6SJean-Jacques Hiblot 			if (*w & caps & mwt->widths) {
1659d4d64889SMasahiro Yamada 				pr_debug("trying mode %s width %d (at %d MHz)\n",
1660d0c221feSJean-Jacques Hiblot 					 mmc_mode_name(mwt->mode),
1661d0c221feSJean-Jacques Hiblot 					 bus_width(*w),
1662d0c221feSJean-Jacques Hiblot 					 mmc_mode2freq(mmc, mwt->mode) / 1000000);
1663d0c221feSJean-Jacques Hiblot 
1664d0c221feSJean-Jacques Hiblot 				/* configure the bus width (card + host) */
1665d0c221feSJean-Jacques Hiblot 				err = sd_select_bus_width(mmc, bus_width(*w));
16668ac8a263SJean-Jacques Hiblot 				if (err)
1667d0c221feSJean-Jacques Hiblot 					goto error;
1668d0c221feSJean-Jacques Hiblot 				mmc_set_bus_width(mmc, bus_width(*w));
16698ac8a263SJean-Jacques Hiblot 
1670d0c221feSJean-Jacques Hiblot 				/* configure the bus mode (card) */
1671d0c221feSJean-Jacques Hiblot 				err = sd_set_card_speed(mmc, mwt->mode);
16728ac8a263SJean-Jacques Hiblot 				if (err)
1673d0c221feSJean-Jacques Hiblot 					goto error;
16748ac8a263SJean-Jacques Hiblot 
1675d0c221feSJean-Jacques Hiblot 				/* configure the bus mode (host) */
1676d0c221feSJean-Jacques Hiblot 				mmc_select_mode(mmc, mwt->mode);
167765117182SJaehoon Chung 				mmc_set_clock(mmc, mmc->tran_speed,
167865117182SJaehoon Chung 						MMC_CLK_ENABLE);
16798ac8a263SJean-Jacques Hiblot 
1680f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
1681c10b85d6SJean-Jacques Hiblot 				/* execute tuning if needed */
1682c10b85d6SJean-Jacques Hiblot 				if (mwt->tuning && !mmc_host_is_spi(mmc)) {
1683c10b85d6SJean-Jacques Hiblot 					err = mmc_execute_tuning(mmc,
1684c10b85d6SJean-Jacques Hiblot 								 mwt->tuning);
1685c10b85d6SJean-Jacques Hiblot 					if (err) {
1686d4d64889SMasahiro Yamada 						pr_debug("tuning failed\n");
1687c10b85d6SJean-Jacques Hiblot 						goto error;
1688c10b85d6SJean-Jacques Hiblot 					}
1689c10b85d6SJean-Jacques Hiblot 				}
1690f99c2efeSJean-Jacques Hiblot #endif
1691c10b85d6SJean-Jacques Hiblot 
16925b2e72f3SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE)
16938ac8a263SJean-Jacques Hiblot 				err = sd_read_ssr(mmc);
16940a4c2b09SPeng Fan 				if (err)
16955b2e72f3SJean-Jacques Hiblot 					pr_warn("unable to read ssr\n");
16965b2e72f3SJean-Jacques Hiblot #endif
16975b2e72f3SJean-Jacques Hiblot 				if (!err)
16988ac8a263SJean-Jacques Hiblot 					return 0;
1699d0c221feSJean-Jacques Hiblot 
1700d0c221feSJean-Jacques Hiblot error:
1701d0c221feSJean-Jacques Hiblot 				/* revert to a safer bus speed */
1702d0c221feSJean-Jacques Hiblot 				mmc_select_mode(mmc, SD_LEGACY);
170365117182SJaehoon Chung 				mmc_set_clock(mmc, mmc->tran_speed,
170465117182SJaehoon Chung 						MMC_CLK_ENABLE);
1705d0c221feSJean-Jacques Hiblot 			}
1706d0c221feSJean-Jacques Hiblot 		}
1707d0c221feSJean-Jacques Hiblot 	}
1708d0c221feSJean-Jacques Hiblot 
1709d4d64889SMasahiro Yamada 	pr_err("unable to select a mode\n");
1710d0c221feSJean-Jacques Hiblot 	return -ENOTSUPP;
17118ac8a263SJean-Jacques Hiblot }
17128ac8a263SJean-Jacques Hiblot 
17137382e691SJean-Jacques Hiblot /*
17147382e691SJean-Jacques Hiblot  * read the compare the part of ext csd that is constant.
17157382e691SJean-Jacques Hiblot  * This can be used to check that the transfer is working
17167382e691SJean-Jacques Hiblot  * as expected.
17177382e691SJean-Jacques Hiblot  */
17187382e691SJean-Jacques Hiblot static int mmc_read_and_compare_ext_csd(struct mmc *mmc)
17197382e691SJean-Jacques Hiblot {
17207382e691SJean-Jacques Hiblot 	int err;
17217382e691SJean-Jacques Hiblot 	const u8 *ext_csd = mmc->ext_csd;
17227382e691SJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
17237382e691SJean-Jacques Hiblot 
17241de06b9fSJean-Jacques Hiblot 	if (mmc->version < MMC_VERSION_4)
17251de06b9fSJean-Jacques Hiblot 		return 0;
17261de06b9fSJean-Jacques Hiblot 
17277382e691SJean-Jacques Hiblot 	err = mmc_send_ext_csd(mmc, test_csd);
17287382e691SJean-Jacques Hiblot 	if (err)
17297382e691SJean-Jacques Hiblot 		return err;
17307382e691SJean-Jacques Hiblot 
17317382e691SJean-Jacques Hiblot 	/* Only compare read only fields */
17327382e691SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT]
17337382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_PARTITIONING_SUPPORT] &&
17347382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_HC_WP_GRP_SIZE]
17357382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_HC_WP_GRP_SIZE] &&
17367382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_REV]
17377382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_REV] &&
17387382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
17397382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] &&
17407382e691SJean-Jacques Hiblot 	    memcmp(&ext_csd[EXT_CSD_SEC_CNT],
17417382e691SJean-Jacques Hiblot 		   &test_csd[EXT_CSD_SEC_CNT], 4) == 0)
17427382e691SJean-Jacques Hiblot 		return 0;
17437382e691SJean-Jacques Hiblot 
17447382e691SJean-Jacques Hiblot 	return -EBADMSG;
17457382e691SJean-Jacques Hiblot }
17467382e691SJean-Jacques Hiblot 
1747f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE)
1748bc1e3272SJean-Jacques Hiblot static int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,
1749bc1e3272SJean-Jacques Hiblot 				  uint32_t allowed_mask)
1750bc1e3272SJean-Jacques Hiblot {
1751bc1e3272SJean-Jacques Hiblot 	u32 card_mask = 0;
1752bc1e3272SJean-Jacques Hiblot 
1753bc1e3272SJean-Jacques Hiblot 	switch (mode) {
17543dd2626fSPeng Fan 	case MMC_HS_400:
1755bc1e3272SJean-Jacques Hiblot 	case MMC_HS_200:
17563dd2626fSPeng Fan 		if (mmc->cardtype & (EXT_CSD_CARD_TYPE_HS200_1_8V |
17573dd2626fSPeng Fan 		    EXT_CSD_CARD_TYPE_HS400_1_8V))
1758bc1e3272SJean-Jacques Hiblot 			card_mask |= MMC_SIGNAL_VOLTAGE_180;
17593dd2626fSPeng Fan 		if (mmc->cardtype & (EXT_CSD_CARD_TYPE_HS200_1_2V |
17603dd2626fSPeng Fan 		    EXT_CSD_CARD_TYPE_HS400_1_2V))
1761bc1e3272SJean-Jacques Hiblot 			card_mask |= MMC_SIGNAL_VOLTAGE_120;
1762bc1e3272SJean-Jacques Hiblot 		break;
1763bc1e3272SJean-Jacques Hiblot 	case MMC_DDR_52:
1764bc1e3272SJean-Jacques Hiblot 		if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V)
1765bc1e3272SJean-Jacques Hiblot 			card_mask |= MMC_SIGNAL_VOLTAGE_330 |
1766bc1e3272SJean-Jacques Hiblot 				     MMC_SIGNAL_VOLTAGE_180;
1767bc1e3272SJean-Jacques Hiblot 		if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_2V)
1768bc1e3272SJean-Jacques Hiblot 			card_mask |= MMC_SIGNAL_VOLTAGE_120;
1769bc1e3272SJean-Jacques Hiblot 		break;
1770bc1e3272SJean-Jacques Hiblot 	default:
1771bc1e3272SJean-Jacques Hiblot 		card_mask |= MMC_SIGNAL_VOLTAGE_330;
1772bc1e3272SJean-Jacques Hiblot 		break;
1773bc1e3272SJean-Jacques Hiblot 	}
1774bc1e3272SJean-Jacques Hiblot 
1775bc1e3272SJean-Jacques Hiblot 	while (card_mask & allowed_mask) {
1776bc1e3272SJean-Jacques Hiblot 		enum mmc_voltage best_match;
1777bc1e3272SJean-Jacques Hiblot 
1778bc1e3272SJean-Jacques Hiblot 		best_match = 1 << (ffs(card_mask & allowed_mask) - 1);
1779bc1e3272SJean-Jacques Hiblot 		if (!mmc_set_signal_voltage(mmc,  best_match))
1780bc1e3272SJean-Jacques Hiblot 			return 0;
1781bc1e3272SJean-Jacques Hiblot 
1782bc1e3272SJean-Jacques Hiblot 		allowed_mask &= ~best_match;
1783bc1e3272SJean-Jacques Hiblot 	}
1784bc1e3272SJean-Jacques Hiblot 
1785bc1e3272SJean-Jacques Hiblot 	return -ENOTSUPP;
1786bc1e3272SJean-Jacques Hiblot }
1787f99c2efeSJean-Jacques Hiblot #else
1788f99c2efeSJean-Jacques Hiblot static inline int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,
1789f99c2efeSJean-Jacques Hiblot 					 uint32_t allowed_mask)
1790f99c2efeSJean-Jacques Hiblot {
1791f99c2efeSJean-Jacques Hiblot 	return 0;
1792f99c2efeSJean-Jacques Hiblot }
1793f99c2efeSJean-Jacques Hiblot #endif
1794bc1e3272SJean-Jacques Hiblot 
17953862b854SJean-Jacques Hiblot static const struct mode_width_tuning mmc_modes_by_pref[] = {
17963dd2626fSPeng Fan #if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
17973dd2626fSPeng Fan 	{
17983dd2626fSPeng Fan 		.mode = MMC_HS_400,
17993dd2626fSPeng Fan 		.widths = MMC_MODE_8BIT,
18003dd2626fSPeng Fan 		.tuning = MMC_CMD_SEND_TUNING_BLOCK_HS200
18013dd2626fSPeng Fan 	},
18023dd2626fSPeng Fan #endif
1803f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
18048ac8a263SJean-Jacques Hiblot 	{
18053862b854SJean-Jacques Hiblot 		.mode = MMC_HS_200,
18063862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
1807634d4849SKishon Vijay Abraham I 		.tuning = MMC_CMD_SEND_TUNING_BLOCK_HS200
18083862b854SJean-Jacques Hiblot 	},
1809f99c2efeSJean-Jacques Hiblot #endif
18103862b854SJean-Jacques Hiblot 	{
18113862b854SJean-Jacques Hiblot 		.mode = MMC_DDR_52,
18123862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
18133862b854SJean-Jacques Hiblot 	},
18143862b854SJean-Jacques Hiblot 	{
18153862b854SJean-Jacques Hiblot 		.mode = MMC_HS_52,
18163862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
18173862b854SJean-Jacques Hiblot 	},
18183862b854SJean-Jacques Hiblot 	{
18193862b854SJean-Jacques Hiblot 		.mode = MMC_HS,
18203862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
18213862b854SJean-Jacques Hiblot 	},
18223862b854SJean-Jacques Hiblot 	{
18233862b854SJean-Jacques Hiblot 		.mode = MMC_LEGACY,
18243862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
18253862b854SJean-Jacques Hiblot 	}
18268ac8a263SJean-Jacques Hiblot };
18278ac8a263SJean-Jacques Hiblot 
18283862b854SJean-Jacques Hiblot #define for_each_mmc_mode_by_pref(caps, mwt) \
18293862b854SJean-Jacques Hiblot 	for (mwt = mmc_modes_by_pref;\
18303862b854SJean-Jacques Hiblot 	    mwt < mmc_modes_by_pref + ARRAY_SIZE(mmc_modes_by_pref);\
18313862b854SJean-Jacques Hiblot 	    mwt++) \
18323862b854SJean-Jacques Hiblot 		if (caps & MMC_CAP(mwt->mode))
18333862b854SJean-Jacques Hiblot 
18343862b854SJean-Jacques Hiblot static const struct ext_csd_bus_width {
18353862b854SJean-Jacques Hiblot 	uint cap;
18363862b854SJean-Jacques Hiblot 	bool is_ddr;
18373862b854SJean-Jacques Hiblot 	uint ext_csd_bits;
18383862b854SJean-Jacques Hiblot } ext_csd_bus_width[] = {
18393862b854SJean-Jacques Hiblot 	{MMC_MODE_8BIT, true, EXT_CSD_DDR_BUS_WIDTH_8},
18403862b854SJean-Jacques Hiblot 	{MMC_MODE_4BIT, true, EXT_CSD_DDR_BUS_WIDTH_4},
18413862b854SJean-Jacques Hiblot 	{MMC_MODE_8BIT, false, EXT_CSD_BUS_WIDTH_8},
18423862b854SJean-Jacques Hiblot 	{MMC_MODE_4BIT, false, EXT_CSD_BUS_WIDTH_4},
18433862b854SJean-Jacques Hiblot 	{MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1},
18443862b854SJean-Jacques Hiblot };
18453862b854SJean-Jacques Hiblot 
18463dd2626fSPeng Fan #if CONFIG_IS_ENABLED(MMC_HS400_SUPPORT)
18473dd2626fSPeng Fan static int mmc_select_hs400(struct mmc *mmc)
18483dd2626fSPeng Fan {
18493dd2626fSPeng Fan 	int err;
18503dd2626fSPeng Fan 
18513dd2626fSPeng Fan 	/* Set timing to HS200 for tuning */
18523dd2626fSPeng Fan 	err = mmc_set_card_speed(mmc, MMC_HS_200);
18533dd2626fSPeng Fan 	if (err)
18543dd2626fSPeng Fan 		return err;
18553dd2626fSPeng Fan 
18563dd2626fSPeng Fan 	/* configure the bus mode (host) */
18573dd2626fSPeng Fan 	mmc_select_mode(mmc, MMC_HS_200);
18583dd2626fSPeng Fan 	mmc_set_clock(mmc, mmc->tran_speed, false);
18593dd2626fSPeng Fan 
18603dd2626fSPeng Fan 	/* execute tuning if needed */
18613dd2626fSPeng Fan 	err = mmc_execute_tuning(mmc, MMC_CMD_SEND_TUNING_BLOCK_HS200);
18623dd2626fSPeng Fan 	if (err) {
18633dd2626fSPeng Fan 		debug("tuning failed\n");
18643dd2626fSPeng Fan 		return err;
18653dd2626fSPeng Fan 	}
18663dd2626fSPeng Fan 
18673dd2626fSPeng Fan 	/* Set back to HS */
18683dd2626fSPeng Fan 	mmc_set_card_speed(mmc, MMC_HS);
18693dd2626fSPeng Fan 	mmc_set_clock(mmc, mmc_mode2freq(mmc, MMC_HS), false);
18703dd2626fSPeng Fan 
18713dd2626fSPeng Fan 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH,
18723dd2626fSPeng Fan 			 EXT_CSD_BUS_WIDTH_8 | EXT_CSD_DDR_FLAG);
18733dd2626fSPeng Fan 	if (err)
18743dd2626fSPeng Fan 		return err;
18753dd2626fSPeng Fan 
18763dd2626fSPeng Fan 	err = mmc_set_card_speed(mmc, MMC_HS_400);
18773dd2626fSPeng Fan 	if (err)
18783dd2626fSPeng Fan 		return err;
18793dd2626fSPeng Fan 
18803dd2626fSPeng Fan 	mmc_select_mode(mmc, MMC_HS_400);
18813dd2626fSPeng Fan 	err = mmc_set_clock(mmc, mmc->tran_speed, false);
18823dd2626fSPeng Fan 	if (err)
18833dd2626fSPeng Fan 		return err;
18843dd2626fSPeng Fan 
18853dd2626fSPeng Fan 	return 0;
18863dd2626fSPeng Fan }
18873dd2626fSPeng Fan #else
18883dd2626fSPeng Fan static int mmc_select_hs400(struct mmc *mmc)
18893dd2626fSPeng Fan {
18903dd2626fSPeng Fan 	return -ENOTSUPP;
18913dd2626fSPeng Fan }
18923dd2626fSPeng Fan #endif
18933dd2626fSPeng Fan 
18943862b854SJean-Jacques Hiblot #define for_each_supported_width(caps, ddr, ecbv) \
18953862b854SJean-Jacques Hiblot 	for (ecbv = ext_csd_bus_width;\
18963862b854SJean-Jacques Hiblot 	    ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\
18973862b854SJean-Jacques Hiblot 	    ecbv++) \
18983862b854SJean-Jacques Hiblot 		if ((ddr == ecbv->is_ddr) && (caps & ecbv->cap))
18993862b854SJean-Jacques Hiblot 
190001298da3SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
19013862b854SJean-Jacques Hiblot {
19023862b854SJean-Jacques Hiblot 	int err;
19033862b854SJean-Jacques Hiblot 	const struct mode_width_tuning *mwt;
19043862b854SJean-Jacques Hiblot 	const struct ext_csd_bus_width *ecbw;
19053862b854SJean-Jacques Hiblot 
190652d241dfSJean-Jacques Hiblot #ifdef DEBUG
190752d241dfSJean-Jacques Hiblot 	mmc_dump_capabilities("mmc", card_caps);
19081da8eb59SJean-Jacques Hiblot 	mmc_dump_capabilities("host", mmc->host_caps);
190952d241dfSJean-Jacques Hiblot #endif
191052d241dfSJean-Jacques Hiblot 
19118ac8a263SJean-Jacques Hiblot 	/* Restrict card's capabilities by what the host can do */
19121da8eb59SJean-Jacques Hiblot 	card_caps &= mmc->host_caps;
19138ac8a263SJean-Jacques Hiblot 
19148ac8a263SJean-Jacques Hiblot 	/* Only version 4 of MMC supports wider bus widths */
19158ac8a263SJean-Jacques Hiblot 	if (mmc->version < MMC_VERSION_4)
19168ac8a263SJean-Jacques Hiblot 		return 0;
19178ac8a263SJean-Jacques Hiblot 
1918dfda9d88SJean-Jacques Hiblot 	if (!mmc->ext_csd) {
1919d4d64889SMasahiro Yamada 		pr_debug("No ext_csd found!\n"); /* this should enver happen */
1920dfda9d88SJean-Jacques Hiblot 		return -ENOTSUPP;
1921dfda9d88SJean-Jacques Hiblot 	}
1922dfda9d88SJean-Jacques Hiblot 
192365117182SJaehoon Chung 	mmc_set_clock(mmc, mmc->legacy_speed, MMC_CLK_ENABLE);
192401298da3SJean-Jacques Hiblot 
192501298da3SJean-Jacques Hiblot 	for_each_mmc_mode_by_pref(card_caps, mwt) {
192601298da3SJean-Jacques Hiblot 		for_each_supported_width(card_caps & mwt->widths,
19273862b854SJean-Jacques Hiblot 					 mmc_is_mode_ddr(mwt->mode), ecbw) {
1928bc1e3272SJean-Jacques Hiblot 			enum mmc_voltage old_voltage;
1929d4d64889SMasahiro Yamada 			pr_debug("trying mode %s width %d (at %d MHz)\n",
19303862b854SJean-Jacques Hiblot 				 mmc_mode_name(mwt->mode),
19313862b854SJean-Jacques Hiblot 				 bus_width(ecbw->cap),
19323862b854SJean-Jacques Hiblot 				 mmc_mode2freq(mmc, mwt->mode) / 1000000);
1933bc1e3272SJean-Jacques Hiblot 			old_voltage = mmc->signal_voltage;
1934bc1e3272SJean-Jacques Hiblot 			err = mmc_set_lowest_voltage(mmc, mwt->mode,
1935bc1e3272SJean-Jacques Hiblot 						     MMC_ALL_SIGNAL_VOLTAGE);
1936bc1e3272SJean-Jacques Hiblot 			if (err)
1937bc1e3272SJean-Jacques Hiblot 				continue;
1938bc1e3272SJean-Jacques Hiblot 
19393862b854SJean-Jacques Hiblot 			/* configure the bus width (card + host) */
19403862b854SJean-Jacques Hiblot 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
19413862b854SJean-Jacques Hiblot 				    EXT_CSD_BUS_WIDTH,
19423862b854SJean-Jacques Hiblot 				    ecbw->ext_csd_bits & ~EXT_CSD_DDR_FLAG);
19433862b854SJean-Jacques Hiblot 			if (err)
19443862b854SJean-Jacques Hiblot 				goto error;
19453862b854SJean-Jacques Hiblot 			mmc_set_bus_width(mmc, bus_width(ecbw->cap));
19463862b854SJean-Jacques Hiblot 
19473dd2626fSPeng Fan 			if (mwt->mode == MMC_HS_400) {
19483dd2626fSPeng Fan 				err = mmc_select_hs400(mmc);
19493dd2626fSPeng Fan 				if (err) {
19503dd2626fSPeng Fan 					printf("Select HS400 failed %d\n", err);
19513dd2626fSPeng Fan 					goto error;
19523dd2626fSPeng Fan 				}
19533dd2626fSPeng Fan 			} else {
19543862b854SJean-Jacques Hiblot 				/* configure the bus speed (card) */
19553862b854SJean-Jacques Hiblot 				err = mmc_set_card_speed(mmc, mwt->mode);
19563862b854SJean-Jacques Hiblot 				if (err)
19573862b854SJean-Jacques Hiblot 					goto error;
19583862b854SJean-Jacques Hiblot 
19598ac8a263SJean-Jacques Hiblot 				/*
19603dd2626fSPeng Fan 				 * configure the bus width AND the ddr mode
19613dd2626fSPeng Fan 				 * (card). The host side will be taken care
19623dd2626fSPeng Fan 				 * of in the next step
19638ac8a263SJean-Jacques Hiblot 				 */
19643862b854SJean-Jacques Hiblot 				if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) {
19653dd2626fSPeng Fan 					err = mmc_switch(mmc,
19663dd2626fSPeng Fan 							 EXT_CSD_CMD_SET_NORMAL,
19673862b854SJean-Jacques Hiblot 							 EXT_CSD_BUS_WIDTH,
19683862b854SJean-Jacques Hiblot 							 ecbw->ext_csd_bits);
19693862b854SJean-Jacques Hiblot 					if (err)
19703862b854SJean-Jacques Hiblot 						goto error;
19718ac8a263SJean-Jacques Hiblot 				}
19728ac8a263SJean-Jacques Hiblot 
19733862b854SJean-Jacques Hiblot 				/* configure the bus mode (host) */
19743862b854SJean-Jacques Hiblot 				mmc_select_mode(mmc, mwt->mode);
19753dd2626fSPeng Fan 				mmc_set_clock(mmc, mmc->tran_speed,
19763dd2626fSPeng Fan 					      MMC_CLK_ENABLE);
1977f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
19788ac8a263SJean-Jacques Hiblot 
1979634d4849SKishon Vijay Abraham I 				/* execute tuning if needed */
1980634d4849SKishon Vijay Abraham I 				if (mwt->tuning) {
19813dd2626fSPeng Fan 					err = mmc_execute_tuning(mmc,
19823dd2626fSPeng Fan 								 mwt->tuning);
1983634d4849SKishon Vijay Abraham I 					if (err) {
1984d4d64889SMasahiro Yamada 						pr_debug("tuning failed\n");
1985634d4849SKishon Vijay Abraham I 						goto error;
1986634d4849SKishon Vijay Abraham I 					}
1987634d4849SKishon Vijay Abraham I 				}
1988f99c2efeSJean-Jacques Hiblot #endif
19893dd2626fSPeng Fan 			}
1990634d4849SKishon Vijay Abraham I 
19913862b854SJean-Jacques Hiblot 			/* do a transfer to check the configuration */
19927382e691SJean-Jacques Hiblot 			err = mmc_read_and_compare_ext_csd(mmc);
19937382e691SJean-Jacques Hiblot 			if (!err)
19943862b854SJean-Jacques Hiblot 				return 0;
19953862b854SJean-Jacques Hiblot error:
1996bc1e3272SJean-Jacques Hiblot 			mmc_set_signal_voltage(mmc, old_voltage);
19973862b854SJean-Jacques Hiblot 			/* if an error occured, revert to a safer bus mode */
19983862b854SJean-Jacques Hiblot 			mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
19993862b854SJean-Jacques Hiblot 				   EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1);
20003862b854SJean-Jacques Hiblot 			mmc_select_mode(mmc, MMC_LEGACY);
20013862b854SJean-Jacques Hiblot 			mmc_set_bus_width(mmc, 1);
20023862b854SJean-Jacques Hiblot 		}
20038ac8a263SJean-Jacques Hiblot 	}
20048ac8a263SJean-Jacques Hiblot 
2005d8e3d420SJean-Jacques Hiblot 	pr_err("unable to select a mode\n");
20068ac8a263SJean-Jacques Hiblot 
20073862b854SJean-Jacques Hiblot 	return -ENOTSUPP;
20088ac8a263SJean-Jacques Hiblot }
200962d77ceaSMarek Vasut #endif
201062d77ceaSMarek Vasut 
201162d77ceaSMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY)
201262d77ceaSMarek Vasut DEFINE_CACHE_ALIGN_BUFFER(u8, ext_csd_bkup, MMC_MAX_BLOCK_LEN);
201362d77ceaSMarek Vasut #endif
20148ac8a263SJean-Jacques Hiblot 
2015dfda9d88SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc)
2016c744b6f6SJean-Jacques Hiblot {
2017c744b6f6SJean-Jacques Hiblot 	int err, i;
2018c744b6f6SJean-Jacques Hiblot 	u64 capacity;
2019c744b6f6SJean-Jacques Hiblot 	bool has_parts = false;
2020c744b6f6SJean-Jacques Hiblot 	bool part_completed;
202158a6fb7bSJean-Jacques Hiblot 	static const u32 mmc_versions[] = {
202258a6fb7bSJean-Jacques Hiblot 		MMC_VERSION_4,
202358a6fb7bSJean-Jacques Hiblot 		MMC_VERSION_4_1,
202458a6fb7bSJean-Jacques Hiblot 		MMC_VERSION_4_2,
202558a6fb7bSJean-Jacques Hiblot 		MMC_VERSION_4_3,
2026ace1bed3SJean-Jacques Hiblot 		MMC_VERSION_4_4,
202758a6fb7bSJean-Jacques Hiblot 		MMC_VERSION_4_41,
202858a6fb7bSJean-Jacques Hiblot 		MMC_VERSION_4_5,
202958a6fb7bSJean-Jacques Hiblot 		MMC_VERSION_5_0,
203058a6fb7bSJean-Jacques Hiblot 		MMC_VERSION_5_1
203158a6fb7bSJean-Jacques Hiblot 	};
203258a6fb7bSJean-Jacques Hiblot 
203362d77ceaSMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY)
203462d77ceaSMarek Vasut 	u8 *ext_csd = ext_csd_bkup;
203562d77ceaSMarek Vasut 
203662d77ceaSMarek Vasut 	if (IS_SD(mmc) || mmc->version < MMC_VERSION_4)
203762d77ceaSMarek Vasut 		return 0;
203862d77ceaSMarek Vasut 
203962d77ceaSMarek Vasut 	if (!mmc->ext_csd)
204062d77ceaSMarek Vasut 		memset(ext_csd_bkup, 0, sizeof(ext_csd_bkup));
204162d77ceaSMarek Vasut 
204262d77ceaSMarek Vasut 	err = mmc_send_ext_csd(mmc, ext_csd);
204362d77ceaSMarek Vasut 	if (err)
204462d77ceaSMarek Vasut 		goto error;
204562d77ceaSMarek Vasut 
204662d77ceaSMarek Vasut 	/* store the ext csd for future reference */
204762d77ceaSMarek Vasut 	if (!mmc->ext_csd)
204862d77ceaSMarek Vasut 		mmc->ext_csd = ext_csd;
204962d77ceaSMarek Vasut #else
2050f7d5dffcSJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
2051c744b6f6SJean-Jacques Hiblot 
2052c744b6f6SJean-Jacques Hiblot 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4))
2053c744b6f6SJean-Jacques Hiblot 		return 0;
2054c744b6f6SJean-Jacques Hiblot 
2055c744b6f6SJean-Jacques Hiblot 	/* check  ext_csd version and capacity */
2056c744b6f6SJean-Jacques Hiblot 	err = mmc_send_ext_csd(mmc, ext_csd);
2057c744b6f6SJean-Jacques Hiblot 	if (err)
2058f7d5dffcSJean-Jacques Hiblot 		goto error;
2059f7d5dffcSJean-Jacques Hiblot 
2060f7d5dffcSJean-Jacques Hiblot 	/* store the ext csd for future reference */
2061f7d5dffcSJean-Jacques Hiblot 	if (!mmc->ext_csd)
2062f7d5dffcSJean-Jacques Hiblot 		mmc->ext_csd = malloc(MMC_MAX_BLOCK_LEN);
2063f7d5dffcSJean-Jacques Hiblot 	if (!mmc->ext_csd)
2064f7d5dffcSJean-Jacques Hiblot 		return -ENOMEM;
2065f7d5dffcSJean-Jacques Hiblot 	memcpy(mmc->ext_csd, ext_csd, MMC_MAX_BLOCK_LEN);
206662d77ceaSMarek Vasut #endif
206776584e33SAlexander Kochetkov 	if (ext_csd[EXT_CSD_REV] >= ARRAY_SIZE(mmc_versions))
206858a6fb7bSJean-Jacques Hiblot 		return -EINVAL;
206958a6fb7bSJean-Jacques Hiblot 
207058a6fb7bSJean-Jacques Hiblot 	mmc->version = mmc_versions[ext_csd[EXT_CSD_REV]];
207158a6fb7bSJean-Jacques Hiblot 
207258a6fb7bSJean-Jacques Hiblot 	if (mmc->version >= MMC_VERSION_4_2) {
2073c744b6f6SJean-Jacques Hiblot 		/*
2074c744b6f6SJean-Jacques Hiblot 		 * According to the JEDEC Standard, the value of
2075c744b6f6SJean-Jacques Hiblot 		 * ext_csd's capacity is valid if the value is more
2076c744b6f6SJean-Jacques Hiblot 		 * than 2GB
2077c744b6f6SJean-Jacques Hiblot 		 */
2078c744b6f6SJean-Jacques Hiblot 		capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
2079c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
2080c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
2081c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
2082c744b6f6SJean-Jacques Hiblot 		capacity *= MMC_MAX_BLOCK_LEN;
2083c744b6f6SJean-Jacques Hiblot 		if ((capacity >> 20) > 2 * 1024)
2084c744b6f6SJean-Jacques Hiblot 			mmc->capacity_user = capacity;
2085c744b6f6SJean-Jacques Hiblot 	}
2086c744b6f6SJean-Jacques Hiblot 
2087c744b6f6SJean-Jacques Hiblot 	/* The partition data may be non-zero but it is only
2088c744b6f6SJean-Jacques Hiblot 	 * effective if PARTITION_SETTING_COMPLETED is set in
2089c744b6f6SJean-Jacques Hiblot 	 * EXT_CSD, so ignore any data if this bit is not set,
2090c744b6f6SJean-Jacques Hiblot 	 * except for enabling the high-capacity group size
2091c744b6f6SJean-Jacques Hiblot 	 * definition (see below).
2092c744b6f6SJean-Jacques Hiblot 	 */
2093c744b6f6SJean-Jacques Hiblot 	part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
2094c744b6f6SJean-Jacques Hiblot 			    EXT_CSD_PARTITION_SETTING_COMPLETED);
2095c744b6f6SJean-Jacques Hiblot 
2096c744b6f6SJean-Jacques Hiblot 	/* store the partition info of emmc */
2097c744b6f6SJean-Jacques Hiblot 	mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
2098c744b6f6SJean-Jacques Hiblot 	if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
2099c744b6f6SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_BOOT_MULT])
2100c744b6f6SJean-Jacques Hiblot 		mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
2101c744b6f6SJean-Jacques Hiblot 	if (part_completed &&
2102c744b6f6SJean-Jacques Hiblot 	    (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
2103c744b6f6SJean-Jacques Hiblot 		mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
2104c744b6f6SJean-Jacques Hiblot 
2105c744b6f6SJean-Jacques Hiblot 	mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
2106c744b6f6SJean-Jacques Hiblot 
2107c744b6f6SJean-Jacques Hiblot 	mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
2108c744b6f6SJean-Jacques Hiblot 
2109c744b6f6SJean-Jacques Hiblot 	for (i = 0; i < 4; i++) {
2110c744b6f6SJean-Jacques Hiblot 		int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
2111c744b6f6SJean-Jacques Hiblot 		uint mult = (ext_csd[idx + 2] << 16) +
2112c744b6f6SJean-Jacques Hiblot 			(ext_csd[idx + 1] << 8) + ext_csd[idx];
2113c744b6f6SJean-Jacques Hiblot 		if (mult)
2114c744b6f6SJean-Jacques Hiblot 			has_parts = true;
2115c744b6f6SJean-Jacques Hiblot 		if (!part_completed)
2116c744b6f6SJean-Jacques Hiblot 			continue;
2117c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] = mult;
2118c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] *=
2119c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
2120c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
2121c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] <<= 19;
2122c744b6f6SJean-Jacques Hiblot 	}
2123c744b6f6SJean-Jacques Hiblot 
2124173c06dfSJean-Jacques Hiblot #ifndef CONFIG_SPL_BUILD
2125c744b6f6SJean-Jacques Hiblot 	if (part_completed) {
2126c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size =
2127c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) +
2128c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) +
2129c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_ENH_SIZE_MULT];
2130c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
2131c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
2132c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size <<= 19;
2133c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_start =
2134c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) +
2135c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) +
2136c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) +
2137c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_ENH_START_ADDR];
2138c744b6f6SJean-Jacques Hiblot 		if (mmc->high_capacity)
2139c744b6f6SJean-Jacques Hiblot 			mmc->enh_user_start <<= 9;
2140c744b6f6SJean-Jacques Hiblot 	}
2141173c06dfSJean-Jacques Hiblot #endif
2142c744b6f6SJean-Jacques Hiblot 
2143c744b6f6SJean-Jacques Hiblot 	/*
2144c744b6f6SJean-Jacques Hiblot 	 * Host needs to enable ERASE_GRP_DEF bit if device is
2145c744b6f6SJean-Jacques Hiblot 	 * partitioned. This bit will be lost every time after a reset
2146c744b6f6SJean-Jacques Hiblot 	 * or power off. This will affect erase size.
2147c744b6f6SJean-Jacques Hiblot 	 */
2148c744b6f6SJean-Jacques Hiblot 	if (part_completed)
2149c744b6f6SJean-Jacques Hiblot 		has_parts = true;
2150c744b6f6SJean-Jacques Hiblot 	if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
2151c744b6f6SJean-Jacques Hiblot 	    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
2152c744b6f6SJean-Jacques Hiblot 		has_parts = true;
2153c744b6f6SJean-Jacques Hiblot 	if (has_parts) {
2154c744b6f6SJean-Jacques Hiblot 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
2155c744b6f6SJean-Jacques Hiblot 				 EXT_CSD_ERASE_GROUP_DEF, 1);
2156c744b6f6SJean-Jacques Hiblot 
2157c744b6f6SJean-Jacques Hiblot 		if (err)
2158f7d5dffcSJean-Jacques Hiblot 			goto error;
2159c744b6f6SJean-Jacques Hiblot 
2160c744b6f6SJean-Jacques Hiblot 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
2161c744b6f6SJean-Jacques Hiblot 	}
2162c744b6f6SJean-Jacques Hiblot 
2163c744b6f6SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
2164e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE)
2165c744b6f6SJean-Jacques Hiblot 		/* Read out group size from ext_csd */
2166c744b6f6SJean-Jacques Hiblot 		mmc->erase_grp_size =
2167c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
2168e6fa5a54SJean-Jacques Hiblot #endif
2169c744b6f6SJean-Jacques Hiblot 		/*
2170c744b6f6SJean-Jacques Hiblot 		 * if high capacity and partition setting completed
2171c744b6f6SJean-Jacques Hiblot 		 * SEC_COUNT is valid even if it is smaller than 2 GiB
2172c744b6f6SJean-Jacques Hiblot 		 * JEDEC Standard JESD84-B45, 6.2.4
2173c744b6f6SJean-Jacques Hiblot 		 */
2174c744b6f6SJean-Jacques Hiblot 		if (mmc->high_capacity && part_completed) {
2175c744b6f6SJean-Jacques Hiblot 			capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
2176c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
2177c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
2178c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
2179c744b6f6SJean-Jacques Hiblot 			capacity *= MMC_MAX_BLOCK_LEN;
2180c744b6f6SJean-Jacques Hiblot 			mmc->capacity_user = capacity;
2181c744b6f6SJean-Jacques Hiblot 		}
2182e6fa5a54SJean-Jacques Hiblot 	}
2183e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE)
2184e6fa5a54SJean-Jacques Hiblot 	else {
2185c744b6f6SJean-Jacques Hiblot 		/* Calculate the group size from the csd value. */
2186c744b6f6SJean-Jacques Hiblot 		int erase_gsz, erase_gmul;
2187c744b6f6SJean-Jacques Hiblot 
2188c744b6f6SJean-Jacques Hiblot 		erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
2189c744b6f6SJean-Jacques Hiblot 		erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
2190c744b6f6SJean-Jacques Hiblot 		mmc->erase_grp_size = (erase_gsz + 1)
2191c744b6f6SJean-Jacques Hiblot 			* (erase_gmul + 1);
2192c744b6f6SJean-Jacques Hiblot 	}
2193e6fa5a54SJean-Jacques Hiblot #endif
2194b7a6e2c9SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING)
2195c744b6f6SJean-Jacques Hiblot 	mmc->hc_wp_grp_size = 1024
2196c744b6f6SJean-Jacques Hiblot 		* ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
2197c744b6f6SJean-Jacques Hiblot 		* ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
2198b7a6e2c9SJean-Jacques Hiblot #endif
2199c744b6f6SJean-Jacques Hiblot 
2200c744b6f6SJean-Jacques Hiblot 	mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
2201c744b6f6SJean-Jacques Hiblot 
2202c744b6f6SJean-Jacques Hiblot 	return 0;
2203f7d5dffcSJean-Jacques Hiblot error:
2204f7d5dffcSJean-Jacques Hiblot 	if (mmc->ext_csd) {
220562d77ceaSMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY)
2206f7d5dffcSJean-Jacques Hiblot 		free(mmc->ext_csd);
220762d77ceaSMarek Vasut #endif
2208f7d5dffcSJean-Jacques Hiblot 		mmc->ext_csd = NULL;
2209f7d5dffcSJean-Jacques Hiblot 	}
2210f7d5dffcSJean-Jacques Hiblot 	return err;
2211c744b6f6SJean-Jacques Hiblot }
2212c744b6f6SJean-Jacques Hiblot 
2213fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc)
2214272cc70bSAndy Fleming {
2215f866a46dSStephen Warren 	int err, i;
2216272cc70bSAndy Fleming 	uint mult, freq;
2217c744b6f6SJean-Jacques Hiblot 	u64 cmult, csize;
2218272cc70bSAndy Fleming 	struct mmc_cmd cmd;
2219c40fdca6SSimon Glass 	struct blk_desc *bdesc;
2220272cc70bSAndy Fleming 
2221d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
2222d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
2223d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
2224d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
2225d52ebf10SThomas Chou 		cmd.cmdarg = 1;
2226d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
2227d52ebf10SThomas Chou 		if (err)
2228d52ebf10SThomas Chou 			return err;
2229d52ebf10SThomas Chou 	}
2230d52ebf10SThomas Chou #endif
2231d52ebf10SThomas Chou 
2232272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
2233d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
2234d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
2235272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
2236272cc70bSAndy Fleming 	cmd.cmdarg = 0;
2237272cc70bSAndy Fleming 
2238272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
2239272cc70bSAndy Fleming 
224083dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS
224183dc4227SKishon Vijay Abraham I 	if (err && (mmc->quirks & MMC_QUIRK_RETRY_SEND_CID)) {
224283dc4227SKishon Vijay Abraham I 		int retries = 4;
224383dc4227SKishon Vijay Abraham I 		/*
224483dc4227SKishon Vijay Abraham I 		 * It has been seen that SEND_CID may fail on the first
224583dc4227SKishon Vijay Abraham I 		 * attempt, let's try a few more time
224683dc4227SKishon Vijay Abraham I 		 */
224783dc4227SKishon Vijay Abraham I 		do {
224883dc4227SKishon Vijay Abraham I 			err = mmc_send_cmd(mmc, &cmd, NULL);
224983dc4227SKishon Vijay Abraham I 			if (!err)
225083dc4227SKishon Vijay Abraham I 				break;
225183dc4227SKishon Vijay Abraham I 		} while (retries--);
225283dc4227SKishon Vijay Abraham I 	}
225383dc4227SKishon Vijay Abraham I #endif
225483dc4227SKishon Vijay Abraham I 
2255272cc70bSAndy Fleming 	if (err)
2256272cc70bSAndy Fleming 		return err;
2257272cc70bSAndy Fleming 
2258272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
2259272cc70bSAndy Fleming 
2260272cc70bSAndy Fleming 	/*
2261272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
2262272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
2263272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
2264272cc70bSAndy Fleming 	 */
2265d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
2266272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
2267272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
2268272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
2269272cc70bSAndy Fleming 
2270272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
2271272cc70bSAndy Fleming 
2272272cc70bSAndy Fleming 		if (err)
2273272cc70bSAndy Fleming 			return err;
2274272cc70bSAndy Fleming 
2275272cc70bSAndy Fleming 		if (IS_SD(mmc))
2276998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
2277d52ebf10SThomas Chou 	}
2278272cc70bSAndy Fleming 
2279272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
2280272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
2281272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
2282272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
2283272cc70bSAndy Fleming 
2284272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
2285272cc70bSAndy Fleming 
2286272cc70bSAndy Fleming 	if (err)
2287272cc70bSAndy Fleming 		return err;
2288272cc70bSAndy Fleming 
2289998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
2290998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
2291998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
2292998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
2293272cc70bSAndy Fleming 
2294272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
22950b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
2296272cc70bSAndy Fleming 
2297272cc70bSAndy Fleming 		switch (version) {
2298272cc70bSAndy Fleming 		case 0:
2299272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
2300272cc70bSAndy Fleming 			break;
2301272cc70bSAndy Fleming 		case 1:
2302272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_4;
2303272cc70bSAndy Fleming 			break;
2304272cc70bSAndy Fleming 		case 2:
2305272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_2_2;
2306272cc70bSAndy Fleming 			break;
2307272cc70bSAndy Fleming 		case 3:
2308272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_3;
2309272cc70bSAndy Fleming 			break;
2310272cc70bSAndy Fleming 		case 4:
2311272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_4;
2312272cc70bSAndy Fleming 			break;
2313272cc70bSAndy Fleming 		default:
2314272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
2315272cc70bSAndy Fleming 			break;
2316272cc70bSAndy Fleming 		}
2317272cc70bSAndy Fleming 	}
2318272cc70bSAndy Fleming 
2319272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
23200b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
23210b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
2322272cc70bSAndy Fleming 
232335f9e196SJean-Jacques Hiblot 	mmc->legacy_speed = freq * mult;
232435f9e196SJean-Jacques Hiblot 	mmc_select_mode(mmc, MMC_LEGACY);
2325272cc70bSAndy Fleming 
2326ab71188cSMarkus Niebel 	mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
2327998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
2328e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE)
2329272cc70bSAndy Fleming 
2330272cc70bSAndy Fleming 	if (IS_SD(mmc))
2331272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
2332272cc70bSAndy Fleming 	else
2333998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
2334e6fa5a54SJean-Jacques Hiblot #endif
2335272cc70bSAndy Fleming 
2336272cc70bSAndy Fleming 	if (mmc->high_capacity) {
2337272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
2338272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
2339272cc70bSAndy Fleming 		cmult = 8;
2340272cc70bSAndy Fleming 	} else {
2341272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
2342272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
2343272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
2344272cc70bSAndy Fleming 	}
2345272cc70bSAndy Fleming 
2346f866a46dSStephen Warren 	mmc->capacity_user = (csize + 1) << (cmult + 2);
2347f866a46dSStephen Warren 	mmc->capacity_user *= mmc->read_bl_len;
2348f866a46dSStephen Warren 	mmc->capacity_boot = 0;
2349f866a46dSStephen Warren 	mmc->capacity_rpmb = 0;
2350f866a46dSStephen Warren 	for (i = 0; i < 4; i++)
2351f866a46dSStephen Warren 		mmc->capacity_gp[i] = 0;
2352272cc70bSAndy Fleming 
23538bfa195eSSimon Glass 	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
23548bfa195eSSimon Glass 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
2355272cc70bSAndy Fleming 
2356e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE)
23578bfa195eSSimon Glass 	if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
23588bfa195eSSimon Glass 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
2359e6fa5a54SJean-Jacques Hiblot #endif
2360272cc70bSAndy Fleming 
2361ab71188cSMarkus Niebel 	if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
2362ab71188cSMarkus Niebel 		cmd.cmdidx = MMC_CMD_SET_DSR;
2363ab71188cSMarkus Niebel 		cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
2364ab71188cSMarkus Niebel 		cmd.resp_type = MMC_RSP_NONE;
2365ab71188cSMarkus Niebel 		if (mmc_send_cmd(mmc, &cmd, NULL))
2366d8e3d420SJean-Jacques Hiblot 			pr_warn("MMC: SET_DSR failed\n");
2367ab71188cSMarkus Niebel 	}
2368ab71188cSMarkus Niebel 
2369272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
2370d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
2371272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
2372fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
2373272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
2374272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
2375272cc70bSAndy Fleming 
2376272cc70bSAndy Fleming 		if (err)
2377272cc70bSAndy Fleming 			return err;
2378d52ebf10SThomas Chou 	}
2379272cc70bSAndy Fleming 
2380e6f99a56SLei Wen 	/*
2381e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
2382e6f99a56SLei Wen 	 */
2383e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE)
2384e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
2385e6fa5a54SJean-Jacques Hiblot #endif
2386bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
2387c744b6f6SJean-Jacques Hiblot 
2388dfda9d88SJean-Jacques Hiblot 	err = mmc_startup_v4(mmc);
23899cf199ebSDiego Santa Cruz 	if (err)
23909cf199ebSDiego Santa Cruz 		return err;
2391f866a46dSStephen Warren 
2392c40fdca6SSimon Glass 	err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart);
2393f866a46dSStephen Warren 	if (err)
2394f866a46dSStephen Warren 		return err;
2395d23e2c09SSukumar Ghorai 
239662d77ceaSMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY)
239762d77ceaSMarek Vasut 	mmc_set_clock(mmc, mmc->legacy_speed, false);
239862d77ceaSMarek Vasut 	mmc_select_mode(mmc, IS_SD(mmc) ? SD_LEGACY : MMC_LEGACY);
239962d77ceaSMarek Vasut 	mmc_set_bus_width(mmc, 1);
240062d77ceaSMarek Vasut #else
240101298da3SJean-Jacques Hiblot 	if (IS_SD(mmc)) {
240201298da3SJean-Jacques Hiblot 		err = sd_get_capabilities(mmc);
240301298da3SJean-Jacques Hiblot 		if (err)
240401298da3SJean-Jacques Hiblot 			return err;
240501298da3SJean-Jacques Hiblot 		err = sd_select_mode_and_width(mmc, mmc->card_caps);
240601298da3SJean-Jacques Hiblot 	} else {
240701298da3SJean-Jacques Hiblot 		err = mmc_get_capabilities(mmc);
240801298da3SJean-Jacques Hiblot 		if (err)
240901298da3SJean-Jacques Hiblot 			return err;
241001298da3SJean-Jacques Hiblot 		mmc_select_mode_and_width(mmc, mmc->card_caps);
241101298da3SJean-Jacques Hiblot 	}
241262d77ceaSMarek Vasut #endif
2413272cc70bSAndy Fleming 	if (err)
2414272cc70bSAndy Fleming 		return err;
2415272cc70bSAndy Fleming 
241601298da3SJean-Jacques Hiblot 	mmc->best_mode = mmc->selected_mode;
2417272cc70bSAndy Fleming 
24185af8f45cSAndrew Gabbasov 	/* Fix the block length for DDR mode */
24195af8f45cSAndrew Gabbasov 	if (mmc->ddr_mode) {
24205af8f45cSAndrew Gabbasov 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
2421e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE)
24225af8f45cSAndrew Gabbasov 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
2423e6fa5a54SJean-Jacques Hiblot #endif
24245af8f45cSAndrew Gabbasov 	}
24255af8f45cSAndrew Gabbasov 
2426272cc70bSAndy Fleming 	/* fill in device description */
2427c40fdca6SSimon Glass 	bdesc = mmc_get_blk_desc(mmc);
2428c40fdca6SSimon Glass 	bdesc->lun = 0;
2429c40fdca6SSimon Glass 	bdesc->hwpart = 0;
2430c40fdca6SSimon Glass 	bdesc->type = 0;
2431c40fdca6SSimon Glass 	bdesc->blksz = mmc->read_bl_len;
2432c40fdca6SSimon Glass 	bdesc->log2blksz = LOG2(bdesc->blksz);
2433c40fdca6SSimon Glass 	bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len);
2434fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \
2435fc011f64SSjoerd Simons 		(defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \
2436fc011f64SSjoerd Simons 		!defined(CONFIG_USE_TINY_PRINTF))
2437c40fdca6SSimon Glass 	sprintf(bdesc->vendor, "Man %06x Snr %04x%04x",
2438babce5f6STaylor Hutt 		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
2439babce5f6STaylor Hutt 		(mmc->cid[3] >> 16) & 0xffff);
2440c40fdca6SSimon Glass 	sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
24410b453ffeSRabin Vincent 		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
2442babce5f6STaylor Hutt 		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
2443babce5f6STaylor Hutt 		(mmc->cid[2] >> 24) & 0xff);
2444c40fdca6SSimon Glass 	sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
2445babce5f6STaylor Hutt 		(mmc->cid[2] >> 16) & 0xf);
244656196826SPaul Burton #else
2447c40fdca6SSimon Glass 	bdesc->vendor[0] = 0;
2448c40fdca6SSimon Glass 	bdesc->product[0] = 0;
2449c40fdca6SSimon Glass 	bdesc->revision[0] = 0;
245056196826SPaul Burton #endif
2451272cc70bSAndy Fleming 
2452*eef05fd3SAndre Przywara #if !defined(CONFIG_DM_MMC) && (!defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT))
2453*eef05fd3SAndre Przywara 	part_init(bdesc);
2454*eef05fd3SAndre Przywara #endif
2455*eef05fd3SAndre Przywara 
2456272cc70bSAndy Fleming 	return 0;
2457272cc70bSAndy Fleming }
2458272cc70bSAndy Fleming 
2459fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc)
2460272cc70bSAndy Fleming {
2461272cc70bSAndy Fleming 	struct mmc_cmd cmd;
2462272cc70bSAndy Fleming 	int err;
2463272cc70bSAndy Fleming 
2464272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
2465272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
246693bfd616SPantelis Antoniou 	cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa;
2467272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
2468272cc70bSAndy Fleming 
2469272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
2470272cc70bSAndy Fleming 
2471272cc70bSAndy Fleming 	if (err)
2472272cc70bSAndy Fleming 		return err;
2473272cc70bSAndy Fleming 
2474998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
2475915ffa52SJaehoon Chung 		return -EOPNOTSUPP;
2476272cc70bSAndy Fleming 	else
2477272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
2478272cc70bSAndy Fleming 
2479272cc70bSAndy Fleming 	return 0;
2480272cc70bSAndy Fleming }
2481272cc70bSAndy Fleming 
2482c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
248395de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */
248495de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void)
248595de9ab2SPaul Kocialkowski {
248695de9ab2SPaul Kocialkowski }
248705cbeb7cSSimon Glass #endif
248895de9ab2SPaul Kocialkowski 
24892051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc)
24902051aefeSPeng Fan {
2491c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
249206ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR)
24932051aefeSPeng Fan 	int ret;
24942051aefeSPeng Fan 
24952051aefeSPeng Fan 	ret = device_get_supply_regulator(mmc->dev, "vmmc-supply",
249606ec045fSJean-Jacques Hiblot 					  &mmc->vmmc_supply);
249706ec045fSJean-Jacques Hiblot 	if (ret)
2498d4d64889SMasahiro Yamada 		pr_debug("%s: No vmmc supply\n", mmc->dev->name);
24992051aefeSPeng Fan 
250006ec045fSJean-Jacques Hiblot 	ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply",
250106ec045fSJean-Jacques Hiblot 					  &mmc->vqmmc_supply);
250206ec045fSJean-Jacques Hiblot 	if (ret)
2503d4d64889SMasahiro Yamada 		pr_debug("%s: No vqmmc supply\n", mmc->dev->name);
25042051aefeSPeng Fan #endif
250505cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */
250605cbeb7cSSimon Glass 	/*
250705cbeb7cSSimon Glass 	 * Driver model should use a regulator, as above, rather than calling
250805cbeb7cSSimon Glass 	 * out to board code.
250905cbeb7cSSimon Glass 	 */
251005cbeb7cSSimon Glass 	board_mmc_power_init();
251105cbeb7cSSimon Glass #endif
25122051aefeSPeng Fan 	return 0;
25132051aefeSPeng Fan }
25142051aefeSPeng Fan 
2515fb7c3bebSKishon Vijay Abraham I /*
2516fb7c3bebSKishon Vijay Abraham I  * put the host in the initial state:
2517fb7c3bebSKishon Vijay Abraham I  * - turn on Vdd (card power supply)
2518fb7c3bebSKishon Vijay Abraham I  * - configure the bus width and clock to minimal values
2519fb7c3bebSKishon Vijay Abraham I  */
2520fb7c3bebSKishon Vijay Abraham I static void mmc_set_initial_state(struct mmc *mmc)
2521fb7c3bebSKishon Vijay Abraham I {
2522fb7c3bebSKishon Vijay Abraham I 	int err;
2523fb7c3bebSKishon Vijay Abraham I 
2524fb7c3bebSKishon Vijay Abraham I 	/* First try to set 3.3V. If it fails set to 1.8V */
2525fb7c3bebSKishon Vijay Abraham I 	err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_330);
2526fb7c3bebSKishon Vijay Abraham I 	if (err != 0)
2527fb7c3bebSKishon Vijay Abraham I 		err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_180);
2528fb7c3bebSKishon Vijay Abraham I 	if (err != 0)
2529d8e3d420SJean-Jacques Hiblot 		pr_warn("mmc: failed to set signal voltage\n");
2530fb7c3bebSKishon Vijay Abraham I 
2531fb7c3bebSKishon Vijay Abraham I 	mmc_select_mode(mmc, MMC_LEGACY);
2532fb7c3bebSKishon Vijay Abraham I 	mmc_set_bus_width(mmc, 1);
253365117182SJaehoon Chung 	mmc_set_clock(mmc, 0, MMC_CLK_ENABLE);
2534fb7c3bebSKishon Vijay Abraham I }
2535fb7c3bebSKishon Vijay Abraham I 
2536fb7c3bebSKishon Vijay Abraham I static int mmc_power_on(struct mmc *mmc)
2537fb7c3bebSKishon Vijay Abraham I {
2538fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR)
2539fb7c3bebSKishon Vijay Abraham I 	if (mmc->vmmc_supply) {
2540fb7c3bebSKishon Vijay Abraham I 		int ret = regulator_set_enable(mmc->vmmc_supply, true);
2541fb7c3bebSKishon Vijay Abraham I 
2542fb7c3bebSKishon Vijay Abraham I 		if (ret) {
2543fb7c3bebSKishon Vijay Abraham I 			puts("Error enabling VMMC supply\n");
2544fb7c3bebSKishon Vijay Abraham I 			return ret;
2545fb7c3bebSKishon Vijay Abraham I 		}
2546fb7c3bebSKishon Vijay Abraham I 	}
2547fb7c3bebSKishon Vijay Abraham I #endif
2548fb7c3bebSKishon Vijay Abraham I 	return 0;
2549fb7c3bebSKishon Vijay Abraham I }
2550fb7c3bebSKishon Vijay Abraham I 
2551fb7c3bebSKishon Vijay Abraham I static int mmc_power_off(struct mmc *mmc)
2552fb7c3bebSKishon Vijay Abraham I {
255365117182SJaehoon Chung 	mmc_set_clock(mmc, 0, MMC_CLK_DISABLE);
2554fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR)
2555fb7c3bebSKishon Vijay Abraham I 	if (mmc->vmmc_supply) {
2556fb7c3bebSKishon Vijay Abraham I 		int ret = regulator_set_enable(mmc->vmmc_supply, false);
2557fb7c3bebSKishon Vijay Abraham I 
2558fb7c3bebSKishon Vijay Abraham I 		if (ret) {
2559d4d64889SMasahiro Yamada 			pr_debug("Error disabling VMMC supply\n");
2560fb7c3bebSKishon Vijay Abraham I 			return ret;
2561fb7c3bebSKishon Vijay Abraham I 		}
2562fb7c3bebSKishon Vijay Abraham I 	}
2563fb7c3bebSKishon Vijay Abraham I #endif
2564fb7c3bebSKishon Vijay Abraham I 	return 0;
2565fb7c3bebSKishon Vijay Abraham I }
2566fb7c3bebSKishon Vijay Abraham I 
2567fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc)
2568fb7c3bebSKishon Vijay Abraham I {
2569fb7c3bebSKishon Vijay Abraham I 	int ret;
2570fb7c3bebSKishon Vijay Abraham I 
2571fb7c3bebSKishon Vijay Abraham I 	ret = mmc_power_off(mmc);
2572fb7c3bebSKishon Vijay Abraham I 	if (ret)
2573fb7c3bebSKishon Vijay Abraham I 		return ret;
2574fb7c3bebSKishon Vijay Abraham I 	/*
2575fb7c3bebSKishon Vijay Abraham I 	 * SD spec recommends at least 1ms of delay. Let's wait for 2ms
2576fb7c3bebSKishon Vijay Abraham I 	 * to be on the safer side.
2577fb7c3bebSKishon Vijay Abraham I 	 */
2578fb7c3bebSKishon Vijay Abraham I 	udelay(2000);
2579fb7c3bebSKishon Vijay Abraham I 	return mmc_power_on(mmc);
2580fb7c3bebSKishon Vijay Abraham I }
2581fb7c3bebSKishon Vijay Abraham I 
25826c09eba5SJon Nettleton int mmc_get_op_cond(struct mmc *mmc)
2583272cc70bSAndy Fleming {
2584c10b85d6SJean-Jacques Hiblot 	bool uhs_en = supports_uhs(mmc->cfg->host_caps);
2585afd5932bSMacpaul Lin 	int err;
2586272cc70bSAndy Fleming 
2587bc897b1dSLei Wen 	if (mmc->has_init)
2588bc897b1dSLei Wen 		return 0;
2589bc897b1dSLei Wen 
25905a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
25915a8dbdc6SYangbo Lu 	mmc_adapter_card_type_ident();
25925a8dbdc6SYangbo Lu #endif
25932051aefeSPeng Fan 	err = mmc_power_init(mmc);
25942051aefeSPeng Fan 	if (err)
25952051aefeSPeng Fan 		return err;
259695de9ab2SPaul Kocialkowski 
259783dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS
259883dc4227SKishon Vijay Abraham I 	mmc->quirks = MMC_QUIRK_RETRY_SET_BLOCKLEN |
259983dc4227SKishon Vijay Abraham I 		      MMC_QUIRK_RETRY_SEND_CID;
260083dc4227SKishon Vijay Abraham I #endif
260183dc4227SKishon Vijay Abraham I 
260204a2ea24SJean-Jacques Hiblot 	err = mmc_power_cycle(mmc);
260304a2ea24SJean-Jacques Hiblot 	if (err) {
260404a2ea24SJean-Jacques Hiblot 		/*
260504a2ea24SJean-Jacques Hiblot 		 * if power cycling is not supported, we should not try
260604a2ea24SJean-Jacques Hiblot 		 * to use the UHS modes, because we wouldn't be able to
260704a2ea24SJean-Jacques Hiblot 		 * recover from an error during the UHS initialization.
260804a2ea24SJean-Jacques Hiblot 		 */
2609d4d64889SMasahiro Yamada 		pr_debug("Unable to do a full power cycle. Disabling the UHS modes for safety\n");
261004a2ea24SJean-Jacques Hiblot 		uhs_en = false;
261104a2ea24SJean-Jacques Hiblot 		mmc->host_caps &= ~UHS_CAPS;
2612fb7c3bebSKishon Vijay Abraham I 		err = mmc_power_on(mmc);
261304a2ea24SJean-Jacques Hiblot 	}
2614fb7c3bebSKishon Vijay Abraham I 	if (err)
2615fb7c3bebSKishon Vijay Abraham I 		return err;
2616fb7c3bebSKishon Vijay Abraham I 
2617e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
26188ca51e51SSimon Glass 	/* The device has already been probed ready for use */
26198ca51e51SSimon Glass #else
2620ab769f22SPantelis Antoniou 	/* made sure it's not NULL earlier */
262193bfd616SPantelis Antoniou 	err = mmc->cfg->ops->init(mmc);
2622272cc70bSAndy Fleming 	if (err)
2623272cc70bSAndy Fleming 		return err;
26248ca51e51SSimon Glass #endif
2625786e8f81SAndrew Gabbasov 	mmc->ddr_mode = 0;
2626aff5d3c8SKishon Vijay Abraham I 
2627c10b85d6SJean-Jacques Hiblot retry:
2628fb7c3bebSKishon Vijay Abraham I 	mmc_set_initial_state(mmc);
2629318a7a57SJean-Jacques Hiblot 	mmc_send_init_stream(mmc);
2630318a7a57SJean-Jacques Hiblot 
2631272cc70bSAndy Fleming 	/* Reset the Card */
2632272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
2633272cc70bSAndy Fleming 
2634272cc70bSAndy Fleming 	if (err)
2635272cc70bSAndy Fleming 		return err;
2636272cc70bSAndy Fleming 
2637bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
2638c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->hwpart = 0;
2639bc897b1dSLei Wen 
2640272cc70bSAndy Fleming 	/* Test for SD version 2 */
2641272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
2642272cc70bSAndy Fleming 
2643272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
2644c10b85d6SJean-Jacques Hiblot 	err = sd_send_op_cond(mmc, uhs_en);
2645c10b85d6SJean-Jacques Hiblot 	if (err && uhs_en) {
2646c10b85d6SJean-Jacques Hiblot 		uhs_en = false;
2647c10b85d6SJean-Jacques Hiblot 		mmc_power_cycle(mmc);
2648c10b85d6SJean-Jacques Hiblot 		goto retry;
2649c10b85d6SJean-Jacques Hiblot 	}
2650272cc70bSAndy Fleming 
2651272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
2652915ffa52SJaehoon Chung 	if (err == -ETIMEDOUT) {
2653272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
2654272cc70bSAndy Fleming 
2655bd47c135SAndrew Gabbasov 		if (err) {
265656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2657d8e3d420SJean-Jacques Hiblot 			pr_err("Card did not respond to voltage select!\n");
265856196826SPaul Burton #endif
2659915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
2660272cc70bSAndy Fleming 		}
2661272cc70bSAndy Fleming 	}
2662272cc70bSAndy Fleming 
26636c09eba5SJon Nettleton 	return err;
26646c09eba5SJon Nettleton }
26656c09eba5SJon Nettleton 
26666c09eba5SJon Nettleton int mmc_start_init(struct mmc *mmc)
26676c09eba5SJon Nettleton {
26686c09eba5SJon Nettleton 	bool no_card;
26696c09eba5SJon Nettleton 	int err = 0;
26706c09eba5SJon Nettleton 
26716c09eba5SJon Nettleton 	/*
26726c09eba5SJon Nettleton 	 * all hosts are capable of 1 bit bus-width and able to use the legacy
26736c09eba5SJon Nettleton 	 * timings.
26746c09eba5SJon Nettleton 	 */
26756c09eba5SJon Nettleton 	mmc->host_caps = mmc->cfg->host_caps | MMC_CAP(SD_LEGACY) |
26766c09eba5SJon Nettleton 			 MMC_CAP(MMC_LEGACY) | MMC_MODE_1BIT;
26776c09eba5SJon Nettleton 
26786c09eba5SJon Nettleton #if !defined(CONFIG_MMC_BROKEN_CD)
26796c09eba5SJon Nettleton 	/* we pretend there's no card when init is NULL */
26806c09eba5SJon Nettleton 	no_card = mmc_getcd(mmc) == 0;
26816c09eba5SJon Nettleton #else
26826c09eba5SJon Nettleton 	no_card = 0;
26836c09eba5SJon Nettleton #endif
26846c09eba5SJon Nettleton #if !CONFIG_IS_ENABLED(DM_MMC)
26856c09eba5SJon Nettleton 	no_card = no_card || (mmc->cfg->ops->init == NULL);
26866c09eba5SJon Nettleton #endif
26876c09eba5SJon Nettleton 	if (no_card) {
26886c09eba5SJon Nettleton 		mmc->has_init = 0;
26896c09eba5SJon Nettleton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
26906c09eba5SJon Nettleton 		pr_err("MMC: no card present\n");
26916c09eba5SJon Nettleton #endif
26926c09eba5SJon Nettleton 		return -ENOMEDIUM;
26936c09eba5SJon Nettleton 	}
26946c09eba5SJon Nettleton 
26956c09eba5SJon Nettleton 	err = mmc_get_op_cond(mmc);
26966c09eba5SJon Nettleton 
2697bd47c135SAndrew Gabbasov 	if (!err)
2698e9550449SChe-Liang Chiou 		mmc->init_in_progress = 1;
2699e9550449SChe-Liang Chiou 
2700e9550449SChe-Liang Chiou 	return err;
2701e9550449SChe-Liang Chiou }
2702e9550449SChe-Liang Chiou 
2703e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc)
2704e9550449SChe-Liang Chiou {
2705e9550449SChe-Liang Chiou 	int err = 0;
2706e9550449SChe-Liang Chiou 
2707bd47c135SAndrew Gabbasov 	mmc->init_in_progress = 0;
2708e9550449SChe-Liang Chiou 	if (mmc->op_cond_pending)
2709e9550449SChe-Liang Chiou 		err = mmc_complete_op_cond(mmc);
2710e9550449SChe-Liang Chiou 
2711e9550449SChe-Liang Chiou 	if (!err)
2712bc897b1dSLei Wen 		err = mmc_startup(mmc);
2713bc897b1dSLei Wen 	if (err)
2714bc897b1dSLei Wen 		mmc->has_init = 0;
2715bc897b1dSLei Wen 	else
2716bc897b1dSLei Wen 		mmc->has_init = 1;
2717e9550449SChe-Liang Chiou 	return err;
2718e9550449SChe-Liang Chiou }
2719e9550449SChe-Liang Chiou 
2720e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc)
2721e9550449SChe-Liang Chiou {
2722bd47c135SAndrew Gabbasov 	int err = 0;
272336332b6eSVipul Kumar 	__maybe_unused ulong start;
2724c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
272533fb211dSSimon Glass 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev);
2726e9550449SChe-Liang Chiou 
272733fb211dSSimon Glass 	upriv->mmc = mmc;
272833fb211dSSimon Glass #endif
2729e9550449SChe-Liang Chiou 	if (mmc->has_init)
2730e9550449SChe-Liang Chiou 		return 0;
2731d803fea5SMateusz Zalega 
2732d803fea5SMateusz Zalega 	start = get_timer(0);
2733d803fea5SMateusz Zalega 
2734e9550449SChe-Liang Chiou 	if (!mmc->init_in_progress)
2735e9550449SChe-Liang Chiou 		err = mmc_start_init(mmc);
2736e9550449SChe-Liang Chiou 
2737bd47c135SAndrew Gabbasov 	if (!err)
2738e9550449SChe-Liang Chiou 		err = mmc_complete_init(mmc);
2739919b4858SJagan Teki 	if (err)
2740d4d64889SMasahiro Yamada 		pr_info("%s: %d, time %lu\n", __func__, err, get_timer(start));
2741919b4858SJagan Teki 
2742bc897b1dSLei Wen 	return err;
2743272cc70bSAndy Fleming }
2744272cc70bSAndy Fleming 
2745ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val)
2746ab71188cSMarkus Niebel {
2747ab71188cSMarkus Niebel 	mmc->dsr = val;
2748ab71188cSMarkus Niebel 	return 0;
2749ab71188cSMarkus Niebel }
2750ab71188cSMarkus Niebel 
2751cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */
2752cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis)
2753272cc70bSAndy Fleming {
2754272cc70bSAndy Fleming 	return -1;
2755272cc70bSAndy Fleming }
2756272cc70bSAndy Fleming 
2757cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */
2758cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis)
2759cee9ab7cSJeroen Hofstee {
2760cee9ab7cSJeroen Hofstee 	return -1;
2761cee9ab7cSJeroen Hofstee }
2762272cc70bSAndy Fleming 
2763e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit)
2764e9550449SChe-Liang Chiou {
2765e9550449SChe-Liang Chiou 	mmc->preinit = preinit;
2766e9550449SChe-Liang Chiou }
2767e9550449SChe-Liang Chiou 
27688a856db2SFaiz Abbas #if CONFIG_IS_ENABLED(DM_MMC)
27698e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
27708e3332e2SSjoerd Simons {
27714a1db6d8SSimon Glass 	int ret, i;
27728e3332e2SSjoerd Simons 	struct uclass *uc;
27734a1db6d8SSimon Glass 	struct udevice *dev;
27748e3332e2SSjoerd Simons 
27758e3332e2SSjoerd Simons 	ret = uclass_get(UCLASS_MMC, &uc);
27768e3332e2SSjoerd Simons 	if (ret)
27778e3332e2SSjoerd Simons 		return ret;
27788e3332e2SSjoerd Simons 
27794a1db6d8SSimon Glass 	/*
27804a1db6d8SSimon Glass 	 * Try to add them in sequence order. Really with driver model we
27814a1db6d8SSimon Glass 	 * should allow holes, but the current MMC list does not allow that.
27824a1db6d8SSimon Glass 	 * So if we request 0, 1, 3 we will get 0, 1, 2.
27834a1db6d8SSimon Glass 	 */
27844a1db6d8SSimon Glass 	for (i = 0; ; i++) {
27854a1db6d8SSimon Glass 		ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev);
27864a1db6d8SSimon Glass 		if (ret == -ENODEV)
27874a1db6d8SSimon Glass 			break;
27884a1db6d8SSimon Glass 	}
27894a1db6d8SSimon Glass 	uclass_foreach_dev(dev, uc) {
27904a1db6d8SSimon Glass 		ret = device_probe(dev);
27918e3332e2SSjoerd Simons 		if (ret)
2792d8e3d420SJean-Jacques Hiblot 			pr_err("%s - probe failed: %d\n", dev->name, ret);
27938e3332e2SSjoerd Simons 	}
27948e3332e2SSjoerd Simons 
27958e3332e2SSjoerd Simons 	return 0;
27968e3332e2SSjoerd Simons }
27978e3332e2SSjoerd Simons #else
27988e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
27998e3332e2SSjoerd Simons {
28008e3332e2SSjoerd Simons 	if (board_mmc_init(bis) < 0)
28018e3332e2SSjoerd Simons 		cpu_mmc_init(bis);
28028e3332e2SSjoerd Simons 
28038e3332e2SSjoerd Simons 	return 0;
28048e3332e2SSjoerd Simons }
28058e3332e2SSjoerd Simons #endif
2806e9550449SChe-Liang Chiou 
2807272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
2808272cc70bSAndy Fleming {
28091b26bab1SDaniel Kochmański 	static int initialized = 0;
28108e3332e2SSjoerd Simons 	int ret;
28111b26bab1SDaniel Kochmański 	if (initialized)	/* Avoid initializing mmc multiple times */
28121b26bab1SDaniel Kochmański 		return 0;
28131b26bab1SDaniel Kochmański 	initialized = 1;
28141b26bab1SDaniel Kochmański 
2815c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK)
2816b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY)
2817c40fdca6SSimon Glass 	mmc_list_init();
2818c40fdca6SSimon Glass #endif
2819b5b838f1SMarek Vasut #endif
28208e3332e2SSjoerd Simons 	ret = mmc_probe(bis);
28218e3332e2SSjoerd Simons 	if (ret)
28228e3332e2SSjoerd Simons 		return ret;
2823272cc70bSAndy Fleming 
2824bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD
2825272cc70bSAndy Fleming 	print_mmc_devices(',');
2826bb0dc108SYing Zhang #endif
2827272cc70bSAndy Fleming 
2828c40fdca6SSimon Glass 	mmc_do_preinit();
2829272cc70bSAndy Fleming 	return 0;
2830272cc70bSAndy Fleming }
2831cd3d4880STomas Melin 
2832cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE
2833cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc)
2834cd3d4880STomas Melin {
2835cd3d4880STomas Melin 	int err;
2836cd3d4880STomas Melin 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
2837cd3d4880STomas Melin 
2838cd3d4880STomas Melin 	err = mmc_send_ext_csd(mmc, ext_csd);
2839cd3d4880STomas Melin 	if (err) {
2840cd3d4880STomas Melin 		puts("Could not get ext_csd register values\n");
2841cd3d4880STomas Melin 		return err;
2842cd3d4880STomas Melin 	}
2843cd3d4880STomas Melin 
2844cd3d4880STomas Melin 	if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) {
2845cd3d4880STomas Melin 		puts("Background operations not supported on device\n");
2846cd3d4880STomas Melin 		return -EMEDIUMTYPE;
2847cd3d4880STomas Melin 	}
2848cd3d4880STomas Melin 
2849cd3d4880STomas Melin 	if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) {
2850cd3d4880STomas Melin 		puts("Background operations already enabled\n");
2851cd3d4880STomas Melin 		return 0;
2852cd3d4880STomas Melin 	}
2853cd3d4880STomas Melin 
2854cd3d4880STomas Melin 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1);
2855cd3d4880STomas Melin 	if (err) {
2856cd3d4880STomas Melin 		puts("Failed to enable manual background operations\n");
2857cd3d4880STomas Melin 		return err;
2858cd3d4880STomas Melin 	}
2859cd3d4880STomas Melin 
2860cd3d4880STomas Melin 	puts("Enabled manual background operations\n");
2861cd3d4880STomas Melin 
2862cd3d4880STomas Melin 	return 0;
2863cd3d4880STomas Melin }
2864cd3d4880STomas Melin #endif
2865