xref: /openbmc/u-boot/drivers/mmc/mmc.c (revision 318a7a576bc49aa8b4207e694d3fbd48c663d6ac)
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);
34aff5d3c8SKishon Vijay Abraham I 
35b5b838f1SMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY)
36b5b838f1SMarek Vasut static struct mmc mmc_static;
37b5b838f1SMarek Vasut struct mmc *find_mmc_device(int dev_num)
38b5b838f1SMarek Vasut {
39b5b838f1SMarek Vasut 	return &mmc_static;
40b5b838f1SMarek Vasut }
41b5b838f1SMarek Vasut 
42b5b838f1SMarek Vasut void mmc_do_preinit(void)
43b5b838f1SMarek Vasut {
44b5b838f1SMarek Vasut 	struct mmc *m = &mmc_static;
45b5b838f1SMarek Vasut #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
46b5b838f1SMarek Vasut 	mmc_set_preinit(m, 1);
47b5b838f1SMarek Vasut #endif
48b5b838f1SMarek Vasut 	if (m->preinit)
49b5b838f1SMarek Vasut 		mmc_start_init(m);
50b5b838f1SMarek Vasut }
51b5b838f1SMarek Vasut 
52b5b838f1SMarek Vasut struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
53b5b838f1SMarek Vasut {
54b5b838f1SMarek Vasut 	return &mmc->block_dev;
55b5b838f1SMarek Vasut }
56b5b838f1SMarek Vasut #endif
57b5b838f1SMarek Vasut 
58e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
59750121c3SJeroen Hofstee __weak int board_mmc_getwp(struct mmc *mmc)
60d23d8d7eSNikita Kiryanov {
61d23d8d7eSNikita Kiryanov 	return -1;
62d23d8d7eSNikita Kiryanov }
63d23d8d7eSNikita Kiryanov 
64d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc)
65d23d8d7eSNikita Kiryanov {
66d23d8d7eSNikita Kiryanov 	int wp;
67d23d8d7eSNikita Kiryanov 
68d23d8d7eSNikita Kiryanov 	wp = board_mmc_getwp(mmc);
69d23d8d7eSNikita Kiryanov 
70d4e1da4eSPeter Korsgaard 	if (wp < 0) {
7193bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getwp)
7293bfd616SPantelis Antoniou 			wp = mmc->cfg->ops->getwp(mmc);
73d4e1da4eSPeter Korsgaard 		else
74d4e1da4eSPeter Korsgaard 			wp = 0;
75d4e1da4eSPeter Korsgaard 	}
76d23d8d7eSNikita Kiryanov 
77d23d8d7eSNikita Kiryanov 	return wp;
78d23d8d7eSNikita Kiryanov }
79d23d8d7eSNikita Kiryanov 
80cee9ab7cSJeroen Hofstee __weak int board_mmc_getcd(struct mmc *mmc)
81cee9ab7cSJeroen Hofstee {
8211fdade2SStefano Babic 	return -1;
8311fdade2SStefano Babic }
848ca51e51SSimon Glass #endif
8511fdade2SStefano Babic 
868635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE
87c0c76ebaSSimon Glass void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd)
88c0c76ebaSSimon Glass {
89c0c76ebaSSimon Glass 	printf("CMD_SEND:%d\n", cmd->cmdidx);
90c0c76ebaSSimon Glass 	printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg);
91c0c76ebaSSimon Glass }
92c0c76ebaSSimon Glass 
93c0c76ebaSSimon Glass void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret)
94c0c76ebaSSimon Glass {
955db2fe3aSRaffaele Recalcati 	int i;
965db2fe3aSRaffaele Recalcati 	u8 *ptr;
975db2fe3aSRaffaele Recalcati 
987863ce58SBin Meng 	if (ret) {
997863ce58SBin Meng 		printf("\t\tRET\t\t\t %d\n", ret);
1007863ce58SBin Meng 	} else {
1015db2fe3aSRaffaele Recalcati 		switch (cmd->resp_type) {
1025db2fe3aSRaffaele Recalcati 		case MMC_RSP_NONE:
1035db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_NONE\n");
1045db2fe3aSRaffaele Recalcati 			break;
1055db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1:
1065db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n",
1075db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1085db2fe3aSRaffaele Recalcati 			break;
1095db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1b:
1105db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n",
1115db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1125db2fe3aSRaffaele Recalcati 			break;
1135db2fe3aSRaffaele Recalcati 		case MMC_RSP_R2:
1145db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R2\t\t 0x%08X \n",
1155db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1165db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1175db2fe3aSRaffaele Recalcati 				cmd->response[1]);
1185db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1195db2fe3aSRaffaele Recalcati 				cmd->response[2]);
1205db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1215db2fe3aSRaffaele Recalcati 				cmd->response[3]);
1225db2fe3aSRaffaele Recalcati 			printf("\n");
1235db2fe3aSRaffaele Recalcati 			printf("\t\t\t\t\tDUMPING DATA\n");
1245db2fe3aSRaffaele Recalcati 			for (i = 0; i < 4; i++) {
1255db2fe3aSRaffaele Recalcati 				int j;
1265db2fe3aSRaffaele Recalcati 				printf("\t\t\t\t\t%03d - ", i*4);
127146bec79SDirk Behme 				ptr = (u8 *)&cmd->response[i];
1285db2fe3aSRaffaele Recalcati 				ptr += 3;
1295db2fe3aSRaffaele Recalcati 				for (j = 0; j < 4; j++)
1305db2fe3aSRaffaele Recalcati 					printf("%02X ", *ptr--);
1315db2fe3aSRaffaele Recalcati 				printf("\n");
1325db2fe3aSRaffaele Recalcati 			}
1335db2fe3aSRaffaele Recalcati 			break;
1345db2fe3aSRaffaele Recalcati 		case MMC_RSP_R3:
1355db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n",
1365db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1375db2fe3aSRaffaele Recalcati 			break;
1385db2fe3aSRaffaele Recalcati 		default:
1395db2fe3aSRaffaele Recalcati 			printf("\t\tERROR MMC rsp not supported\n");
1405db2fe3aSRaffaele Recalcati 			break;
1415db2fe3aSRaffaele Recalcati 		}
1427863ce58SBin Meng 	}
143c0c76ebaSSimon Glass }
144c0c76ebaSSimon Glass 
145c0c76ebaSSimon Glass void mmc_trace_state(struct mmc *mmc, struct mmc_cmd *cmd)
146c0c76ebaSSimon Glass {
147c0c76ebaSSimon Glass 	int status;
148c0c76ebaSSimon Glass 
149c0c76ebaSSimon Glass 	status = (cmd->response[0] & MMC_STATUS_CURR_STATE) >> 9;
150c0c76ebaSSimon Glass 	printf("CURR STATE:%d\n", status);
151c0c76ebaSSimon Glass }
1525db2fe3aSRaffaele Recalcati #endif
153c0c76ebaSSimon Glass 
15435f9e196SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG)
15535f9e196SJean-Jacques Hiblot const char *mmc_mode_name(enum bus_mode mode)
15635f9e196SJean-Jacques Hiblot {
15735f9e196SJean-Jacques Hiblot 	static const char *const names[] = {
15835f9e196SJean-Jacques Hiblot 	      [MMC_LEGACY]	= "MMC legacy",
15935f9e196SJean-Jacques Hiblot 	      [SD_LEGACY]	= "SD Legacy",
16035f9e196SJean-Jacques Hiblot 	      [MMC_HS]		= "MMC High Speed (26MHz)",
16135f9e196SJean-Jacques Hiblot 	      [SD_HS]		= "SD High Speed (50MHz)",
16235f9e196SJean-Jacques Hiblot 	      [UHS_SDR12]	= "UHS SDR12 (25MHz)",
16335f9e196SJean-Jacques Hiblot 	      [UHS_SDR25]	= "UHS SDR25 (50MHz)",
16435f9e196SJean-Jacques Hiblot 	      [UHS_SDR50]	= "UHS SDR50 (100MHz)",
16535f9e196SJean-Jacques Hiblot 	      [UHS_SDR104]	= "UHS SDR104 (208MHz)",
16635f9e196SJean-Jacques Hiblot 	      [UHS_DDR50]	= "UHS DDR50 (50MHz)",
16735f9e196SJean-Jacques Hiblot 	      [MMC_HS_52]	= "MMC High Speed (52MHz)",
16835f9e196SJean-Jacques Hiblot 	      [MMC_DDR_52]	= "MMC DDR52 (52MHz)",
16935f9e196SJean-Jacques Hiblot 	      [MMC_HS_200]	= "HS200 (200MHz)",
17035f9e196SJean-Jacques Hiblot 	};
17135f9e196SJean-Jacques Hiblot 
17235f9e196SJean-Jacques Hiblot 	if (mode >= MMC_MODES_END)
17335f9e196SJean-Jacques Hiblot 		return "Unknown mode";
17435f9e196SJean-Jacques Hiblot 	else
17535f9e196SJean-Jacques Hiblot 		return names[mode];
17635f9e196SJean-Jacques Hiblot }
17735f9e196SJean-Jacques Hiblot #endif
17835f9e196SJean-Jacques Hiblot 
17905038576SJean-Jacques Hiblot static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode)
18005038576SJean-Jacques Hiblot {
18105038576SJean-Jacques Hiblot 	static const int freqs[] = {
18205038576SJean-Jacques Hiblot 	      [SD_LEGACY]	= 25000000,
18305038576SJean-Jacques Hiblot 	      [MMC_HS]		= 26000000,
18405038576SJean-Jacques Hiblot 	      [SD_HS]		= 50000000,
18505038576SJean-Jacques Hiblot 	      [UHS_SDR12]	= 25000000,
18605038576SJean-Jacques Hiblot 	      [UHS_SDR25]	= 50000000,
18705038576SJean-Jacques Hiblot 	      [UHS_SDR50]	= 100000000,
18805038576SJean-Jacques Hiblot 	      [UHS_SDR104]	= 208000000,
18905038576SJean-Jacques Hiblot 	      [UHS_DDR50]	= 50000000,
19005038576SJean-Jacques Hiblot 	      [MMC_HS_52]	= 52000000,
19105038576SJean-Jacques Hiblot 	      [MMC_DDR_52]	= 52000000,
19205038576SJean-Jacques Hiblot 	      [MMC_HS_200]	= 200000000,
19305038576SJean-Jacques Hiblot 	};
19405038576SJean-Jacques Hiblot 
19505038576SJean-Jacques Hiblot 	if (mode == MMC_LEGACY)
19605038576SJean-Jacques Hiblot 		return mmc->legacy_speed;
19705038576SJean-Jacques Hiblot 	else if (mode >= MMC_MODES_END)
19805038576SJean-Jacques Hiblot 		return 0;
19905038576SJean-Jacques Hiblot 	else
20005038576SJean-Jacques Hiblot 		return freqs[mode];
20105038576SJean-Jacques Hiblot }
20205038576SJean-Jacques Hiblot 
20335f9e196SJean-Jacques Hiblot static int mmc_select_mode(struct mmc *mmc, enum bus_mode mode)
20435f9e196SJean-Jacques Hiblot {
20535f9e196SJean-Jacques Hiblot 	mmc->selected_mode = mode;
20605038576SJean-Jacques Hiblot 	mmc->tran_speed = mmc_mode2freq(mmc, mode);
2073862b854SJean-Jacques Hiblot 	mmc->ddr_mode = mmc_is_mode_ddr(mode);
20835f9e196SJean-Jacques Hiblot 	debug("selecting mode %s (freq : %d MHz)\n", mmc_mode_name(mode),
20935f9e196SJean-Jacques Hiblot 	      mmc->tran_speed / 1000000);
21035f9e196SJean-Jacques Hiblot 	return 0;
21135f9e196SJean-Jacques Hiblot }
21235f9e196SJean-Jacques Hiblot 
213e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
214c0c76ebaSSimon Glass int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
215c0c76ebaSSimon Glass {
216c0c76ebaSSimon Glass 	int ret;
217c0c76ebaSSimon Glass 
218c0c76ebaSSimon Glass 	mmmc_trace_before_send(mmc, cmd);
219c0c76ebaSSimon Glass 	ret = mmc->cfg->ops->send_cmd(mmc, cmd, data);
220c0c76ebaSSimon Glass 	mmmc_trace_after_send(mmc, cmd, ret);
221c0c76ebaSSimon Glass 
2228635ff9eSMarek Vasut 	return ret;
223272cc70bSAndy Fleming }
2248ca51e51SSimon Glass #endif
225272cc70bSAndy Fleming 
226da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout)
2275d4fc8d9SRaffaele Recalcati {
2285d4fc8d9SRaffaele Recalcati 	struct mmc_cmd cmd;
229d617c426SJan Kloetzke 	int err, retries = 5;
2305d4fc8d9SRaffaele Recalcati 
2315d4fc8d9SRaffaele Recalcati 	cmd.cmdidx = MMC_CMD_SEND_STATUS;
2325d4fc8d9SRaffaele Recalcati 	cmd.resp_type = MMC_RSP_R1;
233aaf3d41aSMarek Vasut 	if (!mmc_host_is_spi(mmc))
234aaf3d41aSMarek Vasut 		cmd.cmdarg = mmc->rca << 16;
2355d4fc8d9SRaffaele Recalcati 
2361677eef4SAndrew Gabbasov 	while (1) {
2375d4fc8d9SRaffaele Recalcati 		err = mmc_send_cmd(mmc, &cmd, NULL);
238d617c426SJan Kloetzke 		if (!err) {
239d617c426SJan Kloetzke 			if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) &&
240d617c426SJan Kloetzke 			    (cmd.response[0] & MMC_STATUS_CURR_STATE) !=
241d617c426SJan Kloetzke 			     MMC_STATE_PRG)
2425d4fc8d9SRaffaele Recalcati 				break;
243d0c221feSJean-Jacques Hiblot 
244d0c221feSJean-Jacques Hiblot 			if (cmd.response[0] & MMC_STATUS_MASK) {
24556196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
246d617c426SJan Kloetzke 				printf("Status Error: 0x%08X\n",
247d617c426SJan Kloetzke 					cmd.response[0]);
24856196826SPaul Burton #endif
249915ffa52SJaehoon Chung 				return -ECOMM;
250d617c426SJan Kloetzke 			}
251d617c426SJan Kloetzke 		} else if (--retries < 0)
252d617c426SJan Kloetzke 			return err;
2535d4fc8d9SRaffaele Recalcati 
2541677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
2551677eef4SAndrew Gabbasov 			break;
2565d4fc8d9SRaffaele Recalcati 
2571677eef4SAndrew Gabbasov 		udelay(1000);
2581677eef4SAndrew Gabbasov 	}
2595d4fc8d9SRaffaele Recalcati 
260c0c76ebaSSimon Glass 	mmc_trace_state(mmc, &cmd);
2615b0c942fSJongman Heo 	if (timeout <= 0) {
26256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2635d4fc8d9SRaffaele Recalcati 		printf("Timeout waiting card ready\n");
26456196826SPaul Burton #endif
265915ffa52SJaehoon Chung 		return -ETIMEDOUT;
2665d4fc8d9SRaffaele Recalcati 	}
2675d4fc8d9SRaffaele Recalcati 
2685d4fc8d9SRaffaele Recalcati 	return 0;
2695d4fc8d9SRaffaele Recalcati }
2705d4fc8d9SRaffaele Recalcati 
271da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len)
272272cc70bSAndy Fleming {
273272cc70bSAndy Fleming 	struct mmc_cmd cmd;
274272cc70bSAndy Fleming 
275786e8f81SAndrew Gabbasov 	if (mmc->ddr_mode)
276d22e3d46SJaehoon Chung 		return 0;
277d22e3d46SJaehoon Chung 
278272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
279272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
280272cc70bSAndy Fleming 	cmd.cmdarg = len;
281272cc70bSAndy Fleming 
282272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, NULL);
283272cc70bSAndy Fleming }
284272cc70bSAndy Fleming 
285ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
286fdbb873eSKim Phillips 			   lbaint_t blkcnt)
287272cc70bSAndy Fleming {
288272cc70bSAndy Fleming 	struct mmc_cmd cmd;
289272cc70bSAndy Fleming 	struct mmc_data data;
290272cc70bSAndy Fleming 
2914a1a06bcSAlagu Sankar 	if (blkcnt > 1)
2924a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
2934a1a06bcSAlagu Sankar 	else
294272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
295272cc70bSAndy Fleming 
296272cc70bSAndy Fleming 	if (mmc->high_capacity)
2974a1a06bcSAlagu Sankar 		cmd.cmdarg = start;
298272cc70bSAndy Fleming 	else
2994a1a06bcSAlagu Sankar 		cmd.cmdarg = start * mmc->read_bl_len;
300272cc70bSAndy Fleming 
301272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
302272cc70bSAndy Fleming 
303272cc70bSAndy Fleming 	data.dest = dst;
3044a1a06bcSAlagu Sankar 	data.blocks = blkcnt;
305272cc70bSAndy Fleming 	data.blocksize = mmc->read_bl_len;
306272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
307272cc70bSAndy Fleming 
3084a1a06bcSAlagu Sankar 	if (mmc_send_cmd(mmc, &cmd, &data))
3094a1a06bcSAlagu Sankar 		return 0;
3104a1a06bcSAlagu Sankar 
3114a1a06bcSAlagu Sankar 	if (blkcnt > 1) {
3124a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
3134a1a06bcSAlagu Sankar 		cmd.cmdarg = 0;
3144a1a06bcSAlagu Sankar 		cmd.resp_type = MMC_RSP_R1b;
3154a1a06bcSAlagu Sankar 		if (mmc_send_cmd(mmc, &cmd, NULL)) {
31656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
3174a1a06bcSAlagu Sankar 			printf("mmc fail to send stop cmd\n");
31856196826SPaul Burton #endif
3194a1a06bcSAlagu Sankar 			return 0;
3204a1a06bcSAlagu Sankar 		}
321272cc70bSAndy Fleming 	}
322272cc70bSAndy Fleming 
3234a1a06bcSAlagu Sankar 	return blkcnt;
324272cc70bSAndy Fleming }
325272cc70bSAndy Fleming 
326c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
3277dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst)
32833fb211dSSimon Glass #else
3297dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
3307dba0b93SSimon Glass 		void *dst)
33133fb211dSSimon Glass #endif
332272cc70bSAndy Fleming {
333c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
33433fb211dSSimon Glass 	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
33533fb211dSSimon Glass #endif
336bcce53d0SSimon Glass 	int dev_num = block_dev->devnum;
337873cc1d7SStephen Warren 	int err;
3384a1a06bcSAlagu Sankar 	lbaint_t cur, blocks_todo = blkcnt;
339272cc70bSAndy Fleming 
3404a1a06bcSAlagu Sankar 	if (blkcnt == 0)
3414a1a06bcSAlagu Sankar 		return 0;
3424a1a06bcSAlagu Sankar 
3434a1a06bcSAlagu Sankar 	struct mmc *mmc = find_mmc_device(dev_num);
344272cc70bSAndy Fleming 	if (!mmc)
345272cc70bSAndy Fleming 		return 0;
346272cc70bSAndy Fleming 
347b5b838f1SMarek Vasut 	if (CONFIG_IS_ENABLED(MMC_TINY))
348b5b838f1SMarek Vasut 		err = mmc_switch_part(mmc, block_dev->hwpart);
349b5b838f1SMarek Vasut 	else
35069f45cd5SSimon Glass 		err = blk_dselect_hwpart(block_dev, block_dev->hwpart);
351b5b838f1SMarek Vasut 
352873cc1d7SStephen Warren 	if (err < 0)
353873cc1d7SStephen Warren 		return 0;
354873cc1d7SStephen Warren 
355c40fdca6SSimon Glass 	if ((start + blkcnt) > block_dev->lba) {
35656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
357ff8fef56SSascha Silbe 		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
358c40fdca6SSimon Glass 			start + blkcnt, block_dev->lba);
35956196826SPaul Burton #endif
360d2bf29e3SLei Wen 		return 0;
361d2bf29e3SLei Wen 	}
362272cc70bSAndy Fleming 
36311692991SSimon Glass 	if (mmc_set_blocklen(mmc, mmc->read_bl_len)) {
36411692991SSimon Glass 		debug("%s: Failed to set blocklen\n", __func__);
365272cc70bSAndy Fleming 		return 0;
36611692991SSimon Glass 	}
367272cc70bSAndy Fleming 
3684a1a06bcSAlagu Sankar 	do {
36993bfd616SPantelis Antoniou 		cur = (blocks_todo > mmc->cfg->b_max) ?
37093bfd616SPantelis Antoniou 			mmc->cfg->b_max : blocks_todo;
37111692991SSimon Glass 		if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
37211692991SSimon Glass 			debug("%s: Failed to read blocks\n", __func__);
3734a1a06bcSAlagu Sankar 			return 0;
37411692991SSimon Glass 		}
3754a1a06bcSAlagu Sankar 		blocks_todo -= cur;
3764a1a06bcSAlagu Sankar 		start += cur;
3774a1a06bcSAlagu Sankar 		dst += cur * mmc->read_bl_len;
3784a1a06bcSAlagu Sankar 	} while (blocks_todo > 0);
379272cc70bSAndy Fleming 
380272cc70bSAndy Fleming 	return blkcnt;
381272cc70bSAndy Fleming }
382272cc70bSAndy Fleming 
383fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc)
384272cc70bSAndy Fleming {
385272cc70bSAndy Fleming 	struct mmc_cmd cmd;
386272cc70bSAndy Fleming 	int err;
387272cc70bSAndy Fleming 
388272cc70bSAndy Fleming 	udelay(1000);
389272cc70bSAndy Fleming 
390272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
391272cc70bSAndy Fleming 	cmd.cmdarg = 0;
392272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_NONE;
393272cc70bSAndy Fleming 
394272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
395272cc70bSAndy Fleming 
396272cc70bSAndy Fleming 	if (err)
397272cc70bSAndy Fleming 		return err;
398272cc70bSAndy Fleming 
399272cc70bSAndy Fleming 	udelay(2000);
400272cc70bSAndy Fleming 
401272cc70bSAndy Fleming 	return 0;
402272cc70bSAndy Fleming }
403272cc70bSAndy Fleming 
404fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc)
405272cc70bSAndy Fleming {
406272cc70bSAndy Fleming 	int timeout = 1000;
407272cc70bSAndy Fleming 	int err;
408272cc70bSAndy Fleming 	struct mmc_cmd cmd;
409272cc70bSAndy Fleming 
4101677eef4SAndrew Gabbasov 	while (1) {
411272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_APP_CMD;
412272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1;
413272cc70bSAndy Fleming 		cmd.cmdarg = 0;
414272cc70bSAndy Fleming 
415272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
416272cc70bSAndy Fleming 
417272cc70bSAndy Fleming 		if (err)
418272cc70bSAndy Fleming 			return err;
419272cc70bSAndy Fleming 
420272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
421272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
422250de12bSStefano Babic 
423250de12bSStefano Babic 		/*
424250de12bSStefano Babic 		 * Most cards do not answer if some reserved bits
425250de12bSStefano Babic 		 * in the ocr are set. However, Some controller
426250de12bSStefano Babic 		 * can set bit 7 (reserved for low voltages), but
427250de12bSStefano Babic 		 * how to manage low voltages SD card is not yet
428250de12bSStefano Babic 		 * specified.
429250de12bSStefano Babic 		 */
430d52ebf10SThomas Chou 		cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
43193bfd616SPantelis Antoniou 			(mmc->cfg->voltages & 0xff8000);
432272cc70bSAndy Fleming 
433272cc70bSAndy Fleming 		if (mmc->version == SD_VERSION_2)
434272cc70bSAndy Fleming 			cmd.cmdarg |= OCR_HCS;
435272cc70bSAndy Fleming 
436272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
437272cc70bSAndy Fleming 
438272cc70bSAndy Fleming 		if (err)
439272cc70bSAndy Fleming 			return err;
440272cc70bSAndy Fleming 
4411677eef4SAndrew Gabbasov 		if (cmd.response[0] & OCR_BUSY)
4421677eef4SAndrew Gabbasov 			break;
443272cc70bSAndy Fleming 
4441677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
445915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
446272cc70bSAndy Fleming 
4471677eef4SAndrew Gabbasov 		udelay(1000);
4481677eef4SAndrew Gabbasov 	}
4491677eef4SAndrew Gabbasov 
450272cc70bSAndy Fleming 	if (mmc->version != SD_VERSION_2)
451272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
452272cc70bSAndy Fleming 
453d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
454d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
455d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
456d52ebf10SThomas Chou 		cmd.cmdarg = 0;
457d52ebf10SThomas Chou 
458d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
459d52ebf10SThomas Chou 
460d52ebf10SThomas Chou 		if (err)
461d52ebf10SThomas Chou 			return err;
462d52ebf10SThomas Chou 	}
463d52ebf10SThomas Chou 
464998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
465272cc70bSAndy Fleming 
466272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
467272cc70bSAndy Fleming 	mmc->rca = 0;
468272cc70bSAndy Fleming 
469272cc70bSAndy Fleming 	return 0;
470272cc70bSAndy Fleming }
471272cc70bSAndy Fleming 
4725289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg)
473272cc70bSAndy Fleming {
4745289b535SAndrew Gabbasov 	struct mmc_cmd cmd;
475272cc70bSAndy Fleming 	int err;
476272cc70bSAndy Fleming 
4775289b535SAndrew Gabbasov 	cmd.cmdidx = MMC_CMD_SEND_OP_COND;
4785289b535SAndrew Gabbasov 	cmd.resp_type = MMC_RSP_R3;
4795289b535SAndrew Gabbasov 	cmd.cmdarg = 0;
4805a20397bSRob Herring 	if (use_arg && !mmc_host_is_spi(mmc))
4815a20397bSRob Herring 		cmd.cmdarg = OCR_HCS |
48293bfd616SPantelis Antoniou 			(mmc->cfg->voltages &
483a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_VOLTAGE_MASK)) |
484a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_ACCESS_MODE);
485e9550449SChe-Liang Chiou 
4865289b535SAndrew Gabbasov 	err = mmc_send_cmd(mmc, &cmd, NULL);
487e9550449SChe-Liang Chiou 	if (err)
488e9550449SChe-Liang Chiou 		return err;
4895289b535SAndrew Gabbasov 	mmc->ocr = cmd.response[0];
490e9550449SChe-Liang Chiou 	return 0;
491e9550449SChe-Liang Chiou }
492e9550449SChe-Liang Chiou 
493750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc)
494e9550449SChe-Liang Chiou {
495e9550449SChe-Liang Chiou 	int err, i;
496e9550449SChe-Liang Chiou 
497272cc70bSAndy Fleming 	/* Some cards seem to need this */
498272cc70bSAndy Fleming 	mmc_go_idle(mmc);
499272cc70bSAndy Fleming 
50031cacbabSRaffaele Recalcati  	/* Asking to the card its capabilities */
501e9550449SChe-Liang Chiou 	for (i = 0; i < 2; i++) {
5025289b535SAndrew Gabbasov 		err = mmc_send_op_cond_iter(mmc, i != 0);
50331cacbabSRaffaele Recalcati 		if (err)
50431cacbabSRaffaele Recalcati 			return err;
50531cacbabSRaffaele Recalcati 
506e9550449SChe-Liang Chiou 		/* exit if not busy (flag seems to be inverted) */
507a626c8d4SAndrew Gabbasov 		if (mmc->ocr & OCR_BUSY)
508bd47c135SAndrew Gabbasov 			break;
509e9550449SChe-Liang Chiou 	}
510bd47c135SAndrew Gabbasov 	mmc->op_cond_pending = 1;
511bd47c135SAndrew Gabbasov 	return 0;
512e9550449SChe-Liang Chiou }
51331cacbabSRaffaele Recalcati 
514750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc)
515e9550449SChe-Liang Chiou {
516e9550449SChe-Liang Chiou 	struct mmc_cmd cmd;
517e9550449SChe-Liang Chiou 	int timeout = 1000;
518e9550449SChe-Liang Chiou 	uint start;
519e9550449SChe-Liang Chiou 	int err;
520e9550449SChe-Liang Chiou 
521e9550449SChe-Liang Chiou 	mmc->op_cond_pending = 0;
522cc17c01fSAndrew Gabbasov 	if (!(mmc->ocr & OCR_BUSY)) {
523d188b113SYangbo Lu 		/* Some cards seem to need this */
524d188b113SYangbo Lu 		mmc_go_idle(mmc);
525d188b113SYangbo Lu 
526e9550449SChe-Liang Chiou 		start = get_timer(0);
5271677eef4SAndrew Gabbasov 		while (1) {
5285289b535SAndrew Gabbasov 			err = mmc_send_op_cond_iter(mmc, 1);
529272cc70bSAndy Fleming 			if (err)
530272cc70bSAndy Fleming 				return err;
5311677eef4SAndrew Gabbasov 			if (mmc->ocr & OCR_BUSY)
5321677eef4SAndrew Gabbasov 				break;
533e9550449SChe-Liang Chiou 			if (get_timer(start) > timeout)
534915ffa52SJaehoon Chung 				return -EOPNOTSUPP;
535e9550449SChe-Liang Chiou 			udelay(100);
5361677eef4SAndrew Gabbasov 		}
537cc17c01fSAndrew Gabbasov 	}
538272cc70bSAndy Fleming 
539d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
540d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
541d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
542d52ebf10SThomas Chou 		cmd.cmdarg = 0;
543d52ebf10SThomas Chou 
544d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
545d52ebf10SThomas Chou 
546d52ebf10SThomas Chou 		if (err)
547d52ebf10SThomas Chou 			return err;
548a626c8d4SAndrew Gabbasov 
549a626c8d4SAndrew Gabbasov 		mmc->ocr = cmd.response[0];
550d52ebf10SThomas Chou 	}
551d52ebf10SThomas Chou 
552272cc70bSAndy Fleming 	mmc->version = MMC_VERSION_UNKNOWN;
553272cc70bSAndy Fleming 
554272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
555def816a2SStephen Warren 	mmc->rca = 1;
556272cc70bSAndy Fleming 
557272cc70bSAndy Fleming 	return 0;
558272cc70bSAndy Fleming }
559272cc70bSAndy Fleming 
560272cc70bSAndy Fleming 
561fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
562272cc70bSAndy Fleming {
563272cc70bSAndy Fleming 	struct mmc_cmd cmd;
564272cc70bSAndy Fleming 	struct mmc_data data;
565272cc70bSAndy Fleming 	int err;
566272cc70bSAndy Fleming 
567272cc70bSAndy Fleming 	/* Get the Card Status Register */
568272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
569272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
570272cc70bSAndy Fleming 	cmd.cmdarg = 0;
571272cc70bSAndy Fleming 
572cdfd1ac6SYoshihiro Shimoda 	data.dest = (char *)ext_csd;
573272cc70bSAndy Fleming 	data.blocks = 1;
5748bfa195eSSimon Glass 	data.blocksize = MMC_MAX_BLOCK_LEN;
575272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
576272cc70bSAndy Fleming 
577272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
578272cc70bSAndy Fleming 
579272cc70bSAndy Fleming 	return err;
580272cc70bSAndy Fleming }
581272cc70bSAndy Fleming 
582c40704f4SSimon Glass int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
583272cc70bSAndy Fleming {
584272cc70bSAndy Fleming 	struct mmc_cmd cmd;
5855d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
586a9003dc6SMaxime Ripard 	int retries = 3;
5875d4fc8d9SRaffaele Recalcati 	int ret;
588272cc70bSAndy Fleming 
589272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SWITCH;
590272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1b;
591272cc70bSAndy Fleming 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
592272cc70bSAndy Fleming 				 (index << 16) |
593272cc70bSAndy Fleming 				 (value << 8);
594272cc70bSAndy Fleming 
595a9003dc6SMaxime Ripard 	while (retries > 0) {
5965d4fc8d9SRaffaele Recalcati 		ret = mmc_send_cmd(mmc, &cmd, NULL);
5975d4fc8d9SRaffaele Recalcati 
5985d4fc8d9SRaffaele Recalcati 		/* Waiting for the ready status */
599a9003dc6SMaxime Ripard 		if (!ret) {
60093ad0d18SJan Kloetzke 			ret = mmc_send_status(mmc, timeout);
601a9003dc6SMaxime Ripard 			return ret;
602a9003dc6SMaxime Ripard 		}
603a9003dc6SMaxime Ripard 
604a9003dc6SMaxime Ripard 		retries--;
605a9003dc6SMaxime Ripard 	}
6065d4fc8d9SRaffaele Recalcati 
6075d4fc8d9SRaffaele Recalcati 	return ret;
6085d4fc8d9SRaffaele Recalcati 
609272cc70bSAndy Fleming }
610272cc70bSAndy Fleming 
6113862b854SJean-Jacques Hiblot static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode)
612272cc70bSAndy Fleming {
613272cc70bSAndy Fleming 	int err;
6143862b854SJean-Jacques Hiblot 	int speed_bits;
6153862b854SJean-Jacques Hiblot 
6163862b854SJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
6173862b854SJean-Jacques Hiblot 
6183862b854SJean-Jacques Hiblot 	switch (mode) {
6193862b854SJean-Jacques Hiblot 	case MMC_HS:
6203862b854SJean-Jacques Hiblot 	case MMC_HS_52:
6213862b854SJean-Jacques Hiblot 	case MMC_DDR_52:
6223862b854SJean-Jacques Hiblot 		speed_bits = EXT_CSD_TIMING_HS;
6233862b854SJean-Jacques Hiblot 	case MMC_LEGACY:
6243862b854SJean-Jacques Hiblot 		speed_bits = EXT_CSD_TIMING_LEGACY;
6253862b854SJean-Jacques Hiblot 		break;
6263862b854SJean-Jacques Hiblot 	default:
6273862b854SJean-Jacques Hiblot 		return -EINVAL;
6283862b854SJean-Jacques Hiblot 	}
6293862b854SJean-Jacques Hiblot 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
6303862b854SJean-Jacques Hiblot 			 speed_bits);
6313862b854SJean-Jacques Hiblot 	if (err)
6323862b854SJean-Jacques Hiblot 		return err;
6333862b854SJean-Jacques Hiblot 
6343862b854SJean-Jacques Hiblot 	if ((mode == MMC_HS) || (mode == MMC_HS_52)) {
6353862b854SJean-Jacques Hiblot 		/* Now check to see that it worked */
6363862b854SJean-Jacques Hiblot 		err = mmc_send_ext_csd(mmc, test_csd);
6373862b854SJean-Jacques Hiblot 		if (err)
6383862b854SJean-Jacques Hiblot 			return err;
6393862b854SJean-Jacques Hiblot 
6403862b854SJean-Jacques Hiblot 		/* No high-speed support */
6413862b854SJean-Jacques Hiblot 		if (!test_csd[EXT_CSD_HS_TIMING])
6423862b854SJean-Jacques Hiblot 			return -ENOTSUPP;
6433862b854SJean-Jacques Hiblot 	}
6443862b854SJean-Jacques Hiblot 
6453862b854SJean-Jacques Hiblot 	return 0;
6463862b854SJean-Jacques Hiblot }
6473862b854SJean-Jacques Hiblot 
6483862b854SJean-Jacques Hiblot static int mmc_get_capabilities(struct mmc *mmc)
6493862b854SJean-Jacques Hiblot {
6503862b854SJean-Jacques Hiblot 	u8 *ext_csd = mmc->ext_csd;
6513862b854SJean-Jacques Hiblot 	char cardtype;
652272cc70bSAndy Fleming 
653d0c221feSJean-Jacques Hiblot 	mmc->card_caps = MMC_MODE_1BIT;
654272cc70bSAndy Fleming 
655d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
656d52ebf10SThomas Chou 		return 0;
657d52ebf10SThomas Chou 
658272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
659272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
660272cc70bSAndy Fleming 		return 0;
661272cc70bSAndy Fleming 
6623862b854SJean-Jacques Hiblot 	if (!ext_csd) {
6633862b854SJean-Jacques Hiblot 		printf("No ext_csd found!\n"); /* this should enver happen */
6643862b854SJean-Jacques Hiblot 		return -ENOTSUPP;
6653862b854SJean-Jacques Hiblot 	}
6663862b854SJean-Jacques Hiblot 
667fc5b32fbSAndrew Gabbasov 	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
668fc5b32fbSAndrew Gabbasov 
6690560db18SLei Wen 	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf;
670272cc70bSAndy Fleming 
671272cc70bSAndy Fleming 	/* High Speed is set, there are two types: 52MHz and 26MHz */
672d22e3d46SJaehoon Chung 	if (cardtype & EXT_CSD_CARD_TYPE_52) {
6733862b854SJean-Jacques Hiblot 		if (cardtype & EXT_CSD_CARD_TYPE_DDR_52)
674d22e3d46SJaehoon Chung 			mmc->card_caps |= MMC_MODE_DDR_52MHz;
6753862b854SJean-Jacques Hiblot 		mmc->card_caps |= MMC_MODE_HS_52MHz;
676d22e3d46SJaehoon Chung 	}
6773862b854SJean-Jacques Hiblot 	if (cardtype & EXT_CSD_CARD_TYPE_26)
6783862b854SJean-Jacques Hiblot 		mmc->card_caps |= MMC_MODE_HS;
679272cc70bSAndy Fleming 
680272cc70bSAndy Fleming 	return 0;
681272cc70bSAndy Fleming }
682272cc70bSAndy Fleming 
683f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num)
684f866a46dSStephen Warren {
685f866a46dSStephen Warren 	switch (part_num) {
686f866a46dSStephen Warren 	case 0:
687f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_user;
688f866a46dSStephen Warren 		break;
689f866a46dSStephen Warren 	case 1:
690f866a46dSStephen Warren 	case 2:
691f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_boot;
692f866a46dSStephen Warren 		break;
693f866a46dSStephen Warren 	case 3:
694f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_rpmb;
695f866a46dSStephen Warren 		break;
696f866a46dSStephen Warren 	case 4:
697f866a46dSStephen Warren 	case 5:
698f866a46dSStephen Warren 	case 6:
699f866a46dSStephen Warren 	case 7:
700f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_gp[part_num - 4];
701f866a46dSStephen Warren 		break;
702f866a46dSStephen Warren 	default:
703f866a46dSStephen Warren 		return -1;
704f866a46dSStephen Warren 	}
705f866a46dSStephen Warren 
706c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len);
707f866a46dSStephen Warren 
708f866a46dSStephen Warren 	return 0;
709f866a46dSStephen Warren }
710f866a46dSStephen Warren 
7117dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num)
712bc897b1dSLei Wen {
713f866a46dSStephen Warren 	int ret;
714bc897b1dSLei Wen 
715f866a46dSStephen Warren 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
716bc897b1dSLei Wen 			 (mmc->part_config & ~PART_ACCESS_MASK)
717bc897b1dSLei Wen 			 | (part_num & PART_ACCESS_MASK));
718f866a46dSStephen Warren 
7196dc93e70SPeter Bigot 	/*
7206dc93e70SPeter Bigot 	 * Set the capacity if the switch succeeded or was intended
7216dc93e70SPeter Bigot 	 * to return to representing the raw device.
7226dc93e70SPeter Bigot 	 */
723873cc1d7SStephen Warren 	if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) {
7246dc93e70SPeter Bigot 		ret = mmc_set_capacity(mmc, part_num);
725fdbb139fSSimon Glass 		mmc_get_blk_desc(mmc)->hwpart = part_num;
726873cc1d7SStephen Warren 	}
7276dc93e70SPeter Bigot 
7286dc93e70SPeter Bigot 	return ret;
729bc897b1dSLei Wen }
730bc897b1dSLei Wen 
731ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc,
732ac9da0e0SDiego Santa Cruz 		      const struct mmc_hwpart_conf *conf,
733ac9da0e0SDiego Santa Cruz 		      enum mmc_hwpart_conf_mode mode)
734ac9da0e0SDiego Santa Cruz {
735ac9da0e0SDiego Santa Cruz 	u8 part_attrs = 0;
736ac9da0e0SDiego Santa Cruz 	u32 enh_size_mult;
737ac9da0e0SDiego Santa Cruz 	u32 enh_start_addr;
738ac9da0e0SDiego Santa Cruz 	u32 gp_size_mult[4];
739ac9da0e0SDiego Santa Cruz 	u32 max_enh_size_mult;
740ac9da0e0SDiego Santa Cruz 	u32 tot_enh_size_mult = 0;
7418dda5b0eSDiego Santa Cruz 	u8 wr_rel_set;
742ac9da0e0SDiego Santa Cruz 	int i, pidx, err;
743ac9da0e0SDiego Santa Cruz 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
744ac9da0e0SDiego Santa Cruz 
745ac9da0e0SDiego Santa Cruz 	if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE)
746ac9da0e0SDiego Santa Cruz 		return -EINVAL;
747ac9da0e0SDiego Santa Cruz 
748ac9da0e0SDiego Santa Cruz 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) {
749ac9da0e0SDiego Santa Cruz 		printf("eMMC >= 4.4 required for enhanced user data area\n");
750ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
751ac9da0e0SDiego Santa Cruz 	}
752ac9da0e0SDiego Santa Cruz 
753ac9da0e0SDiego Santa Cruz 	if (!(mmc->part_support & PART_SUPPORT)) {
754ac9da0e0SDiego Santa Cruz 		printf("Card does not support partitioning\n");
755ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
756ac9da0e0SDiego Santa Cruz 	}
757ac9da0e0SDiego Santa Cruz 
758ac9da0e0SDiego Santa Cruz 	if (!mmc->hc_wp_grp_size) {
759ac9da0e0SDiego Santa Cruz 		printf("Card does not define HC WP group size\n");
760ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
761ac9da0e0SDiego Santa Cruz 	}
762ac9da0e0SDiego Santa Cruz 
763ac9da0e0SDiego Santa Cruz 	/* check partition alignment and total enhanced size */
764ac9da0e0SDiego Santa Cruz 	if (conf->user.enh_size) {
765ac9da0e0SDiego Santa Cruz 		if (conf->user.enh_size % mmc->hc_wp_grp_size ||
766ac9da0e0SDiego Santa Cruz 		    conf->user.enh_start % mmc->hc_wp_grp_size) {
767ac9da0e0SDiego Santa Cruz 			printf("User data enhanced area not HC WP group "
768ac9da0e0SDiego Santa Cruz 			       "size aligned\n");
769ac9da0e0SDiego Santa Cruz 			return -EINVAL;
770ac9da0e0SDiego Santa Cruz 		}
771ac9da0e0SDiego Santa Cruz 		part_attrs |= EXT_CSD_ENH_USR;
772ac9da0e0SDiego Santa Cruz 		enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size;
773ac9da0e0SDiego Santa Cruz 		if (mmc->high_capacity) {
774ac9da0e0SDiego Santa Cruz 			enh_start_addr = conf->user.enh_start;
775ac9da0e0SDiego Santa Cruz 		} else {
776ac9da0e0SDiego Santa Cruz 			enh_start_addr = (conf->user.enh_start << 9);
777ac9da0e0SDiego Santa Cruz 		}
778ac9da0e0SDiego Santa Cruz 	} else {
779ac9da0e0SDiego Santa Cruz 		enh_size_mult = 0;
780ac9da0e0SDiego Santa Cruz 		enh_start_addr = 0;
781ac9da0e0SDiego Santa Cruz 	}
782ac9da0e0SDiego Santa Cruz 	tot_enh_size_mult += enh_size_mult;
783ac9da0e0SDiego Santa Cruz 
784ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
785ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) {
786ac9da0e0SDiego Santa Cruz 			printf("GP%i partition not HC WP group size "
787ac9da0e0SDiego Santa Cruz 			       "aligned\n", pidx+1);
788ac9da0e0SDiego Santa Cruz 			return -EINVAL;
789ac9da0e0SDiego Santa Cruz 		}
790ac9da0e0SDiego Santa Cruz 		gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size;
791ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) {
792ac9da0e0SDiego Santa Cruz 			part_attrs |= EXT_CSD_ENH_GP(pidx);
793ac9da0e0SDiego Santa Cruz 			tot_enh_size_mult += gp_size_mult[pidx];
794ac9da0e0SDiego Santa Cruz 		}
795ac9da0e0SDiego Santa Cruz 	}
796ac9da0e0SDiego Santa Cruz 
797ac9da0e0SDiego Santa Cruz 	if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) {
798ac9da0e0SDiego Santa Cruz 		printf("Card does not support enhanced attribute\n");
799ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
800ac9da0e0SDiego Santa Cruz 	}
801ac9da0e0SDiego Santa Cruz 
802ac9da0e0SDiego Santa Cruz 	err = mmc_send_ext_csd(mmc, ext_csd);
803ac9da0e0SDiego Santa Cruz 	if (err)
804ac9da0e0SDiego Santa Cruz 		return err;
805ac9da0e0SDiego Santa Cruz 
806ac9da0e0SDiego Santa Cruz 	max_enh_size_mult =
807ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) +
808ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) +
809ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT];
810ac9da0e0SDiego Santa Cruz 	if (tot_enh_size_mult > max_enh_size_mult) {
811ac9da0e0SDiego Santa Cruz 		printf("Total enhanced size exceeds maximum (%u > %u)\n",
812ac9da0e0SDiego Santa Cruz 		       tot_enh_size_mult, max_enh_size_mult);
813ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
814ac9da0e0SDiego Santa Cruz 	}
815ac9da0e0SDiego Santa Cruz 
8168dda5b0eSDiego Santa Cruz 	/* The default value of EXT_CSD_WR_REL_SET is device
8178dda5b0eSDiego Santa Cruz 	 * dependent, the values can only be changed if the
8188dda5b0eSDiego Santa Cruz 	 * EXT_CSD_HS_CTRL_REL bit is set. The values can be
8198dda5b0eSDiego Santa Cruz 	 * changed only once and before partitioning is completed. */
8208dda5b0eSDiego Santa Cruz 	wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
8218dda5b0eSDiego Santa Cruz 	if (conf->user.wr_rel_change) {
8228dda5b0eSDiego Santa Cruz 		if (conf->user.wr_rel_set)
8238dda5b0eSDiego Santa Cruz 			wr_rel_set |= EXT_CSD_WR_DATA_REL_USR;
8248dda5b0eSDiego Santa Cruz 		else
8258dda5b0eSDiego Santa Cruz 			wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR;
8268dda5b0eSDiego Santa Cruz 	}
8278dda5b0eSDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
8288dda5b0eSDiego Santa Cruz 		if (conf->gp_part[pidx].wr_rel_change) {
8298dda5b0eSDiego Santa Cruz 			if (conf->gp_part[pidx].wr_rel_set)
8308dda5b0eSDiego Santa Cruz 				wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx);
8318dda5b0eSDiego Santa Cruz 			else
8328dda5b0eSDiego Santa Cruz 				wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx);
8338dda5b0eSDiego Santa Cruz 		}
8348dda5b0eSDiego Santa Cruz 	}
8358dda5b0eSDiego Santa Cruz 
8368dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] &&
8378dda5b0eSDiego Santa Cruz 	    !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) {
8388dda5b0eSDiego Santa Cruz 		puts("Card does not support host controlled partition write "
8398dda5b0eSDiego Santa Cruz 		     "reliability settings\n");
8408dda5b0eSDiego Santa Cruz 		return -EMEDIUMTYPE;
8418dda5b0eSDiego Santa Cruz 	}
8428dda5b0eSDiego Santa Cruz 
843ac9da0e0SDiego Santa Cruz 	if (ext_csd[EXT_CSD_PARTITION_SETTING] &
844ac9da0e0SDiego Santa Cruz 	    EXT_CSD_PARTITION_SETTING_COMPLETED) {
845ac9da0e0SDiego Santa Cruz 		printf("Card already partitioned\n");
846ac9da0e0SDiego Santa Cruz 		return -EPERM;
847ac9da0e0SDiego Santa Cruz 	}
848ac9da0e0SDiego Santa Cruz 
849ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_CHECK)
850ac9da0e0SDiego Santa Cruz 		return 0;
851ac9da0e0SDiego Santa Cruz 
852ac9da0e0SDiego Santa Cruz 	/* Partitioning requires high-capacity size definitions */
853ac9da0e0SDiego Santa Cruz 	if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) {
854ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
855ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ERASE_GROUP_DEF, 1);
856ac9da0e0SDiego Santa Cruz 
857ac9da0e0SDiego Santa Cruz 		if (err)
858ac9da0e0SDiego Santa Cruz 			return err;
859ac9da0e0SDiego Santa Cruz 
860ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
861ac9da0e0SDiego Santa Cruz 
862ac9da0e0SDiego Santa Cruz 		/* update erase group size to be high-capacity */
863ac9da0e0SDiego Santa Cruz 		mmc->erase_grp_size =
864ac9da0e0SDiego Santa Cruz 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
865ac9da0e0SDiego Santa Cruz 
866ac9da0e0SDiego Santa Cruz 	}
867ac9da0e0SDiego Santa Cruz 
868ac9da0e0SDiego Santa Cruz 	/* all OK, write the configuration */
869ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 4; i++) {
870ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
871ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_START_ADDR+i,
872ac9da0e0SDiego Santa Cruz 				 (enh_start_addr >> (i*8)) & 0xFF);
873ac9da0e0SDiego Santa Cruz 		if (err)
874ac9da0e0SDiego Santa Cruz 			return err;
875ac9da0e0SDiego Santa Cruz 	}
876ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 3; i++) {
877ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
878ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_SIZE_MULT+i,
879ac9da0e0SDiego Santa Cruz 				 (enh_size_mult >> (i*8)) & 0xFF);
880ac9da0e0SDiego Santa Cruz 		if (err)
881ac9da0e0SDiego Santa Cruz 			return err;
882ac9da0e0SDiego Santa Cruz 	}
883ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
884ac9da0e0SDiego Santa Cruz 		for (i = 0; i < 3; i++) {
885ac9da0e0SDiego Santa Cruz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
886ac9da0e0SDiego Santa Cruz 					 EXT_CSD_GP_SIZE_MULT+pidx*3+i,
887ac9da0e0SDiego Santa Cruz 					 (gp_size_mult[pidx] >> (i*8)) & 0xFF);
888ac9da0e0SDiego Santa Cruz 			if (err)
889ac9da0e0SDiego Santa Cruz 				return err;
890ac9da0e0SDiego Santa Cruz 		}
891ac9da0e0SDiego Santa Cruz 	}
892ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
893ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs);
894ac9da0e0SDiego Santa Cruz 	if (err)
895ac9da0e0SDiego Santa Cruz 		return err;
896ac9da0e0SDiego Santa Cruz 
897ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_SET)
898ac9da0e0SDiego Santa Cruz 		return 0;
899ac9da0e0SDiego Santa Cruz 
9008dda5b0eSDiego Santa Cruz 	/* The WR_REL_SET is a write-once register but shall be
9018dda5b0eSDiego Santa Cruz 	 * written before setting PART_SETTING_COMPLETED. As it is
9028dda5b0eSDiego Santa Cruz 	 * write-once we can only write it when completing the
9038dda5b0eSDiego Santa Cruz 	 * partitioning. */
9048dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) {
9058dda5b0eSDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
9068dda5b0eSDiego Santa Cruz 				 EXT_CSD_WR_REL_SET, wr_rel_set);
9078dda5b0eSDiego Santa Cruz 		if (err)
9088dda5b0eSDiego Santa Cruz 			return err;
9098dda5b0eSDiego Santa Cruz 	}
9108dda5b0eSDiego Santa Cruz 
911ac9da0e0SDiego Santa Cruz 	/* Setting PART_SETTING_COMPLETED confirms the partition
912ac9da0e0SDiego Santa Cruz 	 * configuration but it only becomes effective after power
913ac9da0e0SDiego Santa Cruz 	 * cycle, so we do not adjust the partition related settings
914ac9da0e0SDiego Santa Cruz 	 * in the mmc struct. */
915ac9da0e0SDiego Santa Cruz 
916ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
917ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING,
918ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING_COMPLETED);
919ac9da0e0SDiego Santa Cruz 	if (err)
920ac9da0e0SDiego Santa Cruz 		return err;
921ac9da0e0SDiego Santa Cruz 
922ac9da0e0SDiego Santa Cruz 	return 0;
923ac9da0e0SDiego Santa Cruz }
924ac9da0e0SDiego Santa Cruz 
925e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
92648972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
92748972d90SThierry Reding {
92848972d90SThierry Reding 	int cd;
92948972d90SThierry Reding 
93048972d90SThierry Reding 	cd = board_mmc_getcd(mmc);
93148972d90SThierry Reding 
932d4e1da4eSPeter Korsgaard 	if (cd < 0) {
93393bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getcd)
93493bfd616SPantelis Antoniou 			cd = mmc->cfg->ops->getcd(mmc);
935d4e1da4eSPeter Korsgaard 		else
936d4e1da4eSPeter Korsgaard 			cd = 1;
937d4e1da4eSPeter Korsgaard 	}
93848972d90SThierry Reding 
93948972d90SThierry Reding 	return cd;
94048972d90SThierry Reding }
9418ca51e51SSimon Glass #endif
94248972d90SThierry Reding 
943fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
944272cc70bSAndy Fleming {
945272cc70bSAndy Fleming 	struct mmc_cmd cmd;
946272cc70bSAndy Fleming 	struct mmc_data data;
947272cc70bSAndy Fleming 
948272cc70bSAndy Fleming 	/* Switch the frequency */
949272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
950272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
951272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
952272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
953272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
954272cc70bSAndy Fleming 
955272cc70bSAndy Fleming 	data.dest = (char *)resp;
956272cc70bSAndy Fleming 	data.blocksize = 64;
957272cc70bSAndy Fleming 	data.blocks = 1;
958272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
959272cc70bSAndy Fleming 
960272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
961272cc70bSAndy Fleming }
962272cc70bSAndy Fleming 
963272cc70bSAndy Fleming 
964d0c221feSJean-Jacques Hiblot static int sd_get_capabilities(struct mmc *mmc)
965272cc70bSAndy Fleming {
966272cc70bSAndy Fleming 	int err;
967272cc70bSAndy Fleming 	struct mmc_cmd cmd;
96818e7c8f6SSuniel Mahesh 	ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2);
96918e7c8f6SSuniel Mahesh 	ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16);
970272cc70bSAndy Fleming 	struct mmc_data data;
971272cc70bSAndy Fleming 	int timeout;
972272cc70bSAndy Fleming 
973d0c221feSJean-Jacques Hiblot 	mmc->card_caps = MMC_MODE_1BIT;
974272cc70bSAndy Fleming 
975d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
976d52ebf10SThomas Chou 		return 0;
977d52ebf10SThomas Chou 
978272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
979272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
980272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
981272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
982272cc70bSAndy Fleming 
983272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
984272cc70bSAndy Fleming 
985272cc70bSAndy Fleming 	if (err)
986272cc70bSAndy Fleming 		return err;
987272cc70bSAndy Fleming 
988272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
989272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
990272cc70bSAndy Fleming 	cmd.cmdarg = 0;
991272cc70bSAndy Fleming 
992272cc70bSAndy Fleming 	timeout = 3;
993272cc70bSAndy Fleming 
994272cc70bSAndy Fleming retry_scr:
995f781dd38SAnton staaf 	data.dest = (char *)scr;
996272cc70bSAndy Fleming 	data.blocksize = 8;
997272cc70bSAndy Fleming 	data.blocks = 1;
998272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
999272cc70bSAndy Fleming 
1000272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
1001272cc70bSAndy Fleming 
1002272cc70bSAndy Fleming 	if (err) {
1003272cc70bSAndy Fleming 		if (timeout--)
1004272cc70bSAndy Fleming 			goto retry_scr;
1005272cc70bSAndy Fleming 
1006272cc70bSAndy Fleming 		return err;
1007272cc70bSAndy Fleming 	}
1008272cc70bSAndy Fleming 
10094e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
10104e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
1011272cc70bSAndy Fleming 
1012272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
1013272cc70bSAndy Fleming 	case 0:
1014272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1015272cc70bSAndy Fleming 		break;
1016272cc70bSAndy Fleming 	case 1:
1017272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_10;
1018272cc70bSAndy Fleming 		break;
1019272cc70bSAndy Fleming 	case 2:
1020272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
10211741c64dSJaehoon Chung 		if ((mmc->scr[0] >> 15) & 0x1)
10221741c64dSJaehoon Chung 			mmc->version = SD_VERSION_3;
1023272cc70bSAndy Fleming 		break;
1024272cc70bSAndy Fleming 	default:
1025272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1026272cc70bSAndy Fleming 		break;
1027272cc70bSAndy Fleming 	}
1028272cc70bSAndy Fleming 
1029b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
1030b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
1031b44c7083SAlagu Sankar 
1032272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
1033272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
1034272cc70bSAndy Fleming 		return 0;
1035272cc70bSAndy Fleming 
1036272cc70bSAndy Fleming 	timeout = 4;
1037272cc70bSAndy Fleming 	while (timeout--) {
1038272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
1039f781dd38SAnton staaf 				(u8 *)switch_status);
1040272cc70bSAndy Fleming 
1041272cc70bSAndy Fleming 		if (err)
1042272cc70bSAndy Fleming 			return err;
1043272cc70bSAndy Fleming 
1044272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
10454e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
1046272cc70bSAndy Fleming 			break;
1047272cc70bSAndy Fleming 	}
1048272cc70bSAndy Fleming 
1049272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
1050d0c221feSJean-Jacques Hiblot 	if (__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)
1051d0c221feSJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(SD_HS);
1052272cc70bSAndy Fleming 
10532c3fbf4cSMacpaul Lin 	return 0;
1054d0c221feSJean-Jacques Hiblot }
1055d0c221feSJean-Jacques Hiblot 
1056d0c221feSJean-Jacques Hiblot static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode)
1057d0c221feSJean-Jacques Hiblot {
1058d0c221feSJean-Jacques Hiblot 	int err;
1059d0c221feSJean-Jacques Hiblot 
1060d0c221feSJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
10612c3fbf4cSMacpaul Lin 
1062f781dd38SAnton staaf 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status);
1063272cc70bSAndy Fleming 	if (err)
1064272cc70bSAndy Fleming 		return err;
1065272cc70bSAndy Fleming 
1066d0c221feSJean-Jacques Hiblot 	if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) != 0x01000000)
1067d0c221feSJean-Jacques Hiblot 		return -ENOTSUPP;
1068d0c221feSJean-Jacques Hiblot 
1069d0c221feSJean-Jacques Hiblot 	return 0;
1070d0c221feSJean-Jacques Hiblot }
1071d0c221feSJean-Jacques Hiblot 
1072d0c221feSJean-Jacques Hiblot int sd_select_bus_width(struct mmc *mmc, int w)
1073d0c221feSJean-Jacques Hiblot {
1074d0c221feSJean-Jacques Hiblot 	int err;
1075d0c221feSJean-Jacques Hiblot 	struct mmc_cmd cmd;
1076d0c221feSJean-Jacques Hiblot 
1077d0c221feSJean-Jacques Hiblot 	if ((w != 4) && (w != 1))
1078d0c221feSJean-Jacques Hiblot 		return -EINVAL;
1079d0c221feSJean-Jacques Hiblot 
1080d0c221feSJean-Jacques Hiblot 	cmd.cmdidx = MMC_CMD_APP_CMD;
1081d0c221feSJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
1082d0c221feSJean-Jacques Hiblot 	cmd.cmdarg = mmc->rca << 16;
1083d0c221feSJean-Jacques Hiblot 
1084d0c221feSJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
1085d0c221feSJean-Jacques Hiblot 	if (err)
1086d0c221feSJean-Jacques Hiblot 		return err;
1087d0c221feSJean-Jacques Hiblot 
1088d0c221feSJean-Jacques Hiblot 	cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
1089d0c221feSJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
1090d0c221feSJean-Jacques Hiblot 	if (w == 4)
1091d0c221feSJean-Jacques Hiblot 		cmd.cmdarg = 2;
1092d0c221feSJean-Jacques Hiblot 	else if (w == 1)
1093d0c221feSJean-Jacques Hiblot 		cmd.cmdarg = 0;
1094d0c221feSJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
1095d0c221feSJean-Jacques Hiblot 	if (err)
1096d0c221feSJean-Jacques Hiblot 		return err;
1097272cc70bSAndy Fleming 
1098272cc70bSAndy Fleming 	return 0;
1099272cc70bSAndy Fleming }
1100272cc70bSAndy Fleming 
11013697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc)
11023697e599SPeng Fan {
11033697e599SPeng Fan 	int err, i;
11043697e599SPeng Fan 	struct mmc_cmd cmd;
11053697e599SPeng Fan 	ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16);
11063697e599SPeng Fan 	struct mmc_data data;
11073697e599SPeng Fan 	int timeout = 3;
11083697e599SPeng Fan 	unsigned int au, eo, et, es;
11093697e599SPeng Fan 
11103697e599SPeng Fan 	cmd.cmdidx = MMC_CMD_APP_CMD;
11113697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
11123697e599SPeng Fan 	cmd.cmdarg = mmc->rca << 16;
11133697e599SPeng Fan 
11143697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, NULL);
11153697e599SPeng Fan 	if (err)
11163697e599SPeng Fan 		return err;
11173697e599SPeng Fan 
11183697e599SPeng Fan 	cmd.cmdidx = SD_CMD_APP_SD_STATUS;
11193697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
11203697e599SPeng Fan 	cmd.cmdarg = 0;
11213697e599SPeng Fan 
11223697e599SPeng Fan retry_ssr:
11233697e599SPeng Fan 	data.dest = (char *)ssr;
11243697e599SPeng Fan 	data.blocksize = 64;
11253697e599SPeng Fan 	data.blocks = 1;
11263697e599SPeng Fan 	data.flags = MMC_DATA_READ;
11273697e599SPeng Fan 
11283697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, &data);
11293697e599SPeng Fan 	if (err) {
11303697e599SPeng Fan 		if (timeout--)
11313697e599SPeng Fan 			goto retry_ssr;
11323697e599SPeng Fan 
11333697e599SPeng Fan 		return err;
11343697e599SPeng Fan 	}
11353697e599SPeng Fan 
11363697e599SPeng Fan 	for (i = 0; i < 16; i++)
11373697e599SPeng Fan 		ssr[i] = be32_to_cpu(ssr[i]);
11383697e599SPeng Fan 
11393697e599SPeng Fan 	au = (ssr[2] >> 12) & 0xF;
11403697e599SPeng Fan 	if ((au <= 9) || (mmc->version == SD_VERSION_3)) {
11413697e599SPeng Fan 		mmc->ssr.au = sd_au_size[au];
11423697e599SPeng Fan 		es = (ssr[3] >> 24) & 0xFF;
11433697e599SPeng Fan 		es |= (ssr[2] & 0xFF) << 8;
11443697e599SPeng Fan 		et = (ssr[3] >> 18) & 0x3F;
11453697e599SPeng Fan 		if (es && et) {
11463697e599SPeng Fan 			eo = (ssr[3] >> 16) & 0x3;
11473697e599SPeng Fan 			mmc->ssr.erase_timeout = (et * 1000) / es;
11483697e599SPeng Fan 			mmc->ssr.erase_offset = eo * 1000;
11493697e599SPeng Fan 		}
11503697e599SPeng Fan 	} else {
11513697e599SPeng Fan 		debug("Invalid Allocation Unit Size.\n");
11523697e599SPeng Fan 	}
11533697e599SPeng Fan 
11543697e599SPeng Fan 	return 0;
11553697e599SPeng Fan }
11563697e599SPeng Fan 
1157272cc70bSAndy Fleming /* frequency bases */
1158272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
11595f837c2cSMike Frysinger static const int fbase[] = {
1160272cc70bSAndy Fleming 	10000,
1161272cc70bSAndy Fleming 	100000,
1162272cc70bSAndy Fleming 	1000000,
1163272cc70bSAndy Fleming 	10000000,
1164272cc70bSAndy Fleming };
1165272cc70bSAndy Fleming 
1166272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
1167272cc70bSAndy Fleming  * to platforms without floating point.
1168272cc70bSAndy Fleming  */
116961fe076fSSimon Glass static const u8 multipliers[] = {
1170272cc70bSAndy Fleming 	0,	/* reserved */
1171272cc70bSAndy Fleming 	10,
1172272cc70bSAndy Fleming 	12,
1173272cc70bSAndy Fleming 	13,
1174272cc70bSAndy Fleming 	15,
1175272cc70bSAndy Fleming 	20,
1176272cc70bSAndy Fleming 	25,
1177272cc70bSAndy Fleming 	30,
1178272cc70bSAndy Fleming 	35,
1179272cc70bSAndy Fleming 	40,
1180272cc70bSAndy Fleming 	45,
1181272cc70bSAndy Fleming 	50,
1182272cc70bSAndy Fleming 	55,
1183272cc70bSAndy Fleming 	60,
1184272cc70bSAndy Fleming 	70,
1185272cc70bSAndy Fleming 	80,
1186272cc70bSAndy Fleming };
1187272cc70bSAndy Fleming 
1188d0c221feSJean-Jacques Hiblot static inline int bus_width(uint cap)
1189d0c221feSJean-Jacques Hiblot {
1190d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_8BIT)
1191d0c221feSJean-Jacques Hiblot 		return 8;
1192d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_4BIT)
1193d0c221feSJean-Jacques Hiblot 		return 4;
1194d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_1BIT)
1195d0c221feSJean-Jacques Hiblot 		return 1;
1196d0c221feSJean-Jacques Hiblot 	printf("invalid bus witdh capability 0x%x\n", cap);
1197d0c221feSJean-Jacques Hiblot 	return 0;
1198d0c221feSJean-Jacques Hiblot }
1199d0c221feSJean-Jacques Hiblot 
1200e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
1201*318a7a57SJean-Jacques Hiblot static void mmc_send_init_stream(struct mmc *mmc)
1202*318a7a57SJean-Jacques Hiblot {
1203*318a7a57SJean-Jacques Hiblot }
1204*318a7a57SJean-Jacques Hiblot 
12052a4d212fSKishon Vijay Abraham I static int mmc_set_ios(struct mmc *mmc)
1206272cc70bSAndy Fleming {
12072a4d212fSKishon Vijay Abraham I 	int ret = 0;
12082a4d212fSKishon Vijay Abraham I 
120993bfd616SPantelis Antoniou 	if (mmc->cfg->ops->set_ios)
12102a4d212fSKishon Vijay Abraham I 		ret = mmc->cfg->ops->set_ios(mmc);
12112a4d212fSKishon Vijay Abraham I 
12122a4d212fSKishon Vijay Abraham I 	return ret;
1213272cc70bSAndy Fleming }
12148ca51e51SSimon Glass #endif
1215272cc70bSAndy Fleming 
12162a4d212fSKishon Vijay Abraham I int mmc_set_clock(struct mmc *mmc, uint clock)
1217272cc70bSAndy Fleming {
121893bfd616SPantelis Antoniou 	if (clock > mmc->cfg->f_max)
121993bfd616SPantelis Antoniou 		clock = mmc->cfg->f_max;
1220272cc70bSAndy Fleming 
122193bfd616SPantelis Antoniou 	if (clock < mmc->cfg->f_min)
122293bfd616SPantelis Antoniou 		clock = mmc->cfg->f_min;
1223272cc70bSAndy Fleming 
1224272cc70bSAndy Fleming 	mmc->clock = clock;
1225272cc70bSAndy Fleming 
12262a4d212fSKishon Vijay Abraham I 	return mmc_set_ios(mmc);
1227272cc70bSAndy Fleming }
1228272cc70bSAndy Fleming 
12292a4d212fSKishon Vijay Abraham I static int mmc_set_bus_width(struct mmc *mmc, uint width)
1230272cc70bSAndy Fleming {
1231272cc70bSAndy Fleming 	mmc->bus_width = width;
1232272cc70bSAndy Fleming 
12332a4d212fSKishon Vijay Abraham I 	return mmc_set_ios(mmc);
1234272cc70bSAndy Fleming }
1235272cc70bSAndy Fleming 
12364c9d2aaaSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG)
12374c9d2aaaSJean-Jacques Hiblot /*
12384c9d2aaaSJean-Jacques Hiblot  * helper function to display the capabilities in a human
12394c9d2aaaSJean-Jacques Hiblot  * friendly manner. The capabilities include bus width and
12404c9d2aaaSJean-Jacques Hiblot  * supported modes.
12414c9d2aaaSJean-Jacques Hiblot  */
12424c9d2aaaSJean-Jacques Hiblot void mmc_dump_capabilities(const char *text, uint caps)
12434c9d2aaaSJean-Jacques Hiblot {
12444c9d2aaaSJean-Jacques Hiblot 	enum bus_mode mode;
12454c9d2aaaSJean-Jacques Hiblot 
12464c9d2aaaSJean-Jacques Hiblot 	printf("%s: widths [", text);
12474c9d2aaaSJean-Jacques Hiblot 	if (caps & MMC_MODE_8BIT)
12484c9d2aaaSJean-Jacques Hiblot 		printf("8, ");
12494c9d2aaaSJean-Jacques Hiblot 	if (caps & MMC_MODE_4BIT)
12504c9d2aaaSJean-Jacques Hiblot 		printf("4, ");
1251d0c221feSJean-Jacques Hiblot 	if (caps & MMC_MODE_1BIT)
1252d0c221feSJean-Jacques Hiblot 		printf("1, ");
1253d0c221feSJean-Jacques Hiblot 	printf("\b\b] modes [");
12544c9d2aaaSJean-Jacques Hiblot 	for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++)
12554c9d2aaaSJean-Jacques Hiblot 		if (MMC_CAP(mode) & caps)
12564c9d2aaaSJean-Jacques Hiblot 			printf("%s, ", mmc_mode_name(mode));
12574c9d2aaaSJean-Jacques Hiblot 	printf("\b\b]\n");
12584c9d2aaaSJean-Jacques Hiblot }
12594c9d2aaaSJean-Jacques Hiblot #endif
12604c9d2aaaSJean-Jacques Hiblot 
1261d0c221feSJean-Jacques Hiblot struct mode_width_tuning {
1262d0c221feSJean-Jacques Hiblot 	enum bus_mode mode;
1263d0c221feSJean-Jacques Hiblot 	uint widths;
1264d0c221feSJean-Jacques Hiblot };
1265d0c221feSJean-Jacques Hiblot 
1266aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage)
1267aff5d3c8SKishon Vijay Abraham I {
1268aff5d3c8SKishon Vijay Abraham I 	mmc->signal_voltage = signal_voltage;
1269aff5d3c8SKishon Vijay Abraham I 	return mmc_set_ios(mmc);
1270aff5d3c8SKishon Vijay Abraham I }
1271aff5d3c8SKishon Vijay Abraham I 
1272d0c221feSJean-Jacques Hiblot static const struct mode_width_tuning sd_modes_by_pref[] = {
1273d0c221feSJean-Jacques Hiblot 	{
1274d0c221feSJean-Jacques Hiblot 		.mode = SD_HS,
1275d0c221feSJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1276d0c221feSJean-Jacques Hiblot 	},
1277d0c221feSJean-Jacques Hiblot 	{
1278d0c221feSJean-Jacques Hiblot 		.mode = SD_LEGACY,
1279d0c221feSJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1280d0c221feSJean-Jacques Hiblot 	}
1281d0c221feSJean-Jacques Hiblot };
1282d0c221feSJean-Jacques Hiblot 
1283d0c221feSJean-Jacques Hiblot #define for_each_sd_mode_by_pref(caps, mwt) \
1284d0c221feSJean-Jacques Hiblot 	for (mwt = sd_modes_by_pref;\
1285d0c221feSJean-Jacques Hiblot 	     mwt < sd_modes_by_pref + ARRAY_SIZE(sd_modes_by_pref);\
1286d0c221feSJean-Jacques Hiblot 	     mwt++) \
1287d0c221feSJean-Jacques Hiblot 		if (caps & MMC_CAP(mwt->mode))
1288d0c221feSJean-Jacques Hiblot 
1289d0c221feSJean-Jacques Hiblot static int sd_select_mode_and_width(struct mmc *mmc)
12908ac8a263SJean-Jacques Hiblot {
12918ac8a263SJean-Jacques Hiblot 	int err;
1292d0c221feSJean-Jacques Hiblot 	uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT};
1293d0c221feSJean-Jacques Hiblot 	const struct mode_width_tuning *mwt;
12948ac8a263SJean-Jacques Hiblot 
1295d0c221feSJean-Jacques Hiblot 	err = sd_get_capabilities(mmc);
12968ac8a263SJean-Jacques Hiblot 	if (err)
12978ac8a263SJean-Jacques Hiblot 		return err;
12988ac8a263SJean-Jacques Hiblot 	/* Restrict card's capabilities by what the host can do */
1299d0c221feSJean-Jacques Hiblot 	mmc->card_caps &= (mmc->cfg->host_caps | MMC_MODE_1BIT);
13008ac8a263SJean-Jacques Hiblot 
1301d0c221feSJean-Jacques Hiblot 	for_each_sd_mode_by_pref(mmc->card_caps, mwt) {
1302d0c221feSJean-Jacques Hiblot 		uint *w;
13038ac8a263SJean-Jacques Hiblot 
1304d0c221feSJean-Jacques Hiblot 		for (w = widths; w < widths + ARRAY_SIZE(widths); w++) {
1305d0c221feSJean-Jacques Hiblot 			if (*w & mmc->card_caps & mwt->widths) {
1306d0c221feSJean-Jacques Hiblot 				debug("trying mode %s width %d (at %d MHz)\n",
1307d0c221feSJean-Jacques Hiblot 				      mmc_mode_name(mwt->mode),
1308d0c221feSJean-Jacques Hiblot 				      bus_width(*w),
1309d0c221feSJean-Jacques Hiblot 				      mmc_mode2freq(mmc, mwt->mode) / 1000000);
1310d0c221feSJean-Jacques Hiblot 
1311d0c221feSJean-Jacques Hiblot 				/* configure the bus width (card + host) */
1312d0c221feSJean-Jacques Hiblot 				err = sd_select_bus_width(mmc, bus_width(*w));
13138ac8a263SJean-Jacques Hiblot 				if (err)
1314d0c221feSJean-Jacques Hiblot 					goto error;
1315d0c221feSJean-Jacques Hiblot 				mmc_set_bus_width(mmc, bus_width(*w));
13168ac8a263SJean-Jacques Hiblot 
1317d0c221feSJean-Jacques Hiblot 				/* configure the bus mode (card) */
1318d0c221feSJean-Jacques Hiblot 				err = sd_set_card_speed(mmc, mwt->mode);
13198ac8a263SJean-Jacques Hiblot 				if (err)
1320d0c221feSJean-Jacques Hiblot 					goto error;
13218ac8a263SJean-Jacques Hiblot 
1322d0c221feSJean-Jacques Hiblot 				/* configure the bus mode (host) */
1323d0c221feSJean-Jacques Hiblot 				mmc_select_mode(mmc, mwt->mode);
1324d0c221feSJean-Jacques Hiblot 				mmc_set_clock(mmc, mmc->tran_speed);
13258ac8a263SJean-Jacques Hiblot 
13268ac8a263SJean-Jacques Hiblot 				err = sd_read_ssr(mmc);
1327d0c221feSJean-Jacques Hiblot 				if (!err)
13288ac8a263SJean-Jacques Hiblot 					return 0;
1329d0c221feSJean-Jacques Hiblot 
1330d0c221feSJean-Jacques Hiblot 				printf("bad ssr\n");
1331d0c221feSJean-Jacques Hiblot 
1332d0c221feSJean-Jacques Hiblot error:
1333d0c221feSJean-Jacques Hiblot 				/* revert to a safer bus speed */
1334d0c221feSJean-Jacques Hiblot 				mmc_select_mode(mmc, SD_LEGACY);
1335d0c221feSJean-Jacques Hiblot 				mmc_set_clock(mmc, mmc->tran_speed);
1336d0c221feSJean-Jacques Hiblot 			}
1337d0c221feSJean-Jacques Hiblot 		}
1338d0c221feSJean-Jacques Hiblot 	}
1339d0c221feSJean-Jacques Hiblot 
1340d0c221feSJean-Jacques Hiblot 	printf("unable to select a mode\n");
1341d0c221feSJean-Jacques Hiblot 	return -ENOTSUPP;
13428ac8a263SJean-Jacques Hiblot }
13438ac8a263SJean-Jacques Hiblot 
13447382e691SJean-Jacques Hiblot /*
13457382e691SJean-Jacques Hiblot  * read the compare the part of ext csd that is constant.
13467382e691SJean-Jacques Hiblot  * This can be used to check that the transfer is working
13477382e691SJean-Jacques Hiblot  * as expected.
13487382e691SJean-Jacques Hiblot  */
13497382e691SJean-Jacques Hiblot static int mmc_read_and_compare_ext_csd(struct mmc *mmc)
13507382e691SJean-Jacques Hiblot {
13517382e691SJean-Jacques Hiblot 	int err;
13527382e691SJean-Jacques Hiblot 	const u8 *ext_csd = mmc->ext_csd;
13537382e691SJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
13547382e691SJean-Jacques Hiblot 
13557382e691SJean-Jacques Hiblot 	err = mmc_send_ext_csd(mmc, test_csd);
13567382e691SJean-Jacques Hiblot 	if (err)
13577382e691SJean-Jacques Hiblot 		return err;
13587382e691SJean-Jacques Hiblot 
13597382e691SJean-Jacques Hiblot 	/* Only compare read only fields */
13607382e691SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT]
13617382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_PARTITIONING_SUPPORT] &&
13627382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_HC_WP_GRP_SIZE]
13637382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_HC_WP_GRP_SIZE] &&
13647382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_REV]
13657382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_REV] &&
13667382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
13677382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] &&
13687382e691SJean-Jacques Hiblot 	    memcmp(&ext_csd[EXT_CSD_SEC_CNT],
13697382e691SJean-Jacques Hiblot 		   &test_csd[EXT_CSD_SEC_CNT], 4) == 0)
13707382e691SJean-Jacques Hiblot 		return 0;
13717382e691SJean-Jacques Hiblot 
13727382e691SJean-Jacques Hiblot 	return -EBADMSG;
13737382e691SJean-Jacques Hiblot }
13747382e691SJean-Jacques Hiblot 
13753862b854SJean-Jacques Hiblot static const struct mode_width_tuning mmc_modes_by_pref[] = {
13768ac8a263SJean-Jacques Hiblot 	{
13773862b854SJean-Jacques Hiblot 		.mode = MMC_HS_200,
13783862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
13793862b854SJean-Jacques Hiblot 	},
13803862b854SJean-Jacques Hiblot 	{
13813862b854SJean-Jacques Hiblot 		.mode = MMC_DDR_52,
13823862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
13833862b854SJean-Jacques Hiblot 	},
13843862b854SJean-Jacques Hiblot 	{
13853862b854SJean-Jacques Hiblot 		.mode = MMC_HS_52,
13863862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
13873862b854SJean-Jacques Hiblot 	},
13883862b854SJean-Jacques Hiblot 	{
13893862b854SJean-Jacques Hiblot 		.mode = MMC_HS,
13903862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
13913862b854SJean-Jacques Hiblot 	},
13923862b854SJean-Jacques Hiblot 	{
13933862b854SJean-Jacques Hiblot 		.mode = MMC_LEGACY,
13943862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
13953862b854SJean-Jacques Hiblot 	}
13968ac8a263SJean-Jacques Hiblot };
13978ac8a263SJean-Jacques Hiblot 
13983862b854SJean-Jacques Hiblot #define for_each_mmc_mode_by_pref(caps, mwt) \
13993862b854SJean-Jacques Hiblot 	for (mwt = mmc_modes_by_pref;\
14003862b854SJean-Jacques Hiblot 	    mwt < mmc_modes_by_pref + ARRAY_SIZE(mmc_modes_by_pref);\
14013862b854SJean-Jacques Hiblot 	    mwt++) \
14023862b854SJean-Jacques Hiblot 		if (caps & MMC_CAP(mwt->mode))
14033862b854SJean-Jacques Hiblot 
14043862b854SJean-Jacques Hiblot static const struct ext_csd_bus_width {
14053862b854SJean-Jacques Hiblot 	uint cap;
14063862b854SJean-Jacques Hiblot 	bool is_ddr;
14073862b854SJean-Jacques Hiblot 	uint ext_csd_bits;
14083862b854SJean-Jacques Hiblot } ext_csd_bus_width[] = {
14093862b854SJean-Jacques Hiblot 	{MMC_MODE_8BIT, true, EXT_CSD_DDR_BUS_WIDTH_8},
14103862b854SJean-Jacques Hiblot 	{MMC_MODE_4BIT, true, EXT_CSD_DDR_BUS_WIDTH_4},
14113862b854SJean-Jacques Hiblot 	{MMC_MODE_8BIT, false, EXT_CSD_BUS_WIDTH_8},
14123862b854SJean-Jacques Hiblot 	{MMC_MODE_4BIT, false, EXT_CSD_BUS_WIDTH_4},
14133862b854SJean-Jacques Hiblot 	{MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1},
14143862b854SJean-Jacques Hiblot };
14153862b854SJean-Jacques Hiblot 
14163862b854SJean-Jacques Hiblot #define for_each_supported_width(caps, ddr, ecbv) \
14173862b854SJean-Jacques Hiblot 	for (ecbv = ext_csd_bus_width;\
14183862b854SJean-Jacques Hiblot 	    ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\
14193862b854SJean-Jacques Hiblot 	    ecbv++) \
14203862b854SJean-Jacques Hiblot 		if ((ddr == ecbv->is_ddr) && (caps & ecbv->cap))
14213862b854SJean-Jacques Hiblot 
14223862b854SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc)
14233862b854SJean-Jacques Hiblot {
14243862b854SJean-Jacques Hiblot 	int err;
14253862b854SJean-Jacques Hiblot 	const struct mode_width_tuning *mwt;
14263862b854SJean-Jacques Hiblot 	const struct ext_csd_bus_width *ecbw;
14273862b854SJean-Jacques Hiblot 
14283862b854SJean-Jacques Hiblot 	err = mmc_get_capabilities(mmc);
14298ac8a263SJean-Jacques Hiblot 	if (err)
14308ac8a263SJean-Jacques Hiblot 		return err;
14318ac8a263SJean-Jacques Hiblot 
14328ac8a263SJean-Jacques Hiblot 	/* Restrict card's capabilities by what the host can do */
1433d0c221feSJean-Jacques Hiblot 	mmc->card_caps &= (mmc->cfg->host_caps | MMC_MODE_1BIT);
14348ac8a263SJean-Jacques Hiblot 
14358ac8a263SJean-Jacques Hiblot 	/* Only version 4 of MMC supports wider bus widths */
14368ac8a263SJean-Jacques Hiblot 	if (mmc->version < MMC_VERSION_4)
14378ac8a263SJean-Jacques Hiblot 		return 0;
14388ac8a263SJean-Jacques Hiblot 
1439dfda9d88SJean-Jacques Hiblot 	if (!mmc->ext_csd) {
1440dfda9d88SJean-Jacques Hiblot 		debug("No ext_csd found!\n"); /* this should enver happen */
1441dfda9d88SJean-Jacques Hiblot 		return -ENOTSUPP;
1442dfda9d88SJean-Jacques Hiblot 	}
1443dfda9d88SJean-Jacques Hiblot 
14443862b854SJean-Jacques Hiblot 	for_each_mmc_mode_by_pref(mmc->card_caps, mwt) {
14453862b854SJean-Jacques Hiblot 		for_each_supported_width(mmc->card_caps & mwt->widths,
14463862b854SJean-Jacques Hiblot 					 mmc_is_mode_ddr(mwt->mode), ecbw) {
14473862b854SJean-Jacques Hiblot 			debug("trying mode %s width %d (at %d MHz)\n",
14483862b854SJean-Jacques Hiblot 			      mmc_mode_name(mwt->mode),
14493862b854SJean-Jacques Hiblot 			      bus_width(ecbw->cap),
14503862b854SJean-Jacques Hiblot 			      mmc_mode2freq(mmc, mwt->mode) / 1000000);
14513862b854SJean-Jacques Hiblot 			/* configure the bus width (card + host) */
14523862b854SJean-Jacques Hiblot 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
14533862b854SJean-Jacques Hiblot 				    EXT_CSD_BUS_WIDTH,
14543862b854SJean-Jacques Hiblot 				    ecbw->ext_csd_bits & ~EXT_CSD_DDR_FLAG);
14553862b854SJean-Jacques Hiblot 			if (err)
14563862b854SJean-Jacques Hiblot 				goto error;
14573862b854SJean-Jacques Hiblot 			mmc_set_bus_width(mmc, bus_width(ecbw->cap));
14583862b854SJean-Jacques Hiblot 
14593862b854SJean-Jacques Hiblot 			/* configure the bus speed (card) */
14603862b854SJean-Jacques Hiblot 			err = mmc_set_card_speed(mmc, mwt->mode);
14613862b854SJean-Jacques Hiblot 			if (err)
14623862b854SJean-Jacques Hiblot 				goto error;
14633862b854SJean-Jacques Hiblot 
14648ac8a263SJean-Jacques Hiblot 			/*
14653862b854SJean-Jacques Hiblot 			 * configure the bus width AND the ddr mode (card)
14663862b854SJean-Jacques Hiblot 			 * The host side will be taken care of in the next step
14678ac8a263SJean-Jacques Hiblot 			 */
14683862b854SJean-Jacques Hiblot 			if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) {
14693862b854SJean-Jacques Hiblot 				err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
14703862b854SJean-Jacques Hiblot 						 EXT_CSD_BUS_WIDTH,
14713862b854SJean-Jacques Hiblot 						 ecbw->ext_csd_bits);
14723862b854SJean-Jacques Hiblot 				if (err)
14733862b854SJean-Jacques Hiblot 					goto error;
14748ac8a263SJean-Jacques Hiblot 			}
14758ac8a263SJean-Jacques Hiblot 
14763862b854SJean-Jacques Hiblot 			/* configure the bus mode (host) */
14773862b854SJean-Jacques Hiblot 			mmc_select_mode(mmc, mwt->mode);
14783862b854SJean-Jacques Hiblot 			mmc_set_clock(mmc, mmc->tran_speed);
14798ac8a263SJean-Jacques Hiblot 
14803862b854SJean-Jacques Hiblot 			/* do a transfer to check the configuration */
14817382e691SJean-Jacques Hiblot 			err = mmc_read_and_compare_ext_csd(mmc);
14827382e691SJean-Jacques Hiblot 			if (!err)
14833862b854SJean-Jacques Hiblot 				return 0;
14843862b854SJean-Jacques Hiblot error:
14853862b854SJean-Jacques Hiblot 			/* if an error occured, revert to a safer bus mode */
14863862b854SJean-Jacques Hiblot 			mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
14873862b854SJean-Jacques Hiblot 				   EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1);
14883862b854SJean-Jacques Hiblot 			mmc_select_mode(mmc, MMC_LEGACY);
14893862b854SJean-Jacques Hiblot 			mmc_set_bus_width(mmc, 1);
14903862b854SJean-Jacques Hiblot 		}
14918ac8a263SJean-Jacques Hiblot 	}
14928ac8a263SJean-Jacques Hiblot 
14933862b854SJean-Jacques Hiblot 	printf("unable to select a mode\n");
14948ac8a263SJean-Jacques Hiblot 
14953862b854SJean-Jacques Hiblot 	return -ENOTSUPP;
14968ac8a263SJean-Jacques Hiblot }
14978ac8a263SJean-Jacques Hiblot 
1498dfda9d88SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc)
1499c744b6f6SJean-Jacques Hiblot {
1500c744b6f6SJean-Jacques Hiblot 	int err, i;
1501c744b6f6SJean-Jacques Hiblot 	u64 capacity;
1502c744b6f6SJean-Jacques Hiblot 	bool has_parts = false;
1503c744b6f6SJean-Jacques Hiblot 	bool part_completed;
1504dfda9d88SJean-Jacques Hiblot 	u8 *ext_csd;
1505c744b6f6SJean-Jacques Hiblot 
1506c744b6f6SJean-Jacques Hiblot 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4))
1507c744b6f6SJean-Jacques Hiblot 		return 0;
1508c744b6f6SJean-Jacques Hiblot 
1509dfda9d88SJean-Jacques Hiblot 	ext_csd = malloc_cache_aligned(MMC_MAX_BLOCK_LEN);
1510dfda9d88SJean-Jacques Hiblot 	if (!ext_csd)
1511dfda9d88SJean-Jacques Hiblot 		return -ENOMEM;
1512dfda9d88SJean-Jacques Hiblot 
1513dfda9d88SJean-Jacques Hiblot 	mmc->ext_csd = ext_csd;
1514dfda9d88SJean-Jacques Hiblot 
1515c744b6f6SJean-Jacques Hiblot 	/* check  ext_csd version and capacity */
1516c744b6f6SJean-Jacques Hiblot 	err = mmc_send_ext_csd(mmc, ext_csd);
1517c744b6f6SJean-Jacques Hiblot 	if (err)
1518c744b6f6SJean-Jacques Hiblot 		return err;
1519c744b6f6SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_REV] >= 2) {
1520c744b6f6SJean-Jacques Hiblot 		/*
1521c744b6f6SJean-Jacques Hiblot 		 * According to the JEDEC Standard, the value of
1522c744b6f6SJean-Jacques Hiblot 		 * ext_csd's capacity is valid if the value is more
1523c744b6f6SJean-Jacques Hiblot 		 * than 2GB
1524c744b6f6SJean-Jacques Hiblot 		 */
1525c744b6f6SJean-Jacques Hiblot 		capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
1526c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
1527c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
1528c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
1529c744b6f6SJean-Jacques Hiblot 		capacity *= MMC_MAX_BLOCK_LEN;
1530c744b6f6SJean-Jacques Hiblot 		if ((capacity >> 20) > 2 * 1024)
1531c744b6f6SJean-Jacques Hiblot 			mmc->capacity_user = capacity;
1532c744b6f6SJean-Jacques Hiblot 	}
1533c744b6f6SJean-Jacques Hiblot 
1534c744b6f6SJean-Jacques Hiblot 	switch (ext_csd[EXT_CSD_REV]) {
1535c744b6f6SJean-Jacques Hiblot 	case 1:
1536c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_1;
1537c744b6f6SJean-Jacques Hiblot 		break;
1538c744b6f6SJean-Jacques Hiblot 	case 2:
1539c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_2;
1540c744b6f6SJean-Jacques Hiblot 		break;
1541c744b6f6SJean-Jacques Hiblot 	case 3:
1542c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_3;
1543c744b6f6SJean-Jacques Hiblot 		break;
1544c744b6f6SJean-Jacques Hiblot 	case 5:
1545c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_41;
1546c744b6f6SJean-Jacques Hiblot 		break;
1547c744b6f6SJean-Jacques Hiblot 	case 6:
1548c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_5;
1549c744b6f6SJean-Jacques Hiblot 		break;
1550c744b6f6SJean-Jacques Hiblot 	case 7:
1551c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_5_0;
1552c744b6f6SJean-Jacques Hiblot 		break;
1553c744b6f6SJean-Jacques Hiblot 	case 8:
1554c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_5_1;
1555c744b6f6SJean-Jacques Hiblot 		break;
1556c744b6f6SJean-Jacques Hiblot 	}
1557c744b6f6SJean-Jacques Hiblot 
1558c744b6f6SJean-Jacques Hiblot 	/* The partition data may be non-zero but it is only
1559c744b6f6SJean-Jacques Hiblot 	 * effective if PARTITION_SETTING_COMPLETED is set in
1560c744b6f6SJean-Jacques Hiblot 	 * EXT_CSD, so ignore any data if this bit is not set,
1561c744b6f6SJean-Jacques Hiblot 	 * except for enabling the high-capacity group size
1562c744b6f6SJean-Jacques Hiblot 	 * definition (see below).
1563c744b6f6SJean-Jacques Hiblot 	 */
1564c744b6f6SJean-Jacques Hiblot 	part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
1565c744b6f6SJean-Jacques Hiblot 			    EXT_CSD_PARTITION_SETTING_COMPLETED);
1566c744b6f6SJean-Jacques Hiblot 
1567c744b6f6SJean-Jacques Hiblot 	/* store the partition info of emmc */
1568c744b6f6SJean-Jacques Hiblot 	mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
1569c744b6f6SJean-Jacques Hiblot 	if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
1570c744b6f6SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_BOOT_MULT])
1571c744b6f6SJean-Jacques Hiblot 		mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
1572c744b6f6SJean-Jacques Hiblot 	if (part_completed &&
1573c744b6f6SJean-Jacques Hiblot 	    (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
1574c744b6f6SJean-Jacques Hiblot 		mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
1575c744b6f6SJean-Jacques Hiblot 
1576c744b6f6SJean-Jacques Hiblot 	mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
1577c744b6f6SJean-Jacques Hiblot 
1578c744b6f6SJean-Jacques Hiblot 	mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
1579c744b6f6SJean-Jacques Hiblot 
1580c744b6f6SJean-Jacques Hiblot 	for (i = 0; i < 4; i++) {
1581c744b6f6SJean-Jacques Hiblot 		int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
1582c744b6f6SJean-Jacques Hiblot 		uint mult = (ext_csd[idx + 2] << 16) +
1583c744b6f6SJean-Jacques Hiblot 			(ext_csd[idx + 1] << 8) + ext_csd[idx];
1584c744b6f6SJean-Jacques Hiblot 		if (mult)
1585c744b6f6SJean-Jacques Hiblot 			has_parts = true;
1586c744b6f6SJean-Jacques Hiblot 		if (!part_completed)
1587c744b6f6SJean-Jacques Hiblot 			continue;
1588c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] = mult;
1589c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] *=
1590c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1591c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1592c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] <<= 19;
1593c744b6f6SJean-Jacques Hiblot 	}
1594c744b6f6SJean-Jacques Hiblot 
1595c744b6f6SJean-Jacques Hiblot 	if (part_completed) {
1596c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size =
1597c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) +
1598c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) +
1599c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_ENH_SIZE_MULT];
1600c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1601c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1602c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size <<= 19;
1603c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_start =
1604c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) +
1605c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) +
1606c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) +
1607c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_ENH_START_ADDR];
1608c744b6f6SJean-Jacques Hiblot 		if (mmc->high_capacity)
1609c744b6f6SJean-Jacques Hiblot 			mmc->enh_user_start <<= 9;
1610c744b6f6SJean-Jacques Hiblot 	}
1611c744b6f6SJean-Jacques Hiblot 
1612c744b6f6SJean-Jacques Hiblot 	/*
1613c744b6f6SJean-Jacques Hiblot 	 * Host needs to enable ERASE_GRP_DEF bit if device is
1614c744b6f6SJean-Jacques Hiblot 	 * partitioned. This bit will be lost every time after a reset
1615c744b6f6SJean-Jacques Hiblot 	 * or power off. This will affect erase size.
1616c744b6f6SJean-Jacques Hiblot 	 */
1617c744b6f6SJean-Jacques Hiblot 	if (part_completed)
1618c744b6f6SJean-Jacques Hiblot 		has_parts = true;
1619c744b6f6SJean-Jacques Hiblot 	if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
1620c744b6f6SJean-Jacques Hiblot 	    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
1621c744b6f6SJean-Jacques Hiblot 		has_parts = true;
1622c744b6f6SJean-Jacques Hiblot 	if (has_parts) {
1623c744b6f6SJean-Jacques Hiblot 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1624c744b6f6SJean-Jacques Hiblot 				 EXT_CSD_ERASE_GROUP_DEF, 1);
1625c744b6f6SJean-Jacques Hiblot 
1626c744b6f6SJean-Jacques Hiblot 		if (err)
1627c744b6f6SJean-Jacques Hiblot 			return err;
1628c744b6f6SJean-Jacques Hiblot 
1629c744b6f6SJean-Jacques Hiblot 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1630c744b6f6SJean-Jacques Hiblot 	}
1631c744b6f6SJean-Jacques Hiblot 
1632c744b6f6SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
1633c744b6f6SJean-Jacques Hiblot 		/* Read out group size from ext_csd */
1634c744b6f6SJean-Jacques Hiblot 		mmc->erase_grp_size =
1635c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1636c744b6f6SJean-Jacques Hiblot 		/*
1637c744b6f6SJean-Jacques Hiblot 		 * if high capacity and partition setting completed
1638c744b6f6SJean-Jacques Hiblot 		 * SEC_COUNT is valid even if it is smaller than 2 GiB
1639c744b6f6SJean-Jacques Hiblot 		 * JEDEC Standard JESD84-B45, 6.2.4
1640c744b6f6SJean-Jacques Hiblot 		 */
1641c744b6f6SJean-Jacques Hiblot 		if (mmc->high_capacity && part_completed) {
1642c744b6f6SJean-Jacques Hiblot 			capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
1643c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
1644c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
1645c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
1646c744b6f6SJean-Jacques Hiblot 			capacity *= MMC_MAX_BLOCK_LEN;
1647c744b6f6SJean-Jacques Hiblot 			mmc->capacity_user = capacity;
1648c744b6f6SJean-Jacques Hiblot 		}
1649c744b6f6SJean-Jacques Hiblot 	} else {
1650c744b6f6SJean-Jacques Hiblot 		/* Calculate the group size from the csd value. */
1651c744b6f6SJean-Jacques Hiblot 		int erase_gsz, erase_gmul;
1652c744b6f6SJean-Jacques Hiblot 
1653c744b6f6SJean-Jacques Hiblot 		erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
1654c744b6f6SJean-Jacques Hiblot 		erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
1655c744b6f6SJean-Jacques Hiblot 		mmc->erase_grp_size = (erase_gsz + 1)
1656c744b6f6SJean-Jacques Hiblot 			* (erase_gmul + 1);
1657c744b6f6SJean-Jacques Hiblot 	}
1658c744b6f6SJean-Jacques Hiblot 
1659c744b6f6SJean-Jacques Hiblot 	mmc->hc_wp_grp_size = 1024
1660c744b6f6SJean-Jacques Hiblot 		* ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
1661c744b6f6SJean-Jacques Hiblot 		* ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1662c744b6f6SJean-Jacques Hiblot 
1663c744b6f6SJean-Jacques Hiblot 	mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
1664c744b6f6SJean-Jacques Hiblot 
1665c744b6f6SJean-Jacques Hiblot 	return 0;
1666c744b6f6SJean-Jacques Hiblot }
1667c744b6f6SJean-Jacques Hiblot 
1668fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc)
1669272cc70bSAndy Fleming {
1670f866a46dSStephen Warren 	int err, i;
1671272cc70bSAndy Fleming 	uint mult, freq;
1672c744b6f6SJean-Jacques Hiblot 	u64 cmult, csize;
1673272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1674c40fdca6SSimon Glass 	struct blk_desc *bdesc;
1675272cc70bSAndy Fleming 
1676d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
1677d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
1678d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
1679d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
1680d52ebf10SThomas Chou 		cmd.cmdarg = 1;
1681d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
1682d52ebf10SThomas Chou 
1683d52ebf10SThomas Chou 		if (err)
1684d52ebf10SThomas Chou 			return err;
1685d52ebf10SThomas Chou 	}
1686d52ebf10SThomas Chou #endif
1687d52ebf10SThomas Chou 
1688272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
1689d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
1690d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
1691272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1692272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1693272cc70bSAndy Fleming 
1694272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1695272cc70bSAndy Fleming 
1696272cc70bSAndy Fleming 	if (err)
1697272cc70bSAndy Fleming 		return err;
1698272cc70bSAndy Fleming 
1699272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
1700272cc70bSAndy Fleming 
1701272cc70bSAndy Fleming 	/*
1702272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
1703272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
1704272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
1705272cc70bSAndy Fleming 	 */
1706d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1707272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
1708272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1709272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
1710272cc70bSAndy Fleming 
1711272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1712272cc70bSAndy Fleming 
1713272cc70bSAndy Fleming 		if (err)
1714272cc70bSAndy Fleming 			return err;
1715272cc70bSAndy Fleming 
1716272cc70bSAndy Fleming 		if (IS_SD(mmc))
1717998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
1718d52ebf10SThomas Chou 	}
1719272cc70bSAndy Fleming 
1720272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
1721272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
1722272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1723272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1724272cc70bSAndy Fleming 
1725272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1726272cc70bSAndy Fleming 
1727272cc70bSAndy Fleming 	if (err)
1728272cc70bSAndy Fleming 		return err;
1729272cc70bSAndy Fleming 
1730998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
1731998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
1732998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
1733998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
1734272cc70bSAndy Fleming 
1735272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
17360b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
1737272cc70bSAndy Fleming 
1738272cc70bSAndy Fleming 		switch (version) {
1739272cc70bSAndy Fleming 		case 0:
1740272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1741272cc70bSAndy Fleming 			break;
1742272cc70bSAndy Fleming 		case 1:
1743272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_4;
1744272cc70bSAndy Fleming 			break;
1745272cc70bSAndy Fleming 		case 2:
1746272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_2_2;
1747272cc70bSAndy Fleming 			break;
1748272cc70bSAndy Fleming 		case 3:
1749272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_3;
1750272cc70bSAndy Fleming 			break;
1751272cc70bSAndy Fleming 		case 4:
1752272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_4;
1753272cc70bSAndy Fleming 			break;
1754272cc70bSAndy Fleming 		default:
1755272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1756272cc70bSAndy Fleming 			break;
1757272cc70bSAndy Fleming 		}
1758272cc70bSAndy Fleming 	}
1759272cc70bSAndy Fleming 
1760272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
17610b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
17620b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
1763272cc70bSAndy Fleming 
176435f9e196SJean-Jacques Hiblot 	mmc->legacy_speed = freq * mult;
176535f9e196SJean-Jacques Hiblot 	mmc_select_mode(mmc, MMC_LEGACY);
1766272cc70bSAndy Fleming 
1767ab71188cSMarkus Niebel 	mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
1768998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
1769272cc70bSAndy Fleming 
1770272cc70bSAndy Fleming 	if (IS_SD(mmc))
1771272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
1772272cc70bSAndy Fleming 	else
1773998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
1774272cc70bSAndy Fleming 
1775272cc70bSAndy Fleming 	if (mmc->high_capacity) {
1776272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
1777272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
1778272cc70bSAndy Fleming 		cmult = 8;
1779272cc70bSAndy Fleming 	} else {
1780272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
1781272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
1782272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
1783272cc70bSAndy Fleming 	}
1784272cc70bSAndy Fleming 
1785f866a46dSStephen Warren 	mmc->capacity_user = (csize + 1) << (cmult + 2);
1786f866a46dSStephen Warren 	mmc->capacity_user *= mmc->read_bl_len;
1787f866a46dSStephen Warren 	mmc->capacity_boot = 0;
1788f866a46dSStephen Warren 	mmc->capacity_rpmb = 0;
1789f866a46dSStephen Warren 	for (i = 0; i < 4; i++)
1790f866a46dSStephen Warren 		mmc->capacity_gp[i] = 0;
1791272cc70bSAndy Fleming 
17928bfa195eSSimon Glass 	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
17938bfa195eSSimon Glass 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
1794272cc70bSAndy Fleming 
17958bfa195eSSimon Glass 	if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
17968bfa195eSSimon Glass 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
1797272cc70bSAndy Fleming 
1798ab71188cSMarkus Niebel 	if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
1799ab71188cSMarkus Niebel 		cmd.cmdidx = MMC_CMD_SET_DSR;
1800ab71188cSMarkus Niebel 		cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
1801ab71188cSMarkus Niebel 		cmd.resp_type = MMC_RSP_NONE;
1802ab71188cSMarkus Niebel 		if (mmc_send_cmd(mmc, &cmd, NULL))
1803ab71188cSMarkus Niebel 			printf("MMC: SET_DSR failed\n");
1804ab71188cSMarkus Niebel 	}
1805ab71188cSMarkus Niebel 
1806272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
1807d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1808272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
1809fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
1810272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1811272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1812272cc70bSAndy Fleming 
1813272cc70bSAndy Fleming 		if (err)
1814272cc70bSAndy Fleming 			return err;
1815d52ebf10SThomas Chou 	}
1816272cc70bSAndy Fleming 
1817e6f99a56SLei Wen 	/*
1818e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
1819e6f99a56SLei Wen 	 */
1820e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
1821bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
1822c744b6f6SJean-Jacques Hiblot 
1823dfda9d88SJean-Jacques Hiblot 	err = mmc_startup_v4(mmc);
18249cf199ebSDiego Santa Cruz 	if (err)
18259cf199ebSDiego Santa Cruz 		return err;
1826f866a46dSStephen Warren 
1827c40fdca6SSimon Glass 	err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart);
1828f866a46dSStephen Warren 	if (err)
1829f866a46dSStephen Warren 		return err;
1830d23e2c09SSukumar Ghorai 
1831272cc70bSAndy Fleming 	if (IS_SD(mmc))
1832d0c221feSJean-Jacques Hiblot 		err = sd_select_mode_and_width(mmc);
1833272cc70bSAndy Fleming 	else
18343862b854SJean-Jacques Hiblot 		err = mmc_select_mode_and_width(mmc);
1835272cc70bSAndy Fleming 
1836272cc70bSAndy Fleming 	if (err)
1837272cc70bSAndy Fleming 		return err;
1838272cc70bSAndy Fleming 
1839272cc70bSAndy Fleming 
18405af8f45cSAndrew Gabbasov 	/* Fix the block length for DDR mode */
18415af8f45cSAndrew Gabbasov 	if (mmc->ddr_mode) {
18425af8f45cSAndrew Gabbasov 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
18435af8f45cSAndrew Gabbasov 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
18445af8f45cSAndrew Gabbasov 	}
18455af8f45cSAndrew Gabbasov 
1846272cc70bSAndy Fleming 	/* fill in device description */
1847c40fdca6SSimon Glass 	bdesc = mmc_get_blk_desc(mmc);
1848c40fdca6SSimon Glass 	bdesc->lun = 0;
1849c40fdca6SSimon Glass 	bdesc->hwpart = 0;
1850c40fdca6SSimon Glass 	bdesc->type = 0;
1851c40fdca6SSimon Glass 	bdesc->blksz = mmc->read_bl_len;
1852c40fdca6SSimon Glass 	bdesc->log2blksz = LOG2(bdesc->blksz);
1853c40fdca6SSimon Glass 	bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len);
1854fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \
1855fc011f64SSjoerd Simons 		(defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \
1856fc011f64SSjoerd Simons 		!defined(CONFIG_USE_TINY_PRINTF))
1857c40fdca6SSimon Glass 	sprintf(bdesc->vendor, "Man %06x Snr %04x%04x",
1858babce5f6STaylor Hutt 		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
1859babce5f6STaylor Hutt 		(mmc->cid[3] >> 16) & 0xffff);
1860c40fdca6SSimon Glass 	sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
18610b453ffeSRabin Vincent 		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
1862babce5f6STaylor Hutt 		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
1863babce5f6STaylor Hutt 		(mmc->cid[2] >> 24) & 0xff);
1864c40fdca6SSimon Glass 	sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
1865babce5f6STaylor Hutt 		(mmc->cid[2] >> 16) & 0xf);
186656196826SPaul Burton #else
1867c40fdca6SSimon Glass 	bdesc->vendor[0] = 0;
1868c40fdca6SSimon Glass 	bdesc->product[0] = 0;
1869c40fdca6SSimon Glass 	bdesc->revision[0] = 0;
187056196826SPaul Burton #endif
1871122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
1872c40fdca6SSimon Glass 	part_init(bdesc);
1873122efd43SMikhail Kshevetskiy #endif
1874272cc70bSAndy Fleming 
1875272cc70bSAndy Fleming 	return 0;
1876272cc70bSAndy Fleming }
1877272cc70bSAndy Fleming 
1878fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc)
1879272cc70bSAndy Fleming {
1880272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1881272cc70bSAndy Fleming 	int err;
1882272cc70bSAndy Fleming 
1883272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
1884272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
188593bfd616SPantelis Antoniou 	cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa;
1886272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
1887272cc70bSAndy Fleming 
1888272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1889272cc70bSAndy Fleming 
1890272cc70bSAndy Fleming 	if (err)
1891272cc70bSAndy Fleming 		return err;
1892272cc70bSAndy Fleming 
1893998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
1894915ffa52SJaehoon Chung 		return -EOPNOTSUPP;
1895272cc70bSAndy Fleming 	else
1896272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
1897272cc70bSAndy Fleming 
1898272cc70bSAndy Fleming 	return 0;
1899272cc70bSAndy Fleming }
1900272cc70bSAndy Fleming 
1901c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
190295de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */
190395de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void)
190495de9ab2SPaul Kocialkowski {
190595de9ab2SPaul Kocialkowski }
190605cbeb7cSSimon Glass #endif
190795de9ab2SPaul Kocialkowski 
19082051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc)
19092051aefeSPeng Fan {
1910c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
191106ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR)
19122051aefeSPeng Fan 	int ret;
19132051aefeSPeng Fan 
19142051aefeSPeng Fan 	ret = device_get_supply_regulator(mmc->dev, "vmmc-supply",
191506ec045fSJean-Jacques Hiblot 					  &mmc->vmmc_supply);
191606ec045fSJean-Jacques Hiblot 	if (ret)
1917288db7c7SJaehoon Chung 		debug("%s: No vmmc supply\n", mmc->dev->name);
19182051aefeSPeng Fan 
191906ec045fSJean-Jacques Hiblot 	ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply",
192006ec045fSJean-Jacques Hiblot 					  &mmc->vqmmc_supply);
192106ec045fSJean-Jacques Hiblot 	if (ret)
192206ec045fSJean-Jacques Hiblot 		debug("%s: No vqmmc supply\n", mmc->dev->name);
192306ec045fSJean-Jacques Hiblot 
192406ec045fSJean-Jacques Hiblot 	if (mmc->vmmc_supply) {
192506ec045fSJean-Jacques Hiblot 		ret = regulator_set_enable(mmc->vmmc_supply, true);
19262051aefeSPeng Fan 		if (ret) {
19272051aefeSPeng Fan 			puts("Error enabling VMMC supply\n");
19282051aefeSPeng Fan 			return ret;
19292051aefeSPeng Fan 		}
193006ec045fSJean-Jacques Hiblot 	}
19312051aefeSPeng Fan #endif
193205cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */
193305cbeb7cSSimon Glass 	/*
193405cbeb7cSSimon Glass 	 * Driver model should use a regulator, as above, rather than calling
193505cbeb7cSSimon Glass 	 * out to board code.
193605cbeb7cSSimon Glass 	 */
193705cbeb7cSSimon Glass 	board_mmc_power_init();
193805cbeb7cSSimon Glass #endif
19392051aefeSPeng Fan 	return 0;
19402051aefeSPeng Fan }
19412051aefeSPeng Fan 
1942e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc)
1943272cc70bSAndy Fleming {
19448ca51e51SSimon Glass 	bool no_card;
1945afd5932bSMacpaul Lin 	int err;
1946272cc70bSAndy Fleming 
1947ab769f22SPantelis Antoniou 	/* we pretend there's no card when init is NULL */
19488ca51e51SSimon Glass 	no_card = mmc_getcd(mmc) == 0;
1949e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
19508ca51e51SSimon Glass 	no_card = no_card || (mmc->cfg->ops->init == NULL);
19518ca51e51SSimon Glass #endif
19528ca51e51SSimon Glass 	if (no_card) {
195348972d90SThierry Reding 		mmc->has_init = 0;
195456196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
195548972d90SThierry Reding 		printf("MMC: no card present\n");
195656196826SPaul Burton #endif
1957915ffa52SJaehoon Chung 		return -ENOMEDIUM;
195848972d90SThierry Reding 	}
195948972d90SThierry Reding 
1960bc897b1dSLei Wen 	if (mmc->has_init)
1961bc897b1dSLei Wen 		return 0;
1962bc897b1dSLei Wen 
19635a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
19645a8dbdc6SYangbo Lu 	mmc_adapter_card_type_ident();
19655a8dbdc6SYangbo Lu #endif
19662051aefeSPeng Fan 	err = mmc_power_init(mmc);
19672051aefeSPeng Fan 	if (err)
19682051aefeSPeng Fan 		return err;
196995de9ab2SPaul Kocialkowski 
1970e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
19718ca51e51SSimon Glass 	/* The device has already been probed ready for use */
19728ca51e51SSimon Glass #else
1973ab769f22SPantelis Antoniou 	/* made sure it's not NULL earlier */
197493bfd616SPantelis Antoniou 	err = mmc->cfg->ops->init(mmc);
1975272cc70bSAndy Fleming 	if (err)
1976272cc70bSAndy Fleming 		return err;
19778ca51e51SSimon Glass #endif
1978786e8f81SAndrew Gabbasov 	mmc->ddr_mode = 0;
1979aff5d3c8SKishon Vijay Abraham I 
1980aff5d3c8SKishon Vijay Abraham I 	/* First try to set 3.3V. If it fails set to 1.8V */
1981aff5d3c8SKishon Vijay Abraham I 	err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_330);
1982aff5d3c8SKishon Vijay Abraham I 	if (err != 0)
1983aff5d3c8SKishon Vijay Abraham I 		err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_180);
1984aff5d3c8SKishon Vijay Abraham I 	if (err != 0)
1985aff5d3c8SKishon Vijay Abraham I 		printf("failed to set signal voltage\n");
1986aff5d3c8SKishon Vijay Abraham I 
1987b86b85e2SIlya Yanok 	mmc_set_bus_width(mmc, 1);
1988b86b85e2SIlya Yanok 	mmc_set_clock(mmc, 1);
1989b86b85e2SIlya Yanok 
1990*318a7a57SJean-Jacques Hiblot 	mmc_send_init_stream(mmc);
1991*318a7a57SJean-Jacques Hiblot 
1992272cc70bSAndy Fleming 	/* Reset the Card */
1993272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
1994272cc70bSAndy Fleming 
1995272cc70bSAndy Fleming 	if (err)
1996272cc70bSAndy Fleming 		return err;
1997272cc70bSAndy Fleming 
1998bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
1999c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->hwpart = 0;
2000bc897b1dSLei Wen 
2001272cc70bSAndy Fleming 	/* Test for SD version 2 */
2002272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
2003272cc70bSAndy Fleming 
2004272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
2005272cc70bSAndy Fleming 	err = sd_send_op_cond(mmc);
2006272cc70bSAndy Fleming 
2007272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
2008915ffa52SJaehoon Chung 	if (err == -ETIMEDOUT) {
2009272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
2010272cc70bSAndy Fleming 
2011bd47c135SAndrew Gabbasov 		if (err) {
201256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2013272cc70bSAndy Fleming 			printf("Card did not respond to voltage select!\n");
201456196826SPaul Burton #endif
2015915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
2016272cc70bSAndy Fleming 		}
2017272cc70bSAndy Fleming 	}
2018272cc70bSAndy Fleming 
2019bd47c135SAndrew Gabbasov 	if (!err)
2020e9550449SChe-Liang Chiou 		mmc->init_in_progress = 1;
2021e9550449SChe-Liang Chiou 
2022e9550449SChe-Liang Chiou 	return err;
2023e9550449SChe-Liang Chiou }
2024e9550449SChe-Liang Chiou 
2025e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc)
2026e9550449SChe-Liang Chiou {
2027e9550449SChe-Liang Chiou 	int err = 0;
2028e9550449SChe-Liang Chiou 
2029bd47c135SAndrew Gabbasov 	mmc->init_in_progress = 0;
2030e9550449SChe-Liang Chiou 	if (mmc->op_cond_pending)
2031e9550449SChe-Liang Chiou 		err = mmc_complete_op_cond(mmc);
2032e9550449SChe-Liang Chiou 
2033e9550449SChe-Liang Chiou 	if (!err)
2034bc897b1dSLei Wen 		err = mmc_startup(mmc);
2035bc897b1dSLei Wen 	if (err)
2036bc897b1dSLei Wen 		mmc->has_init = 0;
2037bc897b1dSLei Wen 	else
2038bc897b1dSLei Wen 		mmc->has_init = 1;
2039e9550449SChe-Liang Chiou 	return err;
2040e9550449SChe-Liang Chiou }
2041e9550449SChe-Liang Chiou 
2042e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc)
2043e9550449SChe-Liang Chiou {
2044bd47c135SAndrew Gabbasov 	int err = 0;
2045ce9eca94SMarek Vasut 	__maybe_unused unsigned start;
2046c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
204733fb211dSSimon Glass 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev);
2048e9550449SChe-Liang Chiou 
204933fb211dSSimon Glass 	upriv->mmc = mmc;
205033fb211dSSimon Glass #endif
2051e9550449SChe-Liang Chiou 	if (mmc->has_init)
2052e9550449SChe-Liang Chiou 		return 0;
2053d803fea5SMateusz Zalega 
2054d803fea5SMateusz Zalega 	start = get_timer(0);
2055d803fea5SMateusz Zalega 
2056e9550449SChe-Liang Chiou 	if (!mmc->init_in_progress)
2057e9550449SChe-Liang Chiou 		err = mmc_start_init(mmc);
2058e9550449SChe-Liang Chiou 
2059bd47c135SAndrew Gabbasov 	if (!err)
2060e9550449SChe-Liang Chiou 		err = mmc_complete_init(mmc);
2061919b4858SJagan Teki 	if (err)
2062919b4858SJagan Teki 		printf("%s: %d, time %lu\n", __func__, err, get_timer(start));
2063919b4858SJagan Teki 
2064bc897b1dSLei Wen 	return err;
2065272cc70bSAndy Fleming }
2066272cc70bSAndy Fleming 
2067ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val)
2068ab71188cSMarkus Niebel {
2069ab71188cSMarkus Niebel 	mmc->dsr = val;
2070ab71188cSMarkus Niebel 	return 0;
2071ab71188cSMarkus Niebel }
2072ab71188cSMarkus Niebel 
2073cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */
2074cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis)
2075272cc70bSAndy Fleming {
2076272cc70bSAndy Fleming 	return -1;
2077272cc70bSAndy Fleming }
2078272cc70bSAndy Fleming 
2079cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */
2080cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis)
2081cee9ab7cSJeroen Hofstee {
2082cee9ab7cSJeroen Hofstee 	return -1;
2083cee9ab7cSJeroen Hofstee }
2084272cc70bSAndy Fleming 
2085e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit)
2086e9550449SChe-Liang Chiou {
2087e9550449SChe-Liang Chiou 	mmc->preinit = preinit;
2088e9550449SChe-Liang Chiou }
2089e9550449SChe-Liang Chiou 
2090c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD)
20918e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
20928e3332e2SSjoerd Simons {
20938e3332e2SSjoerd Simons 	return 0;
20948e3332e2SSjoerd Simons }
2095c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC)
20968e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
20978e3332e2SSjoerd Simons {
20984a1db6d8SSimon Glass 	int ret, i;
20998e3332e2SSjoerd Simons 	struct uclass *uc;
21004a1db6d8SSimon Glass 	struct udevice *dev;
21018e3332e2SSjoerd Simons 
21028e3332e2SSjoerd Simons 	ret = uclass_get(UCLASS_MMC, &uc);
21038e3332e2SSjoerd Simons 	if (ret)
21048e3332e2SSjoerd Simons 		return ret;
21058e3332e2SSjoerd Simons 
21064a1db6d8SSimon Glass 	/*
21074a1db6d8SSimon Glass 	 * Try to add them in sequence order. Really with driver model we
21084a1db6d8SSimon Glass 	 * should allow holes, but the current MMC list does not allow that.
21094a1db6d8SSimon Glass 	 * So if we request 0, 1, 3 we will get 0, 1, 2.
21104a1db6d8SSimon Glass 	 */
21114a1db6d8SSimon Glass 	for (i = 0; ; i++) {
21124a1db6d8SSimon Glass 		ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev);
21134a1db6d8SSimon Glass 		if (ret == -ENODEV)
21144a1db6d8SSimon Glass 			break;
21154a1db6d8SSimon Glass 	}
21164a1db6d8SSimon Glass 	uclass_foreach_dev(dev, uc) {
21174a1db6d8SSimon Glass 		ret = device_probe(dev);
21188e3332e2SSjoerd Simons 		if (ret)
21194a1db6d8SSimon Glass 			printf("%s - probe failed: %d\n", dev->name, ret);
21208e3332e2SSjoerd Simons 	}
21218e3332e2SSjoerd Simons 
21228e3332e2SSjoerd Simons 	return 0;
21238e3332e2SSjoerd Simons }
21248e3332e2SSjoerd Simons #else
21258e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
21268e3332e2SSjoerd Simons {
21278e3332e2SSjoerd Simons 	if (board_mmc_init(bis) < 0)
21288e3332e2SSjoerd Simons 		cpu_mmc_init(bis);
21298e3332e2SSjoerd Simons 
21308e3332e2SSjoerd Simons 	return 0;
21318e3332e2SSjoerd Simons }
21328e3332e2SSjoerd Simons #endif
2133e9550449SChe-Liang Chiou 
2134272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
2135272cc70bSAndy Fleming {
21361b26bab1SDaniel Kochmański 	static int initialized = 0;
21378e3332e2SSjoerd Simons 	int ret;
21381b26bab1SDaniel Kochmański 	if (initialized)	/* Avoid initializing mmc multiple times */
21391b26bab1SDaniel Kochmański 		return 0;
21401b26bab1SDaniel Kochmański 	initialized = 1;
21411b26bab1SDaniel Kochmański 
2142c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK)
2143b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY)
2144c40fdca6SSimon Glass 	mmc_list_init();
2145c40fdca6SSimon Glass #endif
2146b5b838f1SMarek Vasut #endif
21478e3332e2SSjoerd Simons 	ret = mmc_probe(bis);
21488e3332e2SSjoerd Simons 	if (ret)
21498e3332e2SSjoerd Simons 		return ret;
2150272cc70bSAndy Fleming 
2151bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD
2152272cc70bSAndy Fleming 	print_mmc_devices(',');
2153bb0dc108SYing Zhang #endif
2154272cc70bSAndy Fleming 
2155c40fdca6SSimon Glass 	mmc_do_preinit();
2156272cc70bSAndy Fleming 	return 0;
2157272cc70bSAndy Fleming }
2158cd3d4880STomas Melin 
2159cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE
2160cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc)
2161cd3d4880STomas Melin {
2162cd3d4880STomas Melin 	int err;
2163cd3d4880STomas Melin 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
2164cd3d4880STomas Melin 
2165cd3d4880STomas Melin 	err = mmc_send_ext_csd(mmc, ext_csd);
2166cd3d4880STomas Melin 	if (err) {
2167cd3d4880STomas Melin 		puts("Could not get ext_csd register values\n");
2168cd3d4880STomas Melin 		return err;
2169cd3d4880STomas Melin 	}
2170cd3d4880STomas Melin 
2171cd3d4880STomas Melin 	if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) {
2172cd3d4880STomas Melin 		puts("Background operations not supported on device\n");
2173cd3d4880STomas Melin 		return -EMEDIUMTYPE;
2174cd3d4880STomas Melin 	}
2175cd3d4880STomas Melin 
2176cd3d4880STomas Melin 	if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) {
2177cd3d4880STomas Melin 		puts("Background operations already enabled\n");
2178cd3d4880STomas Melin 		return 0;
2179cd3d4880STomas Melin 	}
2180cd3d4880STomas Melin 
2181cd3d4880STomas Melin 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1);
2182cd3d4880STomas Melin 	if (err) {
2183cd3d4880STomas Melin 		puts("Failed to enable manual background operations\n");
2184cd3d4880STomas Melin 		return err;
2185cd3d4880STomas Melin 	}
2186cd3d4880STomas Melin 
2187cd3d4880STomas Melin 	puts("Enabled manual background operations\n");
2188cd3d4880STomas Melin 
2189cd3d4880STomas Melin 	return 0;
2190cd3d4880STomas Melin }
2191cd3d4880STomas Melin #endif
2192