xref: /openbmc/u-boot/drivers/mmc/mmc.c (revision 83d290c5)
1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2272cc70bSAndy Fleming /*
3272cc70bSAndy Fleming  * Copyright 2008, Freescale Semiconductor, Inc
4272cc70bSAndy Fleming  * Andy Fleming
5272cc70bSAndy Fleming  *
6272cc70bSAndy Fleming  * Based vaguely on the Linux code
7272cc70bSAndy Fleming  */
8272cc70bSAndy Fleming 
9272cc70bSAndy Fleming #include <config.h>
10272cc70bSAndy Fleming #include <common.h>
11272cc70bSAndy Fleming #include <command.h>
128e3332e2SSjoerd Simons #include <dm.h>
138e3332e2SSjoerd Simons #include <dm/device-internal.h>
14d4622df3SStephen Warren #include <errno.h>
15272cc70bSAndy Fleming #include <mmc.h>
16272cc70bSAndy Fleming #include <part.h>
172051aefeSPeng Fan #include <power/regulator.h>
18272cc70bSAndy Fleming #include <malloc.h>
19cf92e05cSSimon Glass #include <memalign.h>
20272cc70bSAndy Fleming #include <linux/list.h>
219b1f942cSRabin Vincent #include <div64.h>
22da61fa5fSPaul Burton #include "mmc_private.h"
23272cc70bSAndy Fleming 
24aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage);
25fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc);
2601298da3SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps);
27aff5d3c8SKishon Vijay Abraham I 
28b5b838f1SMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY)
29b5b838f1SMarek Vasut static struct mmc mmc_static;
30b5b838f1SMarek Vasut struct mmc *find_mmc_device(int dev_num)
31b5b838f1SMarek Vasut {
32b5b838f1SMarek Vasut 	return &mmc_static;
33b5b838f1SMarek Vasut }
34b5b838f1SMarek Vasut 
35b5b838f1SMarek Vasut void mmc_do_preinit(void)
36b5b838f1SMarek Vasut {
37b5b838f1SMarek Vasut 	struct mmc *m = &mmc_static;
38b5b838f1SMarek Vasut #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
39b5b838f1SMarek Vasut 	mmc_set_preinit(m, 1);
40b5b838f1SMarek Vasut #endif
41b5b838f1SMarek Vasut 	if (m->preinit)
42b5b838f1SMarek Vasut 		mmc_start_init(m);
43b5b838f1SMarek Vasut }
44b5b838f1SMarek Vasut 
45b5b838f1SMarek Vasut struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
46b5b838f1SMarek Vasut {
47b5b838f1SMarek Vasut 	return &mmc->block_dev;
48b5b838f1SMarek Vasut }
49b5b838f1SMarek Vasut #endif
50b5b838f1SMarek Vasut 
51e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
52c10b85d6SJean-Jacques Hiblot 
53f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
54c10b85d6SJean-Jacques Hiblot static int mmc_wait_dat0(struct mmc *mmc, int state, int timeout)
55c10b85d6SJean-Jacques Hiblot {
56c10b85d6SJean-Jacques Hiblot 	return -ENOSYS;
57c10b85d6SJean-Jacques Hiblot }
58f99c2efeSJean-Jacques Hiblot #endif
59c10b85d6SJean-Jacques Hiblot 
60750121c3SJeroen Hofstee __weak int board_mmc_getwp(struct mmc *mmc)
61d23d8d7eSNikita Kiryanov {
62d23d8d7eSNikita Kiryanov 	return -1;
63d23d8d7eSNikita Kiryanov }
64d23d8d7eSNikita Kiryanov 
65d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc)
66d23d8d7eSNikita Kiryanov {
67d23d8d7eSNikita Kiryanov 	int wp;
68d23d8d7eSNikita Kiryanov 
69d23d8d7eSNikita Kiryanov 	wp = board_mmc_getwp(mmc);
70d23d8d7eSNikita Kiryanov 
71d4e1da4eSPeter Korsgaard 	if (wp < 0) {
7293bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getwp)
7393bfd616SPantelis Antoniou 			wp = mmc->cfg->ops->getwp(mmc);
74d4e1da4eSPeter Korsgaard 		else
75d4e1da4eSPeter Korsgaard 			wp = 0;
76d4e1da4eSPeter Korsgaard 	}
77d23d8d7eSNikita Kiryanov 
78d23d8d7eSNikita Kiryanov 	return wp;
79d23d8d7eSNikita Kiryanov }
80d23d8d7eSNikita Kiryanov 
81cee9ab7cSJeroen Hofstee __weak int board_mmc_getcd(struct mmc *mmc)
82cee9ab7cSJeroen Hofstee {
8311fdade2SStefano Babic 	return -1;
8411fdade2SStefano Babic }
858ca51e51SSimon Glass #endif
8611fdade2SStefano Babic 
878635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE
88c0c76ebaSSimon Glass void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd)
89c0c76ebaSSimon Glass {
90c0c76ebaSSimon Glass 	printf("CMD_SEND:%d\n", cmd->cmdidx);
91c0c76ebaSSimon Glass 	printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg);
92c0c76ebaSSimon Glass }
93c0c76ebaSSimon Glass 
94c0c76ebaSSimon Glass void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret)
95c0c76ebaSSimon Glass {
965db2fe3aSRaffaele Recalcati 	int i;
975db2fe3aSRaffaele Recalcati 	u8 *ptr;
985db2fe3aSRaffaele Recalcati 
997863ce58SBin Meng 	if (ret) {
1007863ce58SBin Meng 		printf("\t\tRET\t\t\t %d\n", ret);
1017863ce58SBin Meng 	} else {
1025db2fe3aSRaffaele Recalcati 		switch (cmd->resp_type) {
1035db2fe3aSRaffaele Recalcati 		case MMC_RSP_NONE:
1045db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_NONE\n");
1055db2fe3aSRaffaele Recalcati 			break;
1065db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1:
1075db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n",
1085db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1095db2fe3aSRaffaele Recalcati 			break;
1105db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1b:
1115db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n",
1125db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1135db2fe3aSRaffaele Recalcati 			break;
1145db2fe3aSRaffaele Recalcati 		case MMC_RSP_R2:
1155db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R2\t\t 0x%08X \n",
1165db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1175db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1185db2fe3aSRaffaele Recalcati 				cmd->response[1]);
1195db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1205db2fe3aSRaffaele Recalcati 				cmd->response[2]);
1215db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1225db2fe3aSRaffaele Recalcati 				cmd->response[3]);
1235db2fe3aSRaffaele Recalcati 			printf("\n");
1245db2fe3aSRaffaele Recalcati 			printf("\t\t\t\t\tDUMPING DATA\n");
1255db2fe3aSRaffaele Recalcati 			for (i = 0; i < 4; i++) {
1265db2fe3aSRaffaele Recalcati 				int j;
1275db2fe3aSRaffaele Recalcati 				printf("\t\t\t\t\t%03d - ", i*4);
128146bec79SDirk Behme 				ptr = (u8 *)&cmd->response[i];
1295db2fe3aSRaffaele Recalcati 				ptr += 3;
1305db2fe3aSRaffaele Recalcati 				for (j = 0; j < 4; j++)
1315db2fe3aSRaffaele Recalcati 					printf("%02X ", *ptr--);
1325db2fe3aSRaffaele Recalcati 				printf("\n");
1335db2fe3aSRaffaele Recalcati 			}
1345db2fe3aSRaffaele Recalcati 			break;
1355db2fe3aSRaffaele Recalcati 		case MMC_RSP_R3:
1365db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n",
1375db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1385db2fe3aSRaffaele Recalcati 			break;
1395db2fe3aSRaffaele Recalcati 		default:
1405db2fe3aSRaffaele Recalcati 			printf("\t\tERROR MMC rsp not supported\n");
1415db2fe3aSRaffaele Recalcati 			break;
1425db2fe3aSRaffaele Recalcati 		}
1437863ce58SBin Meng 	}
144c0c76ebaSSimon Glass }
145c0c76ebaSSimon Glass 
146c0c76ebaSSimon Glass void mmc_trace_state(struct mmc *mmc, struct mmc_cmd *cmd)
147c0c76ebaSSimon Glass {
148c0c76ebaSSimon Glass 	int status;
149c0c76ebaSSimon Glass 
150c0c76ebaSSimon Glass 	status = (cmd->response[0] & MMC_STATUS_CURR_STATE) >> 9;
151c0c76ebaSSimon Glass 	printf("CURR STATE:%d\n", status);
152c0c76ebaSSimon Glass }
1535db2fe3aSRaffaele Recalcati #endif
154c0c76ebaSSimon Glass 
15535f9e196SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG)
15635f9e196SJean-Jacques Hiblot const char *mmc_mode_name(enum bus_mode mode)
15735f9e196SJean-Jacques Hiblot {
15835f9e196SJean-Jacques Hiblot 	static const char *const names[] = {
15935f9e196SJean-Jacques Hiblot 	      [MMC_LEGACY]	= "MMC legacy",
16035f9e196SJean-Jacques Hiblot 	      [SD_LEGACY]	= "SD Legacy",
16135f9e196SJean-Jacques Hiblot 	      [MMC_HS]		= "MMC High Speed (26MHz)",
16235f9e196SJean-Jacques Hiblot 	      [SD_HS]		= "SD High Speed (50MHz)",
16335f9e196SJean-Jacques Hiblot 	      [UHS_SDR12]	= "UHS SDR12 (25MHz)",
16435f9e196SJean-Jacques Hiblot 	      [UHS_SDR25]	= "UHS SDR25 (50MHz)",
16535f9e196SJean-Jacques Hiblot 	      [UHS_SDR50]	= "UHS SDR50 (100MHz)",
16635f9e196SJean-Jacques Hiblot 	      [UHS_SDR104]	= "UHS SDR104 (208MHz)",
16735f9e196SJean-Jacques Hiblot 	      [UHS_DDR50]	= "UHS DDR50 (50MHz)",
16835f9e196SJean-Jacques Hiblot 	      [MMC_HS_52]	= "MMC High Speed (52MHz)",
16935f9e196SJean-Jacques Hiblot 	      [MMC_DDR_52]	= "MMC DDR52 (52MHz)",
17035f9e196SJean-Jacques Hiblot 	      [MMC_HS_200]	= "HS200 (200MHz)",
17135f9e196SJean-Jacques Hiblot 	};
17235f9e196SJean-Jacques Hiblot 
17335f9e196SJean-Jacques Hiblot 	if (mode >= MMC_MODES_END)
17435f9e196SJean-Jacques Hiblot 		return "Unknown mode";
17535f9e196SJean-Jacques Hiblot 	else
17635f9e196SJean-Jacques Hiblot 		return names[mode];
17735f9e196SJean-Jacques Hiblot }
17835f9e196SJean-Jacques Hiblot #endif
17935f9e196SJean-Jacques Hiblot 
18005038576SJean-Jacques Hiblot static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode)
18105038576SJean-Jacques Hiblot {
18205038576SJean-Jacques Hiblot 	static const int freqs[] = {
1831b313aa3SJaehoon Chung 	      [MMC_LEGACY]	= 25000000,
18405038576SJean-Jacques Hiblot 	      [SD_LEGACY]	= 25000000,
18505038576SJean-Jacques Hiblot 	      [MMC_HS]		= 26000000,
18605038576SJean-Jacques Hiblot 	      [SD_HS]		= 50000000,
1871b313aa3SJaehoon Chung 	      [MMC_HS_52]	= 52000000,
1881b313aa3SJaehoon Chung 	      [MMC_DDR_52]	= 52000000,
18905038576SJean-Jacques Hiblot 	      [UHS_SDR12]	= 25000000,
19005038576SJean-Jacques Hiblot 	      [UHS_SDR25]	= 50000000,
19105038576SJean-Jacques Hiblot 	      [UHS_SDR50]	= 100000000,
19205038576SJean-Jacques Hiblot 	      [UHS_DDR50]	= 50000000,
193f99c2efeSJean-Jacques Hiblot 	      [UHS_SDR104]	= 208000000,
19405038576SJean-Jacques Hiblot 	      [MMC_HS_200]	= 200000000,
19505038576SJean-Jacques Hiblot 	};
19605038576SJean-Jacques Hiblot 
19705038576SJean-Jacques Hiblot 	if (mode == MMC_LEGACY)
19805038576SJean-Jacques Hiblot 		return mmc->legacy_speed;
19905038576SJean-Jacques Hiblot 	else if (mode >= MMC_MODES_END)
20005038576SJean-Jacques Hiblot 		return 0;
20105038576SJean-Jacques Hiblot 	else
20205038576SJean-Jacques Hiblot 		return freqs[mode];
20305038576SJean-Jacques Hiblot }
20405038576SJean-Jacques Hiblot 
20535f9e196SJean-Jacques Hiblot static int mmc_select_mode(struct mmc *mmc, enum bus_mode mode)
20635f9e196SJean-Jacques Hiblot {
20735f9e196SJean-Jacques Hiblot 	mmc->selected_mode = mode;
20805038576SJean-Jacques Hiblot 	mmc->tran_speed = mmc_mode2freq(mmc, mode);
2093862b854SJean-Jacques Hiblot 	mmc->ddr_mode = mmc_is_mode_ddr(mode);
210d4d64889SMasahiro Yamada 	pr_debug("selecting mode %s (freq : %d MHz)\n", mmc_mode_name(mode),
21135f9e196SJean-Jacques Hiblot 		 mmc->tran_speed / 1000000);
21235f9e196SJean-Jacques Hiblot 	return 0;
21335f9e196SJean-Jacques Hiblot }
21435f9e196SJean-Jacques Hiblot 
215e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
216c0c76ebaSSimon Glass int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
217c0c76ebaSSimon Glass {
218c0c76ebaSSimon Glass 	int ret;
219c0c76ebaSSimon Glass 
220c0c76ebaSSimon Glass 	mmmc_trace_before_send(mmc, cmd);
221c0c76ebaSSimon Glass 	ret = mmc->cfg->ops->send_cmd(mmc, cmd, data);
222c0c76ebaSSimon Glass 	mmmc_trace_after_send(mmc, cmd, ret);
223c0c76ebaSSimon Glass 
2248635ff9eSMarek Vasut 	return ret;
225272cc70bSAndy Fleming }
2268ca51e51SSimon Glass #endif
227272cc70bSAndy Fleming 
228da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout)
2295d4fc8d9SRaffaele Recalcati {
2305d4fc8d9SRaffaele Recalcati 	struct mmc_cmd cmd;
231d617c426SJan Kloetzke 	int err, retries = 5;
2325d4fc8d9SRaffaele Recalcati 
2335d4fc8d9SRaffaele Recalcati 	cmd.cmdidx = MMC_CMD_SEND_STATUS;
2345d4fc8d9SRaffaele Recalcati 	cmd.resp_type = MMC_RSP_R1;
235aaf3d41aSMarek Vasut 	if (!mmc_host_is_spi(mmc))
236aaf3d41aSMarek Vasut 		cmd.cmdarg = mmc->rca << 16;
2375d4fc8d9SRaffaele Recalcati 
2381677eef4SAndrew Gabbasov 	while (1) {
2395d4fc8d9SRaffaele Recalcati 		err = mmc_send_cmd(mmc, &cmd, NULL);
240d617c426SJan Kloetzke 		if (!err) {
241d617c426SJan Kloetzke 			if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) &&
242d617c426SJan Kloetzke 			    (cmd.response[0] & MMC_STATUS_CURR_STATE) !=
243d617c426SJan Kloetzke 			     MMC_STATE_PRG)
2445d4fc8d9SRaffaele Recalcati 				break;
245d0c221feSJean-Jacques Hiblot 
246d0c221feSJean-Jacques Hiblot 			if (cmd.response[0] & MMC_STATUS_MASK) {
24756196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
248d8e3d420SJean-Jacques Hiblot 				pr_err("Status Error: 0x%08X\n",
249d617c426SJan Kloetzke 				       cmd.response[0]);
25056196826SPaul Burton #endif
251915ffa52SJaehoon Chung 				return -ECOMM;
252d617c426SJan Kloetzke 			}
253d617c426SJan Kloetzke 		} else if (--retries < 0)
254d617c426SJan Kloetzke 			return err;
2555d4fc8d9SRaffaele Recalcati 
2561677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
2571677eef4SAndrew Gabbasov 			break;
2585d4fc8d9SRaffaele Recalcati 
2591677eef4SAndrew Gabbasov 		udelay(1000);
2601677eef4SAndrew Gabbasov 	}
2615d4fc8d9SRaffaele Recalcati 
262c0c76ebaSSimon Glass 	mmc_trace_state(mmc, &cmd);
2635b0c942fSJongman Heo 	if (timeout <= 0) {
26456196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
265d8e3d420SJean-Jacques Hiblot 		pr_err("Timeout waiting card ready\n");
26656196826SPaul Burton #endif
267915ffa52SJaehoon Chung 		return -ETIMEDOUT;
2685d4fc8d9SRaffaele Recalcati 	}
2695d4fc8d9SRaffaele Recalcati 
2705d4fc8d9SRaffaele Recalcati 	return 0;
2715d4fc8d9SRaffaele Recalcati }
2725d4fc8d9SRaffaele Recalcati 
273da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len)
274272cc70bSAndy Fleming {
275272cc70bSAndy Fleming 	struct mmc_cmd cmd;
27683dc4227SKishon Vijay Abraham I 	int err;
277272cc70bSAndy Fleming 
278786e8f81SAndrew Gabbasov 	if (mmc->ddr_mode)
279d22e3d46SJaehoon Chung 		return 0;
280d22e3d46SJaehoon Chung 
281272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
282272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
283272cc70bSAndy Fleming 	cmd.cmdarg = len;
284272cc70bSAndy Fleming 
28583dc4227SKishon Vijay Abraham I 	err = mmc_send_cmd(mmc, &cmd, NULL);
28683dc4227SKishon Vijay Abraham I 
28783dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS
28883dc4227SKishon Vijay Abraham I 	if (err && (mmc->quirks & MMC_QUIRK_RETRY_SET_BLOCKLEN)) {
28983dc4227SKishon Vijay Abraham I 		int retries = 4;
29083dc4227SKishon Vijay Abraham I 		/*
29183dc4227SKishon Vijay Abraham I 		 * It has been seen that SET_BLOCKLEN may fail on the first
29283dc4227SKishon Vijay Abraham I 		 * attempt, let's try a few more time
29383dc4227SKishon Vijay Abraham I 		 */
29483dc4227SKishon Vijay Abraham I 		do {
29583dc4227SKishon Vijay Abraham I 			err = mmc_send_cmd(mmc, &cmd, NULL);
29683dc4227SKishon Vijay Abraham I 			if (!err)
29783dc4227SKishon Vijay Abraham I 				break;
29883dc4227SKishon Vijay Abraham I 		} while (retries--);
29983dc4227SKishon Vijay Abraham I 	}
30083dc4227SKishon Vijay Abraham I #endif
30183dc4227SKishon Vijay Abraham I 
30283dc4227SKishon Vijay Abraham I 	return err;
303272cc70bSAndy Fleming }
304272cc70bSAndy Fleming 
305f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
3069815e3baSJean-Jacques Hiblot static const u8 tuning_blk_pattern_4bit[] = {
3079815e3baSJean-Jacques Hiblot 	0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
3089815e3baSJean-Jacques Hiblot 	0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
3099815e3baSJean-Jacques Hiblot 	0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
3109815e3baSJean-Jacques Hiblot 	0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
3119815e3baSJean-Jacques Hiblot 	0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
3129815e3baSJean-Jacques Hiblot 	0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
3139815e3baSJean-Jacques Hiblot 	0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
3149815e3baSJean-Jacques Hiblot 	0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
3159815e3baSJean-Jacques Hiblot };
3169815e3baSJean-Jacques Hiblot 
3179815e3baSJean-Jacques Hiblot static const u8 tuning_blk_pattern_8bit[] = {
3189815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
3199815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
3209815e3baSJean-Jacques Hiblot 	0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
3219815e3baSJean-Jacques Hiblot 	0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
3229815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
3239815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
3249815e3baSJean-Jacques Hiblot 	0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
3259815e3baSJean-Jacques Hiblot 	0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
3269815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
3279815e3baSJean-Jacques Hiblot 	0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
3289815e3baSJean-Jacques Hiblot 	0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
3299815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
3309815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
3319815e3baSJean-Jacques Hiblot 	0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
3329815e3baSJean-Jacques Hiblot 	0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
3339815e3baSJean-Jacques Hiblot 	0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
3349815e3baSJean-Jacques Hiblot };
3359815e3baSJean-Jacques Hiblot 
3369815e3baSJean-Jacques Hiblot int mmc_send_tuning(struct mmc *mmc, u32 opcode, int *cmd_error)
3379815e3baSJean-Jacques Hiblot {
3389815e3baSJean-Jacques Hiblot 	struct mmc_cmd cmd;
3399815e3baSJean-Jacques Hiblot 	struct mmc_data data;
3409815e3baSJean-Jacques Hiblot 	const u8 *tuning_block_pattern;
3419815e3baSJean-Jacques Hiblot 	int size, err;
3429815e3baSJean-Jacques Hiblot 
3439815e3baSJean-Jacques Hiblot 	if (mmc->bus_width == 8) {
3449815e3baSJean-Jacques Hiblot 		tuning_block_pattern = tuning_blk_pattern_8bit;
3459815e3baSJean-Jacques Hiblot 		size = sizeof(tuning_blk_pattern_8bit);
3469815e3baSJean-Jacques Hiblot 	} else if (mmc->bus_width == 4) {
3479815e3baSJean-Jacques Hiblot 		tuning_block_pattern = tuning_blk_pattern_4bit;
3489815e3baSJean-Jacques Hiblot 		size = sizeof(tuning_blk_pattern_4bit);
3499815e3baSJean-Jacques Hiblot 	} else {
3509815e3baSJean-Jacques Hiblot 		return -EINVAL;
3519815e3baSJean-Jacques Hiblot 	}
3529815e3baSJean-Jacques Hiblot 
3539815e3baSJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, data_buf, size);
3549815e3baSJean-Jacques Hiblot 
3559815e3baSJean-Jacques Hiblot 	cmd.cmdidx = opcode;
3569815e3baSJean-Jacques Hiblot 	cmd.cmdarg = 0;
3579815e3baSJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
3589815e3baSJean-Jacques Hiblot 
3599815e3baSJean-Jacques Hiblot 	data.dest = (void *)data_buf;
3609815e3baSJean-Jacques Hiblot 	data.blocks = 1;
3619815e3baSJean-Jacques Hiblot 	data.blocksize = size;
3629815e3baSJean-Jacques Hiblot 	data.flags = MMC_DATA_READ;
3639815e3baSJean-Jacques Hiblot 
3649815e3baSJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, &data);
3659815e3baSJean-Jacques Hiblot 	if (err)
3669815e3baSJean-Jacques Hiblot 		return err;
3679815e3baSJean-Jacques Hiblot 
3689815e3baSJean-Jacques Hiblot 	if (memcmp(data_buf, tuning_block_pattern, size))
3699815e3baSJean-Jacques Hiblot 		return -EIO;
3709815e3baSJean-Jacques Hiblot 
3719815e3baSJean-Jacques Hiblot 	return 0;
3729815e3baSJean-Jacques Hiblot }
373f99c2efeSJean-Jacques Hiblot #endif
3749815e3baSJean-Jacques Hiblot 
375ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
376fdbb873eSKim Phillips 			   lbaint_t blkcnt)
377272cc70bSAndy Fleming {
378272cc70bSAndy Fleming 	struct mmc_cmd cmd;
379272cc70bSAndy Fleming 	struct mmc_data data;
380272cc70bSAndy Fleming 
3814a1a06bcSAlagu Sankar 	if (blkcnt > 1)
3824a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
3834a1a06bcSAlagu Sankar 	else
384272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
385272cc70bSAndy Fleming 
386272cc70bSAndy Fleming 	if (mmc->high_capacity)
3874a1a06bcSAlagu Sankar 		cmd.cmdarg = start;
388272cc70bSAndy Fleming 	else
3894a1a06bcSAlagu Sankar 		cmd.cmdarg = start * mmc->read_bl_len;
390272cc70bSAndy Fleming 
391272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
392272cc70bSAndy Fleming 
393272cc70bSAndy Fleming 	data.dest = dst;
3944a1a06bcSAlagu Sankar 	data.blocks = blkcnt;
395272cc70bSAndy Fleming 	data.blocksize = mmc->read_bl_len;
396272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
397272cc70bSAndy Fleming 
3984a1a06bcSAlagu Sankar 	if (mmc_send_cmd(mmc, &cmd, &data))
3994a1a06bcSAlagu Sankar 		return 0;
4004a1a06bcSAlagu Sankar 
4014a1a06bcSAlagu Sankar 	if (blkcnt > 1) {
4024a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
4034a1a06bcSAlagu Sankar 		cmd.cmdarg = 0;
4044a1a06bcSAlagu Sankar 		cmd.resp_type = MMC_RSP_R1b;
4054a1a06bcSAlagu Sankar 		if (mmc_send_cmd(mmc, &cmd, NULL)) {
40656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
407d8e3d420SJean-Jacques Hiblot 			pr_err("mmc fail to send stop cmd\n");
40856196826SPaul Burton #endif
4094a1a06bcSAlagu Sankar 			return 0;
4104a1a06bcSAlagu Sankar 		}
411272cc70bSAndy Fleming 	}
412272cc70bSAndy Fleming 
4134a1a06bcSAlagu Sankar 	return blkcnt;
414272cc70bSAndy Fleming }
415272cc70bSAndy Fleming 
416c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
4177dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst)
41833fb211dSSimon Glass #else
4197dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
4207dba0b93SSimon Glass 		void *dst)
42133fb211dSSimon Glass #endif
422272cc70bSAndy Fleming {
423c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
42433fb211dSSimon Glass 	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
42533fb211dSSimon Glass #endif
426bcce53d0SSimon Glass 	int dev_num = block_dev->devnum;
427873cc1d7SStephen Warren 	int err;
4284a1a06bcSAlagu Sankar 	lbaint_t cur, blocks_todo = blkcnt;
429272cc70bSAndy Fleming 
4304a1a06bcSAlagu Sankar 	if (blkcnt == 0)
4314a1a06bcSAlagu Sankar 		return 0;
4324a1a06bcSAlagu Sankar 
4334a1a06bcSAlagu Sankar 	struct mmc *mmc = find_mmc_device(dev_num);
434272cc70bSAndy Fleming 	if (!mmc)
435272cc70bSAndy Fleming 		return 0;
436272cc70bSAndy Fleming 
437b5b838f1SMarek Vasut 	if (CONFIG_IS_ENABLED(MMC_TINY))
438b5b838f1SMarek Vasut 		err = mmc_switch_part(mmc, block_dev->hwpart);
439b5b838f1SMarek Vasut 	else
44069f45cd5SSimon Glass 		err = blk_dselect_hwpart(block_dev, block_dev->hwpart);
441b5b838f1SMarek Vasut 
442873cc1d7SStephen Warren 	if (err < 0)
443873cc1d7SStephen Warren 		return 0;
444873cc1d7SStephen Warren 
445c40fdca6SSimon Glass 	if ((start + blkcnt) > block_dev->lba) {
44656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
447d8e3d420SJean-Jacques Hiblot 		pr_err("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
448c40fdca6SSimon Glass 		       start + blkcnt, block_dev->lba);
44956196826SPaul Burton #endif
450d2bf29e3SLei Wen 		return 0;
451d2bf29e3SLei Wen 	}
452272cc70bSAndy Fleming 
45311692991SSimon Glass 	if (mmc_set_blocklen(mmc, mmc->read_bl_len)) {
454d4d64889SMasahiro Yamada 		pr_debug("%s: Failed to set blocklen\n", __func__);
455272cc70bSAndy Fleming 		return 0;
45611692991SSimon Glass 	}
457272cc70bSAndy Fleming 
4584a1a06bcSAlagu Sankar 	do {
45993bfd616SPantelis Antoniou 		cur = (blocks_todo > mmc->cfg->b_max) ?
46093bfd616SPantelis Antoniou 			mmc->cfg->b_max : blocks_todo;
46111692991SSimon Glass 		if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
462d4d64889SMasahiro Yamada 			pr_debug("%s: Failed to read blocks\n", __func__);
4634a1a06bcSAlagu Sankar 			return 0;
46411692991SSimon Glass 		}
4654a1a06bcSAlagu Sankar 		blocks_todo -= cur;
4664a1a06bcSAlagu Sankar 		start += cur;
4674a1a06bcSAlagu Sankar 		dst += cur * mmc->read_bl_len;
4684a1a06bcSAlagu Sankar 	} while (blocks_todo > 0);
469272cc70bSAndy Fleming 
470272cc70bSAndy Fleming 	return blkcnt;
471272cc70bSAndy Fleming }
472272cc70bSAndy Fleming 
473fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc)
474272cc70bSAndy Fleming {
475272cc70bSAndy Fleming 	struct mmc_cmd cmd;
476272cc70bSAndy Fleming 	int err;
477272cc70bSAndy Fleming 
478272cc70bSAndy Fleming 	udelay(1000);
479272cc70bSAndy Fleming 
480272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
481272cc70bSAndy Fleming 	cmd.cmdarg = 0;
482272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_NONE;
483272cc70bSAndy Fleming 
484272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
485272cc70bSAndy Fleming 
486272cc70bSAndy Fleming 	if (err)
487272cc70bSAndy Fleming 		return err;
488272cc70bSAndy Fleming 
489272cc70bSAndy Fleming 	udelay(2000);
490272cc70bSAndy Fleming 
491272cc70bSAndy Fleming 	return 0;
492272cc70bSAndy Fleming }
493272cc70bSAndy Fleming 
494f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
495c10b85d6SJean-Jacques Hiblot static int mmc_switch_voltage(struct mmc *mmc, int signal_voltage)
496c10b85d6SJean-Jacques Hiblot {
497c10b85d6SJean-Jacques Hiblot 	struct mmc_cmd cmd;
498c10b85d6SJean-Jacques Hiblot 	int err = 0;
499c10b85d6SJean-Jacques Hiblot 
500c10b85d6SJean-Jacques Hiblot 	/*
501c10b85d6SJean-Jacques Hiblot 	 * Send CMD11 only if the request is to switch the card to
502c10b85d6SJean-Jacques Hiblot 	 * 1.8V signalling.
503c10b85d6SJean-Jacques Hiblot 	 */
504c10b85d6SJean-Jacques Hiblot 	if (signal_voltage == MMC_SIGNAL_VOLTAGE_330)
505c10b85d6SJean-Jacques Hiblot 		return mmc_set_signal_voltage(mmc, signal_voltage);
506c10b85d6SJean-Jacques Hiblot 
507c10b85d6SJean-Jacques Hiblot 	cmd.cmdidx = SD_CMD_SWITCH_UHS18V;
508c10b85d6SJean-Jacques Hiblot 	cmd.cmdarg = 0;
509c10b85d6SJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
510c10b85d6SJean-Jacques Hiblot 
511c10b85d6SJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
512c10b85d6SJean-Jacques Hiblot 	if (err)
513c10b85d6SJean-Jacques Hiblot 		return err;
514c10b85d6SJean-Jacques Hiblot 
515c10b85d6SJean-Jacques Hiblot 	if (!mmc_host_is_spi(mmc) && (cmd.response[0] & MMC_STATUS_ERROR))
516c10b85d6SJean-Jacques Hiblot 		return -EIO;
517c10b85d6SJean-Jacques Hiblot 
518c10b85d6SJean-Jacques Hiblot 	/*
519c10b85d6SJean-Jacques Hiblot 	 * The card should drive cmd and dat[0:3] low immediately
520c10b85d6SJean-Jacques Hiblot 	 * after the response of cmd11, but wait 100 us to be sure
521c10b85d6SJean-Jacques Hiblot 	 */
522c10b85d6SJean-Jacques Hiblot 	err = mmc_wait_dat0(mmc, 0, 100);
523c10b85d6SJean-Jacques Hiblot 	if (err == -ENOSYS)
524c10b85d6SJean-Jacques Hiblot 		udelay(100);
525c10b85d6SJean-Jacques Hiblot 	else if (err)
526c10b85d6SJean-Jacques Hiblot 		return -ETIMEDOUT;
527c10b85d6SJean-Jacques Hiblot 
528c10b85d6SJean-Jacques Hiblot 	/*
529c10b85d6SJean-Jacques Hiblot 	 * During a signal voltage level switch, the clock must be gated
530c10b85d6SJean-Jacques Hiblot 	 * for 5 ms according to the SD spec
531c10b85d6SJean-Jacques Hiblot 	 */
532c10b85d6SJean-Jacques Hiblot 	mmc_set_clock(mmc, mmc->clock, true);
533c10b85d6SJean-Jacques Hiblot 
534c10b85d6SJean-Jacques Hiblot 	err = mmc_set_signal_voltage(mmc, signal_voltage);
535c10b85d6SJean-Jacques Hiblot 	if (err)
536c10b85d6SJean-Jacques Hiblot 		return err;
537c10b85d6SJean-Jacques Hiblot 
538c10b85d6SJean-Jacques Hiblot 	/* Keep clock gated for at least 10 ms, though spec only says 5 ms */
539c10b85d6SJean-Jacques Hiblot 	mdelay(10);
540c10b85d6SJean-Jacques Hiblot 	mmc_set_clock(mmc, mmc->clock, false);
541c10b85d6SJean-Jacques Hiblot 
542c10b85d6SJean-Jacques Hiblot 	/*
543c10b85d6SJean-Jacques Hiblot 	 * Failure to switch is indicated by the card holding
544c10b85d6SJean-Jacques Hiblot 	 * dat[0:3] low. Wait for at least 1 ms according to spec
545c10b85d6SJean-Jacques Hiblot 	 */
546c10b85d6SJean-Jacques Hiblot 	err = mmc_wait_dat0(mmc, 1, 1000);
547c10b85d6SJean-Jacques Hiblot 	if (err == -ENOSYS)
548c10b85d6SJean-Jacques Hiblot 		udelay(1000);
549c10b85d6SJean-Jacques Hiblot 	else if (err)
550c10b85d6SJean-Jacques Hiblot 		return -ETIMEDOUT;
551c10b85d6SJean-Jacques Hiblot 
552c10b85d6SJean-Jacques Hiblot 	return 0;
553c10b85d6SJean-Jacques Hiblot }
554f99c2efeSJean-Jacques Hiblot #endif
555c10b85d6SJean-Jacques Hiblot 
556c10b85d6SJean-Jacques Hiblot static int sd_send_op_cond(struct mmc *mmc, bool uhs_en)
557272cc70bSAndy Fleming {
558272cc70bSAndy Fleming 	int timeout = 1000;
559272cc70bSAndy Fleming 	int err;
560272cc70bSAndy Fleming 	struct mmc_cmd cmd;
561272cc70bSAndy Fleming 
5621677eef4SAndrew Gabbasov 	while (1) {
563272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_APP_CMD;
564272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1;
565272cc70bSAndy Fleming 		cmd.cmdarg = 0;
566272cc70bSAndy Fleming 
567272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
568272cc70bSAndy Fleming 
569272cc70bSAndy Fleming 		if (err)
570272cc70bSAndy Fleming 			return err;
571272cc70bSAndy Fleming 
572272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
573272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
574250de12bSStefano Babic 
575250de12bSStefano Babic 		/*
576250de12bSStefano Babic 		 * Most cards do not answer if some reserved bits
577250de12bSStefano Babic 		 * in the ocr are set. However, Some controller
578250de12bSStefano Babic 		 * can set bit 7 (reserved for low voltages), but
579250de12bSStefano Babic 		 * how to manage low voltages SD card is not yet
580250de12bSStefano Babic 		 * specified.
581250de12bSStefano Babic 		 */
582d52ebf10SThomas Chou 		cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
58393bfd616SPantelis Antoniou 			(mmc->cfg->voltages & 0xff8000);
584272cc70bSAndy Fleming 
585272cc70bSAndy Fleming 		if (mmc->version == SD_VERSION_2)
586272cc70bSAndy Fleming 			cmd.cmdarg |= OCR_HCS;
587272cc70bSAndy Fleming 
588c10b85d6SJean-Jacques Hiblot 		if (uhs_en)
589c10b85d6SJean-Jacques Hiblot 			cmd.cmdarg |= OCR_S18R;
590c10b85d6SJean-Jacques Hiblot 
591272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
592272cc70bSAndy Fleming 
593272cc70bSAndy Fleming 		if (err)
594272cc70bSAndy Fleming 			return err;
595272cc70bSAndy Fleming 
5961677eef4SAndrew Gabbasov 		if (cmd.response[0] & OCR_BUSY)
5971677eef4SAndrew Gabbasov 			break;
598272cc70bSAndy Fleming 
5991677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
600915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
601272cc70bSAndy Fleming 
6021677eef4SAndrew Gabbasov 		udelay(1000);
6031677eef4SAndrew Gabbasov 	}
6041677eef4SAndrew Gabbasov 
605272cc70bSAndy Fleming 	if (mmc->version != SD_VERSION_2)
606272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
607272cc70bSAndy Fleming 
608d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
609d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
610d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
611d52ebf10SThomas Chou 		cmd.cmdarg = 0;
612d52ebf10SThomas Chou 
613d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
614d52ebf10SThomas Chou 
615d52ebf10SThomas Chou 		if (err)
616d52ebf10SThomas Chou 			return err;
617d52ebf10SThomas Chou 	}
618d52ebf10SThomas Chou 
619998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
620272cc70bSAndy Fleming 
621f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
622c10b85d6SJean-Jacques Hiblot 	if (uhs_en && !(mmc_host_is_spi(mmc)) && (cmd.response[0] & 0x41000000)
623c10b85d6SJean-Jacques Hiblot 	    == 0x41000000) {
624c10b85d6SJean-Jacques Hiblot 		err = mmc_switch_voltage(mmc, MMC_SIGNAL_VOLTAGE_180);
625c10b85d6SJean-Jacques Hiblot 		if (err)
626c10b85d6SJean-Jacques Hiblot 			return err;
627c10b85d6SJean-Jacques Hiblot 	}
628f99c2efeSJean-Jacques Hiblot #endif
629c10b85d6SJean-Jacques Hiblot 
630272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
631272cc70bSAndy Fleming 	mmc->rca = 0;
632272cc70bSAndy Fleming 
633272cc70bSAndy Fleming 	return 0;
634272cc70bSAndy Fleming }
635272cc70bSAndy Fleming 
6365289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg)
637272cc70bSAndy Fleming {
6385289b535SAndrew Gabbasov 	struct mmc_cmd cmd;
639272cc70bSAndy Fleming 	int err;
640272cc70bSAndy Fleming 
6415289b535SAndrew Gabbasov 	cmd.cmdidx = MMC_CMD_SEND_OP_COND;
6425289b535SAndrew Gabbasov 	cmd.resp_type = MMC_RSP_R3;
6435289b535SAndrew Gabbasov 	cmd.cmdarg = 0;
6445a20397bSRob Herring 	if (use_arg && !mmc_host_is_spi(mmc))
6455a20397bSRob Herring 		cmd.cmdarg = OCR_HCS |
64693bfd616SPantelis Antoniou 			(mmc->cfg->voltages &
647a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_VOLTAGE_MASK)) |
648a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_ACCESS_MODE);
649e9550449SChe-Liang Chiou 
6505289b535SAndrew Gabbasov 	err = mmc_send_cmd(mmc, &cmd, NULL);
651e9550449SChe-Liang Chiou 	if (err)
652e9550449SChe-Liang Chiou 		return err;
6535289b535SAndrew Gabbasov 	mmc->ocr = cmd.response[0];
654e9550449SChe-Liang Chiou 	return 0;
655e9550449SChe-Liang Chiou }
656e9550449SChe-Liang Chiou 
657750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc)
658e9550449SChe-Liang Chiou {
659e9550449SChe-Liang Chiou 	int err, i;
660e9550449SChe-Liang Chiou 
661272cc70bSAndy Fleming 	/* Some cards seem to need this */
662272cc70bSAndy Fleming 	mmc_go_idle(mmc);
663272cc70bSAndy Fleming 
66431cacbabSRaffaele Recalcati  	/* Asking to the card its capabilities */
665e9550449SChe-Liang Chiou 	for (i = 0; i < 2; i++) {
6665289b535SAndrew Gabbasov 		err = mmc_send_op_cond_iter(mmc, i != 0);
66731cacbabSRaffaele Recalcati 		if (err)
66831cacbabSRaffaele Recalcati 			return err;
66931cacbabSRaffaele Recalcati 
670e9550449SChe-Liang Chiou 		/* exit if not busy (flag seems to be inverted) */
671a626c8d4SAndrew Gabbasov 		if (mmc->ocr & OCR_BUSY)
672bd47c135SAndrew Gabbasov 			break;
673e9550449SChe-Liang Chiou 	}
674bd47c135SAndrew Gabbasov 	mmc->op_cond_pending = 1;
675bd47c135SAndrew Gabbasov 	return 0;
676e9550449SChe-Liang Chiou }
67731cacbabSRaffaele Recalcati 
678750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc)
679e9550449SChe-Liang Chiou {
680e9550449SChe-Liang Chiou 	struct mmc_cmd cmd;
681e9550449SChe-Liang Chiou 	int timeout = 1000;
682e9550449SChe-Liang Chiou 	uint start;
683e9550449SChe-Liang Chiou 	int err;
684e9550449SChe-Liang Chiou 
685e9550449SChe-Liang Chiou 	mmc->op_cond_pending = 0;
686cc17c01fSAndrew Gabbasov 	if (!(mmc->ocr & OCR_BUSY)) {
687d188b113SYangbo Lu 		/* Some cards seem to need this */
688d188b113SYangbo Lu 		mmc_go_idle(mmc);
689d188b113SYangbo Lu 
690e9550449SChe-Liang Chiou 		start = get_timer(0);
6911677eef4SAndrew Gabbasov 		while (1) {
6925289b535SAndrew Gabbasov 			err = mmc_send_op_cond_iter(mmc, 1);
693272cc70bSAndy Fleming 			if (err)
694272cc70bSAndy Fleming 				return err;
6951677eef4SAndrew Gabbasov 			if (mmc->ocr & OCR_BUSY)
6961677eef4SAndrew Gabbasov 				break;
697e9550449SChe-Liang Chiou 			if (get_timer(start) > timeout)
698915ffa52SJaehoon Chung 				return -EOPNOTSUPP;
699e9550449SChe-Liang Chiou 			udelay(100);
7001677eef4SAndrew Gabbasov 		}
701cc17c01fSAndrew Gabbasov 	}
702272cc70bSAndy Fleming 
703d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
704d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
705d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
706d52ebf10SThomas Chou 		cmd.cmdarg = 0;
707d52ebf10SThomas Chou 
708d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
709d52ebf10SThomas Chou 
710d52ebf10SThomas Chou 		if (err)
711d52ebf10SThomas Chou 			return err;
712a626c8d4SAndrew Gabbasov 
713a626c8d4SAndrew Gabbasov 		mmc->ocr = cmd.response[0];
714d52ebf10SThomas Chou 	}
715d52ebf10SThomas Chou 
716272cc70bSAndy Fleming 	mmc->version = MMC_VERSION_UNKNOWN;
717272cc70bSAndy Fleming 
718272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
719def816a2SStephen Warren 	mmc->rca = 1;
720272cc70bSAndy Fleming 
721272cc70bSAndy Fleming 	return 0;
722272cc70bSAndy Fleming }
723272cc70bSAndy Fleming 
724272cc70bSAndy Fleming 
725fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
726272cc70bSAndy Fleming {
727272cc70bSAndy Fleming 	struct mmc_cmd cmd;
728272cc70bSAndy Fleming 	struct mmc_data data;
729272cc70bSAndy Fleming 	int err;
730272cc70bSAndy Fleming 
731272cc70bSAndy Fleming 	/* Get the Card Status Register */
732272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
733272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
734272cc70bSAndy Fleming 	cmd.cmdarg = 0;
735272cc70bSAndy Fleming 
736cdfd1ac6SYoshihiro Shimoda 	data.dest = (char *)ext_csd;
737272cc70bSAndy Fleming 	data.blocks = 1;
7388bfa195eSSimon Glass 	data.blocksize = MMC_MAX_BLOCK_LEN;
739272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
740272cc70bSAndy Fleming 
741272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
742272cc70bSAndy Fleming 
743272cc70bSAndy Fleming 	return err;
744272cc70bSAndy Fleming }
745272cc70bSAndy Fleming 
746c40704f4SSimon Glass int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
747272cc70bSAndy Fleming {
748272cc70bSAndy Fleming 	struct mmc_cmd cmd;
7495d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
750a9003dc6SMaxime Ripard 	int retries = 3;
7515d4fc8d9SRaffaele Recalcati 	int ret;
752272cc70bSAndy Fleming 
753272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SWITCH;
754272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1b;
755272cc70bSAndy Fleming 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
756272cc70bSAndy Fleming 				 (index << 16) |
757272cc70bSAndy Fleming 				 (value << 8);
758272cc70bSAndy Fleming 
759a9003dc6SMaxime Ripard 	while (retries > 0) {
7605d4fc8d9SRaffaele Recalcati 		ret = mmc_send_cmd(mmc, &cmd, NULL);
7615d4fc8d9SRaffaele Recalcati 
7625d4fc8d9SRaffaele Recalcati 		/* Waiting for the ready status */
763a9003dc6SMaxime Ripard 		if (!ret) {
76493ad0d18SJan Kloetzke 			ret = mmc_send_status(mmc, timeout);
765a9003dc6SMaxime Ripard 			return ret;
766a9003dc6SMaxime Ripard 		}
767a9003dc6SMaxime Ripard 
768a9003dc6SMaxime Ripard 		retries--;
769a9003dc6SMaxime Ripard 	}
7705d4fc8d9SRaffaele Recalcati 
7715d4fc8d9SRaffaele Recalcati 	return ret;
7725d4fc8d9SRaffaele Recalcati 
773272cc70bSAndy Fleming }
774272cc70bSAndy Fleming 
7753862b854SJean-Jacques Hiblot static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode)
776272cc70bSAndy Fleming {
777272cc70bSAndy Fleming 	int err;
7783862b854SJean-Jacques Hiblot 	int speed_bits;
7793862b854SJean-Jacques Hiblot 
7803862b854SJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
7813862b854SJean-Jacques Hiblot 
7823862b854SJean-Jacques Hiblot 	switch (mode) {
7833862b854SJean-Jacques Hiblot 	case MMC_HS:
7843862b854SJean-Jacques Hiblot 	case MMC_HS_52:
7853862b854SJean-Jacques Hiblot 	case MMC_DDR_52:
7863862b854SJean-Jacques Hiblot 		speed_bits = EXT_CSD_TIMING_HS;
787634d4849SKishon Vijay Abraham I 		break;
788baef2070SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
789634d4849SKishon Vijay Abraham I 	case MMC_HS_200:
790634d4849SKishon Vijay Abraham I 		speed_bits = EXT_CSD_TIMING_HS200;
791634d4849SKishon Vijay Abraham I 		break;
792baef2070SJean-Jacques Hiblot #endif
7933862b854SJean-Jacques Hiblot 	case MMC_LEGACY:
7943862b854SJean-Jacques Hiblot 		speed_bits = EXT_CSD_TIMING_LEGACY;
7953862b854SJean-Jacques Hiblot 		break;
7963862b854SJean-Jacques Hiblot 	default:
7973862b854SJean-Jacques Hiblot 		return -EINVAL;
7983862b854SJean-Jacques Hiblot 	}
7993862b854SJean-Jacques Hiblot 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
8003862b854SJean-Jacques Hiblot 			 speed_bits);
8013862b854SJean-Jacques Hiblot 	if (err)
8023862b854SJean-Jacques Hiblot 		return err;
8033862b854SJean-Jacques Hiblot 
8043862b854SJean-Jacques Hiblot 	if ((mode == MMC_HS) || (mode == MMC_HS_52)) {
8053862b854SJean-Jacques Hiblot 		/* Now check to see that it worked */
8063862b854SJean-Jacques Hiblot 		err = mmc_send_ext_csd(mmc, test_csd);
8073862b854SJean-Jacques Hiblot 		if (err)
8083862b854SJean-Jacques Hiblot 			return err;
8093862b854SJean-Jacques Hiblot 
8103862b854SJean-Jacques Hiblot 		/* No high-speed support */
8113862b854SJean-Jacques Hiblot 		if (!test_csd[EXT_CSD_HS_TIMING])
8123862b854SJean-Jacques Hiblot 			return -ENOTSUPP;
8133862b854SJean-Jacques Hiblot 	}
8143862b854SJean-Jacques Hiblot 
8153862b854SJean-Jacques Hiblot 	return 0;
8163862b854SJean-Jacques Hiblot }
8173862b854SJean-Jacques Hiblot 
8183862b854SJean-Jacques Hiblot static int mmc_get_capabilities(struct mmc *mmc)
8193862b854SJean-Jacques Hiblot {
8203862b854SJean-Jacques Hiblot 	u8 *ext_csd = mmc->ext_csd;
8213862b854SJean-Jacques Hiblot 	char cardtype;
822272cc70bSAndy Fleming 
82300e446faSJean-Jacques Hiblot 	mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(MMC_LEGACY);
824272cc70bSAndy Fleming 
825d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
826d52ebf10SThomas Chou 		return 0;
827d52ebf10SThomas Chou 
828272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
829272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
830272cc70bSAndy Fleming 		return 0;
831272cc70bSAndy Fleming 
8323862b854SJean-Jacques Hiblot 	if (!ext_csd) {
833d8e3d420SJean-Jacques Hiblot 		pr_err("No ext_csd found!\n"); /* this should enver happen */
8343862b854SJean-Jacques Hiblot 		return -ENOTSUPP;
8353862b854SJean-Jacques Hiblot 	}
8363862b854SJean-Jacques Hiblot 
837fc5b32fbSAndrew Gabbasov 	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
838fc5b32fbSAndrew Gabbasov 
839634d4849SKishon Vijay Abraham I 	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0x3f;
840bc1e3272SJean-Jacques Hiblot 	mmc->cardtype = cardtype;
841272cc70bSAndy Fleming 
842baef2070SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
843634d4849SKishon Vijay Abraham I 	if (cardtype & (EXT_CSD_CARD_TYPE_HS200_1_2V |
844634d4849SKishon Vijay Abraham I 			EXT_CSD_CARD_TYPE_HS200_1_8V)) {
845634d4849SKishon Vijay Abraham I 		mmc->card_caps |= MMC_MODE_HS200;
846634d4849SKishon Vijay Abraham I 	}
847baef2070SJean-Jacques Hiblot #endif
848d22e3d46SJaehoon Chung 	if (cardtype & EXT_CSD_CARD_TYPE_52) {
8493862b854SJean-Jacques Hiblot 		if (cardtype & EXT_CSD_CARD_TYPE_DDR_52)
850d22e3d46SJaehoon Chung 			mmc->card_caps |= MMC_MODE_DDR_52MHz;
8513862b854SJean-Jacques Hiblot 		mmc->card_caps |= MMC_MODE_HS_52MHz;
852d22e3d46SJaehoon Chung 	}
8533862b854SJean-Jacques Hiblot 	if (cardtype & EXT_CSD_CARD_TYPE_26)
8543862b854SJean-Jacques Hiblot 		mmc->card_caps |= MMC_MODE_HS;
855272cc70bSAndy Fleming 
856272cc70bSAndy Fleming 	return 0;
857272cc70bSAndy Fleming }
858272cc70bSAndy Fleming 
859f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num)
860f866a46dSStephen Warren {
861f866a46dSStephen Warren 	switch (part_num) {
862f866a46dSStephen Warren 	case 0:
863f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_user;
864f866a46dSStephen Warren 		break;
865f866a46dSStephen Warren 	case 1:
866f866a46dSStephen Warren 	case 2:
867f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_boot;
868f866a46dSStephen Warren 		break;
869f866a46dSStephen Warren 	case 3:
870f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_rpmb;
871f866a46dSStephen Warren 		break;
872f866a46dSStephen Warren 	case 4:
873f866a46dSStephen Warren 	case 5:
874f866a46dSStephen Warren 	case 6:
875f866a46dSStephen Warren 	case 7:
876f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_gp[part_num - 4];
877f866a46dSStephen Warren 		break;
878f866a46dSStephen Warren 	default:
879f866a46dSStephen Warren 		return -1;
880f866a46dSStephen Warren 	}
881f866a46dSStephen Warren 
882c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len);
883f866a46dSStephen Warren 
884f866a46dSStephen Warren 	return 0;
885f866a46dSStephen Warren }
886f866a46dSStephen Warren 
887f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
88801298da3SJean-Jacques Hiblot static int mmc_boot_part_access_chk(struct mmc *mmc, unsigned int part_num)
88901298da3SJean-Jacques Hiblot {
89001298da3SJean-Jacques Hiblot 	int forbidden = 0;
89101298da3SJean-Jacques Hiblot 	bool change = false;
89201298da3SJean-Jacques Hiblot 
89301298da3SJean-Jacques Hiblot 	if (part_num & PART_ACCESS_MASK)
89401298da3SJean-Jacques Hiblot 		forbidden = MMC_CAP(MMC_HS_200);
89501298da3SJean-Jacques Hiblot 
89601298da3SJean-Jacques Hiblot 	if (MMC_CAP(mmc->selected_mode) & forbidden) {
897d4d64889SMasahiro Yamada 		pr_debug("selected mode (%s) is forbidden for part %d\n",
89801298da3SJean-Jacques Hiblot 			 mmc_mode_name(mmc->selected_mode), part_num);
89901298da3SJean-Jacques Hiblot 		change = true;
90001298da3SJean-Jacques Hiblot 	} else if (mmc->selected_mode != mmc->best_mode) {
901d4d64889SMasahiro Yamada 		pr_debug("selected mode is not optimal\n");
90201298da3SJean-Jacques Hiblot 		change = true;
90301298da3SJean-Jacques Hiblot 	}
90401298da3SJean-Jacques Hiblot 
90501298da3SJean-Jacques Hiblot 	if (change)
90601298da3SJean-Jacques Hiblot 		return mmc_select_mode_and_width(mmc,
90701298da3SJean-Jacques Hiblot 						 mmc->card_caps & ~forbidden);
90801298da3SJean-Jacques Hiblot 
90901298da3SJean-Jacques Hiblot 	return 0;
91001298da3SJean-Jacques Hiblot }
911f99c2efeSJean-Jacques Hiblot #else
912f99c2efeSJean-Jacques Hiblot static inline int mmc_boot_part_access_chk(struct mmc *mmc,
913f99c2efeSJean-Jacques Hiblot 					   unsigned int part_num)
914f99c2efeSJean-Jacques Hiblot {
915f99c2efeSJean-Jacques Hiblot 	return 0;
916f99c2efeSJean-Jacques Hiblot }
917f99c2efeSJean-Jacques Hiblot #endif
91801298da3SJean-Jacques Hiblot 
9197dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num)
920bc897b1dSLei Wen {
921f866a46dSStephen Warren 	int ret;
922bc897b1dSLei Wen 
92301298da3SJean-Jacques Hiblot 	ret = mmc_boot_part_access_chk(mmc, part_num);
92401298da3SJean-Jacques Hiblot 	if (ret)
92501298da3SJean-Jacques Hiblot 		return ret;
92601298da3SJean-Jacques Hiblot 
927f866a46dSStephen Warren 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
928bc897b1dSLei Wen 			 (mmc->part_config & ~PART_ACCESS_MASK)
929bc897b1dSLei Wen 			 | (part_num & PART_ACCESS_MASK));
930f866a46dSStephen Warren 
9316dc93e70SPeter Bigot 	/*
9326dc93e70SPeter Bigot 	 * Set the capacity if the switch succeeded or was intended
9336dc93e70SPeter Bigot 	 * to return to representing the raw device.
9346dc93e70SPeter Bigot 	 */
935873cc1d7SStephen Warren 	if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) {
9366dc93e70SPeter Bigot 		ret = mmc_set_capacity(mmc, part_num);
937fdbb139fSSimon Glass 		mmc_get_blk_desc(mmc)->hwpart = part_num;
938873cc1d7SStephen Warren 	}
9396dc93e70SPeter Bigot 
9406dc93e70SPeter Bigot 	return ret;
941bc897b1dSLei Wen }
942bc897b1dSLei Wen 
943cf17789eSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING)
944ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc,
945ac9da0e0SDiego Santa Cruz 		      const struct mmc_hwpart_conf *conf,
946ac9da0e0SDiego Santa Cruz 		      enum mmc_hwpart_conf_mode mode)
947ac9da0e0SDiego Santa Cruz {
948ac9da0e0SDiego Santa Cruz 	u8 part_attrs = 0;
949ac9da0e0SDiego Santa Cruz 	u32 enh_size_mult;
950ac9da0e0SDiego Santa Cruz 	u32 enh_start_addr;
951ac9da0e0SDiego Santa Cruz 	u32 gp_size_mult[4];
952ac9da0e0SDiego Santa Cruz 	u32 max_enh_size_mult;
953ac9da0e0SDiego Santa Cruz 	u32 tot_enh_size_mult = 0;
9548dda5b0eSDiego Santa Cruz 	u8 wr_rel_set;
955ac9da0e0SDiego Santa Cruz 	int i, pidx, err;
956ac9da0e0SDiego Santa Cruz 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
957ac9da0e0SDiego Santa Cruz 
958ac9da0e0SDiego Santa Cruz 	if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE)
959ac9da0e0SDiego Santa Cruz 		return -EINVAL;
960ac9da0e0SDiego Santa Cruz 
961ac9da0e0SDiego Santa Cruz 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) {
962d8e3d420SJean-Jacques Hiblot 		pr_err("eMMC >= 4.4 required for enhanced user data area\n");
963ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
964ac9da0e0SDiego Santa Cruz 	}
965ac9da0e0SDiego Santa Cruz 
966ac9da0e0SDiego Santa Cruz 	if (!(mmc->part_support & PART_SUPPORT)) {
967d8e3d420SJean-Jacques Hiblot 		pr_err("Card does not support partitioning\n");
968ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
969ac9da0e0SDiego Santa Cruz 	}
970ac9da0e0SDiego Santa Cruz 
971ac9da0e0SDiego Santa Cruz 	if (!mmc->hc_wp_grp_size) {
972d8e3d420SJean-Jacques Hiblot 		pr_err("Card does not define HC WP group size\n");
973ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
974ac9da0e0SDiego Santa Cruz 	}
975ac9da0e0SDiego Santa Cruz 
976ac9da0e0SDiego Santa Cruz 	/* check partition alignment and total enhanced size */
977ac9da0e0SDiego Santa Cruz 	if (conf->user.enh_size) {
978ac9da0e0SDiego Santa Cruz 		if (conf->user.enh_size % mmc->hc_wp_grp_size ||
979ac9da0e0SDiego Santa Cruz 		    conf->user.enh_start % mmc->hc_wp_grp_size) {
980d8e3d420SJean-Jacques Hiblot 			pr_err("User data enhanced area not HC WP group "
981ac9da0e0SDiego Santa Cruz 			       "size aligned\n");
982ac9da0e0SDiego Santa Cruz 			return -EINVAL;
983ac9da0e0SDiego Santa Cruz 		}
984ac9da0e0SDiego Santa Cruz 		part_attrs |= EXT_CSD_ENH_USR;
985ac9da0e0SDiego Santa Cruz 		enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size;
986ac9da0e0SDiego Santa Cruz 		if (mmc->high_capacity) {
987ac9da0e0SDiego Santa Cruz 			enh_start_addr = conf->user.enh_start;
988ac9da0e0SDiego Santa Cruz 		} else {
989ac9da0e0SDiego Santa Cruz 			enh_start_addr = (conf->user.enh_start << 9);
990ac9da0e0SDiego Santa Cruz 		}
991ac9da0e0SDiego Santa Cruz 	} else {
992ac9da0e0SDiego Santa Cruz 		enh_size_mult = 0;
993ac9da0e0SDiego Santa Cruz 		enh_start_addr = 0;
994ac9da0e0SDiego Santa Cruz 	}
995ac9da0e0SDiego Santa Cruz 	tot_enh_size_mult += enh_size_mult;
996ac9da0e0SDiego Santa Cruz 
997ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
998ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) {
999d8e3d420SJean-Jacques Hiblot 			pr_err("GP%i partition not HC WP group size "
1000ac9da0e0SDiego Santa Cruz 			       "aligned\n", pidx+1);
1001ac9da0e0SDiego Santa Cruz 			return -EINVAL;
1002ac9da0e0SDiego Santa Cruz 		}
1003ac9da0e0SDiego Santa Cruz 		gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size;
1004ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) {
1005ac9da0e0SDiego Santa Cruz 			part_attrs |= EXT_CSD_ENH_GP(pidx);
1006ac9da0e0SDiego Santa Cruz 			tot_enh_size_mult += gp_size_mult[pidx];
1007ac9da0e0SDiego Santa Cruz 		}
1008ac9da0e0SDiego Santa Cruz 	}
1009ac9da0e0SDiego Santa Cruz 
1010ac9da0e0SDiego Santa Cruz 	if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) {
1011d8e3d420SJean-Jacques Hiblot 		pr_err("Card does not support enhanced attribute\n");
1012ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1013ac9da0e0SDiego Santa Cruz 	}
1014ac9da0e0SDiego Santa Cruz 
1015ac9da0e0SDiego Santa Cruz 	err = mmc_send_ext_csd(mmc, ext_csd);
1016ac9da0e0SDiego Santa Cruz 	if (err)
1017ac9da0e0SDiego Santa Cruz 		return err;
1018ac9da0e0SDiego Santa Cruz 
1019ac9da0e0SDiego Santa Cruz 	max_enh_size_mult =
1020ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) +
1021ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) +
1022ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT];
1023ac9da0e0SDiego Santa Cruz 	if (tot_enh_size_mult > max_enh_size_mult) {
1024d8e3d420SJean-Jacques Hiblot 		pr_err("Total enhanced size exceeds maximum (%u > %u)\n",
1025ac9da0e0SDiego Santa Cruz 		       tot_enh_size_mult, max_enh_size_mult);
1026ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1027ac9da0e0SDiego Santa Cruz 	}
1028ac9da0e0SDiego Santa Cruz 
10298dda5b0eSDiego Santa Cruz 	/* The default value of EXT_CSD_WR_REL_SET is device
10308dda5b0eSDiego Santa Cruz 	 * dependent, the values can only be changed if the
10318dda5b0eSDiego Santa Cruz 	 * EXT_CSD_HS_CTRL_REL bit is set. The values can be
10328dda5b0eSDiego Santa Cruz 	 * changed only once and before partitioning is completed. */
10338dda5b0eSDiego Santa Cruz 	wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
10348dda5b0eSDiego Santa Cruz 	if (conf->user.wr_rel_change) {
10358dda5b0eSDiego Santa Cruz 		if (conf->user.wr_rel_set)
10368dda5b0eSDiego Santa Cruz 			wr_rel_set |= EXT_CSD_WR_DATA_REL_USR;
10378dda5b0eSDiego Santa Cruz 		else
10388dda5b0eSDiego Santa Cruz 			wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR;
10398dda5b0eSDiego Santa Cruz 	}
10408dda5b0eSDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
10418dda5b0eSDiego Santa Cruz 		if (conf->gp_part[pidx].wr_rel_change) {
10428dda5b0eSDiego Santa Cruz 			if (conf->gp_part[pidx].wr_rel_set)
10438dda5b0eSDiego Santa Cruz 				wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx);
10448dda5b0eSDiego Santa Cruz 			else
10458dda5b0eSDiego Santa Cruz 				wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx);
10468dda5b0eSDiego Santa Cruz 		}
10478dda5b0eSDiego Santa Cruz 	}
10488dda5b0eSDiego Santa Cruz 
10498dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] &&
10508dda5b0eSDiego Santa Cruz 	    !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) {
10518dda5b0eSDiego Santa Cruz 		puts("Card does not support host controlled partition write "
10528dda5b0eSDiego Santa Cruz 		     "reliability settings\n");
10538dda5b0eSDiego Santa Cruz 		return -EMEDIUMTYPE;
10548dda5b0eSDiego Santa Cruz 	}
10558dda5b0eSDiego Santa Cruz 
1056ac9da0e0SDiego Santa Cruz 	if (ext_csd[EXT_CSD_PARTITION_SETTING] &
1057ac9da0e0SDiego Santa Cruz 	    EXT_CSD_PARTITION_SETTING_COMPLETED) {
1058d8e3d420SJean-Jacques Hiblot 		pr_err("Card already partitioned\n");
1059ac9da0e0SDiego Santa Cruz 		return -EPERM;
1060ac9da0e0SDiego Santa Cruz 	}
1061ac9da0e0SDiego Santa Cruz 
1062ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_CHECK)
1063ac9da0e0SDiego Santa Cruz 		return 0;
1064ac9da0e0SDiego Santa Cruz 
1065ac9da0e0SDiego Santa Cruz 	/* Partitioning requires high-capacity size definitions */
1066ac9da0e0SDiego Santa Cruz 	if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) {
1067ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1068ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ERASE_GROUP_DEF, 1);
1069ac9da0e0SDiego Santa Cruz 
1070ac9da0e0SDiego Santa Cruz 		if (err)
1071ac9da0e0SDiego Santa Cruz 			return err;
1072ac9da0e0SDiego Santa Cruz 
1073ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1074ac9da0e0SDiego Santa Cruz 
1075ac9da0e0SDiego Santa Cruz 		/* update erase group size to be high-capacity */
1076ac9da0e0SDiego Santa Cruz 		mmc->erase_grp_size =
1077ac9da0e0SDiego Santa Cruz 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1078ac9da0e0SDiego Santa Cruz 
1079ac9da0e0SDiego Santa Cruz 	}
1080ac9da0e0SDiego Santa Cruz 
1081ac9da0e0SDiego Santa Cruz 	/* all OK, write the configuration */
1082ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 4; i++) {
1083ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1084ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_START_ADDR+i,
1085ac9da0e0SDiego Santa Cruz 				 (enh_start_addr >> (i*8)) & 0xFF);
1086ac9da0e0SDiego Santa Cruz 		if (err)
1087ac9da0e0SDiego Santa Cruz 			return err;
1088ac9da0e0SDiego Santa Cruz 	}
1089ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 3; i++) {
1090ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1091ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_SIZE_MULT+i,
1092ac9da0e0SDiego Santa Cruz 				 (enh_size_mult >> (i*8)) & 0xFF);
1093ac9da0e0SDiego Santa Cruz 		if (err)
1094ac9da0e0SDiego Santa Cruz 			return err;
1095ac9da0e0SDiego Santa Cruz 	}
1096ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
1097ac9da0e0SDiego Santa Cruz 		for (i = 0; i < 3; i++) {
1098ac9da0e0SDiego Santa Cruz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1099ac9da0e0SDiego Santa Cruz 					 EXT_CSD_GP_SIZE_MULT+pidx*3+i,
1100ac9da0e0SDiego Santa Cruz 					 (gp_size_mult[pidx] >> (i*8)) & 0xFF);
1101ac9da0e0SDiego Santa Cruz 			if (err)
1102ac9da0e0SDiego Santa Cruz 				return err;
1103ac9da0e0SDiego Santa Cruz 		}
1104ac9da0e0SDiego Santa Cruz 	}
1105ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1106ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs);
1107ac9da0e0SDiego Santa Cruz 	if (err)
1108ac9da0e0SDiego Santa Cruz 		return err;
1109ac9da0e0SDiego Santa Cruz 
1110ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_SET)
1111ac9da0e0SDiego Santa Cruz 		return 0;
1112ac9da0e0SDiego Santa Cruz 
11138dda5b0eSDiego Santa Cruz 	/* The WR_REL_SET is a write-once register but shall be
11148dda5b0eSDiego Santa Cruz 	 * written before setting PART_SETTING_COMPLETED. As it is
11158dda5b0eSDiego Santa Cruz 	 * write-once we can only write it when completing the
11168dda5b0eSDiego Santa Cruz 	 * partitioning. */
11178dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) {
11188dda5b0eSDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
11198dda5b0eSDiego Santa Cruz 				 EXT_CSD_WR_REL_SET, wr_rel_set);
11208dda5b0eSDiego Santa Cruz 		if (err)
11218dda5b0eSDiego Santa Cruz 			return err;
11228dda5b0eSDiego Santa Cruz 	}
11238dda5b0eSDiego Santa Cruz 
1124ac9da0e0SDiego Santa Cruz 	/* Setting PART_SETTING_COMPLETED confirms the partition
1125ac9da0e0SDiego Santa Cruz 	 * configuration but it only becomes effective after power
1126ac9da0e0SDiego Santa Cruz 	 * cycle, so we do not adjust the partition related settings
1127ac9da0e0SDiego Santa Cruz 	 * in the mmc struct. */
1128ac9da0e0SDiego Santa Cruz 
1129ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1130ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING,
1131ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING_COMPLETED);
1132ac9da0e0SDiego Santa Cruz 	if (err)
1133ac9da0e0SDiego Santa Cruz 		return err;
1134ac9da0e0SDiego Santa Cruz 
1135ac9da0e0SDiego Santa Cruz 	return 0;
1136ac9da0e0SDiego Santa Cruz }
1137cf17789eSJean-Jacques Hiblot #endif
1138ac9da0e0SDiego Santa Cruz 
1139e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
114048972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
114148972d90SThierry Reding {
114248972d90SThierry Reding 	int cd;
114348972d90SThierry Reding 
114448972d90SThierry Reding 	cd = board_mmc_getcd(mmc);
114548972d90SThierry Reding 
1146d4e1da4eSPeter Korsgaard 	if (cd < 0) {
114793bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getcd)
114893bfd616SPantelis Antoniou 			cd = mmc->cfg->ops->getcd(mmc);
1149d4e1da4eSPeter Korsgaard 		else
1150d4e1da4eSPeter Korsgaard 			cd = 1;
1151d4e1da4eSPeter Korsgaard 	}
115248972d90SThierry Reding 
115348972d90SThierry Reding 	return cd;
115448972d90SThierry Reding }
11558ca51e51SSimon Glass #endif
115648972d90SThierry Reding 
1157fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
1158272cc70bSAndy Fleming {
1159272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1160272cc70bSAndy Fleming 	struct mmc_data data;
1161272cc70bSAndy Fleming 
1162272cc70bSAndy Fleming 	/* Switch the frequency */
1163272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
1164272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1165272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
1166272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
1167272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
1168272cc70bSAndy Fleming 
1169272cc70bSAndy Fleming 	data.dest = (char *)resp;
1170272cc70bSAndy Fleming 	data.blocksize = 64;
1171272cc70bSAndy Fleming 	data.blocks = 1;
1172272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
1173272cc70bSAndy Fleming 
1174272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
1175272cc70bSAndy Fleming }
1176272cc70bSAndy Fleming 
1177272cc70bSAndy Fleming 
1178d0c221feSJean-Jacques Hiblot static int sd_get_capabilities(struct mmc *mmc)
1179272cc70bSAndy Fleming {
1180272cc70bSAndy Fleming 	int err;
1181272cc70bSAndy Fleming 	struct mmc_cmd cmd;
118218e7c8f6SSuniel Mahesh 	ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2);
118318e7c8f6SSuniel Mahesh 	ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16);
1184272cc70bSAndy Fleming 	struct mmc_data data;
1185272cc70bSAndy Fleming 	int timeout;
1186f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1187c10b85d6SJean-Jacques Hiblot 	u32 sd3_bus_mode;
1188f99c2efeSJean-Jacques Hiblot #endif
1189272cc70bSAndy Fleming 
119000e446faSJean-Jacques Hiblot 	mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(SD_LEGACY);
1191272cc70bSAndy Fleming 
1192d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
1193d52ebf10SThomas Chou 		return 0;
1194d52ebf10SThomas Chou 
1195272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
1196272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
1197272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1198272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1199272cc70bSAndy Fleming 
1200272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1201272cc70bSAndy Fleming 
1202272cc70bSAndy Fleming 	if (err)
1203272cc70bSAndy Fleming 		return err;
1204272cc70bSAndy Fleming 
1205272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
1206272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1207272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1208272cc70bSAndy Fleming 
1209272cc70bSAndy Fleming 	timeout = 3;
1210272cc70bSAndy Fleming 
1211272cc70bSAndy Fleming retry_scr:
1212f781dd38SAnton staaf 	data.dest = (char *)scr;
1213272cc70bSAndy Fleming 	data.blocksize = 8;
1214272cc70bSAndy Fleming 	data.blocks = 1;
1215272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
1216272cc70bSAndy Fleming 
1217272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
1218272cc70bSAndy Fleming 
1219272cc70bSAndy Fleming 	if (err) {
1220272cc70bSAndy Fleming 		if (timeout--)
1221272cc70bSAndy Fleming 			goto retry_scr;
1222272cc70bSAndy Fleming 
1223272cc70bSAndy Fleming 		return err;
1224272cc70bSAndy Fleming 	}
1225272cc70bSAndy Fleming 
12264e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
12274e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
1228272cc70bSAndy Fleming 
1229272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
1230272cc70bSAndy Fleming 	case 0:
1231272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1232272cc70bSAndy Fleming 		break;
1233272cc70bSAndy Fleming 	case 1:
1234272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_10;
1235272cc70bSAndy Fleming 		break;
1236272cc70bSAndy Fleming 	case 2:
1237272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
12381741c64dSJaehoon Chung 		if ((mmc->scr[0] >> 15) & 0x1)
12391741c64dSJaehoon Chung 			mmc->version = SD_VERSION_3;
1240272cc70bSAndy Fleming 		break;
1241272cc70bSAndy Fleming 	default:
1242272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1243272cc70bSAndy Fleming 		break;
1244272cc70bSAndy Fleming 	}
1245272cc70bSAndy Fleming 
1246b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
1247b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
1248b44c7083SAlagu Sankar 
1249272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
1250272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
1251272cc70bSAndy Fleming 		return 0;
1252272cc70bSAndy Fleming 
1253272cc70bSAndy Fleming 	timeout = 4;
1254272cc70bSAndy Fleming 	while (timeout--) {
1255272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
1256f781dd38SAnton staaf 				(u8 *)switch_status);
1257272cc70bSAndy Fleming 
1258272cc70bSAndy Fleming 		if (err)
1259272cc70bSAndy Fleming 			return err;
1260272cc70bSAndy Fleming 
1261272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
12624e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
1263272cc70bSAndy Fleming 			break;
1264272cc70bSAndy Fleming 	}
1265272cc70bSAndy Fleming 
1266272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
1267d0c221feSJean-Jacques Hiblot 	if (__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)
1268d0c221feSJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(SD_HS);
1269272cc70bSAndy Fleming 
1270f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1271c10b85d6SJean-Jacques Hiblot 	/* Version before 3.0 don't support UHS modes */
1272c10b85d6SJean-Jacques Hiblot 	if (mmc->version < SD_VERSION_3)
1273c10b85d6SJean-Jacques Hiblot 		return 0;
1274c10b85d6SJean-Jacques Hiblot 
1275c10b85d6SJean-Jacques Hiblot 	sd3_bus_mode = __be32_to_cpu(switch_status[3]) >> 16 & 0x1f;
1276c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR104)
1277c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR104);
1278c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR50)
1279c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR50);
1280c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR25)
1281c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR25);
1282c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR12)
1283c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR12);
1284c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_DDR50)
1285c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_DDR50);
1286f99c2efeSJean-Jacques Hiblot #endif
1287c10b85d6SJean-Jacques Hiblot 
12882c3fbf4cSMacpaul Lin 	return 0;
1289d0c221feSJean-Jacques Hiblot }
1290d0c221feSJean-Jacques Hiblot 
1291d0c221feSJean-Jacques Hiblot static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode)
1292d0c221feSJean-Jacques Hiblot {
1293d0c221feSJean-Jacques Hiblot 	int err;
1294d0c221feSJean-Jacques Hiblot 
1295d0c221feSJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
1296c10b85d6SJean-Jacques Hiblot 	int speed;
12972c3fbf4cSMacpaul Lin 
1298c10b85d6SJean-Jacques Hiblot 	switch (mode) {
1299c10b85d6SJean-Jacques Hiblot 	case SD_LEGACY:
1300c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR12_BUS_SPEED;
1301c10b85d6SJean-Jacques Hiblot 		break;
1302c10b85d6SJean-Jacques Hiblot 	case SD_HS:
1303baef2070SJean-Jacques Hiblot 		speed = HIGH_SPEED_BUS_SPEED;
1304baef2070SJean-Jacques Hiblot 		break;
1305baef2070SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1306baef2070SJean-Jacques Hiblot 	case UHS_SDR12:
1307baef2070SJean-Jacques Hiblot 		speed = UHS_SDR12_BUS_SPEED;
1308baef2070SJean-Jacques Hiblot 		break;
1309c10b85d6SJean-Jacques Hiblot 	case UHS_SDR25:
1310c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR25_BUS_SPEED;
1311c10b85d6SJean-Jacques Hiblot 		break;
1312c10b85d6SJean-Jacques Hiblot 	case UHS_SDR50:
1313c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR50_BUS_SPEED;
1314c10b85d6SJean-Jacques Hiblot 		break;
1315c10b85d6SJean-Jacques Hiblot 	case UHS_DDR50:
1316c10b85d6SJean-Jacques Hiblot 		speed = UHS_DDR50_BUS_SPEED;
1317c10b85d6SJean-Jacques Hiblot 		break;
1318c10b85d6SJean-Jacques Hiblot 	case UHS_SDR104:
1319c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR104_BUS_SPEED;
1320c10b85d6SJean-Jacques Hiblot 		break;
1321baef2070SJean-Jacques Hiblot #endif
1322c10b85d6SJean-Jacques Hiblot 	default:
1323c10b85d6SJean-Jacques Hiblot 		return -EINVAL;
1324c10b85d6SJean-Jacques Hiblot 	}
1325c10b85d6SJean-Jacques Hiblot 
1326c10b85d6SJean-Jacques Hiblot 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, speed, (u8 *)switch_status);
1327272cc70bSAndy Fleming 	if (err)
1328272cc70bSAndy Fleming 		return err;
1329272cc70bSAndy Fleming 
1330a0276f3eSJean-Jacques Hiblot 	if (((__be32_to_cpu(switch_status[4]) >> 24) & 0xF) != speed)
1331d0c221feSJean-Jacques Hiblot 		return -ENOTSUPP;
1332d0c221feSJean-Jacques Hiblot 
1333d0c221feSJean-Jacques Hiblot 	return 0;
1334d0c221feSJean-Jacques Hiblot }
1335d0c221feSJean-Jacques Hiblot 
1336ec360e64SMarek Vasut static int sd_select_bus_width(struct mmc *mmc, int w)
1337d0c221feSJean-Jacques Hiblot {
1338d0c221feSJean-Jacques Hiblot 	int err;
1339d0c221feSJean-Jacques Hiblot 	struct mmc_cmd cmd;
1340d0c221feSJean-Jacques Hiblot 
1341d0c221feSJean-Jacques Hiblot 	if ((w != 4) && (w != 1))
1342d0c221feSJean-Jacques Hiblot 		return -EINVAL;
1343d0c221feSJean-Jacques Hiblot 
1344d0c221feSJean-Jacques Hiblot 	cmd.cmdidx = MMC_CMD_APP_CMD;
1345d0c221feSJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
1346d0c221feSJean-Jacques Hiblot 	cmd.cmdarg = mmc->rca << 16;
1347d0c221feSJean-Jacques Hiblot 
1348d0c221feSJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
1349d0c221feSJean-Jacques Hiblot 	if (err)
1350d0c221feSJean-Jacques Hiblot 		return err;
1351d0c221feSJean-Jacques Hiblot 
1352d0c221feSJean-Jacques Hiblot 	cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
1353d0c221feSJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
1354d0c221feSJean-Jacques Hiblot 	if (w == 4)
1355d0c221feSJean-Jacques Hiblot 		cmd.cmdarg = 2;
1356d0c221feSJean-Jacques Hiblot 	else if (w == 1)
1357d0c221feSJean-Jacques Hiblot 		cmd.cmdarg = 0;
1358d0c221feSJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
1359d0c221feSJean-Jacques Hiblot 	if (err)
1360d0c221feSJean-Jacques Hiblot 		return err;
1361272cc70bSAndy Fleming 
1362272cc70bSAndy Fleming 	return 0;
1363272cc70bSAndy Fleming }
1364272cc70bSAndy Fleming 
13655b2e72f3SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE)
13663697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc)
13673697e599SPeng Fan {
13685b2e72f3SJean-Jacques Hiblot 	static const unsigned int sd_au_size[] = {
13695b2e72f3SJean-Jacques Hiblot 		0,		SZ_16K / 512,		SZ_32K / 512,
13705b2e72f3SJean-Jacques Hiblot 		SZ_64K / 512,	SZ_128K / 512,		SZ_256K / 512,
13715b2e72f3SJean-Jacques Hiblot 		SZ_512K / 512,	SZ_1M / 512,		SZ_2M / 512,
13725b2e72f3SJean-Jacques Hiblot 		SZ_4M / 512,	SZ_8M / 512,		(SZ_8M + SZ_4M) / 512,
13735b2e72f3SJean-Jacques Hiblot 		SZ_16M / 512,	(SZ_16M + SZ_8M) / 512,	SZ_32M / 512,
13745b2e72f3SJean-Jacques Hiblot 		SZ_64M / 512,
13755b2e72f3SJean-Jacques Hiblot 	};
13763697e599SPeng Fan 	int err, i;
13773697e599SPeng Fan 	struct mmc_cmd cmd;
13783697e599SPeng Fan 	ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16);
13793697e599SPeng Fan 	struct mmc_data data;
13803697e599SPeng Fan 	int timeout = 3;
13813697e599SPeng Fan 	unsigned int au, eo, et, es;
13823697e599SPeng Fan 
13833697e599SPeng Fan 	cmd.cmdidx = MMC_CMD_APP_CMD;
13843697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
13853697e599SPeng Fan 	cmd.cmdarg = mmc->rca << 16;
13863697e599SPeng Fan 
13873697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, NULL);
13883697e599SPeng Fan 	if (err)
13893697e599SPeng Fan 		return err;
13903697e599SPeng Fan 
13913697e599SPeng Fan 	cmd.cmdidx = SD_CMD_APP_SD_STATUS;
13923697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
13933697e599SPeng Fan 	cmd.cmdarg = 0;
13943697e599SPeng Fan 
13953697e599SPeng Fan retry_ssr:
13963697e599SPeng Fan 	data.dest = (char *)ssr;
13973697e599SPeng Fan 	data.blocksize = 64;
13983697e599SPeng Fan 	data.blocks = 1;
13993697e599SPeng Fan 	data.flags = MMC_DATA_READ;
14003697e599SPeng Fan 
14013697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, &data);
14023697e599SPeng Fan 	if (err) {
14033697e599SPeng Fan 		if (timeout--)
14043697e599SPeng Fan 			goto retry_ssr;
14053697e599SPeng Fan 
14063697e599SPeng Fan 		return err;
14073697e599SPeng Fan 	}
14083697e599SPeng Fan 
14093697e599SPeng Fan 	for (i = 0; i < 16; i++)
14103697e599SPeng Fan 		ssr[i] = be32_to_cpu(ssr[i]);
14113697e599SPeng Fan 
14123697e599SPeng Fan 	au = (ssr[2] >> 12) & 0xF;
14133697e599SPeng Fan 	if ((au <= 9) || (mmc->version == SD_VERSION_3)) {
14143697e599SPeng Fan 		mmc->ssr.au = sd_au_size[au];
14153697e599SPeng Fan 		es = (ssr[3] >> 24) & 0xFF;
14163697e599SPeng Fan 		es |= (ssr[2] & 0xFF) << 8;
14173697e599SPeng Fan 		et = (ssr[3] >> 18) & 0x3F;
14183697e599SPeng Fan 		if (es && et) {
14193697e599SPeng Fan 			eo = (ssr[3] >> 16) & 0x3;
14203697e599SPeng Fan 			mmc->ssr.erase_timeout = (et * 1000) / es;
14213697e599SPeng Fan 			mmc->ssr.erase_offset = eo * 1000;
14223697e599SPeng Fan 		}
14233697e599SPeng Fan 	} else {
1424d4d64889SMasahiro Yamada 		pr_debug("Invalid Allocation Unit Size.\n");
14253697e599SPeng Fan 	}
14263697e599SPeng Fan 
14273697e599SPeng Fan 	return 0;
14283697e599SPeng Fan }
14295b2e72f3SJean-Jacques Hiblot #endif
1430272cc70bSAndy Fleming /* frequency bases */
1431272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
14325f837c2cSMike Frysinger static const int fbase[] = {
1433272cc70bSAndy Fleming 	10000,
1434272cc70bSAndy Fleming 	100000,
1435272cc70bSAndy Fleming 	1000000,
1436272cc70bSAndy Fleming 	10000000,
1437272cc70bSAndy Fleming };
1438272cc70bSAndy Fleming 
1439272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
1440272cc70bSAndy Fleming  * to platforms without floating point.
1441272cc70bSAndy Fleming  */
144261fe076fSSimon Glass static const u8 multipliers[] = {
1443272cc70bSAndy Fleming 	0,	/* reserved */
1444272cc70bSAndy Fleming 	10,
1445272cc70bSAndy Fleming 	12,
1446272cc70bSAndy Fleming 	13,
1447272cc70bSAndy Fleming 	15,
1448272cc70bSAndy Fleming 	20,
1449272cc70bSAndy Fleming 	25,
1450272cc70bSAndy Fleming 	30,
1451272cc70bSAndy Fleming 	35,
1452272cc70bSAndy Fleming 	40,
1453272cc70bSAndy Fleming 	45,
1454272cc70bSAndy Fleming 	50,
1455272cc70bSAndy Fleming 	55,
1456272cc70bSAndy Fleming 	60,
1457272cc70bSAndy Fleming 	70,
1458272cc70bSAndy Fleming 	80,
1459272cc70bSAndy Fleming };
1460272cc70bSAndy Fleming 
1461d0c221feSJean-Jacques Hiblot static inline int bus_width(uint cap)
1462d0c221feSJean-Jacques Hiblot {
1463d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_8BIT)
1464d0c221feSJean-Jacques Hiblot 		return 8;
1465d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_4BIT)
1466d0c221feSJean-Jacques Hiblot 		return 4;
1467d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_1BIT)
1468d0c221feSJean-Jacques Hiblot 		return 1;
1469d8e3d420SJean-Jacques Hiblot 	pr_warn("invalid bus witdh capability 0x%x\n", cap);
1470d0c221feSJean-Jacques Hiblot 	return 0;
1471d0c221feSJean-Jacques Hiblot }
1472d0c221feSJean-Jacques Hiblot 
1473e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
1474f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
1475ec841209SKishon Vijay Abraham I static int mmc_execute_tuning(struct mmc *mmc, uint opcode)
1476ec841209SKishon Vijay Abraham I {
1477ec841209SKishon Vijay Abraham I 	return -ENOTSUPP;
1478ec841209SKishon Vijay Abraham I }
1479f99c2efeSJean-Jacques Hiblot #endif
1480ec841209SKishon Vijay Abraham I 
1481318a7a57SJean-Jacques Hiblot static void mmc_send_init_stream(struct mmc *mmc)
1482318a7a57SJean-Jacques Hiblot {
1483318a7a57SJean-Jacques Hiblot }
1484318a7a57SJean-Jacques Hiblot 
14852a4d212fSKishon Vijay Abraham I static int mmc_set_ios(struct mmc *mmc)
1486272cc70bSAndy Fleming {
14872a4d212fSKishon Vijay Abraham I 	int ret = 0;
14882a4d212fSKishon Vijay Abraham I 
148993bfd616SPantelis Antoniou 	if (mmc->cfg->ops->set_ios)
14902a4d212fSKishon Vijay Abraham I 		ret = mmc->cfg->ops->set_ios(mmc);
14912a4d212fSKishon Vijay Abraham I 
14922a4d212fSKishon Vijay Abraham I 	return ret;
1493272cc70bSAndy Fleming }
14948ca51e51SSimon Glass #endif
1495272cc70bSAndy Fleming 
149635f67820SKishon Vijay Abraham I int mmc_set_clock(struct mmc *mmc, uint clock, bool disable)
1497272cc70bSAndy Fleming {
1498c0fafe64SJaehoon Chung 	if (!disable) {
149993bfd616SPantelis Antoniou 		if (clock > mmc->cfg->f_max)
150093bfd616SPantelis Antoniou 			clock = mmc->cfg->f_max;
1501272cc70bSAndy Fleming 
150293bfd616SPantelis Antoniou 		if (clock < mmc->cfg->f_min)
150393bfd616SPantelis Antoniou 			clock = mmc->cfg->f_min;
15049546eb92SJaehoon Chung 	}
1505272cc70bSAndy Fleming 
1506272cc70bSAndy Fleming 	mmc->clock = clock;
150735f67820SKishon Vijay Abraham I 	mmc->clk_disable = disable;
1508272cc70bSAndy Fleming 
15092a4d212fSKishon Vijay Abraham I 	return mmc_set_ios(mmc);
1510272cc70bSAndy Fleming }
1511272cc70bSAndy Fleming 
15122a4d212fSKishon Vijay Abraham I static int mmc_set_bus_width(struct mmc *mmc, uint width)
1513272cc70bSAndy Fleming {
1514272cc70bSAndy Fleming 	mmc->bus_width = width;
1515272cc70bSAndy Fleming 
15162a4d212fSKishon Vijay Abraham I 	return mmc_set_ios(mmc);
1517272cc70bSAndy Fleming }
1518272cc70bSAndy Fleming 
15194c9d2aaaSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG)
15204c9d2aaaSJean-Jacques Hiblot /*
15214c9d2aaaSJean-Jacques Hiblot  * helper function to display the capabilities in a human
15224c9d2aaaSJean-Jacques Hiblot  * friendly manner. The capabilities include bus width and
15234c9d2aaaSJean-Jacques Hiblot  * supported modes.
15244c9d2aaaSJean-Jacques Hiblot  */
15254c9d2aaaSJean-Jacques Hiblot void mmc_dump_capabilities(const char *text, uint caps)
15264c9d2aaaSJean-Jacques Hiblot {
15274c9d2aaaSJean-Jacques Hiblot 	enum bus_mode mode;
15284c9d2aaaSJean-Jacques Hiblot 
1529d4d64889SMasahiro Yamada 	pr_debug("%s: widths [", text);
15304c9d2aaaSJean-Jacques Hiblot 	if (caps & MMC_MODE_8BIT)
1531d4d64889SMasahiro Yamada 		pr_debug("8, ");
15324c9d2aaaSJean-Jacques Hiblot 	if (caps & MMC_MODE_4BIT)
1533d4d64889SMasahiro Yamada 		pr_debug("4, ");
1534d0c221feSJean-Jacques Hiblot 	if (caps & MMC_MODE_1BIT)
1535d4d64889SMasahiro Yamada 		pr_debug("1, ");
1536d4d64889SMasahiro Yamada 	pr_debug("\b\b] modes [");
15374c9d2aaaSJean-Jacques Hiblot 	for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++)
15384c9d2aaaSJean-Jacques Hiblot 		if (MMC_CAP(mode) & caps)
1539d4d64889SMasahiro Yamada 			pr_debug("%s, ", mmc_mode_name(mode));
1540d4d64889SMasahiro Yamada 	pr_debug("\b\b]\n");
15414c9d2aaaSJean-Jacques Hiblot }
15424c9d2aaaSJean-Jacques Hiblot #endif
15434c9d2aaaSJean-Jacques Hiblot 
1544d0c221feSJean-Jacques Hiblot struct mode_width_tuning {
1545d0c221feSJean-Jacques Hiblot 	enum bus_mode mode;
1546d0c221feSJean-Jacques Hiblot 	uint widths;
1547f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
1548634d4849SKishon Vijay Abraham I 	uint tuning;
1549f99c2efeSJean-Jacques Hiblot #endif
1550d0c221feSJean-Jacques Hiblot };
1551d0c221feSJean-Jacques Hiblot 
1552f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE)
1553bc1e3272SJean-Jacques Hiblot int mmc_voltage_to_mv(enum mmc_voltage voltage)
1554bc1e3272SJean-Jacques Hiblot {
1555bc1e3272SJean-Jacques Hiblot 	switch (voltage) {
1556bc1e3272SJean-Jacques Hiblot 	case MMC_SIGNAL_VOLTAGE_000: return 0;
1557bc1e3272SJean-Jacques Hiblot 	case MMC_SIGNAL_VOLTAGE_330: return 3300;
1558bc1e3272SJean-Jacques Hiblot 	case MMC_SIGNAL_VOLTAGE_180: return 1800;
1559bc1e3272SJean-Jacques Hiblot 	case MMC_SIGNAL_VOLTAGE_120: return 1200;
1560bc1e3272SJean-Jacques Hiblot 	}
1561bc1e3272SJean-Jacques Hiblot 	return -EINVAL;
1562bc1e3272SJean-Jacques Hiblot }
1563bc1e3272SJean-Jacques Hiblot 
1564aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage)
1565aff5d3c8SKishon Vijay Abraham I {
1566bc1e3272SJean-Jacques Hiblot 	int err;
1567bc1e3272SJean-Jacques Hiblot 
1568bc1e3272SJean-Jacques Hiblot 	if (mmc->signal_voltage == signal_voltage)
1569bc1e3272SJean-Jacques Hiblot 		return 0;
1570bc1e3272SJean-Jacques Hiblot 
1571aff5d3c8SKishon Vijay Abraham I 	mmc->signal_voltage = signal_voltage;
1572bc1e3272SJean-Jacques Hiblot 	err = mmc_set_ios(mmc);
1573bc1e3272SJean-Jacques Hiblot 	if (err)
1574d4d64889SMasahiro Yamada 		pr_debug("unable to set voltage (err %d)\n", err);
1575bc1e3272SJean-Jacques Hiblot 
1576bc1e3272SJean-Jacques Hiblot 	return err;
1577aff5d3c8SKishon Vijay Abraham I }
1578f99c2efeSJean-Jacques Hiblot #else
1579f99c2efeSJean-Jacques Hiblot static inline int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage)
1580f99c2efeSJean-Jacques Hiblot {
1581f99c2efeSJean-Jacques Hiblot 	return 0;
1582f99c2efeSJean-Jacques Hiblot }
1583f99c2efeSJean-Jacques Hiblot #endif
1584aff5d3c8SKishon Vijay Abraham I 
1585d0c221feSJean-Jacques Hiblot static const struct mode_width_tuning sd_modes_by_pref[] = {
1586f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1587f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
1588d0c221feSJean-Jacques Hiblot 	{
1589c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR104,
1590c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1591c10b85d6SJean-Jacques Hiblot 		.tuning = MMC_CMD_SEND_TUNING_BLOCK
1592c10b85d6SJean-Jacques Hiblot 	},
1593f99c2efeSJean-Jacques Hiblot #endif
1594c10b85d6SJean-Jacques Hiblot 	{
1595c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR50,
1596c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1597c10b85d6SJean-Jacques Hiblot 	},
1598c10b85d6SJean-Jacques Hiblot 	{
1599c10b85d6SJean-Jacques Hiblot 		.mode = UHS_DDR50,
1600c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1601c10b85d6SJean-Jacques Hiblot 	},
1602c10b85d6SJean-Jacques Hiblot 	{
1603c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR25,
1604c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1605c10b85d6SJean-Jacques Hiblot 	},
1606f99c2efeSJean-Jacques Hiblot #endif
1607c10b85d6SJean-Jacques Hiblot 	{
1608d0c221feSJean-Jacques Hiblot 		.mode = SD_HS,
1609d0c221feSJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1610d0c221feSJean-Jacques Hiblot 	},
1611f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1612d0c221feSJean-Jacques Hiblot 	{
1613c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR12,
1614c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1615c10b85d6SJean-Jacques Hiblot 	},
1616f99c2efeSJean-Jacques Hiblot #endif
1617c10b85d6SJean-Jacques Hiblot 	{
1618d0c221feSJean-Jacques Hiblot 		.mode = SD_LEGACY,
1619d0c221feSJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1620d0c221feSJean-Jacques Hiblot 	}
1621d0c221feSJean-Jacques Hiblot };
1622d0c221feSJean-Jacques Hiblot 
1623d0c221feSJean-Jacques Hiblot #define for_each_sd_mode_by_pref(caps, mwt) \
1624d0c221feSJean-Jacques Hiblot 	for (mwt = sd_modes_by_pref;\
1625d0c221feSJean-Jacques Hiblot 	     mwt < sd_modes_by_pref + ARRAY_SIZE(sd_modes_by_pref);\
1626d0c221feSJean-Jacques Hiblot 	     mwt++) \
1627d0c221feSJean-Jacques Hiblot 		if (caps & MMC_CAP(mwt->mode))
1628d0c221feSJean-Jacques Hiblot 
162901298da3SJean-Jacques Hiblot static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps)
16308ac8a263SJean-Jacques Hiblot {
16318ac8a263SJean-Jacques Hiblot 	int err;
1632d0c221feSJean-Jacques Hiblot 	uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT};
1633d0c221feSJean-Jacques Hiblot 	const struct mode_width_tuning *mwt;
1634f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1635c10b85d6SJean-Jacques Hiblot 	bool uhs_en = (mmc->ocr & OCR_S18R) ? true : false;
1636f99c2efeSJean-Jacques Hiblot #else
1637f99c2efeSJean-Jacques Hiblot 	bool uhs_en = false;
1638f99c2efeSJean-Jacques Hiblot #endif
1639c10b85d6SJean-Jacques Hiblot 	uint caps;
1640c10b85d6SJean-Jacques Hiblot 
164152d241dfSJean-Jacques Hiblot #ifdef DEBUG
164252d241dfSJean-Jacques Hiblot 	mmc_dump_capabilities("sd card", card_caps);
16431da8eb59SJean-Jacques Hiblot 	mmc_dump_capabilities("host", mmc->host_caps);
164452d241dfSJean-Jacques Hiblot #endif
16458ac8a263SJean-Jacques Hiblot 
16468ac8a263SJean-Jacques Hiblot 	/* Restrict card's capabilities by what the host can do */
16471da8eb59SJean-Jacques Hiblot 	caps = card_caps & mmc->host_caps;
16488ac8a263SJean-Jacques Hiblot 
1649c10b85d6SJean-Jacques Hiblot 	if (!uhs_en)
1650c10b85d6SJean-Jacques Hiblot 		caps &= ~UHS_CAPS;
1651c10b85d6SJean-Jacques Hiblot 
1652c10b85d6SJean-Jacques Hiblot 	for_each_sd_mode_by_pref(caps, mwt) {
1653d0c221feSJean-Jacques Hiblot 		uint *w;
16548ac8a263SJean-Jacques Hiblot 
1655d0c221feSJean-Jacques Hiblot 		for (w = widths; w < widths + ARRAY_SIZE(widths); w++) {
1656c10b85d6SJean-Jacques Hiblot 			if (*w & caps & mwt->widths) {
1657d4d64889SMasahiro Yamada 				pr_debug("trying mode %s width %d (at %d MHz)\n",
1658d0c221feSJean-Jacques Hiblot 					 mmc_mode_name(mwt->mode),
1659d0c221feSJean-Jacques Hiblot 					 bus_width(*w),
1660d0c221feSJean-Jacques Hiblot 					 mmc_mode2freq(mmc, mwt->mode) / 1000000);
1661d0c221feSJean-Jacques Hiblot 
1662d0c221feSJean-Jacques Hiblot 				/* configure the bus width (card + host) */
1663d0c221feSJean-Jacques Hiblot 				err = sd_select_bus_width(mmc, bus_width(*w));
16648ac8a263SJean-Jacques Hiblot 				if (err)
1665d0c221feSJean-Jacques Hiblot 					goto error;
1666d0c221feSJean-Jacques Hiblot 				mmc_set_bus_width(mmc, bus_width(*w));
16678ac8a263SJean-Jacques Hiblot 
1668d0c221feSJean-Jacques Hiblot 				/* configure the bus mode (card) */
1669d0c221feSJean-Jacques Hiblot 				err = sd_set_card_speed(mmc, mwt->mode);
16708ac8a263SJean-Jacques Hiblot 				if (err)
1671d0c221feSJean-Jacques Hiblot 					goto error;
16728ac8a263SJean-Jacques Hiblot 
1673d0c221feSJean-Jacques Hiblot 				/* configure the bus mode (host) */
1674d0c221feSJean-Jacques Hiblot 				mmc_select_mode(mmc, mwt->mode);
167535f67820SKishon Vijay Abraham I 				mmc_set_clock(mmc, mmc->tran_speed, false);
16768ac8a263SJean-Jacques Hiblot 
1677f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
1678c10b85d6SJean-Jacques Hiblot 				/* execute tuning if needed */
1679c10b85d6SJean-Jacques Hiblot 				if (mwt->tuning && !mmc_host_is_spi(mmc)) {
1680c10b85d6SJean-Jacques Hiblot 					err = mmc_execute_tuning(mmc,
1681c10b85d6SJean-Jacques Hiblot 								 mwt->tuning);
1682c10b85d6SJean-Jacques Hiblot 					if (err) {
1683d4d64889SMasahiro Yamada 						pr_debug("tuning failed\n");
1684c10b85d6SJean-Jacques Hiblot 						goto error;
1685c10b85d6SJean-Jacques Hiblot 					}
1686c10b85d6SJean-Jacques Hiblot 				}
1687f99c2efeSJean-Jacques Hiblot #endif
1688c10b85d6SJean-Jacques Hiblot 
16895b2e72f3SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE)
16908ac8a263SJean-Jacques Hiblot 				err = sd_read_ssr(mmc);
16910a4c2b09SPeng Fan 				if (err)
16925b2e72f3SJean-Jacques Hiblot 					pr_warn("unable to read ssr\n");
16935b2e72f3SJean-Jacques Hiblot #endif
16945b2e72f3SJean-Jacques Hiblot 				if (!err)
16958ac8a263SJean-Jacques Hiblot 					return 0;
1696d0c221feSJean-Jacques Hiblot 
1697d0c221feSJean-Jacques Hiblot error:
1698d0c221feSJean-Jacques Hiblot 				/* revert to a safer bus speed */
1699d0c221feSJean-Jacques Hiblot 				mmc_select_mode(mmc, SD_LEGACY);
170035f67820SKishon Vijay Abraham I 				mmc_set_clock(mmc, mmc->tran_speed, false);
1701d0c221feSJean-Jacques Hiblot 			}
1702d0c221feSJean-Jacques Hiblot 		}
1703d0c221feSJean-Jacques Hiblot 	}
1704d0c221feSJean-Jacques Hiblot 
1705d4d64889SMasahiro Yamada 	pr_err("unable to select a mode\n");
1706d0c221feSJean-Jacques Hiblot 	return -ENOTSUPP;
17078ac8a263SJean-Jacques Hiblot }
17088ac8a263SJean-Jacques Hiblot 
17097382e691SJean-Jacques Hiblot /*
17107382e691SJean-Jacques Hiblot  * read the compare the part of ext csd that is constant.
17117382e691SJean-Jacques Hiblot  * This can be used to check that the transfer is working
17127382e691SJean-Jacques Hiblot  * as expected.
17137382e691SJean-Jacques Hiblot  */
17147382e691SJean-Jacques Hiblot static int mmc_read_and_compare_ext_csd(struct mmc *mmc)
17157382e691SJean-Jacques Hiblot {
17167382e691SJean-Jacques Hiblot 	int err;
17177382e691SJean-Jacques Hiblot 	const u8 *ext_csd = mmc->ext_csd;
17187382e691SJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
17197382e691SJean-Jacques Hiblot 
17201de06b9fSJean-Jacques Hiblot 	if (mmc->version < MMC_VERSION_4)
17211de06b9fSJean-Jacques Hiblot 		return 0;
17221de06b9fSJean-Jacques Hiblot 
17237382e691SJean-Jacques Hiblot 	err = mmc_send_ext_csd(mmc, test_csd);
17247382e691SJean-Jacques Hiblot 	if (err)
17257382e691SJean-Jacques Hiblot 		return err;
17267382e691SJean-Jacques Hiblot 
17277382e691SJean-Jacques Hiblot 	/* Only compare read only fields */
17287382e691SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT]
17297382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_PARTITIONING_SUPPORT] &&
17307382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_HC_WP_GRP_SIZE]
17317382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_HC_WP_GRP_SIZE] &&
17327382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_REV]
17337382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_REV] &&
17347382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
17357382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] &&
17367382e691SJean-Jacques Hiblot 	    memcmp(&ext_csd[EXT_CSD_SEC_CNT],
17377382e691SJean-Jacques Hiblot 		   &test_csd[EXT_CSD_SEC_CNT], 4) == 0)
17387382e691SJean-Jacques Hiblot 		return 0;
17397382e691SJean-Jacques Hiblot 
17407382e691SJean-Jacques Hiblot 	return -EBADMSG;
17417382e691SJean-Jacques Hiblot }
17427382e691SJean-Jacques Hiblot 
1743f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE)
1744bc1e3272SJean-Jacques Hiblot static int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,
1745bc1e3272SJean-Jacques Hiblot 				  uint32_t allowed_mask)
1746bc1e3272SJean-Jacques Hiblot {
1747bc1e3272SJean-Jacques Hiblot 	u32 card_mask = 0;
1748bc1e3272SJean-Jacques Hiblot 
1749bc1e3272SJean-Jacques Hiblot 	switch (mode) {
1750bc1e3272SJean-Jacques Hiblot 	case MMC_HS_200:
1751bc1e3272SJean-Jacques Hiblot 		if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_8V)
1752bc1e3272SJean-Jacques Hiblot 			card_mask |= MMC_SIGNAL_VOLTAGE_180;
1753bc1e3272SJean-Jacques Hiblot 		if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_2V)
1754bc1e3272SJean-Jacques Hiblot 			card_mask |= MMC_SIGNAL_VOLTAGE_120;
1755bc1e3272SJean-Jacques Hiblot 		break;
1756bc1e3272SJean-Jacques Hiblot 	case MMC_DDR_52:
1757bc1e3272SJean-Jacques Hiblot 		if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V)
1758bc1e3272SJean-Jacques Hiblot 			card_mask |= MMC_SIGNAL_VOLTAGE_330 |
1759bc1e3272SJean-Jacques Hiblot 				     MMC_SIGNAL_VOLTAGE_180;
1760bc1e3272SJean-Jacques Hiblot 		if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_2V)
1761bc1e3272SJean-Jacques Hiblot 			card_mask |= MMC_SIGNAL_VOLTAGE_120;
1762bc1e3272SJean-Jacques Hiblot 		break;
1763bc1e3272SJean-Jacques Hiblot 	default:
1764bc1e3272SJean-Jacques Hiblot 		card_mask |= MMC_SIGNAL_VOLTAGE_330;
1765bc1e3272SJean-Jacques Hiblot 		break;
1766bc1e3272SJean-Jacques Hiblot 	}
1767bc1e3272SJean-Jacques Hiblot 
1768bc1e3272SJean-Jacques Hiblot 	while (card_mask & allowed_mask) {
1769bc1e3272SJean-Jacques Hiblot 		enum mmc_voltage best_match;
1770bc1e3272SJean-Jacques Hiblot 
1771bc1e3272SJean-Jacques Hiblot 		best_match = 1 << (ffs(card_mask & allowed_mask) - 1);
1772bc1e3272SJean-Jacques Hiblot 		if (!mmc_set_signal_voltage(mmc,  best_match))
1773bc1e3272SJean-Jacques Hiblot 			return 0;
1774bc1e3272SJean-Jacques Hiblot 
1775bc1e3272SJean-Jacques Hiblot 		allowed_mask &= ~best_match;
1776bc1e3272SJean-Jacques Hiblot 	}
1777bc1e3272SJean-Jacques Hiblot 
1778bc1e3272SJean-Jacques Hiblot 	return -ENOTSUPP;
1779bc1e3272SJean-Jacques Hiblot }
1780f99c2efeSJean-Jacques Hiblot #else
1781f99c2efeSJean-Jacques Hiblot static inline int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,
1782f99c2efeSJean-Jacques Hiblot 					 uint32_t allowed_mask)
1783f99c2efeSJean-Jacques Hiblot {
1784f99c2efeSJean-Jacques Hiblot 	return 0;
1785f99c2efeSJean-Jacques Hiblot }
1786f99c2efeSJean-Jacques Hiblot #endif
1787bc1e3272SJean-Jacques Hiblot 
17883862b854SJean-Jacques Hiblot static const struct mode_width_tuning mmc_modes_by_pref[] = {
1789f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
17908ac8a263SJean-Jacques Hiblot 	{
17913862b854SJean-Jacques Hiblot 		.mode = MMC_HS_200,
17923862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
1793634d4849SKishon Vijay Abraham I 		.tuning = MMC_CMD_SEND_TUNING_BLOCK_HS200
17943862b854SJean-Jacques Hiblot 	},
1795f99c2efeSJean-Jacques Hiblot #endif
17963862b854SJean-Jacques Hiblot 	{
17973862b854SJean-Jacques Hiblot 		.mode = MMC_DDR_52,
17983862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
17993862b854SJean-Jacques Hiblot 	},
18003862b854SJean-Jacques Hiblot 	{
18013862b854SJean-Jacques Hiblot 		.mode = MMC_HS_52,
18023862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
18033862b854SJean-Jacques Hiblot 	},
18043862b854SJean-Jacques Hiblot 	{
18053862b854SJean-Jacques Hiblot 		.mode = MMC_HS,
18063862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
18073862b854SJean-Jacques Hiblot 	},
18083862b854SJean-Jacques Hiblot 	{
18093862b854SJean-Jacques Hiblot 		.mode = MMC_LEGACY,
18103862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
18113862b854SJean-Jacques Hiblot 	}
18128ac8a263SJean-Jacques Hiblot };
18138ac8a263SJean-Jacques Hiblot 
18143862b854SJean-Jacques Hiblot #define for_each_mmc_mode_by_pref(caps, mwt) \
18153862b854SJean-Jacques Hiblot 	for (mwt = mmc_modes_by_pref;\
18163862b854SJean-Jacques Hiblot 	    mwt < mmc_modes_by_pref + ARRAY_SIZE(mmc_modes_by_pref);\
18173862b854SJean-Jacques Hiblot 	    mwt++) \
18183862b854SJean-Jacques Hiblot 		if (caps & MMC_CAP(mwt->mode))
18193862b854SJean-Jacques Hiblot 
18203862b854SJean-Jacques Hiblot static const struct ext_csd_bus_width {
18213862b854SJean-Jacques Hiblot 	uint cap;
18223862b854SJean-Jacques Hiblot 	bool is_ddr;
18233862b854SJean-Jacques Hiblot 	uint ext_csd_bits;
18243862b854SJean-Jacques Hiblot } ext_csd_bus_width[] = {
18253862b854SJean-Jacques Hiblot 	{MMC_MODE_8BIT, true, EXT_CSD_DDR_BUS_WIDTH_8},
18263862b854SJean-Jacques Hiblot 	{MMC_MODE_4BIT, true, EXT_CSD_DDR_BUS_WIDTH_4},
18273862b854SJean-Jacques Hiblot 	{MMC_MODE_8BIT, false, EXT_CSD_BUS_WIDTH_8},
18283862b854SJean-Jacques Hiblot 	{MMC_MODE_4BIT, false, EXT_CSD_BUS_WIDTH_4},
18293862b854SJean-Jacques Hiblot 	{MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1},
18303862b854SJean-Jacques Hiblot };
18313862b854SJean-Jacques Hiblot 
18323862b854SJean-Jacques Hiblot #define for_each_supported_width(caps, ddr, ecbv) \
18333862b854SJean-Jacques Hiblot 	for (ecbv = ext_csd_bus_width;\
18343862b854SJean-Jacques Hiblot 	    ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\
18353862b854SJean-Jacques Hiblot 	    ecbv++) \
18363862b854SJean-Jacques Hiblot 		if ((ddr == ecbv->is_ddr) && (caps & ecbv->cap))
18373862b854SJean-Jacques Hiblot 
183801298da3SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
18393862b854SJean-Jacques Hiblot {
18403862b854SJean-Jacques Hiblot 	int err;
18413862b854SJean-Jacques Hiblot 	const struct mode_width_tuning *mwt;
18423862b854SJean-Jacques Hiblot 	const struct ext_csd_bus_width *ecbw;
18433862b854SJean-Jacques Hiblot 
184452d241dfSJean-Jacques Hiblot #ifdef DEBUG
184552d241dfSJean-Jacques Hiblot 	mmc_dump_capabilities("mmc", card_caps);
18461da8eb59SJean-Jacques Hiblot 	mmc_dump_capabilities("host", mmc->host_caps);
184752d241dfSJean-Jacques Hiblot #endif
184852d241dfSJean-Jacques Hiblot 
18498ac8a263SJean-Jacques Hiblot 	/* Restrict card's capabilities by what the host can do */
18501da8eb59SJean-Jacques Hiblot 	card_caps &= mmc->host_caps;
18518ac8a263SJean-Jacques Hiblot 
18528ac8a263SJean-Jacques Hiblot 	/* Only version 4 of MMC supports wider bus widths */
18538ac8a263SJean-Jacques Hiblot 	if (mmc->version < MMC_VERSION_4)
18548ac8a263SJean-Jacques Hiblot 		return 0;
18558ac8a263SJean-Jacques Hiblot 
1856dfda9d88SJean-Jacques Hiblot 	if (!mmc->ext_csd) {
1857d4d64889SMasahiro Yamada 		pr_debug("No ext_csd found!\n"); /* this should enver happen */
1858dfda9d88SJean-Jacques Hiblot 		return -ENOTSUPP;
1859dfda9d88SJean-Jacques Hiblot 	}
1860dfda9d88SJean-Jacques Hiblot 
186101298da3SJean-Jacques Hiblot 	mmc_set_clock(mmc, mmc->legacy_speed, false);
186201298da3SJean-Jacques Hiblot 
186301298da3SJean-Jacques Hiblot 	for_each_mmc_mode_by_pref(card_caps, mwt) {
186401298da3SJean-Jacques Hiblot 		for_each_supported_width(card_caps & mwt->widths,
18653862b854SJean-Jacques Hiblot 					 mmc_is_mode_ddr(mwt->mode), ecbw) {
1866bc1e3272SJean-Jacques Hiblot 			enum mmc_voltage old_voltage;
1867d4d64889SMasahiro Yamada 			pr_debug("trying mode %s width %d (at %d MHz)\n",
18683862b854SJean-Jacques Hiblot 				 mmc_mode_name(mwt->mode),
18693862b854SJean-Jacques Hiblot 				 bus_width(ecbw->cap),
18703862b854SJean-Jacques Hiblot 				 mmc_mode2freq(mmc, mwt->mode) / 1000000);
1871bc1e3272SJean-Jacques Hiblot 			old_voltage = mmc->signal_voltage;
1872bc1e3272SJean-Jacques Hiblot 			err = mmc_set_lowest_voltage(mmc, mwt->mode,
1873bc1e3272SJean-Jacques Hiblot 						     MMC_ALL_SIGNAL_VOLTAGE);
1874bc1e3272SJean-Jacques Hiblot 			if (err)
1875bc1e3272SJean-Jacques Hiblot 				continue;
1876bc1e3272SJean-Jacques Hiblot 
18773862b854SJean-Jacques Hiblot 			/* configure the bus width (card + host) */
18783862b854SJean-Jacques Hiblot 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
18793862b854SJean-Jacques Hiblot 				    EXT_CSD_BUS_WIDTH,
18803862b854SJean-Jacques Hiblot 				    ecbw->ext_csd_bits & ~EXT_CSD_DDR_FLAG);
18813862b854SJean-Jacques Hiblot 			if (err)
18823862b854SJean-Jacques Hiblot 				goto error;
18833862b854SJean-Jacques Hiblot 			mmc_set_bus_width(mmc, bus_width(ecbw->cap));
18843862b854SJean-Jacques Hiblot 
18853862b854SJean-Jacques Hiblot 			/* configure the bus speed (card) */
18863862b854SJean-Jacques Hiblot 			err = mmc_set_card_speed(mmc, mwt->mode);
18873862b854SJean-Jacques Hiblot 			if (err)
18883862b854SJean-Jacques Hiblot 				goto error;
18893862b854SJean-Jacques Hiblot 
18908ac8a263SJean-Jacques Hiblot 			/*
18913862b854SJean-Jacques Hiblot 			 * configure the bus width AND the ddr mode (card)
18923862b854SJean-Jacques Hiblot 			 * The host side will be taken care of in the next step
18938ac8a263SJean-Jacques Hiblot 			 */
18943862b854SJean-Jacques Hiblot 			if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) {
18953862b854SJean-Jacques Hiblot 				err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
18963862b854SJean-Jacques Hiblot 						 EXT_CSD_BUS_WIDTH,
18973862b854SJean-Jacques Hiblot 						 ecbw->ext_csd_bits);
18983862b854SJean-Jacques Hiblot 				if (err)
18993862b854SJean-Jacques Hiblot 					goto error;
19008ac8a263SJean-Jacques Hiblot 			}
19018ac8a263SJean-Jacques Hiblot 
19023862b854SJean-Jacques Hiblot 			/* configure the bus mode (host) */
19033862b854SJean-Jacques Hiblot 			mmc_select_mode(mmc, mwt->mode);
190435f67820SKishon Vijay Abraham I 			mmc_set_clock(mmc, mmc->tran_speed, false);
1905f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
19068ac8a263SJean-Jacques Hiblot 
1907634d4849SKishon Vijay Abraham I 			/* execute tuning if needed */
1908634d4849SKishon Vijay Abraham I 			if (mwt->tuning) {
1909634d4849SKishon Vijay Abraham I 				err = mmc_execute_tuning(mmc, mwt->tuning);
1910634d4849SKishon Vijay Abraham I 				if (err) {
1911d4d64889SMasahiro Yamada 					pr_debug("tuning failed\n");
1912634d4849SKishon Vijay Abraham I 					goto error;
1913634d4849SKishon Vijay Abraham I 				}
1914634d4849SKishon Vijay Abraham I 			}
1915f99c2efeSJean-Jacques Hiblot #endif
1916634d4849SKishon Vijay Abraham I 
19173862b854SJean-Jacques Hiblot 			/* do a transfer to check the configuration */
19187382e691SJean-Jacques Hiblot 			err = mmc_read_and_compare_ext_csd(mmc);
19197382e691SJean-Jacques Hiblot 			if (!err)
19203862b854SJean-Jacques Hiblot 				return 0;
19213862b854SJean-Jacques Hiblot error:
1922bc1e3272SJean-Jacques Hiblot 			mmc_set_signal_voltage(mmc, old_voltage);
19233862b854SJean-Jacques Hiblot 			/* if an error occured, revert to a safer bus mode */
19243862b854SJean-Jacques Hiblot 			mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
19253862b854SJean-Jacques Hiblot 				   EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1);
19263862b854SJean-Jacques Hiblot 			mmc_select_mode(mmc, MMC_LEGACY);
19273862b854SJean-Jacques Hiblot 			mmc_set_bus_width(mmc, 1);
19283862b854SJean-Jacques Hiblot 		}
19298ac8a263SJean-Jacques Hiblot 	}
19308ac8a263SJean-Jacques Hiblot 
1931d8e3d420SJean-Jacques Hiblot 	pr_err("unable to select a mode\n");
19328ac8a263SJean-Jacques Hiblot 
19333862b854SJean-Jacques Hiblot 	return -ENOTSUPP;
19348ac8a263SJean-Jacques Hiblot }
19358ac8a263SJean-Jacques Hiblot 
1936dfda9d88SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc)
1937c744b6f6SJean-Jacques Hiblot {
1938c744b6f6SJean-Jacques Hiblot 	int err, i;
1939c744b6f6SJean-Jacques Hiblot 	u64 capacity;
1940c744b6f6SJean-Jacques Hiblot 	bool has_parts = false;
1941c744b6f6SJean-Jacques Hiblot 	bool part_completed;
194258a6fb7bSJean-Jacques Hiblot 	static const u32 mmc_versions[] = {
194358a6fb7bSJean-Jacques Hiblot 		MMC_VERSION_4,
194458a6fb7bSJean-Jacques Hiblot 		MMC_VERSION_4_1,
194558a6fb7bSJean-Jacques Hiblot 		MMC_VERSION_4_2,
194658a6fb7bSJean-Jacques Hiblot 		MMC_VERSION_4_3,
1947ace1bed3SJean-Jacques Hiblot 		MMC_VERSION_4_4,
194858a6fb7bSJean-Jacques Hiblot 		MMC_VERSION_4_41,
194958a6fb7bSJean-Jacques Hiblot 		MMC_VERSION_4_5,
195058a6fb7bSJean-Jacques Hiblot 		MMC_VERSION_5_0,
195158a6fb7bSJean-Jacques Hiblot 		MMC_VERSION_5_1
195258a6fb7bSJean-Jacques Hiblot 	};
195358a6fb7bSJean-Jacques Hiblot 
1954f7d5dffcSJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
1955c744b6f6SJean-Jacques Hiblot 
1956c744b6f6SJean-Jacques Hiblot 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4))
1957c744b6f6SJean-Jacques Hiblot 		return 0;
1958c744b6f6SJean-Jacques Hiblot 
1959c744b6f6SJean-Jacques Hiblot 	/* check  ext_csd version and capacity */
1960c744b6f6SJean-Jacques Hiblot 	err = mmc_send_ext_csd(mmc, ext_csd);
1961c744b6f6SJean-Jacques Hiblot 	if (err)
1962f7d5dffcSJean-Jacques Hiblot 		goto error;
1963f7d5dffcSJean-Jacques Hiblot 
1964f7d5dffcSJean-Jacques Hiblot 	/* store the ext csd for future reference */
1965f7d5dffcSJean-Jacques Hiblot 	if (!mmc->ext_csd)
1966f7d5dffcSJean-Jacques Hiblot 		mmc->ext_csd = malloc(MMC_MAX_BLOCK_LEN);
1967f7d5dffcSJean-Jacques Hiblot 	if (!mmc->ext_csd)
1968f7d5dffcSJean-Jacques Hiblot 		return -ENOMEM;
1969f7d5dffcSJean-Jacques Hiblot 	memcpy(mmc->ext_csd, ext_csd, MMC_MAX_BLOCK_LEN);
1970f7d5dffcSJean-Jacques Hiblot 
197176584e33SAlexander Kochetkov 	if (ext_csd[EXT_CSD_REV] >= ARRAY_SIZE(mmc_versions))
197258a6fb7bSJean-Jacques Hiblot 		return -EINVAL;
197358a6fb7bSJean-Jacques Hiblot 
197458a6fb7bSJean-Jacques Hiblot 	mmc->version = mmc_versions[ext_csd[EXT_CSD_REV]];
197558a6fb7bSJean-Jacques Hiblot 
197658a6fb7bSJean-Jacques Hiblot 	if (mmc->version >= MMC_VERSION_4_2) {
1977c744b6f6SJean-Jacques Hiblot 		/*
1978c744b6f6SJean-Jacques Hiblot 		 * According to the JEDEC Standard, the value of
1979c744b6f6SJean-Jacques Hiblot 		 * ext_csd's capacity is valid if the value is more
1980c744b6f6SJean-Jacques Hiblot 		 * than 2GB
1981c744b6f6SJean-Jacques Hiblot 		 */
1982c744b6f6SJean-Jacques Hiblot 		capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
1983c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
1984c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
1985c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
1986c744b6f6SJean-Jacques Hiblot 		capacity *= MMC_MAX_BLOCK_LEN;
1987c744b6f6SJean-Jacques Hiblot 		if ((capacity >> 20) > 2 * 1024)
1988c744b6f6SJean-Jacques Hiblot 			mmc->capacity_user = capacity;
1989c744b6f6SJean-Jacques Hiblot 	}
1990c744b6f6SJean-Jacques Hiblot 
1991c744b6f6SJean-Jacques Hiblot 	/* The partition data may be non-zero but it is only
1992c744b6f6SJean-Jacques Hiblot 	 * effective if PARTITION_SETTING_COMPLETED is set in
1993c744b6f6SJean-Jacques Hiblot 	 * EXT_CSD, so ignore any data if this bit is not set,
1994c744b6f6SJean-Jacques Hiblot 	 * except for enabling the high-capacity group size
1995c744b6f6SJean-Jacques Hiblot 	 * definition (see below).
1996c744b6f6SJean-Jacques Hiblot 	 */
1997c744b6f6SJean-Jacques Hiblot 	part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
1998c744b6f6SJean-Jacques Hiblot 			    EXT_CSD_PARTITION_SETTING_COMPLETED);
1999c744b6f6SJean-Jacques Hiblot 
2000c744b6f6SJean-Jacques Hiblot 	/* store the partition info of emmc */
2001c744b6f6SJean-Jacques Hiblot 	mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
2002c744b6f6SJean-Jacques Hiblot 	if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
2003c744b6f6SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_BOOT_MULT])
2004c744b6f6SJean-Jacques Hiblot 		mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
2005c744b6f6SJean-Jacques Hiblot 	if (part_completed &&
2006c744b6f6SJean-Jacques Hiblot 	    (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
2007c744b6f6SJean-Jacques Hiblot 		mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
2008c744b6f6SJean-Jacques Hiblot 
2009c744b6f6SJean-Jacques Hiblot 	mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
2010c744b6f6SJean-Jacques Hiblot 
2011c744b6f6SJean-Jacques Hiblot 	mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
2012c744b6f6SJean-Jacques Hiblot 
2013c744b6f6SJean-Jacques Hiblot 	for (i = 0; i < 4; i++) {
2014c744b6f6SJean-Jacques Hiblot 		int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
2015c744b6f6SJean-Jacques Hiblot 		uint mult = (ext_csd[idx + 2] << 16) +
2016c744b6f6SJean-Jacques Hiblot 			(ext_csd[idx + 1] << 8) + ext_csd[idx];
2017c744b6f6SJean-Jacques Hiblot 		if (mult)
2018c744b6f6SJean-Jacques Hiblot 			has_parts = true;
2019c744b6f6SJean-Jacques Hiblot 		if (!part_completed)
2020c744b6f6SJean-Jacques Hiblot 			continue;
2021c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] = mult;
2022c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] *=
2023c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
2024c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
2025c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] <<= 19;
2026c744b6f6SJean-Jacques Hiblot 	}
2027c744b6f6SJean-Jacques Hiblot 
2028173c06dfSJean-Jacques Hiblot #ifndef CONFIG_SPL_BUILD
2029c744b6f6SJean-Jacques Hiblot 	if (part_completed) {
2030c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size =
2031c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) +
2032c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) +
2033c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_ENH_SIZE_MULT];
2034c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
2035c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
2036c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size <<= 19;
2037c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_start =
2038c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) +
2039c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) +
2040c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) +
2041c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_ENH_START_ADDR];
2042c744b6f6SJean-Jacques Hiblot 		if (mmc->high_capacity)
2043c744b6f6SJean-Jacques Hiblot 			mmc->enh_user_start <<= 9;
2044c744b6f6SJean-Jacques Hiblot 	}
2045173c06dfSJean-Jacques Hiblot #endif
2046c744b6f6SJean-Jacques Hiblot 
2047c744b6f6SJean-Jacques Hiblot 	/*
2048c744b6f6SJean-Jacques Hiblot 	 * Host needs to enable ERASE_GRP_DEF bit if device is
2049c744b6f6SJean-Jacques Hiblot 	 * partitioned. This bit will be lost every time after a reset
2050c744b6f6SJean-Jacques Hiblot 	 * or power off. This will affect erase size.
2051c744b6f6SJean-Jacques Hiblot 	 */
2052c744b6f6SJean-Jacques Hiblot 	if (part_completed)
2053c744b6f6SJean-Jacques Hiblot 		has_parts = true;
2054c744b6f6SJean-Jacques Hiblot 	if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
2055c744b6f6SJean-Jacques Hiblot 	    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
2056c744b6f6SJean-Jacques Hiblot 		has_parts = true;
2057c744b6f6SJean-Jacques Hiblot 	if (has_parts) {
2058c744b6f6SJean-Jacques Hiblot 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
2059c744b6f6SJean-Jacques Hiblot 				 EXT_CSD_ERASE_GROUP_DEF, 1);
2060c744b6f6SJean-Jacques Hiblot 
2061c744b6f6SJean-Jacques Hiblot 		if (err)
2062f7d5dffcSJean-Jacques Hiblot 			goto error;
2063c744b6f6SJean-Jacques Hiblot 
2064c744b6f6SJean-Jacques Hiblot 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
2065c744b6f6SJean-Jacques Hiblot 	}
2066c744b6f6SJean-Jacques Hiblot 
2067c744b6f6SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
2068e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE)
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;
2072e6fa5a54SJean-Jacques Hiblot #endif
2073c744b6f6SJean-Jacques Hiblot 		/*
2074c744b6f6SJean-Jacques Hiblot 		 * if high capacity and partition setting completed
2075c744b6f6SJean-Jacques Hiblot 		 * SEC_COUNT is valid even if it is smaller than 2 GiB
2076c744b6f6SJean-Jacques Hiblot 		 * JEDEC Standard JESD84-B45, 6.2.4
2077c744b6f6SJean-Jacques Hiblot 		 */
2078c744b6f6SJean-Jacques Hiblot 		if (mmc->high_capacity && part_completed) {
2079c744b6f6SJean-Jacques Hiblot 			capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
2080c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
2081c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
2082c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
2083c744b6f6SJean-Jacques Hiblot 			capacity *= MMC_MAX_BLOCK_LEN;
2084c744b6f6SJean-Jacques Hiblot 			mmc->capacity_user = capacity;
2085c744b6f6SJean-Jacques Hiblot 		}
2086e6fa5a54SJean-Jacques Hiblot 	}
2087e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE)
2088e6fa5a54SJean-Jacques Hiblot 	else {
2089c744b6f6SJean-Jacques Hiblot 		/* Calculate the group size from the csd value. */
2090c744b6f6SJean-Jacques Hiblot 		int erase_gsz, erase_gmul;
2091c744b6f6SJean-Jacques Hiblot 
2092c744b6f6SJean-Jacques Hiblot 		erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
2093c744b6f6SJean-Jacques Hiblot 		erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
2094c744b6f6SJean-Jacques Hiblot 		mmc->erase_grp_size = (erase_gsz + 1)
2095c744b6f6SJean-Jacques Hiblot 			* (erase_gmul + 1);
2096c744b6f6SJean-Jacques Hiblot 	}
2097e6fa5a54SJean-Jacques Hiblot #endif
2098b7a6e2c9SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING)
2099c744b6f6SJean-Jacques Hiblot 	mmc->hc_wp_grp_size = 1024
2100c744b6f6SJean-Jacques Hiblot 		* ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
2101c744b6f6SJean-Jacques Hiblot 		* ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
2102b7a6e2c9SJean-Jacques Hiblot #endif
2103c744b6f6SJean-Jacques Hiblot 
2104c744b6f6SJean-Jacques Hiblot 	mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
2105c744b6f6SJean-Jacques Hiblot 
2106c744b6f6SJean-Jacques Hiblot 	return 0;
2107f7d5dffcSJean-Jacques Hiblot error:
2108f7d5dffcSJean-Jacques Hiblot 	if (mmc->ext_csd) {
2109f7d5dffcSJean-Jacques Hiblot 		free(mmc->ext_csd);
2110f7d5dffcSJean-Jacques Hiblot 		mmc->ext_csd = NULL;
2111f7d5dffcSJean-Jacques Hiblot 	}
2112f7d5dffcSJean-Jacques Hiblot 	return err;
2113c744b6f6SJean-Jacques Hiblot }
2114c744b6f6SJean-Jacques Hiblot 
2115fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc)
2116272cc70bSAndy Fleming {
2117f866a46dSStephen Warren 	int err, i;
2118272cc70bSAndy Fleming 	uint mult, freq;
2119c744b6f6SJean-Jacques Hiblot 	u64 cmult, csize;
2120272cc70bSAndy Fleming 	struct mmc_cmd cmd;
2121c40fdca6SSimon Glass 	struct blk_desc *bdesc;
2122272cc70bSAndy Fleming 
2123d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
2124d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
2125d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
2126d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
2127d52ebf10SThomas Chou 		cmd.cmdarg = 1;
2128d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
2129d52ebf10SThomas Chou 		if (err)
2130d52ebf10SThomas Chou 			return err;
2131d52ebf10SThomas Chou 	}
2132d52ebf10SThomas Chou #endif
2133d52ebf10SThomas Chou 
2134272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
2135d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
2136d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
2137272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
2138272cc70bSAndy Fleming 	cmd.cmdarg = 0;
2139272cc70bSAndy Fleming 
2140272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
2141272cc70bSAndy Fleming 
214283dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS
214383dc4227SKishon Vijay Abraham I 	if (err && (mmc->quirks & MMC_QUIRK_RETRY_SEND_CID)) {
214483dc4227SKishon Vijay Abraham I 		int retries = 4;
214583dc4227SKishon Vijay Abraham I 		/*
214683dc4227SKishon Vijay Abraham I 		 * It has been seen that SEND_CID may fail on the first
214783dc4227SKishon Vijay Abraham I 		 * attempt, let's try a few more time
214883dc4227SKishon Vijay Abraham I 		 */
214983dc4227SKishon Vijay Abraham I 		do {
215083dc4227SKishon Vijay Abraham I 			err = mmc_send_cmd(mmc, &cmd, NULL);
215183dc4227SKishon Vijay Abraham I 			if (!err)
215283dc4227SKishon Vijay Abraham I 				break;
215383dc4227SKishon Vijay Abraham I 		} while (retries--);
215483dc4227SKishon Vijay Abraham I 	}
215583dc4227SKishon Vijay Abraham I #endif
215683dc4227SKishon Vijay Abraham I 
2157272cc70bSAndy Fleming 	if (err)
2158272cc70bSAndy Fleming 		return err;
2159272cc70bSAndy Fleming 
2160272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
2161272cc70bSAndy Fleming 
2162272cc70bSAndy Fleming 	/*
2163272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
2164272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
2165272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
2166272cc70bSAndy Fleming 	 */
2167d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
2168272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
2169272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
2170272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
2171272cc70bSAndy Fleming 
2172272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
2173272cc70bSAndy Fleming 
2174272cc70bSAndy Fleming 		if (err)
2175272cc70bSAndy Fleming 			return err;
2176272cc70bSAndy Fleming 
2177272cc70bSAndy Fleming 		if (IS_SD(mmc))
2178998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
2179d52ebf10SThomas Chou 	}
2180272cc70bSAndy Fleming 
2181272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
2182272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
2183272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
2184272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
2185272cc70bSAndy Fleming 
2186272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
2187272cc70bSAndy Fleming 
2188272cc70bSAndy Fleming 	if (err)
2189272cc70bSAndy Fleming 		return err;
2190272cc70bSAndy Fleming 
2191998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
2192998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
2193998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
2194998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
2195272cc70bSAndy Fleming 
2196272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
21970b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
2198272cc70bSAndy Fleming 
2199272cc70bSAndy Fleming 		switch (version) {
2200272cc70bSAndy Fleming 		case 0:
2201272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
2202272cc70bSAndy Fleming 			break;
2203272cc70bSAndy Fleming 		case 1:
2204272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_4;
2205272cc70bSAndy Fleming 			break;
2206272cc70bSAndy Fleming 		case 2:
2207272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_2_2;
2208272cc70bSAndy Fleming 			break;
2209272cc70bSAndy Fleming 		case 3:
2210272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_3;
2211272cc70bSAndy Fleming 			break;
2212272cc70bSAndy Fleming 		case 4:
2213272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_4;
2214272cc70bSAndy Fleming 			break;
2215272cc70bSAndy Fleming 		default:
2216272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
2217272cc70bSAndy Fleming 			break;
2218272cc70bSAndy Fleming 		}
2219272cc70bSAndy Fleming 	}
2220272cc70bSAndy Fleming 
2221272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
22220b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
22230b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
2224272cc70bSAndy Fleming 
222535f9e196SJean-Jacques Hiblot 	mmc->legacy_speed = freq * mult;
222635f9e196SJean-Jacques Hiblot 	mmc_select_mode(mmc, MMC_LEGACY);
2227272cc70bSAndy Fleming 
2228ab71188cSMarkus Niebel 	mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
2229998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
2230e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE)
2231272cc70bSAndy Fleming 
2232272cc70bSAndy Fleming 	if (IS_SD(mmc))
2233272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
2234272cc70bSAndy Fleming 	else
2235998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
2236e6fa5a54SJean-Jacques Hiblot #endif
2237272cc70bSAndy Fleming 
2238272cc70bSAndy Fleming 	if (mmc->high_capacity) {
2239272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
2240272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
2241272cc70bSAndy Fleming 		cmult = 8;
2242272cc70bSAndy Fleming 	} else {
2243272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
2244272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
2245272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
2246272cc70bSAndy Fleming 	}
2247272cc70bSAndy Fleming 
2248f866a46dSStephen Warren 	mmc->capacity_user = (csize + 1) << (cmult + 2);
2249f866a46dSStephen Warren 	mmc->capacity_user *= mmc->read_bl_len;
2250f866a46dSStephen Warren 	mmc->capacity_boot = 0;
2251f866a46dSStephen Warren 	mmc->capacity_rpmb = 0;
2252f866a46dSStephen Warren 	for (i = 0; i < 4; i++)
2253f866a46dSStephen Warren 		mmc->capacity_gp[i] = 0;
2254272cc70bSAndy Fleming 
22558bfa195eSSimon Glass 	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
22568bfa195eSSimon Glass 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
2257272cc70bSAndy Fleming 
2258e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE)
22598bfa195eSSimon Glass 	if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
22608bfa195eSSimon Glass 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
2261e6fa5a54SJean-Jacques Hiblot #endif
2262272cc70bSAndy Fleming 
2263ab71188cSMarkus Niebel 	if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
2264ab71188cSMarkus Niebel 		cmd.cmdidx = MMC_CMD_SET_DSR;
2265ab71188cSMarkus Niebel 		cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
2266ab71188cSMarkus Niebel 		cmd.resp_type = MMC_RSP_NONE;
2267ab71188cSMarkus Niebel 		if (mmc_send_cmd(mmc, &cmd, NULL))
2268d8e3d420SJean-Jacques Hiblot 			pr_warn("MMC: SET_DSR failed\n");
2269ab71188cSMarkus Niebel 	}
2270ab71188cSMarkus Niebel 
2271272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
2272d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
2273272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
2274fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
2275272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
2276272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
2277272cc70bSAndy Fleming 
2278272cc70bSAndy Fleming 		if (err)
2279272cc70bSAndy Fleming 			return err;
2280d52ebf10SThomas Chou 	}
2281272cc70bSAndy Fleming 
2282e6f99a56SLei Wen 	/*
2283e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
2284e6f99a56SLei Wen 	 */
2285e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE)
2286e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
2287e6fa5a54SJean-Jacques Hiblot #endif
2288bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
2289c744b6f6SJean-Jacques Hiblot 
2290dfda9d88SJean-Jacques Hiblot 	err = mmc_startup_v4(mmc);
22919cf199ebSDiego Santa Cruz 	if (err)
22929cf199ebSDiego Santa Cruz 		return err;
2293f866a46dSStephen Warren 
2294c40fdca6SSimon Glass 	err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart);
2295f866a46dSStephen Warren 	if (err)
2296f866a46dSStephen Warren 		return err;
2297d23e2c09SSukumar Ghorai 
229801298da3SJean-Jacques Hiblot 	if (IS_SD(mmc)) {
229901298da3SJean-Jacques Hiblot 		err = sd_get_capabilities(mmc);
230001298da3SJean-Jacques Hiblot 		if (err)
230101298da3SJean-Jacques Hiblot 			return err;
230201298da3SJean-Jacques Hiblot 		err = sd_select_mode_and_width(mmc, mmc->card_caps);
230301298da3SJean-Jacques Hiblot 	} else {
230401298da3SJean-Jacques Hiblot 		err = mmc_get_capabilities(mmc);
230501298da3SJean-Jacques Hiblot 		if (err)
230601298da3SJean-Jacques Hiblot 			return err;
230701298da3SJean-Jacques Hiblot 		mmc_select_mode_and_width(mmc, mmc->card_caps);
230801298da3SJean-Jacques Hiblot 	}
2309272cc70bSAndy Fleming 
2310272cc70bSAndy Fleming 	if (err)
2311272cc70bSAndy Fleming 		return err;
2312272cc70bSAndy Fleming 
231301298da3SJean-Jacques Hiblot 	mmc->best_mode = mmc->selected_mode;
2314272cc70bSAndy Fleming 
23155af8f45cSAndrew Gabbasov 	/* Fix the block length for DDR mode */
23165af8f45cSAndrew Gabbasov 	if (mmc->ddr_mode) {
23175af8f45cSAndrew Gabbasov 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
2318e6fa5a54SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_WRITE)
23195af8f45cSAndrew Gabbasov 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
2320e6fa5a54SJean-Jacques Hiblot #endif
23215af8f45cSAndrew Gabbasov 	}
23225af8f45cSAndrew Gabbasov 
2323272cc70bSAndy Fleming 	/* fill in device description */
2324c40fdca6SSimon Glass 	bdesc = mmc_get_blk_desc(mmc);
2325c40fdca6SSimon Glass 	bdesc->lun = 0;
2326c40fdca6SSimon Glass 	bdesc->hwpart = 0;
2327c40fdca6SSimon Glass 	bdesc->type = 0;
2328c40fdca6SSimon Glass 	bdesc->blksz = mmc->read_bl_len;
2329c40fdca6SSimon Glass 	bdesc->log2blksz = LOG2(bdesc->blksz);
2330c40fdca6SSimon Glass 	bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len);
2331fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \
2332fc011f64SSjoerd Simons 		(defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \
2333fc011f64SSjoerd Simons 		!defined(CONFIG_USE_TINY_PRINTF))
2334c40fdca6SSimon Glass 	sprintf(bdesc->vendor, "Man %06x Snr %04x%04x",
2335babce5f6STaylor Hutt 		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
2336babce5f6STaylor Hutt 		(mmc->cid[3] >> 16) & 0xffff);
2337c40fdca6SSimon Glass 	sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
23380b453ffeSRabin Vincent 		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
2339babce5f6STaylor Hutt 		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
2340babce5f6STaylor Hutt 		(mmc->cid[2] >> 24) & 0xff);
2341c40fdca6SSimon Glass 	sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
2342babce5f6STaylor Hutt 		(mmc->cid[2] >> 16) & 0xf);
234356196826SPaul Burton #else
2344c40fdca6SSimon Glass 	bdesc->vendor[0] = 0;
2345c40fdca6SSimon Glass 	bdesc->product[0] = 0;
2346c40fdca6SSimon Glass 	bdesc->revision[0] = 0;
234756196826SPaul Burton #endif
2348122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
2349c40fdca6SSimon Glass 	part_init(bdesc);
2350122efd43SMikhail Kshevetskiy #endif
2351272cc70bSAndy Fleming 
2352272cc70bSAndy Fleming 	return 0;
2353272cc70bSAndy Fleming }
2354272cc70bSAndy Fleming 
2355fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc)
2356272cc70bSAndy Fleming {
2357272cc70bSAndy Fleming 	struct mmc_cmd cmd;
2358272cc70bSAndy Fleming 	int err;
2359272cc70bSAndy Fleming 
2360272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
2361272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
236293bfd616SPantelis Antoniou 	cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa;
2363272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
2364272cc70bSAndy Fleming 
2365272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
2366272cc70bSAndy Fleming 
2367272cc70bSAndy Fleming 	if (err)
2368272cc70bSAndy Fleming 		return err;
2369272cc70bSAndy Fleming 
2370998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
2371915ffa52SJaehoon Chung 		return -EOPNOTSUPP;
2372272cc70bSAndy Fleming 	else
2373272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
2374272cc70bSAndy Fleming 
2375272cc70bSAndy Fleming 	return 0;
2376272cc70bSAndy Fleming }
2377272cc70bSAndy Fleming 
2378c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
237995de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */
238095de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void)
238195de9ab2SPaul Kocialkowski {
238295de9ab2SPaul Kocialkowski }
238305cbeb7cSSimon Glass #endif
238495de9ab2SPaul Kocialkowski 
23852051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc)
23862051aefeSPeng Fan {
2387c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
238806ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR)
23892051aefeSPeng Fan 	int ret;
23902051aefeSPeng Fan 
23912051aefeSPeng Fan 	ret = device_get_supply_regulator(mmc->dev, "vmmc-supply",
239206ec045fSJean-Jacques Hiblot 					  &mmc->vmmc_supply);
239306ec045fSJean-Jacques Hiblot 	if (ret)
2394d4d64889SMasahiro Yamada 		pr_debug("%s: No vmmc supply\n", mmc->dev->name);
23952051aefeSPeng Fan 
239606ec045fSJean-Jacques Hiblot 	ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply",
239706ec045fSJean-Jacques Hiblot 					  &mmc->vqmmc_supply);
239806ec045fSJean-Jacques Hiblot 	if (ret)
2399d4d64889SMasahiro Yamada 		pr_debug("%s: No vqmmc supply\n", mmc->dev->name);
24002051aefeSPeng Fan #endif
240105cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */
240205cbeb7cSSimon Glass 	/*
240305cbeb7cSSimon Glass 	 * Driver model should use a regulator, as above, rather than calling
240405cbeb7cSSimon Glass 	 * out to board code.
240505cbeb7cSSimon Glass 	 */
240605cbeb7cSSimon Glass 	board_mmc_power_init();
240705cbeb7cSSimon Glass #endif
24082051aefeSPeng Fan 	return 0;
24092051aefeSPeng Fan }
24102051aefeSPeng Fan 
2411fb7c3bebSKishon Vijay Abraham I /*
2412fb7c3bebSKishon Vijay Abraham I  * put the host in the initial state:
2413fb7c3bebSKishon Vijay Abraham I  * - turn on Vdd (card power supply)
2414fb7c3bebSKishon Vijay Abraham I  * - configure the bus width and clock to minimal values
2415fb7c3bebSKishon Vijay Abraham I  */
2416fb7c3bebSKishon Vijay Abraham I static void mmc_set_initial_state(struct mmc *mmc)
2417fb7c3bebSKishon Vijay Abraham I {
2418fb7c3bebSKishon Vijay Abraham I 	int err;
2419fb7c3bebSKishon Vijay Abraham I 
2420fb7c3bebSKishon Vijay Abraham I 	/* First try to set 3.3V. If it fails set to 1.8V */
2421fb7c3bebSKishon Vijay Abraham I 	err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_330);
2422fb7c3bebSKishon Vijay Abraham I 	if (err != 0)
2423fb7c3bebSKishon Vijay Abraham I 		err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_180);
2424fb7c3bebSKishon Vijay Abraham I 	if (err != 0)
2425d8e3d420SJean-Jacques Hiblot 		pr_warn("mmc: failed to set signal voltage\n");
2426fb7c3bebSKishon Vijay Abraham I 
2427fb7c3bebSKishon Vijay Abraham I 	mmc_select_mode(mmc, MMC_LEGACY);
2428fb7c3bebSKishon Vijay Abraham I 	mmc_set_bus_width(mmc, 1);
242935f67820SKishon Vijay Abraham I 	mmc_set_clock(mmc, 0, false);
2430fb7c3bebSKishon Vijay Abraham I }
2431fb7c3bebSKishon Vijay Abraham I 
2432fb7c3bebSKishon Vijay Abraham I static int mmc_power_on(struct mmc *mmc)
2433fb7c3bebSKishon Vijay Abraham I {
2434fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR)
2435fb7c3bebSKishon Vijay Abraham I 	if (mmc->vmmc_supply) {
2436fb7c3bebSKishon Vijay Abraham I 		int ret = regulator_set_enable(mmc->vmmc_supply, true);
2437fb7c3bebSKishon Vijay Abraham I 
2438fb7c3bebSKishon Vijay Abraham I 		if (ret) {
2439fb7c3bebSKishon Vijay Abraham I 			puts("Error enabling VMMC supply\n");
2440fb7c3bebSKishon Vijay Abraham I 			return ret;
2441fb7c3bebSKishon Vijay Abraham I 		}
2442fb7c3bebSKishon Vijay Abraham I 	}
2443fb7c3bebSKishon Vijay Abraham I #endif
2444fb7c3bebSKishon Vijay Abraham I 	return 0;
2445fb7c3bebSKishon Vijay Abraham I }
2446fb7c3bebSKishon Vijay Abraham I 
2447fb7c3bebSKishon Vijay Abraham I static int mmc_power_off(struct mmc *mmc)
2448fb7c3bebSKishon Vijay Abraham I {
24499546eb92SJaehoon Chung 	mmc_set_clock(mmc, 0, true);
2450fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR)
2451fb7c3bebSKishon Vijay Abraham I 	if (mmc->vmmc_supply) {
2452fb7c3bebSKishon Vijay Abraham I 		int ret = regulator_set_enable(mmc->vmmc_supply, false);
2453fb7c3bebSKishon Vijay Abraham I 
2454fb7c3bebSKishon Vijay Abraham I 		if (ret) {
2455d4d64889SMasahiro Yamada 			pr_debug("Error disabling VMMC supply\n");
2456fb7c3bebSKishon Vijay Abraham I 			return ret;
2457fb7c3bebSKishon Vijay Abraham I 		}
2458fb7c3bebSKishon Vijay Abraham I 	}
2459fb7c3bebSKishon Vijay Abraham I #endif
2460fb7c3bebSKishon Vijay Abraham I 	return 0;
2461fb7c3bebSKishon Vijay Abraham I }
2462fb7c3bebSKishon Vijay Abraham I 
2463fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc)
2464fb7c3bebSKishon Vijay Abraham I {
2465fb7c3bebSKishon Vijay Abraham I 	int ret;
2466fb7c3bebSKishon Vijay Abraham I 
2467fb7c3bebSKishon Vijay Abraham I 	ret = mmc_power_off(mmc);
2468fb7c3bebSKishon Vijay Abraham I 	if (ret)
2469fb7c3bebSKishon Vijay Abraham I 		return ret;
2470fb7c3bebSKishon Vijay Abraham I 	/*
2471fb7c3bebSKishon Vijay Abraham I 	 * SD spec recommends at least 1ms of delay. Let's wait for 2ms
2472fb7c3bebSKishon Vijay Abraham I 	 * to be on the safer side.
2473fb7c3bebSKishon Vijay Abraham I 	 */
2474fb7c3bebSKishon Vijay Abraham I 	udelay(2000);
2475fb7c3bebSKishon Vijay Abraham I 	return mmc_power_on(mmc);
2476fb7c3bebSKishon Vijay Abraham I }
2477fb7c3bebSKishon Vijay Abraham I 
2478e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc)
2479272cc70bSAndy Fleming {
24808ca51e51SSimon Glass 	bool no_card;
2481c10b85d6SJean-Jacques Hiblot 	bool uhs_en = supports_uhs(mmc->cfg->host_caps);
2482afd5932bSMacpaul Lin 	int err;
2483272cc70bSAndy Fleming 
24841da8eb59SJean-Jacques Hiblot 	/*
24851da8eb59SJean-Jacques Hiblot 	 * all hosts are capable of 1 bit bus-width and able to use the legacy
24861da8eb59SJean-Jacques Hiblot 	 * timings.
24871da8eb59SJean-Jacques Hiblot 	 */
24881da8eb59SJean-Jacques Hiblot 	mmc->host_caps = mmc->cfg->host_caps | MMC_CAP(SD_LEGACY) |
24891da8eb59SJean-Jacques Hiblot 			 MMC_CAP(MMC_LEGACY) | MMC_MODE_1BIT;
249004a2ea24SJean-Jacques Hiblot 
24912f516e4aSJun Nie #if !defined(CONFIG_MMC_BROKEN_CD)
2492ab769f22SPantelis Antoniou 	/* we pretend there's no card when init is NULL */
24938ca51e51SSimon Glass 	no_card = mmc_getcd(mmc) == 0;
24942f516e4aSJun Nie #else
24952f516e4aSJun Nie 	no_card = 0;
24962f516e4aSJun Nie #endif
2497e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
24988ca51e51SSimon Glass 	no_card = no_card || (mmc->cfg->ops->init == NULL);
24998ca51e51SSimon Glass #endif
25008ca51e51SSimon Glass 	if (no_card) {
250148972d90SThierry Reding 		mmc->has_init = 0;
250256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2503d4d64889SMasahiro Yamada 		pr_err("MMC: no card present\n");
250456196826SPaul Burton #endif
2505915ffa52SJaehoon Chung 		return -ENOMEDIUM;
250648972d90SThierry Reding 	}
250748972d90SThierry Reding 
2508bc897b1dSLei Wen 	if (mmc->has_init)
2509bc897b1dSLei Wen 		return 0;
2510bc897b1dSLei Wen 
25115a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
25125a8dbdc6SYangbo Lu 	mmc_adapter_card_type_ident();
25135a8dbdc6SYangbo Lu #endif
25142051aefeSPeng Fan 	err = mmc_power_init(mmc);
25152051aefeSPeng Fan 	if (err)
25162051aefeSPeng Fan 		return err;
251795de9ab2SPaul Kocialkowski 
251883dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS
251983dc4227SKishon Vijay Abraham I 	mmc->quirks = MMC_QUIRK_RETRY_SET_BLOCKLEN |
252083dc4227SKishon Vijay Abraham I 		      MMC_QUIRK_RETRY_SEND_CID;
252183dc4227SKishon Vijay Abraham I #endif
252283dc4227SKishon Vijay Abraham I 
252304a2ea24SJean-Jacques Hiblot 	err = mmc_power_cycle(mmc);
252404a2ea24SJean-Jacques Hiblot 	if (err) {
252504a2ea24SJean-Jacques Hiblot 		/*
252604a2ea24SJean-Jacques Hiblot 		 * if power cycling is not supported, we should not try
252704a2ea24SJean-Jacques Hiblot 		 * to use the UHS modes, because we wouldn't be able to
252804a2ea24SJean-Jacques Hiblot 		 * recover from an error during the UHS initialization.
252904a2ea24SJean-Jacques Hiblot 		 */
2530d4d64889SMasahiro Yamada 		pr_debug("Unable to do a full power cycle. Disabling the UHS modes for safety\n");
253104a2ea24SJean-Jacques Hiblot 		uhs_en = false;
253204a2ea24SJean-Jacques Hiblot 		mmc->host_caps &= ~UHS_CAPS;
2533fb7c3bebSKishon Vijay Abraham I 		err = mmc_power_on(mmc);
253404a2ea24SJean-Jacques Hiblot 	}
2535fb7c3bebSKishon Vijay Abraham I 	if (err)
2536fb7c3bebSKishon Vijay Abraham I 		return err;
2537fb7c3bebSKishon Vijay Abraham I 
2538e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
25398ca51e51SSimon Glass 	/* The device has already been probed ready for use */
25408ca51e51SSimon Glass #else
2541ab769f22SPantelis Antoniou 	/* made sure it's not NULL earlier */
254293bfd616SPantelis Antoniou 	err = mmc->cfg->ops->init(mmc);
2543272cc70bSAndy Fleming 	if (err)
2544272cc70bSAndy Fleming 		return err;
25458ca51e51SSimon Glass #endif
2546786e8f81SAndrew Gabbasov 	mmc->ddr_mode = 0;
2547aff5d3c8SKishon Vijay Abraham I 
2548c10b85d6SJean-Jacques Hiblot retry:
2549fb7c3bebSKishon Vijay Abraham I 	mmc_set_initial_state(mmc);
2550318a7a57SJean-Jacques Hiblot 	mmc_send_init_stream(mmc);
2551318a7a57SJean-Jacques Hiblot 
2552272cc70bSAndy Fleming 	/* Reset the Card */
2553272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
2554272cc70bSAndy Fleming 
2555272cc70bSAndy Fleming 	if (err)
2556272cc70bSAndy Fleming 		return err;
2557272cc70bSAndy Fleming 
2558bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
2559c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->hwpart = 0;
2560bc897b1dSLei Wen 
2561272cc70bSAndy Fleming 	/* Test for SD version 2 */
2562272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
2563272cc70bSAndy Fleming 
2564272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
2565c10b85d6SJean-Jacques Hiblot 	err = sd_send_op_cond(mmc, uhs_en);
2566c10b85d6SJean-Jacques Hiblot 	if (err && uhs_en) {
2567c10b85d6SJean-Jacques Hiblot 		uhs_en = false;
2568c10b85d6SJean-Jacques Hiblot 		mmc_power_cycle(mmc);
2569c10b85d6SJean-Jacques Hiblot 		goto retry;
2570c10b85d6SJean-Jacques Hiblot 	}
2571272cc70bSAndy Fleming 
2572272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
2573915ffa52SJaehoon Chung 	if (err == -ETIMEDOUT) {
2574272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
2575272cc70bSAndy Fleming 
2576bd47c135SAndrew Gabbasov 		if (err) {
257756196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2578d8e3d420SJean-Jacques Hiblot 			pr_err("Card did not respond to voltage select!\n");
257956196826SPaul Burton #endif
2580915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
2581272cc70bSAndy Fleming 		}
2582272cc70bSAndy Fleming 	}
2583272cc70bSAndy Fleming 
2584bd47c135SAndrew Gabbasov 	if (!err)
2585e9550449SChe-Liang Chiou 		mmc->init_in_progress = 1;
2586e9550449SChe-Liang Chiou 
2587e9550449SChe-Liang Chiou 	return err;
2588e9550449SChe-Liang Chiou }
2589e9550449SChe-Liang Chiou 
2590e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc)
2591e9550449SChe-Liang Chiou {
2592e9550449SChe-Liang Chiou 	int err = 0;
2593e9550449SChe-Liang Chiou 
2594bd47c135SAndrew Gabbasov 	mmc->init_in_progress = 0;
2595e9550449SChe-Liang Chiou 	if (mmc->op_cond_pending)
2596e9550449SChe-Liang Chiou 		err = mmc_complete_op_cond(mmc);
2597e9550449SChe-Liang Chiou 
2598e9550449SChe-Liang Chiou 	if (!err)
2599bc897b1dSLei Wen 		err = mmc_startup(mmc);
2600bc897b1dSLei Wen 	if (err)
2601bc897b1dSLei Wen 		mmc->has_init = 0;
2602bc897b1dSLei Wen 	else
2603bc897b1dSLei Wen 		mmc->has_init = 1;
2604e9550449SChe-Liang Chiou 	return err;
2605e9550449SChe-Liang Chiou }
2606e9550449SChe-Liang Chiou 
2607e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc)
2608e9550449SChe-Liang Chiou {
2609bd47c135SAndrew Gabbasov 	int err = 0;
2610ce9eca94SMarek Vasut 	__maybe_unused unsigned start;
2611c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
261233fb211dSSimon Glass 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev);
2613e9550449SChe-Liang Chiou 
261433fb211dSSimon Glass 	upriv->mmc = mmc;
261533fb211dSSimon Glass #endif
2616e9550449SChe-Liang Chiou 	if (mmc->has_init)
2617e9550449SChe-Liang Chiou 		return 0;
2618d803fea5SMateusz Zalega 
2619d803fea5SMateusz Zalega 	start = get_timer(0);
2620d803fea5SMateusz Zalega 
2621e9550449SChe-Liang Chiou 	if (!mmc->init_in_progress)
2622e9550449SChe-Liang Chiou 		err = mmc_start_init(mmc);
2623e9550449SChe-Liang Chiou 
2624bd47c135SAndrew Gabbasov 	if (!err)
2625e9550449SChe-Liang Chiou 		err = mmc_complete_init(mmc);
2626919b4858SJagan Teki 	if (err)
2627d4d64889SMasahiro Yamada 		pr_info("%s: %d, time %lu\n", __func__, err, get_timer(start));
2628919b4858SJagan Teki 
2629bc897b1dSLei Wen 	return err;
2630272cc70bSAndy Fleming }
2631272cc70bSAndy Fleming 
2632ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val)
2633ab71188cSMarkus Niebel {
2634ab71188cSMarkus Niebel 	mmc->dsr = val;
2635ab71188cSMarkus Niebel 	return 0;
2636ab71188cSMarkus Niebel }
2637ab71188cSMarkus Niebel 
2638cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */
2639cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis)
2640272cc70bSAndy Fleming {
2641272cc70bSAndy Fleming 	return -1;
2642272cc70bSAndy Fleming }
2643272cc70bSAndy Fleming 
2644cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */
2645cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis)
2646cee9ab7cSJeroen Hofstee {
2647cee9ab7cSJeroen Hofstee 	return -1;
2648cee9ab7cSJeroen Hofstee }
2649272cc70bSAndy Fleming 
2650e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit)
2651e9550449SChe-Liang Chiou {
2652e9550449SChe-Liang Chiou 	mmc->preinit = preinit;
2653e9550449SChe-Liang Chiou }
2654e9550449SChe-Liang Chiou 
26558a856db2SFaiz Abbas #if CONFIG_IS_ENABLED(DM_MMC)
26568e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
26578e3332e2SSjoerd Simons {
26584a1db6d8SSimon Glass 	int ret, i;
26598e3332e2SSjoerd Simons 	struct uclass *uc;
26604a1db6d8SSimon Glass 	struct udevice *dev;
26618e3332e2SSjoerd Simons 
26628e3332e2SSjoerd Simons 	ret = uclass_get(UCLASS_MMC, &uc);
26638e3332e2SSjoerd Simons 	if (ret)
26648e3332e2SSjoerd Simons 		return ret;
26658e3332e2SSjoerd Simons 
26664a1db6d8SSimon Glass 	/*
26674a1db6d8SSimon Glass 	 * Try to add them in sequence order. Really with driver model we
26684a1db6d8SSimon Glass 	 * should allow holes, but the current MMC list does not allow that.
26694a1db6d8SSimon Glass 	 * So if we request 0, 1, 3 we will get 0, 1, 2.
26704a1db6d8SSimon Glass 	 */
26714a1db6d8SSimon Glass 	for (i = 0; ; i++) {
26724a1db6d8SSimon Glass 		ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev);
26734a1db6d8SSimon Glass 		if (ret == -ENODEV)
26744a1db6d8SSimon Glass 			break;
26754a1db6d8SSimon Glass 	}
26764a1db6d8SSimon Glass 	uclass_foreach_dev(dev, uc) {
26774a1db6d8SSimon Glass 		ret = device_probe(dev);
26788e3332e2SSjoerd Simons 		if (ret)
2679d8e3d420SJean-Jacques Hiblot 			pr_err("%s - probe failed: %d\n", dev->name, ret);
26808e3332e2SSjoerd Simons 	}
26818e3332e2SSjoerd Simons 
26828e3332e2SSjoerd Simons 	return 0;
26838e3332e2SSjoerd Simons }
26848e3332e2SSjoerd Simons #else
26858e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
26868e3332e2SSjoerd Simons {
26878e3332e2SSjoerd Simons 	if (board_mmc_init(bis) < 0)
26888e3332e2SSjoerd Simons 		cpu_mmc_init(bis);
26898e3332e2SSjoerd Simons 
26908e3332e2SSjoerd Simons 	return 0;
26918e3332e2SSjoerd Simons }
26928e3332e2SSjoerd Simons #endif
2693e9550449SChe-Liang Chiou 
2694272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
2695272cc70bSAndy Fleming {
26961b26bab1SDaniel Kochmański 	static int initialized = 0;
26978e3332e2SSjoerd Simons 	int ret;
26981b26bab1SDaniel Kochmański 	if (initialized)	/* Avoid initializing mmc multiple times */
26991b26bab1SDaniel Kochmański 		return 0;
27001b26bab1SDaniel Kochmański 	initialized = 1;
27011b26bab1SDaniel Kochmański 
2702c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK)
2703b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY)
2704c40fdca6SSimon Glass 	mmc_list_init();
2705c40fdca6SSimon Glass #endif
2706b5b838f1SMarek Vasut #endif
27078e3332e2SSjoerd Simons 	ret = mmc_probe(bis);
27088e3332e2SSjoerd Simons 	if (ret)
27098e3332e2SSjoerd Simons 		return ret;
2710272cc70bSAndy Fleming 
2711bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD
2712272cc70bSAndy Fleming 	print_mmc_devices(',');
2713bb0dc108SYing Zhang #endif
2714272cc70bSAndy Fleming 
2715c40fdca6SSimon Glass 	mmc_do_preinit();
2716272cc70bSAndy Fleming 	return 0;
2717272cc70bSAndy Fleming }
2718cd3d4880STomas Melin 
2719cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE
2720cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc)
2721cd3d4880STomas Melin {
2722cd3d4880STomas Melin 	int err;
2723cd3d4880STomas Melin 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
2724cd3d4880STomas Melin 
2725cd3d4880STomas Melin 	err = mmc_send_ext_csd(mmc, ext_csd);
2726cd3d4880STomas Melin 	if (err) {
2727cd3d4880STomas Melin 		puts("Could not get ext_csd register values\n");
2728cd3d4880STomas Melin 		return err;
2729cd3d4880STomas Melin 	}
2730cd3d4880STomas Melin 
2731cd3d4880STomas Melin 	if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) {
2732cd3d4880STomas Melin 		puts("Background operations not supported on device\n");
2733cd3d4880STomas Melin 		return -EMEDIUMTYPE;
2734cd3d4880STomas Melin 	}
2735cd3d4880STomas Melin 
2736cd3d4880STomas Melin 	if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) {
2737cd3d4880STomas Melin 		puts("Background operations already enabled\n");
2738cd3d4880STomas Melin 		return 0;
2739cd3d4880STomas Melin 	}
2740cd3d4880STomas Melin 
2741cd3d4880STomas Melin 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1);
2742cd3d4880STomas Melin 	if (err) {
2743cd3d4880STomas Melin 		puts("Failed to enable manual background operations\n");
2744cd3d4880STomas Melin 		return err;
2745cd3d4880STomas Melin 	}
2746cd3d4880STomas Melin 
2747cd3d4880STomas Melin 	puts("Enabled manual background operations\n");
2748cd3d4880STomas Melin 
2749cd3d4880STomas Melin 	return 0;
2750cd3d4880STomas Melin }
2751cd3d4880STomas Melin #endif
2752