xref: /openbmc/u-boot/drivers/mmc/mmc.c (revision 04a2ea248f58b3b6216d0cd0a6b8698df8b14355)
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);
35aff5d3c8SKishon Vijay Abraham I 
36b5b838f1SMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY)
37b5b838f1SMarek Vasut static struct mmc mmc_static;
38b5b838f1SMarek Vasut struct mmc *find_mmc_device(int dev_num)
39b5b838f1SMarek Vasut {
40b5b838f1SMarek Vasut 	return &mmc_static;
41b5b838f1SMarek Vasut }
42b5b838f1SMarek Vasut 
43b5b838f1SMarek Vasut void mmc_do_preinit(void)
44b5b838f1SMarek Vasut {
45b5b838f1SMarek Vasut 	struct mmc *m = &mmc_static;
46b5b838f1SMarek Vasut #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
47b5b838f1SMarek Vasut 	mmc_set_preinit(m, 1);
48b5b838f1SMarek Vasut #endif
49b5b838f1SMarek Vasut 	if (m->preinit)
50b5b838f1SMarek Vasut 		mmc_start_init(m);
51b5b838f1SMarek Vasut }
52b5b838f1SMarek Vasut 
53b5b838f1SMarek Vasut struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
54b5b838f1SMarek Vasut {
55b5b838f1SMarek Vasut 	return &mmc->block_dev;
56b5b838f1SMarek Vasut }
57b5b838f1SMarek Vasut #endif
58b5b838f1SMarek Vasut 
59e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
60c10b85d6SJean-Jacques Hiblot 
61c10b85d6SJean-Jacques Hiblot static int mmc_wait_dat0(struct mmc *mmc, int state, int timeout)
62c10b85d6SJean-Jacques Hiblot {
63c10b85d6SJean-Jacques Hiblot 	return -ENOSYS;
64c10b85d6SJean-Jacques Hiblot }
65c10b85d6SJean-Jacques Hiblot 
66750121c3SJeroen Hofstee __weak int board_mmc_getwp(struct mmc *mmc)
67d23d8d7eSNikita Kiryanov {
68d23d8d7eSNikita Kiryanov 	return -1;
69d23d8d7eSNikita Kiryanov }
70d23d8d7eSNikita Kiryanov 
71d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc)
72d23d8d7eSNikita Kiryanov {
73d23d8d7eSNikita Kiryanov 	int wp;
74d23d8d7eSNikita Kiryanov 
75d23d8d7eSNikita Kiryanov 	wp = board_mmc_getwp(mmc);
76d23d8d7eSNikita Kiryanov 
77d4e1da4eSPeter Korsgaard 	if (wp < 0) {
7893bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getwp)
7993bfd616SPantelis Antoniou 			wp = mmc->cfg->ops->getwp(mmc);
80d4e1da4eSPeter Korsgaard 		else
81d4e1da4eSPeter Korsgaard 			wp = 0;
82d4e1da4eSPeter Korsgaard 	}
83d23d8d7eSNikita Kiryanov 
84d23d8d7eSNikita Kiryanov 	return wp;
85d23d8d7eSNikita Kiryanov }
86d23d8d7eSNikita Kiryanov 
87cee9ab7cSJeroen Hofstee __weak int board_mmc_getcd(struct mmc *mmc)
88cee9ab7cSJeroen Hofstee {
8911fdade2SStefano Babic 	return -1;
9011fdade2SStefano Babic }
918ca51e51SSimon Glass #endif
9211fdade2SStefano Babic 
938635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE
94c0c76ebaSSimon Glass void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd)
95c0c76ebaSSimon Glass {
96c0c76ebaSSimon Glass 	printf("CMD_SEND:%d\n", cmd->cmdidx);
97c0c76ebaSSimon Glass 	printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg);
98c0c76ebaSSimon Glass }
99c0c76ebaSSimon Glass 
100c0c76ebaSSimon Glass void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret)
101c0c76ebaSSimon Glass {
1025db2fe3aSRaffaele Recalcati 	int i;
1035db2fe3aSRaffaele Recalcati 	u8 *ptr;
1045db2fe3aSRaffaele Recalcati 
1057863ce58SBin Meng 	if (ret) {
1067863ce58SBin Meng 		printf("\t\tRET\t\t\t %d\n", ret);
1077863ce58SBin Meng 	} else {
1085db2fe3aSRaffaele Recalcati 		switch (cmd->resp_type) {
1095db2fe3aSRaffaele Recalcati 		case MMC_RSP_NONE:
1105db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_NONE\n");
1115db2fe3aSRaffaele Recalcati 			break;
1125db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1:
1135db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n",
1145db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1155db2fe3aSRaffaele Recalcati 			break;
1165db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1b:
1175db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n",
1185db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1195db2fe3aSRaffaele Recalcati 			break;
1205db2fe3aSRaffaele Recalcati 		case MMC_RSP_R2:
1215db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R2\t\t 0x%08X \n",
1225db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1235db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1245db2fe3aSRaffaele Recalcati 				cmd->response[1]);
1255db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1265db2fe3aSRaffaele Recalcati 				cmd->response[2]);
1275db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1285db2fe3aSRaffaele Recalcati 				cmd->response[3]);
1295db2fe3aSRaffaele Recalcati 			printf("\n");
1305db2fe3aSRaffaele Recalcati 			printf("\t\t\t\t\tDUMPING DATA\n");
1315db2fe3aSRaffaele Recalcati 			for (i = 0; i < 4; i++) {
1325db2fe3aSRaffaele Recalcati 				int j;
1335db2fe3aSRaffaele Recalcati 				printf("\t\t\t\t\t%03d - ", i*4);
134146bec79SDirk Behme 				ptr = (u8 *)&cmd->response[i];
1355db2fe3aSRaffaele Recalcati 				ptr += 3;
1365db2fe3aSRaffaele Recalcati 				for (j = 0; j < 4; j++)
1375db2fe3aSRaffaele Recalcati 					printf("%02X ", *ptr--);
1385db2fe3aSRaffaele Recalcati 				printf("\n");
1395db2fe3aSRaffaele Recalcati 			}
1405db2fe3aSRaffaele Recalcati 			break;
1415db2fe3aSRaffaele Recalcati 		case MMC_RSP_R3:
1425db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n",
1435db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1445db2fe3aSRaffaele Recalcati 			break;
1455db2fe3aSRaffaele Recalcati 		default:
1465db2fe3aSRaffaele Recalcati 			printf("\t\tERROR MMC rsp not supported\n");
1475db2fe3aSRaffaele Recalcati 			break;
1485db2fe3aSRaffaele Recalcati 		}
1497863ce58SBin Meng 	}
150c0c76ebaSSimon Glass }
151c0c76ebaSSimon Glass 
152c0c76ebaSSimon Glass void mmc_trace_state(struct mmc *mmc, struct mmc_cmd *cmd)
153c0c76ebaSSimon Glass {
154c0c76ebaSSimon Glass 	int status;
155c0c76ebaSSimon Glass 
156c0c76ebaSSimon Glass 	status = (cmd->response[0] & MMC_STATUS_CURR_STATE) >> 9;
157c0c76ebaSSimon Glass 	printf("CURR STATE:%d\n", status);
158c0c76ebaSSimon Glass }
1595db2fe3aSRaffaele Recalcati #endif
160c0c76ebaSSimon Glass 
16135f9e196SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG)
16235f9e196SJean-Jacques Hiblot const char *mmc_mode_name(enum bus_mode mode)
16335f9e196SJean-Jacques Hiblot {
16435f9e196SJean-Jacques Hiblot 	static const char *const names[] = {
16535f9e196SJean-Jacques Hiblot 	      [MMC_LEGACY]	= "MMC legacy",
16635f9e196SJean-Jacques Hiblot 	      [SD_LEGACY]	= "SD Legacy",
16735f9e196SJean-Jacques Hiblot 	      [MMC_HS]		= "MMC High Speed (26MHz)",
16835f9e196SJean-Jacques Hiblot 	      [SD_HS]		= "SD High Speed (50MHz)",
16935f9e196SJean-Jacques Hiblot 	      [UHS_SDR12]	= "UHS SDR12 (25MHz)",
17035f9e196SJean-Jacques Hiblot 	      [UHS_SDR25]	= "UHS SDR25 (50MHz)",
17135f9e196SJean-Jacques Hiblot 	      [UHS_SDR50]	= "UHS SDR50 (100MHz)",
17235f9e196SJean-Jacques Hiblot 	      [UHS_SDR104]	= "UHS SDR104 (208MHz)",
17335f9e196SJean-Jacques Hiblot 	      [UHS_DDR50]	= "UHS DDR50 (50MHz)",
17435f9e196SJean-Jacques Hiblot 	      [MMC_HS_52]	= "MMC High Speed (52MHz)",
17535f9e196SJean-Jacques Hiblot 	      [MMC_DDR_52]	= "MMC DDR52 (52MHz)",
17635f9e196SJean-Jacques Hiblot 	      [MMC_HS_200]	= "HS200 (200MHz)",
17735f9e196SJean-Jacques Hiblot 	};
17835f9e196SJean-Jacques Hiblot 
17935f9e196SJean-Jacques Hiblot 	if (mode >= MMC_MODES_END)
18035f9e196SJean-Jacques Hiblot 		return "Unknown mode";
18135f9e196SJean-Jacques Hiblot 	else
18235f9e196SJean-Jacques Hiblot 		return names[mode];
18335f9e196SJean-Jacques Hiblot }
18435f9e196SJean-Jacques Hiblot #endif
18535f9e196SJean-Jacques Hiblot 
18605038576SJean-Jacques Hiblot static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode)
18705038576SJean-Jacques Hiblot {
18805038576SJean-Jacques Hiblot 	static const int freqs[] = {
18905038576SJean-Jacques Hiblot 	      [SD_LEGACY]	= 25000000,
19005038576SJean-Jacques Hiblot 	      [MMC_HS]		= 26000000,
19105038576SJean-Jacques Hiblot 	      [SD_HS]		= 50000000,
19205038576SJean-Jacques Hiblot 	      [UHS_SDR12]	= 25000000,
19305038576SJean-Jacques Hiblot 	      [UHS_SDR25]	= 50000000,
19405038576SJean-Jacques Hiblot 	      [UHS_SDR50]	= 100000000,
19505038576SJean-Jacques Hiblot 	      [UHS_SDR104]	= 208000000,
19605038576SJean-Jacques Hiblot 	      [UHS_DDR50]	= 50000000,
19705038576SJean-Jacques Hiblot 	      [MMC_HS_52]	= 52000000,
19805038576SJean-Jacques Hiblot 	      [MMC_DDR_52]	= 52000000,
19905038576SJean-Jacques Hiblot 	      [MMC_HS_200]	= 200000000,
20005038576SJean-Jacques Hiblot 	};
20105038576SJean-Jacques Hiblot 
20205038576SJean-Jacques Hiblot 	if (mode == MMC_LEGACY)
20305038576SJean-Jacques Hiblot 		return mmc->legacy_speed;
20405038576SJean-Jacques Hiblot 	else if (mode >= MMC_MODES_END)
20505038576SJean-Jacques Hiblot 		return 0;
20605038576SJean-Jacques Hiblot 	else
20705038576SJean-Jacques Hiblot 		return freqs[mode];
20805038576SJean-Jacques Hiblot }
20905038576SJean-Jacques Hiblot 
21035f9e196SJean-Jacques Hiblot static int mmc_select_mode(struct mmc *mmc, enum bus_mode mode)
21135f9e196SJean-Jacques Hiblot {
21235f9e196SJean-Jacques Hiblot 	mmc->selected_mode = mode;
21305038576SJean-Jacques Hiblot 	mmc->tran_speed = mmc_mode2freq(mmc, mode);
2143862b854SJean-Jacques Hiblot 	mmc->ddr_mode = mmc_is_mode_ddr(mode);
21535f9e196SJean-Jacques Hiblot 	debug("selecting mode %s (freq : %d MHz)\n", mmc_mode_name(mode),
21635f9e196SJean-Jacques Hiblot 	      mmc->tran_speed / 1000000);
21735f9e196SJean-Jacques Hiblot 	return 0;
21835f9e196SJean-Jacques Hiblot }
21935f9e196SJean-Jacques Hiblot 
220e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
221c0c76ebaSSimon Glass int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
222c0c76ebaSSimon Glass {
223c0c76ebaSSimon Glass 	int ret;
224c0c76ebaSSimon Glass 
225c0c76ebaSSimon Glass 	mmmc_trace_before_send(mmc, cmd);
226c0c76ebaSSimon Glass 	ret = mmc->cfg->ops->send_cmd(mmc, cmd, data);
227c0c76ebaSSimon Glass 	mmmc_trace_after_send(mmc, cmd, ret);
228c0c76ebaSSimon Glass 
2298635ff9eSMarek Vasut 	return ret;
230272cc70bSAndy Fleming }
2318ca51e51SSimon Glass #endif
232272cc70bSAndy Fleming 
233da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout)
2345d4fc8d9SRaffaele Recalcati {
2355d4fc8d9SRaffaele Recalcati 	struct mmc_cmd cmd;
236d617c426SJan Kloetzke 	int err, retries = 5;
2375d4fc8d9SRaffaele Recalcati 
2385d4fc8d9SRaffaele Recalcati 	cmd.cmdidx = MMC_CMD_SEND_STATUS;
2395d4fc8d9SRaffaele Recalcati 	cmd.resp_type = MMC_RSP_R1;
240aaf3d41aSMarek Vasut 	if (!mmc_host_is_spi(mmc))
241aaf3d41aSMarek Vasut 		cmd.cmdarg = mmc->rca << 16;
2425d4fc8d9SRaffaele Recalcati 
2431677eef4SAndrew Gabbasov 	while (1) {
2445d4fc8d9SRaffaele Recalcati 		err = mmc_send_cmd(mmc, &cmd, NULL);
245d617c426SJan Kloetzke 		if (!err) {
246d617c426SJan Kloetzke 			if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) &&
247d617c426SJan Kloetzke 			    (cmd.response[0] & MMC_STATUS_CURR_STATE) !=
248d617c426SJan Kloetzke 			     MMC_STATE_PRG)
2495d4fc8d9SRaffaele Recalcati 				break;
250d0c221feSJean-Jacques Hiblot 
251d0c221feSJean-Jacques Hiblot 			if (cmd.response[0] & MMC_STATUS_MASK) {
25256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
253d617c426SJan Kloetzke 				printf("Status Error: 0x%08X\n",
254d617c426SJan Kloetzke 					cmd.response[0]);
25556196826SPaul Burton #endif
256915ffa52SJaehoon Chung 				return -ECOMM;
257d617c426SJan Kloetzke 			}
258d617c426SJan Kloetzke 		} else if (--retries < 0)
259d617c426SJan Kloetzke 			return err;
2605d4fc8d9SRaffaele Recalcati 
2611677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
2621677eef4SAndrew Gabbasov 			break;
2635d4fc8d9SRaffaele Recalcati 
2641677eef4SAndrew Gabbasov 		udelay(1000);
2651677eef4SAndrew Gabbasov 	}
2665d4fc8d9SRaffaele Recalcati 
267c0c76ebaSSimon Glass 	mmc_trace_state(mmc, &cmd);
2685b0c942fSJongman Heo 	if (timeout <= 0) {
26956196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2705d4fc8d9SRaffaele Recalcati 		printf("Timeout waiting card ready\n");
27156196826SPaul Burton #endif
272915ffa52SJaehoon Chung 		return -ETIMEDOUT;
2735d4fc8d9SRaffaele Recalcati 	}
2745d4fc8d9SRaffaele Recalcati 
2755d4fc8d9SRaffaele Recalcati 	return 0;
2765d4fc8d9SRaffaele Recalcati }
2775d4fc8d9SRaffaele Recalcati 
278da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len)
279272cc70bSAndy Fleming {
280272cc70bSAndy Fleming 	struct mmc_cmd cmd;
281272cc70bSAndy Fleming 
282786e8f81SAndrew Gabbasov 	if (mmc->ddr_mode)
283d22e3d46SJaehoon Chung 		return 0;
284d22e3d46SJaehoon Chung 
285272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
286272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
287272cc70bSAndy Fleming 	cmd.cmdarg = len;
288272cc70bSAndy Fleming 
289272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, NULL);
290272cc70bSAndy Fleming }
291272cc70bSAndy Fleming 
292ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
293fdbb873eSKim Phillips 			   lbaint_t blkcnt)
294272cc70bSAndy Fleming {
295272cc70bSAndy Fleming 	struct mmc_cmd cmd;
296272cc70bSAndy Fleming 	struct mmc_data data;
297272cc70bSAndy Fleming 
2984a1a06bcSAlagu Sankar 	if (blkcnt > 1)
2994a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
3004a1a06bcSAlagu Sankar 	else
301272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
302272cc70bSAndy Fleming 
303272cc70bSAndy Fleming 	if (mmc->high_capacity)
3044a1a06bcSAlagu Sankar 		cmd.cmdarg = start;
305272cc70bSAndy Fleming 	else
3064a1a06bcSAlagu Sankar 		cmd.cmdarg = start * mmc->read_bl_len;
307272cc70bSAndy Fleming 
308272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
309272cc70bSAndy Fleming 
310272cc70bSAndy Fleming 	data.dest = dst;
3114a1a06bcSAlagu Sankar 	data.blocks = blkcnt;
312272cc70bSAndy Fleming 	data.blocksize = mmc->read_bl_len;
313272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
314272cc70bSAndy Fleming 
3154a1a06bcSAlagu Sankar 	if (mmc_send_cmd(mmc, &cmd, &data))
3164a1a06bcSAlagu Sankar 		return 0;
3174a1a06bcSAlagu Sankar 
3184a1a06bcSAlagu Sankar 	if (blkcnt > 1) {
3194a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
3204a1a06bcSAlagu Sankar 		cmd.cmdarg = 0;
3214a1a06bcSAlagu Sankar 		cmd.resp_type = MMC_RSP_R1b;
3224a1a06bcSAlagu Sankar 		if (mmc_send_cmd(mmc, &cmd, NULL)) {
32356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
3244a1a06bcSAlagu Sankar 			printf("mmc fail to send stop cmd\n");
32556196826SPaul Burton #endif
3264a1a06bcSAlagu Sankar 			return 0;
3274a1a06bcSAlagu Sankar 		}
328272cc70bSAndy Fleming 	}
329272cc70bSAndy Fleming 
3304a1a06bcSAlagu Sankar 	return blkcnt;
331272cc70bSAndy Fleming }
332272cc70bSAndy Fleming 
333c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
3347dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst)
33533fb211dSSimon Glass #else
3367dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
3377dba0b93SSimon Glass 		void *dst)
33833fb211dSSimon Glass #endif
339272cc70bSAndy Fleming {
340c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
34133fb211dSSimon Glass 	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
34233fb211dSSimon Glass #endif
343bcce53d0SSimon Glass 	int dev_num = block_dev->devnum;
344873cc1d7SStephen Warren 	int err;
3454a1a06bcSAlagu Sankar 	lbaint_t cur, blocks_todo = blkcnt;
346272cc70bSAndy Fleming 
3474a1a06bcSAlagu Sankar 	if (blkcnt == 0)
3484a1a06bcSAlagu Sankar 		return 0;
3494a1a06bcSAlagu Sankar 
3504a1a06bcSAlagu Sankar 	struct mmc *mmc = find_mmc_device(dev_num);
351272cc70bSAndy Fleming 	if (!mmc)
352272cc70bSAndy Fleming 		return 0;
353272cc70bSAndy Fleming 
354b5b838f1SMarek Vasut 	if (CONFIG_IS_ENABLED(MMC_TINY))
355b5b838f1SMarek Vasut 		err = mmc_switch_part(mmc, block_dev->hwpart);
356b5b838f1SMarek Vasut 	else
35769f45cd5SSimon Glass 		err = blk_dselect_hwpart(block_dev, block_dev->hwpart);
358b5b838f1SMarek Vasut 
359873cc1d7SStephen Warren 	if (err < 0)
360873cc1d7SStephen Warren 		return 0;
361873cc1d7SStephen Warren 
362c40fdca6SSimon Glass 	if ((start + blkcnt) > block_dev->lba) {
36356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
364ff8fef56SSascha Silbe 		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
365c40fdca6SSimon Glass 			start + blkcnt, block_dev->lba);
36656196826SPaul Burton #endif
367d2bf29e3SLei Wen 		return 0;
368d2bf29e3SLei Wen 	}
369272cc70bSAndy Fleming 
37011692991SSimon Glass 	if (mmc_set_blocklen(mmc, mmc->read_bl_len)) {
37111692991SSimon Glass 		debug("%s: Failed to set blocklen\n", __func__);
372272cc70bSAndy Fleming 		return 0;
37311692991SSimon Glass 	}
374272cc70bSAndy Fleming 
3754a1a06bcSAlagu Sankar 	do {
37693bfd616SPantelis Antoniou 		cur = (blocks_todo > mmc->cfg->b_max) ?
37793bfd616SPantelis Antoniou 			mmc->cfg->b_max : blocks_todo;
37811692991SSimon Glass 		if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
37911692991SSimon Glass 			debug("%s: Failed to read blocks\n", __func__);
3804a1a06bcSAlagu Sankar 			return 0;
38111692991SSimon Glass 		}
3824a1a06bcSAlagu Sankar 		blocks_todo -= cur;
3834a1a06bcSAlagu Sankar 		start += cur;
3844a1a06bcSAlagu Sankar 		dst += cur * mmc->read_bl_len;
3854a1a06bcSAlagu Sankar 	} while (blocks_todo > 0);
386272cc70bSAndy Fleming 
387272cc70bSAndy Fleming 	return blkcnt;
388272cc70bSAndy Fleming }
389272cc70bSAndy Fleming 
390fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc)
391272cc70bSAndy Fleming {
392272cc70bSAndy Fleming 	struct mmc_cmd cmd;
393272cc70bSAndy Fleming 	int err;
394272cc70bSAndy Fleming 
395272cc70bSAndy Fleming 	udelay(1000);
396272cc70bSAndy Fleming 
397272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
398272cc70bSAndy Fleming 	cmd.cmdarg = 0;
399272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_NONE;
400272cc70bSAndy Fleming 
401272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
402272cc70bSAndy Fleming 
403272cc70bSAndy Fleming 	if (err)
404272cc70bSAndy Fleming 		return err;
405272cc70bSAndy Fleming 
406272cc70bSAndy Fleming 	udelay(2000);
407272cc70bSAndy Fleming 
408272cc70bSAndy Fleming 	return 0;
409272cc70bSAndy Fleming }
410272cc70bSAndy Fleming 
411c10b85d6SJean-Jacques Hiblot static int mmc_switch_voltage(struct mmc *mmc, int signal_voltage)
412c10b85d6SJean-Jacques Hiblot {
413c10b85d6SJean-Jacques Hiblot 	struct mmc_cmd cmd;
414c10b85d6SJean-Jacques Hiblot 	int err = 0;
415c10b85d6SJean-Jacques Hiblot 
416c10b85d6SJean-Jacques Hiblot 	/*
417c10b85d6SJean-Jacques Hiblot 	 * Send CMD11 only if the request is to switch the card to
418c10b85d6SJean-Jacques Hiblot 	 * 1.8V signalling.
419c10b85d6SJean-Jacques Hiblot 	 */
420c10b85d6SJean-Jacques Hiblot 	if (signal_voltage == MMC_SIGNAL_VOLTAGE_330)
421c10b85d6SJean-Jacques Hiblot 		return mmc_set_signal_voltage(mmc, signal_voltage);
422c10b85d6SJean-Jacques Hiblot 
423c10b85d6SJean-Jacques Hiblot 	cmd.cmdidx = SD_CMD_SWITCH_UHS18V;
424c10b85d6SJean-Jacques Hiblot 	cmd.cmdarg = 0;
425c10b85d6SJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
426c10b85d6SJean-Jacques Hiblot 
427c10b85d6SJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
428c10b85d6SJean-Jacques Hiblot 	if (err)
429c10b85d6SJean-Jacques Hiblot 		return err;
430c10b85d6SJean-Jacques Hiblot 
431c10b85d6SJean-Jacques Hiblot 	if (!mmc_host_is_spi(mmc) && (cmd.response[0] & MMC_STATUS_ERROR))
432c10b85d6SJean-Jacques Hiblot 		return -EIO;
433c10b85d6SJean-Jacques Hiblot 
434c10b85d6SJean-Jacques Hiblot 	/*
435c10b85d6SJean-Jacques Hiblot 	 * The card should drive cmd and dat[0:3] low immediately
436c10b85d6SJean-Jacques Hiblot 	 * after the response of cmd11, but wait 100 us to be sure
437c10b85d6SJean-Jacques Hiblot 	 */
438c10b85d6SJean-Jacques Hiblot 	err = mmc_wait_dat0(mmc, 0, 100);
439c10b85d6SJean-Jacques Hiblot 	if (err == -ENOSYS)
440c10b85d6SJean-Jacques Hiblot 		udelay(100);
441c10b85d6SJean-Jacques Hiblot 	else if (err)
442c10b85d6SJean-Jacques Hiblot 		return -ETIMEDOUT;
443c10b85d6SJean-Jacques Hiblot 
444c10b85d6SJean-Jacques Hiblot 	/*
445c10b85d6SJean-Jacques Hiblot 	 * During a signal voltage level switch, the clock must be gated
446c10b85d6SJean-Jacques Hiblot 	 * for 5 ms according to the SD spec
447c10b85d6SJean-Jacques Hiblot 	 */
448c10b85d6SJean-Jacques Hiblot 	mmc_set_clock(mmc, mmc->clock, true);
449c10b85d6SJean-Jacques Hiblot 
450c10b85d6SJean-Jacques Hiblot 	err = mmc_set_signal_voltage(mmc, signal_voltage);
451c10b85d6SJean-Jacques Hiblot 	if (err)
452c10b85d6SJean-Jacques Hiblot 		return err;
453c10b85d6SJean-Jacques Hiblot 
454c10b85d6SJean-Jacques Hiblot 	/* Keep clock gated for at least 10 ms, though spec only says 5 ms */
455c10b85d6SJean-Jacques Hiblot 	mdelay(10);
456c10b85d6SJean-Jacques Hiblot 	mmc_set_clock(mmc, mmc->clock, false);
457c10b85d6SJean-Jacques Hiblot 
458c10b85d6SJean-Jacques Hiblot 	/*
459c10b85d6SJean-Jacques Hiblot 	 * Failure to switch is indicated by the card holding
460c10b85d6SJean-Jacques Hiblot 	 * dat[0:3] low. Wait for at least 1 ms according to spec
461c10b85d6SJean-Jacques Hiblot 	 */
462c10b85d6SJean-Jacques Hiblot 	err = mmc_wait_dat0(mmc, 1, 1000);
463c10b85d6SJean-Jacques Hiblot 	if (err == -ENOSYS)
464c10b85d6SJean-Jacques Hiblot 		udelay(1000);
465c10b85d6SJean-Jacques Hiblot 	else if (err)
466c10b85d6SJean-Jacques Hiblot 		return -ETIMEDOUT;
467c10b85d6SJean-Jacques Hiblot 
468c10b85d6SJean-Jacques Hiblot 	return 0;
469c10b85d6SJean-Jacques Hiblot }
470c10b85d6SJean-Jacques Hiblot 
471c10b85d6SJean-Jacques Hiblot static int sd_send_op_cond(struct mmc *mmc, bool uhs_en)
472272cc70bSAndy Fleming {
473272cc70bSAndy Fleming 	int timeout = 1000;
474272cc70bSAndy Fleming 	int err;
475272cc70bSAndy Fleming 	struct mmc_cmd cmd;
476272cc70bSAndy Fleming 
4771677eef4SAndrew Gabbasov 	while (1) {
478272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_APP_CMD;
479272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1;
480272cc70bSAndy Fleming 		cmd.cmdarg = 0;
481272cc70bSAndy Fleming 
482272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
483272cc70bSAndy Fleming 
484272cc70bSAndy Fleming 		if (err)
485272cc70bSAndy Fleming 			return err;
486272cc70bSAndy Fleming 
487272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
488272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
489250de12bSStefano Babic 
490250de12bSStefano Babic 		/*
491250de12bSStefano Babic 		 * Most cards do not answer if some reserved bits
492250de12bSStefano Babic 		 * in the ocr are set. However, Some controller
493250de12bSStefano Babic 		 * can set bit 7 (reserved for low voltages), but
494250de12bSStefano Babic 		 * how to manage low voltages SD card is not yet
495250de12bSStefano Babic 		 * specified.
496250de12bSStefano Babic 		 */
497d52ebf10SThomas Chou 		cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
49893bfd616SPantelis Antoniou 			(mmc->cfg->voltages & 0xff8000);
499272cc70bSAndy Fleming 
500272cc70bSAndy Fleming 		if (mmc->version == SD_VERSION_2)
501272cc70bSAndy Fleming 			cmd.cmdarg |= OCR_HCS;
502272cc70bSAndy Fleming 
503c10b85d6SJean-Jacques Hiblot 		if (uhs_en)
504c10b85d6SJean-Jacques Hiblot 			cmd.cmdarg |= OCR_S18R;
505c10b85d6SJean-Jacques Hiblot 
506272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
507272cc70bSAndy Fleming 
508272cc70bSAndy Fleming 		if (err)
509272cc70bSAndy Fleming 			return err;
510272cc70bSAndy Fleming 
5111677eef4SAndrew Gabbasov 		if (cmd.response[0] & OCR_BUSY)
5121677eef4SAndrew Gabbasov 			break;
513272cc70bSAndy Fleming 
5141677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
515915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
516272cc70bSAndy Fleming 
5171677eef4SAndrew Gabbasov 		udelay(1000);
5181677eef4SAndrew Gabbasov 	}
5191677eef4SAndrew Gabbasov 
520272cc70bSAndy Fleming 	if (mmc->version != SD_VERSION_2)
521272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
522272cc70bSAndy Fleming 
523d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
524d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
525d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
526d52ebf10SThomas Chou 		cmd.cmdarg = 0;
527d52ebf10SThomas Chou 
528d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
529d52ebf10SThomas Chou 
530d52ebf10SThomas Chou 		if (err)
531d52ebf10SThomas Chou 			return err;
532d52ebf10SThomas Chou 	}
533d52ebf10SThomas Chou 
534998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
535272cc70bSAndy Fleming 
536c10b85d6SJean-Jacques Hiblot 	if (uhs_en && !(mmc_host_is_spi(mmc)) && (cmd.response[0] & 0x41000000)
537c10b85d6SJean-Jacques Hiblot 	    == 0x41000000) {
538c10b85d6SJean-Jacques Hiblot 		err = mmc_switch_voltage(mmc, MMC_SIGNAL_VOLTAGE_180);
539c10b85d6SJean-Jacques Hiblot 		if (err)
540c10b85d6SJean-Jacques Hiblot 			return err;
541c10b85d6SJean-Jacques Hiblot 	}
542c10b85d6SJean-Jacques Hiblot 
543272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
544272cc70bSAndy Fleming 	mmc->rca = 0;
545272cc70bSAndy Fleming 
546272cc70bSAndy Fleming 	return 0;
547272cc70bSAndy Fleming }
548272cc70bSAndy Fleming 
5495289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg)
550272cc70bSAndy Fleming {
5515289b535SAndrew Gabbasov 	struct mmc_cmd cmd;
552272cc70bSAndy Fleming 	int err;
553272cc70bSAndy Fleming 
5545289b535SAndrew Gabbasov 	cmd.cmdidx = MMC_CMD_SEND_OP_COND;
5555289b535SAndrew Gabbasov 	cmd.resp_type = MMC_RSP_R3;
5565289b535SAndrew Gabbasov 	cmd.cmdarg = 0;
5575a20397bSRob Herring 	if (use_arg && !mmc_host_is_spi(mmc))
5585a20397bSRob Herring 		cmd.cmdarg = OCR_HCS |
55993bfd616SPantelis Antoniou 			(mmc->cfg->voltages &
560a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_VOLTAGE_MASK)) |
561a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_ACCESS_MODE);
562e9550449SChe-Liang Chiou 
5635289b535SAndrew Gabbasov 	err = mmc_send_cmd(mmc, &cmd, NULL);
564e9550449SChe-Liang Chiou 	if (err)
565e9550449SChe-Liang Chiou 		return err;
5665289b535SAndrew Gabbasov 	mmc->ocr = cmd.response[0];
567e9550449SChe-Liang Chiou 	return 0;
568e9550449SChe-Liang Chiou }
569e9550449SChe-Liang Chiou 
570750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc)
571e9550449SChe-Liang Chiou {
572e9550449SChe-Liang Chiou 	int err, i;
573e9550449SChe-Liang Chiou 
574272cc70bSAndy Fleming 	/* Some cards seem to need this */
575272cc70bSAndy Fleming 	mmc_go_idle(mmc);
576272cc70bSAndy Fleming 
57731cacbabSRaffaele Recalcati  	/* Asking to the card its capabilities */
578e9550449SChe-Liang Chiou 	for (i = 0; i < 2; i++) {
5795289b535SAndrew Gabbasov 		err = mmc_send_op_cond_iter(mmc, i != 0);
58031cacbabSRaffaele Recalcati 		if (err)
58131cacbabSRaffaele Recalcati 			return err;
58231cacbabSRaffaele Recalcati 
583e9550449SChe-Liang Chiou 		/* exit if not busy (flag seems to be inverted) */
584a626c8d4SAndrew Gabbasov 		if (mmc->ocr & OCR_BUSY)
585bd47c135SAndrew Gabbasov 			break;
586e9550449SChe-Liang Chiou 	}
587bd47c135SAndrew Gabbasov 	mmc->op_cond_pending = 1;
588bd47c135SAndrew Gabbasov 	return 0;
589e9550449SChe-Liang Chiou }
59031cacbabSRaffaele Recalcati 
591750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc)
592e9550449SChe-Liang Chiou {
593e9550449SChe-Liang Chiou 	struct mmc_cmd cmd;
594e9550449SChe-Liang Chiou 	int timeout = 1000;
595e9550449SChe-Liang Chiou 	uint start;
596e9550449SChe-Liang Chiou 	int err;
597e9550449SChe-Liang Chiou 
598e9550449SChe-Liang Chiou 	mmc->op_cond_pending = 0;
599cc17c01fSAndrew Gabbasov 	if (!(mmc->ocr & OCR_BUSY)) {
600d188b113SYangbo Lu 		/* Some cards seem to need this */
601d188b113SYangbo Lu 		mmc_go_idle(mmc);
602d188b113SYangbo Lu 
603e9550449SChe-Liang Chiou 		start = get_timer(0);
6041677eef4SAndrew Gabbasov 		while (1) {
6055289b535SAndrew Gabbasov 			err = mmc_send_op_cond_iter(mmc, 1);
606272cc70bSAndy Fleming 			if (err)
607272cc70bSAndy Fleming 				return err;
6081677eef4SAndrew Gabbasov 			if (mmc->ocr & OCR_BUSY)
6091677eef4SAndrew Gabbasov 				break;
610e9550449SChe-Liang Chiou 			if (get_timer(start) > timeout)
611915ffa52SJaehoon Chung 				return -EOPNOTSUPP;
612e9550449SChe-Liang Chiou 			udelay(100);
6131677eef4SAndrew Gabbasov 		}
614cc17c01fSAndrew Gabbasov 	}
615272cc70bSAndy Fleming 
616d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
617d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
618d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
619d52ebf10SThomas Chou 		cmd.cmdarg = 0;
620d52ebf10SThomas Chou 
621d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
622d52ebf10SThomas Chou 
623d52ebf10SThomas Chou 		if (err)
624d52ebf10SThomas Chou 			return err;
625a626c8d4SAndrew Gabbasov 
626a626c8d4SAndrew Gabbasov 		mmc->ocr = cmd.response[0];
627d52ebf10SThomas Chou 	}
628d52ebf10SThomas Chou 
629272cc70bSAndy Fleming 	mmc->version = MMC_VERSION_UNKNOWN;
630272cc70bSAndy Fleming 
631272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
632def816a2SStephen Warren 	mmc->rca = 1;
633272cc70bSAndy Fleming 
634272cc70bSAndy Fleming 	return 0;
635272cc70bSAndy Fleming }
636272cc70bSAndy Fleming 
637272cc70bSAndy Fleming 
638fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
639272cc70bSAndy Fleming {
640272cc70bSAndy Fleming 	struct mmc_cmd cmd;
641272cc70bSAndy Fleming 	struct mmc_data data;
642272cc70bSAndy Fleming 	int err;
643272cc70bSAndy Fleming 
644272cc70bSAndy Fleming 	/* Get the Card Status Register */
645272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
646272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
647272cc70bSAndy Fleming 	cmd.cmdarg = 0;
648272cc70bSAndy Fleming 
649cdfd1ac6SYoshihiro Shimoda 	data.dest = (char *)ext_csd;
650272cc70bSAndy Fleming 	data.blocks = 1;
6518bfa195eSSimon Glass 	data.blocksize = MMC_MAX_BLOCK_LEN;
652272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
653272cc70bSAndy Fleming 
654272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
655272cc70bSAndy Fleming 
656272cc70bSAndy Fleming 	return err;
657272cc70bSAndy Fleming }
658272cc70bSAndy Fleming 
659c40704f4SSimon Glass int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
660272cc70bSAndy Fleming {
661272cc70bSAndy Fleming 	struct mmc_cmd cmd;
6625d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
663a9003dc6SMaxime Ripard 	int retries = 3;
6645d4fc8d9SRaffaele Recalcati 	int ret;
665272cc70bSAndy Fleming 
666272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SWITCH;
667272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1b;
668272cc70bSAndy Fleming 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
669272cc70bSAndy Fleming 				 (index << 16) |
670272cc70bSAndy Fleming 				 (value << 8);
671272cc70bSAndy Fleming 
672a9003dc6SMaxime Ripard 	while (retries > 0) {
6735d4fc8d9SRaffaele Recalcati 		ret = mmc_send_cmd(mmc, &cmd, NULL);
6745d4fc8d9SRaffaele Recalcati 
6755d4fc8d9SRaffaele Recalcati 		/* Waiting for the ready status */
676a9003dc6SMaxime Ripard 		if (!ret) {
67793ad0d18SJan Kloetzke 			ret = mmc_send_status(mmc, timeout);
678a9003dc6SMaxime Ripard 			return ret;
679a9003dc6SMaxime Ripard 		}
680a9003dc6SMaxime Ripard 
681a9003dc6SMaxime Ripard 		retries--;
682a9003dc6SMaxime Ripard 	}
6835d4fc8d9SRaffaele Recalcati 
6845d4fc8d9SRaffaele Recalcati 	return ret;
6855d4fc8d9SRaffaele Recalcati 
686272cc70bSAndy Fleming }
687272cc70bSAndy Fleming 
6883862b854SJean-Jacques Hiblot static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode)
689272cc70bSAndy Fleming {
690272cc70bSAndy Fleming 	int err;
6913862b854SJean-Jacques Hiblot 	int speed_bits;
6923862b854SJean-Jacques Hiblot 
6933862b854SJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
6943862b854SJean-Jacques Hiblot 
6953862b854SJean-Jacques Hiblot 	switch (mode) {
6963862b854SJean-Jacques Hiblot 	case MMC_HS:
6973862b854SJean-Jacques Hiblot 	case MMC_HS_52:
6983862b854SJean-Jacques Hiblot 	case MMC_DDR_52:
6993862b854SJean-Jacques Hiblot 		speed_bits = EXT_CSD_TIMING_HS;
700634d4849SKishon Vijay Abraham I 		break;
701634d4849SKishon Vijay Abraham I 	case MMC_HS_200:
702634d4849SKishon Vijay Abraham I 		speed_bits = EXT_CSD_TIMING_HS200;
703634d4849SKishon Vijay Abraham I 		break;
7043862b854SJean-Jacques Hiblot 	case MMC_LEGACY:
7053862b854SJean-Jacques Hiblot 		speed_bits = EXT_CSD_TIMING_LEGACY;
7063862b854SJean-Jacques Hiblot 		break;
7073862b854SJean-Jacques Hiblot 	default:
7083862b854SJean-Jacques Hiblot 		return -EINVAL;
7093862b854SJean-Jacques Hiblot 	}
7103862b854SJean-Jacques Hiblot 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
7113862b854SJean-Jacques Hiblot 			 speed_bits);
7123862b854SJean-Jacques Hiblot 	if (err)
7133862b854SJean-Jacques Hiblot 		return err;
7143862b854SJean-Jacques Hiblot 
7153862b854SJean-Jacques Hiblot 	if ((mode == MMC_HS) || (mode == MMC_HS_52)) {
7163862b854SJean-Jacques Hiblot 		/* Now check to see that it worked */
7173862b854SJean-Jacques Hiblot 		err = mmc_send_ext_csd(mmc, test_csd);
7183862b854SJean-Jacques Hiblot 		if (err)
7193862b854SJean-Jacques Hiblot 			return err;
7203862b854SJean-Jacques Hiblot 
7213862b854SJean-Jacques Hiblot 		/* No high-speed support */
7223862b854SJean-Jacques Hiblot 		if (!test_csd[EXT_CSD_HS_TIMING])
7233862b854SJean-Jacques Hiblot 			return -ENOTSUPP;
7243862b854SJean-Jacques Hiblot 	}
7253862b854SJean-Jacques Hiblot 
7263862b854SJean-Jacques Hiblot 	return 0;
7273862b854SJean-Jacques Hiblot }
7283862b854SJean-Jacques Hiblot 
7293862b854SJean-Jacques Hiblot static int mmc_get_capabilities(struct mmc *mmc)
7303862b854SJean-Jacques Hiblot {
7313862b854SJean-Jacques Hiblot 	u8 *ext_csd = mmc->ext_csd;
7323862b854SJean-Jacques Hiblot 	char cardtype;
733272cc70bSAndy Fleming 
734d0c221feSJean-Jacques Hiblot 	mmc->card_caps = MMC_MODE_1BIT;
735272cc70bSAndy Fleming 
736d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
737d52ebf10SThomas Chou 		return 0;
738d52ebf10SThomas Chou 
739272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
740272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
741272cc70bSAndy Fleming 		return 0;
742272cc70bSAndy Fleming 
7433862b854SJean-Jacques Hiblot 	if (!ext_csd) {
7443862b854SJean-Jacques Hiblot 		printf("No ext_csd found!\n"); /* this should enver happen */
7453862b854SJean-Jacques Hiblot 		return -ENOTSUPP;
7463862b854SJean-Jacques Hiblot 	}
7473862b854SJean-Jacques Hiblot 
748fc5b32fbSAndrew Gabbasov 	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
749fc5b32fbSAndrew Gabbasov 
750634d4849SKishon Vijay Abraham I 	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0x3f;
751272cc70bSAndy Fleming 
752634d4849SKishon Vijay Abraham I 	if (cardtype & (EXT_CSD_CARD_TYPE_HS200_1_2V |
753634d4849SKishon Vijay Abraham I 			EXT_CSD_CARD_TYPE_HS200_1_8V)) {
754634d4849SKishon Vijay Abraham I 		mmc->card_caps |= MMC_MODE_HS200;
755634d4849SKishon Vijay Abraham I 	}
756d22e3d46SJaehoon Chung 	if (cardtype & EXT_CSD_CARD_TYPE_52) {
7573862b854SJean-Jacques Hiblot 		if (cardtype & EXT_CSD_CARD_TYPE_DDR_52)
758d22e3d46SJaehoon Chung 			mmc->card_caps |= MMC_MODE_DDR_52MHz;
7593862b854SJean-Jacques Hiblot 		mmc->card_caps |= MMC_MODE_HS_52MHz;
760d22e3d46SJaehoon Chung 	}
7613862b854SJean-Jacques Hiblot 	if (cardtype & EXT_CSD_CARD_TYPE_26)
7623862b854SJean-Jacques Hiblot 		mmc->card_caps |= MMC_MODE_HS;
763272cc70bSAndy Fleming 
764272cc70bSAndy Fleming 	return 0;
765272cc70bSAndy Fleming }
766272cc70bSAndy Fleming 
767f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num)
768f866a46dSStephen Warren {
769f866a46dSStephen Warren 	switch (part_num) {
770f866a46dSStephen Warren 	case 0:
771f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_user;
772f866a46dSStephen Warren 		break;
773f866a46dSStephen Warren 	case 1:
774f866a46dSStephen Warren 	case 2:
775f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_boot;
776f866a46dSStephen Warren 		break;
777f866a46dSStephen Warren 	case 3:
778f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_rpmb;
779f866a46dSStephen Warren 		break;
780f866a46dSStephen Warren 	case 4:
781f866a46dSStephen Warren 	case 5:
782f866a46dSStephen Warren 	case 6:
783f866a46dSStephen Warren 	case 7:
784f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_gp[part_num - 4];
785f866a46dSStephen Warren 		break;
786f866a46dSStephen Warren 	default:
787f866a46dSStephen Warren 		return -1;
788f866a46dSStephen Warren 	}
789f866a46dSStephen Warren 
790c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len);
791f866a46dSStephen Warren 
792f866a46dSStephen Warren 	return 0;
793f866a46dSStephen Warren }
794f866a46dSStephen Warren 
7957dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num)
796bc897b1dSLei Wen {
797f866a46dSStephen Warren 	int ret;
798bc897b1dSLei Wen 
799f866a46dSStephen Warren 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
800bc897b1dSLei Wen 			 (mmc->part_config & ~PART_ACCESS_MASK)
801bc897b1dSLei Wen 			 | (part_num & PART_ACCESS_MASK));
802f866a46dSStephen Warren 
8036dc93e70SPeter Bigot 	/*
8046dc93e70SPeter Bigot 	 * Set the capacity if the switch succeeded or was intended
8056dc93e70SPeter Bigot 	 * to return to representing the raw device.
8066dc93e70SPeter Bigot 	 */
807873cc1d7SStephen Warren 	if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) {
8086dc93e70SPeter Bigot 		ret = mmc_set_capacity(mmc, part_num);
809fdbb139fSSimon Glass 		mmc_get_blk_desc(mmc)->hwpart = part_num;
810873cc1d7SStephen Warren 	}
8116dc93e70SPeter Bigot 
8126dc93e70SPeter Bigot 	return ret;
813bc897b1dSLei Wen }
814bc897b1dSLei Wen 
815ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc,
816ac9da0e0SDiego Santa Cruz 		      const struct mmc_hwpart_conf *conf,
817ac9da0e0SDiego Santa Cruz 		      enum mmc_hwpart_conf_mode mode)
818ac9da0e0SDiego Santa Cruz {
819ac9da0e0SDiego Santa Cruz 	u8 part_attrs = 0;
820ac9da0e0SDiego Santa Cruz 	u32 enh_size_mult;
821ac9da0e0SDiego Santa Cruz 	u32 enh_start_addr;
822ac9da0e0SDiego Santa Cruz 	u32 gp_size_mult[4];
823ac9da0e0SDiego Santa Cruz 	u32 max_enh_size_mult;
824ac9da0e0SDiego Santa Cruz 	u32 tot_enh_size_mult = 0;
8258dda5b0eSDiego Santa Cruz 	u8 wr_rel_set;
826ac9da0e0SDiego Santa Cruz 	int i, pidx, err;
827ac9da0e0SDiego Santa Cruz 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
828ac9da0e0SDiego Santa Cruz 
829ac9da0e0SDiego Santa Cruz 	if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE)
830ac9da0e0SDiego Santa Cruz 		return -EINVAL;
831ac9da0e0SDiego Santa Cruz 
832ac9da0e0SDiego Santa Cruz 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) {
833ac9da0e0SDiego Santa Cruz 		printf("eMMC >= 4.4 required for enhanced user data area\n");
834ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
835ac9da0e0SDiego Santa Cruz 	}
836ac9da0e0SDiego Santa Cruz 
837ac9da0e0SDiego Santa Cruz 	if (!(mmc->part_support & PART_SUPPORT)) {
838ac9da0e0SDiego Santa Cruz 		printf("Card does not support partitioning\n");
839ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
840ac9da0e0SDiego Santa Cruz 	}
841ac9da0e0SDiego Santa Cruz 
842ac9da0e0SDiego Santa Cruz 	if (!mmc->hc_wp_grp_size) {
843ac9da0e0SDiego Santa Cruz 		printf("Card does not define HC WP group size\n");
844ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
845ac9da0e0SDiego Santa Cruz 	}
846ac9da0e0SDiego Santa Cruz 
847ac9da0e0SDiego Santa Cruz 	/* check partition alignment and total enhanced size */
848ac9da0e0SDiego Santa Cruz 	if (conf->user.enh_size) {
849ac9da0e0SDiego Santa Cruz 		if (conf->user.enh_size % mmc->hc_wp_grp_size ||
850ac9da0e0SDiego Santa Cruz 		    conf->user.enh_start % mmc->hc_wp_grp_size) {
851ac9da0e0SDiego Santa Cruz 			printf("User data enhanced area not HC WP group "
852ac9da0e0SDiego Santa Cruz 			       "size aligned\n");
853ac9da0e0SDiego Santa Cruz 			return -EINVAL;
854ac9da0e0SDiego Santa Cruz 		}
855ac9da0e0SDiego Santa Cruz 		part_attrs |= EXT_CSD_ENH_USR;
856ac9da0e0SDiego Santa Cruz 		enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size;
857ac9da0e0SDiego Santa Cruz 		if (mmc->high_capacity) {
858ac9da0e0SDiego Santa Cruz 			enh_start_addr = conf->user.enh_start;
859ac9da0e0SDiego Santa Cruz 		} else {
860ac9da0e0SDiego Santa Cruz 			enh_start_addr = (conf->user.enh_start << 9);
861ac9da0e0SDiego Santa Cruz 		}
862ac9da0e0SDiego Santa Cruz 	} else {
863ac9da0e0SDiego Santa Cruz 		enh_size_mult = 0;
864ac9da0e0SDiego Santa Cruz 		enh_start_addr = 0;
865ac9da0e0SDiego Santa Cruz 	}
866ac9da0e0SDiego Santa Cruz 	tot_enh_size_mult += enh_size_mult;
867ac9da0e0SDiego Santa Cruz 
868ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
869ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) {
870ac9da0e0SDiego Santa Cruz 			printf("GP%i partition not HC WP group size "
871ac9da0e0SDiego Santa Cruz 			       "aligned\n", pidx+1);
872ac9da0e0SDiego Santa Cruz 			return -EINVAL;
873ac9da0e0SDiego Santa Cruz 		}
874ac9da0e0SDiego Santa Cruz 		gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size;
875ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) {
876ac9da0e0SDiego Santa Cruz 			part_attrs |= EXT_CSD_ENH_GP(pidx);
877ac9da0e0SDiego Santa Cruz 			tot_enh_size_mult += gp_size_mult[pidx];
878ac9da0e0SDiego Santa Cruz 		}
879ac9da0e0SDiego Santa Cruz 	}
880ac9da0e0SDiego Santa Cruz 
881ac9da0e0SDiego Santa Cruz 	if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) {
882ac9da0e0SDiego Santa Cruz 		printf("Card does not support enhanced attribute\n");
883ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
884ac9da0e0SDiego Santa Cruz 	}
885ac9da0e0SDiego Santa Cruz 
886ac9da0e0SDiego Santa Cruz 	err = mmc_send_ext_csd(mmc, ext_csd);
887ac9da0e0SDiego Santa Cruz 	if (err)
888ac9da0e0SDiego Santa Cruz 		return err;
889ac9da0e0SDiego Santa Cruz 
890ac9da0e0SDiego Santa Cruz 	max_enh_size_mult =
891ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) +
892ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) +
893ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT];
894ac9da0e0SDiego Santa Cruz 	if (tot_enh_size_mult > max_enh_size_mult) {
895ac9da0e0SDiego Santa Cruz 		printf("Total enhanced size exceeds maximum (%u > %u)\n",
896ac9da0e0SDiego Santa Cruz 		       tot_enh_size_mult, max_enh_size_mult);
897ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
898ac9da0e0SDiego Santa Cruz 	}
899ac9da0e0SDiego Santa Cruz 
9008dda5b0eSDiego Santa Cruz 	/* The default value of EXT_CSD_WR_REL_SET is device
9018dda5b0eSDiego Santa Cruz 	 * dependent, the values can only be changed if the
9028dda5b0eSDiego Santa Cruz 	 * EXT_CSD_HS_CTRL_REL bit is set. The values can be
9038dda5b0eSDiego Santa Cruz 	 * changed only once and before partitioning is completed. */
9048dda5b0eSDiego Santa Cruz 	wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
9058dda5b0eSDiego Santa Cruz 	if (conf->user.wr_rel_change) {
9068dda5b0eSDiego Santa Cruz 		if (conf->user.wr_rel_set)
9078dda5b0eSDiego Santa Cruz 			wr_rel_set |= EXT_CSD_WR_DATA_REL_USR;
9088dda5b0eSDiego Santa Cruz 		else
9098dda5b0eSDiego Santa Cruz 			wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR;
9108dda5b0eSDiego Santa Cruz 	}
9118dda5b0eSDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
9128dda5b0eSDiego Santa Cruz 		if (conf->gp_part[pidx].wr_rel_change) {
9138dda5b0eSDiego Santa Cruz 			if (conf->gp_part[pidx].wr_rel_set)
9148dda5b0eSDiego Santa Cruz 				wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx);
9158dda5b0eSDiego Santa Cruz 			else
9168dda5b0eSDiego Santa Cruz 				wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx);
9178dda5b0eSDiego Santa Cruz 		}
9188dda5b0eSDiego Santa Cruz 	}
9198dda5b0eSDiego Santa Cruz 
9208dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] &&
9218dda5b0eSDiego Santa Cruz 	    !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) {
9228dda5b0eSDiego Santa Cruz 		puts("Card does not support host controlled partition write "
9238dda5b0eSDiego Santa Cruz 		     "reliability settings\n");
9248dda5b0eSDiego Santa Cruz 		return -EMEDIUMTYPE;
9258dda5b0eSDiego Santa Cruz 	}
9268dda5b0eSDiego Santa Cruz 
927ac9da0e0SDiego Santa Cruz 	if (ext_csd[EXT_CSD_PARTITION_SETTING] &
928ac9da0e0SDiego Santa Cruz 	    EXT_CSD_PARTITION_SETTING_COMPLETED) {
929ac9da0e0SDiego Santa Cruz 		printf("Card already partitioned\n");
930ac9da0e0SDiego Santa Cruz 		return -EPERM;
931ac9da0e0SDiego Santa Cruz 	}
932ac9da0e0SDiego Santa Cruz 
933ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_CHECK)
934ac9da0e0SDiego Santa Cruz 		return 0;
935ac9da0e0SDiego Santa Cruz 
936ac9da0e0SDiego Santa Cruz 	/* Partitioning requires high-capacity size definitions */
937ac9da0e0SDiego Santa Cruz 	if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) {
938ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
939ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ERASE_GROUP_DEF, 1);
940ac9da0e0SDiego Santa Cruz 
941ac9da0e0SDiego Santa Cruz 		if (err)
942ac9da0e0SDiego Santa Cruz 			return err;
943ac9da0e0SDiego Santa Cruz 
944ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
945ac9da0e0SDiego Santa Cruz 
946ac9da0e0SDiego Santa Cruz 		/* update erase group size to be high-capacity */
947ac9da0e0SDiego Santa Cruz 		mmc->erase_grp_size =
948ac9da0e0SDiego Santa Cruz 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
949ac9da0e0SDiego Santa Cruz 
950ac9da0e0SDiego Santa Cruz 	}
951ac9da0e0SDiego Santa Cruz 
952ac9da0e0SDiego Santa Cruz 	/* all OK, write the configuration */
953ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 4; i++) {
954ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
955ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_START_ADDR+i,
956ac9da0e0SDiego Santa Cruz 				 (enh_start_addr >> (i*8)) & 0xFF);
957ac9da0e0SDiego Santa Cruz 		if (err)
958ac9da0e0SDiego Santa Cruz 			return err;
959ac9da0e0SDiego Santa Cruz 	}
960ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 3; i++) {
961ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
962ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_SIZE_MULT+i,
963ac9da0e0SDiego Santa Cruz 				 (enh_size_mult >> (i*8)) & 0xFF);
964ac9da0e0SDiego Santa Cruz 		if (err)
965ac9da0e0SDiego Santa Cruz 			return err;
966ac9da0e0SDiego Santa Cruz 	}
967ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
968ac9da0e0SDiego Santa Cruz 		for (i = 0; i < 3; i++) {
969ac9da0e0SDiego Santa Cruz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
970ac9da0e0SDiego Santa Cruz 					 EXT_CSD_GP_SIZE_MULT+pidx*3+i,
971ac9da0e0SDiego Santa Cruz 					 (gp_size_mult[pidx] >> (i*8)) & 0xFF);
972ac9da0e0SDiego Santa Cruz 			if (err)
973ac9da0e0SDiego Santa Cruz 				return err;
974ac9da0e0SDiego Santa Cruz 		}
975ac9da0e0SDiego Santa Cruz 	}
976ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
977ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs);
978ac9da0e0SDiego Santa Cruz 	if (err)
979ac9da0e0SDiego Santa Cruz 		return err;
980ac9da0e0SDiego Santa Cruz 
981ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_SET)
982ac9da0e0SDiego Santa Cruz 		return 0;
983ac9da0e0SDiego Santa Cruz 
9848dda5b0eSDiego Santa Cruz 	/* The WR_REL_SET is a write-once register but shall be
9858dda5b0eSDiego Santa Cruz 	 * written before setting PART_SETTING_COMPLETED. As it is
9868dda5b0eSDiego Santa Cruz 	 * write-once we can only write it when completing the
9878dda5b0eSDiego Santa Cruz 	 * partitioning. */
9888dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) {
9898dda5b0eSDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
9908dda5b0eSDiego Santa Cruz 				 EXT_CSD_WR_REL_SET, wr_rel_set);
9918dda5b0eSDiego Santa Cruz 		if (err)
9928dda5b0eSDiego Santa Cruz 			return err;
9938dda5b0eSDiego Santa Cruz 	}
9948dda5b0eSDiego Santa Cruz 
995ac9da0e0SDiego Santa Cruz 	/* Setting PART_SETTING_COMPLETED confirms the partition
996ac9da0e0SDiego Santa Cruz 	 * configuration but it only becomes effective after power
997ac9da0e0SDiego Santa Cruz 	 * cycle, so we do not adjust the partition related settings
998ac9da0e0SDiego Santa Cruz 	 * in the mmc struct. */
999ac9da0e0SDiego Santa Cruz 
1000ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1001ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING,
1002ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING_COMPLETED);
1003ac9da0e0SDiego Santa Cruz 	if (err)
1004ac9da0e0SDiego Santa Cruz 		return err;
1005ac9da0e0SDiego Santa Cruz 
1006ac9da0e0SDiego Santa Cruz 	return 0;
1007ac9da0e0SDiego Santa Cruz }
1008ac9da0e0SDiego Santa Cruz 
1009e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
101048972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
101148972d90SThierry Reding {
101248972d90SThierry Reding 	int cd;
101348972d90SThierry Reding 
101448972d90SThierry Reding 	cd = board_mmc_getcd(mmc);
101548972d90SThierry Reding 
1016d4e1da4eSPeter Korsgaard 	if (cd < 0) {
101793bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getcd)
101893bfd616SPantelis Antoniou 			cd = mmc->cfg->ops->getcd(mmc);
1019d4e1da4eSPeter Korsgaard 		else
1020d4e1da4eSPeter Korsgaard 			cd = 1;
1021d4e1da4eSPeter Korsgaard 	}
102248972d90SThierry Reding 
102348972d90SThierry Reding 	return cd;
102448972d90SThierry Reding }
10258ca51e51SSimon Glass #endif
102648972d90SThierry Reding 
1027fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
1028272cc70bSAndy Fleming {
1029272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1030272cc70bSAndy Fleming 	struct mmc_data data;
1031272cc70bSAndy Fleming 
1032272cc70bSAndy Fleming 	/* Switch the frequency */
1033272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
1034272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1035272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
1036272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
1037272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
1038272cc70bSAndy Fleming 
1039272cc70bSAndy Fleming 	data.dest = (char *)resp;
1040272cc70bSAndy Fleming 	data.blocksize = 64;
1041272cc70bSAndy Fleming 	data.blocks = 1;
1042272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
1043272cc70bSAndy Fleming 
1044272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
1045272cc70bSAndy Fleming }
1046272cc70bSAndy Fleming 
1047272cc70bSAndy Fleming 
1048d0c221feSJean-Jacques Hiblot static int sd_get_capabilities(struct mmc *mmc)
1049272cc70bSAndy Fleming {
1050272cc70bSAndy Fleming 	int err;
1051272cc70bSAndy Fleming 	struct mmc_cmd cmd;
105218e7c8f6SSuniel Mahesh 	ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2);
105318e7c8f6SSuniel Mahesh 	ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16);
1054272cc70bSAndy Fleming 	struct mmc_data data;
1055272cc70bSAndy Fleming 	int timeout;
1056c10b85d6SJean-Jacques Hiblot 	u32 sd3_bus_mode;
1057272cc70bSAndy Fleming 
1058d0c221feSJean-Jacques Hiblot 	mmc->card_caps = MMC_MODE_1BIT;
1059272cc70bSAndy Fleming 
1060d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
1061d52ebf10SThomas Chou 		return 0;
1062d52ebf10SThomas Chou 
1063272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
1064272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
1065272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1066272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1067272cc70bSAndy Fleming 
1068272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1069272cc70bSAndy Fleming 
1070272cc70bSAndy Fleming 	if (err)
1071272cc70bSAndy Fleming 		return err;
1072272cc70bSAndy Fleming 
1073272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
1074272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1075272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1076272cc70bSAndy Fleming 
1077272cc70bSAndy Fleming 	timeout = 3;
1078272cc70bSAndy Fleming 
1079272cc70bSAndy Fleming retry_scr:
1080f781dd38SAnton staaf 	data.dest = (char *)scr;
1081272cc70bSAndy Fleming 	data.blocksize = 8;
1082272cc70bSAndy Fleming 	data.blocks = 1;
1083272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
1084272cc70bSAndy Fleming 
1085272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
1086272cc70bSAndy Fleming 
1087272cc70bSAndy Fleming 	if (err) {
1088272cc70bSAndy Fleming 		if (timeout--)
1089272cc70bSAndy Fleming 			goto retry_scr;
1090272cc70bSAndy Fleming 
1091272cc70bSAndy Fleming 		return err;
1092272cc70bSAndy Fleming 	}
1093272cc70bSAndy Fleming 
10944e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
10954e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
1096272cc70bSAndy Fleming 
1097272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
1098272cc70bSAndy Fleming 	case 0:
1099272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1100272cc70bSAndy Fleming 		break;
1101272cc70bSAndy Fleming 	case 1:
1102272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_10;
1103272cc70bSAndy Fleming 		break;
1104272cc70bSAndy Fleming 	case 2:
1105272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
11061741c64dSJaehoon Chung 		if ((mmc->scr[0] >> 15) & 0x1)
11071741c64dSJaehoon Chung 			mmc->version = SD_VERSION_3;
1108272cc70bSAndy Fleming 		break;
1109272cc70bSAndy Fleming 	default:
1110272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1111272cc70bSAndy Fleming 		break;
1112272cc70bSAndy Fleming 	}
1113272cc70bSAndy Fleming 
1114b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
1115b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
1116b44c7083SAlagu Sankar 
1117272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
1118272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
1119272cc70bSAndy Fleming 		return 0;
1120272cc70bSAndy Fleming 
1121272cc70bSAndy Fleming 	timeout = 4;
1122272cc70bSAndy Fleming 	while (timeout--) {
1123272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
1124f781dd38SAnton staaf 				(u8 *)switch_status);
1125272cc70bSAndy Fleming 
1126272cc70bSAndy Fleming 		if (err)
1127272cc70bSAndy Fleming 			return err;
1128272cc70bSAndy Fleming 
1129272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
11304e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
1131272cc70bSAndy Fleming 			break;
1132272cc70bSAndy Fleming 	}
1133272cc70bSAndy Fleming 
1134272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
1135d0c221feSJean-Jacques Hiblot 	if (__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)
1136d0c221feSJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(SD_HS);
1137272cc70bSAndy Fleming 
1138c10b85d6SJean-Jacques Hiblot 	/* Version before 3.0 don't support UHS modes */
1139c10b85d6SJean-Jacques Hiblot 	if (mmc->version < SD_VERSION_3)
1140c10b85d6SJean-Jacques Hiblot 		return 0;
1141c10b85d6SJean-Jacques Hiblot 
1142c10b85d6SJean-Jacques Hiblot 	sd3_bus_mode = __be32_to_cpu(switch_status[3]) >> 16 & 0x1f;
1143c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR104)
1144c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR104);
1145c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR50)
1146c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR50);
1147c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR25)
1148c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR25);
1149c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_SDR12)
1150c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_SDR12);
1151c10b85d6SJean-Jacques Hiblot 	if (sd3_bus_mode & SD_MODE_UHS_DDR50)
1152c10b85d6SJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(UHS_DDR50);
1153c10b85d6SJean-Jacques Hiblot 
11542c3fbf4cSMacpaul Lin 	return 0;
1155d0c221feSJean-Jacques Hiblot }
1156d0c221feSJean-Jacques Hiblot 
1157d0c221feSJean-Jacques Hiblot static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode)
1158d0c221feSJean-Jacques Hiblot {
1159d0c221feSJean-Jacques Hiblot 	int err;
1160d0c221feSJean-Jacques Hiblot 
1161d0c221feSJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
1162c10b85d6SJean-Jacques Hiblot 	int speed;
11632c3fbf4cSMacpaul Lin 
1164c10b85d6SJean-Jacques Hiblot 	switch (mode) {
1165c10b85d6SJean-Jacques Hiblot 	case SD_LEGACY:
1166c10b85d6SJean-Jacques Hiblot 	case UHS_SDR12:
1167c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR12_BUS_SPEED;
1168c10b85d6SJean-Jacques Hiblot 		break;
1169c10b85d6SJean-Jacques Hiblot 	case SD_HS:
1170c10b85d6SJean-Jacques Hiblot 	case UHS_SDR25:
1171c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR25_BUS_SPEED;
1172c10b85d6SJean-Jacques Hiblot 		break;
1173c10b85d6SJean-Jacques Hiblot 	case UHS_SDR50:
1174c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR50_BUS_SPEED;
1175c10b85d6SJean-Jacques Hiblot 		break;
1176c10b85d6SJean-Jacques Hiblot 	case UHS_DDR50:
1177c10b85d6SJean-Jacques Hiblot 		speed = UHS_DDR50_BUS_SPEED;
1178c10b85d6SJean-Jacques Hiblot 		break;
1179c10b85d6SJean-Jacques Hiblot 	case UHS_SDR104:
1180c10b85d6SJean-Jacques Hiblot 		speed = UHS_SDR104_BUS_SPEED;
1181c10b85d6SJean-Jacques Hiblot 		break;
1182c10b85d6SJean-Jacques Hiblot 	default:
1183c10b85d6SJean-Jacques Hiblot 		return -EINVAL;
1184c10b85d6SJean-Jacques Hiblot 	}
1185c10b85d6SJean-Jacques Hiblot 
1186c10b85d6SJean-Jacques Hiblot 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, speed, (u8 *)switch_status);
1187272cc70bSAndy Fleming 	if (err)
1188272cc70bSAndy Fleming 		return err;
1189272cc70bSAndy Fleming 
1190c10b85d6SJean-Jacques Hiblot 	if ((__be32_to_cpu(switch_status[4]) >> 24) != speed)
1191d0c221feSJean-Jacques Hiblot 		return -ENOTSUPP;
1192d0c221feSJean-Jacques Hiblot 
1193d0c221feSJean-Jacques Hiblot 	return 0;
1194d0c221feSJean-Jacques Hiblot }
1195d0c221feSJean-Jacques Hiblot 
1196d0c221feSJean-Jacques Hiblot int sd_select_bus_width(struct mmc *mmc, int w)
1197d0c221feSJean-Jacques Hiblot {
1198d0c221feSJean-Jacques Hiblot 	int err;
1199d0c221feSJean-Jacques Hiblot 	struct mmc_cmd cmd;
1200d0c221feSJean-Jacques Hiblot 
1201d0c221feSJean-Jacques Hiblot 	if ((w != 4) && (w != 1))
1202d0c221feSJean-Jacques Hiblot 		return -EINVAL;
1203d0c221feSJean-Jacques Hiblot 
1204d0c221feSJean-Jacques Hiblot 	cmd.cmdidx = MMC_CMD_APP_CMD;
1205d0c221feSJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
1206d0c221feSJean-Jacques Hiblot 	cmd.cmdarg = mmc->rca << 16;
1207d0c221feSJean-Jacques Hiblot 
1208d0c221feSJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
1209d0c221feSJean-Jacques Hiblot 	if (err)
1210d0c221feSJean-Jacques Hiblot 		return err;
1211d0c221feSJean-Jacques Hiblot 
1212d0c221feSJean-Jacques Hiblot 	cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
1213d0c221feSJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
1214d0c221feSJean-Jacques Hiblot 	if (w == 4)
1215d0c221feSJean-Jacques Hiblot 		cmd.cmdarg = 2;
1216d0c221feSJean-Jacques Hiblot 	else if (w == 1)
1217d0c221feSJean-Jacques Hiblot 		cmd.cmdarg = 0;
1218d0c221feSJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
1219d0c221feSJean-Jacques Hiblot 	if (err)
1220d0c221feSJean-Jacques Hiblot 		return err;
1221272cc70bSAndy Fleming 
1222272cc70bSAndy Fleming 	return 0;
1223272cc70bSAndy Fleming }
1224272cc70bSAndy Fleming 
12253697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc)
12263697e599SPeng Fan {
12273697e599SPeng Fan 	int err, i;
12283697e599SPeng Fan 	struct mmc_cmd cmd;
12293697e599SPeng Fan 	ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16);
12303697e599SPeng Fan 	struct mmc_data data;
12313697e599SPeng Fan 	int timeout = 3;
12323697e599SPeng Fan 	unsigned int au, eo, et, es;
12333697e599SPeng Fan 
12343697e599SPeng Fan 	cmd.cmdidx = MMC_CMD_APP_CMD;
12353697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
12363697e599SPeng Fan 	cmd.cmdarg = mmc->rca << 16;
12373697e599SPeng Fan 
12383697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, NULL);
12393697e599SPeng Fan 	if (err)
12403697e599SPeng Fan 		return err;
12413697e599SPeng Fan 
12423697e599SPeng Fan 	cmd.cmdidx = SD_CMD_APP_SD_STATUS;
12433697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
12443697e599SPeng Fan 	cmd.cmdarg = 0;
12453697e599SPeng Fan 
12463697e599SPeng Fan retry_ssr:
12473697e599SPeng Fan 	data.dest = (char *)ssr;
12483697e599SPeng Fan 	data.blocksize = 64;
12493697e599SPeng Fan 	data.blocks = 1;
12503697e599SPeng Fan 	data.flags = MMC_DATA_READ;
12513697e599SPeng Fan 
12523697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, &data);
12533697e599SPeng Fan 	if (err) {
12543697e599SPeng Fan 		if (timeout--)
12553697e599SPeng Fan 			goto retry_ssr;
12563697e599SPeng Fan 
12573697e599SPeng Fan 		return err;
12583697e599SPeng Fan 	}
12593697e599SPeng Fan 
12603697e599SPeng Fan 	for (i = 0; i < 16; i++)
12613697e599SPeng Fan 		ssr[i] = be32_to_cpu(ssr[i]);
12623697e599SPeng Fan 
12633697e599SPeng Fan 	au = (ssr[2] >> 12) & 0xF;
12643697e599SPeng Fan 	if ((au <= 9) || (mmc->version == SD_VERSION_3)) {
12653697e599SPeng Fan 		mmc->ssr.au = sd_au_size[au];
12663697e599SPeng Fan 		es = (ssr[3] >> 24) & 0xFF;
12673697e599SPeng Fan 		es |= (ssr[2] & 0xFF) << 8;
12683697e599SPeng Fan 		et = (ssr[3] >> 18) & 0x3F;
12693697e599SPeng Fan 		if (es && et) {
12703697e599SPeng Fan 			eo = (ssr[3] >> 16) & 0x3;
12713697e599SPeng Fan 			mmc->ssr.erase_timeout = (et * 1000) / es;
12723697e599SPeng Fan 			mmc->ssr.erase_offset = eo * 1000;
12733697e599SPeng Fan 		}
12743697e599SPeng Fan 	} else {
12753697e599SPeng Fan 		debug("Invalid Allocation Unit Size.\n");
12763697e599SPeng Fan 	}
12773697e599SPeng Fan 
12783697e599SPeng Fan 	return 0;
12793697e599SPeng Fan }
12803697e599SPeng Fan 
1281272cc70bSAndy Fleming /* frequency bases */
1282272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
12835f837c2cSMike Frysinger static const int fbase[] = {
1284272cc70bSAndy Fleming 	10000,
1285272cc70bSAndy Fleming 	100000,
1286272cc70bSAndy Fleming 	1000000,
1287272cc70bSAndy Fleming 	10000000,
1288272cc70bSAndy Fleming };
1289272cc70bSAndy Fleming 
1290272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
1291272cc70bSAndy Fleming  * to platforms without floating point.
1292272cc70bSAndy Fleming  */
129361fe076fSSimon Glass static const u8 multipliers[] = {
1294272cc70bSAndy Fleming 	0,	/* reserved */
1295272cc70bSAndy Fleming 	10,
1296272cc70bSAndy Fleming 	12,
1297272cc70bSAndy Fleming 	13,
1298272cc70bSAndy Fleming 	15,
1299272cc70bSAndy Fleming 	20,
1300272cc70bSAndy Fleming 	25,
1301272cc70bSAndy Fleming 	30,
1302272cc70bSAndy Fleming 	35,
1303272cc70bSAndy Fleming 	40,
1304272cc70bSAndy Fleming 	45,
1305272cc70bSAndy Fleming 	50,
1306272cc70bSAndy Fleming 	55,
1307272cc70bSAndy Fleming 	60,
1308272cc70bSAndy Fleming 	70,
1309272cc70bSAndy Fleming 	80,
1310272cc70bSAndy Fleming };
1311272cc70bSAndy Fleming 
1312d0c221feSJean-Jacques Hiblot static inline int bus_width(uint cap)
1313d0c221feSJean-Jacques Hiblot {
1314d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_8BIT)
1315d0c221feSJean-Jacques Hiblot 		return 8;
1316d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_4BIT)
1317d0c221feSJean-Jacques Hiblot 		return 4;
1318d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_1BIT)
1319d0c221feSJean-Jacques Hiblot 		return 1;
1320d0c221feSJean-Jacques Hiblot 	printf("invalid bus witdh capability 0x%x\n", cap);
1321d0c221feSJean-Jacques Hiblot 	return 0;
1322d0c221feSJean-Jacques Hiblot }
1323d0c221feSJean-Jacques Hiblot 
1324e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
1325ec841209SKishon Vijay Abraham I static int mmc_execute_tuning(struct mmc *mmc, uint opcode)
1326ec841209SKishon Vijay Abraham I {
1327ec841209SKishon Vijay Abraham I 	return -ENOTSUPP;
1328ec841209SKishon Vijay Abraham I }
1329ec841209SKishon Vijay Abraham I 
1330318a7a57SJean-Jacques Hiblot static void mmc_send_init_stream(struct mmc *mmc)
1331318a7a57SJean-Jacques Hiblot {
1332318a7a57SJean-Jacques Hiblot }
1333318a7a57SJean-Jacques Hiblot 
13342a4d212fSKishon Vijay Abraham I static int mmc_set_ios(struct mmc *mmc)
1335272cc70bSAndy Fleming {
13362a4d212fSKishon Vijay Abraham I 	int ret = 0;
13372a4d212fSKishon Vijay Abraham I 
133893bfd616SPantelis Antoniou 	if (mmc->cfg->ops->set_ios)
13392a4d212fSKishon Vijay Abraham I 		ret = mmc->cfg->ops->set_ios(mmc);
13402a4d212fSKishon Vijay Abraham I 
13412a4d212fSKishon Vijay Abraham I 	return ret;
1342272cc70bSAndy Fleming }
13438ca51e51SSimon Glass #endif
1344272cc70bSAndy Fleming 
134535f67820SKishon Vijay Abraham I int mmc_set_clock(struct mmc *mmc, uint clock, bool disable)
1346272cc70bSAndy Fleming {
134793bfd616SPantelis Antoniou 	if (clock > mmc->cfg->f_max)
134893bfd616SPantelis Antoniou 		clock = mmc->cfg->f_max;
1349272cc70bSAndy Fleming 
135093bfd616SPantelis Antoniou 	if (clock < mmc->cfg->f_min)
135193bfd616SPantelis Antoniou 		clock = mmc->cfg->f_min;
1352272cc70bSAndy Fleming 
1353272cc70bSAndy Fleming 	mmc->clock = clock;
135435f67820SKishon Vijay Abraham I 	mmc->clk_disable = disable;
1355272cc70bSAndy Fleming 
13562a4d212fSKishon Vijay Abraham I 	return mmc_set_ios(mmc);
1357272cc70bSAndy Fleming }
1358272cc70bSAndy Fleming 
13592a4d212fSKishon Vijay Abraham I static int mmc_set_bus_width(struct mmc *mmc, uint width)
1360272cc70bSAndy Fleming {
1361272cc70bSAndy Fleming 	mmc->bus_width = width;
1362272cc70bSAndy Fleming 
13632a4d212fSKishon Vijay Abraham I 	return mmc_set_ios(mmc);
1364272cc70bSAndy Fleming }
1365272cc70bSAndy Fleming 
13664c9d2aaaSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG)
13674c9d2aaaSJean-Jacques Hiblot /*
13684c9d2aaaSJean-Jacques Hiblot  * helper function to display the capabilities in a human
13694c9d2aaaSJean-Jacques Hiblot  * friendly manner. The capabilities include bus width and
13704c9d2aaaSJean-Jacques Hiblot  * supported modes.
13714c9d2aaaSJean-Jacques Hiblot  */
13724c9d2aaaSJean-Jacques Hiblot void mmc_dump_capabilities(const char *text, uint caps)
13734c9d2aaaSJean-Jacques Hiblot {
13744c9d2aaaSJean-Jacques Hiblot 	enum bus_mode mode;
13754c9d2aaaSJean-Jacques Hiblot 
13764c9d2aaaSJean-Jacques Hiblot 	printf("%s: widths [", text);
13774c9d2aaaSJean-Jacques Hiblot 	if (caps & MMC_MODE_8BIT)
13784c9d2aaaSJean-Jacques Hiblot 		printf("8, ");
13794c9d2aaaSJean-Jacques Hiblot 	if (caps & MMC_MODE_4BIT)
13804c9d2aaaSJean-Jacques Hiblot 		printf("4, ");
1381d0c221feSJean-Jacques Hiblot 	if (caps & MMC_MODE_1BIT)
1382d0c221feSJean-Jacques Hiblot 		printf("1, ");
1383d0c221feSJean-Jacques Hiblot 	printf("\b\b] modes [");
13844c9d2aaaSJean-Jacques Hiblot 	for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++)
13854c9d2aaaSJean-Jacques Hiblot 		if (MMC_CAP(mode) & caps)
13864c9d2aaaSJean-Jacques Hiblot 			printf("%s, ", mmc_mode_name(mode));
13874c9d2aaaSJean-Jacques Hiblot 	printf("\b\b]\n");
13884c9d2aaaSJean-Jacques Hiblot }
13894c9d2aaaSJean-Jacques Hiblot #endif
13904c9d2aaaSJean-Jacques Hiblot 
1391d0c221feSJean-Jacques Hiblot struct mode_width_tuning {
1392d0c221feSJean-Jacques Hiblot 	enum bus_mode mode;
1393d0c221feSJean-Jacques Hiblot 	uint widths;
1394634d4849SKishon Vijay Abraham I 	uint tuning;
1395d0c221feSJean-Jacques Hiblot };
1396d0c221feSJean-Jacques Hiblot 
1397aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage)
1398aff5d3c8SKishon Vijay Abraham I {
1399aff5d3c8SKishon Vijay Abraham I 	mmc->signal_voltage = signal_voltage;
1400aff5d3c8SKishon Vijay Abraham I 	return mmc_set_ios(mmc);
1401aff5d3c8SKishon Vijay Abraham I }
1402aff5d3c8SKishon Vijay Abraham I 
1403d0c221feSJean-Jacques Hiblot static const struct mode_width_tuning sd_modes_by_pref[] = {
1404d0c221feSJean-Jacques Hiblot 	{
1405c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR104,
1406c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1407c10b85d6SJean-Jacques Hiblot 		.tuning = MMC_CMD_SEND_TUNING_BLOCK
1408c10b85d6SJean-Jacques Hiblot 	},
1409c10b85d6SJean-Jacques Hiblot 	{
1410c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR50,
1411c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1412c10b85d6SJean-Jacques Hiblot 	},
1413c10b85d6SJean-Jacques Hiblot 	{
1414c10b85d6SJean-Jacques Hiblot 		.mode = UHS_DDR50,
1415c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1416c10b85d6SJean-Jacques Hiblot 	},
1417c10b85d6SJean-Jacques Hiblot 	{
1418c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR25,
1419c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1420c10b85d6SJean-Jacques Hiblot 	},
1421c10b85d6SJean-Jacques Hiblot 	{
1422d0c221feSJean-Jacques Hiblot 		.mode = SD_HS,
1423d0c221feSJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1424d0c221feSJean-Jacques Hiblot 	},
1425d0c221feSJean-Jacques Hiblot 	{
1426c10b85d6SJean-Jacques Hiblot 		.mode = UHS_SDR12,
1427c10b85d6SJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1428c10b85d6SJean-Jacques Hiblot 	},
1429c10b85d6SJean-Jacques Hiblot 	{
1430d0c221feSJean-Jacques Hiblot 		.mode = SD_LEGACY,
1431d0c221feSJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1432d0c221feSJean-Jacques Hiblot 	}
1433d0c221feSJean-Jacques Hiblot };
1434d0c221feSJean-Jacques Hiblot 
1435d0c221feSJean-Jacques Hiblot #define for_each_sd_mode_by_pref(caps, mwt) \
1436d0c221feSJean-Jacques Hiblot 	for (mwt = sd_modes_by_pref;\
1437d0c221feSJean-Jacques Hiblot 	     mwt < sd_modes_by_pref + ARRAY_SIZE(sd_modes_by_pref);\
1438d0c221feSJean-Jacques Hiblot 	     mwt++) \
1439d0c221feSJean-Jacques Hiblot 		if (caps & MMC_CAP(mwt->mode))
1440d0c221feSJean-Jacques Hiblot 
1441d0c221feSJean-Jacques Hiblot static int sd_select_mode_and_width(struct mmc *mmc)
14428ac8a263SJean-Jacques Hiblot {
14438ac8a263SJean-Jacques Hiblot 	int err;
1444d0c221feSJean-Jacques Hiblot 	uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT};
1445d0c221feSJean-Jacques Hiblot 	const struct mode_width_tuning *mwt;
1446c10b85d6SJean-Jacques Hiblot 	bool uhs_en = (mmc->ocr & OCR_S18R) ? true : false;
1447c10b85d6SJean-Jacques Hiblot 	uint caps;
1448c10b85d6SJean-Jacques Hiblot 
14498ac8a263SJean-Jacques Hiblot 
1450d0c221feSJean-Jacques Hiblot 	err = sd_get_capabilities(mmc);
14518ac8a263SJean-Jacques Hiblot 	if (err)
14528ac8a263SJean-Jacques Hiblot 		return err;
14538ac8a263SJean-Jacques Hiblot 	/* Restrict card's capabilities by what the host can do */
1454*04a2ea24SJean-Jacques Hiblot 	caps = mmc->card_caps & (mmc->host_caps | MMC_MODE_1BIT);
14558ac8a263SJean-Jacques Hiblot 
1456c10b85d6SJean-Jacques Hiblot 	if (!uhs_en)
1457c10b85d6SJean-Jacques Hiblot 		caps &= ~UHS_CAPS;
1458c10b85d6SJean-Jacques Hiblot 
1459c10b85d6SJean-Jacques Hiblot 	for_each_sd_mode_by_pref(caps, mwt) {
1460d0c221feSJean-Jacques Hiblot 		uint *w;
14618ac8a263SJean-Jacques Hiblot 
1462d0c221feSJean-Jacques Hiblot 		for (w = widths; w < widths + ARRAY_SIZE(widths); w++) {
1463c10b85d6SJean-Jacques Hiblot 			if (*w & caps & mwt->widths) {
1464d0c221feSJean-Jacques Hiblot 				debug("trying mode %s width %d (at %d MHz)\n",
1465d0c221feSJean-Jacques Hiblot 				      mmc_mode_name(mwt->mode),
1466d0c221feSJean-Jacques Hiblot 				      bus_width(*w),
1467d0c221feSJean-Jacques Hiblot 				      mmc_mode2freq(mmc, mwt->mode) / 1000000);
1468d0c221feSJean-Jacques Hiblot 
1469d0c221feSJean-Jacques Hiblot 				/* configure the bus width (card + host) */
1470d0c221feSJean-Jacques Hiblot 				err = sd_select_bus_width(mmc, bus_width(*w));
14718ac8a263SJean-Jacques Hiblot 				if (err)
1472d0c221feSJean-Jacques Hiblot 					goto error;
1473d0c221feSJean-Jacques Hiblot 				mmc_set_bus_width(mmc, bus_width(*w));
14748ac8a263SJean-Jacques Hiblot 
1475d0c221feSJean-Jacques Hiblot 				/* configure the bus mode (card) */
1476d0c221feSJean-Jacques Hiblot 				err = sd_set_card_speed(mmc, mwt->mode);
14778ac8a263SJean-Jacques Hiblot 				if (err)
1478d0c221feSJean-Jacques Hiblot 					goto error;
14798ac8a263SJean-Jacques Hiblot 
1480d0c221feSJean-Jacques Hiblot 				/* configure the bus mode (host) */
1481d0c221feSJean-Jacques Hiblot 				mmc_select_mode(mmc, mwt->mode);
148235f67820SKishon Vijay Abraham I 				mmc_set_clock(mmc, mmc->tran_speed, false);
14838ac8a263SJean-Jacques Hiblot 
1484c10b85d6SJean-Jacques Hiblot 				/* execute tuning if needed */
1485c10b85d6SJean-Jacques Hiblot 				if (mwt->tuning && !mmc_host_is_spi(mmc)) {
1486c10b85d6SJean-Jacques Hiblot 					err = mmc_execute_tuning(mmc,
1487c10b85d6SJean-Jacques Hiblot 								 mwt->tuning);
1488c10b85d6SJean-Jacques Hiblot 					if (err) {
1489c10b85d6SJean-Jacques Hiblot 						debug("tuning failed\n");
1490c10b85d6SJean-Jacques Hiblot 						goto error;
1491c10b85d6SJean-Jacques Hiblot 					}
1492c10b85d6SJean-Jacques Hiblot 				}
1493c10b85d6SJean-Jacques Hiblot 
14948ac8a263SJean-Jacques Hiblot 				err = sd_read_ssr(mmc);
1495d0c221feSJean-Jacques Hiblot 				if (!err)
14968ac8a263SJean-Jacques Hiblot 					return 0;
1497d0c221feSJean-Jacques Hiblot 
1498d0c221feSJean-Jacques Hiblot 				printf("bad ssr\n");
1499d0c221feSJean-Jacques Hiblot 
1500d0c221feSJean-Jacques Hiblot error:
1501d0c221feSJean-Jacques Hiblot 				/* revert to a safer bus speed */
1502d0c221feSJean-Jacques Hiblot 				mmc_select_mode(mmc, SD_LEGACY);
150335f67820SKishon Vijay Abraham I 				mmc_set_clock(mmc, mmc->tran_speed, false);
1504d0c221feSJean-Jacques Hiblot 			}
1505d0c221feSJean-Jacques Hiblot 		}
1506d0c221feSJean-Jacques Hiblot 	}
1507d0c221feSJean-Jacques Hiblot 
1508d0c221feSJean-Jacques Hiblot 	printf("unable to select a mode\n");
1509d0c221feSJean-Jacques Hiblot 	return -ENOTSUPP;
15108ac8a263SJean-Jacques Hiblot }
15118ac8a263SJean-Jacques Hiblot 
15127382e691SJean-Jacques Hiblot /*
15137382e691SJean-Jacques Hiblot  * read the compare the part of ext csd that is constant.
15147382e691SJean-Jacques Hiblot  * This can be used to check that the transfer is working
15157382e691SJean-Jacques Hiblot  * as expected.
15167382e691SJean-Jacques Hiblot  */
15177382e691SJean-Jacques Hiblot static int mmc_read_and_compare_ext_csd(struct mmc *mmc)
15187382e691SJean-Jacques Hiblot {
15197382e691SJean-Jacques Hiblot 	int err;
15207382e691SJean-Jacques Hiblot 	const u8 *ext_csd = mmc->ext_csd;
15217382e691SJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
15227382e691SJean-Jacques Hiblot 
15237382e691SJean-Jacques Hiblot 	err = mmc_send_ext_csd(mmc, test_csd);
15247382e691SJean-Jacques Hiblot 	if (err)
15257382e691SJean-Jacques Hiblot 		return err;
15267382e691SJean-Jacques Hiblot 
15277382e691SJean-Jacques Hiblot 	/* Only compare read only fields */
15287382e691SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT]
15297382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_PARTITIONING_SUPPORT] &&
15307382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_HC_WP_GRP_SIZE]
15317382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_HC_WP_GRP_SIZE] &&
15327382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_REV]
15337382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_REV] &&
15347382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
15357382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] &&
15367382e691SJean-Jacques Hiblot 	    memcmp(&ext_csd[EXT_CSD_SEC_CNT],
15377382e691SJean-Jacques Hiblot 		   &test_csd[EXT_CSD_SEC_CNT], 4) == 0)
15387382e691SJean-Jacques Hiblot 		return 0;
15397382e691SJean-Jacques Hiblot 
15407382e691SJean-Jacques Hiblot 	return -EBADMSG;
15417382e691SJean-Jacques Hiblot }
15427382e691SJean-Jacques Hiblot 
15433862b854SJean-Jacques Hiblot static const struct mode_width_tuning mmc_modes_by_pref[] = {
15448ac8a263SJean-Jacques Hiblot 	{
15453862b854SJean-Jacques Hiblot 		.mode = MMC_HS_200,
15463862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
1547634d4849SKishon Vijay Abraham I 		.tuning = MMC_CMD_SEND_TUNING_BLOCK_HS200
15483862b854SJean-Jacques Hiblot 	},
15493862b854SJean-Jacques Hiblot 	{
15503862b854SJean-Jacques Hiblot 		.mode = MMC_DDR_52,
15513862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
15523862b854SJean-Jacques Hiblot 	},
15533862b854SJean-Jacques Hiblot 	{
15543862b854SJean-Jacques Hiblot 		.mode = MMC_HS_52,
15553862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
15563862b854SJean-Jacques Hiblot 	},
15573862b854SJean-Jacques Hiblot 	{
15583862b854SJean-Jacques Hiblot 		.mode = MMC_HS,
15593862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
15603862b854SJean-Jacques Hiblot 	},
15613862b854SJean-Jacques Hiblot 	{
15623862b854SJean-Jacques Hiblot 		.mode = MMC_LEGACY,
15633862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
15643862b854SJean-Jacques Hiblot 	}
15658ac8a263SJean-Jacques Hiblot };
15668ac8a263SJean-Jacques Hiblot 
15673862b854SJean-Jacques Hiblot #define for_each_mmc_mode_by_pref(caps, mwt) \
15683862b854SJean-Jacques Hiblot 	for (mwt = mmc_modes_by_pref;\
15693862b854SJean-Jacques Hiblot 	    mwt < mmc_modes_by_pref + ARRAY_SIZE(mmc_modes_by_pref);\
15703862b854SJean-Jacques Hiblot 	    mwt++) \
15713862b854SJean-Jacques Hiblot 		if (caps & MMC_CAP(mwt->mode))
15723862b854SJean-Jacques Hiblot 
15733862b854SJean-Jacques Hiblot static const struct ext_csd_bus_width {
15743862b854SJean-Jacques Hiblot 	uint cap;
15753862b854SJean-Jacques Hiblot 	bool is_ddr;
15763862b854SJean-Jacques Hiblot 	uint ext_csd_bits;
15773862b854SJean-Jacques Hiblot } ext_csd_bus_width[] = {
15783862b854SJean-Jacques Hiblot 	{MMC_MODE_8BIT, true, EXT_CSD_DDR_BUS_WIDTH_8},
15793862b854SJean-Jacques Hiblot 	{MMC_MODE_4BIT, true, EXT_CSD_DDR_BUS_WIDTH_4},
15803862b854SJean-Jacques Hiblot 	{MMC_MODE_8BIT, false, EXT_CSD_BUS_WIDTH_8},
15813862b854SJean-Jacques Hiblot 	{MMC_MODE_4BIT, false, EXT_CSD_BUS_WIDTH_4},
15823862b854SJean-Jacques Hiblot 	{MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1},
15833862b854SJean-Jacques Hiblot };
15843862b854SJean-Jacques Hiblot 
15853862b854SJean-Jacques Hiblot #define for_each_supported_width(caps, ddr, ecbv) \
15863862b854SJean-Jacques Hiblot 	for (ecbv = ext_csd_bus_width;\
15873862b854SJean-Jacques Hiblot 	    ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\
15883862b854SJean-Jacques Hiblot 	    ecbv++) \
15893862b854SJean-Jacques Hiblot 		if ((ddr == ecbv->is_ddr) && (caps & ecbv->cap))
15903862b854SJean-Jacques Hiblot 
15913862b854SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc)
15923862b854SJean-Jacques Hiblot {
15933862b854SJean-Jacques Hiblot 	int err;
15943862b854SJean-Jacques Hiblot 	const struct mode_width_tuning *mwt;
15953862b854SJean-Jacques Hiblot 	const struct ext_csd_bus_width *ecbw;
15963862b854SJean-Jacques Hiblot 
15973862b854SJean-Jacques Hiblot 	err = mmc_get_capabilities(mmc);
15988ac8a263SJean-Jacques Hiblot 	if (err)
15998ac8a263SJean-Jacques Hiblot 		return err;
16008ac8a263SJean-Jacques Hiblot 
16018ac8a263SJean-Jacques Hiblot 	/* Restrict card's capabilities by what the host can do */
1602*04a2ea24SJean-Jacques Hiblot 	mmc->card_caps &= (mmc->host_caps | MMC_MODE_1BIT);
16038ac8a263SJean-Jacques Hiblot 
16048ac8a263SJean-Jacques Hiblot 	/* Only version 4 of MMC supports wider bus widths */
16058ac8a263SJean-Jacques Hiblot 	if (mmc->version < MMC_VERSION_4)
16068ac8a263SJean-Jacques Hiblot 		return 0;
16078ac8a263SJean-Jacques Hiblot 
1608dfda9d88SJean-Jacques Hiblot 	if (!mmc->ext_csd) {
1609dfda9d88SJean-Jacques Hiblot 		debug("No ext_csd found!\n"); /* this should enver happen */
1610dfda9d88SJean-Jacques Hiblot 		return -ENOTSUPP;
1611dfda9d88SJean-Jacques Hiblot 	}
1612dfda9d88SJean-Jacques Hiblot 
16133862b854SJean-Jacques Hiblot 	for_each_mmc_mode_by_pref(mmc->card_caps, mwt) {
16143862b854SJean-Jacques Hiblot 		for_each_supported_width(mmc->card_caps & mwt->widths,
16153862b854SJean-Jacques Hiblot 					 mmc_is_mode_ddr(mwt->mode), ecbw) {
16163862b854SJean-Jacques Hiblot 			debug("trying mode %s width %d (at %d MHz)\n",
16173862b854SJean-Jacques Hiblot 			      mmc_mode_name(mwt->mode),
16183862b854SJean-Jacques Hiblot 			      bus_width(ecbw->cap),
16193862b854SJean-Jacques Hiblot 			      mmc_mode2freq(mmc, mwt->mode) / 1000000);
16203862b854SJean-Jacques Hiblot 			/* configure the bus width (card + host) */
16213862b854SJean-Jacques Hiblot 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
16223862b854SJean-Jacques Hiblot 				    EXT_CSD_BUS_WIDTH,
16233862b854SJean-Jacques Hiblot 				    ecbw->ext_csd_bits & ~EXT_CSD_DDR_FLAG);
16243862b854SJean-Jacques Hiblot 			if (err)
16253862b854SJean-Jacques Hiblot 				goto error;
16263862b854SJean-Jacques Hiblot 			mmc_set_bus_width(mmc, bus_width(ecbw->cap));
16273862b854SJean-Jacques Hiblot 
16283862b854SJean-Jacques Hiblot 			/* configure the bus speed (card) */
16293862b854SJean-Jacques Hiblot 			err = mmc_set_card_speed(mmc, mwt->mode);
16303862b854SJean-Jacques Hiblot 			if (err)
16313862b854SJean-Jacques Hiblot 				goto error;
16323862b854SJean-Jacques Hiblot 
16338ac8a263SJean-Jacques Hiblot 			/*
16343862b854SJean-Jacques Hiblot 			 * configure the bus width AND the ddr mode (card)
16353862b854SJean-Jacques Hiblot 			 * The host side will be taken care of in the next step
16368ac8a263SJean-Jacques Hiblot 			 */
16373862b854SJean-Jacques Hiblot 			if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) {
16383862b854SJean-Jacques Hiblot 				err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
16393862b854SJean-Jacques Hiblot 						 EXT_CSD_BUS_WIDTH,
16403862b854SJean-Jacques Hiblot 						 ecbw->ext_csd_bits);
16413862b854SJean-Jacques Hiblot 				if (err)
16423862b854SJean-Jacques Hiblot 					goto error;
16438ac8a263SJean-Jacques Hiblot 			}
16448ac8a263SJean-Jacques Hiblot 
16453862b854SJean-Jacques Hiblot 			/* configure the bus mode (host) */
16463862b854SJean-Jacques Hiblot 			mmc_select_mode(mmc, mwt->mode);
164735f67820SKishon Vijay Abraham I 			mmc_set_clock(mmc, mmc->tran_speed, false);
16488ac8a263SJean-Jacques Hiblot 
1649634d4849SKishon Vijay Abraham I 			/* execute tuning if needed */
1650634d4849SKishon Vijay Abraham I 			if (mwt->tuning) {
1651634d4849SKishon Vijay Abraham I 				err = mmc_execute_tuning(mmc, mwt->tuning);
1652634d4849SKishon Vijay Abraham I 				if (err) {
1653634d4849SKishon Vijay Abraham I 					debug("tuning failed\n");
1654634d4849SKishon Vijay Abraham I 					goto error;
1655634d4849SKishon Vijay Abraham I 				}
1656634d4849SKishon Vijay Abraham I 			}
1657634d4849SKishon Vijay Abraham I 
16583862b854SJean-Jacques Hiblot 			/* do a transfer to check the configuration */
16597382e691SJean-Jacques Hiblot 			err = mmc_read_and_compare_ext_csd(mmc);
16607382e691SJean-Jacques Hiblot 			if (!err)
16613862b854SJean-Jacques Hiblot 				return 0;
16623862b854SJean-Jacques Hiblot error:
16633862b854SJean-Jacques Hiblot 			/* if an error occured, revert to a safer bus mode */
16643862b854SJean-Jacques Hiblot 			mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
16653862b854SJean-Jacques Hiblot 				   EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1);
16663862b854SJean-Jacques Hiblot 			mmc_select_mode(mmc, MMC_LEGACY);
16673862b854SJean-Jacques Hiblot 			mmc_set_bus_width(mmc, 1);
16683862b854SJean-Jacques Hiblot 		}
16698ac8a263SJean-Jacques Hiblot 	}
16708ac8a263SJean-Jacques Hiblot 
16713862b854SJean-Jacques Hiblot 	printf("unable to select a mode\n");
16728ac8a263SJean-Jacques Hiblot 
16733862b854SJean-Jacques Hiblot 	return -ENOTSUPP;
16748ac8a263SJean-Jacques Hiblot }
16758ac8a263SJean-Jacques Hiblot 
1676dfda9d88SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc)
1677c744b6f6SJean-Jacques Hiblot {
1678c744b6f6SJean-Jacques Hiblot 	int err, i;
1679c744b6f6SJean-Jacques Hiblot 	u64 capacity;
1680c744b6f6SJean-Jacques Hiblot 	bool has_parts = false;
1681c744b6f6SJean-Jacques Hiblot 	bool part_completed;
1682dfda9d88SJean-Jacques Hiblot 	u8 *ext_csd;
1683c744b6f6SJean-Jacques Hiblot 
1684c744b6f6SJean-Jacques Hiblot 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4))
1685c744b6f6SJean-Jacques Hiblot 		return 0;
1686c744b6f6SJean-Jacques Hiblot 
1687dfda9d88SJean-Jacques Hiblot 	ext_csd = malloc_cache_aligned(MMC_MAX_BLOCK_LEN);
1688dfda9d88SJean-Jacques Hiblot 	if (!ext_csd)
1689dfda9d88SJean-Jacques Hiblot 		return -ENOMEM;
1690dfda9d88SJean-Jacques Hiblot 
1691dfda9d88SJean-Jacques Hiblot 	mmc->ext_csd = ext_csd;
1692dfda9d88SJean-Jacques Hiblot 
1693c744b6f6SJean-Jacques Hiblot 	/* check  ext_csd version and capacity */
1694c744b6f6SJean-Jacques Hiblot 	err = mmc_send_ext_csd(mmc, ext_csd);
1695c744b6f6SJean-Jacques Hiblot 	if (err)
1696c744b6f6SJean-Jacques Hiblot 		return err;
1697c744b6f6SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_REV] >= 2) {
1698c744b6f6SJean-Jacques Hiblot 		/*
1699c744b6f6SJean-Jacques Hiblot 		 * According to the JEDEC Standard, the value of
1700c744b6f6SJean-Jacques Hiblot 		 * ext_csd's capacity is valid if the value is more
1701c744b6f6SJean-Jacques Hiblot 		 * than 2GB
1702c744b6f6SJean-Jacques Hiblot 		 */
1703c744b6f6SJean-Jacques Hiblot 		capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
1704c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
1705c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
1706c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
1707c744b6f6SJean-Jacques Hiblot 		capacity *= MMC_MAX_BLOCK_LEN;
1708c744b6f6SJean-Jacques Hiblot 		if ((capacity >> 20) > 2 * 1024)
1709c744b6f6SJean-Jacques Hiblot 			mmc->capacity_user = capacity;
1710c744b6f6SJean-Jacques Hiblot 	}
1711c744b6f6SJean-Jacques Hiblot 
1712c744b6f6SJean-Jacques Hiblot 	switch (ext_csd[EXT_CSD_REV]) {
1713c744b6f6SJean-Jacques Hiblot 	case 1:
1714c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_1;
1715c744b6f6SJean-Jacques Hiblot 		break;
1716c744b6f6SJean-Jacques Hiblot 	case 2:
1717c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_2;
1718c744b6f6SJean-Jacques Hiblot 		break;
1719c744b6f6SJean-Jacques Hiblot 	case 3:
1720c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_3;
1721c744b6f6SJean-Jacques Hiblot 		break;
1722c744b6f6SJean-Jacques Hiblot 	case 5:
1723c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_41;
1724c744b6f6SJean-Jacques Hiblot 		break;
1725c744b6f6SJean-Jacques Hiblot 	case 6:
1726c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_5;
1727c744b6f6SJean-Jacques Hiblot 		break;
1728c744b6f6SJean-Jacques Hiblot 	case 7:
1729c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_5_0;
1730c744b6f6SJean-Jacques Hiblot 		break;
1731c744b6f6SJean-Jacques Hiblot 	case 8:
1732c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_5_1;
1733c744b6f6SJean-Jacques Hiblot 		break;
1734c744b6f6SJean-Jacques Hiblot 	}
1735c744b6f6SJean-Jacques Hiblot 
1736c744b6f6SJean-Jacques Hiblot 	/* The partition data may be non-zero but it is only
1737c744b6f6SJean-Jacques Hiblot 	 * effective if PARTITION_SETTING_COMPLETED is set in
1738c744b6f6SJean-Jacques Hiblot 	 * EXT_CSD, so ignore any data if this bit is not set,
1739c744b6f6SJean-Jacques Hiblot 	 * except for enabling the high-capacity group size
1740c744b6f6SJean-Jacques Hiblot 	 * definition (see below).
1741c744b6f6SJean-Jacques Hiblot 	 */
1742c744b6f6SJean-Jacques Hiblot 	part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
1743c744b6f6SJean-Jacques Hiblot 			    EXT_CSD_PARTITION_SETTING_COMPLETED);
1744c744b6f6SJean-Jacques Hiblot 
1745c744b6f6SJean-Jacques Hiblot 	/* store the partition info of emmc */
1746c744b6f6SJean-Jacques Hiblot 	mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
1747c744b6f6SJean-Jacques Hiblot 	if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
1748c744b6f6SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_BOOT_MULT])
1749c744b6f6SJean-Jacques Hiblot 		mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
1750c744b6f6SJean-Jacques Hiblot 	if (part_completed &&
1751c744b6f6SJean-Jacques Hiblot 	    (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
1752c744b6f6SJean-Jacques Hiblot 		mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
1753c744b6f6SJean-Jacques Hiblot 
1754c744b6f6SJean-Jacques Hiblot 	mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
1755c744b6f6SJean-Jacques Hiblot 
1756c744b6f6SJean-Jacques Hiblot 	mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
1757c744b6f6SJean-Jacques Hiblot 
1758c744b6f6SJean-Jacques Hiblot 	for (i = 0; i < 4; i++) {
1759c744b6f6SJean-Jacques Hiblot 		int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
1760c744b6f6SJean-Jacques Hiblot 		uint mult = (ext_csd[idx + 2] << 16) +
1761c744b6f6SJean-Jacques Hiblot 			(ext_csd[idx + 1] << 8) + ext_csd[idx];
1762c744b6f6SJean-Jacques Hiblot 		if (mult)
1763c744b6f6SJean-Jacques Hiblot 			has_parts = true;
1764c744b6f6SJean-Jacques Hiblot 		if (!part_completed)
1765c744b6f6SJean-Jacques Hiblot 			continue;
1766c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] = mult;
1767c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] *=
1768c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1769c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1770c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] <<= 19;
1771c744b6f6SJean-Jacques Hiblot 	}
1772c744b6f6SJean-Jacques Hiblot 
1773c744b6f6SJean-Jacques Hiblot 	if (part_completed) {
1774c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size =
1775c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) +
1776c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) +
1777c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_ENH_SIZE_MULT];
1778c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1779c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1780c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size <<= 19;
1781c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_start =
1782c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) +
1783c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) +
1784c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) +
1785c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_ENH_START_ADDR];
1786c744b6f6SJean-Jacques Hiblot 		if (mmc->high_capacity)
1787c744b6f6SJean-Jacques Hiblot 			mmc->enh_user_start <<= 9;
1788c744b6f6SJean-Jacques Hiblot 	}
1789c744b6f6SJean-Jacques Hiblot 
1790c744b6f6SJean-Jacques Hiblot 	/*
1791c744b6f6SJean-Jacques Hiblot 	 * Host needs to enable ERASE_GRP_DEF bit if device is
1792c744b6f6SJean-Jacques Hiblot 	 * partitioned. This bit will be lost every time after a reset
1793c744b6f6SJean-Jacques Hiblot 	 * or power off. This will affect erase size.
1794c744b6f6SJean-Jacques Hiblot 	 */
1795c744b6f6SJean-Jacques Hiblot 	if (part_completed)
1796c744b6f6SJean-Jacques Hiblot 		has_parts = true;
1797c744b6f6SJean-Jacques Hiblot 	if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
1798c744b6f6SJean-Jacques Hiblot 	    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
1799c744b6f6SJean-Jacques Hiblot 		has_parts = true;
1800c744b6f6SJean-Jacques Hiblot 	if (has_parts) {
1801c744b6f6SJean-Jacques Hiblot 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1802c744b6f6SJean-Jacques Hiblot 				 EXT_CSD_ERASE_GROUP_DEF, 1);
1803c744b6f6SJean-Jacques Hiblot 
1804c744b6f6SJean-Jacques Hiblot 		if (err)
1805c744b6f6SJean-Jacques Hiblot 			return err;
1806c744b6f6SJean-Jacques Hiblot 
1807c744b6f6SJean-Jacques Hiblot 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1808c744b6f6SJean-Jacques Hiblot 	}
1809c744b6f6SJean-Jacques Hiblot 
1810c744b6f6SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
1811c744b6f6SJean-Jacques Hiblot 		/* Read out group size from ext_csd */
1812c744b6f6SJean-Jacques Hiblot 		mmc->erase_grp_size =
1813c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1814c744b6f6SJean-Jacques Hiblot 		/*
1815c744b6f6SJean-Jacques Hiblot 		 * if high capacity and partition setting completed
1816c744b6f6SJean-Jacques Hiblot 		 * SEC_COUNT is valid even if it is smaller than 2 GiB
1817c744b6f6SJean-Jacques Hiblot 		 * JEDEC Standard JESD84-B45, 6.2.4
1818c744b6f6SJean-Jacques Hiblot 		 */
1819c744b6f6SJean-Jacques Hiblot 		if (mmc->high_capacity && part_completed) {
1820c744b6f6SJean-Jacques Hiblot 			capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
1821c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
1822c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
1823c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
1824c744b6f6SJean-Jacques Hiblot 			capacity *= MMC_MAX_BLOCK_LEN;
1825c744b6f6SJean-Jacques Hiblot 			mmc->capacity_user = capacity;
1826c744b6f6SJean-Jacques Hiblot 		}
1827c744b6f6SJean-Jacques Hiblot 	} else {
1828c744b6f6SJean-Jacques Hiblot 		/* Calculate the group size from the csd value. */
1829c744b6f6SJean-Jacques Hiblot 		int erase_gsz, erase_gmul;
1830c744b6f6SJean-Jacques Hiblot 
1831c744b6f6SJean-Jacques Hiblot 		erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
1832c744b6f6SJean-Jacques Hiblot 		erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
1833c744b6f6SJean-Jacques Hiblot 		mmc->erase_grp_size = (erase_gsz + 1)
1834c744b6f6SJean-Jacques Hiblot 			* (erase_gmul + 1);
1835c744b6f6SJean-Jacques Hiblot 	}
1836c744b6f6SJean-Jacques Hiblot 
1837c744b6f6SJean-Jacques Hiblot 	mmc->hc_wp_grp_size = 1024
1838c744b6f6SJean-Jacques Hiblot 		* ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
1839c744b6f6SJean-Jacques Hiblot 		* ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1840c744b6f6SJean-Jacques Hiblot 
1841c744b6f6SJean-Jacques Hiblot 	mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
1842c744b6f6SJean-Jacques Hiblot 
1843c744b6f6SJean-Jacques Hiblot 	return 0;
1844c744b6f6SJean-Jacques Hiblot }
1845c744b6f6SJean-Jacques Hiblot 
1846fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc)
1847272cc70bSAndy Fleming {
1848f866a46dSStephen Warren 	int err, i;
1849272cc70bSAndy Fleming 	uint mult, freq;
1850c744b6f6SJean-Jacques Hiblot 	u64 cmult, csize;
1851272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1852c40fdca6SSimon Glass 	struct blk_desc *bdesc;
1853272cc70bSAndy Fleming 
1854d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
1855d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
1856d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
1857d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
1858d52ebf10SThomas Chou 		cmd.cmdarg = 1;
1859d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
1860d52ebf10SThomas Chou 
1861d52ebf10SThomas Chou 		if (err)
1862d52ebf10SThomas Chou 			return err;
1863d52ebf10SThomas Chou 	}
1864d52ebf10SThomas Chou #endif
1865d52ebf10SThomas Chou 
1866272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
1867d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
1868d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
1869272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1870272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1871272cc70bSAndy Fleming 
1872272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1873272cc70bSAndy Fleming 
1874272cc70bSAndy Fleming 	if (err)
1875272cc70bSAndy Fleming 		return err;
1876272cc70bSAndy Fleming 
1877272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
1878272cc70bSAndy Fleming 
1879272cc70bSAndy Fleming 	/*
1880272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
1881272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
1882272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
1883272cc70bSAndy Fleming 	 */
1884d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1885272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
1886272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1887272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
1888272cc70bSAndy Fleming 
1889272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1890272cc70bSAndy Fleming 
1891272cc70bSAndy Fleming 		if (err)
1892272cc70bSAndy Fleming 			return err;
1893272cc70bSAndy Fleming 
1894272cc70bSAndy Fleming 		if (IS_SD(mmc))
1895998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
1896d52ebf10SThomas Chou 	}
1897272cc70bSAndy Fleming 
1898272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
1899272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
1900272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1901272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1902272cc70bSAndy Fleming 
1903272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1904272cc70bSAndy Fleming 
1905272cc70bSAndy Fleming 	if (err)
1906272cc70bSAndy Fleming 		return err;
1907272cc70bSAndy Fleming 
1908998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
1909998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
1910998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
1911998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
1912272cc70bSAndy Fleming 
1913272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
19140b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
1915272cc70bSAndy Fleming 
1916272cc70bSAndy Fleming 		switch (version) {
1917272cc70bSAndy Fleming 		case 0:
1918272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1919272cc70bSAndy Fleming 			break;
1920272cc70bSAndy Fleming 		case 1:
1921272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_4;
1922272cc70bSAndy Fleming 			break;
1923272cc70bSAndy Fleming 		case 2:
1924272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_2_2;
1925272cc70bSAndy Fleming 			break;
1926272cc70bSAndy Fleming 		case 3:
1927272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_3;
1928272cc70bSAndy Fleming 			break;
1929272cc70bSAndy Fleming 		case 4:
1930272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_4;
1931272cc70bSAndy Fleming 			break;
1932272cc70bSAndy Fleming 		default:
1933272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1934272cc70bSAndy Fleming 			break;
1935272cc70bSAndy Fleming 		}
1936272cc70bSAndy Fleming 	}
1937272cc70bSAndy Fleming 
1938272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
19390b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
19400b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
1941272cc70bSAndy Fleming 
194235f9e196SJean-Jacques Hiblot 	mmc->legacy_speed = freq * mult;
194335f9e196SJean-Jacques Hiblot 	mmc_select_mode(mmc, MMC_LEGACY);
1944272cc70bSAndy Fleming 
1945ab71188cSMarkus Niebel 	mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
1946998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
1947272cc70bSAndy Fleming 
1948272cc70bSAndy Fleming 	if (IS_SD(mmc))
1949272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
1950272cc70bSAndy Fleming 	else
1951998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
1952272cc70bSAndy Fleming 
1953272cc70bSAndy Fleming 	if (mmc->high_capacity) {
1954272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
1955272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
1956272cc70bSAndy Fleming 		cmult = 8;
1957272cc70bSAndy Fleming 	} else {
1958272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
1959272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
1960272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
1961272cc70bSAndy Fleming 	}
1962272cc70bSAndy Fleming 
1963f866a46dSStephen Warren 	mmc->capacity_user = (csize + 1) << (cmult + 2);
1964f866a46dSStephen Warren 	mmc->capacity_user *= mmc->read_bl_len;
1965f866a46dSStephen Warren 	mmc->capacity_boot = 0;
1966f866a46dSStephen Warren 	mmc->capacity_rpmb = 0;
1967f866a46dSStephen Warren 	for (i = 0; i < 4; i++)
1968f866a46dSStephen Warren 		mmc->capacity_gp[i] = 0;
1969272cc70bSAndy Fleming 
19708bfa195eSSimon Glass 	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
19718bfa195eSSimon Glass 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
1972272cc70bSAndy Fleming 
19738bfa195eSSimon Glass 	if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
19748bfa195eSSimon Glass 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
1975272cc70bSAndy Fleming 
1976ab71188cSMarkus Niebel 	if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
1977ab71188cSMarkus Niebel 		cmd.cmdidx = MMC_CMD_SET_DSR;
1978ab71188cSMarkus Niebel 		cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
1979ab71188cSMarkus Niebel 		cmd.resp_type = MMC_RSP_NONE;
1980ab71188cSMarkus Niebel 		if (mmc_send_cmd(mmc, &cmd, NULL))
1981ab71188cSMarkus Niebel 			printf("MMC: SET_DSR failed\n");
1982ab71188cSMarkus Niebel 	}
1983ab71188cSMarkus Niebel 
1984272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
1985d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1986272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
1987fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
1988272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1989272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1990272cc70bSAndy Fleming 
1991272cc70bSAndy Fleming 		if (err)
1992272cc70bSAndy Fleming 			return err;
1993d52ebf10SThomas Chou 	}
1994272cc70bSAndy Fleming 
1995e6f99a56SLei Wen 	/*
1996e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
1997e6f99a56SLei Wen 	 */
1998e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
1999bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
2000c744b6f6SJean-Jacques Hiblot 
2001dfda9d88SJean-Jacques Hiblot 	err = mmc_startup_v4(mmc);
20029cf199ebSDiego Santa Cruz 	if (err)
20039cf199ebSDiego Santa Cruz 		return err;
2004f866a46dSStephen Warren 
2005c40fdca6SSimon Glass 	err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart);
2006f866a46dSStephen Warren 	if (err)
2007f866a46dSStephen Warren 		return err;
2008d23e2c09SSukumar Ghorai 
2009272cc70bSAndy Fleming 	if (IS_SD(mmc))
2010d0c221feSJean-Jacques Hiblot 		err = sd_select_mode_and_width(mmc);
2011272cc70bSAndy Fleming 	else
20123862b854SJean-Jacques Hiblot 		err = mmc_select_mode_and_width(mmc);
2013272cc70bSAndy Fleming 
2014272cc70bSAndy Fleming 	if (err)
2015272cc70bSAndy Fleming 		return err;
2016272cc70bSAndy Fleming 
2017272cc70bSAndy Fleming 
20185af8f45cSAndrew Gabbasov 	/* Fix the block length for DDR mode */
20195af8f45cSAndrew Gabbasov 	if (mmc->ddr_mode) {
20205af8f45cSAndrew Gabbasov 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
20215af8f45cSAndrew Gabbasov 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
20225af8f45cSAndrew Gabbasov 	}
20235af8f45cSAndrew Gabbasov 
2024272cc70bSAndy Fleming 	/* fill in device description */
2025c40fdca6SSimon Glass 	bdesc = mmc_get_blk_desc(mmc);
2026c40fdca6SSimon Glass 	bdesc->lun = 0;
2027c40fdca6SSimon Glass 	bdesc->hwpart = 0;
2028c40fdca6SSimon Glass 	bdesc->type = 0;
2029c40fdca6SSimon Glass 	bdesc->blksz = mmc->read_bl_len;
2030c40fdca6SSimon Glass 	bdesc->log2blksz = LOG2(bdesc->blksz);
2031c40fdca6SSimon Glass 	bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len);
2032fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \
2033fc011f64SSjoerd Simons 		(defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \
2034fc011f64SSjoerd Simons 		!defined(CONFIG_USE_TINY_PRINTF))
2035c40fdca6SSimon Glass 	sprintf(bdesc->vendor, "Man %06x Snr %04x%04x",
2036babce5f6STaylor Hutt 		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
2037babce5f6STaylor Hutt 		(mmc->cid[3] >> 16) & 0xffff);
2038c40fdca6SSimon Glass 	sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
20390b453ffeSRabin Vincent 		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
2040babce5f6STaylor Hutt 		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
2041babce5f6STaylor Hutt 		(mmc->cid[2] >> 24) & 0xff);
2042c40fdca6SSimon Glass 	sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
2043babce5f6STaylor Hutt 		(mmc->cid[2] >> 16) & 0xf);
204456196826SPaul Burton #else
2045c40fdca6SSimon Glass 	bdesc->vendor[0] = 0;
2046c40fdca6SSimon Glass 	bdesc->product[0] = 0;
2047c40fdca6SSimon Glass 	bdesc->revision[0] = 0;
204856196826SPaul Burton #endif
2049122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
2050c40fdca6SSimon Glass 	part_init(bdesc);
2051122efd43SMikhail Kshevetskiy #endif
2052272cc70bSAndy Fleming 
2053272cc70bSAndy Fleming 	return 0;
2054272cc70bSAndy Fleming }
2055272cc70bSAndy Fleming 
2056fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc)
2057272cc70bSAndy Fleming {
2058272cc70bSAndy Fleming 	struct mmc_cmd cmd;
2059272cc70bSAndy Fleming 	int err;
2060272cc70bSAndy Fleming 
2061272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
2062272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
206393bfd616SPantelis Antoniou 	cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa;
2064272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
2065272cc70bSAndy Fleming 
2066272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
2067272cc70bSAndy Fleming 
2068272cc70bSAndy Fleming 	if (err)
2069272cc70bSAndy Fleming 		return err;
2070272cc70bSAndy Fleming 
2071998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
2072915ffa52SJaehoon Chung 		return -EOPNOTSUPP;
2073272cc70bSAndy Fleming 	else
2074272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
2075272cc70bSAndy Fleming 
2076272cc70bSAndy Fleming 	return 0;
2077272cc70bSAndy Fleming }
2078272cc70bSAndy Fleming 
2079c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
208095de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */
208195de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void)
208295de9ab2SPaul Kocialkowski {
208395de9ab2SPaul Kocialkowski }
208405cbeb7cSSimon Glass #endif
208595de9ab2SPaul Kocialkowski 
20862051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc)
20872051aefeSPeng Fan {
2088c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
208906ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR)
20902051aefeSPeng Fan 	int ret;
20912051aefeSPeng Fan 
20922051aefeSPeng Fan 	ret = device_get_supply_regulator(mmc->dev, "vmmc-supply",
209306ec045fSJean-Jacques Hiblot 					  &mmc->vmmc_supply);
209406ec045fSJean-Jacques Hiblot 	if (ret)
2095288db7c7SJaehoon Chung 		debug("%s: No vmmc supply\n", mmc->dev->name);
20962051aefeSPeng Fan 
209706ec045fSJean-Jacques Hiblot 	ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply",
209806ec045fSJean-Jacques Hiblot 					  &mmc->vqmmc_supply);
209906ec045fSJean-Jacques Hiblot 	if (ret)
210006ec045fSJean-Jacques Hiblot 		debug("%s: No vqmmc supply\n", mmc->dev->name);
21012051aefeSPeng Fan #endif
210205cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */
210305cbeb7cSSimon Glass 	/*
210405cbeb7cSSimon Glass 	 * Driver model should use a regulator, as above, rather than calling
210505cbeb7cSSimon Glass 	 * out to board code.
210605cbeb7cSSimon Glass 	 */
210705cbeb7cSSimon Glass 	board_mmc_power_init();
210805cbeb7cSSimon Glass #endif
21092051aefeSPeng Fan 	return 0;
21102051aefeSPeng Fan }
21112051aefeSPeng Fan 
2112fb7c3bebSKishon Vijay Abraham I /*
2113fb7c3bebSKishon Vijay Abraham I  * put the host in the initial state:
2114fb7c3bebSKishon Vijay Abraham I  * - turn on Vdd (card power supply)
2115fb7c3bebSKishon Vijay Abraham I  * - configure the bus width and clock to minimal values
2116fb7c3bebSKishon Vijay Abraham I  */
2117fb7c3bebSKishon Vijay Abraham I static void mmc_set_initial_state(struct mmc *mmc)
2118fb7c3bebSKishon Vijay Abraham I {
2119fb7c3bebSKishon Vijay Abraham I 	int err;
2120fb7c3bebSKishon Vijay Abraham I 
2121fb7c3bebSKishon Vijay Abraham I 	/* First try to set 3.3V. If it fails set to 1.8V */
2122fb7c3bebSKishon Vijay Abraham I 	err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_330);
2123fb7c3bebSKishon Vijay Abraham I 	if (err != 0)
2124fb7c3bebSKishon Vijay Abraham I 		err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_180);
2125fb7c3bebSKishon Vijay Abraham I 	if (err != 0)
2126fb7c3bebSKishon Vijay Abraham I 		printf("mmc: failed to set signal voltage\n");
2127fb7c3bebSKishon Vijay Abraham I 
2128fb7c3bebSKishon Vijay Abraham I 	mmc_select_mode(mmc, MMC_LEGACY);
2129fb7c3bebSKishon Vijay Abraham I 	mmc_set_bus_width(mmc, 1);
213035f67820SKishon Vijay Abraham I 	mmc_set_clock(mmc, 0, false);
2131fb7c3bebSKishon Vijay Abraham I }
2132fb7c3bebSKishon Vijay Abraham I 
2133fb7c3bebSKishon Vijay Abraham I static int mmc_power_on(struct mmc *mmc)
2134fb7c3bebSKishon Vijay Abraham I {
2135fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR)
2136fb7c3bebSKishon Vijay Abraham I 	if (mmc->vmmc_supply) {
2137fb7c3bebSKishon Vijay Abraham I 		int ret = regulator_set_enable(mmc->vmmc_supply, true);
2138fb7c3bebSKishon Vijay Abraham I 
2139fb7c3bebSKishon Vijay Abraham I 		if (ret) {
2140fb7c3bebSKishon Vijay Abraham I 			puts("Error enabling VMMC supply\n");
2141fb7c3bebSKishon Vijay Abraham I 			return ret;
2142fb7c3bebSKishon Vijay Abraham I 		}
2143fb7c3bebSKishon Vijay Abraham I 	}
2144fb7c3bebSKishon Vijay Abraham I #endif
2145fb7c3bebSKishon Vijay Abraham I 	return 0;
2146fb7c3bebSKishon Vijay Abraham I }
2147fb7c3bebSKishon Vijay Abraham I 
2148fb7c3bebSKishon Vijay Abraham I static int mmc_power_off(struct mmc *mmc)
2149fb7c3bebSKishon Vijay Abraham I {
21502e7410d7SKishon Vijay Abraham I 	mmc_set_clock(mmc, 1, true);
2151fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR)
2152fb7c3bebSKishon Vijay Abraham I 	if (mmc->vmmc_supply) {
2153fb7c3bebSKishon Vijay Abraham I 		int ret = regulator_set_enable(mmc->vmmc_supply, false);
2154fb7c3bebSKishon Vijay Abraham I 
2155fb7c3bebSKishon Vijay Abraham I 		if (ret) {
2156c10b85d6SJean-Jacques Hiblot 			debug("Error disabling VMMC supply\n");
2157fb7c3bebSKishon Vijay Abraham I 			return ret;
2158fb7c3bebSKishon Vijay Abraham I 		}
2159fb7c3bebSKishon Vijay Abraham I 	}
2160fb7c3bebSKishon Vijay Abraham I #endif
2161fb7c3bebSKishon Vijay Abraham I 	return 0;
2162fb7c3bebSKishon Vijay Abraham I }
2163fb7c3bebSKishon Vijay Abraham I 
2164fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc)
2165fb7c3bebSKishon Vijay Abraham I {
2166fb7c3bebSKishon Vijay Abraham I 	int ret;
2167fb7c3bebSKishon Vijay Abraham I 
2168fb7c3bebSKishon Vijay Abraham I 	ret = mmc_power_off(mmc);
2169fb7c3bebSKishon Vijay Abraham I 	if (ret)
2170fb7c3bebSKishon Vijay Abraham I 		return ret;
2171fb7c3bebSKishon Vijay Abraham I 	/*
2172fb7c3bebSKishon Vijay Abraham I 	 * SD spec recommends at least 1ms of delay. Let's wait for 2ms
2173fb7c3bebSKishon Vijay Abraham I 	 * to be on the safer side.
2174fb7c3bebSKishon Vijay Abraham I 	 */
2175fb7c3bebSKishon Vijay Abraham I 	udelay(2000);
2176fb7c3bebSKishon Vijay Abraham I 	return mmc_power_on(mmc);
2177fb7c3bebSKishon Vijay Abraham I }
2178fb7c3bebSKishon Vijay Abraham I 
2179e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc)
2180272cc70bSAndy Fleming {
21818ca51e51SSimon Glass 	bool no_card;
2182c10b85d6SJean-Jacques Hiblot 	bool uhs_en = supports_uhs(mmc->cfg->host_caps);
2183afd5932bSMacpaul Lin 	int err;
2184272cc70bSAndy Fleming 
2185*04a2ea24SJean-Jacques Hiblot 	mmc->host_caps = mmc->cfg->host_caps;
2186*04a2ea24SJean-Jacques Hiblot 
2187ab769f22SPantelis Antoniou 	/* we pretend there's no card when init is NULL */
21888ca51e51SSimon Glass 	no_card = mmc_getcd(mmc) == 0;
2189e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
21908ca51e51SSimon Glass 	no_card = no_card || (mmc->cfg->ops->init == NULL);
21918ca51e51SSimon Glass #endif
21928ca51e51SSimon Glass 	if (no_card) {
219348972d90SThierry Reding 		mmc->has_init = 0;
219456196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
219548972d90SThierry Reding 		printf("MMC: no card present\n");
219656196826SPaul Burton #endif
2197915ffa52SJaehoon Chung 		return -ENOMEDIUM;
219848972d90SThierry Reding 	}
219948972d90SThierry Reding 
2200bc897b1dSLei Wen 	if (mmc->has_init)
2201bc897b1dSLei Wen 		return 0;
2202bc897b1dSLei Wen 
22035a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
22045a8dbdc6SYangbo Lu 	mmc_adapter_card_type_ident();
22055a8dbdc6SYangbo Lu #endif
22062051aefeSPeng Fan 	err = mmc_power_init(mmc);
22072051aefeSPeng Fan 	if (err)
22082051aefeSPeng Fan 		return err;
220995de9ab2SPaul Kocialkowski 
2210*04a2ea24SJean-Jacques Hiblot 	err = mmc_power_cycle(mmc);
2211*04a2ea24SJean-Jacques Hiblot 	if (err) {
2212*04a2ea24SJean-Jacques Hiblot 		/*
2213*04a2ea24SJean-Jacques Hiblot 		 * if power cycling is not supported, we should not try
2214*04a2ea24SJean-Jacques Hiblot 		 * to use the UHS modes, because we wouldn't be able to
2215*04a2ea24SJean-Jacques Hiblot 		 * recover from an error during the UHS initialization.
2216*04a2ea24SJean-Jacques Hiblot 		 */
2217*04a2ea24SJean-Jacques Hiblot 		debug("Unable to do a full power cycle. Disabling the UHS modes for safety\n");
2218*04a2ea24SJean-Jacques Hiblot 		uhs_en = false;
2219*04a2ea24SJean-Jacques Hiblot 		mmc->host_caps &= ~UHS_CAPS;
2220fb7c3bebSKishon Vijay Abraham I 		err = mmc_power_on(mmc);
2221*04a2ea24SJean-Jacques Hiblot 	}
2222fb7c3bebSKishon Vijay Abraham I 	if (err)
2223fb7c3bebSKishon Vijay Abraham I 		return err;
2224fb7c3bebSKishon Vijay Abraham I 
2225e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
22268ca51e51SSimon Glass 	/* The device has already been probed ready for use */
22278ca51e51SSimon Glass #else
2228ab769f22SPantelis Antoniou 	/* made sure it's not NULL earlier */
222993bfd616SPantelis Antoniou 	err = mmc->cfg->ops->init(mmc);
2230272cc70bSAndy Fleming 	if (err)
2231272cc70bSAndy Fleming 		return err;
22328ca51e51SSimon Glass #endif
2233786e8f81SAndrew Gabbasov 	mmc->ddr_mode = 0;
2234aff5d3c8SKishon Vijay Abraham I 
2235c10b85d6SJean-Jacques Hiblot retry:
2236fb7c3bebSKishon Vijay Abraham I 	mmc_set_initial_state(mmc);
2237318a7a57SJean-Jacques Hiblot 	mmc_send_init_stream(mmc);
2238318a7a57SJean-Jacques Hiblot 
2239272cc70bSAndy Fleming 	/* Reset the Card */
2240272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
2241272cc70bSAndy Fleming 
2242272cc70bSAndy Fleming 	if (err)
2243272cc70bSAndy Fleming 		return err;
2244272cc70bSAndy Fleming 
2245bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
2246c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->hwpart = 0;
2247bc897b1dSLei Wen 
2248272cc70bSAndy Fleming 	/* Test for SD version 2 */
2249272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
2250272cc70bSAndy Fleming 
2251272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
2252c10b85d6SJean-Jacques Hiblot 	err = sd_send_op_cond(mmc, uhs_en);
2253c10b85d6SJean-Jacques Hiblot 	if (err && uhs_en) {
2254c10b85d6SJean-Jacques Hiblot 		uhs_en = false;
2255c10b85d6SJean-Jacques Hiblot 		mmc_power_cycle(mmc);
2256c10b85d6SJean-Jacques Hiblot 		goto retry;
2257c10b85d6SJean-Jacques Hiblot 	}
2258272cc70bSAndy Fleming 
2259272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
2260915ffa52SJaehoon Chung 	if (err == -ETIMEDOUT) {
2261272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
2262272cc70bSAndy Fleming 
2263bd47c135SAndrew Gabbasov 		if (err) {
226456196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2265272cc70bSAndy Fleming 			printf("Card did not respond to voltage select!\n");
226656196826SPaul Burton #endif
2267915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
2268272cc70bSAndy Fleming 		}
2269272cc70bSAndy Fleming 	}
2270272cc70bSAndy Fleming 
2271bd47c135SAndrew Gabbasov 	if (!err)
2272e9550449SChe-Liang Chiou 		mmc->init_in_progress = 1;
2273e9550449SChe-Liang Chiou 
2274e9550449SChe-Liang Chiou 	return err;
2275e9550449SChe-Liang Chiou }
2276e9550449SChe-Liang Chiou 
2277e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc)
2278e9550449SChe-Liang Chiou {
2279e9550449SChe-Liang Chiou 	int err = 0;
2280e9550449SChe-Liang Chiou 
2281bd47c135SAndrew Gabbasov 	mmc->init_in_progress = 0;
2282e9550449SChe-Liang Chiou 	if (mmc->op_cond_pending)
2283e9550449SChe-Liang Chiou 		err = mmc_complete_op_cond(mmc);
2284e9550449SChe-Liang Chiou 
2285e9550449SChe-Liang Chiou 	if (!err)
2286bc897b1dSLei Wen 		err = mmc_startup(mmc);
2287bc897b1dSLei Wen 	if (err)
2288bc897b1dSLei Wen 		mmc->has_init = 0;
2289bc897b1dSLei Wen 	else
2290bc897b1dSLei Wen 		mmc->has_init = 1;
2291e9550449SChe-Liang Chiou 	return err;
2292e9550449SChe-Liang Chiou }
2293e9550449SChe-Liang Chiou 
2294e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc)
2295e9550449SChe-Liang Chiou {
2296bd47c135SAndrew Gabbasov 	int err = 0;
2297ce9eca94SMarek Vasut 	__maybe_unused unsigned start;
2298c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
229933fb211dSSimon Glass 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev);
2300e9550449SChe-Liang Chiou 
230133fb211dSSimon Glass 	upriv->mmc = mmc;
230233fb211dSSimon Glass #endif
2303e9550449SChe-Liang Chiou 	if (mmc->has_init)
2304e9550449SChe-Liang Chiou 		return 0;
2305d803fea5SMateusz Zalega 
2306d803fea5SMateusz Zalega 	start = get_timer(0);
2307d803fea5SMateusz Zalega 
2308e9550449SChe-Liang Chiou 	if (!mmc->init_in_progress)
2309e9550449SChe-Liang Chiou 		err = mmc_start_init(mmc);
2310e9550449SChe-Liang Chiou 
2311bd47c135SAndrew Gabbasov 	if (!err)
2312e9550449SChe-Liang Chiou 		err = mmc_complete_init(mmc);
2313919b4858SJagan Teki 	if (err)
2314919b4858SJagan Teki 		printf("%s: %d, time %lu\n", __func__, err, get_timer(start));
2315919b4858SJagan Teki 
2316bc897b1dSLei Wen 	return err;
2317272cc70bSAndy Fleming }
2318272cc70bSAndy Fleming 
2319ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val)
2320ab71188cSMarkus Niebel {
2321ab71188cSMarkus Niebel 	mmc->dsr = val;
2322ab71188cSMarkus Niebel 	return 0;
2323ab71188cSMarkus Niebel }
2324ab71188cSMarkus Niebel 
2325cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */
2326cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis)
2327272cc70bSAndy Fleming {
2328272cc70bSAndy Fleming 	return -1;
2329272cc70bSAndy Fleming }
2330272cc70bSAndy Fleming 
2331cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */
2332cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis)
2333cee9ab7cSJeroen Hofstee {
2334cee9ab7cSJeroen Hofstee 	return -1;
2335cee9ab7cSJeroen Hofstee }
2336272cc70bSAndy Fleming 
2337e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit)
2338e9550449SChe-Liang Chiou {
2339e9550449SChe-Liang Chiou 	mmc->preinit = preinit;
2340e9550449SChe-Liang Chiou }
2341e9550449SChe-Liang Chiou 
2342c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD)
23438e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
23448e3332e2SSjoerd Simons {
23458e3332e2SSjoerd Simons 	return 0;
23468e3332e2SSjoerd Simons }
2347c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC)
23488e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
23498e3332e2SSjoerd Simons {
23504a1db6d8SSimon Glass 	int ret, i;
23518e3332e2SSjoerd Simons 	struct uclass *uc;
23524a1db6d8SSimon Glass 	struct udevice *dev;
23538e3332e2SSjoerd Simons 
23548e3332e2SSjoerd Simons 	ret = uclass_get(UCLASS_MMC, &uc);
23558e3332e2SSjoerd Simons 	if (ret)
23568e3332e2SSjoerd Simons 		return ret;
23578e3332e2SSjoerd Simons 
23584a1db6d8SSimon Glass 	/*
23594a1db6d8SSimon Glass 	 * Try to add them in sequence order. Really with driver model we
23604a1db6d8SSimon Glass 	 * should allow holes, but the current MMC list does not allow that.
23614a1db6d8SSimon Glass 	 * So if we request 0, 1, 3 we will get 0, 1, 2.
23624a1db6d8SSimon Glass 	 */
23634a1db6d8SSimon Glass 	for (i = 0; ; i++) {
23644a1db6d8SSimon Glass 		ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev);
23654a1db6d8SSimon Glass 		if (ret == -ENODEV)
23664a1db6d8SSimon Glass 			break;
23674a1db6d8SSimon Glass 	}
23684a1db6d8SSimon Glass 	uclass_foreach_dev(dev, uc) {
23694a1db6d8SSimon Glass 		ret = device_probe(dev);
23708e3332e2SSjoerd Simons 		if (ret)
23714a1db6d8SSimon Glass 			printf("%s - probe failed: %d\n", dev->name, ret);
23728e3332e2SSjoerd Simons 	}
23738e3332e2SSjoerd Simons 
23748e3332e2SSjoerd Simons 	return 0;
23758e3332e2SSjoerd Simons }
23768e3332e2SSjoerd Simons #else
23778e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
23788e3332e2SSjoerd Simons {
23798e3332e2SSjoerd Simons 	if (board_mmc_init(bis) < 0)
23808e3332e2SSjoerd Simons 		cpu_mmc_init(bis);
23818e3332e2SSjoerd Simons 
23828e3332e2SSjoerd Simons 	return 0;
23838e3332e2SSjoerd Simons }
23848e3332e2SSjoerd Simons #endif
2385e9550449SChe-Liang Chiou 
2386272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
2387272cc70bSAndy Fleming {
23881b26bab1SDaniel Kochmański 	static int initialized = 0;
23898e3332e2SSjoerd Simons 	int ret;
23901b26bab1SDaniel Kochmański 	if (initialized)	/* Avoid initializing mmc multiple times */
23911b26bab1SDaniel Kochmański 		return 0;
23921b26bab1SDaniel Kochmański 	initialized = 1;
23931b26bab1SDaniel Kochmański 
2394c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK)
2395b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY)
2396c40fdca6SSimon Glass 	mmc_list_init();
2397c40fdca6SSimon Glass #endif
2398b5b838f1SMarek Vasut #endif
23998e3332e2SSjoerd Simons 	ret = mmc_probe(bis);
24008e3332e2SSjoerd Simons 	if (ret)
24018e3332e2SSjoerd Simons 		return ret;
2402272cc70bSAndy Fleming 
2403bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD
2404272cc70bSAndy Fleming 	print_mmc_devices(',');
2405bb0dc108SYing Zhang #endif
2406272cc70bSAndy Fleming 
2407c40fdca6SSimon Glass 	mmc_do_preinit();
2408272cc70bSAndy Fleming 	return 0;
2409272cc70bSAndy Fleming }
2410cd3d4880STomas Melin 
2411cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE
2412cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc)
2413cd3d4880STomas Melin {
2414cd3d4880STomas Melin 	int err;
2415cd3d4880STomas Melin 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
2416cd3d4880STomas Melin 
2417cd3d4880STomas Melin 	err = mmc_send_ext_csd(mmc, ext_csd);
2418cd3d4880STomas Melin 	if (err) {
2419cd3d4880STomas Melin 		puts("Could not get ext_csd register values\n");
2420cd3d4880STomas Melin 		return err;
2421cd3d4880STomas Melin 	}
2422cd3d4880STomas Melin 
2423cd3d4880STomas Melin 	if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) {
2424cd3d4880STomas Melin 		puts("Background operations not supported on device\n");
2425cd3d4880STomas Melin 		return -EMEDIUMTYPE;
2426cd3d4880STomas Melin 	}
2427cd3d4880STomas Melin 
2428cd3d4880STomas Melin 	if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) {
2429cd3d4880STomas Melin 		puts("Background operations already enabled\n");
2430cd3d4880STomas Melin 		return 0;
2431cd3d4880STomas Melin 	}
2432cd3d4880STomas Melin 
2433cd3d4880STomas Melin 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1);
2434cd3d4880STomas Melin 	if (err) {
2435cd3d4880STomas Melin 		puts("Failed to enable manual background operations\n");
2436cd3d4880STomas Melin 		return err;
2437cd3d4880STomas Melin 	}
2438cd3d4880STomas Melin 
2439cd3d4880STomas Melin 	puts("Enabled manual background operations\n");
2440cd3d4880STomas Melin 
2441cd3d4880STomas Melin 	return 0;
2442cd3d4880STomas Melin }
2443cd3d4880STomas Melin #endif
2444