xref: /openbmc/u-boot/drivers/mmc/mmc.c (revision cf17789e)
1272cc70bSAndy Fleming /*
2272cc70bSAndy Fleming  * Copyright 2008, Freescale Semiconductor, Inc
3272cc70bSAndy Fleming  * Andy Fleming
4272cc70bSAndy Fleming  *
5272cc70bSAndy Fleming  * Based vaguely on the Linux code
6272cc70bSAndy Fleming  *
71a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
8272cc70bSAndy Fleming  */
9272cc70bSAndy Fleming 
10272cc70bSAndy Fleming #include <config.h>
11272cc70bSAndy Fleming #include <common.h>
12272cc70bSAndy Fleming #include <command.h>
138e3332e2SSjoerd Simons #include <dm.h>
148e3332e2SSjoerd Simons #include <dm/device-internal.h>
15d4622df3SStephen Warren #include <errno.h>
16272cc70bSAndy Fleming #include <mmc.h>
17272cc70bSAndy Fleming #include <part.h>
182051aefeSPeng Fan #include <power/regulator.h>
19272cc70bSAndy Fleming #include <malloc.h>
20cf92e05cSSimon Glass #include <memalign.h>
21272cc70bSAndy Fleming #include <linux/list.h>
229b1f942cSRabin Vincent #include <div64.h>
23da61fa5fSPaul Burton #include "mmc_private.h"
24272cc70bSAndy Fleming 
253697e599SPeng Fan static const unsigned int sd_au_size[] = {
263697e599SPeng Fan 	0,		SZ_16K / 512,		SZ_32K / 512,
273697e599SPeng Fan 	SZ_64K / 512,	SZ_128K / 512,		SZ_256K / 512,
283697e599SPeng Fan 	SZ_512K / 512,	SZ_1M / 512,		SZ_2M / 512,
293697e599SPeng Fan 	SZ_4M / 512,	SZ_8M / 512,		(SZ_8M + SZ_4M) / 512,
303697e599SPeng Fan 	SZ_16M / 512,	(SZ_16M + SZ_8M) / 512,	SZ_32M / 512,	SZ_64M / 512,
313697e599SPeng Fan };
323697e599SPeng Fan 
33aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage);
34fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc);
3501298da3SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps);
36aff5d3c8SKishon Vijay Abraham I 
37b5b838f1SMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY)
38b5b838f1SMarek Vasut static struct mmc mmc_static;
39b5b838f1SMarek Vasut struct mmc *find_mmc_device(int dev_num)
40b5b838f1SMarek Vasut {
41b5b838f1SMarek Vasut 	return &mmc_static;
42b5b838f1SMarek Vasut }
43b5b838f1SMarek Vasut 
44b5b838f1SMarek Vasut void mmc_do_preinit(void)
45b5b838f1SMarek Vasut {
46b5b838f1SMarek Vasut 	struct mmc *m = &mmc_static;
47b5b838f1SMarek Vasut #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
48b5b838f1SMarek Vasut 	mmc_set_preinit(m, 1);
49b5b838f1SMarek Vasut #endif
50b5b838f1SMarek Vasut 	if (m->preinit)
51b5b838f1SMarek Vasut 		mmc_start_init(m);
52b5b838f1SMarek Vasut }
53b5b838f1SMarek Vasut 
54b5b838f1SMarek Vasut struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
55b5b838f1SMarek Vasut {
56b5b838f1SMarek Vasut 	return &mmc->block_dev;
57b5b838f1SMarek Vasut }
58b5b838f1SMarek Vasut #endif
59b5b838f1SMarek Vasut 
60e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
61c10b85d6SJean-Jacques Hiblot 
62f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
63c10b85d6SJean-Jacques Hiblot static int mmc_wait_dat0(struct mmc *mmc, int state, int timeout)
64c10b85d6SJean-Jacques Hiblot {
65c10b85d6SJean-Jacques Hiblot 	return -ENOSYS;
66c10b85d6SJean-Jacques Hiblot }
67f99c2efeSJean-Jacques Hiblot #endif
68c10b85d6SJean-Jacques Hiblot 
69750121c3SJeroen Hofstee __weak int board_mmc_getwp(struct mmc *mmc)
70d23d8d7eSNikita Kiryanov {
71d23d8d7eSNikita Kiryanov 	return -1;
72d23d8d7eSNikita Kiryanov }
73d23d8d7eSNikita Kiryanov 
74d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc)
75d23d8d7eSNikita Kiryanov {
76d23d8d7eSNikita Kiryanov 	int wp;
77d23d8d7eSNikita Kiryanov 
78d23d8d7eSNikita Kiryanov 	wp = board_mmc_getwp(mmc);
79d23d8d7eSNikita Kiryanov 
80d4e1da4eSPeter Korsgaard 	if (wp < 0) {
8193bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getwp)
8293bfd616SPantelis Antoniou 			wp = mmc->cfg->ops->getwp(mmc);
83d4e1da4eSPeter Korsgaard 		else
84d4e1da4eSPeter Korsgaard 			wp = 0;
85d4e1da4eSPeter Korsgaard 	}
86d23d8d7eSNikita Kiryanov 
87d23d8d7eSNikita Kiryanov 	return wp;
88d23d8d7eSNikita Kiryanov }
89d23d8d7eSNikita Kiryanov 
90cee9ab7cSJeroen Hofstee __weak int board_mmc_getcd(struct mmc *mmc)
91cee9ab7cSJeroen Hofstee {
9211fdade2SStefano Babic 	return -1;
9311fdade2SStefano Babic }
948ca51e51SSimon Glass #endif
9511fdade2SStefano Babic 
968635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE
97c0c76ebaSSimon Glass void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd)
98c0c76ebaSSimon Glass {
99c0c76ebaSSimon Glass 	printf("CMD_SEND:%d\n", cmd->cmdidx);
100c0c76ebaSSimon Glass 	printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg);
101c0c76ebaSSimon Glass }
102c0c76ebaSSimon Glass 
103c0c76ebaSSimon Glass void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret)
104c0c76ebaSSimon Glass {
1055db2fe3aSRaffaele Recalcati 	int i;
1065db2fe3aSRaffaele Recalcati 	u8 *ptr;
1075db2fe3aSRaffaele Recalcati 
1087863ce58SBin Meng 	if (ret) {
1097863ce58SBin Meng 		printf("\t\tRET\t\t\t %d\n", ret);
1107863ce58SBin Meng 	} else {
1115db2fe3aSRaffaele Recalcati 		switch (cmd->resp_type) {
1125db2fe3aSRaffaele Recalcati 		case MMC_RSP_NONE:
1135db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_NONE\n");
1145db2fe3aSRaffaele Recalcati 			break;
1155db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1:
1165db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n",
1175db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1185db2fe3aSRaffaele Recalcati 			break;
1195db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1b:
1205db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n",
1215db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1225db2fe3aSRaffaele Recalcati 			break;
1235db2fe3aSRaffaele Recalcati 		case MMC_RSP_R2:
1245db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R2\t\t 0x%08X \n",
1255db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1265db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1275db2fe3aSRaffaele Recalcati 				cmd->response[1]);
1285db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1295db2fe3aSRaffaele Recalcati 				cmd->response[2]);
1305db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1315db2fe3aSRaffaele Recalcati 				cmd->response[3]);
1325db2fe3aSRaffaele Recalcati 			printf("\n");
1335db2fe3aSRaffaele Recalcati 			printf("\t\t\t\t\tDUMPING DATA\n");
1345db2fe3aSRaffaele Recalcati 			for (i = 0; i < 4; i++) {
1355db2fe3aSRaffaele Recalcati 				int j;
1365db2fe3aSRaffaele Recalcati 				printf("\t\t\t\t\t%03d - ", i*4);
137146bec79SDirk Behme 				ptr = (u8 *)&cmd->response[i];
1385db2fe3aSRaffaele Recalcati 				ptr += 3;
1395db2fe3aSRaffaele Recalcati 				for (j = 0; j < 4; j++)
1405db2fe3aSRaffaele Recalcati 					printf("%02X ", *ptr--);
1415db2fe3aSRaffaele Recalcati 				printf("\n");
1425db2fe3aSRaffaele Recalcati 			}
1435db2fe3aSRaffaele Recalcati 			break;
1445db2fe3aSRaffaele Recalcati 		case MMC_RSP_R3:
1455db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n",
1465db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1475db2fe3aSRaffaele Recalcati 			break;
1485db2fe3aSRaffaele Recalcati 		default:
1495db2fe3aSRaffaele Recalcati 			printf("\t\tERROR MMC rsp not supported\n");
1505db2fe3aSRaffaele Recalcati 			break;
1515db2fe3aSRaffaele Recalcati 		}
1527863ce58SBin Meng 	}
153c0c76ebaSSimon Glass }
154c0c76ebaSSimon Glass 
155c0c76ebaSSimon Glass void mmc_trace_state(struct mmc *mmc, struct mmc_cmd *cmd)
156c0c76ebaSSimon Glass {
157c0c76ebaSSimon Glass 	int status;
158c0c76ebaSSimon Glass 
159c0c76ebaSSimon Glass 	status = (cmd->response[0] & MMC_STATUS_CURR_STATE) >> 9;
160c0c76ebaSSimon Glass 	printf("CURR STATE:%d\n", status);
161c0c76ebaSSimon Glass }
1625db2fe3aSRaffaele Recalcati #endif
163c0c76ebaSSimon Glass 
16435f9e196SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG)
16535f9e196SJean-Jacques Hiblot const char *mmc_mode_name(enum bus_mode mode)
16635f9e196SJean-Jacques Hiblot {
16735f9e196SJean-Jacques Hiblot 	static const char *const names[] = {
16835f9e196SJean-Jacques Hiblot 	      [MMC_LEGACY]	= "MMC legacy",
16935f9e196SJean-Jacques Hiblot 	      [SD_LEGACY]	= "SD Legacy",
17035f9e196SJean-Jacques Hiblot 	      [MMC_HS]		= "MMC High Speed (26MHz)",
17135f9e196SJean-Jacques Hiblot 	      [SD_HS]		= "SD High Speed (50MHz)",
17235f9e196SJean-Jacques Hiblot 	      [UHS_SDR12]	= "UHS SDR12 (25MHz)",
17335f9e196SJean-Jacques Hiblot 	      [UHS_SDR25]	= "UHS SDR25 (50MHz)",
17435f9e196SJean-Jacques Hiblot 	      [UHS_SDR50]	= "UHS SDR50 (100MHz)",
17535f9e196SJean-Jacques Hiblot 	      [UHS_SDR104]	= "UHS SDR104 (208MHz)",
17635f9e196SJean-Jacques Hiblot 	      [UHS_DDR50]	= "UHS DDR50 (50MHz)",
17735f9e196SJean-Jacques Hiblot 	      [MMC_HS_52]	= "MMC High Speed (52MHz)",
17835f9e196SJean-Jacques Hiblot 	      [MMC_DDR_52]	= "MMC DDR52 (52MHz)",
17935f9e196SJean-Jacques Hiblot 	      [MMC_HS_200]	= "HS200 (200MHz)",
18035f9e196SJean-Jacques Hiblot 	};
18135f9e196SJean-Jacques Hiblot 
18235f9e196SJean-Jacques Hiblot 	if (mode >= MMC_MODES_END)
18335f9e196SJean-Jacques Hiblot 		return "Unknown mode";
18435f9e196SJean-Jacques Hiblot 	else
18535f9e196SJean-Jacques Hiblot 		return names[mode];
18635f9e196SJean-Jacques Hiblot }
18735f9e196SJean-Jacques Hiblot #endif
18835f9e196SJean-Jacques Hiblot 
18905038576SJean-Jacques Hiblot static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode)
19005038576SJean-Jacques Hiblot {
19105038576SJean-Jacques Hiblot 	static const int freqs[] = {
19205038576SJean-Jacques Hiblot 	      [SD_LEGACY]	= 25000000,
19305038576SJean-Jacques Hiblot 	      [MMC_HS]		= 26000000,
19405038576SJean-Jacques Hiblot 	      [SD_HS]		= 50000000,
195f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
19605038576SJean-Jacques Hiblot 	      [UHS_SDR12]	= 25000000,
19705038576SJean-Jacques Hiblot 	      [UHS_SDR25]	= 50000000,
19805038576SJean-Jacques Hiblot 	      [UHS_SDR50]	= 100000000,
19905038576SJean-Jacques Hiblot 	      [UHS_DDR50]	= 50000000,
200f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
201f99c2efeSJean-Jacques Hiblot 	      [UHS_SDR104]	= 208000000,
202f99c2efeSJean-Jacques Hiblot #endif
203f99c2efeSJean-Jacques Hiblot #endif
20405038576SJean-Jacques Hiblot 	      [MMC_HS_52]	= 52000000,
20505038576SJean-Jacques Hiblot 	      [MMC_DDR_52]	= 52000000,
206f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
20705038576SJean-Jacques Hiblot 	      [MMC_HS_200]	= 200000000,
208f99c2efeSJean-Jacques Hiblot #endif
20905038576SJean-Jacques Hiblot 	};
21005038576SJean-Jacques Hiblot 
21105038576SJean-Jacques Hiblot 	if (mode == MMC_LEGACY)
21205038576SJean-Jacques Hiblot 		return mmc->legacy_speed;
21305038576SJean-Jacques Hiblot 	else if (mode >= MMC_MODES_END)
21405038576SJean-Jacques Hiblot 		return 0;
21505038576SJean-Jacques Hiblot 	else
21605038576SJean-Jacques Hiblot 		return freqs[mode];
21705038576SJean-Jacques Hiblot }
21805038576SJean-Jacques Hiblot 
21935f9e196SJean-Jacques Hiblot static int mmc_select_mode(struct mmc *mmc, enum bus_mode mode)
22035f9e196SJean-Jacques Hiblot {
22135f9e196SJean-Jacques Hiblot 	mmc->selected_mode = mode;
22205038576SJean-Jacques Hiblot 	mmc->tran_speed = mmc_mode2freq(mmc, mode);
2233862b854SJean-Jacques Hiblot 	mmc->ddr_mode = mmc_is_mode_ddr(mode);
22435f9e196SJean-Jacques Hiblot 	debug("selecting mode %s (freq : %d MHz)\n", mmc_mode_name(mode),
22535f9e196SJean-Jacques Hiblot 	      mmc->tran_speed / 1000000);
22635f9e196SJean-Jacques Hiblot 	return 0;
22735f9e196SJean-Jacques Hiblot }
22835f9e196SJean-Jacques Hiblot 
229e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
230c0c76ebaSSimon Glass int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
231c0c76ebaSSimon Glass {
232c0c76ebaSSimon Glass 	int ret;
233c0c76ebaSSimon Glass 
234c0c76ebaSSimon Glass 	mmmc_trace_before_send(mmc, cmd);
235c0c76ebaSSimon Glass 	ret = mmc->cfg->ops->send_cmd(mmc, cmd, data);
236c0c76ebaSSimon Glass 	mmmc_trace_after_send(mmc, cmd, ret);
237c0c76ebaSSimon Glass 
2388635ff9eSMarek Vasut 	return ret;
239272cc70bSAndy Fleming }
2408ca51e51SSimon Glass #endif
241272cc70bSAndy Fleming 
242da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout)
2435d4fc8d9SRaffaele Recalcati {
2445d4fc8d9SRaffaele Recalcati 	struct mmc_cmd cmd;
245d617c426SJan Kloetzke 	int err, retries = 5;
2465d4fc8d9SRaffaele Recalcati 
2475d4fc8d9SRaffaele Recalcati 	cmd.cmdidx = MMC_CMD_SEND_STATUS;
2485d4fc8d9SRaffaele Recalcati 	cmd.resp_type = MMC_RSP_R1;
249aaf3d41aSMarek Vasut 	if (!mmc_host_is_spi(mmc))
250aaf3d41aSMarek Vasut 		cmd.cmdarg = mmc->rca << 16;
2515d4fc8d9SRaffaele Recalcati 
2521677eef4SAndrew Gabbasov 	while (1) {
2535d4fc8d9SRaffaele Recalcati 		err = mmc_send_cmd(mmc, &cmd, NULL);
254d617c426SJan Kloetzke 		if (!err) {
255d617c426SJan Kloetzke 			if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) &&
256d617c426SJan Kloetzke 			    (cmd.response[0] & MMC_STATUS_CURR_STATE) !=
257d617c426SJan Kloetzke 			     MMC_STATE_PRG)
2585d4fc8d9SRaffaele Recalcati 				break;
259d0c221feSJean-Jacques Hiblot 
260d0c221feSJean-Jacques Hiblot 			if (cmd.response[0] & MMC_STATUS_MASK) {
26156196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
262d8e3d420SJean-Jacques Hiblot 				pr_err("Status Error: 0x%08X\n",
263d617c426SJan Kloetzke 				       cmd.response[0]);
26456196826SPaul Burton #endif
265915ffa52SJaehoon Chung 				return -ECOMM;
266d617c426SJan Kloetzke 			}
267d617c426SJan Kloetzke 		} else if (--retries < 0)
268d617c426SJan Kloetzke 			return err;
2695d4fc8d9SRaffaele Recalcati 
2701677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
2711677eef4SAndrew Gabbasov 			break;
2725d4fc8d9SRaffaele Recalcati 
2731677eef4SAndrew Gabbasov 		udelay(1000);
2741677eef4SAndrew Gabbasov 	}
2755d4fc8d9SRaffaele Recalcati 
276c0c76ebaSSimon Glass 	mmc_trace_state(mmc, &cmd);
2775b0c942fSJongman Heo 	if (timeout <= 0) {
27856196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
279d8e3d420SJean-Jacques Hiblot 		pr_err("Timeout waiting card ready\n");
28056196826SPaul Burton #endif
281915ffa52SJaehoon Chung 		return -ETIMEDOUT;
2825d4fc8d9SRaffaele Recalcati 	}
2835d4fc8d9SRaffaele Recalcati 
2845d4fc8d9SRaffaele Recalcati 	return 0;
2855d4fc8d9SRaffaele Recalcati }
2865d4fc8d9SRaffaele Recalcati 
287da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len)
288272cc70bSAndy Fleming {
289272cc70bSAndy Fleming 	struct mmc_cmd cmd;
29083dc4227SKishon Vijay Abraham I 	int err;
291272cc70bSAndy Fleming 
292786e8f81SAndrew Gabbasov 	if (mmc->ddr_mode)
293d22e3d46SJaehoon Chung 		return 0;
294d22e3d46SJaehoon Chung 
295272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
296272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
297272cc70bSAndy Fleming 	cmd.cmdarg = len;
298272cc70bSAndy Fleming 
29983dc4227SKishon Vijay Abraham I 	err = mmc_send_cmd(mmc, &cmd, NULL);
30083dc4227SKishon Vijay Abraham I 
30183dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS
30283dc4227SKishon Vijay Abraham I 	if (err && (mmc->quirks & MMC_QUIRK_RETRY_SET_BLOCKLEN)) {
30383dc4227SKishon Vijay Abraham I 		int retries = 4;
30483dc4227SKishon Vijay Abraham I 		/*
30583dc4227SKishon Vijay Abraham I 		 * It has been seen that SET_BLOCKLEN may fail on the first
30683dc4227SKishon Vijay Abraham I 		 * attempt, let's try a few more time
30783dc4227SKishon Vijay Abraham I 		 */
30883dc4227SKishon Vijay Abraham I 		do {
30983dc4227SKishon Vijay Abraham I 			err = mmc_send_cmd(mmc, &cmd, NULL);
31083dc4227SKishon Vijay Abraham I 			if (!err)
31183dc4227SKishon Vijay Abraham I 				break;
31283dc4227SKishon Vijay Abraham I 		} while (retries--);
31383dc4227SKishon Vijay Abraham I 	}
31483dc4227SKishon Vijay Abraham I #endif
31583dc4227SKishon Vijay Abraham I 
31683dc4227SKishon Vijay Abraham I 	return err;
317272cc70bSAndy Fleming }
318272cc70bSAndy Fleming 
319f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
3209815e3baSJean-Jacques Hiblot static const u8 tuning_blk_pattern_4bit[] = {
3219815e3baSJean-Jacques Hiblot 	0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
3229815e3baSJean-Jacques Hiblot 	0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
3239815e3baSJean-Jacques Hiblot 	0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
3249815e3baSJean-Jacques Hiblot 	0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
3259815e3baSJean-Jacques Hiblot 	0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
3269815e3baSJean-Jacques Hiblot 	0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
3279815e3baSJean-Jacques Hiblot 	0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
3289815e3baSJean-Jacques Hiblot 	0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
3299815e3baSJean-Jacques Hiblot };
3309815e3baSJean-Jacques Hiblot 
3319815e3baSJean-Jacques Hiblot static const u8 tuning_blk_pattern_8bit[] = {
3329815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
3339815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
3349815e3baSJean-Jacques Hiblot 	0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
3359815e3baSJean-Jacques Hiblot 	0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
3369815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
3379815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
3389815e3baSJean-Jacques Hiblot 	0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
3399815e3baSJean-Jacques Hiblot 	0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
3409815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
3419815e3baSJean-Jacques Hiblot 	0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
3429815e3baSJean-Jacques Hiblot 	0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
3439815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
3449815e3baSJean-Jacques Hiblot 	0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
3459815e3baSJean-Jacques Hiblot 	0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
3469815e3baSJean-Jacques Hiblot 	0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
3479815e3baSJean-Jacques Hiblot 	0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
3489815e3baSJean-Jacques Hiblot };
3499815e3baSJean-Jacques Hiblot 
3509815e3baSJean-Jacques Hiblot int mmc_send_tuning(struct mmc *mmc, u32 opcode, int *cmd_error)
3519815e3baSJean-Jacques Hiblot {
3529815e3baSJean-Jacques Hiblot 	struct mmc_cmd cmd;
3539815e3baSJean-Jacques Hiblot 	struct mmc_data data;
3549815e3baSJean-Jacques Hiblot 	const u8 *tuning_block_pattern;
3559815e3baSJean-Jacques Hiblot 	int size, err;
3569815e3baSJean-Jacques Hiblot 
3579815e3baSJean-Jacques Hiblot 	if (mmc->bus_width == 8) {
3589815e3baSJean-Jacques Hiblot 		tuning_block_pattern = tuning_blk_pattern_8bit;
3599815e3baSJean-Jacques Hiblot 		size = sizeof(tuning_blk_pattern_8bit);
3609815e3baSJean-Jacques Hiblot 	} else if (mmc->bus_width == 4) {
3619815e3baSJean-Jacques Hiblot 		tuning_block_pattern = tuning_blk_pattern_4bit;
3629815e3baSJean-Jacques Hiblot 		size = sizeof(tuning_blk_pattern_4bit);
3639815e3baSJean-Jacques Hiblot 	} else {
3649815e3baSJean-Jacques Hiblot 		return -EINVAL;
3659815e3baSJean-Jacques Hiblot 	}
3669815e3baSJean-Jacques Hiblot 
3679815e3baSJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, data_buf, size);
3689815e3baSJean-Jacques Hiblot 
3699815e3baSJean-Jacques Hiblot 	cmd.cmdidx = opcode;
3709815e3baSJean-Jacques Hiblot 	cmd.cmdarg = 0;
3719815e3baSJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
3729815e3baSJean-Jacques Hiblot 
3739815e3baSJean-Jacques Hiblot 	data.dest = (void *)data_buf;
3749815e3baSJean-Jacques Hiblot 	data.blocks = 1;
3759815e3baSJean-Jacques Hiblot 	data.blocksize = size;
3769815e3baSJean-Jacques Hiblot 	data.flags = MMC_DATA_READ;
3779815e3baSJean-Jacques Hiblot 
3789815e3baSJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, &data);
3799815e3baSJean-Jacques Hiblot 	if (err)
3809815e3baSJean-Jacques Hiblot 		return err;
3819815e3baSJean-Jacques Hiblot 
3829815e3baSJean-Jacques Hiblot 	if (memcmp(data_buf, tuning_block_pattern, size))
3839815e3baSJean-Jacques Hiblot 		return -EIO;
3849815e3baSJean-Jacques Hiblot 
3859815e3baSJean-Jacques Hiblot 	return 0;
3869815e3baSJean-Jacques Hiblot }
387f99c2efeSJean-Jacques Hiblot #endif
3889815e3baSJean-Jacques Hiblot 
389ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
390fdbb873eSKim Phillips 			   lbaint_t blkcnt)
391272cc70bSAndy Fleming {
392272cc70bSAndy Fleming 	struct mmc_cmd cmd;
393272cc70bSAndy Fleming 	struct mmc_data data;
394272cc70bSAndy Fleming 
3954a1a06bcSAlagu Sankar 	if (blkcnt > 1)
3964a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
3974a1a06bcSAlagu Sankar 	else
398272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
399272cc70bSAndy Fleming 
400272cc70bSAndy Fleming 	if (mmc->high_capacity)
4014a1a06bcSAlagu Sankar 		cmd.cmdarg = start;
402272cc70bSAndy Fleming 	else
4034a1a06bcSAlagu Sankar 		cmd.cmdarg = start * mmc->read_bl_len;
404272cc70bSAndy Fleming 
405272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
406272cc70bSAndy Fleming 
407272cc70bSAndy Fleming 	data.dest = dst;
4084a1a06bcSAlagu Sankar 	data.blocks = blkcnt;
409272cc70bSAndy Fleming 	data.blocksize = mmc->read_bl_len;
410272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
411272cc70bSAndy Fleming 
4124a1a06bcSAlagu Sankar 	if (mmc_send_cmd(mmc, &cmd, &data))
4134a1a06bcSAlagu Sankar 		return 0;
4144a1a06bcSAlagu Sankar 
4154a1a06bcSAlagu Sankar 	if (blkcnt > 1) {
4164a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
4174a1a06bcSAlagu Sankar 		cmd.cmdarg = 0;
4184a1a06bcSAlagu Sankar 		cmd.resp_type = MMC_RSP_R1b;
4194a1a06bcSAlagu Sankar 		if (mmc_send_cmd(mmc, &cmd, NULL)) {
42056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
421d8e3d420SJean-Jacques Hiblot 			pr_err("mmc fail to send stop cmd\n");
42256196826SPaul Burton #endif
4234a1a06bcSAlagu Sankar 			return 0;
4244a1a06bcSAlagu Sankar 		}
425272cc70bSAndy Fleming 	}
426272cc70bSAndy Fleming 
4274a1a06bcSAlagu Sankar 	return blkcnt;
428272cc70bSAndy Fleming }
429272cc70bSAndy Fleming 
430c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
4317dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst)
43233fb211dSSimon Glass #else
4337dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
4347dba0b93SSimon Glass 		void *dst)
43533fb211dSSimon Glass #endif
436272cc70bSAndy Fleming {
437c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
43833fb211dSSimon Glass 	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
43933fb211dSSimon Glass #endif
440bcce53d0SSimon Glass 	int dev_num = block_dev->devnum;
441873cc1d7SStephen Warren 	int err;
4424a1a06bcSAlagu Sankar 	lbaint_t cur, blocks_todo = blkcnt;
443272cc70bSAndy Fleming 
4444a1a06bcSAlagu Sankar 	if (blkcnt == 0)
4454a1a06bcSAlagu Sankar 		return 0;
4464a1a06bcSAlagu Sankar 
4474a1a06bcSAlagu Sankar 	struct mmc *mmc = find_mmc_device(dev_num);
448272cc70bSAndy Fleming 	if (!mmc)
449272cc70bSAndy Fleming 		return 0;
450272cc70bSAndy Fleming 
451b5b838f1SMarek Vasut 	if (CONFIG_IS_ENABLED(MMC_TINY))
452b5b838f1SMarek Vasut 		err = mmc_switch_part(mmc, block_dev->hwpart);
453b5b838f1SMarek Vasut 	else
45469f45cd5SSimon Glass 		err = blk_dselect_hwpart(block_dev, block_dev->hwpart);
455b5b838f1SMarek Vasut 
456873cc1d7SStephen Warren 	if (err < 0)
457873cc1d7SStephen Warren 		return 0;
458873cc1d7SStephen Warren 
459c40fdca6SSimon Glass 	if ((start + blkcnt) > block_dev->lba) {
46056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
461d8e3d420SJean-Jacques Hiblot 		pr_err("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
462c40fdca6SSimon Glass 		       start + blkcnt, block_dev->lba);
46356196826SPaul Burton #endif
464d2bf29e3SLei Wen 		return 0;
465d2bf29e3SLei Wen 	}
466272cc70bSAndy Fleming 
46711692991SSimon Glass 	if (mmc_set_blocklen(mmc, mmc->read_bl_len)) {
46811692991SSimon Glass 		debug("%s: Failed to set blocklen\n", __func__);
469272cc70bSAndy Fleming 		return 0;
47011692991SSimon Glass 	}
471272cc70bSAndy Fleming 
4724a1a06bcSAlagu Sankar 	do {
47393bfd616SPantelis Antoniou 		cur = (blocks_todo > mmc->cfg->b_max) ?
47493bfd616SPantelis Antoniou 			mmc->cfg->b_max : blocks_todo;
47511692991SSimon Glass 		if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
47611692991SSimon Glass 			debug("%s: Failed to read blocks\n", __func__);
4774a1a06bcSAlagu Sankar 			return 0;
47811692991SSimon Glass 		}
4794a1a06bcSAlagu Sankar 		blocks_todo -= cur;
4804a1a06bcSAlagu Sankar 		start += cur;
4814a1a06bcSAlagu Sankar 		dst += cur * mmc->read_bl_len;
4824a1a06bcSAlagu Sankar 	} while (blocks_todo > 0);
483272cc70bSAndy Fleming 
484272cc70bSAndy Fleming 	return blkcnt;
485272cc70bSAndy Fleming }
486272cc70bSAndy Fleming 
487fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc)
488272cc70bSAndy Fleming {
489272cc70bSAndy Fleming 	struct mmc_cmd cmd;
490272cc70bSAndy Fleming 	int err;
491272cc70bSAndy Fleming 
492272cc70bSAndy Fleming 	udelay(1000);
493272cc70bSAndy Fleming 
494272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
495272cc70bSAndy Fleming 	cmd.cmdarg = 0;
496272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_NONE;
497272cc70bSAndy Fleming 
498272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
499272cc70bSAndy Fleming 
500272cc70bSAndy Fleming 	if (err)
501272cc70bSAndy Fleming 		return err;
502272cc70bSAndy Fleming 
503272cc70bSAndy Fleming 	udelay(2000);
504272cc70bSAndy Fleming 
505272cc70bSAndy Fleming 	return 0;
506272cc70bSAndy Fleming }
507272cc70bSAndy Fleming 
508f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
509c10b85d6SJean-Jacques Hiblot static int mmc_switch_voltage(struct mmc *mmc, int signal_voltage)
510c10b85d6SJean-Jacques Hiblot {
511c10b85d6SJean-Jacques Hiblot 	struct mmc_cmd cmd;
512c10b85d6SJean-Jacques Hiblot 	int err = 0;
513c10b85d6SJean-Jacques Hiblot 
514c10b85d6SJean-Jacques Hiblot 	/*
515c10b85d6SJean-Jacques Hiblot 	 * Send CMD11 only if the request is to switch the card to
516c10b85d6SJean-Jacques Hiblot 	 * 1.8V signalling.
517c10b85d6SJean-Jacques Hiblot 	 */
518c10b85d6SJean-Jacques Hiblot 	if (signal_voltage == MMC_SIGNAL_VOLTAGE_330)
519c10b85d6SJean-Jacques Hiblot 		return mmc_set_signal_voltage(mmc, signal_voltage);
520c10b85d6SJean-Jacques Hiblot 
521c10b85d6SJean-Jacques Hiblot 	cmd.cmdidx = SD_CMD_SWITCH_UHS18V;
522c10b85d6SJean-Jacques Hiblot 	cmd.cmdarg = 0;
523c10b85d6SJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
524c10b85d6SJean-Jacques Hiblot 
525c10b85d6SJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
526c10b85d6SJean-Jacques Hiblot 	if (err)
527c10b85d6SJean-Jacques Hiblot 		return err;
528c10b85d6SJean-Jacques Hiblot 
529c10b85d6SJean-Jacques Hiblot 	if (!mmc_host_is_spi(mmc) && (cmd.response[0] & MMC_STATUS_ERROR))
530c10b85d6SJean-Jacques Hiblot 		return -EIO;
531c10b85d6SJean-Jacques Hiblot 
532c10b85d6SJean-Jacques Hiblot 	/*
533c10b85d6SJean-Jacques Hiblot 	 * The card should drive cmd and dat[0:3] low immediately
534c10b85d6SJean-Jacques Hiblot 	 * after the response of cmd11, but wait 100 us to be sure
535c10b85d6SJean-Jacques Hiblot 	 */
536c10b85d6SJean-Jacques Hiblot 	err = mmc_wait_dat0(mmc, 0, 100);
537c10b85d6SJean-Jacques Hiblot 	if (err == -ENOSYS)
538c10b85d6SJean-Jacques Hiblot 		udelay(100);
539c10b85d6SJean-Jacques Hiblot 	else if (err)
540c10b85d6SJean-Jacques Hiblot 		return -ETIMEDOUT;
541c10b85d6SJean-Jacques Hiblot 
542c10b85d6SJean-Jacques Hiblot 	/*
543c10b85d6SJean-Jacques Hiblot 	 * During a signal voltage level switch, the clock must be gated
544c10b85d6SJean-Jacques Hiblot 	 * for 5 ms according to the SD spec
545c10b85d6SJean-Jacques Hiblot 	 */
546c10b85d6SJean-Jacques Hiblot 	mmc_set_clock(mmc, mmc->clock, true);
547c10b85d6SJean-Jacques Hiblot 
548c10b85d6SJean-Jacques Hiblot 	err = mmc_set_signal_voltage(mmc, signal_voltage);
549c10b85d6SJean-Jacques Hiblot 	if (err)
550c10b85d6SJean-Jacques Hiblot 		return err;
551c10b85d6SJean-Jacques Hiblot 
552c10b85d6SJean-Jacques Hiblot 	/* Keep clock gated for at least 10 ms, though spec only says 5 ms */
553c10b85d6SJean-Jacques Hiblot 	mdelay(10);
554c10b85d6SJean-Jacques Hiblot 	mmc_set_clock(mmc, mmc->clock, false);
555c10b85d6SJean-Jacques Hiblot 
556c10b85d6SJean-Jacques Hiblot 	/*
557c10b85d6SJean-Jacques Hiblot 	 * Failure to switch is indicated by the card holding
558c10b85d6SJean-Jacques Hiblot 	 * dat[0:3] low. Wait for at least 1 ms according to spec
559c10b85d6SJean-Jacques Hiblot 	 */
560c10b85d6SJean-Jacques Hiblot 	err = mmc_wait_dat0(mmc, 1, 1000);
561c10b85d6SJean-Jacques Hiblot 	if (err == -ENOSYS)
562c10b85d6SJean-Jacques Hiblot 		udelay(1000);
563c10b85d6SJean-Jacques Hiblot 	else if (err)
564c10b85d6SJean-Jacques Hiblot 		return -ETIMEDOUT;
565c10b85d6SJean-Jacques Hiblot 
566c10b85d6SJean-Jacques Hiblot 	return 0;
567c10b85d6SJean-Jacques Hiblot }
568f99c2efeSJean-Jacques Hiblot #endif
569c10b85d6SJean-Jacques Hiblot 
570c10b85d6SJean-Jacques Hiblot static int sd_send_op_cond(struct mmc *mmc, bool uhs_en)
571272cc70bSAndy Fleming {
572272cc70bSAndy Fleming 	int timeout = 1000;
573272cc70bSAndy Fleming 	int err;
574272cc70bSAndy Fleming 	struct mmc_cmd cmd;
575272cc70bSAndy Fleming 
5761677eef4SAndrew Gabbasov 	while (1) {
577272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_APP_CMD;
578272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1;
579272cc70bSAndy Fleming 		cmd.cmdarg = 0;
580272cc70bSAndy Fleming 
581272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
582272cc70bSAndy Fleming 
583272cc70bSAndy Fleming 		if (err)
584272cc70bSAndy Fleming 			return err;
585272cc70bSAndy Fleming 
586272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
587272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
588250de12bSStefano Babic 
589250de12bSStefano Babic 		/*
590250de12bSStefano Babic 		 * Most cards do not answer if some reserved bits
591250de12bSStefano Babic 		 * in the ocr are set. However, Some controller
592250de12bSStefano Babic 		 * can set bit 7 (reserved for low voltages), but
593250de12bSStefano Babic 		 * how to manage low voltages SD card is not yet
594250de12bSStefano Babic 		 * specified.
595250de12bSStefano Babic 		 */
596d52ebf10SThomas Chou 		cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
59793bfd616SPantelis Antoniou 			(mmc->cfg->voltages & 0xff8000);
598272cc70bSAndy Fleming 
599272cc70bSAndy Fleming 		if (mmc->version == SD_VERSION_2)
600272cc70bSAndy Fleming 			cmd.cmdarg |= OCR_HCS;
601272cc70bSAndy Fleming 
602c10b85d6SJean-Jacques Hiblot 		if (uhs_en)
603c10b85d6SJean-Jacques Hiblot 			cmd.cmdarg |= OCR_S18R;
604c10b85d6SJean-Jacques Hiblot 
605272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
606272cc70bSAndy Fleming 
607272cc70bSAndy Fleming 		if (err)
608272cc70bSAndy Fleming 			return err;
609272cc70bSAndy Fleming 
6101677eef4SAndrew Gabbasov 		if (cmd.response[0] & OCR_BUSY)
6111677eef4SAndrew Gabbasov 			break;
612272cc70bSAndy Fleming 
6131677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
614915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
615272cc70bSAndy Fleming 
6161677eef4SAndrew Gabbasov 		udelay(1000);
6171677eef4SAndrew Gabbasov 	}
6181677eef4SAndrew Gabbasov 
619272cc70bSAndy Fleming 	if (mmc->version != SD_VERSION_2)
620272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
621272cc70bSAndy Fleming 
622d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
623d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
624d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
625d52ebf10SThomas Chou 		cmd.cmdarg = 0;
626d52ebf10SThomas Chou 
627d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
628d52ebf10SThomas Chou 
629d52ebf10SThomas Chou 		if (err)
630d52ebf10SThomas Chou 			return err;
631d52ebf10SThomas Chou 	}
632d52ebf10SThomas Chou 
633998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
634272cc70bSAndy Fleming 
635f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
636c10b85d6SJean-Jacques Hiblot 	if (uhs_en && !(mmc_host_is_spi(mmc)) && (cmd.response[0] & 0x41000000)
637c10b85d6SJean-Jacques Hiblot 	    == 0x41000000) {
638c10b85d6SJean-Jacques Hiblot 		err = mmc_switch_voltage(mmc, MMC_SIGNAL_VOLTAGE_180);
639c10b85d6SJean-Jacques Hiblot 		if (err)
640c10b85d6SJean-Jacques Hiblot 			return err;
641c10b85d6SJean-Jacques Hiblot 	}
642f99c2efeSJean-Jacques Hiblot #endif
643c10b85d6SJean-Jacques Hiblot 
644272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
645272cc70bSAndy Fleming 	mmc->rca = 0;
646272cc70bSAndy Fleming 
647272cc70bSAndy Fleming 	return 0;
648272cc70bSAndy Fleming }
649272cc70bSAndy Fleming 
6505289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg)
651272cc70bSAndy Fleming {
6525289b535SAndrew Gabbasov 	struct mmc_cmd cmd;
653272cc70bSAndy Fleming 	int err;
654272cc70bSAndy Fleming 
6555289b535SAndrew Gabbasov 	cmd.cmdidx = MMC_CMD_SEND_OP_COND;
6565289b535SAndrew Gabbasov 	cmd.resp_type = MMC_RSP_R3;
6575289b535SAndrew Gabbasov 	cmd.cmdarg = 0;
6585a20397bSRob Herring 	if (use_arg && !mmc_host_is_spi(mmc))
6595a20397bSRob Herring 		cmd.cmdarg = OCR_HCS |
66093bfd616SPantelis Antoniou 			(mmc->cfg->voltages &
661a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_VOLTAGE_MASK)) |
662a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_ACCESS_MODE);
663e9550449SChe-Liang Chiou 
6645289b535SAndrew Gabbasov 	err = mmc_send_cmd(mmc, &cmd, NULL);
665e9550449SChe-Liang Chiou 	if (err)
666e9550449SChe-Liang Chiou 		return err;
6675289b535SAndrew Gabbasov 	mmc->ocr = cmd.response[0];
668e9550449SChe-Liang Chiou 	return 0;
669e9550449SChe-Liang Chiou }
670e9550449SChe-Liang Chiou 
671750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc)
672e9550449SChe-Liang Chiou {
673e9550449SChe-Liang Chiou 	int err, i;
674e9550449SChe-Liang Chiou 
675272cc70bSAndy Fleming 	/* Some cards seem to need this */
676272cc70bSAndy Fleming 	mmc_go_idle(mmc);
677272cc70bSAndy Fleming 
67831cacbabSRaffaele Recalcati  	/* Asking to the card its capabilities */
679e9550449SChe-Liang Chiou 	for (i = 0; i < 2; i++) {
6805289b535SAndrew Gabbasov 		err = mmc_send_op_cond_iter(mmc, i != 0);
68131cacbabSRaffaele Recalcati 		if (err)
68231cacbabSRaffaele Recalcati 			return err;
68331cacbabSRaffaele Recalcati 
684e9550449SChe-Liang Chiou 		/* exit if not busy (flag seems to be inverted) */
685a626c8d4SAndrew Gabbasov 		if (mmc->ocr & OCR_BUSY)
686bd47c135SAndrew Gabbasov 			break;
687e9550449SChe-Liang Chiou 	}
688bd47c135SAndrew Gabbasov 	mmc->op_cond_pending = 1;
689bd47c135SAndrew Gabbasov 	return 0;
690e9550449SChe-Liang Chiou }
69131cacbabSRaffaele Recalcati 
692750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc)
693e9550449SChe-Liang Chiou {
694e9550449SChe-Liang Chiou 	struct mmc_cmd cmd;
695e9550449SChe-Liang Chiou 	int timeout = 1000;
696e9550449SChe-Liang Chiou 	uint start;
697e9550449SChe-Liang Chiou 	int err;
698e9550449SChe-Liang Chiou 
699e9550449SChe-Liang Chiou 	mmc->op_cond_pending = 0;
700cc17c01fSAndrew Gabbasov 	if (!(mmc->ocr & OCR_BUSY)) {
701d188b113SYangbo Lu 		/* Some cards seem to need this */
702d188b113SYangbo Lu 		mmc_go_idle(mmc);
703d188b113SYangbo Lu 
704e9550449SChe-Liang Chiou 		start = get_timer(0);
7051677eef4SAndrew Gabbasov 		while (1) {
7065289b535SAndrew Gabbasov 			err = mmc_send_op_cond_iter(mmc, 1);
707272cc70bSAndy Fleming 			if (err)
708272cc70bSAndy Fleming 				return err;
7091677eef4SAndrew Gabbasov 			if (mmc->ocr & OCR_BUSY)
7101677eef4SAndrew Gabbasov 				break;
711e9550449SChe-Liang Chiou 			if (get_timer(start) > timeout)
712915ffa52SJaehoon Chung 				return -EOPNOTSUPP;
713e9550449SChe-Liang Chiou 			udelay(100);
7141677eef4SAndrew Gabbasov 		}
715cc17c01fSAndrew Gabbasov 	}
716272cc70bSAndy Fleming 
717d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
718d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
719d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
720d52ebf10SThomas Chou 		cmd.cmdarg = 0;
721d52ebf10SThomas Chou 
722d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
723d52ebf10SThomas Chou 
724d52ebf10SThomas Chou 		if (err)
725d52ebf10SThomas Chou 			return err;
726a626c8d4SAndrew Gabbasov 
727a626c8d4SAndrew Gabbasov 		mmc->ocr = cmd.response[0];
728d52ebf10SThomas Chou 	}
729d52ebf10SThomas Chou 
730272cc70bSAndy Fleming 	mmc->version = MMC_VERSION_UNKNOWN;
731272cc70bSAndy Fleming 
732272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
733def816a2SStephen Warren 	mmc->rca = 1;
734272cc70bSAndy Fleming 
735272cc70bSAndy Fleming 	return 0;
736272cc70bSAndy Fleming }
737272cc70bSAndy Fleming 
738272cc70bSAndy Fleming 
739fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
740272cc70bSAndy Fleming {
741272cc70bSAndy Fleming 	struct mmc_cmd cmd;
742272cc70bSAndy Fleming 	struct mmc_data data;
743272cc70bSAndy Fleming 	int err;
744272cc70bSAndy Fleming 
745272cc70bSAndy Fleming 	/* Get the Card Status Register */
746272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
747272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
748272cc70bSAndy Fleming 	cmd.cmdarg = 0;
749272cc70bSAndy Fleming 
750cdfd1ac6SYoshihiro Shimoda 	data.dest = (char *)ext_csd;
751272cc70bSAndy Fleming 	data.blocks = 1;
7528bfa195eSSimon Glass 	data.blocksize = MMC_MAX_BLOCK_LEN;
753272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
754272cc70bSAndy Fleming 
755272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
756272cc70bSAndy Fleming 
757272cc70bSAndy Fleming 	return err;
758272cc70bSAndy Fleming }
759272cc70bSAndy Fleming 
760c40704f4SSimon Glass int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
761272cc70bSAndy Fleming {
762272cc70bSAndy Fleming 	struct mmc_cmd cmd;
7635d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
764a9003dc6SMaxime Ripard 	int retries = 3;
7655d4fc8d9SRaffaele Recalcati 	int ret;
766272cc70bSAndy Fleming 
767272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SWITCH;
768272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1b;
769272cc70bSAndy Fleming 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
770272cc70bSAndy Fleming 				 (index << 16) |
771272cc70bSAndy Fleming 				 (value << 8);
772272cc70bSAndy Fleming 
773a9003dc6SMaxime Ripard 	while (retries > 0) {
7745d4fc8d9SRaffaele Recalcati 		ret = mmc_send_cmd(mmc, &cmd, NULL);
7755d4fc8d9SRaffaele Recalcati 
7765d4fc8d9SRaffaele Recalcati 		/* Waiting for the ready status */
777a9003dc6SMaxime Ripard 		if (!ret) {
77893ad0d18SJan Kloetzke 			ret = mmc_send_status(mmc, timeout);
779a9003dc6SMaxime Ripard 			return ret;
780a9003dc6SMaxime Ripard 		}
781a9003dc6SMaxime Ripard 
782a9003dc6SMaxime Ripard 		retries--;
783a9003dc6SMaxime Ripard 	}
7845d4fc8d9SRaffaele Recalcati 
7855d4fc8d9SRaffaele Recalcati 	return ret;
7865d4fc8d9SRaffaele Recalcati 
787272cc70bSAndy Fleming }
788272cc70bSAndy Fleming 
7893862b854SJean-Jacques Hiblot static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode)
790272cc70bSAndy Fleming {
791272cc70bSAndy Fleming 	int err;
7923862b854SJean-Jacques Hiblot 	int speed_bits;
7933862b854SJean-Jacques Hiblot 
7943862b854SJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
7953862b854SJean-Jacques Hiblot 
7963862b854SJean-Jacques Hiblot 	switch (mode) {
7973862b854SJean-Jacques Hiblot 	case MMC_HS:
7983862b854SJean-Jacques Hiblot 	case MMC_HS_52:
7993862b854SJean-Jacques Hiblot 	case MMC_DDR_52:
8003862b854SJean-Jacques Hiblot 		speed_bits = EXT_CSD_TIMING_HS;
801634d4849SKishon Vijay Abraham I 		break;
802634d4849SKishon Vijay Abraham I 	case MMC_HS_200:
803634d4849SKishon Vijay Abraham I 		speed_bits = EXT_CSD_TIMING_HS200;
804634d4849SKishon Vijay Abraham I 		break;
8053862b854SJean-Jacques Hiblot 	case MMC_LEGACY:
8063862b854SJean-Jacques Hiblot 		speed_bits = EXT_CSD_TIMING_LEGACY;
8073862b854SJean-Jacques Hiblot 		break;
8083862b854SJean-Jacques Hiblot 	default:
8093862b854SJean-Jacques Hiblot 		return -EINVAL;
8103862b854SJean-Jacques Hiblot 	}
8113862b854SJean-Jacques Hiblot 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
8123862b854SJean-Jacques Hiblot 			 speed_bits);
8133862b854SJean-Jacques Hiblot 	if (err)
8143862b854SJean-Jacques Hiblot 		return err;
8153862b854SJean-Jacques Hiblot 
8163862b854SJean-Jacques Hiblot 	if ((mode == MMC_HS) || (mode == MMC_HS_52)) {
8173862b854SJean-Jacques Hiblot 		/* Now check to see that it worked */
8183862b854SJean-Jacques Hiblot 		err = mmc_send_ext_csd(mmc, test_csd);
8193862b854SJean-Jacques Hiblot 		if (err)
8203862b854SJean-Jacques Hiblot 			return err;
8213862b854SJean-Jacques Hiblot 
8223862b854SJean-Jacques Hiblot 		/* No high-speed support */
8233862b854SJean-Jacques Hiblot 		if (!test_csd[EXT_CSD_HS_TIMING])
8243862b854SJean-Jacques Hiblot 			return -ENOTSUPP;
8253862b854SJean-Jacques Hiblot 	}
8263862b854SJean-Jacques Hiblot 
8273862b854SJean-Jacques Hiblot 	return 0;
8283862b854SJean-Jacques Hiblot }
8293862b854SJean-Jacques Hiblot 
8303862b854SJean-Jacques Hiblot static int mmc_get_capabilities(struct mmc *mmc)
8313862b854SJean-Jacques Hiblot {
8323862b854SJean-Jacques Hiblot 	u8 *ext_csd = mmc->ext_csd;
8333862b854SJean-Jacques Hiblot 	char cardtype;
834272cc70bSAndy Fleming 
83500e446faSJean-Jacques Hiblot 	mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(MMC_LEGACY);
836272cc70bSAndy Fleming 
837d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
838d52ebf10SThomas Chou 		return 0;
839d52ebf10SThomas Chou 
840272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
841272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
842272cc70bSAndy Fleming 		return 0;
843272cc70bSAndy Fleming 
8443862b854SJean-Jacques Hiblot 	if (!ext_csd) {
845d8e3d420SJean-Jacques Hiblot 		pr_err("No ext_csd found!\n"); /* this should enver happen */
8463862b854SJean-Jacques Hiblot 		return -ENOTSUPP;
8473862b854SJean-Jacques Hiblot 	}
8483862b854SJean-Jacques Hiblot 
849fc5b32fbSAndrew Gabbasov 	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
850fc5b32fbSAndrew Gabbasov 
851634d4849SKishon Vijay Abraham I 	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0x3f;
852bc1e3272SJean-Jacques Hiblot 	mmc->cardtype = cardtype;
853272cc70bSAndy Fleming 
854634d4849SKishon Vijay Abraham I 	if (cardtype & (EXT_CSD_CARD_TYPE_HS200_1_2V |
855634d4849SKishon Vijay Abraham I 			EXT_CSD_CARD_TYPE_HS200_1_8V)) {
856634d4849SKishon Vijay Abraham I 		mmc->card_caps |= MMC_MODE_HS200;
857634d4849SKishon Vijay Abraham I 	}
858d22e3d46SJaehoon Chung 	if (cardtype & EXT_CSD_CARD_TYPE_52) {
8593862b854SJean-Jacques Hiblot 		if (cardtype & EXT_CSD_CARD_TYPE_DDR_52)
860d22e3d46SJaehoon Chung 			mmc->card_caps |= MMC_MODE_DDR_52MHz;
8613862b854SJean-Jacques Hiblot 		mmc->card_caps |= MMC_MODE_HS_52MHz;
862d22e3d46SJaehoon Chung 	}
8633862b854SJean-Jacques Hiblot 	if (cardtype & EXT_CSD_CARD_TYPE_26)
8643862b854SJean-Jacques Hiblot 		mmc->card_caps |= MMC_MODE_HS;
865272cc70bSAndy Fleming 
866272cc70bSAndy Fleming 	return 0;
867272cc70bSAndy Fleming }
868272cc70bSAndy Fleming 
869f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num)
870f866a46dSStephen Warren {
871f866a46dSStephen Warren 	switch (part_num) {
872f866a46dSStephen Warren 	case 0:
873f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_user;
874f866a46dSStephen Warren 		break;
875f866a46dSStephen Warren 	case 1:
876f866a46dSStephen Warren 	case 2:
877f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_boot;
878f866a46dSStephen Warren 		break;
879f866a46dSStephen Warren 	case 3:
880f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_rpmb;
881f866a46dSStephen Warren 		break;
882f866a46dSStephen Warren 	case 4:
883f866a46dSStephen Warren 	case 5:
884f866a46dSStephen Warren 	case 6:
885f866a46dSStephen Warren 	case 7:
886f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_gp[part_num - 4];
887f866a46dSStephen Warren 		break;
888f866a46dSStephen Warren 	default:
889f866a46dSStephen Warren 		return -1;
890f866a46dSStephen Warren 	}
891f866a46dSStephen Warren 
892c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len);
893f866a46dSStephen Warren 
894f866a46dSStephen Warren 	return 0;
895f866a46dSStephen Warren }
896f866a46dSStephen Warren 
897f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
89801298da3SJean-Jacques Hiblot static int mmc_boot_part_access_chk(struct mmc *mmc, unsigned int part_num)
89901298da3SJean-Jacques Hiblot {
90001298da3SJean-Jacques Hiblot 	int forbidden = 0;
90101298da3SJean-Jacques Hiblot 	bool change = false;
90201298da3SJean-Jacques Hiblot 
90301298da3SJean-Jacques Hiblot 	if (part_num & PART_ACCESS_MASK)
90401298da3SJean-Jacques Hiblot 		forbidden = MMC_CAP(MMC_HS_200);
90501298da3SJean-Jacques Hiblot 
90601298da3SJean-Jacques Hiblot 	if (MMC_CAP(mmc->selected_mode) & forbidden) {
90701298da3SJean-Jacques Hiblot 		debug("selected mode (%s) is forbidden for part %d\n",
90801298da3SJean-Jacques Hiblot 		      mmc_mode_name(mmc->selected_mode), part_num);
90901298da3SJean-Jacques Hiblot 		change = true;
91001298da3SJean-Jacques Hiblot 	} else if (mmc->selected_mode != mmc->best_mode) {
91101298da3SJean-Jacques Hiblot 		debug("selected mode is not optimal\n");
91201298da3SJean-Jacques Hiblot 		change = true;
91301298da3SJean-Jacques Hiblot 	}
91401298da3SJean-Jacques Hiblot 
91501298da3SJean-Jacques Hiblot 	if (change)
91601298da3SJean-Jacques Hiblot 		return mmc_select_mode_and_width(mmc,
91701298da3SJean-Jacques Hiblot 						 mmc->card_caps & ~forbidden);
91801298da3SJean-Jacques Hiblot 
91901298da3SJean-Jacques Hiblot 	return 0;
92001298da3SJean-Jacques Hiblot }
921f99c2efeSJean-Jacques Hiblot #else
922f99c2efeSJean-Jacques Hiblot static inline int mmc_boot_part_access_chk(struct mmc *mmc,
923f99c2efeSJean-Jacques Hiblot 					   unsigned int part_num)
924f99c2efeSJean-Jacques Hiblot {
925f99c2efeSJean-Jacques Hiblot 	return 0;
926f99c2efeSJean-Jacques Hiblot }
927f99c2efeSJean-Jacques Hiblot #endif
92801298da3SJean-Jacques Hiblot 
9297dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num)
930bc897b1dSLei Wen {
931f866a46dSStephen Warren 	int ret;
932bc897b1dSLei Wen 
93301298da3SJean-Jacques Hiblot 	ret = mmc_boot_part_access_chk(mmc, part_num);
93401298da3SJean-Jacques Hiblot 	if (ret)
93501298da3SJean-Jacques Hiblot 		return ret;
93601298da3SJean-Jacques Hiblot 
937f866a46dSStephen Warren 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
938bc897b1dSLei Wen 			 (mmc->part_config & ~PART_ACCESS_MASK)
939bc897b1dSLei Wen 			 | (part_num & PART_ACCESS_MASK));
940f866a46dSStephen Warren 
9416dc93e70SPeter Bigot 	/*
9426dc93e70SPeter Bigot 	 * Set the capacity if the switch succeeded or was intended
9436dc93e70SPeter Bigot 	 * to return to representing the raw device.
9446dc93e70SPeter Bigot 	 */
945873cc1d7SStephen Warren 	if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) {
9466dc93e70SPeter Bigot 		ret = mmc_set_capacity(mmc, part_num);
947fdbb139fSSimon Glass 		mmc_get_blk_desc(mmc)->hwpart = part_num;
948873cc1d7SStephen Warren 	}
9496dc93e70SPeter Bigot 
9506dc93e70SPeter Bigot 	return ret;
951bc897b1dSLei Wen }
952bc897b1dSLei Wen 
953*cf17789eSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HW_PARTITIONING)
954ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc,
955ac9da0e0SDiego Santa Cruz 		      const struct mmc_hwpart_conf *conf,
956ac9da0e0SDiego Santa Cruz 		      enum mmc_hwpart_conf_mode mode)
957ac9da0e0SDiego Santa Cruz {
958ac9da0e0SDiego Santa Cruz 	u8 part_attrs = 0;
959ac9da0e0SDiego Santa Cruz 	u32 enh_size_mult;
960ac9da0e0SDiego Santa Cruz 	u32 enh_start_addr;
961ac9da0e0SDiego Santa Cruz 	u32 gp_size_mult[4];
962ac9da0e0SDiego Santa Cruz 	u32 max_enh_size_mult;
963ac9da0e0SDiego Santa Cruz 	u32 tot_enh_size_mult = 0;
9648dda5b0eSDiego Santa Cruz 	u8 wr_rel_set;
965ac9da0e0SDiego Santa Cruz 	int i, pidx, err;
966ac9da0e0SDiego Santa Cruz 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
967ac9da0e0SDiego Santa Cruz 
968ac9da0e0SDiego Santa Cruz 	if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE)
969ac9da0e0SDiego Santa Cruz 		return -EINVAL;
970ac9da0e0SDiego Santa Cruz 
971ac9da0e0SDiego Santa Cruz 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) {
972d8e3d420SJean-Jacques Hiblot 		pr_err("eMMC >= 4.4 required for enhanced user data area\n");
973ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
974ac9da0e0SDiego Santa Cruz 	}
975ac9da0e0SDiego Santa Cruz 
976ac9da0e0SDiego Santa Cruz 	if (!(mmc->part_support & PART_SUPPORT)) {
977d8e3d420SJean-Jacques Hiblot 		pr_err("Card does not support partitioning\n");
978ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
979ac9da0e0SDiego Santa Cruz 	}
980ac9da0e0SDiego Santa Cruz 
981ac9da0e0SDiego Santa Cruz 	if (!mmc->hc_wp_grp_size) {
982d8e3d420SJean-Jacques Hiblot 		pr_err("Card does not define HC WP group size\n");
983ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
984ac9da0e0SDiego Santa Cruz 	}
985ac9da0e0SDiego Santa Cruz 
986ac9da0e0SDiego Santa Cruz 	/* check partition alignment and total enhanced size */
987ac9da0e0SDiego Santa Cruz 	if (conf->user.enh_size) {
988ac9da0e0SDiego Santa Cruz 		if (conf->user.enh_size % mmc->hc_wp_grp_size ||
989ac9da0e0SDiego Santa Cruz 		    conf->user.enh_start % mmc->hc_wp_grp_size) {
990d8e3d420SJean-Jacques Hiblot 			pr_err("User data enhanced area not HC WP group "
991ac9da0e0SDiego Santa Cruz 			       "size aligned\n");
992ac9da0e0SDiego Santa Cruz 			return -EINVAL;
993ac9da0e0SDiego Santa Cruz 		}
994ac9da0e0SDiego Santa Cruz 		part_attrs |= EXT_CSD_ENH_USR;
995ac9da0e0SDiego Santa Cruz 		enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size;
996ac9da0e0SDiego Santa Cruz 		if (mmc->high_capacity) {
997ac9da0e0SDiego Santa Cruz 			enh_start_addr = conf->user.enh_start;
998ac9da0e0SDiego Santa Cruz 		} else {
999ac9da0e0SDiego Santa Cruz 			enh_start_addr = (conf->user.enh_start << 9);
1000ac9da0e0SDiego Santa Cruz 		}
1001ac9da0e0SDiego Santa Cruz 	} else {
1002ac9da0e0SDiego Santa Cruz 		enh_size_mult = 0;
1003ac9da0e0SDiego Santa Cruz 		enh_start_addr = 0;
1004ac9da0e0SDiego Santa Cruz 	}
1005ac9da0e0SDiego Santa Cruz 	tot_enh_size_mult += enh_size_mult;
1006ac9da0e0SDiego Santa Cruz 
1007ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
1008ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) {
1009d8e3d420SJean-Jacques Hiblot 			pr_err("GP%i partition not HC WP group size "
1010ac9da0e0SDiego Santa Cruz 			       "aligned\n", pidx+1);
1011ac9da0e0SDiego Santa Cruz 			return -EINVAL;
1012ac9da0e0SDiego Santa Cruz 		}
1013ac9da0e0SDiego Santa Cruz 		gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size;
1014ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) {
1015ac9da0e0SDiego Santa Cruz 			part_attrs |= EXT_CSD_ENH_GP(pidx);
1016ac9da0e0SDiego Santa Cruz 			tot_enh_size_mult += gp_size_mult[pidx];
1017ac9da0e0SDiego Santa Cruz 		}
1018ac9da0e0SDiego Santa Cruz 	}
1019ac9da0e0SDiego Santa Cruz 
1020ac9da0e0SDiego Santa Cruz 	if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) {
1021d8e3d420SJean-Jacques Hiblot 		pr_err("Card does not support enhanced attribute\n");
1022ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1023ac9da0e0SDiego Santa Cruz 	}
1024ac9da0e0SDiego Santa Cruz 
1025ac9da0e0SDiego Santa Cruz 	err = mmc_send_ext_csd(mmc, ext_csd);
1026ac9da0e0SDiego Santa Cruz 	if (err)
1027ac9da0e0SDiego Santa Cruz 		return err;
1028ac9da0e0SDiego Santa Cruz 
1029ac9da0e0SDiego Santa Cruz 	max_enh_size_mult =
1030ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) +
1031ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) +
1032ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT];
1033ac9da0e0SDiego Santa Cruz 	if (tot_enh_size_mult > max_enh_size_mult) {
1034d8e3d420SJean-Jacques Hiblot 		pr_err("Total enhanced size exceeds maximum (%u > %u)\n",
1035ac9da0e0SDiego Santa Cruz 		       tot_enh_size_mult, max_enh_size_mult);
1036ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1037ac9da0e0SDiego Santa Cruz 	}
1038ac9da0e0SDiego Santa Cruz 
10398dda5b0eSDiego Santa Cruz 	/* The default value of EXT_CSD_WR_REL_SET is device
10408dda5b0eSDiego Santa Cruz 	 * dependent, the values can only be changed if the
10418dda5b0eSDiego Santa Cruz 	 * EXT_CSD_HS_CTRL_REL bit is set. The values can be
10428dda5b0eSDiego Santa Cruz 	 * changed only once and before partitioning is completed. */
10438dda5b0eSDiego Santa Cruz 	wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
10448dda5b0eSDiego Santa Cruz 	if (conf->user.wr_rel_change) {
10458dda5b0eSDiego Santa Cruz 		if (conf->user.wr_rel_set)
10468dda5b0eSDiego Santa Cruz 			wr_rel_set |= EXT_CSD_WR_DATA_REL_USR;
10478dda5b0eSDiego Santa Cruz 		else
10488dda5b0eSDiego Santa Cruz 			wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR;
10498dda5b0eSDiego Santa Cruz 	}
10508dda5b0eSDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
10518dda5b0eSDiego Santa Cruz 		if (conf->gp_part[pidx].wr_rel_change) {
10528dda5b0eSDiego Santa Cruz 			if (conf->gp_part[pidx].wr_rel_set)
10538dda5b0eSDiego Santa Cruz 				wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx);
10548dda5b0eSDiego Santa Cruz 			else
10558dda5b0eSDiego Santa Cruz 				wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx);
10568dda5b0eSDiego Santa Cruz 		}
10578dda5b0eSDiego Santa Cruz 	}
10588dda5b0eSDiego Santa Cruz 
10598dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] &&
10608dda5b0eSDiego Santa Cruz 	    !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) {
10618dda5b0eSDiego Santa Cruz 		puts("Card does not support host controlled partition write "
10628dda5b0eSDiego Santa Cruz 		     "reliability settings\n");
10638dda5b0eSDiego Santa Cruz 		return -EMEDIUMTYPE;
10648dda5b0eSDiego Santa Cruz 	}
10658dda5b0eSDiego Santa Cruz 
1066ac9da0e0SDiego Santa Cruz 	if (ext_csd[EXT_CSD_PARTITION_SETTING] &
1067ac9da0e0SDiego Santa Cruz 	    EXT_CSD_PARTITION_SETTING_COMPLETED) {
1068d8e3d420SJean-Jacques Hiblot 		pr_err("Card already partitioned\n");
1069ac9da0e0SDiego Santa Cruz 		return -EPERM;
1070ac9da0e0SDiego Santa Cruz 	}
1071ac9da0e0SDiego Santa Cruz 
1072ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_CHECK)
1073ac9da0e0SDiego Santa Cruz 		return 0;
1074ac9da0e0SDiego Santa Cruz 
1075ac9da0e0SDiego Santa Cruz 	/* Partitioning requires high-capacity size definitions */
1076ac9da0e0SDiego Santa Cruz 	if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) {
1077ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1078ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ERASE_GROUP_DEF, 1);
1079ac9da0e0SDiego Santa Cruz 
1080ac9da0e0SDiego Santa Cruz 		if (err)
1081ac9da0e0SDiego Santa Cruz 			return err;
1082ac9da0e0SDiego Santa Cruz 
1083ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1084ac9da0e0SDiego Santa Cruz 
1085ac9da0e0SDiego Santa Cruz 		/* update erase group size to be high-capacity */
1086ac9da0e0SDiego Santa Cruz 		mmc->erase_grp_size =
1087ac9da0e0SDiego Santa Cruz 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1088ac9da0e0SDiego Santa Cruz 
1089ac9da0e0SDiego Santa Cruz 	}
1090ac9da0e0SDiego Santa Cruz 
1091ac9da0e0SDiego Santa Cruz 	/* all OK, write the configuration */
1092ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 4; i++) {
1093ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1094ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_START_ADDR+i,
1095ac9da0e0SDiego Santa Cruz 				 (enh_start_addr >> (i*8)) & 0xFF);
1096ac9da0e0SDiego Santa Cruz 		if (err)
1097ac9da0e0SDiego Santa Cruz 			return err;
1098ac9da0e0SDiego Santa Cruz 	}
1099ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 3; i++) {
1100ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1101ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_SIZE_MULT+i,
1102ac9da0e0SDiego Santa Cruz 				 (enh_size_mult >> (i*8)) & 0xFF);
1103ac9da0e0SDiego Santa Cruz 		if (err)
1104ac9da0e0SDiego Santa Cruz 			return err;
1105ac9da0e0SDiego Santa Cruz 	}
1106ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
1107ac9da0e0SDiego Santa Cruz 		for (i = 0; i < 3; i++) {
1108ac9da0e0SDiego Santa Cruz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1109ac9da0e0SDiego Santa Cruz 					 EXT_CSD_GP_SIZE_MULT+pidx*3+i,
1110ac9da0e0SDiego Santa Cruz 					 (gp_size_mult[pidx] >> (i*8)) & 0xFF);
1111ac9da0e0SDiego Santa Cruz 			if (err)
1112ac9da0e0SDiego Santa Cruz 				return err;
1113ac9da0e0SDiego Santa Cruz 		}
1114ac9da0e0SDiego Santa Cruz 	}
1115ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1116ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs);
1117ac9da0e0SDiego Santa Cruz 	if (err)
1118ac9da0e0SDiego Santa Cruz 		return err;
1119ac9da0e0SDiego Santa Cruz 
1120ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_SET)
1121ac9da0e0SDiego Santa Cruz 		return 0;
1122ac9da0e0SDiego Santa Cruz 
11238dda5b0eSDiego Santa Cruz 	/* The WR_REL_SET is a write-once register but shall be
11248dda5b0eSDiego Santa Cruz 	 * written before setting PART_SETTING_COMPLETED. As it is
11258dda5b0eSDiego Santa Cruz 	 * write-once we can only write it when completing the
11268dda5b0eSDiego Santa Cruz 	 * partitioning. */
11278dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) {
11288dda5b0eSDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
11298dda5b0eSDiego Santa Cruz 				 EXT_CSD_WR_REL_SET, wr_rel_set);
11308dda5b0eSDiego Santa Cruz 		if (err)
11318dda5b0eSDiego Santa Cruz 			return err;
11328dda5b0eSDiego Santa Cruz 	}
11338dda5b0eSDiego Santa Cruz 
1134ac9da0e0SDiego Santa Cruz 	/* Setting PART_SETTING_COMPLETED confirms the partition
1135ac9da0e0SDiego Santa Cruz 	 * configuration but it only becomes effective after power
1136ac9da0e0SDiego Santa Cruz 	 * cycle, so we do not adjust the partition related settings
1137ac9da0e0SDiego Santa Cruz 	 * in the mmc struct. */
1138ac9da0e0SDiego Santa Cruz 
1139ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1140ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING,
1141ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING_COMPLETED);
1142ac9da0e0SDiego Santa Cruz 	if (err)
1143ac9da0e0SDiego Santa Cruz 		return err;
1144ac9da0e0SDiego Santa Cruz 
1145ac9da0e0SDiego Santa Cruz 	return 0;
1146ac9da0e0SDiego Santa Cruz }
1147*cf17789eSJean-Jacques Hiblot #endif
1148ac9da0e0SDiego Santa Cruz 
1149e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
115048972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
115148972d90SThierry Reding {
115248972d90SThierry Reding 	int cd;
115348972d90SThierry Reding 
115448972d90SThierry Reding 	cd = board_mmc_getcd(mmc);
115548972d90SThierry Reding 
1156d4e1da4eSPeter Korsgaard 	if (cd < 0) {
115793bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getcd)
115893bfd616SPantelis Antoniou 			cd = mmc->cfg->ops->getcd(mmc);
1159d4e1da4eSPeter Korsgaard 		else
1160d4e1da4eSPeter Korsgaard 			cd = 1;
1161d4e1da4eSPeter Korsgaard 	}
116248972d90SThierry Reding 
116348972d90SThierry Reding 	return cd;
116448972d90SThierry Reding }
11658ca51e51SSimon Glass #endif
116648972d90SThierry Reding 
1167fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
1168272cc70bSAndy Fleming {
1169272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1170272cc70bSAndy Fleming 	struct mmc_data data;
1171272cc70bSAndy Fleming 
1172272cc70bSAndy Fleming 	/* Switch the frequency */
1173272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
1174272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1175272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
1176272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
1177272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
1178272cc70bSAndy Fleming 
1179272cc70bSAndy Fleming 	data.dest = (char *)resp;
1180272cc70bSAndy Fleming 	data.blocksize = 64;
1181272cc70bSAndy Fleming 	data.blocks = 1;
1182272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
1183272cc70bSAndy Fleming 
1184272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
1185272cc70bSAndy Fleming }
1186272cc70bSAndy Fleming 
1187272cc70bSAndy Fleming 
1188d0c221feSJean-Jacques Hiblot static int sd_get_capabilities(struct mmc *mmc)
1189272cc70bSAndy Fleming {
1190272cc70bSAndy Fleming 	int err;
1191272cc70bSAndy Fleming 	struct mmc_cmd cmd;
119218e7c8f6SSuniel Mahesh 	ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2);
119318e7c8f6SSuniel Mahesh 	ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16);
1194272cc70bSAndy Fleming 	struct mmc_data data;
1195272cc70bSAndy Fleming 	int timeout;
1196f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1197c10b85d6SJean-Jacques Hiblot 	u32 sd3_bus_mode;
1198f99c2efeSJean-Jacques Hiblot #endif
1199272cc70bSAndy Fleming 
120000e446faSJean-Jacques Hiblot 	mmc->card_caps = MMC_MODE_1BIT | MMC_CAP(SD_LEGACY);
1201272cc70bSAndy Fleming 
1202d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
1203d52ebf10SThomas Chou 		return 0;
1204d52ebf10SThomas Chou 
1205272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
1206272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
1207272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1208272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1209272cc70bSAndy Fleming 
1210272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1211272cc70bSAndy Fleming 
1212272cc70bSAndy Fleming 	if (err)
1213272cc70bSAndy Fleming 		return err;
1214272cc70bSAndy Fleming 
1215272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
1216272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1217272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1218272cc70bSAndy Fleming 
1219272cc70bSAndy Fleming 	timeout = 3;
1220272cc70bSAndy Fleming 
1221272cc70bSAndy Fleming retry_scr:
1222f781dd38SAnton staaf 	data.dest = (char *)scr;
1223272cc70bSAndy Fleming 	data.blocksize = 8;
1224272cc70bSAndy Fleming 	data.blocks = 1;
1225272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
1226272cc70bSAndy Fleming 
1227272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
1228272cc70bSAndy Fleming 
1229272cc70bSAndy Fleming 	if (err) {
1230272cc70bSAndy Fleming 		if (timeout--)
1231272cc70bSAndy Fleming 			goto retry_scr;
1232272cc70bSAndy Fleming 
1233272cc70bSAndy Fleming 		return err;
1234272cc70bSAndy Fleming 	}
1235272cc70bSAndy Fleming 
12364e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
12374e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
1238272cc70bSAndy Fleming 
1239272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
1240272cc70bSAndy Fleming 	case 0:
1241272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1242272cc70bSAndy Fleming 		break;
1243272cc70bSAndy Fleming 	case 1:
1244272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_10;
1245272cc70bSAndy Fleming 		break;
1246272cc70bSAndy Fleming 	case 2:
1247272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
12481741c64dSJaehoon Chung 		if ((mmc->scr[0] >> 15) & 0x1)
12491741c64dSJaehoon Chung 			mmc->version = SD_VERSION_3;
1250272cc70bSAndy Fleming 		break;
1251272cc70bSAndy Fleming 	default:
1252272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1253272cc70bSAndy Fleming 		break;
1254272cc70bSAndy Fleming 	}
1255272cc70bSAndy Fleming 
1256b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
1257b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
1258b44c7083SAlagu Sankar 
1259272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
1260272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
1261272cc70bSAndy Fleming 		return 0;
1262272cc70bSAndy Fleming 
1263272cc70bSAndy Fleming 	timeout = 4;
1264272cc70bSAndy Fleming 	while (timeout--) {
1265272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
1266f781dd38SAnton staaf 				(u8 *)switch_status);
1267272cc70bSAndy Fleming 
1268272cc70bSAndy Fleming 		if (err)
1269272cc70bSAndy Fleming 			return err;
1270272cc70bSAndy Fleming 
1271272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
12724e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
1273272cc70bSAndy Fleming 			break;
1274272cc70bSAndy Fleming 	}
1275272cc70bSAndy Fleming 
1276272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
1277d0c221feSJean-Jacques Hiblot 	if (__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)
1278d0c221feSJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(SD_HS);
1279272cc70bSAndy Fleming 
1280f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1281c10b85d6SJean-Jacques Hiblot 	/* Version before 3.0 don't support UHS modes */
1282c10b85d6SJean-Jacques Hiblot 	if (mmc->version < SD_VERSION_3)
1283c10b85d6SJean-Jacques Hiblot 		return 0;
1284c10b85d6SJean-Jacques Hiblot 
1285c10b85d6SJean-Jacques Hiblot 	sd3_bus_mode = __be32_to_cpu(switch_status[3]) >> 16 & 0x1f;
1286c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR104)
1287c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR104);
1288c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR50)
1289c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR50);
1290c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR25)
1291c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR25);
1292c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR12)
1293c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR12);
1294c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_DDR50)
1295c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_DDR50);
1296f99c2efeSJean-Jacques Hiblot #endif
1297c10b85d6SJean-Jacques Hiblot 
12982c3fbf4cSMacpaul Lin 	return 0;
1299d0c221feSJean-Jacques Hiblot }
1300d0c221feSJean-Jacques Hiblot 
1301d0c221feSJean-Jacques Hiblot static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode)
1302d0c221feSJean-Jacques Hiblot {
1303d0c221feSJean-Jacques Hiblot 	int err;
1304d0c221feSJean-Jacques Hiblot 
1305d0c221feSJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
1306c10b85d6SJean-Jacques Hiblot 	int speed;
13072c3fbf4cSMacpaul Lin 
1308c10b85d6SJean-Jacques Hiblot 	switch (mode) {
1309c10b85d6SJean-Jacques Hiblot 	case SD_LEGACY:
1310c10b85d6SJean-Jacques Hiblot 	case UHS_SDR12:
1311c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR12_BUS_SPEED;
1312c10b85d6SJean-Jacques Hiblot 		break;
1313c10b85d6SJean-Jacques Hiblot 	case SD_HS:
1314c10b85d6SJean-Jacques Hiblot 	case UHS_SDR25:
1315c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR25_BUS_SPEED;
1316c10b85d6SJean-Jacques Hiblot 		break;
1317c10b85d6SJean-Jacques Hiblot 	case UHS_SDR50:
1318c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR50_BUS_SPEED;
1319c10b85d6SJean-Jacques Hiblot 		break;
1320c10b85d6SJean-Jacques Hiblot 	case UHS_DDR50:
1321c10b85d6SJean-Jacques Hiblot 		speed = UHS_DDR50_BUS_SPEED;
1322c10b85d6SJean-Jacques Hiblot 		break;
1323c10b85d6SJean-Jacques Hiblot 	case UHS_SDR104:
1324c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR104_BUS_SPEED;
1325c10b85d6SJean-Jacques Hiblot 		break;
1326c10b85d6SJean-Jacques Hiblot 	default:
1327c10b85d6SJean-Jacques Hiblot 		return -EINVAL;
1328c10b85d6SJean-Jacques Hiblot 	}
1329c10b85d6SJean-Jacques Hiblot 
1330c10b85d6SJean-Jacques Hiblot 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, speed, (u8 *)switch_status);
1331272cc70bSAndy Fleming 	if (err)
1332272cc70bSAndy Fleming 		return err;
1333272cc70bSAndy Fleming 
1334c10b85d6SJean-Jacques Hiblot 	if ((__be32_to_cpu(switch_status[4]) >> 24) != speed)
1335d0c221feSJean-Jacques Hiblot 		return -ENOTSUPP;
1336d0c221feSJean-Jacques Hiblot 
1337d0c221feSJean-Jacques Hiblot 	return 0;
1338d0c221feSJean-Jacques Hiblot }
1339d0c221feSJean-Jacques Hiblot 
1340d0c221feSJean-Jacques Hiblot int sd_select_bus_width(struct mmc *mmc, int w)
1341d0c221feSJean-Jacques Hiblot {
1342d0c221feSJean-Jacques Hiblot 	int err;
1343d0c221feSJean-Jacques Hiblot 	struct mmc_cmd cmd;
1344d0c221feSJean-Jacques Hiblot 
1345d0c221feSJean-Jacques Hiblot 	if ((w != 4) && (w != 1))
1346d0c221feSJean-Jacques Hiblot 		return -EINVAL;
1347d0c221feSJean-Jacques Hiblot 
1348d0c221feSJean-Jacques Hiblot 	cmd.cmdidx = MMC_CMD_APP_CMD;
1349d0c221feSJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
1350d0c221feSJean-Jacques Hiblot 	cmd.cmdarg = mmc->rca << 16;
1351d0c221feSJean-Jacques Hiblot 
1352d0c221feSJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
1353d0c221feSJean-Jacques Hiblot 	if (err)
1354d0c221feSJean-Jacques Hiblot 		return err;
1355d0c221feSJean-Jacques Hiblot 
1356d0c221feSJean-Jacques Hiblot 	cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
1357d0c221feSJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
1358d0c221feSJean-Jacques Hiblot 	if (w == 4)
1359d0c221feSJean-Jacques Hiblot 		cmd.cmdarg = 2;
1360d0c221feSJean-Jacques Hiblot 	else if (w == 1)
1361d0c221feSJean-Jacques Hiblot 		cmd.cmdarg = 0;
1362d0c221feSJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
1363d0c221feSJean-Jacques Hiblot 	if (err)
1364d0c221feSJean-Jacques Hiblot 		return err;
1365272cc70bSAndy Fleming 
1366272cc70bSAndy Fleming 	return 0;
1367272cc70bSAndy Fleming }
1368272cc70bSAndy Fleming 
13693697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc)
13703697e599SPeng Fan {
13713697e599SPeng Fan 	int err, i;
13723697e599SPeng Fan 	struct mmc_cmd cmd;
13733697e599SPeng Fan 	ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16);
13743697e599SPeng Fan 	struct mmc_data data;
13753697e599SPeng Fan 	int timeout = 3;
13763697e599SPeng Fan 	unsigned int au, eo, et, es;
13773697e599SPeng Fan 
13783697e599SPeng Fan 	cmd.cmdidx = MMC_CMD_APP_CMD;
13793697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
13803697e599SPeng Fan 	cmd.cmdarg = mmc->rca << 16;
13813697e599SPeng Fan 
13823697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, NULL);
13833697e599SPeng Fan 	if (err)
13843697e599SPeng Fan 		return err;
13853697e599SPeng Fan 
13863697e599SPeng Fan 	cmd.cmdidx = SD_CMD_APP_SD_STATUS;
13873697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
13883697e599SPeng Fan 	cmd.cmdarg = 0;
13893697e599SPeng Fan 
13903697e599SPeng Fan retry_ssr:
13913697e599SPeng Fan 	data.dest = (char *)ssr;
13923697e599SPeng Fan 	data.blocksize = 64;
13933697e599SPeng Fan 	data.blocks = 1;
13943697e599SPeng Fan 	data.flags = MMC_DATA_READ;
13953697e599SPeng Fan 
13963697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, &data);
13973697e599SPeng Fan 	if (err) {
13983697e599SPeng Fan 		if (timeout--)
13993697e599SPeng Fan 			goto retry_ssr;
14003697e599SPeng Fan 
14013697e599SPeng Fan 		return err;
14023697e599SPeng Fan 	}
14033697e599SPeng Fan 
14043697e599SPeng Fan 	for (i = 0; i < 16; i++)
14053697e599SPeng Fan 		ssr[i] = be32_to_cpu(ssr[i]);
14063697e599SPeng Fan 
14073697e599SPeng Fan 	au = (ssr[2] >> 12) & 0xF;
14083697e599SPeng Fan 	if ((au <= 9) || (mmc->version == SD_VERSION_3)) {
14093697e599SPeng Fan 		mmc->ssr.au = sd_au_size[au];
14103697e599SPeng Fan 		es = (ssr[3] >> 24) & 0xFF;
14113697e599SPeng Fan 		es |= (ssr[2] & 0xFF) << 8;
14123697e599SPeng Fan 		et = (ssr[3] >> 18) & 0x3F;
14133697e599SPeng Fan 		if (es && et) {
14143697e599SPeng Fan 			eo = (ssr[3] >> 16) & 0x3;
14153697e599SPeng Fan 			mmc->ssr.erase_timeout = (et * 1000) / es;
14163697e599SPeng Fan 			mmc->ssr.erase_offset = eo * 1000;
14173697e599SPeng Fan 		}
14183697e599SPeng Fan 	} else {
14193697e599SPeng Fan 		debug("Invalid Allocation Unit Size.\n");
14203697e599SPeng Fan 	}
14213697e599SPeng Fan 
14223697e599SPeng Fan 	return 0;
14233697e599SPeng Fan }
14243697e599SPeng Fan 
1425272cc70bSAndy Fleming /* frequency bases */
1426272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
14275f837c2cSMike Frysinger static const int fbase[] = {
1428272cc70bSAndy Fleming 	10000,
1429272cc70bSAndy Fleming 	100000,
1430272cc70bSAndy Fleming 	1000000,
1431272cc70bSAndy Fleming 	10000000,
1432272cc70bSAndy Fleming };
1433272cc70bSAndy Fleming 
1434272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
1435272cc70bSAndy Fleming  * to platforms without floating point.
1436272cc70bSAndy Fleming  */
143761fe076fSSimon Glass static const u8 multipliers[] = {
1438272cc70bSAndy Fleming 	0,	/* reserved */
1439272cc70bSAndy Fleming 	10,
1440272cc70bSAndy Fleming 	12,
1441272cc70bSAndy Fleming 	13,
1442272cc70bSAndy Fleming 	15,
1443272cc70bSAndy Fleming 	20,
1444272cc70bSAndy Fleming 	25,
1445272cc70bSAndy Fleming 	30,
1446272cc70bSAndy Fleming 	35,
1447272cc70bSAndy Fleming 	40,
1448272cc70bSAndy Fleming 	45,
1449272cc70bSAndy Fleming 	50,
1450272cc70bSAndy Fleming 	55,
1451272cc70bSAndy Fleming 	60,
1452272cc70bSAndy Fleming 	70,
1453272cc70bSAndy Fleming 	80,
1454272cc70bSAndy Fleming };
1455272cc70bSAndy Fleming 
1456d0c221feSJean-Jacques Hiblot static inline int bus_width(uint cap)
1457d0c221feSJean-Jacques Hiblot {
1458d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_8BIT)
1459d0c221feSJean-Jacques Hiblot 		return 8;
1460d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_4BIT)
1461d0c221feSJean-Jacques Hiblot 		return 4;
1462d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_1BIT)
1463d0c221feSJean-Jacques Hiblot 		return 1;
1464d8e3d420SJean-Jacques Hiblot 	pr_warn("invalid bus witdh capability 0x%x\n", cap);
1465d0c221feSJean-Jacques Hiblot 	return 0;
1466d0c221feSJean-Jacques Hiblot }
1467d0c221feSJean-Jacques Hiblot 
1468e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
1469f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
1470ec841209SKishon Vijay Abraham I static int mmc_execute_tuning(struct mmc *mmc, uint opcode)
1471ec841209SKishon Vijay Abraham I {
1472ec841209SKishon Vijay Abraham I 	return -ENOTSUPP;
1473ec841209SKishon Vijay Abraham I }
1474f99c2efeSJean-Jacques Hiblot #endif
1475ec841209SKishon Vijay Abraham I 
1476318a7a57SJean-Jacques Hiblot static void mmc_send_init_stream(struct mmc *mmc)
1477318a7a57SJean-Jacques Hiblot {
1478318a7a57SJean-Jacques Hiblot }
1479318a7a57SJean-Jacques Hiblot 
14802a4d212fSKishon Vijay Abraham I static int mmc_set_ios(struct mmc *mmc)
1481272cc70bSAndy Fleming {
14822a4d212fSKishon Vijay Abraham I 	int ret = 0;
14832a4d212fSKishon Vijay Abraham I 
148493bfd616SPantelis Antoniou 	if (mmc->cfg->ops->set_ios)
14852a4d212fSKishon Vijay Abraham I 		ret = mmc->cfg->ops->set_ios(mmc);
14862a4d212fSKishon Vijay Abraham I 
14872a4d212fSKishon Vijay Abraham I 	return ret;
1488272cc70bSAndy Fleming }
14898ca51e51SSimon Glass #endif
1490272cc70bSAndy Fleming 
149135f67820SKishon Vijay Abraham I int mmc_set_clock(struct mmc *mmc, uint clock, bool disable)
1492272cc70bSAndy Fleming {
149393bfd616SPantelis Antoniou 	if (clock > mmc->cfg->f_max)
149493bfd616SPantelis Antoniou 		clock = mmc->cfg->f_max;
1495272cc70bSAndy Fleming 
149693bfd616SPantelis Antoniou 	if (clock < mmc->cfg->f_min)
149793bfd616SPantelis Antoniou 		clock = mmc->cfg->f_min;
1498272cc70bSAndy Fleming 
1499272cc70bSAndy Fleming 	mmc->clock = clock;
150035f67820SKishon Vijay Abraham I 	mmc->clk_disable = disable;
1501272cc70bSAndy Fleming 
15022a4d212fSKishon Vijay Abraham I 	return mmc_set_ios(mmc);
1503272cc70bSAndy Fleming }
1504272cc70bSAndy Fleming 
15052a4d212fSKishon Vijay Abraham I static int mmc_set_bus_width(struct mmc *mmc, uint width)
1506272cc70bSAndy Fleming {
1507272cc70bSAndy Fleming 	mmc->bus_width = width;
1508272cc70bSAndy Fleming 
15092a4d212fSKishon Vijay Abraham I 	return mmc_set_ios(mmc);
1510272cc70bSAndy Fleming }
1511272cc70bSAndy Fleming 
15124c9d2aaaSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG)
15134c9d2aaaSJean-Jacques Hiblot /*
15144c9d2aaaSJean-Jacques Hiblot  * helper function to display the capabilities in a human
15154c9d2aaaSJean-Jacques Hiblot  * friendly manner. The capabilities include bus width and
15164c9d2aaaSJean-Jacques Hiblot  * supported modes.
15174c9d2aaaSJean-Jacques Hiblot  */
15184c9d2aaaSJean-Jacques Hiblot void mmc_dump_capabilities(const char *text, uint caps)
15194c9d2aaaSJean-Jacques Hiblot {
15204c9d2aaaSJean-Jacques Hiblot 	enum bus_mode mode;
15214c9d2aaaSJean-Jacques Hiblot 
15224c9d2aaaSJean-Jacques Hiblot 	printf("%s: widths [", text);
15234c9d2aaaSJean-Jacques Hiblot 	if (caps & MMC_MODE_8BIT)
15244c9d2aaaSJean-Jacques Hiblot 		printf("8, ");
15254c9d2aaaSJean-Jacques Hiblot 	if (caps & MMC_MODE_4BIT)
15264c9d2aaaSJean-Jacques Hiblot 		printf("4, ");
1527d0c221feSJean-Jacques Hiblot 	if (caps & MMC_MODE_1BIT)
1528d0c221feSJean-Jacques Hiblot 		printf("1, ");
1529d0c221feSJean-Jacques Hiblot 	printf("\b\b] modes [");
15304c9d2aaaSJean-Jacques Hiblot 	for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++)
15314c9d2aaaSJean-Jacques Hiblot 		if (MMC_CAP(mode) & caps)
15324c9d2aaaSJean-Jacques Hiblot 			printf("%s, ", mmc_mode_name(mode));
15334c9d2aaaSJean-Jacques Hiblot 	printf("\b\b]\n");
15344c9d2aaaSJean-Jacques Hiblot }
15354c9d2aaaSJean-Jacques Hiblot #endif
15364c9d2aaaSJean-Jacques Hiblot 
1537d0c221feSJean-Jacques Hiblot struct mode_width_tuning {
1538d0c221feSJean-Jacques Hiblot 	enum bus_mode mode;
1539d0c221feSJean-Jacques Hiblot 	uint widths;
1540f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
1541634d4849SKishon Vijay Abraham I 	uint tuning;
1542f99c2efeSJean-Jacques Hiblot #endif
1543d0c221feSJean-Jacques Hiblot };
1544d0c221feSJean-Jacques Hiblot 
1545f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE)
1546bc1e3272SJean-Jacques Hiblot int mmc_voltage_to_mv(enum mmc_voltage voltage)
1547bc1e3272SJean-Jacques Hiblot {
1548bc1e3272SJean-Jacques Hiblot 	switch (voltage) {
1549bc1e3272SJean-Jacques Hiblot 	case MMC_SIGNAL_VOLTAGE_000: return 0;
1550bc1e3272SJean-Jacques Hiblot 	case MMC_SIGNAL_VOLTAGE_330: return 3300;
1551bc1e3272SJean-Jacques Hiblot 	case MMC_SIGNAL_VOLTAGE_180: return 1800;
1552bc1e3272SJean-Jacques Hiblot 	case MMC_SIGNAL_VOLTAGE_120: return 1200;
1553bc1e3272SJean-Jacques Hiblot 	}
1554bc1e3272SJean-Jacques Hiblot 	return -EINVAL;
1555bc1e3272SJean-Jacques Hiblot }
1556bc1e3272SJean-Jacques Hiblot 
1557aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage)
1558aff5d3c8SKishon Vijay Abraham I {
1559bc1e3272SJean-Jacques Hiblot 	int err;
1560bc1e3272SJean-Jacques Hiblot 
1561bc1e3272SJean-Jacques Hiblot 	if (mmc->signal_voltage == signal_voltage)
1562bc1e3272SJean-Jacques Hiblot 		return 0;
1563bc1e3272SJean-Jacques Hiblot 
1564aff5d3c8SKishon Vijay Abraham I 	mmc->signal_voltage = signal_voltage;
1565bc1e3272SJean-Jacques Hiblot 	err = mmc_set_ios(mmc);
1566bc1e3272SJean-Jacques Hiblot 	if (err)
1567bc1e3272SJean-Jacques Hiblot 		debug("unable to set voltage (err %d)\n", err);
1568bc1e3272SJean-Jacques Hiblot 
1569bc1e3272SJean-Jacques Hiblot 	return err;
1570aff5d3c8SKishon Vijay Abraham I }
1571f99c2efeSJean-Jacques Hiblot #else
1572f99c2efeSJean-Jacques Hiblot static inline int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage)
1573f99c2efeSJean-Jacques Hiblot {
1574f99c2efeSJean-Jacques Hiblot 	return 0;
1575f99c2efeSJean-Jacques Hiblot }
1576f99c2efeSJean-Jacques Hiblot #endif
1577aff5d3c8SKishon Vijay Abraham I 
1578d0c221feSJean-Jacques Hiblot static const struct mode_width_tuning sd_modes_by_pref[] = {
1579f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1580f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
1581d0c221feSJean-Jacques Hiblot 	{
1582c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR104,
1583c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1584c10b85d6SJean-Jacques Hiblot 		.tuning = MMC_CMD_SEND_TUNING_BLOCK
1585c10b85d6SJean-Jacques Hiblot 	},
1586f99c2efeSJean-Jacques Hiblot #endif
1587c10b85d6SJean-Jacques Hiblot 	{
1588c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR50,
1589c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1590c10b85d6SJean-Jacques Hiblot 	},
1591c10b85d6SJean-Jacques Hiblot 	{
1592c10b85d6SJean-Jacques Hiblot 		.mode = UHS_DDR50,
1593c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1594c10b85d6SJean-Jacques Hiblot 	},
1595c10b85d6SJean-Jacques Hiblot 	{
1596c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR25,
1597c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1598c10b85d6SJean-Jacques Hiblot 	},
1599f99c2efeSJean-Jacques Hiblot #endif
1600c10b85d6SJean-Jacques Hiblot 	{
1601d0c221feSJean-Jacques Hiblot 		.mode = SD_HS,
1602d0c221feSJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1603d0c221feSJean-Jacques Hiblot 	},
1604f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1605d0c221feSJean-Jacques Hiblot 	{
1606c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR12,
1607c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1608c10b85d6SJean-Jacques Hiblot 	},
1609f99c2efeSJean-Jacques Hiblot #endif
1610c10b85d6SJean-Jacques Hiblot 	{
1611d0c221feSJean-Jacques Hiblot 		.mode = SD_LEGACY,
1612d0c221feSJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1613d0c221feSJean-Jacques Hiblot 	}
1614d0c221feSJean-Jacques Hiblot };
1615d0c221feSJean-Jacques Hiblot 
1616d0c221feSJean-Jacques Hiblot #define for_each_sd_mode_by_pref(caps, mwt) \
1617d0c221feSJean-Jacques Hiblot 	for (mwt = sd_modes_by_pref;\
1618d0c221feSJean-Jacques Hiblot 	     mwt < sd_modes_by_pref + ARRAY_SIZE(sd_modes_by_pref);\
1619d0c221feSJean-Jacques Hiblot 	     mwt++) \
1620d0c221feSJean-Jacques Hiblot 		if (caps & MMC_CAP(mwt->mode))
1621d0c221feSJean-Jacques Hiblot 
162201298da3SJean-Jacques Hiblot static int sd_select_mode_and_width(struct mmc *mmc, uint card_caps)
16238ac8a263SJean-Jacques Hiblot {
16248ac8a263SJean-Jacques Hiblot 	int err;
1625d0c221feSJean-Jacques Hiblot 	uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT};
1626d0c221feSJean-Jacques Hiblot 	const struct mode_width_tuning *mwt;
1627f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_UHS_SUPPORT)
1628c10b85d6SJean-Jacques Hiblot 	bool uhs_en = (mmc->ocr & OCR_S18R) ? true : false;
1629f99c2efeSJean-Jacques Hiblot #else
1630f99c2efeSJean-Jacques Hiblot 	bool uhs_en = false;
1631f99c2efeSJean-Jacques Hiblot #endif
1632c10b85d6SJean-Jacques Hiblot 	uint caps;
1633c10b85d6SJean-Jacques Hiblot 
163452d241dfSJean-Jacques Hiblot #ifdef DEBUG
163552d241dfSJean-Jacques Hiblot 	mmc_dump_capabilities("sd card", card_caps);
16361da8eb59SJean-Jacques Hiblot 	mmc_dump_capabilities("host", mmc->host_caps);
163752d241dfSJean-Jacques Hiblot #endif
16388ac8a263SJean-Jacques Hiblot 
16398ac8a263SJean-Jacques Hiblot 	/* Restrict card's capabilities by what the host can do */
16401da8eb59SJean-Jacques Hiblot 	caps = card_caps & mmc->host_caps;
16418ac8a263SJean-Jacques Hiblot 
1642c10b85d6SJean-Jacques Hiblot 	if (!uhs_en)
1643c10b85d6SJean-Jacques Hiblot 		caps &= ~UHS_CAPS;
1644c10b85d6SJean-Jacques Hiblot 
1645c10b85d6SJean-Jacques Hiblot 	for_each_sd_mode_by_pref(caps, mwt) {
1646d0c221feSJean-Jacques Hiblot 		uint *w;
16478ac8a263SJean-Jacques Hiblot 
1648d0c221feSJean-Jacques Hiblot 		for (w = widths; w < widths + ARRAY_SIZE(widths); w++) {
1649c10b85d6SJean-Jacques Hiblot 			if (*w & caps & mwt->widths) {
1650d0c221feSJean-Jacques Hiblot 				debug("trying mode %s width %d (at %d MHz)\n",
1651d0c221feSJean-Jacques Hiblot 				      mmc_mode_name(mwt->mode),
1652d0c221feSJean-Jacques Hiblot 				      bus_width(*w),
1653d0c221feSJean-Jacques Hiblot 				      mmc_mode2freq(mmc, mwt->mode) / 1000000);
1654d0c221feSJean-Jacques Hiblot 
1655d0c221feSJean-Jacques Hiblot 				/* configure the bus width (card + host) */
1656d0c221feSJean-Jacques Hiblot 				err = sd_select_bus_width(mmc, bus_width(*w));
16578ac8a263SJean-Jacques Hiblot 				if (err)
1658d0c221feSJean-Jacques Hiblot 					goto error;
1659d0c221feSJean-Jacques Hiblot 				mmc_set_bus_width(mmc, bus_width(*w));
16608ac8a263SJean-Jacques Hiblot 
1661d0c221feSJean-Jacques Hiblot 				/* configure the bus mode (card) */
1662d0c221feSJean-Jacques Hiblot 				err = sd_set_card_speed(mmc, mwt->mode);
16638ac8a263SJean-Jacques Hiblot 				if (err)
1664d0c221feSJean-Jacques Hiblot 					goto error;
16658ac8a263SJean-Jacques Hiblot 
1666d0c221feSJean-Jacques Hiblot 				/* configure the bus mode (host) */
1667d0c221feSJean-Jacques Hiblot 				mmc_select_mode(mmc, mwt->mode);
166835f67820SKishon Vijay Abraham I 				mmc_set_clock(mmc, mmc->tran_speed, false);
16698ac8a263SJean-Jacques Hiblot 
1670f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
1671c10b85d6SJean-Jacques Hiblot 				/* execute tuning if needed */
1672c10b85d6SJean-Jacques Hiblot 				if (mwt->tuning && !mmc_host_is_spi(mmc)) {
1673c10b85d6SJean-Jacques Hiblot 					err = mmc_execute_tuning(mmc,
1674c10b85d6SJean-Jacques Hiblot 								 mwt->tuning);
1675c10b85d6SJean-Jacques Hiblot 					if (err) {
1676c10b85d6SJean-Jacques Hiblot 						debug("tuning failed\n");
1677c10b85d6SJean-Jacques Hiblot 						goto error;
1678c10b85d6SJean-Jacques Hiblot 					}
1679c10b85d6SJean-Jacques Hiblot 				}
1680f99c2efeSJean-Jacques Hiblot #endif
1681c10b85d6SJean-Jacques Hiblot 
16828ac8a263SJean-Jacques Hiblot 				err = sd_read_ssr(mmc);
1683d0c221feSJean-Jacques Hiblot 				if (!err)
16848ac8a263SJean-Jacques Hiblot 					return 0;
1685d0c221feSJean-Jacques Hiblot 
1686d8e3d420SJean-Jacques Hiblot 				pr_warn("bad ssr\n");
1687d0c221feSJean-Jacques Hiblot 
1688d0c221feSJean-Jacques Hiblot error:
1689d0c221feSJean-Jacques Hiblot 				/* revert to a safer bus speed */
1690d0c221feSJean-Jacques Hiblot 				mmc_select_mode(mmc, SD_LEGACY);
169135f67820SKishon Vijay Abraham I 				mmc_set_clock(mmc, mmc->tran_speed, false);
1692d0c221feSJean-Jacques Hiblot 			}
1693d0c221feSJean-Jacques Hiblot 		}
1694d0c221feSJean-Jacques Hiblot 	}
1695d0c221feSJean-Jacques Hiblot 
1696d0c221feSJean-Jacques Hiblot 	printf("unable to select a mode\n");
1697d0c221feSJean-Jacques Hiblot 	return -ENOTSUPP;
16988ac8a263SJean-Jacques Hiblot }
16998ac8a263SJean-Jacques Hiblot 
17007382e691SJean-Jacques Hiblot /*
17017382e691SJean-Jacques Hiblot  * read the compare the part of ext csd that is constant.
17027382e691SJean-Jacques Hiblot  * This can be used to check that the transfer is working
17037382e691SJean-Jacques Hiblot  * as expected.
17047382e691SJean-Jacques Hiblot  */
17057382e691SJean-Jacques Hiblot static int mmc_read_and_compare_ext_csd(struct mmc *mmc)
17067382e691SJean-Jacques Hiblot {
17077382e691SJean-Jacques Hiblot 	int err;
17087382e691SJean-Jacques Hiblot 	const u8 *ext_csd = mmc->ext_csd;
17097382e691SJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
17107382e691SJean-Jacques Hiblot 
17111de06b9fSJean-Jacques Hiblot 	if (mmc->version < MMC_VERSION_4)
17121de06b9fSJean-Jacques Hiblot 		return 0;
17131de06b9fSJean-Jacques Hiblot 
17147382e691SJean-Jacques Hiblot 	err = mmc_send_ext_csd(mmc, test_csd);
17157382e691SJean-Jacques Hiblot 	if (err)
17167382e691SJean-Jacques Hiblot 		return err;
17177382e691SJean-Jacques Hiblot 
17187382e691SJean-Jacques Hiblot 	/* Only compare read only fields */
17197382e691SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT]
17207382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_PARTITIONING_SUPPORT] &&
17217382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_HC_WP_GRP_SIZE]
17227382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_HC_WP_GRP_SIZE] &&
17237382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_REV]
17247382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_REV] &&
17257382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
17267382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] &&
17277382e691SJean-Jacques Hiblot 	    memcmp(&ext_csd[EXT_CSD_SEC_CNT],
17287382e691SJean-Jacques Hiblot 		   &test_csd[EXT_CSD_SEC_CNT], 4) == 0)
17297382e691SJean-Jacques Hiblot 		return 0;
17307382e691SJean-Jacques Hiblot 
17317382e691SJean-Jacques Hiblot 	return -EBADMSG;
17327382e691SJean-Jacques Hiblot }
17337382e691SJean-Jacques Hiblot 
1734f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_IO_VOLTAGE)
1735bc1e3272SJean-Jacques Hiblot static int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,
1736bc1e3272SJean-Jacques Hiblot 				  uint32_t allowed_mask)
1737bc1e3272SJean-Jacques Hiblot {
1738bc1e3272SJean-Jacques Hiblot 	u32 card_mask = 0;
1739bc1e3272SJean-Jacques Hiblot 
1740bc1e3272SJean-Jacques Hiblot 	switch (mode) {
1741bc1e3272SJean-Jacques Hiblot 	case MMC_HS_200:
1742bc1e3272SJean-Jacques Hiblot 		if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_8V)
1743bc1e3272SJean-Jacques Hiblot 			card_mask |= MMC_SIGNAL_VOLTAGE_180;
1744bc1e3272SJean-Jacques Hiblot 		if (mmc->cardtype & EXT_CSD_CARD_TYPE_HS200_1_2V)
1745bc1e3272SJean-Jacques Hiblot 			card_mask |= MMC_SIGNAL_VOLTAGE_120;
1746bc1e3272SJean-Jacques Hiblot 		break;
1747bc1e3272SJean-Jacques Hiblot 	case MMC_DDR_52:
1748bc1e3272SJean-Jacques Hiblot 		if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V)
1749bc1e3272SJean-Jacques Hiblot 			card_mask |= MMC_SIGNAL_VOLTAGE_330 |
1750bc1e3272SJean-Jacques Hiblot 				     MMC_SIGNAL_VOLTAGE_180;
1751bc1e3272SJean-Jacques Hiblot 		if (mmc->cardtype & EXT_CSD_CARD_TYPE_DDR_1_2V)
1752bc1e3272SJean-Jacques Hiblot 			card_mask |= MMC_SIGNAL_VOLTAGE_120;
1753bc1e3272SJean-Jacques Hiblot 		break;
1754bc1e3272SJean-Jacques Hiblot 	default:
1755bc1e3272SJean-Jacques Hiblot 		card_mask |= MMC_SIGNAL_VOLTAGE_330;
1756bc1e3272SJean-Jacques Hiblot 		break;
1757bc1e3272SJean-Jacques Hiblot 	}
1758bc1e3272SJean-Jacques Hiblot 
1759bc1e3272SJean-Jacques Hiblot 	while (card_mask & allowed_mask) {
1760bc1e3272SJean-Jacques Hiblot 		enum mmc_voltage best_match;
1761bc1e3272SJean-Jacques Hiblot 
1762bc1e3272SJean-Jacques Hiblot 		best_match = 1 << (ffs(card_mask & allowed_mask) - 1);
1763bc1e3272SJean-Jacques Hiblot 		if (!mmc_set_signal_voltage(mmc,  best_match))
1764bc1e3272SJean-Jacques Hiblot 			return 0;
1765bc1e3272SJean-Jacques Hiblot 
1766bc1e3272SJean-Jacques Hiblot 		allowed_mask &= ~best_match;
1767bc1e3272SJean-Jacques Hiblot 	}
1768bc1e3272SJean-Jacques Hiblot 
1769bc1e3272SJean-Jacques Hiblot 	return -ENOTSUPP;
1770bc1e3272SJean-Jacques Hiblot }
1771f99c2efeSJean-Jacques Hiblot #else
1772f99c2efeSJean-Jacques Hiblot static inline int mmc_set_lowest_voltage(struct mmc *mmc, enum bus_mode mode,
1773f99c2efeSJean-Jacques Hiblot 					 uint32_t allowed_mask)
1774f99c2efeSJean-Jacques Hiblot {
1775f99c2efeSJean-Jacques Hiblot 	return 0;
1776f99c2efeSJean-Jacques Hiblot }
1777f99c2efeSJean-Jacques Hiblot #endif
1778bc1e3272SJean-Jacques Hiblot 
17793862b854SJean-Jacques Hiblot static const struct mode_width_tuning mmc_modes_by_pref[] = {
1780f99c2efeSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_HS200_SUPPORT)
17818ac8a263SJean-Jacques Hiblot 	{
17823862b854SJean-Jacques Hiblot 		.mode = MMC_HS_200,
17833862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
1784634d4849SKishon Vijay Abraham I 		.tuning = MMC_CMD_SEND_TUNING_BLOCK_HS200
17853862b854SJean-Jacques Hiblot 	},
1786f99c2efeSJean-Jacques Hiblot #endif
17873862b854SJean-Jacques Hiblot 	{
17883862b854SJean-Jacques Hiblot 		.mode = MMC_DDR_52,
17893862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
17903862b854SJean-Jacques Hiblot 	},
17913862b854SJean-Jacques Hiblot 	{
17923862b854SJean-Jacques Hiblot 		.mode = MMC_HS_52,
17933862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
17943862b854SJean-Jacques Hiblot 	},
17953862b854SJean-Jacques Hiblot 	{
17963862b854SJean-Jacques Hiblot 		.mode = MMC_HS,
17973862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
17983862b854SJean-Jacques Hiblot 	},
17993862b854SJean-Jacques Hiblot 	{
18003862b854SJean-Jacques Hiblot 		.mode = MMC_LEGACY,
18013862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
18023862b854SJean-Jacques Hiblot 	}
18038ac8a263SJean-Jacques Hiblot };
18048ac8a263SJean-Jacques Hiblot 
18053862b854SJean-Jacques Hiblot #define for_each_mmc_mode_by_pref(caps, mwt) \
18063862b854SJean-Jacques Hiblot 	for (mwt = mmc_modes_by_pref;\
18073862b854SJean-Jacques Hiblot 	    mwt < mmc_modes_by_pref + ARRAY_SIZE(mmc_modes_by_pref);\
18083862b854SJean-Jacques Hiblot 	    mwt++) \
18093862b854SJean-Jacques Hiblot 		if (caps & MMC_CAP(mwt->mode))
18103862b854SJean-Jacques Hiblot 
18113862b854SJean-Jacques Hiblot static const struct ext_csd_bus_width {
18123862b854SJean-Jacques Hiblot 	uint cap;
18133862b854SJean-Jacques Hiblot 	bool is_ddr;
18143862b854SJean-Jacques Hiblot 	uint ext_csd_bits;
18153862b854SJean-Jacques Hiblot } ext_csd_bus_width[] = {
18163862b854SJean-Jacques Hiblot 	{MMC_MODE_8BIT, true, EXT_CSD_DDR_BUS_WIDTH_8},
18173862b854SJean-Jacques Hiblot 	{MMC_MODE_4BIT, true, EXT_CSD_DDR_BUS_WIDTH_4},
18183862b854SJean-Jacques Hiblot 	{MMC_MODE_8BIT, false, EXT_CSD_BUS_WIDTH_8},
18193862b854SJean-Jacques Hiblot 	{MMC_MODE_4BIT, false, EXT_CSD_BUS_WIDTH_4},
18203862b854SJean-Jacques Hiblot 	{MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1},
18213862b854SJean-Jacques Hiblot };
18223862b854SJean-Jacques Hiblot 
18233862b854SJean-Jacques Hiblot #define for_each_supported_width(caps, ddr, ecbv) \
18243862b854SJean-Jacques Hiblot 	for (ecbv = ext_csd_bus_width;\
18253862b854SJean-Jacques Hiblot 	    ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\
18263862b854SJean-Jacques Hiblot 	    ecbv++) \
18273862b854SJean-Jacques Hiblot 		if ((ddr == ecbv->is_ddr) && (caps & ecbv->cap))
18283862b854SJean-Jacques Hiblot 
182901298da3SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc, uint card_caps)
18303862b854SJean-Jacques Hiblot {
18313862b854SJean-Jacques Hiblot 	int err;
18323862b854SJean-Jacques Hiblot 	const struct mode_width_tuning *mwt;
18333862b854SJean-Jacques Hiblot 	const struct ext_csd_bus_width *ecbw;
18343862b854SJean-Jacques Hiblot 
183552d241dfSJean-Jacques Hiblot #ifdef DEBUG
183652d241dfSJean-Jacques Hiblot 	mmc_dump_capabilities("mmc", card_caps);
18371da8eb59SJean-Jacques Hiblot 	mmc_dump_capabilities("host", mmc->host_caps);
183852d241dfSJean-Jacques Hiblot #endif
183952d241dfSJean-Jacques Hiblot 
18408ac8a263SJean-Jacques Hiblot 	/* Restrict card's capabilities by what the host can do */
18411da8eb59SJean-Jacques Hiblot 	card_caps &= mmc->host_caps;
18428ac8a263SJean-Jacques Hiblot 
18438ac8a263SJean-Jacques Hiblot 	/* Only version 4 of MMC supports wider bus widths */
18448ac8a263SJean-Jacques Hiblot 	if (mmc->version < MMC_VERSION_4)
18458ac8a263SJean-Jacques Hiblot 		return 0;
18468ac8a263SJean-Jacques Hiblot 
1847dfda9d88SJean-Jacques Hiblot 	if (!mmc->ext_csd) {
1848dfda9d88SJean-Jacques Hiblot 		debug("No ext_csd found!\n"); /* this should enver happen */
1849dfda9d88SJean-Jacques Hiblot 		return -ENOTSUPP;
1850dfda9d88SJean-Jacques Hiblot 	}
1851dfda9d88SJean-Jacques Hiblot 
185201298da3SJean-Jacques Hiblot 	mmc_set_clock(mmc, mmc->legacy_speed, false);
185301298da3SJean-Jacques Hiblot 
185401298da3SJean-Jacques Hiblot 	for_each_mmc_mode_by_pref(card_caps, mwt) {
185501298da3SJean-Jacques Hiblot 		for_each_supported_width(card_caps & mwt->widths,
18563862b854SJean-Jacques Hiblot 					 mmc_is_mode_ddr(mwt->mode), ecbw) {
1857bc1e3272SJean-Jacques Hiblot 			enum mmc_voltage old_voltage;
18583862b854SJean-Jacques Hiblot 			debug("trying mode %s width %d (at %d MHz)\n",
18593862b854SJean-Jacques Hiblot 			      mmc_mode_name(mwt->mode),
18603862b854SJean-Jacques Hiblot 			      bus_width(ecbw->cap),
18613862b854SJean-Jacques Hiblot 			      mmc_mode2freq(mmc, mwt->mode) / 1000000);
1862bc1e3272SJean-Jacques Hiblot 			old_voltage = mmc->signal_voltage;
1863bc1e3272SJean-Jacques Hiblot 			err = mmc_set_lowest_voltage(mmc, mwt->mode,
1864bc1e3272SJean-Jacques Hiblot 						     MMC_ALL_SIGNAL_VOLTAGE);
1865bc1e3272SJean-Jacques Hiblot 			if (err)
1866bc1e3272SJean-Jacques Hiblot 				continue;
1867bc1e3272SJean-Jacques Hiblot 
18683862b854SJean-Jacques Hiblot 			/* configure the bus width (card + host) */
18693862b854SJean-Jacques Hiblot 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
18703862b854SJean-Jacques Hiblot 				    EXT_CSD_BUS_WIDTH,
18713862b854SJean-Jacques Hiblot 				    ecbw->ext_csd_bits & ~EXT_CSD_DDR_FLAG);
18723862b854SJean-Jacques Hiblot 			if (err)
18733862b854SJean-Jacques Hiblot 				goto error;
18743862b854SJean-Jacques Hiblot 			mmc_set_bus_width(mmc, bus_width(ecbw->cap));
18753862b854SJean-Jacques Hiblot 
18763862b854SJean-Jacques Hiblot 			/* configure the bus speed (card) */
18773862b854SJean-Jacques Hiblot 			err = mmc_set_card_speed(mmc, mwt->mode);
18783862b854SJean-Jacques Hiblot 			if (err)
18793862b854SJean-Jacques Hiblot 				goto error;
18803862b854SJean-Jacques Hiblot 
18818ac8a263SJean-Jacques Hiblot 			/*
18823862b854SJean-Jacques Hiblot 			 * configure the bus width AND the ddr mode (card)
18833862b854SJean-Jacques Hiblot 			 * The host side will be taken care of in the next step
18848ac8a263SJean-Jacques Hiblot 			 */
18853862b854SJean-Jacques Hiblot 			if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) {
18863862b854SJean-Jacques Hiblot 				err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
18873862b854SJean-Jacques Hiblot 						 EXT_CSD_BUS_WIDTH,
18883862b854SJean-Jacques Hiblot 						 ecbw->ext_csd_bits);
18893862b854SJean-Jacques Hiblot 				if (err)
18903862b854SJean-Jacques Hiblot 					goto error;
18918ac8a263SJean-Jacques Hiblot 			}
18928ac8a263SJean-Jacques Hiblot 
18933862b854SJean-Jacques Hiblot 			/* configure the bus mode (host) */
18943862b854SJean-Jacques Hiblot 			mmc_select_mode(mmc, mwt->mode);
189535f67820SKishon Vijay Abraham I 			mmc_set_clock(mmc, mmc->tran_speed, false);
1896f99c2efeSJean-Jacques Hiblot #ifdef MMC_SUPPORTS_TUNING
18978ac8a263SJean-Jacques Hiblot 
1898634d4849SKishon Vijay Abraham I 			/* execute tuning if needed */
1899634d4849SKishon Vijay Abraham I 			if (mwt->tuning) {
1900634d4849SKishon Vijay Abraham I 				err = mmc_execute_tuning(mmc, mwt->tuning);
1901634d4849SKishon Vijay Abraham I 				if (err) {
1902634d4849SKishon Vijay Abraham I 					debug("tuning failed\n");
1903634d4849SKishon Vijay Abraham I 					goto error;
1904634d4849SKishon Vijay Abraham I 				}
1905634d4849SKishon Vijay Abraham I 			}
1906f99c2efeSJean-Jacques Hiblot #endif
1907634d4849SKishon Vijay Abraham I 
19083862b854SJean-Jacques Hiblot 			/* do a transfer to check the configuration */
19097382e691SJean-Jacques Hiblot 			err = mmc_read_and_compare_ext_csd(mmc);
19107382e691SJean-Jacques Hiblot 			if (!err)
19113862b854SJean-Jacques Hiblot 				return 0;
19123862b854SJean-Jacques Hiblot error:
1913bc1e3272SJean-Jacques Hiblot 			mmc_set_signal_voltage(mmc, old_voltage);
19143862b854SJean-Jacques Hiblot 			/* if an error occured, revert to a safer bus mode */
19153862b854SJean-Jacques Hiblot 			mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
19163862b854SJean-Jacques Hiblot 				   EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1);
19173862b854SJean-Jacques Hiblot 			mmc_select_mode(mmc, MMC_LEGACY);
19183862b854SJean-Jacques Hiblot 			mmc_set_bus_width(mmc, 1);
19193862b854SJean-Jacques Hiblot 		}
19208ac8a263SJean-Jacques Hiblot 	}
19218ac8a263SJean-Jacques Hiblot 
1922d8e3d420SJean-Jacques Hiblot 	pr_err("unable to select a mode\n");
19238ac8a263SJean-Jacques Hiblot 
19243862b854SJean-Jacques Hiblot 	return -ENOTSUPP;
19258ac8a263SJean-Jacques Hiblot }
19268ac8a263SJean-Jacques Hiblot 
1927dfda9d88SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc)
1928c744b6f6SJean-Jacques Hiblot {
1929c744b6f6SJean-Jacques Hiblot 	int err, i;
1930c744b6f6SJean-Jacques Hiblot 	u64 capacity;
1931c744b6f6SJean-Jacques Hiblot 	bool has_parts = false;
1932c744b6f6SJean-Jacques Hiblot 	bool part_completed;
1933f7d5dffcSJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
1934c744b6f6SJean-Jacques Hiblot 
1935c744b6f6SJean-Jacques Hiblot 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4))
1936c744b6f6SJean-Jacques Hiblot 		return 0;
1937c744b6f6SJean-Jacques Hiblot 
1938c744b6f6SJean-Jacques Hiblot 	/* check  ext_csd version and capacity */
1939c744b6f6SJean-Jacques Hiblot 	err = mmc_send_ext_csd(mmc, ext_csd);
1940c744b6f6SJean-Jacques Hiblot 	if (err)
1941f7d5dffcSJean-Jacques Hiblot 		goto error;
1942f7d5dffcSJean-Jacques Hiblot 
1943f7d5dffcSJean-Jacques Hiblot 	/* store the ext csd for future reference */
1944f7d5dffcSJean-Jacques Hiblot 	if (!mmc->ext_csd)
1945f7d5dffcSJean-Jacques Hiblot 		mmc->ext_csd = malloc(MMC_MAX_BLOCK_LEN);
1946f7d5dffcSJean-Jacques Hiblot 	if (!mmc->ext_csd)
1947f7d5dffcSJean-Jacques Hiblot 		return -ENOMEM;
1948f7d5dffcSJean-Jacques Hiblot 	memcpy(mmc->ext_csd, ext_csd, MMC_MAX_BLOCK_LEN);
1949f7d5dffcSJean-Jacques Hiblot 
1950c744b6f6SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_REV] >= 2) {
1951c744b6f6SJean-Jacques Hiblot 		/*
1952c744b6f6SJean-Jacques Hiblot 		 * According to the JEDEC Standard, the value of
1953c744b6f6SJean-Jacques Hiblot 		 * ext_csd's capacity is valid if the value is more
1954c744b6f6SJean-Jacques Hiblot 		 * than 2GB
1955c744b6f6SJean-Jacques Hiblot 		 */
1956c744b6f6SJean-Jacques Hiblot 		capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
1957c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
1958c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
1959c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
1960c744b6f6SJean-Jacques Hiblot 		capacity *= MMC_MAX_BLOCK_LEN;
1961c744b6f6SJean-Jacques Hiblot 		if ((capacity >> 20) > 2 * 1024)
1962c744b6f6SJean-Jacques Hiblot 			mmc->capacity_user = capacity;
1963c744b6f6SJean-Jacques Hiblot 	}
1964c744b6f6SJean-Jacques Hiblot 
1965c744b6f6SJean-Jacques Hiblot 	switch (ext_csd[EXT_CSD_REV]) {
1966c744b6f6SJean-Jacques Hiblot 	case 1:
1967c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_1;
1968c744b6f6SJean-Jacques Hiblot 		break;
1969c744b6f6SJean-Jacques Hiblot 	case 2:
1970c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_2;
1971c744b6f6SJean-Jacques Hiblot 		break;
1972c744b6f6SJean-Jacques Hiblot 	case 3:
1973c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_3;
1974c744b6f6SJean-Jacques Hiblot 		break;
1975c744b6f6SJean-Jacques Hiblot 	case 5:
1976c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_41;
1977c744b6f6SJean-Jacques Hiblot 		break;
1978c744b6f6SJean-Jacques Hiblot 	case 6:
1979c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_5;
1980c744b6f6SJean-Jacques Hiblot 		break;
1981c744b6f6SJean-Jacques Hiblot 	case 7:
1982c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_5_0;
1983c744b6f6SJean-Jacques Hiblot 		break;
1984c744b6f6SJean-Jacques Hiblot 	case 8:
1985c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_5_1;
1986c744b6f6SJean-Jacques Hiblot 		break;
1987c744b6f6SJean-Jacques Hiblot 	}
1988c744b6f6SJean-Jacques Hiblot 
1989c744b6f6SJean-Jacques Hiblot 	/* The partition data may be non-zero but it is only
1990c744b6f6SJean-Jacques Hiblot 	 * effective if PARTITION_SETTING_COMPLETED is set in
1991c744b6f6SJean-Jacques Hiblot 	 * EXT_CSD, so ignore any data if this bit is not set,
1992c744b6f6SJean-Jacques Hiblot 	 * except for enabling the high-capacity group size
1993c744b6f6SJean-Jacques Hiblot 	 * definition (see below).
1994c744b6f6SJean-Jacques Hiblot 	 */
1995c744b6f6SJean-Jacques Hiblot 	part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
1996c744b6f6SJean-Jacques Hiblot 			    EXT_CSD_PARTITION_SETTING_COMPLETED);
1997c744b6f6SJean-Jacques Hiblot 
1998c744b6f6SJean-Jacques Hiblot 	/* store the partition info of emmc */
1999c744b6f6SJean-Jacques Hiblot 	mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
2000c744b6f6SJean-Jacques Hiblot 	if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
2001c744b6f6SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_BOOT_MULT])
2002c744b6f6SJean-Jacques Hiblot 		mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
2003c744b6f6SJean-Jacques Hiblot 	if (part_completed &&
2004c744b6f6SJean-Jacques Hiblot 	    (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
2005c744b6f6SJean-Jacques Hiblot 		mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
2006c744b6f6SJean-Jacques Hiblot 
2007c744b6f6SJean-Jacques Hiblot 	mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
2008c744b6f6SJean-Jacques Hiblot 
2009c744b6f6SJean-Jacques Hiblot 	mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
2010c744b6f6SJean-Jacques Hiblot 
2011c744b6f6SJean-Jacques Hiblot 	for (i = 0; i < 4; i++) {
2012c744b6f6SJean-Jacques Hiblot 		int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
2013c744b6f6SJean-Jacques Hiblot 		uint mult = (ext_csd[idx + 2] << 16) +
2014c744b6f6SJean-Jacques Hiblot 			(ext_csd[idx + 1] << 8) + ext_csd[idx];
2015c744b6f6SJean-Jacques Hiblot 		if (mult)
2016c744b6f6SJean-Jacques Hiblot 			has_parts = true;
2017c744b6f6SJean-Jacques Hiblot 		if (!part_completed)
2018c744b6f6SJean-Jacques Hiblot 			continue;
2019c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] = mult;
2020c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] *=
2021c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
2022c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
2023c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] <<= 19;
2024c744b6f6SJean-Jacques Hiblot 	}
2025c744b6f6SJean-Jacques Hiblot 
2026c744b6f6SJean-Jacques Hiblot 	if (part_completed) {
2027c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size =
2028c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) +
2029c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) +
2030c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_ENH_SIZE_MULT];
2031c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
2032c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
2033c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size <<= 19;
2034c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_start =
2035c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) +
2036c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) +
2037c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) +
2038c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_ENH_START_ADDR];
2039c744b6f6SJean-Jacques Hiblot 		if (mmc->high_capacity)
2040c744b6f6SJean-Jacques Hiblot 			mmc->enh_user_start <<= 9;
2041c744b6f6SJean-Jacques Hiblot 	}
2042c744b6f6SJean-Jacques Hiblot 
2043c744b6f6SJean-Jacques Hiblot 	/*
2044c744b6f6SJean-Jacques Hiblot 	 * Host needs to enable ERASE_GRP_DEF bit if device is
2045c744b6f6SJean-Jacques Hiblot 	 * partitioned. This bit will be lost every time after a reset
2046c744b6f6SJean-Jacques Hiblot 	 * or power off. This will affect erase size.
2047c744b6f6SJean-Jacques Hiblot 	 */
2048c744b6f6SJean-Jacques Hiblot 	if (part_completed)
2049c744b6f6SJean-Jacques Hiblot 		has_parts = true;
2050c744b6f6SJean-Jacques Hiblot 	if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
2051c744b6f6SJean-Jacques Hiblot 	    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
2052c744b6f6SJean-Jacques Hiblot 		has_parts = true;
2053c744b6f6SJean-Jacques Hiblot 	if (has_parts) {
2054c744b6f6SJean-Jacques Hiblot 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
2055c744b6f6SJean-Jacques Hiblot 				 EXT_CSD_ERASE_GROUP_DEF, 1);
2056c744b6f6SJean-Jacques Hiblot 
2057c744b6f6SJean-Jacques Hiblot 		if (err)
2058f7d5dffcSJean-Jacques Hiblot 			goto error;
2059c744b6f6SJean-Jacques Hiblot 
2060c744b6f6SJean-Jacques Hiblot 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
2061c744b6f6SJean-Jacques Hiblot 	}
2062c744b6f6SJean-Jacques Hiblot 
2063c744b6f6SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
2064c744b6f6SJean-Jacques Hiblot 		/* Read out group size from ext_csd */
2065c744b6f6SJean-Jacques Hiblot 		mmc->erase_grp_size =
2066c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
2067c744b6f6SJean-Jacques Hiblot 		/*
2068c744b6f6SJean-Jacques Hiblot 		 * if high capacity and partition setting completed
2069c744b6f6SJean-Jacques Hiblot 		 * SEC_COUNT is valid even if it is smaller than 2 GiB
2070c744b6f6SJean-Jacques Hiblot 		 * JEDEC Standard JESD84-B45, 6.2.4
2071c744b6f6SJean-Jacques Hiblot 		 */
2072c744b6f6SJean-Jacques Hiblot 		if (mmc->high_capacity && part_completed) {
2073c744b6f6SJean-Jacques Hiblot 			capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
2074c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
2075c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
2076c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
2077c744b6f6SJean-Jacques Hiblot 			capacity *= MMC_MAX_BLOCK_LEN;
2078c744b6f6SJean-Jacques Hiblot 			mmc->capacity_user = capacity;
2079c744b6f6SJean-Jacques Hiblot 		}
2080c744b6f6SJean-Jacques Hiblot 	} else {
2081c744b6f6SJean-Jacques Hiblot 		/* Calculate the group size from the csd value. */
2082c744b6f6SJean-Jacques Hiblot 		int erase_gsz, erase_gmul;
2083c744b6f6SJean-Jacques Hiblot 
2084c744b6f6SJean-Jacques Hiblot 		erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
2085c744b6f6SJean-Jacques Hiblot 		erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
2086c744b6f6SJean-Jacques Hiblot 		mmc->erase_grp_size = (erase_gsz + 1)
2087c744b6f6SJean-Jacques Hiblot 			* (erase_gmul + 1);
2088c744b6f6SJean-Jacques Hiblot 	}
2089c744b6f6SJean-Jacques Hiblot 
2090c744b6f6SJean-Jacques Hiblot 	mmc->hc_wp_grp_size = 1024
2091c744b6f6SJean-Jacques Hiblot 		* ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
2092c744b6f6SJean-Jacques Hiblot 		* ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
2093c744b6f6SJean-Jacques Hiblot 
2094c744b6f6SJean-Jacques Hiblot 	mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
2095c744b6f6SJean-Jacques Hiblot 
2096c744b6f6SJean-Jacques Hiblot 	return 0;
2097f7d5dffcSJean-Jacques Hiblot error:
2098f7d5dffcSJean-Jacques Hiblot 	if (mmc->ext_csd) {
2099f7d5dffcSJean-Jacques Hiblot 		free(mmc->ext_csd);
2100f7d5dffcSJean-Jacques Hiblot 		mmc->ext_csd = NULL;
2101f7d5dffcSJean-Jacques Hiblot 	}
2102f7d5dffcSJean-Jacques Hiblot 	return err;
2103c744b6f6SJean-Jacques Hiblot }
2104c744b6f6SJean-Jacques Hiblot 
2105fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc)
2106272cc70bSAndy Fleming {
2107f866a46dSStephen Warren 	int err, i;
2108272cc70bSAndy Fleming 	uint mult, freq;
2109c744b6f6SJean-Jacques Hiblot 	u64 cmult, csize;
2110272cc70bSAndy Fleming 	struct mmc_cmd cmd;
2111c40fdca6SSimon Glass 	struct blk_desc *bdesc;
2112272cc70bSAndy Fleming 
2113d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
2114d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
2115d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
2116d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
2117d52ebf10SThomas Chou 		cmd.cmdarg = 1;
2118d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
2119d52ebf10SThomas Chou 		if (err)
2120d52ebf10SThomas Chou 			return err;
2121d52ebf10SThomas Chou 	}
2122d52ebf10SThomas Chou #endif
2123d52ebf10SThomas Chou 
2124272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
2125d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
2126d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
2127272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
2128272cc70bSAndy Fleming 	cmd.cmdarg = 0;
2129272cc70bSAndy Fleming 
2130272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
2131272cc70bSAndy Fleming 
213283dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS
213383dc4227SKishon Vijay Abraham I 	if (err && (mmc->quirks & MMC_QUIRK_RETRY_SEND_CID)) {
213483dc4227SKishon Vijay Abraham I 		int retries = 4;
213583dc4227SKishon Vijay Abraham I 		/*
213683dc4227SKishon Vijay Abraham I 		 * It has been seen that SEND_CID may fail on the first
213783dc4227SKishon Vijay Abraham I 		 * attempt, let's try a few more time
213883dc4227SKishon Vijay Abraham I 		 */
213983dc4227SKishon Vijay Abraham I 		do {
214083dc4227SKishon Vijay Abraham I 			err = mmc_send_cmd(mmc, &cmd, NULL);
214183dc4227SKishon Vijay Abraham I 			if (!err)
214283dc4227SKishon Vijay Abraham I 				break;
214383dc4227SKishon Vijay Abraham I 		} while (retries--);
214483dc4227SKishon Vijay Abraham I 	}
214583dc4227SKishon Vijay Abraham I #endif
214683dc4227SKishon Vijay Abraham I 
2147272cc70bSAndy Fleming 	if (err)
2148272cc70bSAndy Fleming 		return err;
2149272cc70bSAndy Fleming 
2150272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
2151272cc70bSAndy Fleming 
2152272cc70bSAndy Fleming 	/*
2153272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
2154272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
2155272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
2156272cc70bSAndy Fleming 	 */
2157d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
2158272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
2159272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
2160272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
2161272cc70bSAndy Fleming 
2162272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
2163272cc70bSAndy Fleming 
2164272cc70bSAndy Fleming 		if (err)
2165272cc70bSAndy Fleming 			return err;
2166272cc70bSAndy Fleming 
2167272cc70bSAndy Fleming 		if (IS_SD(mmc))
2168998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
2169d52ebf10SThomas Chou 	}
2170272cc70bSAndy Fleming 
2171272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
2172272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
2173272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
2174272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
2175272cc70bSAndy Fleming 
2176272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
2177272cc70bSAndy Fleming 
2178272cc70bSAndy Fleming 	if (err)
2179272cc70bSAndy Fleming 		return err;
2180272cc70bSAndy Fleming 
2181998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
2182998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
2183998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
2184998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
2185272cc70bSAndy Fleming 
2186272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
21870b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
2188272cc70bSAndy Fleming 
2189272cc70bSAndy Fleming 		switch (version) {
2190272cc70bSAndy Fleming 		case 0:
2191272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
2192272cc70bSAndy Fleming 			break;
2193272cc70bSAndy Fleming 		case 1:
2194272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_4;
2195272cc70bSAndy Fleming 			break;
2196272cc70bSAndy Fleming 		case 2:
2197272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_2_2;
2198272cc70bSAndy Fleming 			break;
2199272cc70bSAndy Fleming 		case 3:
2200272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_3;
2201272cc70bSAndy Fleming 			break;
2202272cc70bSAndy Fleming 		case 4:
2203272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_4;
2204272cc70bSAndy Fleming 			break;
2205272cc70bSAndy Fleming 		default:
2206272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
2207272cc70bSAndy Fleming 			break;
2208272cc70bSAndy Fleming 		}
2209272cc70bSAndy Fleming 	}
2210272cc70bSAndy Fleming 
2211272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
22120b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
22130b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
2214272cc70bSAndy Fleming 
221535f9e196SJean-Jacques Hiblot 	mmc->legacy_speed = freq * mult;
221635f9e196SJean-Jacques Hiblot 	mmc_select_mode(mmc, MMC_LEGACY);
2217272cc70bSAndy Fleming 
2218ab71188cSMarkus Niebel 	mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
2219998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
2220272cc70bSAndy Fleming 
2221272cc70bSAndy Fleming 	if (IS_SD(mmc))
2222272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
2223272cc70bSAndy Fleming 	else
2224998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
2225272cc70bSAndy Fleming 
2226272cc70bSAndy Fleming 	if (mmc->high_capacity) {
2227272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
2228272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
2229272cc70bSAndy Fleming 		cmult = 8;
2230272cc70bSAndy Fleming 	} else {
2231272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
2232272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
2233272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
2234272cc70bSAndy Fleming 	}
2235272cc70bSAndy Fleming 
2236f866a46dSStephen Warren 	mmc->capacity_user = (csize + 1) << (cmult + 2);
2237f866a46dSStephen Warren 	mmc->capacity_user *= mmc->read_bl_len;
2238f866a46dSStephen Warren 	mmc->capacity_boot = 0;
2239f866a46dSStephen Warren 	mmc->capacity_rpmb = 0;
2240f866a46dSStephen Warren 	for (i = 0; i < 4; i++)
2241f866a46dSStephen Warren 		mmc->capacity_gp[i] = 0;
2242272cc70bSAndy Fleming 
22438bfa195eSSimon Glass 	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
22448bfa195eSSimon Glass 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
2245272cc70bSAndy Fleming 
22468bfa195eSSimon Glass 	if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
22478bfa195eSSimon Glass 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
2248272cc70bSAndy Fleming 
2249ab71188cSMarkus Niebel 	if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
2250ab71188cSMarkus Niebel 		cmd.cmdidx = MMC_CMD_SET_DSR;
2251ab71188cSMarkus Niebel 		cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
2252ab71188cSMarkus Niebel 		cmd.resp_type = MMC_RSP_NONE;
2253ab71188cSMarkus Niebel 		if (mmc_send_cmd(mmc, &cmd, NULL))
2254d8e3d420SJean-Jacques Hiblot 			pr_warn("MMC: SET_DSR failed\n");
2255ab71188cSMarkus Niebel 	}
2256ab71188cSMarkus Niebel 
2257272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
2258d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
2259272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
2260fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
2261272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
2262272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
2263272cc70bSAndy Fleming 
2264272cc70bSAndy Fleming 		if (err)
2265272cc70bSAndy Fleming 			return err;
2266d52ebf10SThomas Chou 	}
2267272cc70bSAndy Fleming 
2268e6f99a56SLei Wen 	/*
2269e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
2270e6f99a56SLei Wen 	 */
2271e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
2272bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
2273c744b6f6SJean-Jacques Hiblot 
2274dfda9d88SJean-Jacques Hiblot 	err = mmc_startup_v4(mmc);
22759cf199ebSDiego Santa Cruz 	if (err)
22769cf199ebSDiego Santa Cruz 		return err;
2277f866a46dSStephen Warren 
2278c40fdca6SSimon Glass 	err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart);
2279f866a46dSStephen Warren 	if (err)
2280f866a46dSStephen Warren 		return err;
2281d23e2c09SSukumar Ghorai 
228201298da3SJean-Jacques Hiblot 	if (IS_SD(mmc)) {
228301298da3SJean-Jacques Hiblot 		err = sd_get_capabilities(mmc);
228401298da3SJean-Jacques Hiblot 		if (err)
228501298da3SJean-Jacques Hiblot 			return err;
228601298da3SJean-Jacques Hiblot 		err = sd_select_mode_and_width(mmc, mmc->card_caps);
228701298da3SJean-Jacques Hiblot 	} else {
228801298da3SJean-Jacques Hiblot 		err = mmc_get_capabilities(mmc);
228901298da3SJean-Jacques Hiblot 		if (err)
229001298da3SJean-Jacques Hiblot 			return err;
229101298da3SJean-Jacques Hiblot 		mmc_select_mode_and_width(mmc, mmc->card_caps);
229201298da3SJean-Jacques Hiblot 	}
2293272cc70bSAndy Fleming 
2294272cc70bSAndy Fleming 	if (err)
2295272cc70bSAndy Fleming 		return err;
2296272cc70bSAndy Fleming 
229701298da3SJean-Jacques Hiblot 	mmc->best_mode = mmc->selected_mode;
2298272cc70bSAndy Fleming 
22995af8f45cSAndrew Gabbasov 	/* Fix the block length for DDR mode */
23005af8f45cSAndrew Gabbasov 	if (mmc->ddr_mode) {
23015af8f45cSAndrew Gabbasov 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
23025af8f45cSAndrew Gabbasov 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
23035af8f45cSAndrew Gabbasov 	}
23045af8f45cSAndrew Gabbasov 
2305272cc70bSAndy Fleming 	/* fill in device description */
2306c40fdca6SSimon Glass 	bdesc = mmc_get_blk_desc(mmc);
2307c40fdca6SSimon Glass 	bdesc->lun = 0;
2308c40fdca6SSimon Glass 	bdesc->hwpart = 0;
2309c40fdca6SSimon Glass 	bdesc->type = 0;
2310c40fdca6SSimon Glass 	bdesc->blksz = mmc->read_bl_len;
2311c40fdca6SSimon Glass 	bdesc->log2blksz = LOG2(bdesc->blksz);
2312c40fdca6SSimon Glass 	bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len);
2313fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \
2314fc011f64SSjoerd Simons 		(defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \
2315fc011f64SSjoerd Simons 		!defined(CONFIG_USE_TINY_PRINTF))
2316c40fdca6SSimon Glass 	sprintf(bdesc->vendor, "Man %06x Snr %04x%04x",
2317babce5f6STaylor Hutt 		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
2318babce5f6STaylor Hutt 		(mmc->cid[3] >> 16) & 0xffff);
2319c40fdca6SSimon Glass 	sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
23200b453ffeSRabin Vincent 		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
2321babce5f6STaylor Hutt 		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
2322babce5f6STaylor Hutt 		(mmc->cid[2] >> 24) & 0xff);
2323c40fdca6SSimon Glass 	sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
2324babce5f6STaylor Hutt 		(mmc->cid[2] >> 16) & 0xf);
232556196826SPaul Burton #else
2326c40fdca6SSimon Glass 	bdesc->vendor[0] = 0;
2327c40fdca6SSimon Glass 	bdesc->product[0] = 0;
2328c40fdca6SSimon Glass 	bdesc->revision[0] = 0;
232956196826SPaul Burton #endif
2330122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
2331c40fdca6SSimon Glass 	part_init(bdesc);
2332122efd43SMikhail Kshevetskiy #endif
2333272cc70bSAndy Fleming 
2334272cc70bSAndy Fleming 	return 0;
2335272cc70bSAndy Fleming }
2336272cc70bSAndy Fleming 
2337fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc)
2338272cc70bSAndy Fleming {
2339272cc70bSAndy Fleming 	struct mmc_cmd cmd;
2340272cc70bSAndy Fleming 	int err;
2341272cc70bSAndy Fleming 
2342272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
2343272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
234493bfd616SPantelis Antoniou 	cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa;
2345272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
2346272cc70bSAndy Fleming 
2347272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
2348272cc70bSAndy Fleming 
2349272cc70bSAndy Fleming 	if (err)
2350272cc70bSAndy Fleming 		return err;
2351272cc70bSAndy Fleming 
2352998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
2353915ffa52SJaehoon Chung 		return -EOPNOTSUPP;
2354272cc70bSAndy Fleming 	else
2355272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
2356272cc70bSAndy Fleming 
2357272cc70bSAndy Fleming 	return 0;
2358272cc70bSAndy Fleming }
2359272cc70bSAndy Fleming 
2360c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
236195de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */
236295de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void)
236395de9ab2SPaul Kocialkowski {
236495de9ab2SPaul Kocialkowski }
236505cbeb7cSSimon Glass #endif
236695de9ab2SPaul Kocialkowski 
23672051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc)
23682051aefeSPeng Fan {
2369c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
237006ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR)
23712051aefeSPeng Fan 	int ret;
23722051aefeSPeng Fan 
23732051aefeSPeng Fan 	ret = device_get_supply_regulator(mmc->dev, "vmmc-supply",
237406ec045fSJean-Jacques Hiblot 					  &mmc->vmmc_supply);
237506ec045fSJean-Jacques Hiblot 	if (ret)
2376288db7c7SJaehoon Chung 		debug("%s: No vmmc supply\n", mmc->dev->name);
23772051aefeSPeng Fan 
237806ec045fSJean-Jacques Hiblot 	ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply",
237906ec045fSJean-Jacques Hiblot 					  &mmc->vqmmc_supply);
238006ec045fSJean-Jacques Hiblot 	if (ret)
238106ec045fSJean-Jacques Hiblot 		debug("%s: No vqmmc supply\n", mmc->dev->name);
23822051aefeSPeng Fan #endif
238305cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */
238405cbeb7cSSimon Glass 	/*
238505cbeb7cSSimon Glass 	 * Driver model should use a regulator, as above, rather than calling
238605cbeb7cSSimon Glass 	 * out to board code.
238705cbeb7cSSimon Glass 	 */
238805cbeb7cSSimon Glass 	board_mmc_power_init();
238905cbeb7cSSimon Glass #endif
23902051aefeSPeng Fan 	return 0;
23912051aefeSPeng Fan }
23922051aefeSPeng Fan 
2393fb7c3bebSKishon Vijay Abraham I /*
2394fb7c3bebSKishon Vijay Abraham I  * put the host in the initial state:
2395fb7c3bebSKishon Vijay Abraham I  * - turn on Vdd (card power supply)
2396fb7c3bebSKishon Vijay Abraham I  * - configure the bus width and clock to minimal values
2397fb7c3bebSKishon Vijay Abraham I  */
2398fb7c3bebSKishon Vijay Abraham I static void mmc_set_initial_state(struct mmc *mmc)
2399fb7c3bebSKishon Vijay Abraham I {
2400fb7c3bebSKishon Vijay Abraham I 	int err;
2401fb7c3bebSKishon Vijay Abraham I 
2402fb7c3bebSKishon Vijay Abraham I 	/* First try to set 3.3V. If it fails set to 1.8V */
2403fb7c3bebSKishon Vijay Abraham I 	err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_330);
2404fb7c3bebSKishon Vijay Abraham I 	if (err != 0)
2405fb7c3bebSKishon Vijay Abraham I 		err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_180);
2406fb7c3bebSKishon Vijay Abraham I 	if (err != 0)
2407d8e3d420SJean-Jacques Hiblot 		pr_warn("mmc: failed to set signal voltage\n");
2408fb7c3bebSKishon Vijay Abraham I 
2409fb7c3bebSKishon Vijay Abraham I 	mmc_select_mode(mmc, MMC_LEGACY);
2410fb7c3bebSKishon Vijay Abraham I 	mmc_set_bus_width(mmc, 1);
241135f67820SKishon Vijay Abraham I 	mmc_set_clock(mmc, 0, false);
2412fb7c3bebSKishon Vijay Abraham I }
2413fb7c3bebSKishon Vijay Abraham I 
2414fb7c3bebSKishon Vijay Abraham I static int mmc_power_on(struct mmc *mmc)
2415fb7c3bebSKishon Vijay Abraham I {
2416fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR)
2417fb7c3bebSKishon Vijay Abraham I 	if (mmc->vmmc_supply) {
2418fb7c3bebSKishon Vijay Abraham I 		int ret = regulator_set_enable(mmc->vmmc_supply, true);
2419fb7c3bebSKishon Vijay Abraham I 
2420fb7c3bebSKishon Vijay Abraham I 		if (ret) {
2421fb7c3bebSKishon Vijay Abraham I 			puts("Error enabling VMMC supply\n");
2422fb7c3bebSKishon Vijay Abraham I 			return ret;
2423fb7c3bebSKishon Vijay Abraham I 		}
2424fb7c3bebSKishon Vijay Abraham I 	}
2425fb7c3bebSKishon Vijay Abraham I #endif
2426fb7c3bebSKishon Vijay Abraham I 	return 0;
2427fb7c3bebSKishon Vijay Abraham I }
2428fb7c3bebSKishon Vijay Abraham I 
2429fb7c3bebSKishon Vijay Abraham I static int mmc_power_off(struct mmc *mmc)
2430fb7c3bebSKishon Vijay Abraham I {
24312e7410d7SKishon Vijay Abraham I 	mmc_set_clock(mmc, 1, true);
2432fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR)
2433fb7c3bebSKishon Vijay Abraham I 	if (mmc->vmmc_supply) {
2434fb7c3bebSKishon Vijay Abraham I 		int ret = regulator_set_enable(mmc->vmmc_supply, false);
2435fb7c3bebSKishon Vijay Abraham I 
2436fb7c3bebSKishon Vijay Abraham I 		if (ret) {
2437c10b85d6SJean-Jacques Hiblot 			debug("Error disabling VMMC supply\n");
2438fb7c3bebSKishon Vijay Abraham I 			return ret;
2439fb7c3bebSKishon Vijay Abraham I 		}
2440fb7c3bebSKishon Vijay Abraham I 	}
2441fb7c3bebSKishon Vijay Abraham I #endif
2442fb7c3bebSKishon Vijay Abraham I 	return 0;
2443fb7c3bebSKishon Vijay Abraham I }
2444fb7c3bebSKishon Vijay Abraham I 
2445fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc)
2446fb7c3bebSKishon Vijay Abraham I {
2447fb7c3bebSKishon Vijay Abraham I 	int ret;
2448fb7c3bebSKishon Vijay Abraham I 
2449fb7c3bebSKishon Vijay Abraham I 	ret = mmc_power_off(mmc);
2450fb7c3bebSKishon Vijay Abraham I 	if (ret)
2451fb7c3bebSKishon Vijay Abraham I 		return ret;
2452fb7c3bebSKishon Vijay Abraham I 	/*
2453fb7c3bebSKishon Vijay Abraham I 	 * SD spec recommends at least 1ms of delay. Let's wait for 2ms
2454fb7c3bebSKishon Vijay Abraham I 	 * to be on the safer side.
2455fb7c3bebSKishon Vijay Abraham I 	 */
2456fb7c3bebSKishon Vijay Abraham I 	udelay(2000);
2457fb7c3bebSKishon Vijay Abraham I 	return mmc_power_on(mmc);
2458fb7c3bebSKishon Vijay Abraham I }
2459fb7c3bebSKishon Vijay Abraham I 
2460e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc)
2461272cc70bSAndy Fleming {
24628ca51e51SSimon Glass 	bool no_card;
2463c10b85d6SJean-Jacques Hiblot 	bool uhs_en = supports_uhs(mmc->cfg->host_caps);
2464afd5932bSMacpaul Lin 	int err;
2465272cc70bSAndy Fleming 
24661da8eb59SJean-Jacques Hiblot 	/*
24671da8eb59SJean-Jacques Hiblot 	 * all hosts are capable of 1 bit bus-width and able to use the legacy
24681da8eb59SJean-Jacques Hiblot 	 * timings.
24691da8eb59SJean-Jacques Hiblot 	 */
24701da8eb59SJean-Jacques Hiblot 	mmc->host_caps = mmc->cfg->host_caps | MMC_CAP(SD_LEGACY) |
24711da8eb59SJean-Jacques Hiblot 			 MMC_CAP(MMC_LEGACY) | MMC_MODE_1BIT;
247204a2ea24SJean-Jacques Hiblot 
2473ab769f22SPantelis Antoniou 	/* we pretend there's no card when init is NULL */
24748ca51e51SSimon Glass 	no_card = mmc_getcd(mmc) == 0;
2475e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
24768ca51e51SSimon Glass 	no_card = no_card || (mmc->cfg->ops->init == NULL);
24778ca51e51SSimon Glass #endif
24788ca51e51SSimon Glass 	if (no_card) {
247948972d90SThierry Reding 		mmc->has_init = 0;
248056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
248148972d90SThierry Reding 		printf("MMC: no card present\n");
248256196826SPaul Burton #endif
2483915ffa52SJaehoon Chung 		return -ENOMEDIUM;
248448972d90SThierry Reding 	}
248548972d90SThierry Reding 
2486bc897b1dSLei Wen 	if (mmc->has_init)
2487bc897b1dSLei Wen 		return 0;
2488bc897b1dSLei Wen 
24895a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
24905a8dbdc6SYangbo Lu 	mmc_adapter_card_type_ident();
24915a8dbdc6SYangbo Lu #endif
24922051aefeSPeng Fan 	err = mmc_power_init(mmc);
24932051aefeSPeng Fan 	if (err)
24942051aefeSPeng Fan 		return err;
249595de9ab2SPaul Kocialkowski 
249683dc4227SKishon Vijay Abraham I #ifdef CONFIG_MMC_QUIRKS
249783dc4227SKishon Vijay Abraham I 	mmc->quirks = MMC_QUIRK_RETRY_SET_BLOCKLEN |
249883dc4227SKishon Vijay Abraham I 		      MMC_QUIRK_RETRY_SEND_CID;
249983dc4227SKishon Vijay Abraham I #endif
250083dc4227SKishon Vijay Abraham I 
250104a2ea24SJean-Jacques Hiblot 	err = mmc_power_cycle(mmc);
250204a2ea24SJean-Jacques Hiblot 	if (err) {
250304a2ea24SJean-Jacques Hiblot 		/*
250404a2ea24SJean-Jacques Hiblot 		 * if power cycling is not supported, we should not try
250504a2ea24SJean-Jacques Hiblot 		 * to use the UHS modes, because we wouldn't be able to
250604a2ea24SJean-Jacques Hiblot 		 * recover from an error during the UHS initialization.
250704a2ea24SJean-Jacques Hiblot 		 */
250804a2ea24SJean-Jacques Hiblot 		debug("Unable to do a full power cycle. Disabling the UHS modes for safety\n");
250904a2ea24SJean-Jacques Hiblot 		uhs_en = false;
251004a2ea24SJean-Jacques Hiblot 		mmc->host_caps &= ~UHS_CAPS;
2511fb7c3bebSKishon Vijay Abraham I 		err = mmc_power_on(mmc);
251204a2ea24SJean-Jacques Hiblot 	}
2513fb7c3bebSKishon Vijay Abraham I 	if (err)
2514fb7c3bebSKishon Vijay Abraham I 		return err;
2515fb7c3bebSKishon Vijay Abraham I 
2516e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
25178ca51e51SSimon Glass 	/* The device has already been probed ready for use */
25188ca51e51SSimon Glass #else
2519ab769f22SPantelis Antoniou 	/* made sure it's not NULL earlier */
252093bfd616SPantelis Antoniou 	err = mmc->cfg->ops->init(mmc);
2521272cc70bSAndy Fleming 	if (err)
2522272cc70bSAndy Fleming 		return err;
25238ca51e51SSimon Glass #endif
2524786e8f81SAndrew Gabbasov 	mmc->ddr_mode = 0;
2525aff5d3c8SKishon Vijay Abraham I 
2526c10b85d6SJean-Jacques Hiblot retry:
2527fb7c3bebSKishon Vijay Abraham I 	mmc_set_initial_state(mmc);
2528318a7a57SJean-Jacques Hiblot 	mmc_send_init_stream(mmc);
2529318a7a57SJean-Jacques Hiblot 
2530272cc70bSAndy Fleming 	/* Reset the Card */
2531272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
2532272cc70bSAndy Fleming 
2533272cc70bSAndy Fleming 	if (err)
2534272cc70bSAndy Fleming 		return err;
2535272cc70bSAndy Fleming 
2536bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
2537c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->hwpart = 0;
2538bc897b1dSLei Wen 
2539272cc70bSAndy Fleming 	/* Test for SD version 2 */
2540272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
2541272cc70bSAndy Fleming 
2542272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
2543c10b85d6SJean-Jacques Hiblot 	err = sd_send_op_cond(mmc, uhs_en);
2544c10b85d6SJean-Jacques Hiblot 	if (err && uhs_en) {
2545c10b85d6SJean-Jacques Hiblot 		uhs_en = false;
2546c10b85d6SJean-Jacques Hiblot 		mmc_power_cycle(mmc);
2547c10b85d6SJean-Jacques Hiblot 		goto retry;
2548c10b85d6SJean-Jacques Hiblot 	}
2549272cc70bSAndy Fleming 
2550272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
2551915ffa52SJaehoon Chung 	if (err == -ETIMEDOUT) {
2552272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
2553272cc70bSAndy Fleming 
2554bd47c135SAndrew Gabbasov 		if (err) {
255556196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2556d8e3d420SJean-Jacques Hiblot 			pr_err("Card did not respond to voltage select!\n");
255756196826SPaul Burton #endif
2558915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
2559272cc70bSAndy Fleming 		}
2560272cc70bSAndy Fleming 	}
2561272cc70bSAndy Fleming 
2562bd47c135SAndrew Gabbasov 	if (!err)
2563e9550449SChe-Liang Chiou 		mmc->init_in_progress = 1;
2564e9550449SChe-Liang Chiou 
2565e9550449SChe-Liang Chiou 	return err;
2566e9550449SChe-Liang Chiou }
2567e9550449SChe-Liang Chiou 
2568e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc)
2569e9550449SChe-Liang Chiou {
2570e9550449SChe-Liang Chiou 	int err = 0;
2571e9550449SChe-Liang Chiou 
2572bd47c135SAndrew Gabbasov 	mmc->init_in_progress = 0;
2573e9550449SChe-Liang Chiou 	if (mmc->op_cond_pending)
2574e9550449SChe-Liang Chiou 		err = mmc_complete_op_cond(mmc);
2575e9550449SChe-Liang Chiou 
2576e9550449SChe-Liang Chiou 	if (!err)
2577bc897b1dSLei Wen 		err = mmc_startup(mmc);
2578bc897b1dSLei Wen 	if (err)
2579bc897b1dSLei Wen 		mmc->has_init = 0;
2580bc897b1dSLei Wen 	else
2581bc897b1dSLei Wen 		mmc->has_init = 1;
2582e9550449SChe-Liang Chiou 	return err;
2583e9550449SChe-Liang Chiou }
2584e9550449SChe-Liang Chiou 
2585e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc)
2586e9550449SChe-Liang Chiou {
2587bd47c135SAndrew Gabbasov 	int err = 0;
2588ce9eca94SMarek Vasut 	__maybe_unused unsigned start;
2589c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
259033fb211dSSimon Glass 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev);
2591e9550449SChe-Liang Chiou 
259233fb211dSSimon Glass 	upriv->mmc = mmc;
259333fb211dSSimon Glass #endif
2594e9550449SChe-Liang Chiou 	if (mmc->has_init)
2595e9550449SChe-Liang Chiou 		return 0;
2596d803fea5SMateusz Zalega 
2597d803fea5SMateusz Zalega 	start = get_timer(0);
2598d803fea5SMateusz Zalega 
2599e9550449SChe-Liang Chiou 	if (!mmc->init_in_progress)
2600e9550449SChe-Liang Chiou 		err = mmc_start_init(mmc);
2601e9550449SChe-Liang Chiou 
2602bd47c135SAndrew Gabbasov 	if (!err)
2603e9550449SChe-Liang Chiou 		err = mmc_complete_init(mmc);
2604919b4858SJagan Teki 	if (err)
2605919b4858SJagan Teki 		printf("%s: %d, time %lu\n", __func__, err, get_timer(start));
2606919b4858SJagan Teki 
2607bc897b1dSLei Wen 	return err;
2608272cc70bSAndy Fleming }
2609272cc70bSAndy Fleming 
2610ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val)
2611ab71188cSMarkus Niebel {
2612ab71188cSMarkus Niebel 	mmc->dsr = val;
2613ab71188cSMarkus Niebel 	return 0;
2614ab71188cSMarkus Niebel }
2615ab71188cSMarkus Niebel 
2616cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */
2617cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis)
2618272cc70bSAndy Fleming {
2619272cc70bSAndy Fleming 	return -1;
2620272cc70bSAndy Fleming }
2621272cc70bSAndy Fleming 
2622cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */
2623cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis)
2624cee9ab7cSJeroen Hofstee {
2625cee9ab7cSJeroen Hofstee 	return -1;
2626cee9ab7cSJeroen Hofstee }
2627272cc70bSAndy Fleming 
2628e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit)
2629e9550449SChe-Liang Chiou {
2630e9550449SChe-Liang Chiou 	mmc->preinit = preinit;
2631e9550449SChe-Liang Chiou }
2632e9550449SChe-Liang Chiou 
2633c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD)
26348e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
26358e3332e2SSjoerd Simons {
26368e3332e2SSjoerd Simons 	return 0;
26378e3332e2SSjoerd Simons }
2638c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC)
26398e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
26408e3332e2SSjoerd Simons {
26414a1db6d8SSimon Glass 	int ret, i;
26428e3332e2SSjoerd Simons 	struct uclass *uc;
26434a1db6d8SSimon Glass 	struct udevice *dev;
26448e3332e2SSjoerd Simons 
26458e3332e2SSjoerd Simons 	ret = uclass_get(UCLASS_MMC, &uc);
26468e3332e2SSjoerd Simons 	if (ret)
26478e3332e2SSjoerd Simons 		return ret;
26488e3332e2SSjoerd Simons 
26494a1db6d8SSimon Glass 	/*
26504a1db6d8SSimon Glass 	 * Try to add them in sequence order. Really with driver model we
26514a1db6d8SSimon Glass 	 * should allow holes, but the current MMC list does not allow that.
26524a1db6d8SSimon Glass 	 * So if we request 0, 1, 3 we will get 0, 1, 2.
26534a1db6d8SSimon Glass 	 */
26544a1db6d8SSimon Glass 	for (i = 0; ; i++) {
26554a1db6d8SSimon Glass 		ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev);
26564a1db6d8SSimon Glass 		if (ret == -ENODEV)
26574a1db6d8SSimon Glass 			break;
26584a1db6d8SSimon Glass 	}
26594a1db6d8SSimon Glass 	uclass_foreach_dev(dev, uc) {
26604a1db6d8SSimon Glass 		ret = device_probe(dev);
26618e3332e2SSjoerd Simons 		if (ret)
2662d8e3d420SJean-Jacques Hiblot 			pr_err("%s - probe failed: %d\n", dev->name, ret);
26638e3332e2SSjoerd Simons 	}
26648e3332e2SSjoerd Simons 
26658e3332e2SSjoerd Simons 	return 0;
26668e3332e2SSjoerd Simons }
26678e3332e2SSjoerd Simons #else
26688e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
26698e3332e2SSjoerd Simons {
26708e3332e2SSjoerd Simons 	if (board_mmc_init(bis) < 0)
26718e3332e2SSjoerd Simons 		cpu_mmc_init(bis);
26728e3332e2SSjoerd Simons 
26738e3332e2SSjoerd Simons 	return 0;
26748e3332e2SSjoerd Simons }
26758e3332e2SSjoerd Simons #endif
2676e9550449SChe-Liang Chiou 
2677272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
2678272cc70bSAndy Fleming {
26791b26bab1SDaniel Kochmański 	static int initialized = 0;
26808e3332e2SSjoerd Simons 	int ret;
26811b26bab1SDaniel Kochmański 	if (initialized)	/* Avoid initializing mmc multiple times */
26821b26bab1SDaniel Kochmański 		return 0;
26831b26bab1SDaniel Kochmański 	initialized = 1;
26841b26bab1SDaniel Kochmański 
2685c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK)
2686b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY)
2687c40fdca6SSimon Glass 	mmc_list_init();
2688c40fdca6SSimon Glass #endif
2689b5b838f1SMarek Vasut #endif
26908e3332e2SSjoerd Simons 	ret = mmc_probe(bis);
26918e3332e2SSjoerd Simons 	if (ret)
26928e3332e2SSjoerd Simons 		return ret;
2693272cc70bSAndy Fleming 
2694bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD
2695272cc70bSAndy Fleming 	print_mmc_devices(',');
2696bb0dc108SYing Zhang #endif
2697272cc70bSAndy Fleming 
2698c40fdca6SSimon Glass 	mmc_do_preinit();
2699272cc70bSAndy Fleming 	return 0;
2700272cc70bSAndy Fleming }
2701cd3d4880STomas Melin 
2702cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE
2703cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc)
2704cd3d4880STomas Melin {
2705cd3d4880STomas Melin 	int err;
2706cd3d4880STomas Melin 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
2707cd3d4880STomas Melin 
2708cd3d4880STomas Melin 	err = mmc_send_ext_csd(mmc, ext_csd);
2709cd3d4880STomas Melin 	if (err) {
2710cd3d4880STomas Melin 		puts("Could not get ext_csd register values\n");
2711cd3d4880STomas Melin 		return err;
2712cd3d4880STomas Melin 	}
2713cd3d4880STomas Melin 
2714cd3d4880STomas Melin 	if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) {
2715cd3d4880STomas Melin 		puts("Background operations not supported on device\n");
2716cd3d4880STomas Melin 		return -EMEDIUMTYPE;
2717cd3d4880STomas Melin 	}
2718cd3d4880STomas Melin 
2719cd3d4880STomas Melin 	if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) {
2720cd3d4880STomas Melin 		puts("Background operations already enabled\n");
2721cd3d4880STomas Melin 		return 0;
2722cd3d4880STomas Melin 	}
2723cd3d4880STomas Melin 
2724cd3d4880STomas Melin 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1);
2725cd3d4880STomas Melin 	if (err) {
2726cd3d4880STomas Melin 		puts("Failed to enable manual background operations\n");
2727cd3d4880STomas Melin 		return err;
2728cd3d4880STomas Melin 	}
2729cd3d4880STomas Melin 
2730cd3d4880STomas Melin 	puts("Enabled manual background operations\n");
2731cd3d4880STomas Melin 
2732cd3d4880STomas Melin 	return 0;
2733cd3d4880STomas Melin }
2734cd3d4880STomas Melin #endif
2735