xref: /openbmc/u-boot/drivers/mmc/mmc.c (revision 5b2e72f3)
1272cc70bSAndy Fleming /*
2272cc70bSAndy Fleming  * Copyright 2008, Freescale Semiconductor, Inc
3272cc70bSAndy Fleming  * Andy Fleming
4272cc70bSAndy Fleming  *
5272cc70bSAndy Fleming  * Based vaguely on the Linux code
6272cc70bSAndy Fleming  *
71a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
8272cc70bSAndy Fleming  */
9272cc70bSAndy Fleming 
10272cc70bSAndy Fleming #include <config.h>
11272cc70bSAndy Fleming #include <common.h>
12272cc70bSAndy Fleming #include <command.h>
138e3332e2SSjoerd Simons #include <dm.h>
148e3332e2SSjoerd Simons #include <dm/device-internal.h>
15d4622df3SStephen Warren #include <errno.h>
16272cc70bSAndy Fleming #include <mmc.h>
17272cc70bSAndy Fleming #include <part.h>
182051aefeSPeng Fan #include <power/regulator.h>
19272cc70bSAndy Fleming #include <malloc.h>
20cf92e05cSSimon Glass #include <memalign.h>
21272cc70bSAndy Fleming #include <linux/list.h>
229b1f942cSRabin Vincent #include <div64.h>
23da61fa5fSPaul Burton #include "mmc_private.h"
24272cc70bSAndy Fleming 
25aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage);
26fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc);
2701298da3SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps);
28aff5d3c8SKishon Vijay Abraham I 
29b5b838f1SMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY)
30b5b838f1SMarek Vasut static struct mmc mmc_static;
31b5b838f1SMarek Vasut struct mmc *find_mmc_device(int dev_num)
32b5b838f1SMarek Vasut {
33b5b838f1SMarek Vasut 	return &mmc_static;
34b5b838f1SMarek Vasut }
35b5b838f1SMarek Vasut 
36b5b838f1SMarek Vasut void mmc_do_preinit(void)
37b5b838f1SMarek Vasut {
38b5b838f1SMarek Vasut 	struct mmc *m = &mmc_static;
39b5b838f1SMarek Vasut #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
40b5b838f1SMarek Vasut 	mmc_set_preinit(m, 1);
41b5b838f1SMarek Vasut #endif
42b5b838f1SMarek Vasut 	if (m->preinit)
43b5b838f1SMarek Vasut 		mmc_start_init(m);
44b5b838f1SMarek Vasut }
45b5b838f1SMarek Vasut 
46b5b838f1SMarek Vasut struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
47b5b838f1SMarek Vasut {
48b5b838f1SMarek Vasut 	return &mmc->block_dev;
49b5b838f1SMarek Vasut }
50b5b838f1SMarek Vasut #endif
51b5b838f1SMarek Vasut 
52e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
53c10b85d6SJean-Jacques Hiblot 
54f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
55c10b85d6SJean-Jacques Hiblot static int mmc_wait_dat0(struct mmc *mmc, int state, int timeout)
56c10b85d6SJean-Jacques Hiblot {
57c10b85d6SJean-Jacques Hiblot 	return -ENOSYS;
58c10b85d6SJean-Jacques Hiblot }
59f99c2efeSJean-Jacques Hiblot #endif
60c10b85d6SJean-Jacques Hiblot 
61750121c3SJeroen Hofstee __weak int board_mmc_getwp(struct mmc *mmc)
62d23d8d7eSNikita Kiryanov {
63d23d8d7eSNikita Kiryanov 	return -1;
64d23d8d7eSNikita Kiryanov }
65d23d8d7eSNikita Kiryanov 
66d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc)
67d23d8d7eSNikita Kiryanov {
68d23d8d7eSNikita Kiryanov 	int wp;
69d23d8d7eSNikita Kiryanov 
70d23d8d7eSNikita Kiryanov 	wp = board_mmc_getwp(mmc);
71d23d8d7eSNikita Kiryanov 
72d4e1da4eSPeter Korsgaard 	if (wp < 0) {
7393bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getwp)
7493bfd616SPantelis Antoniou 			wp = mmc->cfg->ops->getwp(mmc);
75d4e1da4eSPeter Korsgaard 		else
76d4e1da4eSPeter Korsgaard 			wp = 0;
77d4e1da4eSPeter Korsgaard 	}
78d23d8d7eSNikita Kiryanov 
79d23d8d7eSNikita Kiryanov 	return wp;
80d23d8d7eSNikita Kiryanov }
81d23d8d7eSNikita Kiryanov 
82cee9ab7cSJeroen Hofstee __weak int board_mmc_getcd(struct mmc *mmc)
83cee9ab7cSJeroen Hofstee {
8411fdade2SStefano Babic 	return -1;
8511fdade2SStefano Babic }
868ca51e51SSimon Glass #endif
8711fdade2SStefano Babic 
888635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE
89c0c76ebaSSimon Glass void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd)
90c0c76ebaSSimon Glass {
91c0c76ebaSSimon Glass 	printf("CMD_SEND:%d\n", cmd->cmdidx);
92c0c76ebaSSimon Glass 	printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg);
93c0c76ebaSSimon Glass }
94c0c76ebaSSimon Glass 
95c0c76ebaSSimon Glass void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret)
96c0c76ebaSSimon Glass {
975db2fe3aSRaffaele Recalcati 	int i;
985db2fe3aSRaffaele Recalcati 	u8 *ptr;
995db2fe3aSRaffaele Recalcati 
1007863ce58SBin Meng 	if (ret) {
1017863ce58SBin Meng 		printf("\t\tRET\t\t\t %d\n", ret);
1027863ce58SBin Meng 	} else {
1035db2fe3aSRaffaele Recalcati 		switch (cmd->resp_type) {
1045db2fe3aSRaffaele Recalcati 		case MMC_RSP_NONE:
1055db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_NONE\n");
1065db2fe3aSRaffaele Recalcati 			break;
1075db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1:
1085db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n",
1095db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1105db2fe3aSRaffaele Recalcati 			break;
1115db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1b:
1125db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n",
1135db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1145db2fe3aSRaffaele Recalcati 			break;
1155db2fe3aSRaffaele Recalcati 		case MMC_RSP_R2:
1165db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R2\t\t 0x%08X \n",
1175db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1185db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1195db2fe3aSRaffaele Recalcati 				cmd->response[1]);
1205db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1215db2fe3aSRaffaele Recalcati 				cmd->response[2]);
1225db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1235db2fe3aSRaffaele Recalcati 				cmd->response[3]);
1245db2fe3aSRaffaele Recalcati 			printf("\n");
1255db2fe3aSRaffaele Recalcati 			printf("\t\t\t\t\tDUMPING DATA\n");
1265db2fe3aSRaffaele Recalcati 			for (i = 0; i < 4; i++) {
1275db2fe3aSRaffaele Recalcati 				int j;
1285db2fe3aSRaffaele Recalcati 				printf("\t\t\t\t\t%03d - ", i*4);
129146bec79SDirk Behme 				ptr = (u8 *)&cmd->response[i];
1305db2fe3aSRaffaele Recalcati 				ptr += 3;
1315db2fe3aSRaffaele Recalcati 				for (j = 0; j < 4; j++)
1325db2fe3aSRaffaele Recalcati 					printf("%02X ", *ptr--);
1335db2fe3aSRaffaele Recalcati 				printf("\n");
1345db2fe3aSRaffaele Recalcati 			}
1355db2fe3aSRaffaele Recalcati 			break;
1365db2fe3aSRaffaele Recalcati 		case MMC_RSP_R3:
1375db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n",
1385db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1395db2fe3aSRaffaele Recalcati 			break;
1405db2fe3aSRaffaele Recalcati 		default:
1415db2fe3aSRaffaele Recalcati 			printf("\t\tERROR MMC rsp not supported\n");
1425db2fe3aSRaffaele Recalcati 			break;
1435db2fe3aSRaffaele Recalcati 		}
1447863ce58SBin Meng 	}
145c0c76ebaSSimon Glass }
146c0c76ebaSSimon Glass 
147c0c76ebaSSimon Glass void mmc_trace_state(struct mmc *mmc, struct mmc_cmd *cmd)
148c0c76ebaSSimon Glass {
149c0c76ebaSSimon Glass 	int status;
150c0c76ebaSSimon Glass 
151c0c76ebaSSimon Glass 	status = (cmd->response[0] & MMC_STATUS_CURR_STATE) >> 9;
152c0c76ebaSSimon Glass 	printf("CURR STATE:%d\n", status);
153c0c76ebaSSimon Glass }
1545db2fe3aSRaffaele Recalcati #endif
155c0c76ebaSSimon Glass 
15635f9e196SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG)
15735f9e196SJean-Jacques Hiblot const char *mmc_mode_name(enum bus_mode mode)
15835f9e196SJean-Jacques Hiblot {
15935f9e196SJean-Jacques Hiblot 	static const char *const names[] = {
16035f9e196SJean-Jacques Hiblot 	      [MMC_LEGACY]	= "MMC legacy",
16135f9e196SJean-Jacques Hiblot 	      [SD_LEGACY]	= "SD Legacy",
16235f9e196SJean-Jacques Hiblot 	      [MMC_HS]		= "MMC High Speed (26MHz)",
16335f9e196SJean-Jacques Hiblot 	      [SD_HS]		= "SD High Speed (50MHz)",
16435f9e196SJean-Jacques Hiblot 	      [UHS_SDR12]	= "UHS SDR12 (25MHz)",
16535f9e196SJean-Jacques Hiblot 	      [UHS_SDR25]	= "UHS SDR25 (50MHz)",
16635f9e196SJean-Jacques Hiblot 	      [UHS_SDR50]	= "UHS SDR50 (100MHz)",
16735f9e196SJean-Jacques Hiblot 	      [UHS_SDR104]	= "UHS SDR104 (208MHz)",
16835f9e196SJean-Jacques Hiblot 	      [UHS_DDR50]	= "UHS DDR50 (50MHz)",
16935f9e196SJean-Jacques Hiblot 	      [MMC_HS_52]	= "MMC High Speed (52MHz)",
17035f9e196SJean-Jacques Hiblot 	      [MMC_DDR_52]	= "MMC DDR52 (52MHz)",
17135f9e196SJean-Jacques Hiblot 	      [MMC_HS_200]	= "HS200 (200MHz)",
17235f9e196SJean-Jacques Hiblot 	};
17335f9e196SJean-Jacques Hiblot 
17435f9e196SJean-Jacques Hiblot 	if (mode >= MMC_MODES_END)
17535f9e196SJean-Jacques Hiblot 		return "Unknown mode";
17635f9e196SJean-Jacques Hiblot 	else
17735f9e196SJean-Jacques Hiblot 		return names[mode];
17835f9e196SJean-Jacques Hiblot }
17935f9e196SJean-Jacques Hiblot #endif
18035f9e196SJean-Jacques Hiblot 
18105038576SJean-Jacques Hiblot static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode)
18205038576SJean-Jacques Hiblot {
18305038576SJean-Jacques Hiblot 	static const int freqs[] = {
18405038576SJean-Jacques Hiblot 	      [SD_LEGACY]	= 25000000,
18505038576SJean-Jacques Hiblot 	      [MMC_HS]		= 26000000,
18605038576SJean-Jacques Hiblot 	      [SD_HS]		= 50000000,
187f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
18805038576SJean-Jacques Hiblot 	      [UHS_SDR12]	= 25000000,
18905038576SJean-Jacques Hiblot 	      [UHS_SDR25]	= 50000000,
19005038576SJean-Jacques Hiblot 	      [UHS_SDR50]	= 100000000,
19105038576SJean-Jacques Hiblot 	      [UHS_DDR50]	= 50000000,
192f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
193f99c2efeSJean-Jacques Hiblot 	      [UHS_SDR104]	= 208000000,
194f99c2efeSJean-Jacques Hiblot #endif
195f99c2efeSJean-Jacques Hiblot #endif
19605038576SJean-Jacques Hiblot 	      [MMC_HS_52]	= 52000000,
19705038576SJean-Jacques Hiblot 	      [MMC_DDR_52]	= 52000000,
198f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
19905038576SJean-Jacques Hiblot 	      [MMC_HS_200]	= 200000000,
200f99c2efeSJean-Jacques Hiblot #endif
20105038576SJean-Jacques Hiblot 	};
20205038576SJean-Jacques Hiblot 
20305038576SJean-Jacques Hiblot 	if (mode == MMC_LEGACY)
20405038576SJean-Jacques Hiblot 		return mmc->legacy_speed;
20505038576SJean-Jacques Hiblot 	else if (mode >= MMC_MODES_END)
20605038576SJean-Jacques Hiblot 		return 0;
20705038576SJean-Jacques Hiblot 	else
20805038576SJean-Jacques Hiblot 		return freqs[mode];
20905038576SJean-Jacques Hiblot }
21005038576SJean-Jacques Hiblot 
21135f9e196SJean-Jacques Hiblot static int mmc_select_mode(struct mmc *mmc, enum bus_mode mode)
21235f9e196SJean-Jacques Hiblot {
21335f9e196SJean-Jacques Hiblot 	mmc->selected_mode = mode;
21405038576SJean-Jacques Hiblot 	mmc->tran_speed = mmc_mode2freq(mmc, mode);
2153862b854SJean-Jacques Hiblot 	mmc->ddr_mode = mmc_is_mode_ddr(mode);
21635f9e196SJean-Jacques Hiblot 	debug("selecting mode %s (freq : %d MHz)\n", mmc_mode_name(mode),
21735f9e196SJean-Jacques Hiblot 	      mmc->tran_speed / 1000000);
21835f9e196SJean-Jacques Hiblot 	return 0;
21935f9e196SJean-Jacques Hiblot }
22035f9e196SJean-Jacques Hiblot 
221e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
222c0c76ebaSSimon Glass int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
223c0c76ebaSSimon Glass {
224c0c76ebaSSimon Glass 	int ret;
225c0c76ebaSSimon Glass 
226c0c76ebaSSimon Glass 	mmmc_trace_before_send(mmc, cmd);
227c0c76ebaSSimon Glass 	ret = mmc->cfg->ops->send_cmd(mmc, cmd, data);
228c0c76ebaSSimon Glass 	mmmc_trace_after_send(mmc, cmd, ret);
229c0c76ebaSSimon Glass 
2308635ff9eSMarek Vasut 	return ret;
231272cc70bSAndy Fleming }
2328ca51e51SSimon Glass #endif
233272cc70bSAndy Fleming 
234da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout)
2355d4fc8d9SRaffaele Recalcati {
2365d4fc8d9SRaffaele Recalcati 	struct mmc_cmd cmd;
237d617c426SJan Kloetzke 	int err, retries = 5;
2385d4fc8d9SRaffaele Recalcati 
2395d4fc8d9SRaffaele Recalcati 	cmd.cmdidx = MMC_CMD_SEND_STATUS;
2405d4fc8d9SRaffaele Recalcati 	cmd.resp_type = MMC_RSP_R1;
241aaf3d41aSMarek Vasut 	if (!mmc_host_is_spi(mmc))
242aaf3d41aSMarek Vasut 		cmd.cmdarg = mmc->rca << 16;
2435d4fc8d9SRaffaele Recalcati 
2441677eef4SAndrew Gabbasov 	while (1) {
2455d4fc8d9SRaffaele Recalcati 		err = mmc_send_cmd(mmc, &cmd, NULL);
246d617c426SJan Kloetzke 		if (!err) {
247d617c426SJan Kloetzke 			if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) &&
248d617c426SJan Kloetzke 			    (cmd.response[0] & MMC_STATUS_CURR_STATE) !=
249d617c426SJan Kloetzke 			     MMC_STATE_PRG)
2505d4fc8d9SRaffaele Recalcati 				break;
251d0c221feSJean-Jacques Hiblot 
252d0c221feSJean-Jacques Hiblot 			if (cmd.response[0] & MMC_STATUS_MASK) {
25356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
254d8e3d420SJean-Jacques Hiblot 				pr_err("Status Error: 0x%08X\n",
255d617c426SJan Kloetzke 				       cmd.response[0]);
25656196826SPaul Burton #endif
257915ffa52SJaehoon Chung 				return -ECOMM;
258d617c426SJan Kloetzke 			}
259d617c426SJan Kloetzke 		} else if (--retries < 0)
260d617c426SJan Kloetzke 			return err;
2615d4fc8d9SRaffaele Recalcati 
2621677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
2631677eef4SAndrew Gabbasov 			break;
2645d4fc8d9SRaffaele Recalcati 
2651677eef4SAndrew Gabbasov 		udelay(1000);
2661677eef4SAndrew Gabbasov 	}
2675d4fc8d9SRaffaele Recalcati 
268c0c76ebaSSimon Glass 	mmc_trace_state(mmc, &cmd);
2695b0c942fSJongman Heo 	if (timeout <= 0) {
27056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
271d8e3d420SJean-Jacques Hiblot 		pr_err("Timeout waiting card ready\n");
27256196826SPaul Burton #endif
273915ffa52SJaehoon Chung 		return -ETIMEDOUT;
2745d4fc8d9SRaffaele Recalcati 	}
2755d4fc8d9SRaffaele Recalcati 
2765d4fc8d9SRaffaele Recalcati 	return 0;
2775d4fc8d9SRaffaele Recalcati }
2785d4fc8d9SRaffaele Recalcati 
279da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len)
280272cc70bSAndy Fleming {
281272cc70bSAndy Fleming 	struct mmc_cmd cmd;
28283dc4227SKishon Vijay Abraham I 	int err;
283272cc70bSAndy Fleming 
284786e8f81SAndrew Gabbasov 	if (mmc->ddr_mode)
285d22e3d46SJaehoon Chung 		return 0;
286d22e3d46SJaehoon Chung 
287272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
288272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
289272cc70bSAndy Fleming 	cmd.cmdarg = len;
290272cc70bSAndy Fleming 
29183dc4227SKishon Vijay Abraham I 	err = mmc_send_cmd(mmc, &cmd, NULL);
29283dc4227SKishon Vijay Abraham I 
29383dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS
29483dc4227SKishon Vijay Abraham I 	if (err && (mmc->quirks & MMC_QUIRK_RETRY_SET_BLOCKLEN)) {
29583dc4227SKishon Vijay Abraham I 		int retries = 4;
29683dc4227SKishon Vijay Abraham I 		/*
29783dc4227SKishon Vijay Abraham I 		 * It has been seen that SET_BLOCKLEN may fail on the first
29883dc4227SKishon Vijay Abraham I 		 * attempt, let's try a few more time
29983dc4227SKishon Vijay Abraham I 		 */
30083dc4227SKishon Vijay Abraham I 		do {
30183dc4227SKishon Vijay Abraham I 			err = mmc_send_cmd(mmc, &cmd, NULL);
30283dc4227SKishon Vijay Abraham I 			if (!err)
30383dc4227SKishon Vijay Abraham I 				break;
30483dc4227SKishon Vijay Abraham I 		} while (retries--);
30583dc4227SKishon Vijay Abraham I 	}
30683dc4227SKishon Vijay Abraham I #endif
30783dc4227SKishon Vijay Abraham I 
30883dc4227SKishon Vijay Abraham I 	return err;
309272cc70bSAndy Fleming }
310272cc70bSAndy Fleming 
311f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
3129815e3baSJean-Jacques Hiblot static const u8 tuning_blk_pattern_4bit[] = {
3139815e3baSJean-Jacques Hiblot 	0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
3149815e3baSJean-Jacques Hiblot 	0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
3159815e3baSJean-Jacques Hiblot 	0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
3169815e3baSJean-Jacques Hiblot 	0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
3179815e3baSJean-Jacques Hiblot 	0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
3189815e3baSJean-Jacques Hiblot 	0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
3199815e3baSJean-Jacques Hiblot 	0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
3209815e3baSJean-Jacques Hiblot 	0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
3219815e3baSJean-Jacques Hiblot };
3229815e3baSJean-Jacques Hiblot 
3239815e3baSJean-Jacques Hiblot static const u8 tuning_blk_pattern_8bit[] = {
3249815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
3259815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
3269815e3baSJean-Jacques Hiblot 	0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
3279815e3baSJean-Jacques Hiblot 	0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
3289815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
3299815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
3309815e3baSJean-Jacques Hiblot 	0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
3319815e3baSJean-Jacques Hiblot 	0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
3329815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
3339815e3baSJean-Jacques Hiblot 	0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
3349815e3baSJean-Jacques Hiblot 	0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
3359815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
3369815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
3379815e3baSJean-Jacques Hiblot 	0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
3389815e3baSJean-Jacques Hiblot 	0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
3399815e3baSJean-Jacques Hiblot 	0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
3409815e3baSJean-Jacques Hiblot };
3419815e3baSJean-Jacques Hiblot 
3429815e3baSJean-Jacques Hiblot int mmc_send_tuning(struct mmc *mmc, u32 opcode, int *cmd_error)
3439815e3baSJean-Jacques Hiblot {
3449815e3baSJean-Jacques Hiblot 	struct mmc_cmd cmd;
3459815e3baSJean-Jacques Hiblot 	struct mmc_data data;
3469815e3baSJean-Jacques Hiblot 	const u8 *tuning_block_pattern;
3479815e3baSJean-Jacques Hiblot 	int size, err;
3489815e3baSJean-Jacques Hiblot 
3499815e3baSJean-Jacques Hiblot 	if (mmc->bus_width == 8) {
3509815e3baSJean-Jacques Hiblot 		tuning_block_pattern = tuning_blk_pattern_8bit;
3519815e3baSJean-Jacques Hiblot 		size = sizeof(tuning_blk_pattern_8bit);
3529815e3baSJean-Jacques Hiblot 	} else if (mmc->bus_width == 4) {
3539815e3baSJean-Jacques Hiblot 		tuning_block_pattern = tuning_blk_pattern_4bit;
3549815e3baSJean-Jacques Hiblot 		size = sizeof(tuning_blk_pattern_4bit);
3559815e3baSJean-Jacques Hiblot 	} else {
3569815e3baSJean-Jacques Hiblot 		return -EINVAL;
3579815e3baSJean-Jacques Hiblot 	}
3589815e3baSJean-Jacques Hiblot 
3599815e3baSJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, data_buf, size);
3609815e3baSJean-Jacques Hiblot 
3619815e3baSJean-Jacques Hiblot 	cmd.cmdidx = opcode;
3629815e3baSJean-Jacques Hiblot 	cmd.cmdarg = 0;
3639815e3baSJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
3649815e3baSJean-Jacques Hiblot 
3659815e3baSJean-Jacques Hiblot 	data.dest = (void *)data_buf;
3669815e3baSJean-Jacques Hiblot 	data.blocks = 1;
3679815e3baSJean-Jacques Hiblot 	data.blocksize = size;
3689815e3baSJean-Jacques Hiblot 	data.flags = MMC_DATA_READ;
3699815e3baSJean-Jacques Hiblot 
3709815e3baSJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, &data);
3719815e3baSJean-Jacques Hiblot 	if (err)
3729815e3baSJean-Jacques Hiblot 		return err;
3739815e3baSJean-Jacques Hiblot 
3749815e3baSJean-Jacques Hiblot 	if (memcmp(data_buf, tuning_block_pattern, size))
3759815e3baSJean-Jacques Hiblot 		return -EIO;
3769815e3baSJean-Jacques Hiblot 
3779815e3baSJean-Jacques Hiblot 	return 0;
3789815e3baSJean-Jacques Hiblot }
379f99c2efeSJean-Jacques Hiblot #endif
3809815e3baSJean-Jacques Hiblot 
381ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
382fdbb873eSKim Phillips 			   lbaint_t blkcnt)
383272cc70bSAndy Fleming {
384272cc70bSAndy Fleming 	struct mmc_cmd cmd;
385272cc70bSAndy Fleming 	struct mmc_data data;
386272cc70bSAndy Fleming 
3874a1a06bcSAlagu Sankar 	if (blkcnt > 1)
3884a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
3894a1a06bcSAlagu Sankar 	else
390272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
391272cc70bSAndy Fleming 
392272cc70bSAndy Fleming 	if (mmc->high_capacity)
3934a1a06bcSAlagu Sankar 		cmd.cmdarg = start;
394272cc70bSAndy Fleming 	else
3954a1a06bcSAlagu Sankar 		cmd.cmdarg = start * mmc->read_bl_len;
396272cc70bSAndy Fleming 
397272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
398272cc70bSAndy Fleming 
399272cc70bSAndy Fleming 	data.dest = dst;
4004a1a06bcSAlagu Sankar 	data.blocks = blkcnt;
401272cc70bSAndy Fleming 	data.blocksize = mmc->read_bl_len;
402272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
403272cc70bSAndy Fleming 
4044a1a06bcSAlagu Sankar 	if (mmc_send_cmd(mmc, &cmd, &data))
4054a1a06bcSAlagu Sankar 		return 0;
4064a1a06bcSAlagu Sankar 
4074a1a06bcSAlagu Sankar 	if (blkcnt > 1) {
4084a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
4094a1a06bcSAlagu Sankar 		cmd.cmdarg = 0;
4104a1a06bcSAlagu Sankar 		cmd.resp_type = MMC_RSP_R1b;
4114a1a06bcSAlagu Sankar 		if (mmc_send_cmd(mmc, &cmd, NULL)) {
41256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
413d8e3d420SJean-Jacques Hiblot 			pr_err("mmc fail to send stop cmd\n");
41456196826SPaul Burton #endif
4154a1a06bcSAlagu Sankar 			return 0;
4164a1a06bcSAlagu Sankar 		}
417272cc70bSAndy Fleming 	}
418272cc70bSAndy Fleming 
4194a1a06bcSAlagu Sankar 	return blkcnt;
420272cc70bSAndy Fleming }
421272cc70bSAndy Fleming 
422c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
4237dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst)
42433fb211dSSimon Glass #else
4257dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
4267dba0b93SSimon Glass 		void *dst)
42733fb211dSSimon Glass #endif
428272cc70bSAndy Fleming {
429c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
43033fb211dSSimon Glass 	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
43133fb211dSSimon Glass #endif
432bcce53d0SSimon Glass 	int dev_num = block_dev->devnum;
433873cc1d7SStephen Warren 	int err;
4344a1a06bcSAlagu Sankar 	lbaint_t cur, blocks_todo = blkcnt;
435272cc70bSAndy Fleming 
4364a1a06bcSAlagu Sankar 	if (blkcnt == 0)
4374a1a06bcSAlagu Sankar 		return 0;
4384a1a06bcSAlagu Sankar 
4394a1a06bcSAlagu Sankar 	struct mmc *mmc = find_mmc_device(dev_num);
440272cc70bSAndy Fleming 	if (!mmc)
441272cc70bSAndy Fleming 		return 0;
442272cc70bSAndy Fleming 
443b5b838f1SMarek Vasut 	if (CONFIG_IS_ENABLED(MMC_TINY))
444b5b838f1SMarek Vasut 		err = mmc_switch_part(mmc, block_dev->hwpart);
445b5b838f1SMarek Vasut 	else
44669f45cd5SSimon Glass 		err = blk_dselect_hwpart(block_dev, block_dev->hwpart);
447b5b838f1SMarek Vasut 
448873cc1d7SStephen Warren 	if (err < 0)
449873cc1d7SStephen Warren 		return 0;
450873cc1d7SStephen Warren 
451c40fdca6SSimon Glass 	if ((start + blkcnt) > block_dev->lba) {
45256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
453d8e3d420SJean-Jacques Hiblot 		pr_err("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
454c40fdca6SSimon Glass 		       start + blkcnt, block_dev->lba);
45556196826SPaul Burton #endif
456d2bf29e3SLei Wen 		return 0;
457d2bf29e3SLei Wen 	}
458272cc70bSAndy Fleming 
45911692991SSimon Glass 	if (mmc_set_blocklen(mmc, mmc->read_bl_len)) {
46011692991SSimon Glass 		debug("%s: Failed to set blocklen\n", __func__);
461272cc70bSAndy Fleming 		return 0;
46211692991SSimon Glass 	}
463272cc70bSAndy Fleming 
4644a1a06bcSAlagu Sankar 	do {
46593bfd616SPantelis Antoniou 		cur = (blocks_todo > mmc->cfg->b_max) ?
46693bfd616SPantelis Antoniou 			mmc->cfg->b_max : blocks_todo;
46711692991SSimon Glass 		if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
46811692991SSimon Glass 			debug("%s: Failed to read blocks\n", __func__);
4694a1a06bcSAlagu Sankar 			return 0;
47011692991SSimon Glass 		}
4714a1a06bcSAlagu Sankar 		blocks_todo -= cur;
4724a1a06bcSAlagu Sankar 		start += cur;
4734a1a06bcSAlagu Sankar 		dst += cur * mmc->read_bl_len;
4744a1a06bcSAlagu Sankar 	} while (blocks_todo > 0);
475272cc70bSAndy Fleming 
476272cc70bSAndy Fleming 	return blkcnt;
477272cc70bSAndy Fleming }
478272cc70bSAndy Fleming 
479fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc)
480272cc70bSAndy Fleming {
481272cc70bSAndy Fleming 	struct mmc_cmd cmd;
482272cc70bSAndy Fleming 	int err;
483272cc70bSAndy Fleming 
484272cc70bSAndy Fleming 	udelay(1000);
485272cc70bSAndy Fleming 
486272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
487272cc70bSAndy Fleming 	cmd.cmdarg = 0;
488272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_NONE;
489272cc70bSAndy Fleming 
490272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
491272cc70bSAndy Fleming 
492272cc70bSAndy Fleming 	if (err)
493272cc70bSAndy Fleming 		return err;
494272cc70bSAndy Fleming 
495272cc70bSAndy Fleming 	udelay(2000);
496272cc70bSAndy Fleming 
497272cc70bSAndy Fleming 	return 0;
498272cc70bSAndy Fleming }
499272cc70bSAndy Fleming 
500f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
501c10b85d6SJean-Jacques Hiblot static int mmc_switch_voltage(struct mmc *mmc, int signal_voltage)
502c10b85d6SJean-Jacques Hiblot {
503c10b85d6SJean-Jacques Hiblot 	struct mmc_cmd cmd;
504c10b85d6SJean-Jacques Hiblot 	int err = 0;
505c10b85d6SJean-Jacques Hiblot 
506c10b85d6SJean-Jacques Hiblot 	/*
507c10b85d6SJean-Jacques Hiblot 	 * Send CMD11 only if the request is to switch the card to
508c10b85d6SJean-Jacques Hiblot 	 * 1.8V signalling.
509c10b85d6SJean-Jacques Hiblot 	 */
510c10b85d6SJean-Jacques Hiblot 	if (signal_voltage == MMC_SIGNAL_VOLTAGE_330)
511c10b85d6SJean-Jacques Hiblot 		return mmc_set_signal_voltage(mmc, signal_voltage);
512c10b85d6SJean-Jacques Hiblot 
513c10b85d6SJean-Jacques Hiblot 	cmd.cmdidx = SD_CMD_SWITCH_UHS18V;
514c10b85d6SJean-Jacques Hiblot 	cmd.cmdarg = 0;
515c10b85d6SJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
516c10b85d6SJean-Jacques Hiblot 
517c10b85d6SJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
518c10b85d6SJean-Jacques Hiblot 	if (err)
519c10b85d6SJean-Jacques Hiblot 		return err;
520c10b85d6SJean-Jacques Hiblot 
521c10b85d6SJean-Jacques Hiblot 	if (!mmc_host_is_spi(mmc) && (cmd.response[0] & MMC_STATUS_ERROR))
522c10b85d6SJean-Jacques Hiblot 		return -EIO;
523c10b85d6SJean-Jacques Hiblot 
524c10b85d6SJean-Jacques Hiblot 	/*
525c10b85d6SJean-Jacques Hiblot 	 * The card should drive cmd and dat[0:3] low immediately
526c10b85d6SJean-Jacques Hiblot 	 * after the response of cmd11, but wait 100 us to be sure
527c10b85d6SJean-Jacques Hiblot 	 */
528c10b85d6SJean-Jacques Hiblot 	err = mmc_wait_dat0(mmc, 0, 100);
529c10b85d6SJean-Jacques Hiblot 	if (err == -ENOSYS)
530c10b85d6SJean-Jacques Hiblot 		udelay(100);
531c10b85d6SJean-Jacques Hiblot 	else if (err)
532c10b85d6SJean-Jacques Hiblot 		return -ETIMEDOUT;
533c10b85d6SJean-Jacques Hiblot 
534c10b85d6SJean-Jacques Hiblot 	/*
535c10b85d6SJean-Jacques Hiblot 	 * During a signal voltage level switch, the clock must be gated
536c10b85d6SJean-Jacques Hiblot 	 * for 5 ms according to the SD spec
537c10b85d6SJean-Jacques Hiblot 	 */
538c10b85d6SJean-Jacques Hiblot 	mmc_set_clock(mmc, mmc->clock, true);
539c10b85d6SJean-Jacques Hiblot 
540c10b85d6SJean-Jacques Hiblot 	err = mmc_set_signal_voltage(mmc, signal_voltage);
541c10b85d6SJean-Jacques Hiblot 	if (err)
542c10b85d6SJean-Jacques Hiblot 		return err;
543c10b85d6SJean-Jacques Hiblot 
544c10b85d6SJean-Jacques Hiblot 	/* Keep clock gated for at least 10 ms, though spec only says 5 ms */
545c10b85d6SJean-Jacques Hiblot 	mdelay(10);
546c10b85d6SJean-Jacques Hiblot 	mmc_set_clock(mmc, mmc->clock, false);
547c10b85d6SJean-Jacques Hiblot 
548c10b85d6SJean-Jacques Hiblot 	/*
549c10b85d6SJean-Jacques Hiblot 	 * Failure to switch is indicated by the card holding
550c10b85d6SJean-Jacques Hiblot 	 * dat[0:3] low. Wait for at least 1 ms according to spec
551c10b85d6SJean-Jacques Hiblot 	 */
552c10b85d6SJean-Jacques Hiblot 	err = mmc_wait_dat0(mmc, 1, 1000);
553c10b85d6SJean-Jacques Hiblot 	if (err == -ENOSYS)
554c10b85d6SJean-Jacques Hiblot 		udelay(1000);
555c10b85d6SJean-Jacques Hiblot 	else if (err)
556c10b85d6SJean-Jacques Hiblot 		return -ETIMEDOUT;
557c10b85d6SJean-Jacques Hiblot 
558c10b85d6SJean-Jacques Hiblot 	return 0;
559c10b85d6SJean-Jacques Hiblot }
560f99c2efeSJean-Jacques Hiblot #endif
561c10b85d6SJean-Jacques Hiblot 
562c10b85d6SJean-Jacques Hiblot static int sd_send_op_cond(struct mmc *mmc, bool uhs_en)
563272cc70bSAndy Fleming {
564272cc70bSAndy Fleming 	int timeout = 1000;
565272cc70bSAndy Fleming 	int err;
566272cc70bSAndy Fleming 	struct mmc_cmd cmd;
567272cc70bSAndy Fleming 
5681677eef4SAndrew Gabbasov 	while (1) {
569272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_APP_CMD;
570272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1;
571272cc70bSAndy Fleming 		cmd.cmdarg = 0;
572272cc70bSAndy Fleming 
573272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
574272cc70bSAndy Fleming 
575272cc70bSAndy Fleming 		if (err)
576272cc70bSAndy Fleming 			return err;
577272cc70bSAndy Fleming 
578272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
579272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
580250de12bSStefano Babic 
581250de12bSStefano Babic 		/*
582250de12bSStefano Babic 		 * Most cards do not answer if some reserved bits
583250de12bSStefano Babic 		 * in the ocr are set. However, Some controller
584250de12bSStefano Babic 		 * can set bit 7 (reserved for low voltages), but
585250de12bSStefano Babic 		 * how to manage low voltages SD card is not yet
586250de12bSStefano Babic 		 * specified.
587250de12bSStefano Babic 		 */
588d52ebf10SThomas Chou 		cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
58993bfd616SPantelis Antoniou 			(mmc->cfg->voltages & 0xff8000);
590272cc70bSAndy Fleming 
591272cc70bSAndy Fleming 		if (mmc->version == SD_VERSION_2)
592272cc70bSAndy Fleming 			cmd.cmdarg |= OCR_HCS;
593272cc70bSAndy Fleming 
594c10b85d6SJean-Jacques Hiblot 		if (uhs_en)
595c10b85d6SJean-Jacques Hiblot 			cmd.cmdarg |= OCR_S18R;
596c10b85d6SJean-Jacques Hiblot 
597272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
598272cc70bSAndy Fleming 
599272cc70bSAndy Fleming 		if (err)
600272cc70bSAndy Fleming 			return err;
601272cc70bSAndy Fleming 
6021677eef4SAndrew Gabbasov 		if (cmd.response[0] & OCR_BUSY)
6031677eef4SAndrew Gabbasov 			break;
604272cc70bSAndy Fleming 
6051677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
606915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
607272cc70bSAndy Fleming 
6081677eef4SAndrew Gabbasov 		udelay(1000);
6091677eef4SAndrew Gabbasov 	}
6101677eef4SAndrew Gabbasov 
611272cc70bSAndy Fleming 	if (mmc->version != SD_VERSION_2)
612272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
613272cc70bSAndy Fleming 
614d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
615d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
616d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
617d52ebf10SThomas Chou 		cmd.cmdarg = 0;
618d52ebf10SThomas Chou 
619d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
620d52ebf10SThomas Chou 
621d52ebf10SThomas Chou 		if (err)
622d52ebf10SThomas Chou 			return err;
623d52ebf10SThomas Chou 	}
624d52ebf10SThomas Chou 
625998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
626272cc70bSAndy Fleming 
627f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
628c10b85d6SJean-Jacques Hiblot 	if (uhs_en && !(mmc_host_is_spi(mmc)) && (cmd.response[0] & 0x41000000)
629c10b85d6SJean-Jacques Hiblot 	    == 0x41000000) {
630c10b85d6SJean-Jacques Hiblot 		err = mmc_switch_voltage(mmc, MMC_SIGNAL_VOLTAGE_180);
631c10b85d6SJean-Jacques Hiblot 		if (err)
632c10b85d6SJean-Jacques Hiblot 			return err;
633c10b85d6SJean-Jacques Hiblot 	}
634f99c2efeSJean-Jacques Hiblot #endif
635c10b85d6SJean-Jacques Hiblot 
636272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
637272cc70bSAndy Fleming 	mmc->rca = 0;
638272cc70bSAndy Fleming 
639272cc70bSAndy Fleming 	return 0;
640272cc70bSAndy Fleming }
641272cc70bSAndy Fleming 
6425289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg)
643272cc70bSAndy Fleming {
6445289b535SAndrew Gabbasov 	struct mmc_cmd cmd;
645272cc70bSAndy Fleming 	int err;
646272cc70bSAndy Fleming 
6475289b535SAndrew Gabbasov 	cmd.cmdidx = MMC_CMD_SEND_OP_COND;
6485289b535SAndrew Gabbasov 	cmd.resp_type = MMC_RSP_R3;
6495289b535SAndrew Gabbasov 	cmd.cmdarg = 0;
6505a20397bSRob Herring 	if (use_arg && !mmc_host_is_spi(mmc))
6515a20397bSRob Herring 		cmd.cmdarg = OCR_HCS |
65293bfd616SPantelis Antoniou 			(mmc->cfg->voltages &
653a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_VOLTAGE_MASK)) |
654a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_ACCESS_MODE);
655e9550449SChe-Liang Chiou 
6565289b535SAndrew Gabbasov 	err = mmc_send_cmd(mmc, &cmd, NULL);
657e9550449SChe-Liang Chiou 	if (err)
658e9550449SChe-Liang Chiou 		return err;
6595289b535SAndrew Gabbasov 	mmc->ocr = cmd.response[0];
660e9550449SChe-Liang Chiou 	return 0;
661e9550449SChe-Liang Chiou }
662e9550449SChe-Liang Chiou 
663750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc)
664e9550449SChe-Liang Chiou {
665e9550449SChe-Liang Chiou 	int err, i;
666e9550449SChe-Liang Chiou 
667272cc70bSAndy Fleming 	/* Some cards seem to need this */
668272cc70bSAndy Fleming 	mmc_go_idle(mmc);
669272cc70bSAndy Fleming 
67031cacbabSRaffaele Recalcati  	/* Asking to the card its capabilities */
671e9550449SChe-Liang Chiou 	for (i = 0; i < 2; i++) {
6725289b535SAndrew Gabbasov 		err = mmc_send_op_cond_iter(mmc, i != 0);
67331cacbabSRaffaele Recalcati 		if (err)
67431cacbabSRaffaele Recalcati 			return err;
67531cacbabSRaffaele Recalcati 
676e9550449SChe-Liang Chiou 		/* exit if not busy (flag seems to be inverted) */
677a626c8d4SAndrew Gabbasov 		if (mmc->ocr & OCR_BUSY)
678bd47c135SAndrew Gabbasov 			break;
679e9550449SChe-Liang Chiou 	}
680bd47c135SAndrew Gabbasov 	mmc->op_cond_pending = 1;
681bd47c135SAndrew Gabbasov 	return 0;
682e9550449SChe-Liang Chiou }
68331cacbabSRaffaele Recalcati 
684750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc)
685e9550449SChe-Liang Chiou {
686e9550449SChe-Liang Chiou 	struct mmc_cmd cmd;
687e9550449SChe-Liang Chiou 	int timeout = 1000;
688e9550449SChe-Liang Chiou 	uint start;
689e9550449SChe-Liang Chiou 	int err;
690e9550449SChe-Liang Chiou 
691e9550449SChe-Liang Chiou 	mmc->op_cond_pending = 0;
692cc17c01fSAndrew Gabbasov 	if (!(mmc->ocr & OCR_BUSY)) {
693d188b113SYangbo Lu 		/* Some cards seem to need this */
694d188b113SYangbo Lu 		mmc_go_idle(mmc);
695d188b113SYangbo Lu 
696e9550449SChe-Liang Chiou 		start = get_timer(0);
6971677eef4SAndrew Gabbasov 		while (1) {
6985289b535SAndrew Gabbasov 			err = mmc_send_op_cond_iter(mmc, 1);
699272cc70bSAndy Fleming 			if (err)
700272cc70bSAndy Fleming 				return err;
7011677eef4SAndrew Gabbasov 			if (mmc->ocr & OCR_BUSY)
7021677eef4SAndrew Gabbasov 				break;
703e9550449SChe-Liang Chiou 			if (get_timer(start) > timeout)
704915ffa52SJaehoon Chung 				return -EOPNOTSUPP;
705e9550449SChe-Liang Chiou 			udelay(100);
7061677eef4SAndrew Gabbasov 		}
707cc17c01fSAndrew Gabbasov 	}
708272cc70bSAndy Fleming 
709d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
710d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
711d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
712d52ebf10SThomas Chou 		cmd.cmdarg = 0;
713d52ebf10SThomas Chou 
714d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
715d52ebf10SThomas Chou 
716d52ebf10SThomas Chou 		if (err)
717d52ebf10SThomas Chou 			return err;
718a626c8d4SAndrew Gabbasov 
719a626c8d4SAndrew Gabbasov 		mmc->ocr = cmd.response[0];
720d52ebf10SThomas Chou 	}
721d52ebf10SThomas Chou 
722272cc70bSAndy Fleming 	mmc->version = MMC_VERSION_UNKNOWN;
723272cc70bSAndy Fleming 
724272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
725def816a2SStephen Warren 	mmc->rca = 1;
726272cc70bSAndy Fleming 
727272cc70bSAndy Fleming 	return 0;
728272cc70bSAndy Fleming }
729272cc70bSAndy Fleming 
730272cc70bSAndy Fleming 
731fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
732272cc70bSAndy Fleming {
733272cc70bSAndy Fleming 	struct mmc_cmd cmd;
734272cc70bSAndy Fleming 	struct mmc_data data;
735272cc70bSAndy Fleming 	int err;
736272cc70bSAndy Fleming 
737272cc70bSAndy Fleming 	/* Get the Card Status Register */
738272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
739272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
740272cc70bSAndy Fleming 	cmd.cmdarg = 0;
741272cc70bSAndy Fleming 
742cdfd1ac6SYoshihiro Shimoda 	data.dest = (char *)ext_csd;
743272cc70bSAndy Fleming 	data.blocks = 1;
7448bfa195eSSimon Glass 	data.blocksize = MMC_MAX_BLOCK_LEN;
745272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
746272cc70bSAndy Fleming 
747272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
748272cc70bSAndy Fleming 
749272cc70bSAndy Fleming 	return err;
750272cc70bSAndy Fleming }
751272cc70bSAndy Fleming 
752c40704f4SSimon Glass int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
753272cc70bSAndy Fleming {
754272cc70bSAndy Fleming 	struct mmc_cmd cmd;
7555d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
756a9003dc6SMaxime Ripard 	int retries = 3;
7575d4fc8d9SRaffaele Recalcati 	int ret;
758272cc70bSAndy Fleming 
759272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SWITCH;
760272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1b;
761272cc70bSAndy Fleming 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
762272cc70bSAndy Fleming 				 (index << 16) |
763272cc70bSAndy Fleming 				 (value << 8);
764272cc70bSAndy Fleming 
765a9003dc6SMaxime Ripard 	while (retries > 0) {
7665d4fc8d9SRaffaele Recalcati 		ret = mmc_send_cmd(mmc, &cmd, NULL);
7675d4fc8d9SRaffaele Recalcati 
7685d4fc8d9SRaffaele Recalcati 		/* Waiting for the ready status */
769a9003dc6SMaxime Ripard 		if (!ret) {
77093ad0d18SJan Kloetzke 			ret = mmc_send_status(mmc, timeout);
771a9003dc6SMaxime Ripard 			return ret;
772a9003dc6SMaxime Ripard 		}
773a9003dc6SMaxime Ripard 
774a9003dc6SMaxime Ripard 		retries--;
775a9003dc6SMaxime Ripard 	}
7765d4fc8d9SRaffaele Recalcati 
7775d4fc8d9SRaffaele Recalcati 	return ret;
7785d4fc8d9SRaffaele Recalcati 
779272cc70bSAndy Fleming }
780272cc70bSAndy Fleming 
7813862b854SJean-Jacques Hiblot static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode)
782272cc70bSAndy Fleming {
783272cc70bSAndy Fleming 	int err;
7843862b854SJean-Jacques Hiblot 	int speed_bits;
7853862b854SJean-Jacques Hiblot 
7863862b854SJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
7873862b854SJean-Jacques Hiblot 
7883862b854SJean-Jacques Hiblot 	switch (mode) {
7893862b854SJean-Jacques Hiblot 	case MMC_HS:
7903862b854SJean-Jacques Hiblot 	case MMC_HS_52:
7913862b854SJean-Jacques Hiblot 	case MMC_DDR_52:
7923862b854SJean-Jacques Hiblot 		speed_bits = EXT_CSD_TIMING_HS;
793634d4849SKishon Vijay Abraham I 		break;
794baef2070SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
795634d4849SKishon Vijay Abraham I 	case MMC_HS_200:
796634d4849SKishon Vijay Abraham I 		speed_bits = EXT_CSD_TIMING_HS200;
797634d4849SKishon Vijay Abraham I 		break;
798baef2070SJean-Jacques Hiblot #endif
7993862b854SJean-Jacques Hiblot 	case MMC_LEGACY:
8003862b854SJean-Jacques Hiblot 		speed_bits = EXT_CSD_TIMING_LEGACY;
8013862b854SJean-Jacques Hiblot 		break;
8023862b854SJean-Jacques Hiblot 	default:
8033862b854SJean-Jacques Hiblot 		return -EINVAL;
8043862b854SJean-Jacques Hiblot 	}
8053862b854SJean-Jacques Hiblot 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
8063862b854SJean-Jacques Hiblot 			 speed_bits);
8073862b854SJean-Jacques Hiblot 	if (err)
8083862b854SJean-Jacques Hiblot 		return err;
8093862b854SJean-Jacques Hiblot 
8103862b854SJean-Jacques Hiblot 	if ((mode == MMC_HS) || (mode == MMC_HS_52)) {
8113862b854SJean-Jacques Hiblot 		/* Now check to see that it worked */
8123862b854SJean-Jacques Hiblot 		err = mmc_send_ext_csd(mmc, test_csd);
8133862b854SJean-Jacques Hiblot 		if (err)
8143862b854SJean-Jacques Hiblot 			return err;
8153862b854SJean-Jacques Hiblot 
8163862b854SJean-Jacques Hiblot 		/* No high-speed support */
8173862b854SJean-Jacques Hiblot 		if (!test_csd[EXT_CSD_HS_TIMING])
8183862b854SJean-Jacques Hiblot 			return -ENOTSUPP;
8193862b854SJean-Jacques Hiblot 	}
8203862b854SJean-Jacques Hiblot 
8213862b854SJean-Jacques Hiblot 	return 0;
8223862b854SJean-Jacques Hiblot }
8233862b854SJean-Jacques Hiblot 
8243862b854SJean-Jacques Hiblot static int mmc_get_capabilities(struct mmc *mmc)
8253862b854SJean-Jacques Hiblot {
8263862b854SJean-Jacques Hiblot 	u8 *ext_csd = mmc->ext_csd;
8273862b854SJean-Jacques Hiblot 	char cardtype;
828272cc70bSAndy Fleming 
82900e446faSJean-Jacques Hiblot 	mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(MMC_LEGACY);
830272cc70bSAndy Fleming 
831d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
832d52ebf10SThomas Chou 		return 0;
833d52ebf10SThomas Chou 
834272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
835272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
836272cc70bSAndy Fleming 		return 0;
837272cc70bSAndy Fleming 
8383862b854SJean-Jacques Hiblot 	if (!ext_csd) {
839d8e3d420SJean-Jacques Hiblot 		pr_err("No ext_csd found!\n"); /* this should enver happen */
8403862b854SJean-Jacques Hiblot 		return -ENOTSUPP;
8413862b854SJean-Jacques Hiblot 	}
8423862b854SJean-Jacques Hiblot 
843fc5b32fbSAndrew Gabbasov 	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
844fc5b32fbSAndrew Gabbasov 
845634d4849SKishon Vijay Abraham I 	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0x3f;
846bc1e3272SJean-Jacques Hiblot 	mmc->cardtype = cardtype;
847272cc70bSAndy Fleming 
848baef2070SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
849634d4849SKishon Vijay Abraham I 	if (cardtype & (EXT_CSD_CARD_TYPE_HS200_1_2V |
850634d4849SKishon Vijay Abraham I 			EXT_CSD_CARD_TYPE_HS200_1_8V)) {
851634d4849SKishon Vijay Abraham I 		mmc->card_caps |= MMC_MODE_HS200;
852634d4849SKishon Vijay Abraham I 	}
853baef2070SJean-Jacques Hiblot #endif
854d22e3d46SJaehoon Chung 	if (cardtype & EXT_CSD_CARD_TYPE_52) {
8553862b854SJean-Jacques Hiblot 		if (cardtype & EXT_CSD_CARD_TYPE_DDR_52)
856d22e3d46SJaehoon Chung 			mmc->card_caps |= MMC_MODE_DDR_52MHz;
8573862b854SJean-Jacques Hiblot 		mmc->card_caps |= MMC_MODE_HS_52MHz;
858d22e3d46SJaehoon Chung 	}
8593862b854SJean-Jacques Hiblot 	if (cardtype & EXT_CSD_CARD_TYPE_26)
8603862b854SJean-Jacques Hiblot 		mmc->card_caps |= MMC_MODE_HS;
861272cc70bSAndy Fleming 
862272cc70bSAndy Fleming 	return 0;
863272cc70bSAndy Fleming }
864272cc70bSAndy Fleming 
865f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num)
866f866a46dSStephen Warren {
867f866a46dSStephen Warren 	switch (part_num) {
868f866a46dSStephen Warren 	case 0:
869f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_user;
870f866a46dSStephen Warren 		break;
871f866a46dSStephen Warren 	case 1:
872f866a46dSStephen Warren 	case 2:
873f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_boot;
874f866a46dSStephen Warren 		break;
875f866a46dSStephen Warren 	case 3:
876f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_rpmb;
877f866a46dSStephen Warren 		break;
878f866a46dSStephen Warren 	case 4:
879f866a46dSStephen Warren 	case 5:
880f866a46dSStephen Warren 	case 6:
881f866a46dSStephen Warren 	case 7:
882f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_gp[part_num - 4];
883f866a46dSStephen Warren 		break;
884f866a46dSStephen Warren 	default:
885f866a46dSStephen Warren 		return -1;
886f866a46dSStephen Warren 	}
887f866a46dSStephen Warren 
888c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len);
889f866a46dSStephen Warren 
890f866a46dSStephen Warren 	return 0;
891f866a46dSStephen Warren }
892f866a46dSStephen Warren 
893f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
89401298da3SJean-Jacques Hiblot static int mmc_boot_part_access_chk(struct mmc *mmc, unsigned int part_num)
89501298da3SJean-Jacques Hiblot {
89601298da3SJean-Jacques Hiblot 	int forbidden = 0;
89701298da3SJean-Jacques Hiblot 	bool change = false;
89801298da3SJean-Jacques Hiblot 
89901298da3SJean-Jacques Hiblot 	if (part_num & PART_ACCESS_MASK)
90001298da3SJean-Jacques Hiblot 		forbidden = MMC_CAP(MMC_HS_200);
90101298da3SJean-Jacques Hiblot 
90201298da3SJean-Jacques Hiblot 	if (MMC_CAP(mmc->selected_mode) & forbidden) {
90301298da3SJean-Jacques Hiblot 		debug("selected mode (%s) is forbidden for part %d\n",
90401298da3SJean-Jacques Hiblot 		      mmc_mode_name(mmc->selected_mode), part_num);
90501298da3SJean-Jacques Hiblot 		change = true;
90601298da3SJean-Jacques Hiblot 	} else if (mmc->selected_mode != mmc->best_mode) {
90701298da3SJean-Jacques Hiblot 		debug("selected mode is not optimal\n");
90801298da3SJean-Jacques Hiblot 		change = true;
90901298da3SJean-Jacques Hiblot 	}
91001298da3SJean-Jacques Hiblot 
91101298da3SJean-Jacques Hiblot 	if (change)
91201298da3SJean-Jacques Hiblot 		return mmc_select_mode_and_width(mmc,
91301298da3SJean-Jacques Hiblot 						 mmc->card_caps & ~forbidden);
91401298da3SJean-Jacques Hiblot 
91501298da3SJean-Jacques Hiblot 	return 0;
91601298da3SJean-Jacques Hiblot }
917f99c2efeSJean-Jacques Hiblot #else
918f99c2efeSJean-Jacques Hiblot static inline int mmc_boot_part_access_chk(struct mmc *mmc,
919f99c2efeSJean-Jacques Hiblot 					   unsigned int part_num)
920f99c2efeSJean-Jacques Hiblot {
921f99c2efeSJean-Jacques Hiblot 	return 0;
922f99c2efeSJean-Jacques Hiblot }
923f99c2efeSJean-Jacques Hiblot #endif
92401298da3SJean-Jacques Hiblot 
9257dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num)
926bc897b1dSLei Wen {
927f866a46dSStephen Warren 	int ret;
928bc897b1dSLei Wen 
92901298da3SJean-Jacques Hiblot 	ret = mmc_boot_part_access_chk(mmc, part_num);
93001298da3SJean-Jacques Hiblot 	if (ret)
93101298da3SJean-Jacques Hiblot 		return ret;
93201298da3SJean-Jacques Hiblot 
933f866a46dSStephen Warren 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
934bc897b1dSLei Wen 			 (mmc->part_config & ~PART_ACCESS_MASK)
935bc897b1dSLei Wen 			 | (part_num & PART_ACCESS_MASK));
936f866a46dSStephen Warren 
9376dc93e70SPeter Bigot 	/*
9386dc93e70SPeter Bigot 	 * Set the capacity if the switch succeeded or was intended
9396dc93e70SPeter Bigot 	 * to return to representing the raw device.
9406dc93e70SPeter Bigot 	 */
941873cc1d7SStephen Warren 	if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) {
9426dc93e70SPeter Bigot 		ret = mmc_set_capacity(mmc, part_num);
943fdbb139fSSimon Glass 		mmc_get_blk_desc(mmc)->hwpart = part_num;
944873cc1d7SStephen Warren 	}
9456dc93e70SPeter Bigot 
9466dc93e70SPeter Bigot 	return ret;
947bc897b1dSLei Wen }
948bc897b1dSLei Wen 
949cf17789eSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING)
950ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc,
951ac9da0e0SDiego Santa Cruz 		      const struct mmc_hwpart_conf *conf,
952ac9da0e0SDiego Santa Cruz 		      enum mmc_hwpart_conf_mode mode)
953ac9da0e0SDiego Santa Cruz {
954ac9da0e0SDiego Santa Cruz 	u8 part_attrs = 0;
955ac9da0e0SDiego Santa Cruz 	u32 enh_size_mult;
956ac9da0e0SDiego Santa Cruz 	u32 enh_start_addr;
957ac9da0e0SDiego Santa Cruz 	u32 gp_size_mult[4];
958ac9da0e0SDiego Santa Cruz 	u32 max_enh_size_mult;
959ac9da0e0SDiego Santa Cruz 	u32 tot_enh_size_mult = 0;
9608dda5b0eSDiego Santa Cruz 	u8 wr_rel_set;
961ac9da0e0SDiego Santa Cruz 	int i, pidx, err;
962ac9da0e0SDiego Santa Cruz 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
963ac9da0e0SDiego Santa Cruz 
964ac9da0e0SDiego Santa Cruz 	if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE)
965ac9da0e0SDiego Santa Cruz 		return -EINVAL;
966ac9da0e0SDiego Santa Cruz 
967ac9da0e0SDiego Santa Cruz 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) {
968d8e3d420SJean-Jacques Hiblot 		pr_err("eMMC >= 4.4 required for enhanced user data area\n");
969ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
970ac9da0e0SDiego Santa Cruz 	}
971ac9da0e0SDiego Santa Cruz 
972ac9da0e0SDiego Santa Cruz 	if (!(mmc->part_support & PART_SUPPORT)) {
973d8e3d420SJean-Jacques Hiblot 		pr_err("Card does not support partitioning\n");
974ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
975ac9da0e0SDiego Santa Cruz 	}
976ac9da0e0SDiego Santa Cruz 
977ac9da0e0SDiego Santa Cruz 	if (!mmc->hc_wp_grp_size) {
978d8e3d420SJean-Jacques Hiblot 		pr_err("Card does not define HC WP group size\n");
979ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
980ac9da0e0SDiego Santa Cruz 	}
981ac9da0e0SDiego Santa Cruz 
982ac9da0e0SDiego Santa Cruz 	/* check partition alignment and total enhanced size */
983ac9da0e0SDiego Santa Cruz 	if (conf->user.enh_size) {
984ac9da0e0SDiego Santa Cruz 		if (conf->user.enh_size % mmc->hc_wp_grp_size ||
985ac9da0e0SDiego Santa Cruz 		    conf->user.enh_start % mmc->hc_wp_grp_size) {
986d8e3d420SJean-Jacques Hiblot 			pr_err("User data enhanced area not HC WP group "
987ac9da0e0SDiego Santa Cruz 			       "size aligned\n");
988ac9da0e0SDiego Santa Cruz 			return -EINVAL;
989ac9da0e0SDiego Santa Cruz 		}
990ac9da0e0SDiego Santa Cruz 		part_attrs |= EXT_CSD_ENH_USR;
991ac9da0e0SDiego Santa Cruz 		enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size;
992ac9da0e0SDiego Santa Cruz 		if (mmc->high_capacity) {
993ac9da0e0SDiego Santa Cruz 			enh_start_addr = conf->user.enh_start;
994ac9da0e0SDiego Santa Cruz 		} else {
995ac9da0e0SDiego Santa Cruz 			enh_start_addr = (conf->user.enh_start << 9);
996ac9da0e0SDiego Santa Cruz 		}
997ac9da0e0SDiego Santa Cruz 	} else {
998ac9da0e0SDiego Santa Cruz 		enh_size_mult = 0;
999ac9da0e0SDiego Santa Cruz 		enh_start_addr = 0;
1000ac9da0e0SDiego Santa Cruz 	}
1001ac9da0e0SDiego Santa Cruz 	tot_enh_size_mult += enh_size_mult;
1002ac9da0e0SDiego Santa Cruz 
1003ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
1004ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) {
1005d8e3d420SJean-Jacques Hiblot 			pr_err("GP%i partition not HC WP group size "
1006ac9da0e0SDiego Santa Cruz 			       "aligned\n", pidx+1);
1007ac9da0e0SDiego Santa Cruz 			return -EINVAL;
1008ac9da0e0SDiego Santa Cruz 		}
1009ac9da0e0SDiego Santa Cruz 		gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size;
1010ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) {
1011ac9da0e0SDiego Santa Cruz 			part_attrs |= EXT_CSD_ENH_GP(pidx);
1012ac9da0e0SDiego Santa Cruz 			tot_enh_size_mult += gp_size_mult[pidx];
1013ac9da0e0SDiego Santa Cruz 		}
1014ac9da0e0SDiego Santa Cruz 	}
1015ac9da0e0SDiego Santa Cruz 
1016ac9da0e0SDiego Santa Cruz 	if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) {
1017d8e3d420SJean-Jacques Hiblot 		pr_err("Card does not support enhanced attribute\n");
1018ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1019ac9da0e0SDiego Santa Cruz 	}
1020ac9da0e0SDiego Santa Cruz 
1021ac9da0e0SDiego Santa Cruz 	err = mmc_send_ext_csd(mmc, ext_csd);
1022ac9da0e0SDiego Santa Cruz 	if (err)
1023ac9da0e0SDiego Santa Cruz 		return err;
1024ac9da0e0SDiego Santa Cruz 
1025ac9da0e0SDiego Santa Cruz 	max_enh_size_mult =
1026ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) +
1027ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) +
1028ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT];
1029ac9da0e0SDiego Santa Cruz 	if (tot_enh_size_mult > max_enh_size_mult) {
1030d8e3d420SJean-Jacques Hiblot 		pr_err("Total enhanced size exceeds maximum (%u > %u)\n",
1031ac9da0e0SDiego Santa Cruz 		       tot_enh_size_mult, max_enh_size_mult);
1032ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1033ac9da0e0SDiego Santa Cruz 	}
1034ac9da0e0SDiego Santa Cruz 
10358dda5b0eSDiego Santa Cruz 	/* The default value of EXT_CSD_WR_REL_SET is device
10368dda5b0eSDiego Santa Cruz 	 * dependent, the values can only be changed if the
10378dda5b0eSDiego Santa Cruz 	 * EXT_CSD_HS_CTRL_REL bit is set. The values can be
10388dda5b0eSDiego Santa Cruz 	 * changed only once and before partitioning is completed. */
10398dda5b0eSDiego Santa Cruz 	wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
10408dda5b0eSDiego Santa Cruz 	if (conf->user.wr_rel_change) {
10418dda5b0eSDiego Santa Cruz 		if (conf->user.wr_rel_set)
10428dda5b0eSDiego Santa Cruz 			wr_rel_set |= EXT_CSD_WR_DATA_REL_USR;
10438dda5b0eSDiego Santa Cruz 		else
10448dda5b0eSDiego Santa Cruz 			wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR;
10458dda5b0eSDiego Santa Cruz 	}
10468dda5b0eSDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
10478dda5b0eSDiego Santa Cruz 		if (conf->gp_part[pidx].wr_rel_change) {
10488dda5b0eSDiego Santa Cruz 			if (conf->gp_part[pidx].wr_rel_set)
10498dda5b0eSDiego Santa Cruz 				wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx);
10508dda5b0eSDiego Santa Cruz 			else
10518dda5b0eSDiego Santa Cruz 				wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx);
10528dda5b0eSDiego Santa Cruz 		}
10538dda5b0eSDiego Santa Cruz 	}
10548dda5b0eSDiego Santa Cruz 
10558dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] &&
10568dda5b0eSDiego Santa Cruz 	    !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) {
10578dda5b0eSDiego Santa Cruz 		puts("Card does not support host controlled partition write "
10588dda5b0eSDiego Santa Cruz 		     "reliability settings\n");
10598dda5b0eSDiego Santa Cruz 		return -EMEDIUMTYPE;
10608dda5b0eSDiego Santa Cruz 	}
10618dda5b0eSDiego Santa Cruz 
1062ac9da0e0SDiego Santa Cruz 	if (ext_csd[EXT_CSD_PARTITION_SETTING] &
1063ac9da0e0SDiego Santa Cruz 	    EXT_CSD_PARTITION_SETTING_COMPLETED) {
1064d8e3d420SJean-Jacques Hiblot 		pr_err("Card already partitioned\n");
1065ac9da0e0SDiego Santa Cruz 		return -EPERM;
1066ac9da0e0SDiego Santa Cruz 	}
1067ac9da0e0SDiego Santa Cruz 
1068ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_CHECK)
1069ac9da0e0SDiego Santa Cruz 		return 0;
1070ac9da0e0SDiego Santa Cruz 
1071ac9da0e0SDiego Santa Cruz 	/* Partitioning requires high-capacity size definitions */
1072ac9da0e0SDiego Santa Cruz 	if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) {
1073ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1074ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ERASE_GROUP_DEF, 1);
1075ac9da0e0SDiego Santa Cruz 
1076ac9da0e0SDiego Santa Cruz 		if (err)
1077ac9da0e0SDiego Santa Cruz 			return err;
1078ac9da0e0SDiego Santa Cruz 
1079ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1080ac9da0e0SDiego Santa Cruz 
1081ac9da0e0SDiego Santa Cruz 		/* update erase group size to be high-capacity */
1082ac9da0e0SDiego Santa Cruz 		mmc->erase_grp_size =
1083ac9da0e0SDiego Santa Cruz 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1084ac9da0e0SDiego Santa Cruz 
1085ac9da0e0SDiego Santa Cruz 	}
1086ac9da0e0SDiego Santa Cruz 
1087ac9da0e0SDiego Santa Cruz 	/* all OK, write the configuration */
1088ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 4; i++) {
1089ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1090ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_START_ADDR+i,
1091ac9da0e0SDiego Santa Cruz 				 (enh_start_addr >> (i*8)) & 0xFF);
1092ac9da0e0SDiego Santa Cruz 		if (err)
1093ac9da0e0SDiego Santa Cruz 			return err;
1094ac9da0e0SDiego Santa Cruz 	}
1095ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 3; i++) {
1096ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1097ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_SIZE_MULT+i,
1098ac9da0e0SDiego Santa Cruz 				 (enh_size_mult >> (i*8)) & 0xFF);
1099ac9da0e0SDiego Santa Cruz 		if (err)
1100ac9da0e0SDiego Santa Cruz 			return err;
1101ac9da0e0SDiego Santa Cruz 	}
1102ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
1103ac9da0e0SDiego Santa Cruz 		for (i = 0; i < 3; i++) {
1104ac9da0e0SDiego Santa Cruz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1105ac9da0e0SDiego Santa Cruz 					 EXT_CSD_GP_SIZE_MULT+pidx*3+i,
1106ac9da0e0SDiego Santa Cruz 					 (gp_size_mult[pidx] >> (i*8)) & 0xFF);
1107ac9da0e0SDiego Santa Cruz 			if (err)
1108ac9da0e0SDiego Santa Cruz 				return err;
1109ac9da0e0SDiego Santa Cruz 		}
1110ac9da0e0SDiego Santa Cruz 	}
1111ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1112ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs);
1113ac9da0e0SDiego Santa Cruz 	if (err)
1114ac9da0e0SDiego Santa Cruz 		return err;
1115ac9da0e0SDiego Santa Cruz 
1116ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_SET)
1117ac9da0e0SDiego Santa Cruz 		return 0;
1118ac9da0e0SDiego Santa Cruz 
11198dda5b0eSDiego Santa Cruz 	/* The WR_REL_SET is a write-once register but shall be
11208dda5b0eSDiego Santa Cruz 	 * written before setting PART_SETTING_COMPLETED. As it is
11218dda5b0eSDiego Santa Cruz 	 * write-once we can only write it when completing the
11228dda5b0eSDiego Santa Cruz 	 * partitioning. */
11238dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) {
11248dda5b0eSDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
11258dda5b0eSDiego Santa Cruz 				 EXT_CSD_WR_REL_SET, wr_rel_set);
11268dda5b0eSDiego Santa Cruz 		if (err)
11278dda5b0eSDiego Santa Cruz 			return err;
11288dda5b0eSDiego Santa Cruz 	}
11298dda5b0eSDiego Santa Cruz 
1130ac9da0e0SDiego Santa Cruz 	/* Setting PART_SETTING_COMPLETED confirms the partition
1131ac9da0e0SDiego Santa Cruz 	 * configuration but it only becomes effective after power
1132ac9da0e0SDiego Santa Cruz 	 * cycle, so we do not adjust the partition related settings
1133ac9da0e0SDiego Santa Cruz 	 * in the mmc struct. */
1134ac9da0e0SDiego Santa Cruz 
1135ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1136ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING,
1137ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING_COMPLETED);
1138ac9da0e0SDiego Santa Cruz 	if (err)
1139ac9da0e0SDiego Santa Cruz 		return err;
1140ac9da0e0SDiego Santa Cruz 
1141ac9da0e0SDiego Santa Cruz 	return 0;
1142ac9da0e0SDiego Santa Cruz }
1143cf17789eSJean-Jacques Hiblot #endif
1144ac9da0e0SDiego Santa Cruz 
1145e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
114648972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
114748972d90SThierry Reding {
114848972d90SThierry Reding 	int cd;
114948972d90SThierry Reding 
115048972d90SThierry Reding 	cd = board_mmc_getcd(mmc);
115148972d90SThierry Reding 
1152d4e1da4eSPeter Korsgaard 	if (cd < 0) {
115393bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getcd)
115493bfd616SPantelis Antoniou 			cd = mmc->cfg->ops->getcd(mmc);
1155d4e1da4eSPeter Korsgaard 		else
1156d4e1da4eSPeter Korsgaard 			cd = 1;
1157d4e1da4eSPeter Korsgaard 	}
115848972d90SThierry Reding 
115948972d90SThierry Reding 	return cd;
116048972d90SThierry Reding }
11618ca51e51SSimon Glass #endif
116248972d90SThierry Reding 
1163fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
1164272cc70bSAndy Fleming {
1165272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1166272cc70bSAndy Fleming 	struct mmc_data data;
1167272cc70bSAndy Fleming 
1168272cc70bSAndy Fleming 	/* Switch the frequency */
1169272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
1170272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1171272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
1172272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
1173272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
1174272cc70bSAndy Fleming 
1175272cc70bSAndy Fleming 	data.dest = (char *)resp;
1176272cc70bSAndy Fleming 	data.blocksize = 64;
1177272cc70bSAndy Fleming 	data.blocks = 1;
1178272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
1179272cc70bSAndy Fleming 
1180272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
1181272cc70bSAndy Fleming }
1182272cc70bSAndy Fleming 
1183272cc70bSAndy Fleming 
1184d0c221feSJean-Jacques Hiblot static int sd_get_capabilities(struct mmc *mmc)
1185272cc70bSAndy Fleming {
1186272cc70bSAndy Fleming 	int err;
1187272cc70bSAndy Fleming 	struct mmc_cmd cmd;
118818e7c8f6SSuniel Mahesh 	ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2);
118918e7c8f6SSuniel Mahesh 	ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16);
1190272cc70bSAndy Fleming 	struct mmc_data data;
1191272cc70bSAndy Fleming 	int timeout;
1192f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1193c10b85d6SJean-Jacques Hiblot 	u32 sd3_bus_mode;
1194f99c2efeSJean-Jacques Hiblot #endif
1195272cc70bSAndy Fleming 
119600e446faSJean-Jacques Hiblot 	mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(SD_LEGACY);
1197272cc70bSAndy Fleming 
1198d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
1199d52ebf10SThomas Chou 		return 0;
1200d52ebf10SThomas Chou 
1201272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
1202272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
1203272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1204272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1205272cc70bSAndy Fleming 
1206272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1207272cc70bSAndy Fleming 
1208272cc70bSAndy Fleming 	if (err)
1209272cc70bSAndy Fleming 		return err;
1210272cc70bSAndy Fleming 
1211272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
1212272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1213272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1214272cc70bSAndy Fleming 
1215272cc70bSAndy Fleming 	timeout = 3;
1216272cc70bSAndy Fleming 
1217272cc70bSAndy Fleming retry_scr:
1218f781dd38SAnton staaf 	data.dest = (char *)scr;
1219272cc70bSAndy Fleming 	data.blocksize = 8;
1220272cc70bSAndy Fleming 	data.blocks = 1;
1221272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
1222272cc70bSAndy Fleming 
1223272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
1224272cc70bSAndy Fleming 
1225272cc70bSAndy Fleming 	if (err) {
1226272cc70bSAndy Fleming 		if (timeout--)
1227272cc70bSAndy Fleming 			goto retry_scr;
1228272cc70bSAndy Fleming 
1229272cc70bSAndy Fleming 		return err;
1230272cc70bSAndy Fleming 	}
1231272cc70bSAndy Fleming 
12324e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
12334e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
1234272cc70bSAndy Fleming 
1235272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
1236272cc70bSAndy Fleming 	case 0:
1237272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1238272cc70bSAndy Fleming 		break;
1239272cc70bSAndy Fleming 	case 1:
1240272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_10;
1241272cc70bSAndy Fleming 		break;
1242272cc70bSAndy Fleming 	case 2:
1243272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
12441741c64dSJaehoon Chung 		if ((mmc->scr[0] >> 15) & 0x1)
12451741c64dSJaehoon Chung 			mmc->version = SD_VERSION_3;
1246272cc70bSAndy Fleming 		break;
1247272cc70bSAndy Fleming 	default:
1248272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1249272cc70bSAndy Fleming 		break;
1250272cc70bSAndy Fleming 	}
1251272cc70bSAndy Fleming 
1252b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
1253b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
1254b44c7083SAlagu Sankar 
1255272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
1256272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
1257272cc70bSAndy Fleming 		return 0;
1258272cc70bSAndy Fleming 
1259272cc70bSAndy Fleming 	timeout = 4;
1260272cc70bSAndy Fleming 	while (timeout--) {
1261272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
1262f781dd38SAnton staaf 				(u8 *)switch_status);
1263272cc70bSAndy Fleming 
1264272cc70bSAndy Fleming 		if (err)
1265272cc70bSAndy Fleming 			return err;
1266272cc70bSAndy Fleming 
1267272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
12684e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
1269272cc70bSAndy Fleming 			break;
1270272cc70bSAndy Fleming 	}
1271272cc70bSAndy Fleming 
1272272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
1273d0c221feSJean-Jacques Hiblot 	if (__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)
1274d0c221feSJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(SD_HS);
1275272cc70bSAndy Fleming 
1276f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1277c10b85d6SJean-Jacques Hiblot 	/* Version before 3.0 don't support UHS modes */
1278c10b85d6SJean-Jacques Hiblot 	if (mmc->version < SD_VERSION_3)
1279c10b85d6SJean-Jacques Hiblot 		return 0;
1280c10b85d6SJean-Jacques Hiblot 
1281c10b85d6SJean-Jacques Hiblot 	sd3_bus_mode = __be32_to_cpu(switch_status[3]) >> 16 & 0x1f;
1282c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR104)
1283c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR104);
1284c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR50)
1285c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR50);
1286c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR25)
1287c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR25);
1288c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR12)
1289c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR12);
1290c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_DDR50)
1291c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_DDR50);
1292f99c2efeSJean-Jacques Hiblot #endif
1293c10b85d6SJean-Jacques Hiblot 
12942c3fbf4cSMacpaul Lin 	return 0;
1295d0c221feSJean-Jacques Hiblot }
1296d0c221feSJean-Jacques Hiblot 
1297d0c221feSJean-Jacques Hiblot static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode)
1298d0c221feSJean-Jacques Hiblot {
1299d0c221feSJean-Jacques Hiblot 	int err;
1300d0c221feSJean-Jacques Hiblot 
1301d0c221feSJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
1302c10b85d6SJean-Jacques Hiblot 	int speed;
13032c3fbf4cSMacpaul Lin 
1304c10b85d6SJean-Jacques Hiblot 	switch (mode) {
1305c10b85d6SJean-Jacques Hiblot 	case SD_LEGACY:
1306c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR12_BUS_SPEED;
1307c10b85d6SJean-Jacques Hiblot 		break;
1308c10b85d6SJean-Jacques Hiblot 	case SD_HS:
1309baef2070SJean-Jacques Hiblot 		speed = HIGH_SPEED_BUS_SPEED;
1310baef2070SJean-Jacques Hiblot 		break;
1311baef2070SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1312baef2070SJean-Jacques Hiblot 	case UHS_SDR12:
1313baef2070SJean-Jacques Hiblot 		speed = UHS_SDR12_BUS_SPEED;
1314baef2070SJean-Jacques Hiblot 		break;
1315c10b85d6SJean-Jacques Hiblot 	case UHS_SDR25:
1316c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR25_BUS_SPEED;
1317c10b85d6SJean-Jacques Hiblot 		break;
1318c10b85d6SJean-Jacques Hiblot 	case UHS_SDR50:
1319c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR50_BUS_SPEED;
1320c10b85d6SJean-Jacques Hiblot 		break;
1321c10b85d6SJean-Jacques Hiblot 	case UHS_DDR50:
1322c10b85d6SJean-Jacques Hiblot 		speed = UHS_DDR50_BUS_SPEED;
1323c10b85d6SJean-Jacques Hiblot 		break;
1324c10b85d6SJean-Jacques Hiblot 	case UHS_SDR104:
1325c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR104_BUS_SPEED;
1326c10b85d6SJean-Jacques Hiblot 		break;
1327baef2070SJean-Jacques Hiblot #endif
1328c10b85d6SJean-Jacques Hiblot 	default:
1329c10b85d6SJean-Jacques Hiblot 		return -EINVAL;
1330c10b85d6SJean-Jacques Hiblot 	}
1331c10b85d6SJean-Jacques Hiblot 
1332c10b85d6SJean-Jacques Hiblot 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, speed, (u8 *)switch_status);
1333272cc70bSAndy Fleming 	if (err)
1334272cc70bSAndy Fleming 		return err;
1335272cc70bSAndy Fleming 
1336c10b85d6SJean-Jacques Hiblot 	if ((__be32_to_cpu(switch_status[4]) >> 24) != speed)
1337d0c221feSJean-Jacques Hiblot 		return -ENOTSUPP;
1338d0c221feSJean-Jacques Hiblot 
1339d0c221feSJean-Jacques Hiblot 	return 0;
1340d0c221feSJean-Jacques Hiblot }
1341d0c221feSJean-Jacques Hiblot 
1342d0c221feSJean-Jacques Hiblot int sd_select_bus_width(struct mmc *mmc, int w)
1343d0c221feSJean-Jacques Hiblot {
1344d0c221feSJean-Jacques Hiblot 	int err;
1345d0c221feSJean-Jacques Hiblot 	struct mmc_cmd cmd;
1346d0c221feSJean-Jacques Hiblot 
1347d0c221feSJean-Jacques Hiblot 	if ((w != 4) && (w != 1))
1348d0c221feSJean-Jacques Hiblot 		return -EINVAL;
1349d0c221feSJean-Jacques Hiblot 
1350d0c221feSJean-Jacques Hiblot 	cmd.cmdidx = MMC_CMD_APP_CMD;
1351d0c221feSJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
1352d0c221feSJean-Jacques Hiblot 	cmd.cmdarg = mmc->rca << 16;
1353d0c221feSJean-Jacques Hiblot 
1354d0c221feSJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
1355d0c221feSJean-Jacques Hiblot 	if (err)
1356d0c221feSJean-Jacques Hiblot 		return err;
1357d0c221feSJean-Jacques Hiblot 
1358d0c221feSJean-Jacques Hiblot 	cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
1359d0c221feSJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
1360d0c221feSJean-Jacques Hiblot 	if (w == 4)
1361d0c221feSJean-Jacques Hiblot 		cmd.cmdarg = 2;
1362d0c221feSJean-Jacques Hiblot 	else if (w == 1)
1363d0c221feSJean-Jacques Hiblot 		cmd.cmdarg = 0;
1364d0c221feSJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
1365d0c221feSJean-Jacques Hiblot 	if (err)
1366d0c221feSJean-Jacques Hiblot 		return err;
1367272cc70bSAndy Fleming 
1368272cc70bSAndy Fleming 	return 0;
1369272cc70bSAndy Fleming }
1370272cc70bSAndy Fleming 
1371*5b2e72f3SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE)
13723697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc)
13733697e599SPeng Fan {
1374*5b2e72f3SJean-Jacques Hiblot 	static const unsigned int sd_au_size[] = {
1375*5b2e72f3SJean-Jacques Hiblot 		0,		SZ_16K / 512,		SZ_32K / 512,
1376*5b2e72f3SJean-Jacques Hiblot 		SZ_64K / 512,	SZ_128K / 512,		SZ_256K / 512,
1377*5b2e72f3SJean-Jacques Hiblot 		SZ_512K / 512,	SZ_1M / 512,		SZ_2M / 512,
1378*5b2e72f3SJean-Jacques Hiblot 		SZ_4M / 512,	SZ_8M / 512,		(SZ_8M + SZ_4M) / 512,
1379*5b2e72f3SJean-Jacques Hiblot 		SZ_16M / 512,	(SZ_16M + SZ_8M) / 512,	SZ_32M / 512,
1380*5b2e72f3SJean-Jacques Hiblot 		SZ_64M / 512,
1381*5b2e72f3SJean-Jacques Hiblot 	};
13823697e599SPeng Fan 	int err, i;
13833697e599SPeng Fan 	struct mmc_cmd cmd;
13843697e599SPeng Fan 	ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16);
13853697e599SPeng Fan 	struct mmc_data data;
13863697e599SPeng Fan 	int timeout = 3;
13873697e599SPeng Fan 	unsigned int au, eo, et, es;
13883697e599SPeng Fan 
13893697e599SPeng Fan 	cmd.cmdidx = MMC_CMD_APP_CMD;
13903697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
13913697e599SPeng Fan 	cmd.cmdarg = mmc->rca << 16;
13923697e599SPeng Fan 
13933697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, NULL);
13943697e599SPeng Fan 	if (err)
13953697e599SPeng Fan 		return err;
13963697e599SPeng Fan 
13973697e599SPeng Fan 	cmd.cmdidx = SD_CMD_APP_SD_STATUS;
13983697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
13993697e599SPeng Fan 	cmd.cmdarg = 0;
14003697e599SPeng Fan 
14013697e599SPeng Fan retry_ssr:
14023697e599SPeng Fan 	data.dest = (char *)ssr;
14033697e599SPeng Fan 	data.blocksize = 64;
14043697e599SPeng Fan 	data.blocks = 1;
14053697e599SPeng Fan 	data.flags = MMC_DATA_READ;
14063697e599SPeng Fan 
14073697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, &data);
14083697e599SPeng Fan 	if (err) {
14093697e599SPeng Fan 		if (timeout--)
14103697e599SPeng Fan 			goto retry_ssr;
14113697e599SPeng Fan 
14123697e599SPeng Fan 		return err;
14133697e599SPeng Fan 	}
14143697e599SPeng Fan 
14153697e599SPeng Fan 	for (i = 0; i < 16; i++)
14163697e599SPeng Fan 		ssr[i] = be32_to_cpu(ssr[i]);
14173697e599SPeng Fan 
14183697e599SPeng Fan 	au = (ssr[2] >> 12) & 0xF;
14193697e599SPeng Fan 	if ((au <= 9) || (mmc->version == SD_VERSION_3)) {
14203697e599SPeng Fan 		mmc->ssr.au = sd_au_size[au];
14213697e599SPeng Fan 		es = (ssr[3] >> 24) & 0xFF;
14223697e599SPeng Fan 		es |= (ssr[2] & 0xFF) << 8;
14233697e599SPeng Fan 		et = (ssr[3] >> 18) & 0x3F;
14243697e599SPeng Fan 		if (es && et) {
14253697e599SPeng Fan 			eo = (ssr[3] >> 16) & 0x3;
14263697e599SPeng Fan 			mmc->ssr.erase_timeout = (et * 1000) / es;
14273697e599SPeng Fan 			mmc->ssr.erase_offset = eo * 1000;
14283697e599SPeng Fan 		}
14293697e599SPeng Fan 	} else {
14303697e599SPeng Fan 		debug("Invalid Allocation Unit Size.\n");
14313697e599SPeng Fan 	}
14323697e599SPeng Fan 
14333697e599SPeng Fan 	return 0;
14343697e599SPeng Fan }
1435*5b2e72f3SJean-Jacques Hiblot #endif
1436272cc70bSAndy Fleming /* frequency bases */
1437272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
14385f837c2cSMike Frysinger static const int fbase[] = {
1439272cc70bSAndy Fleming 	10000,
1440272cc70bSAndy Fleming 	100000,
1441272cc70bSAndy Fleming 	1000000,
1442272cc70bSAndy Fleming 	10000000,
1443272cc70bSAndy Fleming };
1444272cc70bSAndy Fleming 
1445272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
1446272cc70bSAndy Fleming  * to platforms without floating point.
1447272cc70bSAndy Fleming  */
144861fe076fSSimon Glass static const u8 multipliers[] = {
1449272cc70bSAndy Fleming 	0,	/* reserved */
1450272cc70bSAndy Fleming 	10,
1451272cc70bSAndy Fleming 	12,
1452272cc70bSAndy Fleming 	13,
1453272cc70bSAndy Fleming 	15,
1454272cc70bSAndy Fleming 	20,
1455272cc70bSAndy Fleming 	25,
1456272cc70bSAndy Fleming 	30,
1457272cc70bSAndy Fleming 	35,
1458272cc70bSAndy Fleming 	40,
1459272cc70bSAndy Fleming 	45,
1460272cc70bSAndy Fleming 	50,
1461272cc70bSAndy Fleming 	55,
1462272cc70bSAndy Fleming 	60,
1463272cc70bSAndy Fleming 	70,
1464272cc70bSAndy Fleming 	80,
1465272cc70bSAndy Fleming };
1466272cc70bSAndy Fleming 
1467d0c221feSJean-Jacques Hiblot static inline int bus_width(uint cap)
1468d0c221feSJean-Jacques Hiblot {
1469d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_8BIT)
1470d0c221feSJean-Jacques Hiblot 		return 8;
1471d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_4BIT)
1472d0c221feSJean-Jacques Hiblot 		return 4;
1473d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_1BIT)
1474d0c221feSJean-Jacques Hiblot 		return 1;
1475d8e3d420SJean-Jacques Hiblot 	pr_warn("invalid bus witdh capability 0x%x\n", cap);
1476d0c221feSJean-Jacques Hiblot 	return 0;
1477d0c221feSJean-Jacques Hiblot }
1478d0c221feSJean-Jacques Hiblot 
1479e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
1480f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
1481ec841209SKishon Vijay Abraham I static int mmc_execute_tuning(struct mmc *mmc, uint opcode)
1482ec841209SKishon Vijay Abraham I {
1483ec841209SKishon Vijay Abraham I 	return -ENOTSUPP;
1484ec841209SKishon Vijay Abraham I }
1485f99c2efeSJean-Jacques Hiblot #endif
1486ec841209SKishon Vijay Abraham I 
1487318a7a57SJean-Jacques Hiblot static void mmc_send_init_stream(struct mmc *mmc)
1488318a7a57SJean-Jacques Hiblot {
1489318a7a57SJean-Jacques Hiblot }
1490318a7a57SJean-Jacques Hiblot 
14912a4d212fSKishon Vijay Abraham I static int mmc_set_ios(struct mmc *mmc)
1492272cc70bSAndy Fleming {
14932a4d212fSKishon Vijay Abraham I 	int ret = 0;
14942a4d212fSKishon Vijay Abraham I 
149593bfd616SPantelis Antoniou 	if (mmc->cfg->ops->set_ios)
14962a4d212fSKishon Vijay Abraham I 		ret = mmc->cfg->ops->set_ios(mmc);
14972a4d212fSKishon Vijay Abraham I 
14982a4d212fSKishon Vijay Abraham I 	return ret;
1499272cc70bSAndy Fleming }
15008ca51e51SSimon Glass #endif
1501272cc70bSAndy Fleming 
150235f67820SKishon Vijay Abraham I int mmc_set_clock(struct mmc *mmc, uint clock, bool disable)
1503272cc70bSAndy Fleming {
150493bfd616SPantelis Antoniou 	if (clock > mmc->cfg->f_max)
150593bfd616SPantelis Antoniou 		clock = mmc->cfg->f_max;
1506272cc70bSAndy Fleming 
150793bfd616SPantelis Antoniou 	if (clock < mmc->cfg->f_min)
150893bfd616SPantelis Antoniou 		clock = mmc->cfg->f_min;
1509272cc70bSAndy Fleming 
1510272cc70bSAndy Fleming 	mmc->clock = clock;
151135f67820SKishon Vijay Abraham I 	mmc->clk_disable = disable;
1512272cc70bSAndy Fleming 
15132a4d212fSKishon Vijay Abraham I 	return mmc_set_ios(mmc);
1514272cc70bSAndy Fleming }
1515272cc70bSAndy Fleming 
15162a4d212fSKishon Vijay Abraham I static int mmc_set_bus_width(struct mmc *mmc, uint width)
1517272cc70bSAndy Fleming {
1518272cc70bSAndy Fleming 	mmc->bus_width = width;
1519272cc70bSAndy Fleming 
15202a4d212fSKishon Vijay Abraham I 	return mmc_set_ios(mmc);
1521272cc70bSAndy Fleming }
1522272cc70bSAndy Fleming 
15234c9d2aaaSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG)
15244c9d2aaaSJean-Jacques Hiblot /*
15254c9d2aaaSJean-Jacques Hiblot  * helper function to display the capabilities in a human
15264c9d2aaaSJean-Jacques Hiblot  * friendly manner. The capabilities include bus width and
15274c9d2aaaSJean-Jacques Hiblot  * supported modes.
15284c9d2aaaSJean-Jacques Hiblot  */
15294c9d2aaaSJean-Jacques Hiblot void mmc_dump_capabilities(const char *text, uint caps)
15304c9d2aaaSJean-Jacques Hiblot {
15314c9d2aaaSJean-Jacques Hiblot 	enum bus_mode mode;
15324c9d2aaaSJean-Jacques Hiblot 
15334c9d2aaaSJean-Jacques Hiblot 	printf("%s: widths [", text);
15344c9d2aaaSJean-Jacques Hiblot 	if (caps & MMC_MODE_8BIT)
15354c9d2aaaSJean-Jacques Hiblot 		printf("8, ");
15364c9d2aaaSJean-Jacques Hiblot 	if (caps & MMC_MODE_4BIT)
15374c9d2aaaSJean-Jacques Hiblot 		printf("4, ");
1538d0c221feSJean-Jacques Hiblot 	if (caps & MMC_MODE_1BIT)
1539d0c221feSJean-Jacques Hiblot 		printf("1, ");
1540d0c221feSJean-Jacques Hiblot 	printf("\b\b] modes [");
15414c9d2aaaSJean-Jacques Hiblot 	for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++)
15424c9d2aaaSJean-Jacques Hiblot 		if (MMC_CAP(mode) & caps)
15434c9d2aaaSJean-Jacques Hiblot 			printf("%s, ", mmc_mode_name(mode));
15444c9d2aaaSJean-Jacques Hiblot 	printf("\b\b]\n");
15454c9d2aaaSJean-Jacques Hiblot }
15464c9d2aaaSJean-Jacques Hiblot #endif
15474c9d2aaaSJean-Jacques Hiblot 
1548d0c221feSJean-Jacques Hiblot struct mode_width_tuning {
1549d0c221feSJean-Jacques Hiblot 	enum bus_mode mode;
1550d0c221feSJean-Jacques Hiblot 	uint widths;
1551f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
1552634d4849SKishon Vijay Abraham I 	uint tuning;
1553f99c2efeSJean-Jacques Hiblot #endif
1554d0c221feSJean-Jacques Hiblot };
1555d0c221feSJean-Jacques Hiblot 
1556f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE)
1557bc1e3272SJean-Jacques Hiblot int mmc_voltage_to_mv(enum mmc_voltage voltage)
1558bc1e3272SJean-Jacques Hiblot {
1559bc1e3272SJean-Jacques Hiblot 	switch (voltage) {
1560bc1e3272SJean-Jacques Hiblot 	case MMC_SIGNAL_VOLTAGE_000: return 0;
1561bc1e3272SJean-Jacques Hiblot 	case MMC_SIGNAL_VOLTAGE_330: return 3300;
1562bc1e3272SJean-Jacques Hiblot 	case MMC_SIGNAL_VOLTAGE_180: return 1800;
1563bc1e3272SJean-Jacques Hiblot 	case MMC_SIGNAL_VOLTAGE_120: return 1200;
1564bc1e3272SJean-Jacques Hiblot 	}
1565bc1e3272SJean-Jacques Hiblot 	return -EINVAL;
1566bc1e3272SJean-Jacques Hiblot }
1567bc1e3272SJean-Jacques Hiblot 
1568aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage)
1569aff5d3c8SKishon Vijay Abraham I {
1570bc1e3272SJean-Jacques Hiblot 	int err;
1571bc1e3272SJean-Jacques Hiblot 
1572bc1e3272SJean-Jacques Hiblot 	if (mmc->signal_voltage == signal_voltage)
1573bc1e3272SJean-Jacques Hiblot 		return 0;
1574bc1e3272SJean-Jacques Hiblot 
1575aff5d3c8SKishon Vijay Abraham I 	mmc->signal_voltage = signal_voltage;
1576bc1e3272SJean-Jacques Hiblot 	err = mmc_set_ios(mmc);
1577bc1e3272SJean-Jacques Hiblot 	if (err)
1578bc1e3272SJean-Jacques Hiblot 		debug("unable to set voltage (err %d)\n", err);
1579bc1e3272SJean-Jacques Hiblot 
1580bc1e3272SJean-Jacques Hiblot 	return err;
1581aff5d3c8SKishon Vijay Abraham I }
1582f99c2efeSJean-Jacques Hiblot #else
1583f99c2efeSJean-Jacques Hiblot static inline int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage)
1584f99c2efeSJean-Jacques Hiblot {
1585f99c2efeSJean-Jacques Hiblot 	return 0;
1586f99c2efeSJean-Jacques Hiblot }
1587f99c2efeSJean-Jacques Hiblot #endif
1588aff5d3c8SKishon Vijay Abraham I 
1589d0c221feSJean-Jacques Hiblot static const struct mode_width_tuning sd_modes_by_pref[] = {
1590f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1591f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
1592d0c221feSJean-Jacques Hiblot 	{
1593c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR104,
1594c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1595c10b85d6SJean-Jacques Hiblot 		.tuning = MMC_CMD_SEND_TUNING_BLOCK
1596c10b85d6SJean-Jacques Hiblot 	},
1597f99c2efeSJean-Jacques Hiblot #endif
1598c10b85d6SJean-Jacques Hiblot 	{
1599c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR50,
1600c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1601c10b85d6SJean-Jacques Hiblot 	},
1602c10b85d6SJean-Jacques Hiblot 	{
1603c10b85d6SJean-Jacques Hiblot 		.mode = UHS_DDR50,
1604c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1605c10b85d6SJean-Jacques Hiblot 	},
1606c10b85d6SJean-Jacques Hiblot 	{
1607c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR25,
1608c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1609c10b85d6SJean-Jacques Hiblot 	},
1610f99c2efeSJean-Jacques Hiblot #endif
1611c10b85d6SJean-Jacques Hiblot 	{
1612d0c221feSJean-Jacques Hiblot 		.mode = SD_HS,
1613d0c221feSJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1614d0c221feSJean-Jacques Hiblot 	},
1615f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1616d0c221feSJean-Jacques Hiblot 	{
1617c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR12,
1618c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1619c10b85d6SJean-Jacques Hiblot 	},
1620f99c2efeSJean-Jacques Hiblot #endif
1621c10b85d6SJean-Jacques Hiblot 	{
1622d0c221feSJean-Jacques Hiblot 		.mode = SD_LEGACY,
1623d0c221feSJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1624d0c221feSJean-Jacques Hiblot 	}
1625d0c221feSJean-Jacques Hiblot };
1626d0c221feSJean-Jacques Hiblot 
1627d0c221feSJean-Jacques Hiblot #define for_each_sd_mode_by_pref(caps, mwt) \
1628d0c221feSJean-Jacques Hiblot 	for (mwt = sd_modes_by_pref;\
1629d0c221feSJean-Jacques Hiblot 	     mwt < sd_modes_by_pref + ARRAY_SIZE(sd_modes_by_pref);\
1630d0c221feSJean-Jacques Hiblot 	     mwt++) \
1631d0c221feSJean-Jacques Hiblot 		if (caps & MMC_CAP(mwt->mode))
1632d0c221feSJean-Jacques Hiblot 
163301298da3SJean-Jacques Hiblot static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps)
16348ac8a263SJean-Jacques Hiblot {
16358ac8a263SJean-Jacques Hiblot 	int err;
1636d0c221feSJean-Jacques Hiblot 	uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT};
1637d0c221feSJean-Jacques Hiblot 	const struct mode_width_tuning *mwt;
1638f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1639c10b85d6SJean-Jacques Hiblot 	bool uhs_en = (mmc->ocr & OCR_S18R) ? true : false;
1640f99c2efeSJean-Jacques Hiblot #else
1641f99c2efeSJean-Jacques Hiblot 	bool uhs_en = false;
1642f99c2efeSJean-Jacques Hiblot #endif
1643c10b85d6SJean-Jacques Hiblot 	uint caps;
1644c10b85d6SJean-Jacques Hiblot 
164552d241dfSJean-Jacques Hiblot #ifdef DEBUG
164652d241dfSJean-Jacques Hiblot 	mmc_dump_capabilities("sd card", card_caps);
16471da8eb59SJean-Jacques Hiblot 	mmc_dump_capabilities("host", mmc->host_caps);
164852d241dfSJean-Jacques Hiblot #endif
16498ac8a263SJean-Jacques Hiblot 
16508ac8a263SJean-Jacques Hiblot 	/* Restrict card's capabilities by what the host can do */
16511da8eb59SJean-Jacques Hiblot 	caps = card_caps & mmc->host_caps;
16528ac8a263SJean-Jacques Hiblot 
1653c10b85d6SJean-Jacques Hiblot 	if (!uhs_en)
1654c10b85d6SJean-Jacques Hiblot 		caps &= ~UHS_CAPS;
1655c10b85d6SJean-Jacques Hiblot 
1656c10b85d6SJean-Jacques Hiblot 	for_each_sd_mode_by_pref(caps, mwt) {
1657d0c221feSJean-Jacques Hiblot 		uint *w;
16588ac8a263SJean-Jacques Hiblot 
1659d0c221feSJean-Jacques Hiblot 		for (w = widths; w < widths + ARRAY_SIZE(widths); w++) {
1660c10b85d6SJean-Jacques Hiblot 			if (*w & caps & mwt->widths) {
1661d0c221feSJean-Jacques Hiblot 				debug("trying mode %s width %d (at %d MHz)\n",
1662d0c221feSJean-Jacques Hiblot 				      mmc_mode_name(mwt->mode),
1663d0c221feSJean-Jacques Hiblot 				      bus_width(*w),
1664d0c221feSJean-Jacques Hiblot 				      mmc_mode2freq(mmc, mwt->mode) / 1000000);
1665d0c221feSJean-Jacques Hiblot 
1666d0c221feSJean-Jacques Hiblot 				/* configure the bus width (card + host) */
1667d0c221feSJean-Jacques Hiblot 				err = sd_select_bus_width(mmc, bus_width(*w));
16688ac8a263SJean-Jacques Hiblot 				if (err)
1669d0c221feSJean-Jacques Hiblot 					goto error;
1670d0c221feSJean-Jacques Hiblot 				mmc_set_bus_width(mmc, bus_width(*w));
16718ac8a263SJean-Jacques Hiblot 
1672d0c221feSJean-Jacques Hiblot 				/* configure the bus mode (card) */
1673d0c221feSJean-Jacques Hiblot 				err = sd_set_card_speed(mmc, mwt->mode);
16748ac8a263SJean-Jacques Hiblot 				if (err)
1675d0c221feSJean-Jacques Hiblot 					goto error;
16768ac8a263SJean-Jacques Hiblot 
1677d0c221feSJean-Jacques Hiblot 				/* configure the bus mode (host) */
1678d0c221feSJean-Jacques Hiblot 				mmc_select_mode(mmc, mwt->mode);
167935f67820SKishon Vijay Abraham I 				mmc_set_clock(mmc, mmc->tran_speed, false);
16808ac8a263SJean-Jacques Hiblot 
1681f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
1682c10b85d6SJean-Jacques Hiblot 				/* execute tuning if needed */
1683c10b85d6SJean-Jacques Hiblot 				if (mwt->tuning && !mmc_host_is_spi(mmc)) {
1684c10b85d6SJean-Jacques Hiblot 					err = mmc_execute_tuning(mmc,
1685c10b85d6SJean-Jacques Hiblot 								 mwt->tuning);
1686c10b85d6SJean-Jacques Hiblot 					if (err) {
1687c10b85d6SJean-Jacques Hiblot 						debug("tuning failed\n");
1688c10b85d6SJean-Jacques Hiblot 						goto error;
1689c10b85d6SJean-Jacques Hiblot 					}
1690c10b85d6SJean-Jacques Hiblot 				}
1691f99c2efeSJean-Jacques Hiblot #endif
1692c10b85d6SJean-Jacques Hiblot 
1693*5b2e72f3SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE)
16948ac8a263SJean-Jacques Hiblot 				err = sd_read_ssr(mmc);
1695d0c221feSJean-Jacques Hiblot 				if (!err)
1696*5b2e72f3SJean-Jacques Hiblot 					pr_warn("unable to read ssr\n");
1697*5b2e72f3SJean-Jacques Hiblot #endif
1698*5b2e72f3SJean-Jacques Hiblot 				if (!err)
16998ac8a263SJean-Jacques Hiblot 					return 0;
1700d0c221feSJean-Jacques Hiblot 
1701d0c221feSJean-Jacques Hiblot error:
1702d0c221feSJean-Jacques Hiblot 				/* revert to a safer bus speed */
1703d0c221feSJean-Jacques Hiblot 				mmc_select_mode(mmc, SD_LEGACY);
170435f67820SKishon Vijay Abraham I 				mmc_set_clock(mmc, mmc->tran_speed, false);
1705d0c221feSJean-Jacques Hiblot 			}
1706d0c221feSJean-Jacques Hiblot 		}
1707d0c221feSJean-Jacques Hiblot 	}
1708d0c221feSJean-Jacques Hiblot 
1709d0c221feSJean-Jacques Hiblot 	printf("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) {
1754bc1e3272SJean-Jacques Hiblot 	case MMC_HS_200:
1755bc1e3272SJean-Jacques Hiblot 		if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_8V)
1756bc1e3272SJean-Jacques Hiblot 			card_mask |= MMC_SIGNAL_VOLTAGE_180;
1757bc1e3272SJean-Jacques Hiblot 		if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_2V)
1758bc1e3272SJean-Jacques Hiblot 			card_mask |= MMC_SIGNAL_VOLTAGE_120;
1759bc1e3272SJean-Jacques Hiblot 		break;
1760bc1e3272SJean-Jacques Hiblot 	case MMC_DDR_52:
1761bc1e3272SJean-Jacques Hiblot 		if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V)
1762bc1e3272SJean-Jacques Hiblot 			card_mask |= MMC_SIGNAL_VOLTAGE_330 |
1763bc1e3272SJean-Jacques Hiblot 				     MMC_SIGNAL_VOLTAGE_180;
1764bc1e3272SJean-Jacques Hiblot 		if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_2V)
1765bc1e3272SJean-Jacques Hiblot 			card_mask |= MMC_SIGNAL_VOLTAGE_120;
1766bc1e3272SJean-Jacques Hiblot 		break;
1767bc1e3272SJean-Jacques Hiblot 	default:
1768bc1e3272SJean-Jacques Hiblot 		card_mask |= MMC_SIGNAL_VOLTAGE_330;
1769bc1e3272SJean-Jacques Hiblot 		break;
1770bc1e3272SJean-Jacques Hiblot 	}
1771bc1e3272SJean-Jacques Hiblot 
1772bc1e3272SJean-Jacques Hiblot 	while (card_mask & allowed_mask) {
1773bc1e3272SJean-Jacques Hiblot 		enum mmc_voltage best_match;
1774bc1e3272SJean-Jacques Hiblot 
1775bc1e3272SJean-Jacques Hiblot 		best_match = 1 << (ffs(card_mask & allowed_mask) - 1);
1776bc1e3272SJean-Jacques Hiblot 		if (!mmc_set_signal_voltage(mmc,  best_match))
1777bc1e3272SJean-Jacques Hiblot 			return 0;
1778bc1e3272SJean-Jacques Hiblot 
1779bc1e3272SJean-Jacques Hiblot 		allowed_mask &= ~best_match;
1780bc1e3272SJean-Jacques Hiblot 	}
1781bc1e3272SJean-Jacques Hiblot 
1782bc1e3272SJean-Jacques Hiblot 	return -ENOTSUPP;
1783bc1e3272SJean-Jacques Hiblot }
1784f99c2efeSJean-Jacques Hiblot #else
1785f99c2efeSJean-Jacques Hiblot static inline int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,
1786f99c2efeSJean-Jacques Hiblot 					 uint32_t allowed_mask)
1787f99c2efeSJean-Jacques Hiblot {
1788f99c2efeSJean-Jacques Hiblot 	return 0;
1789f99c2efeSJean-Jacques Hiblot }
1790f99c2efeSJean-Jacques Hiblot #endif
1791bc1e3272SJean-Jacques Hiblot 
17923862b854SJean-Jacques Hiblot static const struct mode_width_tuning mmc_modes_by_pref[] = {
1793f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
17948ac8a263SJean-Jacques Hiblot 	{
17953862b854SJean-Jacques Hiblot 		.mode = MMC_HS_200,
17963862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
1797634d4849SKishon Vijay Abraham I 		.tuning = MMC_CMD_SEND_TUNING_BLOCK_HS200
17983862b854SJean-Jacques Hiblot 	},
1799f99c2efeSJean-Jacques Hiblot #endif
18003862b854SJean-Jacques Hiblot 	{
18013862b854SJean-Jacques Hiblot 		.mode = MMC_DDR_52,
18023862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
18033862b854SJean-Jacques Hiblot 	},
18043862b854SJean-Jacques Hiblot 	{
18053862b854SJean-Jacques Hiblot 		.mode = MMC_HS_52,
18063862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
18073862b854SJean-Jacques Hiblot 	},
18083862b854SJean-Jacques Hiblot 	{
18093862b854SJean-Jacques Hiblot 		.mode = MMC_HS,
18103862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
18113862b854SJean-Jacques Hiblot 	},
18123862b854SJean-Jacques Hiblot 	{
18133862b854SJean-Jacques Hiblot 		.mode = MMC_LEGACY,
18143862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
18153862b854SJean-Jacques Hiblot 	}
18168ac8a263SJean-Jacques Hiblot };
18178ac8a263SJean-Jacques Hiblot 
18183862b854SJean-Jacques Hiblot #define for_each_mmc_mode_by_pref(caps, mwt) \
18193862b854SJean-Jacques Hiblot 	for (mwt = mmc_modes_by_pref;\
18203862b854SJean-Jacques Hiblot 	    mwt < mmc_modes_by_pref + ARRAY_SIZE(mmc_modes_by_pref);\
18213862b854SJean-Jacques Hiblot 	    mwt++) \
18223862b854SJean-Jacques Hiblot 		if (caps & MMC_CAP(mwt->mode))
18233862b854SJean-Jacques Hiblot 
18243862b854SJean-Jacques Hiblot static const struct ext_csd_bus_width {
18253862b854SJean-Jacques Hiblot 	uint cap;
18263862b854SJean-Jacques Hiblot 	bool is_ddr;
18273862b854SJean-Jacques Hiblot 	uint ext_csd_bits;
18283862b854SJean-Jacques Hiblot } ext_csd_bus_width[] = {
18293862b854SJean-Jacques Hiblot 	{MMC_MODE_8BIT, true, EXT_CSD_DDR_BUS_WIDTH_8},
18303862b854SJean-Jacques Hiblot 	{MMC_MODE_4BIT, true, EXT_CSD_DDR_BUS_WIDTH_4},
18313862b854SJean-Jacques Hiblot 	{MMC_MODE_8BIT, false, EXT_CSD_BUS_WIDTH_8},
18323862b854SJean-Jacques Hiblot 	{MMC_MODE_4BIT, false, EXT_CSD_BUS_WIDTH_4},
18333862b854SJean-Jacques Hiblot 	{MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1},
18343862b854SJean-Jacques Hiblot };
18353862b854SJean-Jacques Hiblot 
18363862b854SJean-Jacques Hiblot #define for_each_supported_width(caps, ddr, ecbv) \
18373862b854SJean-Jacques Hiblot 	for (ecbv = ext_csd_bus_width;\
18383862b854SJean-Jacques Hiblot 	    ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\
18393862b854SJean-Jacques Hiblot 	    ecbv++) \
18403862b854SJean-Jacques Hiblot 		if ((ddr == ecbv->is_ddr) && (caps & ecbv->cap))
18413862b854SJean-Jacques Hiblot 
184201298da3SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
18433862b854SJean-Jacques Hiblot {
18443862b854SJean-Jacques Hiblot 	int err;
18453862b854SJean-Jacques Hiblot 	const struct mode_width_tuning *mwt;
18463862b854SJean-Jacques Hiblot 	const struct ext_csd_bus_width *ecbw;
18473862b854SJean-Jacques Hiblot 
184852d241dfSJean-Jacques Hiblot #ifdef DEBUG
184952d241dfSJean-Jacques Hiblot 	mmc_dump_capabilities("mmc", card_caps);
18501da8eb59SJean-Jacques Hiblot 	mmc_dump_capabilities("host", mmc->host_caps);
185152d241dfSJean-Jacques Hiblot #endif
185252d241dfSJean-Jacques Hiblot 
18538ac8a263SJean-Jacques Hiblot 	/* Restrict card's capabilities by what the host can do */
18541da8eb59SJean-Jacques Hiblot 	card_caps &= mmc->host_caps;
18558ac8a263SJean-Jacques Hiblot 
18568ac8a263SJean-Jacques Hiblot 	/* Only version 4 of MMC supports wider bus widths */
18578ac8a263SJean-Jacques Hiblot 	if (mmc->version < MMC_VERSION_4)
18588ac8a263SJean-Jacques Hiblot 		return 0;
18598ac8a263SJean-Jacques Hiblot 
1860dfda9d88SJean-Jacques Hiblot 	if (!mmc->ext_csd) {
1861dfda9d88SJean-Jacques Hiblot 		debug("No ext_csd found!\n"); /* this should enver happen */
1862dfda9d88SJean-Jacques Hiblot 		return -ENOTSUPP;
1863dfda9d88SJean-Jacques Hiblot 	}
1864dfda9d88SJean-Jacques Hiblot 
186501298da3SJean-Jacques Hiblot 	mmc_set_clock(mmc, mmc->legacy_speed, false);
186601298da3SJean-Jacques Hiblot 
186701298da3SJean-Jacques Hiblot 	for_each_mmc_mode_by_pref(card_caps, mwt) {
186801298da3SJean-Jacques Hiblot 		for_each_supported_width(card_caps & mwt->widths,
18693862b854SJean-Jacques Hiblot 					 mmc_is_mode_ddr(mwt->mode), ecbw) {
1870bc1e3272SJean-Jacques Hiblot 			enum mmc_voltage old_voltage;
18713862b854SJean-Jacques Hiblot 			debug("trying mode %s width %d (at %d MHz)\n",
18723862b854SJean-Jacques Hiblot 			      mmc_mode_name(mwt->mode),
18733862b854SJean-Jacques Hiblot 			      bus_width(ecbw->cap),
18743862b854SJean-Jacques Hiblot 			      mmc_mode2freq(mmc, mwt->mode) / 1000000);
1875bc1e3272SJean-Jacques Hiblot 			old_voltage = mmc->signal_voltage;
1876bc1e3272SJean-Jacques Hiblot 			err = mmc_set_lowest_voltage(mmc, mwt->mode,
1877bc1e3272SJean-Jacques Hiblot 						     MMC_ALL_SIGNAL_VOLTAGE);
1878bc1e3272SJean-Jacques Hiblot 			if (err)
1879bc1e3272SJean-Jacques Hiblot 				continue;
1880bc1e3272SJean-Jacques Hiblot 
18813862b854SJean-Jacques Hiblot 			/* configure the bus width (card + host) */
18823862b854SJean-Jacques Hiblot 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
18833862b854SJean-Jacques Hiblot 				    EXT_CSD_BUS_WIDTH,
18843862b854SJean-Jacques Hiblot 				    ecbw->ext_csd_bits & ~EXT_CSD_DDR_FLAG);
18853862b854SJean-Jacques Hiblot 			if (err)
18863862b854SJean-Jacques Hiblot 				goto error;
18873862b854SJean-Jacques Hiblot 			mmc_set_bus_width(mmc, bus_width(ecbw->cap));
18883862b854SJean-Jacques Hiblot 
18893862b854SJean-Jacques Hiblot 			/* configure the bus speed (card) */
18903862b854SJean-Jacques Hiblot 			err = mmc_set_card_speed(mmc, mwt->mode);
18913862b854SJean-Jacques Hiblot 			if (err)
18923862b854SJean-Jacques Hiblot 				goto error;
18933862b854SJean-Jacques Hiblot 
18948ac8a263SJean-Jacques Hiblot 			/*
18953862b854SJean-Jacques Hiblot 			 * configure the bus width AND the ddr mode (card)
18963862b854SJean-Jacques Hiblot 			 * The host side will be taken care of in the next step
18978ac8a263SJean-Jacques Hiblot 			 */
18983862b854SJean-Jacques Hiblot 			if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) {
18993862b854SJean-Jacques Hiblot 				err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
19003862b854SJean-Jacques Hiblot 						 EXT_CSD_BUS_WIDTH,
19013862b854SJean-Jacques Hiblot 						 ecbw->ext_csd_bits);
19023862b854SJean-Jacques Hiblot 				if (err)
19033862b854SJean-Jacques Hiblot 					goto error;
19048ac8a263SJean-Jacques Hiblot 			}
19058ac8a263SJean-Jacques Hiblot 
19063862b854SJean-Jacques Hiblot 			/* configure the bus mode (host) */
19073862b854SJean-Jacques Hiblot 			mmc_select_mode(mmc, mwt->mode);
190835f67820SKishon Vijay Abraham I 			mmc_set_clock(mmc, mmc->tran_speed, false);
1909f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
19108ac8a263SJean-Jacques Hiblot 
1911634d4849SKishon Vijay Abraham I 			/* execute tuning if needed */
1912634d4849SKishon Vijay Abraham I 			if (mwt->tuning) {
1913634d4849SKishon Vijay Abraham I 				err = mmc_execute_tuning(mmc, mwt->tuning);
1914634d4849SKishon Vijay Abraham I 				if (err) {
1915634d4849SKishon Vijay Abraham I 					debug("tuning failed\n");
1916634d4849SKishon Vijay Abraham I 					goto error;
1917634d4849SKishon Vijay Abraham I 				}
1918634d4849SKishon Vijay Abraham I 			}
1919f99c2efeSJean-Jacques Hiblot #endif
1920634d4849SKishon Vijay Abraham I 
19213862b854SJean-Jacques Hiblot 			/* do a transfer to check the configuration */
19227382e691SJean-Jacques Hiblot 			err = mmc_read_and_compare_ext_csd(mmc);
19237382e691SJean-Jacques Hiblot 			if (!err)
19243862b854SJean-Jacques Hiblot 				return 0;
19253862b854SJean-Jacques Hiblot error:
1926bc1e3272SJean-Jacques Hiblot 			mmc_set_signal_voltage(mmc, old_voltage);
19273862b854SJean-Jacques Hiblot 			/* if an error occured, revert to a safer bus mode */
19283862b854SJean-Jacques Hiblot 			mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
19293862b854SJean-Jacques Hiblot 				   EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1);
19303862b854SJean-Jacques Hiblot 			mmc_select_mode(mmc, MMC_LEGACY);
19313862b854SJean-Jacques Hiblot 			mmc_set_bus_width(mmc, 1);
19323862b854SJean-Jacques Hiblot 		}
19338ac8a263SJean-Jacques Hiblot 	}
19348ac8a263SJean-Jacques Hiblot 
1935d8e3d420SJean-Jacques Hiblot 	pr_err("unable to select a mode\n");
19368ac8a263SJean-Jacques Hiblot 
19373862b854SJean-Jacques Hiblot 	return -ENOTSUPP;
19388ac8a263SJean-Jacques Hiblot }
19398ac8a263SJean-Jacques Hiblot 
1940dfda9d88SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc)
1941c744b6f6SJean-Jacques Hiblot {
1942c744b6f6SJean-Jacques Hiblot 	int err, i;
1943c744b6f6SJean-Jacques Hiblot 	u64 capacity;
1944c744b6f6SJean-Jacques Hiblot 	bool has_parts = false;
1945c744b6f6SJean-Jacques Hiblot 	bool part_completed;
194658a6fb7bSJean-Jacques Hiblot 	static const u32 mmc_versions[] = {
194758a6fb7bSJean-Jacques Hiblot 		MMC_VERSION_4,
194858a6fb7bSJean-Jacques Hiblot 		MMC_VERSION_4_1,
194958a6fb7bSJean-Jacques Hiblot 		MMC_VERSION_4_2,
195058a6fb7bSJean-Jacques Hiblot 		MMC_VERSION_4_3,
195158a6fb7bSJean-Jacques Hiblot 		MMC_VERSION_4_41,
195258a6fb7bSJean-Jacques Hiblot 		MMC_VERSION_4_5,
195358a6fb7bSJean-Jacques Hiblot 		MMC_VERSION_5_0,
195458a6fb7bSJean-Jacques Hiblot 		MMC_VERSION_5_1
195558a6fb7bSJean-Jacques Hiblot 	};
195658a6fb7bSJean-Jacques Hiblot 
1957f7d5dffcSJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
1958c744b6f6SJean-Jacques Hiblot 
1959c744b6f6SJean-Jacques Hiblot 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4))
1960c744b6f6SJean-Jacques Hiblot 		return 0;
1961c744b6f6SJean-Jacques Hiblot 
1962c744b6f6SJean-Jacques Hiblot 	/* check  ext_csd version and capacity */
1963c744b6f6SJean-Jacques Hiblot 	err = mmc_send_ext_csd(mmc, ext_csd);
1964c744b6f6SJean-Jacques Hiblot 	if (err)
1965f7d5dffcSJean-Jacques Hiblot 		goto error;
1966f7d5dffcSJean-Jacques Hiblot 
1967f7d5dffcSJean-Jacques Hiblot 	/* store the ext csd for future reference */
1968f7d5dffcSJean-Jacques Hiblot 	if (!mmc->ext_csd)
1969f7d5dffcSJean-Jacques Hiblot 		mmc->ext_csd = malloc(MMC_MAX_BLOCK_LEN);
1970f7d5dffcSJean-Jacques Hiblot 	if (!mmc->ext_csd)
1971f7d5dffcSJean-Jacques Hiblot 		return -ENOMEM;
1972f7d5dffcSJean-Jacques Hiblot 	memcpy(mmc->ext_csd, ext_csd, MMC_MAX_BLOCK_LEN);
1973f7d5dffcSJean-Jacques Hiblot 
197458a6fb7bSJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_REV] > ARRAY_SIZE(mmc_versions))
197558a6fb7bSJean-Jacques Hiblot 		return -EINVAL;
197658a6fb7bSJean-Jacques Hiblot 
197758a6fb7bSJean-Jacques Hiblot 	mmc->version = mmc_versions[ext_csd[EXT_CSD_REV]];
197858a6fb7bSJean-Jacques Hiblot 
197958a6fb7bSJean-Jacques Hiblot 	if (mmc->version >= MMC_VERSION_4_2) {
1980c744b6f6SJean-Jacques Hiblot 		/*
1981c744b6f6SJean-Jacques Hiblot 		 * According to the JEDEC Standard, the value of
1982c744b6f6SJean-Jacques Hiblot 		 * ext_csd's capacity is valid if the value is more
1983c744b6f6SJean-Jacques Hiblot 		 * than 2GB
1984c744b6f6SJean-Jacques Hiblot 		 */
1985c744b6f6SJean-Jacques Hiblot 		capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
1986c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
1987c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
1988c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
1989c744b6f6SJean-Jacques Hiblot 		capacity *= MMC_MAX_BLOCK_LEN;
1990c744b6f6SJean-Jacques Hiblot 		if ((capacity >> 20) > 2 * 1024)
1991c744b6f6SJean-Jacques Hiblot 			mmc->capacity_user = capacity;
1992c744b6f6SJean-Jacques Hiblot 	}
1993c744b6f6SJean-Jacques Hiblot 
1994c744b6f6SJean-Jacques Hiblot 	/* The partition data may be non-zero but it is only
1995c744b6f6SJean-Jacques Hiblot 	 * effective if PARTITION_SETTING_COMPLETED is set in
1996c744b6f6SJean-Jacques Hiblot 	 * EXT_CSD, so ignore any data if this bit is not set,
1997c744b6f6SJean-Jacques Hiblot 	 * except for enabling the high-capacity group size
1998c744b6f6SJean-Jacques Hiblot 	 * definition (see below).
1999c744b6f6SJean-Jacques Hiblot 	 */
2000c744b6f6SJean-Jacques Hiblot 	part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
2001c744b6f6SJean-Jacques Hiblot 			    EXT_CSD_PARTITION_SETTING_COMPLETED);
2002c744b6f6SJean-Jacques Hiblot 
2003c744b6f6SJean-Jacques Hiblot 	/* store the partition info of emmc */
2004c744b6f6SJean-Jacques Hiblot 	mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
2005c744b6f6SJean-Jacques Hiblot 	if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
2006c744b6f6SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_BOOT_MULT])
2007c744b6f6SJean-Jacques Hiblot 		mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
2008c744b6f6SJean-Jacques Hiblot 	if (part_completed &&
2009c744b6f6SJean-Jacques Hiblot 	    (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
2010c744b6f6SJean-Jacques Hiblot 		mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
2011c744b6f6SJean-Jacques Hiblot 
2012c744b6f6SJean-Jacques Hiblot 	mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
2013c744b6f6SJean-Jacques Hiblot 
2014c744b6f6SJean-Jacques Hiblot 	mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
2015c744b6f6SJean-Jacques Hiblot 
2016c744b6f6SJean-Jacques Hiblot 	for (i = 0; i < 4; i++) {
2017c744b6f6SJean-Jacques Hiblot 		int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
2018c744b6f6SJean-Jacques Hiblot 		uint mult = (ext_csd[idx + 2] << 16) +
2019c744b6f6SJean-Jacques Hiblot 			(ext_csd[idx + 1] << 8) + ext_csd[idx];
2020c744b6f6SJean-Jacques Hiblot 		if (mult)
2021c744b6f6SJean-Jacques Hiblot 			has_parts = true;
2022c744b6f6SJean-Jacques Hiblot 		if (!part_completed)
2023c744b6f6SJean-Jacques Hiblot 			continue;
2024c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] = mult;
2025c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] *=
2026c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
2027c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
2028c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] <<= 19;
2029c744b6f6SJean-Jacques Hiblot 	}
2030c744b6f6SJean-Jacques Hiblot 
2031c744b6f6SJean-Jacques Hiblot 	if (part_completed) {
2032c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size =
2033c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) +
2034c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) +
2035c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_ENH_SIZE_MULT];
2036c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
2037c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
2038c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size <<= 19;
2039c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_start =
2040c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) +
2041c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) +
2042c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) +
2043c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_ENH_START_ADDR];
2044c744b6f6SJean-Jacques Hiblot 		if (mmc->high_capacity)
2045c744b6f6SJean-Jacques Hiblot 			mmc->enh_user_start <<= 9;
2046c744b6f6SJean-Jacques Hiblot 	}
2047c744b6f6SJean-Jacques Hiblot 
2048c744b6f6SJean-Jacques Hiblot 	/*
2049c744b6f6SJean-Jacques Hiblot 	 * Host needs to enable ERASE_GRP_DEF bit if device is
2050c744b6f6SJean-Jacques Hiblot 	 * partitioned. This bit will be lost every time after a reset
2051c744b6f6SJean-Jacques Hiblot 	 * or power off. This will affect erase size.
2052c744b6f6SJean-Jacques Hiblot 	 */
2053c744b6f6SJean-Jacques Hiblot 	if (part_completed)
2054c744b6f6SJean-Jacques Hiblot 		has_parts = true;
2055c744b6f6SJean-Jacques Hiblot 	if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
2056c744b6f6SJean-Jacques Hiblot 	    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
2057c744b6f6SJean-Jacques Hiblot 		has_parts = true;
2058c744b6f6SJean-Jacques Hiblot 	if (has_parts) {
2059c744b6f6SJean-Jacques Hiblot 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
2060c744b6f6SJean-Jacques Hiblot 				 EXT_CSD_ERASE_GROUP_DEF, 1);
2061c744b6f6SJean-Jacques Hiblot 
2062c744b6f6SJean-Jacques Hiblot 		if (err)
2063f7d5dffcSJean-Jacques Hiblot 			goto error;
2064c744b6f6SJean-Jacques Hiblot 
2065c744b6f6SJean-Jacques Hiblot 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
2066c744b6f6SJean-Jacques Hiblot 	}
2067c744b6f6SJean-Jacques Hiblot 
2068c744b6f6SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
2069c744b6f6SJean-Jacques Hiblot 		/* Read out group size from ext_csd */
2070c744b6f6SJean-Jacques Hiblot 		mmc->erase_grp_size =
2071c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
2072c744b6f6SJean-Jacques Hiblot 		/*
2073c744b6f6SJean-Jacques Hiblot 		 * if high capacity and partition setting completed
2074c744b6f6SJean-Jacques Hiblot 		 * SEC_COUNT is valid even if it is smaller than 2 GiB
2075c744b6f6SJean-Jacques Hiblot 		 * JEDEC Standard JESD84-B45, 6.2.4
2076c744b6f6SJean-Jacques Hiblot 		 */
2077c744b6f6SJean-Jacques Hiblot 		if (mmc->high_capacity && part_completed) {
2078c744b6f6SJean-Jacques Hiblot 			capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
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 			mmc->capacity_user = capacity;
2084c744b6f6SJean-Jacques Hiblot 		}
2085c744b6f6SJean-Jacques Hiblot 	} else {
2086c744b6f6SJean-Jacques Hiblot 		/* Calculate the group size from the csd value. */
2087c744b6f6SJean-Jacques Hiblot 		int erase_gsz, erase_gmul;
2088c744b6f6SJean-Jacques Hiblot 
2089c744b6f6SJean-Jacques Hiblot 		erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
2090c744b6f6SJean-Jacques Hiblot 		erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
2091c744b6f6SJean-Jacques Hiblot 		mmc->erase_grp_size = (erase_gsz + 1)
2092c744b6f6SJean-Jacques Hiblot 			* (erase_gmul + 1);
2093c744b6f6SJean-Jacques Hiblot 	}
2094c744b6f6SJean-Jacques Hiblot 
2095c744b6f6SJean-Jacques Hiblot 	mmc->hc_wp_grp_size = 1024
2096c744b6f6SJean-Jacques Hiblot 		* ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
2097c744b6f6SJean-Jacques Hiblot 		* ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
2098c744b6f6SJean-Jacques Hiblot 
2099c744b6f6SJean-Jacques Hiblot 	mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
2100c744b6f6SJean-Jacques Hiblot 
2101c744b6f6SJean-Jacques Hiblot 	return 0;
2102f7d5dffcSJean-Jacques Hiblot error:
2103f7d5dffcSJean-Jacques Hiblot 	if (mmc->ext_csd) {
2104f7d5dffcSJean-Jacques Hiblot 		free(mmc->ext_csd);
2105f7d5dffcSJean-Jacques Hiblot 		mmc->ext_csd = NULL;
2106f7d5dffcSJean-Jacques Hiblot 	}
2107f7d5dffcSJean-Jacques Hiblot 	return err;
2108c744b6f6SJean-Jacques Hiblot }
2109c744b6f6SJean-Jacques Hiblot 
2110fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc)
2111272cc70bSAndy Fleming {
2112f866a46dSStephen Warren 	int err, i;
2113272cc70bSAndy Fleming 	uint mult, freq;
2114c744b6f6SJean-Jacques Hiblot 	u64 cmult, csize;
2115272cc70bSAndy Fleming 	struct mmc_cmd cmd;
2116c40fdca6SSimon Glass 	struct blk_desc *bdesc;
2117272cc70bSAndy Fleming 
2118d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
2119d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
2120d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
2121d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
2122d52ebf10SThomas Chou 		cmd.cmdarg = 1;
2123d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
2124d52ebf10SThomas Chou 		if (err)
2125d52ebf10SThomas Chou 			return err;
2126d52ebf10SThomas Chou 	}
2127d52ebf10SThomas Chou #endif
2128d52ebf10SThomas Chou 
2129272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
2130d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
2131d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
2132272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
2133272cc70bSAndy Fleming 	cmd.cmdarg = 0;
2134272cc70bSAndy Fleming 
2135272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
2136272cc70bSAndy Fleming 
213783dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS
213883dc4227SKishon Vijay Abraham I 	if (err && (mmc->quirks & MMC_QUIRK_RETRY_SEND_CID)) {
213983dc4227SKishon Vijay Abraham I 		int retries = 4;
214083dc4227SKishon Vijay Abraham I 		/*
214183dc4227SKishon Vijay Abraham I 		 * It has been seen that SEND_CID may fail on the first
214283dc4227SKishon Vijay Abraham I 		 * attempt, let's try a few more time
214383dc4227SKishon Vijay Abraham I 		 */
214483dc4227SKishon Vijay Abraham I 		do {
214583dc4227SKishon Vijay Abraham I 			err = mmc_send_cmd(mmc, &cmd, NULL);
214683dc4227SKishon Vijay Abraham I 			if (!err)
214783dc4227SKishon Vijay Abraham I 				break;
214883dc4227SKishon Vijay Abraham I 		} while (retries--);
214983dc4227SKishon Vijay Abraham I 	}
215083dc4227SKishon Vijay Abraham I #endif
215183dc4227SKishon Vijay Abraham I 
2152272cc70bSAndy Fleming 	if (err)
2153272cc70bSAndy Fleming 		return err;
2154272cc70bSAndy Fleming 
2155272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
2156272cc70bSAndy Fleming 
2157272cc70bSAndy Fleming 	/*
2158272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
2159272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
2160272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
2161272cc70bSAndy Fleming 	 */
2162d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
2163272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
2164272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
2165272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
2166272cc70bSAndy Fleming 
2167272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
2168272cc70bSAndy Fleming 
2169272cc70bSAndy Fleming 		if (err)
2170272cc70bSAndy Fleming 			return err;
2171272cc70bSAndy Fleming 
2172272cc70bSAndy Fleming 		if (IS_SD(mmc))
2173998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
2174d52ebf10SThomas Chou 	}
2175272cc70bSAndy Fleming 
2176272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
2177272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
2178272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
2179272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
2180272cc70bSAndy Fleming 
2181272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
2182272cc70bSAndy Fleming 
2183272cc70bSAndy Fleming 	if (err)
2184272cc70bSAndy Fleming 		return err;
2185272cc70bSAndy Fleming 
2186998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
2187998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
2188998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
2189998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
2190272cc70bSAndy Fleming 
2191272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
21920b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
2193272cc70bSAndy Fleming 
2194272cc70bSAndy Fleming 		switch (version) {
2195272cc70bSAndy Fleming 		case 0:
2196272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
2197272cc70bSAndy Fleming 			break;
2198272cc70bSAndy Fleming 		case 1:
2199272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_4;
2200272cc70bSAndy Fleming 			break;
2201272cc70bSAndy Fleming 		case 2:
2202272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_2_2;
2203272cc70bSAndy Fleming 			break;
2204272cc70bSAndy Fleming 		case 3:
2205272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_3;
2206272cc70bSAndy Fleming 			break;
2207272cc70bSAndy Fleming 		case 4:
2208272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_4;
2209272cc70bSAndy Fleming 			break;
2210272cc70bSAndy Fleming 		default:
2211272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
2212272cc70bSAndy Fleming 			break;
2213272cc70bSAndy Fleming 		}
2214272cc70bSAndy Fleming 	}
2215272cc70bSAndy Fleming 
2216272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
22170b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
22180b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
2219272cc70bSAndy Fleming 
222035f9e196SJean-Jacques Hiblot 	mmc->legacy_speed = freq * mult;
222135f9e196SJean-Jacques Hiblot 	mmc_select_mode(mmc, MMC_LEGACY);
2222272cc70bSAndy Fleming 
2223ab71188cSMarkus Niebel 	mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
2224998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
2225272cc70bSAndy Fleming 
2226272cc70bSAndy Fleming 	if (IS_SD(mmc))
2227272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
2228272cc70bSAndy Fleming 	else
2229998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
2230272cc70bSAndy Fleming 
2231272cc70bSAndy Fleming 	if (mmc->high_capacity) {
2232272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
2233272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
2234272cc70bSAndy Fleming 		cmult = 8;
2235272cc70bSAndy Fleming 	} else {
2236272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
2237272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
2238272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
2239272cc70bSAndy Fleming 	}
2240272cc70bSAndy Fleming 
2241f866a46dSStephen Warren 	mmc->capacity_user = (csize + 1) << (cmult + 2);
2242f866a46dSStephen Warren 	mmc->capacity_user *= mmc->read_bl_len;
2243f866a46dSStephen Warren 	mmc->capacity_boot = 0;
2244f866a46dSStephen Warren 	mmc->capacity_rpmb = 0;
2245f866a46dSStephen Warren 	for (i = 0; i < 4; i++)
2246f866a46dSStephen Warren 		mmc->capacity_gp[i] = 0;
2247272cc70bSAndy Fleming 
22488bfa195eSSimon Glass 	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
22498bfa195eSSimon Glass 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
2250272cc70bSAndy Fleming 
22518bfa195eSSimon Glass 	if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
22528bfa195eSSimon Glass 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
2253272cc70bSAndy Fleming 
2254ab71188cSMarkus Niebel 	if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
2255ab71188cSMarkus Niebel 		cmd.cmdidx = MMC_CMD_SET_DSR;
2256ab71188cSMarkus Niebel 		cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
2257ab71188cSMarkus Niebel 		cmd.resp_type = MMC_RSP_NONE;
2258ab71188cSMarkus Niebel 		if (mmc_send_cmd(mmc, &cmd, NULL))
2259d8e3d420SJean-Jacques Hiblot 			pr_warn("MMC: SET_DSR failed\n");
2260ab71188cSMarkus Niebel 	}
2261ab71188cSMarkus Niebel 
2262272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
2263d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
2264272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
2265fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
2266272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
2267272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
2268272cc70bSAndy Fleming 
2269272cc70bSAndy Fleming 		if (err)
2270272cc70bSAndy Fleming 			return err;
2271d52ebf10SThomas Chou 	}
2272272cc70bSAndy Fleming 
2273e6f99a56SLei Wen 	/*
2274e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
2275e6f99a56SLei Wen 	 */
2276e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
2277bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
2278c744b6f6SJean-Jacques Hiblot 
2279dfda9d88SJean-Jacques Hiblot 	err = mmc_startup_v4(mmc);
22809cf199ebSDiego Santa Cruz 	if (err)
22819cf199ebSDiego Santa Cruz 		return err;
2282f866a46dSStephen Warren 
2283c40fdca6SSimon Glass 	err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart);
2284f866a46dSStephen Warren 	if (err)
2285f866a46dSStephen Warren 		return err;
2286d23e2c09SSukumar Ghorai 
228701298da3SJean-Jacques Hiblot 	if (IS_SD(mmc)) {
228801298da3SJean-Jacques Hiblot 		err = sd_get_capabilities(mmc);
228901298da3SJean-Jacques Hiblot 		if (err)
229001298da3SJean-Jacques Hiblot 			return err;
229101298da3SJean-Jacques Hiblot 		err = sd_select_mode_and_width(mmc, mmc->card_caps);
229201298da3SJean-Jacques Hiblot 	} else {
229301298da3SJean-Jacques Hiblot 		err = mmc_get_capabilities(mmc);
229401298da3SJean-Jacques Hiblot 		if (err)
229501298da3SJean-Jacques Hiblot 			return err;
229601298da3SJean-Jacques Hiblot 		mmc_select_mode_and_width(mmc, mmc->card_caps);
229701298da3SJean-Jacques Hiblot 	}
2298272cc70bSAndy Fleming 
2299272cc70bSAndy Fleming 	if (err)
2300272cc70bSAndy Fleming 		return err;
2301272cc70bSAndy Fleming 
230201298da3SJean-Jacques Hiblot 	mmc->best_mode = mmc->selected_mode;
2303272cc70bSAndy Fleming 
23045af8f45cSAndrew Gabbasov 	/* Fix the block length for DDR mode */
23055af8f45cSAndrew Gabbasov 	if (mmc->ddr_mode) {
23065af8f45cSAndrew Gabbasov 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
23075af8f45cSAndrew Gabbasov 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
23085af8f45cSAndrew Gabbasov 	}
23095af8f45cSAndrew Gabbasov 
2310272cc70bSAndy Fleming 	/* fill in device description */
2311c40fdca6SSimon Glass 	bdesc = mmc_get_blk_desc(mmc);
2312c40fdca6SSimon Glass 	bdesc->lun = 0;
2313c40fdca6SSimon Glass 	bdesc->hwpart = 0;
2314c40fdca6SSimon Glass 	bdesc->type = 0;
2315c40fdca6SSimon Glass 	bdesc->blksz = mmc->read_bl_len;
2316c40fdca6SSimon Glass 	bdesc->log2blksz = LOG2(bdesc->blksz);
2317c40fdca6SSimon Glass 	bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len);
2318fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \
2319fc011f64SSjoerd Simons 		(defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \
2320fc011f64SSjoerd Simons 		!defined(CONFIG_USE_TINY_PRINTF))
2321c40fdca6SSimon Glass 	sprintf(bdesc->vendor, "Man %06x Snr %04x%04x",
2322babce5f6STaylor Hutt 		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
2323babce5f6STaylor Hutt 		(mmc->cid[3] >> 16) & 0xffff);
2324c40fdca6SSimon Glass 	sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
23250b453ffeSRabin Vincent 		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
2326babce5f6STaylor Hutt 		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
2327babce5f6STaylor Hutt 		(mmc->cid[2] >> 24) & 0xff);
2328c40fdca6SSimon Glass 	sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
2329babce5f6STaylor Hutt 		(mmc->cid[2] >> 16) & 0xf);
233056196826SPaul Burton #else
2331c40fdca6SSimon Glass 	bdesc->vendor[0] = 0;
2332c40fdca6SSimon Glass 	bdesc->product[0] = 0;
2333c40fdca6SSimon Glass 	bdesc->revision[0] = 0;
233456196826SPaul Burton #endif
2335122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
2336c40fdca6SSimon Glass 	part_init(bdesc);
2337122efd43SMikhail Kshevetskiy #endif
2338272cc70bSAndy Fleming 
2339272cc70bSAndy Fleming 	return 0;
2340272cc70bSAndy Fleming }
2341272cc70bSAndy Fleming 
2342fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc)
2343272cc70bSAndy Fleming {
2344272cc70bSAndy Fleming 	struct mmc_cmd cmd;
2345272cc70bSAndy Fleming 	int err;
2346272cc70bSAndy Fleming 
2347272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
2348272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
234993bfd616SPantelis Antoniou 	cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa;
2350272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
2351272cc70bSAndy Fleming 
2352272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
2353272cc70bSAndy Fleming 
2354272cc70bSAndy Fleming 	if (err)
2355272cc70bSAndy Fleming 		return err;
2356272cc70bSAndy Fleming 
2357998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
2358915ffa52SJaehoon Chung 		return -EOPNOTSUPP;
2359272cc70bSAndy Fleming 	else
2360272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
2361272cc70bSAndy Fleming 
2362272cc70bSAndy Fleming 	return 0;
2363272cc70bSAndy Fleming }
2364272cc70bSAndy Fleming 
2365c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
236695de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */
236795de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void)
236895de9ab2SPaul Kocialkowski {
236995de9ab2SPaul Kocialkowski }
237005cbeb7cSSimon Glass #endif
237195de9ab2SPaul Kocialkowski 
23722051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc)
23732051aefeSPeng Fan {
2374c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
237506ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR)
23762051aefeSPeng Fan 	int ret;
23772051aefeSPeng Fan 
23782051aefeSPeng Fan 	ret = device_get_supply_regulator(mmc->dev, "vmmc-supply",
237906ec045fSJean-Jacques Hiblot 					  &mmc->vmmc_supply);
238006ec045fSJean-Jacques Hiblot 	if (ret)
2381288db7c7SJaehoon Chung 		debug("%s: No vmmc supply\n", mmc->dev->name);
23822051aefeSPeng Fan 
238306ec045fSJean-Jacques Hiblot 	ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply",
238406ec045fSJean-Jacques Hiblot 					  &mmc->vqmmc_supply);
238506ec045fSJean-Jacques Hiblot 	if (ret)
238606ec045fSJean-Jacques Hiblot 		debug("%s: No vqmmc supply\n", mmc->dev->name);
23872051aefeSPeng Fan #endif
238805cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */
238905cbeb7cSSimon Glass 	/*
239005cbeb7cSSimon Glass 	 * Driver model should use a regulator, as above, rather than calling
239105cbeb7cSSimon Glass 	 * out to board code.
239205cbeb7cSSimon Glass 	 */
239305cbeb7cSSimon Glass 	board_mmc_power_init();
239405cbeb7cSSimon Glass #endif
23952051aefeSPeng Fan 	return 0;
23962051aefeSPeng Fan }
23972051aefeSPeng Fan 
2398fb7c3bebSKishon Vijay Abraham I /*
2399fb7c3bebSKishon Vijay Abraham I  * put the host in the initial state:
2400fb7c3bebSKishon Vijay Abraham I  * - turn on Vdd (card power supply)
2401fb7c3bebSKishon Vijay Abraham I  * - configure the bus width and clock to minimal values
2402fb7c3bebSKishon Vijay Abraham I  */
2403fb7c3bebSKishon Vijay Abraham I static void mmc_set_initial_state(struct mmc *mmc)
2404fb7c3bebSKishon Vijay Abraham I {
2405fb7c3bebSKishon Vijay Abraham I 	int err;
2406fb7c3bebSKishon Vijay Abraham I 
2407fb7c3bebSKishon Vijay Abraham I 	/* First try to set 3.3V. If it fails set to 1.8V */
2408fb7c3bebSKishon Vijay Abraham I 	err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_330);
2409fb7c3bebSKishon Vijay Abraham I 	if (err != 0)
2410fb7c3bebSKishon Vijay Abraham I 		err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_180);
2411fb7c3bebSKishon Vijay Abraham I 	if (err != 0)
2412d8e3d420SJean-Jacques Hiblot 		pr_warn("mmc: failed to set signal voltage\n");
2413fb7c3bebSKishon Vijay Abraham I 
2414fb7c3bebSKishon Vijay Abraham I 	mmc_select_mode(mmc, MMC_LEGACY);
2415fb7c3bebSKishon Vijay Abraham I 	mmc_set_bus_width(mmc, 1);
241635f67820SKishon Vijay Abraham I 	mmc_set_clock(mmc, 0, false);
2417fb7c3bebSKishon Vijay Abraham I }
2418fb7c3bebSKishon Vijay Abraham I 
2419fb7c3bebSKishon Vijay Abraham I static int mmc_power_on(struct mmc *mmc)
2420fb7c3bebSKishon Vijay Abraham I {
2421fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR)
2422fb7c3bebSKishon Vijay Abraham I 	if (mmc->vmmc_supply) {
2423fb7c3bebSKishon Vijay Abraham I 		int ret = regulator_set_enable(mmc->vmmc_supply, true);
2424fb7c3bebSKishon Vijay Abraham I 
2425fb7c3bebSKishon Vijay Abraham I 		if (ret) {
2426fb7c3bebSKishon Vijay Abraham I 			puts("Error enabling VMMC supply\n");
2427fb7c3bebSKishon Vijay Abraham I 			return ret;
2428fb7c3bebSKishon Vijay Abraham I 		}
2429fb7c3bebSKishon Vijay Abraham I 	}
2430fb7c3bebSKishon Vijay Abraham I #endif
2431fb7c3bebSKishon Vijay Abraham I 	return 0;
2432fb7c3bebSKishon Vijay Abraham I }
2433fb7c3bebSKishon Vijay Abraham I 
2434fb7c3bebSKishon Vijay Abraham I static int mmc_power_off(struct mmc *mmc)
2435fb7c3bebSKishon Vijay Abraham I {
24362e7410d7SKishon Vijay Abraham I 	mmc_set_clock(mmc, 1, true);
2437fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR)
2438fb7c3bebSKishon Vijay Abraham I 	if (mmc->vmmc_supply) {
2439fb7c3bebSKishon Vijay Abraham I 		int ret = regulator_set_enable(mmc->vmmc_supply, false);
2440fb7c3bebSKishon Vijay Abraham I 
2441fb7c3bebSKishon Vijay Abraham I 		if (ret) {
2442c10b85d6SJean-Jacques Hiblot 			debug("Error disabling VMMC supply\n");
2443fb7c3bebSKishon Vijay Abraham I 			return ret;
2444fb7c3bebSKishon Vijay Abraham I 		}
2445fb7c3bebSKishon Vijay Abraham I 	}
2446fb7c3bebSKishon Vijay Abraham I #endif
2447fb7c3bebSKishon Vijay Abraham I 	return 0;
2448fb7c3bebSKishon Vijay Abraham I }
2449fb7c3bebSKishon Vijay Abraham I 
2450fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc)
2451fb7c3bebSKishon Vijay Abraham I {
2452fb7c3bebSKishon Vijay Abraham I 	int ret;
2453fb7c3bebSKishon Vijay Abraham I 
2454fb7c3bebSKishon Vijay Abraham I 	ret = mmc_power_off(mmc);
2455fb7c3bebSKishon Vijay Abraham I 	if (ret)
2456fb7c3bebSKishon Vijay Abraham I 		return ret;
2457fb7c3bebSKishon Vijay Abraham I 	/*
2458fb7c3bebSKishon Vijay Abraham I 	 * SD spec recommends at least 1ms of delay. Let's wait for 2ms
2459fb7c3bebSKishon Vijay Abraham I 	 * to be on the safer side.
2460fb7c3bebSKishon Vijay Abraham I 	 */
2461fb7c3bebSKishon Vijay Abraham I 	udelay(2000);
2462fb7c3bebSKishon Vijay Abraham I 	return mmc_power_on(mmc);
2463fb7c3bebSKishon Vijay Abraham I }
2464fb7c3bebSKishon Vijay Abraham I 
2465e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc)
2466272cc70bSAndy Fleming {
24678ca51e51SSimon Glass 	bool no_card;
2468c10b85d6SJean-Jacques Hiblot 	bool uhs_en = supports_uhs(mmc->cfg->host_caps);
2469afd5932bSMacpaul Lin 	int err;
2470272cc70bSAndy Fleming 
24711da8eb59SJean-Jacques Hiblot 	/*
24721da8eb59SJean-Jacques Hiblot 	 * all hosts are capable of 1 bit bus-width and able to use the legacy
24731da8eb59SJean-Jacques Hiblot 	 * timings.
24741da8eb59SJean-Jacques Hiblot 	 */
24751da8eb59SJean-Jacques Hiblot 	mmc->host_caps = mmc->cfg->host_caps | MMC_CAP(SD_LEGACY) |
24761da8eb59SJean-Jacques Hiblot 			 MMC_CAP(MMC_LEGACY) | MMC_MODE_1BIT;
247704a2ea24SJean-Jacques Hiblot 
2478ab769f22SPantelis Antoniou 	/* we pretend there's no card when init is NULL */
24798ca51e51SSimon Glass 	no_card = mmc_getcd(mmc) == 0;
2480e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
24818ca51e51SSimon Glass 	no_card = no_card || (mmc->cfg->ops->init == NULL);
24828ca51e51SSimon Glass #endif
24838ca51e51SSimon Glass 	if (no_card) {
248448972d90SThierry Reding 		mmc->has_init = 0;
248556196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
248648972d90SThierry Reding 		printf("MMC: no card present\n");
248756196826SPaul Burton #endif
2488915ffa52SJaehoon Chung 		return -ENOMEDIUM;
248948972d90SThierry Reding 	}
249048972d90SThierry Reding 
2491bc897b1dSLei Wen 	if (mmc->has_init)
2492bc897b1dSLei Wen 		return 0;
2493bc897b1dSLei Wen 
24945a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
24955a8dbdc6SYangbo Lu 	mmc_adapter_card_type_ident();
24965a8dbdc6SYangbo Lu #endif
24972051aefeSPeng Fan 	err = mmc_power_init(mmc);
24982051aefeSPeng Fan 	if (err)
24992051aefeSPeng Fan 		return err;
250095de9ab2SPaul Kocialkowski 
250183dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS
250283dc4227SKishon Vijay Abraham I 	mmc->quirks = MMC_QUIRK_RETRY_SET_BLOCKLEN |
250383dc4227SKishon Vijay Abraham I 		      MMC_QUIRK_RETRY_SEND_CID;
250483dc4227SKishon Vijay Abraham I #endif
250583dc4227SKishon Vijay Abraham I 
250604a2ea24SJean-Jacques Hiblot 	err = mmc_power_cycle(mmc);
250704a2ea24SJean-Jacques Hiblot 	if (err) {
250804a2ea24SJean-Jacques Hiblot 		/*
250904a2ea24SJean-Jacques Hiblot 		 * if power cycling is not supported, we should not try
251004a2ea24SJean-Jacques Hiblot 		 * to use the UHS modes, because we wouldn't be able to
251104a2ea24SJean-Jacques Hiblot 		 * recover from an error during the UHS initialization.
251204a2ea24SJean-Jacques Hiblot 		 */
251304a2ea24SJean-Jacques Hiblot 		debug("Unable to do a full power cycle. Disabling the UHS modes for safety\n");
251404a2ea24SJean-Jacques Hiblot 		uhs_en = false;
251504a2ea24SJean-Jacques Hiblot 		mmc->host_caps &= ~UHS_CAPS;
2516fb7c3bebSKishon Vijay Abraham I 		err = mmc_power_on(mmc);
251704a2ea24SJean-Jacques Hiblot 	}
2518fb7c3bebSKishon Vijay Abraham I 	if (err)
2519fb7c3bebSKishon Vijay Abraham I 		return err;
2520fb7c3bebSKishon Vijay Abraham I 
2521e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
25228ca51e51SSimon Glass 	/* The device has already been probed ready for use */
25238ca51e51SSimon Glass #else
2524ab769f22SPantelis Antoniou 	/* made sure it's not NULL earlier */
252593bfd616SPantelis Antoniou 	err = mmc->cfg->ops->init(mmc);
2526272cc70bSAndy Fleming 	if (err)
2527272cc70bSAndy Fleming 		return err;
25288ca51e51SSimon Glass #endif
2529786e8f81SAndrew Gabbasov 	mmc->ddr_mode = 0;
2530aff5d3c8SKishon Vijay Abraham I 
2531c10b85d6SJean-Jacques Hiblot retry:
2532fb7c3bebSKishon Vijay Abraham I 	mmc_set_initial_state(mmc);
2533318a7a57SJean-Jacques Hiblot 	mmc_send_init_stream(mmc);
2534318a7a57SJean-Jacques Hiblot 
2535272cc70bSAndy Fleming 	/* Reset the Card */
2536272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
2537272cc70bSAndy Fleming 
2538272cc70bSAndy Fleming 	if (err)
2539272cc70bSAndy Fleming 		return err;
2540272cc70bSAndy Fleming 
2541bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
2542c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->hwpart = 0;
2543bc897b1dSLei Wen 
2544272cc70bSAndy Fleming 	/* Test for SD version 2 */
2545272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
2546272cc70bSAndy Fleming 
2547272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
2548c10b85d6SJean-Jacques Hiblot 	err = sd_send_op_cond(mmc, uhs_en);
2549c10b85d6SJean-Jacques Hiblot 	if (err && uhs_en) {
2550c10b85d6SJean-Jacques Hiblot 		uhs_en = false;
2551c10b85d6SJean-Jacques Hiblot 		mmc_power_cycle(mmc);
2552c10b85d6SJean-Jacques Hiblot 		goto retry;
2553c10b85d6SJean-Jacques Hiblot 	}
2554272cc70bSAndy Fleming 
2555272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
2556915ffa52SJaehoon Chung 	if (err == -ETIMEDOUT) {
2557272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
2558272cc70bSAndy Fleming 
2559bd47c135SAndrew Gabbasov 		if (err) {
256056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2561d8e3d420SJean-Jacques Hiblot 			pr_err("Card did not respond to voltage select!\n");
256256196826SPaul Burton #endif
2563915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
2564272cc70bSAndy Fleming 		}
2565272cc70bSAndy Fleming 	}
2566272cc70bSAndy Fleming 
2567bd47c135SAndrew Gabbasov 	if (!err)
2568e9550449SChe-Liang Chiou 		mmc->init_in_progress = 1;
2569e9550449SChe-Liang Chiou 
2570e9550449SChe-Liang Chiou 	return err;
2571e9550449SChe-Liang Chiou }
2572e9550449SChe-Liang Chiou 
2573e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc)
2574e9550449SChe-Liang Chiou {
2575e9550449SChe-Liang Chiou 	int err = 0;
2576e9550449SChe-Liang Chiou 
2577bd47c135SAndrew Gabbasov 	mmc->init_in_progress = 0;
2578e9550449SChe-Liang Chiou 	if (mmc->op_cond_pending)
2579e9550449SChe-Liang Chiou 		err = mmc_complete_op_cond(mmc);
2580e9550449SChe-Liang Chiou 
2581e9550449SChe-Liang Chiou 	if (!err)
2582bc897b1dSLei Wen 		err = mmc_startup(mmc);
2583bc897b1dSLei Wen 	if (err)
2584bc897b1dSLei Wen 		mmc->has_init = 0;
2585bc897b1dSLei Wen 	else
2586bc897b1dSLei Wen 		mmc->has_init = 1;
2587e9550449SChe-Liang Chiou 	return err;
2588e9550449SChe-Liang Chiou }
2589e9550449SChe-Liang Chiou 
2590e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc)
2591e9550449SChe-Liang Chiou {
2592bd47c135SAndrew Gabbasov 	int err = 0;
2593ce9eca94SMarek Vasut 	__maybe_unused unsigned start;
2594c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
259533fb211dSSimon Glass 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev);
2596e9550449SChe-Liang Chiou 
259733fb211dSSimon Glass 	upriv->mmc = mmc;
259833fb211dSSimon Glass #endif
2599e9550449SChe-Liang Chiou 	if (mmc->has_init)
2600e9550449SChe-Liang Chiou 		return 0;
2601d803fea5SMateusz Zalega 
2602d803fea5SMateusz Zalega 	start = get_timer(0);
2603d803fea5SMateusz Zalega 
2604e9550449SChe-Liang Chiou 	if (!mmc->init_in_progress)
2605e9550449SChe-Liang Chiou 		err = mmc_start_init(mmc);
2606e9550449SChe-Liang Chiou 
2607bd47c135SAndrew Gabbasov 	if (!err)
2608e9550449SChe-Liang Chiou 		err = mmc_complete_init(mmc);
2609919b4858SJagan Teki 	if (err)
2610919b4858SJagan Teki 		printf("%s: %d, time %lu\n", __func__, err, get_timer(start));
2611919b4858SJagan Teki 
2612bc897b1dSLei Wen 	return err;
2613272cc70bSAndy Fleming }
2614272cc70bSAndy Fleming 
2615ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val)
2616ab71188cSMarkus Niebel {
2617ab71188cSMarkus Niebel 	mmc->dsr = val;
2618ab71188cSMarkus Niebel 	return 0;
2619ab71188cSMarkus Niebel }
2620ab71188cSMarkus Niebel 
2621cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */
2622cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis)
2623272cc70bSAndy Fleming {
2624272cc70bSAndy Fleming 	return -1;
2625272cc70bSAndy Fleming }
2626272cc70bSAndy Fleming 
2627cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */
2628cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis)
2629cee9ab7cSJeroen Hofstee {
2630cee9ab7cSJeroen Hofstee 	return -1;
2631cee9ab7cSJeroen Hofstee }
2632272cc70bSAndy Fleming 
2633e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit)
2634e9550449SChe-Liang Chiou {
2635e9550449SChe-Liang Chiou 	mmc->preinit = preinit;
2636e9550449SChe-Liang Chiou }
2637e9550449SChe-Liang Chiou 
2638c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD)
26398e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
26408e3332e2SSjoerd Simons {
26418e3332e2SSjoerd Simons 	return 0;
26428e3332e2SSjoerd Simons }
2643c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC)
26448e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
26458e3332e2SSjoerd Simons {
26464a1db6d8SSimon Glass 	int ret, i;
26478e3332e2SSjoerd Simons 	struct uclass *uc;
26484a1db6d8SSimon Glass 	struct udevice *dev;
26498e3332e2SSjoerd Simons 
26508e3332e2SSjoerd Simons 	ret = uclass_get(UCLASS_MMC, &uc);
26518e3332e2SSjoerd Simons 	if (ret)
26528e3332e2SSjoerd Simons 		return ret;
26538e3332e2SSjoerd Simons 
26544a1db6d8SSimon Glass 	/*
26554a1db6d8SSimon Glass 	 * Try to add them in sequence order. Really with driver model we
26564a1db6d8SSimon Glass 	 * should allow holes, but the current MMC list does not allow that.
26574a1db6d8SSimon Glass 	 * So if we request 0, 1, 3 we will get 0, 1, 2.
26584a1db6d8SSimon Glass 	 */
26594a1db6d8SSimon Glass 	for (i = 0; ; i++) {
26604a1db6d8SSimon Glass 		ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev);
26614a1db6d8SSimon Glass 		if (ret == -ENODEV)
26624a1db6d8SSimon Glass 			break;
26634a1db6d8SSimon Glass 	}
26644a1db6d8SSimon Glass 	uclass_foreach_dev(dev, uc) {
26654a1db6d8SSimon Glass 		ret = device_probe(dev);
26668e3332e2SSjoerd Simons 		if (ret)
2667d8e3d420SJean-Jacques Hiblot 			pr_err("%s - probe failed: %d\n", dev->name, ret);
26688e3332e2SSjoerd Simons 	}
26698e3332e2SSjoerd Simons 
26708e3332e2SSjoerd Simons 	return 0;
26718e3332e2SSjoerd Simons }
26728e3332e2SSjoerd Simons #else
26738e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
26748e3332e2SSjoerd Simons {
26758e3332e2SSjoerd Simons 	if (board_mmc_init(bis) < 0)
26768e3332e2SSjoerd Simons 		cpu_mmc_init(bis);
26778e3332e2SSjoerd Simons 
26788e3332e2SSjoerd Simons 	return 0;
26798e3332e2SSjoerd Simons }
26808e3332e2SSjoerd Simons #endif
2681e9550449SChe-Liang Chiou 
2682272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
2683272cc70bSAndy Fleming {
26841b26bab1SDaniel Kochmański 	static int initialized = 0;
26858e3332e2SSjoerd Simons 	int ret;
26861b26bab1SDaniel Kochmański 	if (initialized)	/* Avoid initializing mmc multiple times */
26871b26bab1SDaniel Kochmański 		return 0;
26881b26bab1SDaniel Kochmański 	initialized = 1;
26891b26bab1SDaniel Kochmański 
2690c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK)
2691b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY)
2692c40fdca6SSimon Glass 	mmc_list_init();
2693c40fdca6SSimon Glass #endif
2694b5b838f1SMarek Vasut #endif
26958e3332e2SSjoerd Simons 	ret = mmc_probe(bis);
26968e3332e2SSjoerd Simons 	if (ret)
26978e3332e2SSjoerd Simons 		return ret;
2698272cc70bSAndy Fleming 
2699bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD
2700272cc70bSAndy Fleming 	print_mmc_devices(',');
2701bb0dc108SYing Zhang #endif
2702272cc70bSAndy Fleming 
2703c40fdca6SSimon Glass 	mmc_do_preinit();
2704272cc70bSAndy Fleming 	return 0;
2705272cc70bSAndy Fleming }
2706cd3d4880STomas Melin 
2707cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE
2708cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc)
2709cd3d4880STomas Melin {
2710cd3d4880STomas Melin 	int err;
2711cd3d4880STomas Melin 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
2712cd3d4880STomas Melin 
2713cd3d4880STomas Melin 	err = mmc_send_ext_csd(mmc, ext_csd);
2714cd3d4880STomas Melin 	if (err) {
2715cd3d4880STomas Melin 		puts("Could not get ext_csd register values\n");
2716cd3d4880STomas Melin 		return err;
2717cd3d4880STomas Melin 	}
2718cd3d4880STomas Melin 
2719cd3d4880STomas Melin 	if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) {
2720cd3d4880STomas Melin 		puts("Background operations not supported on device\n");
2721cd3d4880STomas Melin 		return -EMEDIUMTYPE;
2722cd3d4880STomas Melin 	}
2723cd3d4880STomas Melin 
2724cd3d4880STomas Melin 	if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) {
2725cd3d4880STomas Melin 		puts("Background operations already enabled\n");
2726cd3d4880STomas Melin 		return 0;
2727cd3d4880STomas Melin 	}
2728cd3d4880STomas Melin 
2729cd3d4880STomas Melin 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1);
2730cd3d4880STomas Melin 	if (err) {
2731cd3d4880STomas Melin 		puts("Failed to enable manual background operations\n");
2732cd3d4880STomas Melin 		return err;
2733cd3d4880STomas Melin 	}
2734cd3d4880STomas Melin 
2735cd3d4880STomas Melin 	puts("Enabled manual background operations\n");
2736cd3d4880STomas Melin 
2737cd3d4880STomas Melin 	return 0;
2738cd3d4880STomas Melin }
2739cd3d4880STomas Melin #endif
2740