xref: /openbmc/u-boot/drivers/mmc/mmc.c (revision aff5d3c83fb8c294b3c4b97c5b6386306b47f1a0)
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 
33*aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage);
34*aff5d3c8SKishon 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)
12012a4d212fSKishon Vijay Abraham I static int mmc_set_ios(struct mmc *mmc)
1202272cc70bSAndy Fleming {
12032a4d212fSKishon Vijay Abraham I 	int ret = 0;
12042a4d212fSKishon Vijay Abraham I 
120593bfd616SPantelis Antoniou 	if (mmc->cfg->ops->set_ios)
12062a4d212fSKishon Vijay Abraham I 		ret = mmc->cfg->ops->set_ios(mmc);
12072a4d212fSKishon Vijay Abraham I 
12082a4d212fSKishon Vijay Abraham I 	return ret;
1209272cc70bSAndy Fleming }
12108ca51e51SSimon Glass #endif
1211272cc70bSAndy Fleming 
12122a4d212fSKishon Vijay Abraham I int mmc_set_clock(struct mmc *mmc, uint clock)
1213272cc70bSAndy Fleming {
121493bfd616SPantelis Antoniou 	if (clock > mmc->cfg->f_max)
121593bfd616SPantelis Antoniou 		clock = mmc->cfg->f_max;
1216272cc70bSAndy Fleming 
121793bfd616SPantelis Antoniou 	if (clock < mmc->cfg->f_min)
121893bfd616SPantelis Antoniou 		clock = mmc->cfg->f_min;
1219272cc70bSAndy Fleming 
1220272cc70bSAndy Fleming 	mmc->clock = clock;
1221272cc70bSAndy Fleming 
12222a4d212fSKishon Vijay Abraham I 	return mmc_set_ios(mmc);
1223272cc70bSAndy Fleming }
1224272cc70bSAndy Fleming 
12252a4d212fSKishon Vijay Abraham I static int mmc_set_bus_width(struct mmc *mmc, uint width)
1226272cc70bSAndy Fleming {
1227272cc70bSAndy Fleming 	mmc->bus_width = width;
1228272cc70bSAndy Fleming 
12292a4d212fSKishon Vijay Abraham I 	return mmc_set_ios(mmc);
1230272cc70bSAndy Fleming }
1231272cc70bSAndy Fleming 
12324c9d2aaaSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG)
12334c9d2aaaSJean-Jacques Hiblot /*
12344c9d2aaaSJean-Jacques Hiblot  * helper function to display the capabilities in a human
12354c9d2aaaSJean-Jacques Hiblot  * friendly manner. The capabilities include bus width and
12364c9d2aaaSJean-Jacques Hiblot  * supported modes.
12374c9d2aaaSJean-Jacques Hiblot  */
12384c9d2aaaSJean-Jacques Hiblot void mmc_dump_capabilities(const char *text, uint caps)
12394c9d2aaaSJean-Jacques Hiblot {
12404c9d2aaaSJean-Jacques Hiblot 	enum bus_mode mode;
12414c9d2aaaSJean-Jacques Hiblot 
12424c9d2aaaSJean-Jacques Hiblot 	printf("%s: widths [", text);
12434c9d2aaaSJean-Jacques Hiblot 	if (caps & MMC_MODE_8BIT)
12444c9d2aaaSJean-Jacques Hiblot 		printf("8, ");
12454c9d2aaaSJean-Jacques Hiblot 	if (caps & MMC_MODE_4BIT)
12464c9d2aaaSJean-Jacques Hiblot 		printf("4, ");
1247d0c221feSJean-Jacques Hiblot 	if (caps & MMC_MODE_1BIT)
1248d0c221feSJean-Jacques Hiblot 		printf("1, ");
1249d0c221feSJean-Jacques Hiblot 	printf("\b\b] modes [");
12504c9d2aaaSJean-Jacques Hiblot 	for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++)
12514c9d2aaaSJean-Jacques Hiblot 		if (MMC_CAP(mode) & caps)
12524c9d2aaaSJean-Jacques Hiblot 			printf("%s, ", mmc_mode_name(mode));
12534c9d2aaaSJean-Jacques Hiblot 	printf("\b\b]\n");
12544c9d2aaaSJean-Jacques Hiblot }
12554c9d2aaaSJean-Jacques Hiblot #endif
12564c9d2aaaSJean-Jacques Hiblot 
1257d0c221feSJean-Jacques Hiblot struct mode_width_tuning {
1258d0c221feSJean-Jacques Hiblot 	enum bus_mode mode;
1259d0c221feSJean-Jacques Hiblot 	uint widths;
1260d0c221feSJean-Jacques Hiblot };
1261d0c221feSJean-Jacques Hiblot 
1262*aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage)
1263*aff5d3c8SKishon Vijay Abraham I {
1264*aff5d3c8SKishon Vijay Abraham I 	mmc->signal_voltage = signal_voltage;
1265*aff5d3c8SKishon Vijay Abraham I 	return mmc_set_ios(mmc);
1266*aff5d3c8SKishon Vijay Abraham I }
1267*aff5d3c8SKishon Vijay Abraham I 
1268d0c221feSJean-Jacques Hiblot static const struct mode_width_tuning sd_modes_by_pref[] = {
1269d0c221feSJean-Jacques Hiblot 	{
1270d0c221feSJean-Jacques Hiblot 		.mode = SD_HS,
1271d0c221feSJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1272d0c221feSJean-Jacques Hiblot 	},
1273d0c221feSJean-Jacques Hiblot 	{
1274d0c221feSJean-Jacques Hiblot 		.mode = SD_LEGACY,
1275d0c221feSJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1276d0c221feSJean-Jacques Hiblot 	}
1277d0c221feSJean-Jacques Hiblot };
1278d0c221feSJean-Jacques Hiblot 
1279d0c221feSJean-Jacques Hiblot #define for_each_sd_mode_by_pref(caps, mwt) \
1280d0c221feSJean-Jacques Hiblot 	for (mwt = sd_modes_by_pref;\
1281d0c221feSJean-Jacques Hiblot 	     mwt < sd_modes_by_pref + ARRAY_SIZE(sd_modes_by_pref);\
1282d0c221feSJean-Jacques Hiblot 	     mwt++) \
1283d0c221feSJean-Jacques Hiblot 		if (caps & MMC_CAP(mwt->mode))
1284d0c221feSJean-Jacques Hiblot 
1285d0c221feSJean-Jacques Hiblot static int sd_select_mode_and_width(struct mmc *mmc)
12868ac8a263SJean-Jacques Hiblot {
12878ac8a263SJean-Jacques Hiblot 	int err;
1288d0c221feSJean-Jacques Hiblot 	uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT};
1289d0c221feSJean-Jacques Hiblot 	const struct mode_width_tuning *mwt;
12908ac8a263SJean-Jacques Hiblot 
1291d0c221feSJean-Jacques Hiblot 	err = sd_get_capabilities(mmc);
12928ac8a263SJean-Jacques Hiblot 	if (err)
12938ac8a263SJean-Jacques Hiblot 		return err;
12948ac8a263SJean-Jacques Hiblot 	/* Restrict card's capabilities by what the host can do */
1295d0c221feSJean-Jacques Hiblot 	mmc->card_caps &= (mmc->cfg->host_caps | MMC_MODE_1BIT);
12968ac8a263SJean-Jacques Hiblot 
1297d0c221feSJean-Jacques Hiblot 	for_each_sd_mode_by_pref(mmc->card_caps, mwt) {
1298d0c221feSJean-Jacques Hiblot 		uint *w;
12998ac8a263SJean-Jacques Hiblot 
1300d0c221feSJean-Jacques Hiblot 		for (w = widths; w < widths + ARRAY_SIZE(widths); w++) {
1301d0c221feSJean-Jacques Hiblot 			if (*w & mmc->card_caps & mwt->widths) {
1302d0c221feSJean-Jacques Hiblot 				debug("trying mode %s width %d (at %d MHz)\n",
1303d0c221feSJean-Jacques Hiblot 				      mmc_mode_name(mwt->mode),
1304d0c221feSJean-Jacques Hiblot 				      bus_width(*w),
1305d0c221feSJean-Jacques Hiblot 				      mmc_mode2freq(mmc, mwt->mode) / 1000000);
1306d0c221feSJean-Jacques Hiblot 
1307d0c221feSJean-Jacques Hiblot 				/* configure the bus width (card + host) */
1308d0c221feSJean-Jacques Hiblot 				err = sd_select_bus_width(mmc, bus_width(*w));
13098ac8a263SJean-Jacques Hiblot 				if (err)
1310d0c221feSJean-Jacques Hiblot 					goto error;
1311d0c221feSJean-Jacques Hiblot 				mmc_set_bus_width(mmc, bus_width(*w));
13128ac8a263SJean-Jacques Hiblot 
1313d0c221feSJean-Jacques Hiblot 				/* configure the bus mode (card) */
1314d0c221feSJean-Jacques Hiblot 				err = sd_set_card_speed(mmc, mwt->mode);
13158ac8a263SJean-Jacques Hiblot 				if (err)
1316d0c221feSJean-Jacques Hiblot 					goto error;
13178ac8a263SJean-Jacques Hiblot 
1318d0c221feSJean-Jacques Hiblot 				/* configure the bus mode (host) */
1319d0c221feSJean-Jacques Hiblot 				mmc_select_mode(mmc, mwt->mode);
1320d0c221feSJean-Jacques Hiblot 				mmc_set_clock(mmc, mmc->tran_speed);
13218ac8a263SJean-Jacques Hiblot 
13228ac8a263SJean-Jacques Hiblot 				err = sd_read_ssr(mmc);
1323d0c221feSJean-Jacques Hiblot 				if (!err)
13248ac8a263SJean-Jacques Hiblot 					return 0;
1325d0c221feSJean-Jacques Hiblot 
1326d0c221feSJean-Jacques Hiblot 				printf("bad ssr\n");
1327d0c221feSJean-Jacques Hiblot 
1328d0c221feSJean-Jacques Hiblot error:
1329d0c221feSJean-Jacques Hiblot 				/* revert to a safer bus speed */
1330d0c221feSJean-Jacques Hiblot 				mmc_select_mode(mmc, SD_LEGACY);
1331d0c221feSJean-Jacques Hiblot 				mmc_set_clock(mmc, mmc->tran_speed);
1332d0c221feSJean-Jacques Hiblot 			}
1333d0c221feSJean-Jacques Hiblot 		}
1334d0c221feSJean-Jacques Hiblot 	}
1335d0c221feSJean-Jacques Hiblot 
1336d0c221feSJean-Jacques Hiblot 	printf("unable to select a mode\n");
1337d0c221feSJean-Jacques Hiblot 	return -ENOTSUPP;
13388ac8a263SJean-Jacques Hiblot }
13398ac8a263SJean-Jacques Hiblot 
13407382e691SJean-Jacques Hiblot /*
13417382e691SJean-Jacques Hiblot  * read the compare the part of ext csd that is constant.
13427382e691SJean-Jacques Hiblot  * This can be used to check that the transfer is working
13437382e691SJean-Jacques Hiblot  * as expected.
13447382e691SJean-Jacques Hiblot  */
13457382e691SJean-Jacques Hiblot static int mmc_read_and_compare_ext_csd(struct mmc *mmc)
13467382e691SJean-Jacques Hiblot {
13477382e691SJean-Jacques Hiblot 	int err;
13487382e691SJean-Jacques Hiblot 	const u8 *ext_csd = mmc->ext_csd;
13497382e691SJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
13507382e691SJean-Jacques Hiblot 
13517382e691SJean-Jacques Hiblot 	err = mmc_send_ext_csd(mmc, test_csd);
13527382e691SJean-Jacques Hiblot 	if (err)
13537382e691SJean-Jacques Hiblot 		return err;
13547382e691SJean-Jacques Hiblot 
13557382e691SJean-Jacques Hiblot 	/* Only compare read only fields */
13567382e691SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT]
13577382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_PARTITIONING_SUPPORT] &&
13587382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_HC_WP_GRP_SIZE]
13597382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_HC_WP_GRP_SIZE] &&
13607382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_REV]
13617382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_REV] &&
13627382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
13637382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] &&
13647382e691SJean-Jacques Hiblot 	    memcmp(&ext_csd[EXT_CSD_SEC_CNT],
13657382e691SJean-Jacques Hiblot 		   &test_csd[EXT_CSD_SEC_CNT], 4) == 0)
13667382e691SJean-Jacques Hiblot 		return 0;
13677382e691SJean-Jacques Hiblot 
13687382e691SJean-Jacques Hiblot 	return -EBADMSG;
13697382e691SJean-Jacques Hiblot }
13707382e691SJean-Jacques Hiblot 
13713862b854SJean-Jacques Hiblot static const struct mode_width_tuning mmc_modes_by_pref[] = {
13728ac8a263SJean-Jacques Hiblot 	{
13733862b854SJean-Jacques Hiblot 		.mode = MMC_HS_200,
13743862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
13753862b854SJean-Jacques Hiblot 	},
13763862b854SJean-Jacques Hiblot 	{
13773862b854SJean-Jacques Hiblot 		.mode = MMC_DDR_52,
13783862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
13793862b854SJean-Jacques Hiblot 	},
13803862b854SJean-Jacques Hiblot 	{
13813862b854SJean-Jacques Hiblot 		.mode = MMC_HS_52,
13823862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
13833862b854SJean-Jacques Hiblot 	},
13843862b854SJean-Jacques Hiblot 	{
13853862b854SJean-Jacques Hiblot 		.mode = MMC_HS,
13863862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
13873862b854SJean-Jacques Hiblot 	},
13883862b854SJean-Jacques Hiblot 	{
13893862b854SJean-Jacques Hiblot 		.mode = MMC_LEGACY,
13903862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
13913862b854SJean-Jacques Hiblot 	}
13928ac8a263SJean-Jacques Hiblot };
13938ac8a263SJean-Jacques Hiblot 
13943862b854SJean-Jacques Hiblot #define for_each_mmc_mode_by_pref(caps, mwt) \
13953862b854SJean-Jacques Hiblot 	for (mwt = mmc_modes_by_pref;\
13963862b854SJean-Jacques Hiblot 	    mwt < mmc_modes_by_pref + ARRAY_SIZE(mmc_modes_by_pref);\
13973862b854SJean-Jacques Hiblot 	    mwt++) \
13983862b854SJean-Jacques Hiblot 		if (caps & MMC_CAP(mwt->mode))
13993862b854SJean-Jacques Hiblot 
14003862b854SJean-Jacques Hiblot static const struct ext_csd_bus_width {
14013862b854SJean-Jacques Hiblot 	uint cap;
14023862b854SJean-Jacques Hiblot 	bool is_ddr;
14033862b854SJean-Jacques Hiblot 	uint ext_csd_bits;
14043862b854SJean-Jacques Hiblot } ext_csd_bus_width[] = {
14053862b854SJean-Jacques Hiblot 	{MMC_MODE_8BIT, true, EXT_CSD_DDR_BUS_WIDTH_8},
14063862b854SJean-Jacques Hiblot 	{MMC_MODE_4BIT, true, EXT_CSD_DDR_BUS_WIDTH_4},
14073862b854SJean-Jacques Hiblot 	{MMC_MODE_8BIT, false, EXT_CSD_BUS_WIDTH_8},
14083862b854SJean-Jacques Hiblot 	{MMC_MODE_4BIT, false, EXT_CSD_BUS_WIDTH_4},
14093862b854SJean-Jacques Hiblot 	{MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1},
14103862b854SJean-Jacques Hiblot };
14113862b854SJean-Jacques Hiblot 
14123862b854SJean-Jacques Hiblot #define for_each_supported_width(caps, ddr, ecbv) \
14133862b854SJean-Jacques Hiblot 	for (ecbv = ext_csd_bus_width;\
14143862b854SJean-Jacques Hiblot 	    ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\
14153862b854SJean-Jacques Hiblot 	    ecbv++) \
14163862b854SJean-Jacques Hiblot 		if ((ddr == ecbv->is_ddr) && (caps & ecbv->cap))
14173862b854SJean-Jacques Hiblot 
14183862b854SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc)
14193862b854SJean-Jacques Hiblot {
14203862b854SJean-Jacques Hiblot 	int err;
14213862b854SJean-Jacques Hiblot 	const struct mode_width_tuning *mwt;
14223862b854SJean-Jacques Hiblot 	const struct ext_csd_bus_width *ecbw;
14233862b854SJean-Jacques Hiblot 
14243862b854SJean-Jacques Hiblot 	err = mmc_get_capabilities(mmc);
14258ac8a263SJean-Jacques Hiblot 	if (err)
14268ac8a263SJean-Jacques Hiblot 		return err;
14278ac8a263SJean-Jacques Hiblot 
14288ac8a263SJean-Jacques Hiblot 	/* Restrict card's capabilities by what the host can do */
1429d0c221feSJean-Jacques Hiblot 	mmc->card_caps &= (mmc->cfg->host_caps | MMC_MODE_1BIT);
14308ac8a263SJean-Jacques Hiblot 
14318ac8a263SJean-Jacques Hiblot 	/* Only version 4 of MMC supports wider bus widths */
14328ac8a263SJean-Jacques Hiblot 	if (mmc->version < MMC_VERSION_4)
14338ac8a263SJean-Jacques Hiblot 		return 0;
14348ac8a263SJean-Jacques Hiblot 
1435dfda9d88SJean-Jacques Hiblot 	if (!mmc->ext_csd) {
1436dfda9d88SJean-Jacques Hiblot 		debug("No ext_csd found!\n"); /* this should enver happen */
1437dfda9d88SJean-Jacques Hiblot 		return -ENOTSUPP;
1438dfda9d88SJean-Jacques Hiblot 	}
1439dfda9d88SJean-Jacques Hiblot 
14403862b854SJean-Jacques Hiblot 	for_each_mmc_mode_by_pref(mmc->card_caps, mwt) {
14413862b854SJean-Jacques Hiblot 		for_each_supported_width(mmc->card_caps & mwt->widths,
14423862b854SJean-Jacques Hiblot 					 mmc_is_mode_ddr(mwt->mode), ecbw) {
14433862b854SJean-Jacques Hiblot 			debug("trying mode %s width %d (at %d MHz)\n",
14443862b854SJean-Jacques Hiblot 			      mmc_mode_name(mwt->mode),
14453862b854SJean-Jacques Hiblot 			      bus_width(ecbw->cap),
14463862b854SJean-Jacques Hiblot 			      mmc_mode2freq(mmc, mwt->mode) / 1000000);
14473862b854SJean-Jacques Hiblot 			/* configure the bus width (card + host) */
14483862b854SJean-Jacques Hiblot 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
14493862b854SJean-Jacques Hiblot 				    EXT_CSD_BUS_WIDTH,
14503862b854SJean-Jacques Hiblot 				    ecbw->ext_csd_bits & ~EXT_CSD_DDR_FLAG);
14513862b854SJean-Jacques Hiblot 			if (err)
14523862b854SJean-Jacques Hiblot 				goto error;
14533862b854SJean-Jacques Hiblot 			mmc_set_bus_width(mmc, bus_width(ecbw->cap));
14543862b854SJean-Jacques Hiblot 
14553862b854SJean-Jacques Hiblot 			/* configure the bus speed (card) */
14563862b854SJean-Jacques Hiblot 			err = mmc_set_card_speed(mmc, mwt->mode);
14573862b854SJean-Jacques Hiblot 			if (err)
14583862b854SJean-Jacques Hiblot 				goto error;
14593862b854SJean-Jacques Hiblot 
14608ac8a263SJean-Jacques Hiblot 			/*
14613862b854SJean-Jacques Hiblot 			 * configure the bus width AND the ddr mode (card)
14623862b854SJean-Jacques Hiblot 			 * The host side will be taken care of in the next step
14638ac8a263SJean-Jacques Hiblot 			 */
14643862b854SJean-Jacques Hiblot 			if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) {
14653862b854SJean-Jacques Hiblot 				err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
14663862b854SJean-Jacques Hiblot 						 EXT_CSD_BUS_WIDTH,
14673862b854SJean-Jacques Hiblot 						 ecbw->ext_csd_bits);
14683862b854SJean-Jacques Hiblot 				if (err)
14693862b854SJean-Jacques Hiblot 					goto error;
14708ac8a263SJean-Jacques Hiblot 			}
14718ac8a263SJean-Jacques Hiblot 
14723862b854SJean-Jacques Hiblot 			/* configure the bus mode (host) */
14733862b854SJean-Jacques Hiblot 			mmc_select_mode(mmc, mwt->mode);
14743862b854SJean-Jacques Hiblot 			mmc_set_clock(mmc, mmc->tran_speed);
14758ac8a263SJean-Jacques Hiblot 
14763862b854SJean-Jacques Hiblot 			/* do a transfer to check the configuration */
14777382e691SJean-Jacques Hiblot 			err = mmc_read_and_compare_ext_csd(mmc);
14787382e691SJean-Jacques Hiblot 			if (!err)
14793862b854SJean-Jacques Hiblot 				return 0;
14803862b854SJean-Jacques Hiblot error:
14813862b854SJean-Jacques Hiblot 			/* if an error occured, revert to a safer bus mode */
14823862b854SJean-Jacques Hiblot 			mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
14833862b854SJean-Jacques Hiblot 				   EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1);
14843862b854SJean-Jacques Hiblot 			mmc_select_mode(mmc, MMC_LEGACY);
14853862b854SJean-Jacques Hiblot 			mmc_set_bus_width(mmc, 1);
14863862b854SJean-Jacques Hiblot 		}
14878ac8a263SJean-Jacques Hiblot 	}
14888ac8a263SJean-Jacques Hiblot 
14893862b854SJean-Jacques Hiblot 	printf("unable to select a mode\n");
14908ac8a263SJean-Jacques Hiblot 
14913862b854SJean-Jacques Hiblot 	return -ENOTSUPP;
14928ac8a263SJean-Jacques Hiblot }
14938ac8a263SJean-Jacques Hiblot 
1494dfda9d88SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc)
1495c744b6f6SJean-Jacques Hiblot {
1496c744b6f6SJean-Jacques Hiblot 	int err, i;
1497c744b6f6SJean-Jacques Hiblot 	u64 capacity;
1498c744b6f6SJean-Jacques Hiblot 	bool has_parts = false;
1499c744b6f6SJean-Jacques Hiblot 	bool part_completed;
1500dfda9d88SJean-Jacques Hiblot 	u8 *ext_csd;
1501c744b6f6SJean-Jacques Hiblot 
1502c744b6f6SJean-Jacques Hiblot 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4))
1503c744b6f6SJean-Jacques Hiblot 		return 0;
1504c744b6f6SJean-Jacques Hiblot 
1505dfda9d88SJean-Jacques Hiblot 	ext_csd = malloc_cache_aligned(MMC_MAX_BLOCK_LEN);
1506dfda9d88SJean-Jacques Hiblot 	if (!ext_csd)
1507dfda9d88SJean-Jacques Hiblot 		return -ENOMEM;
1508dfda9d88SJean-Jacques Hiblot 
1509dfda9d88SJean-Jacques Hiblot 	mmc->ext_csd = ext_csd;
1510dfda9d88SJean-Jacques Hiblot 
1511c744b6f6SJean-Jacques Hiblot 	/* check  ext_csd version and capacity */
1512c744b6f6SJean-Jacques Hiblot 	err = mmc_send_ext_csd(mmc, ext_csd);
1513c744b6f6SJean-Jacques Hiblot 	if (err)
1514c744b6f6SJean-Jacques Hiblot 		return err;
1515c744b6f6SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_REV] >= 2) {
1516c744b6f6SJean-Jacques Hiblot 		/*
1517c744b6f6SJean-Jacques Hiblot 		 * According to the JEDEC Standard, the value of
1518c744b6f6SJean-Jacques Hiblot 		 * ext_csd's capacity is valid if the value is more
1519c744b6f6SJean-Jacques Hiblot 		 * than 2GB
1520c744b6f6SJean-Jacques Hiblot 		 */
1521c744b6f6SJean-Jacques Hiblot 		capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
1522c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
1523c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
1524c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
1525c744b6f6SJean-Jacques Hiblot 		capacity *= MMC_MAX_BLOCK_LEN;
1526c744b6f6SJean-Jacques Hiblot 		if ((capacity >> 20) > 2 * 1024)
1527c744b6f6SJean-Jacques Hiblot 			mmc->capacity_user = capacity;
1528c744b6f6SJean-Jacques Hiblot 	}
1529c744b6f6SJean-Jacques Hiblot 
1530c744b6f6SJean-Jacques Hiblot 	switch (ext_csd[EXT_CSD_REV]) {
1531c744b6f6SJean-Jacques Hiblot 	case 1:
1532c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_1;
1533c744b6f6SJean-Jacques Hiblot 		break;
1534c744b6f6SJean-Jacques Hiblot 	case 2:
1535c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_2;
1536c744b6f6SJean-Jacques Hiblot 		break;
1537c744b6f6SJean-Jacques Hiblot 	case 3:
1538c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_3;
1539c744b6f6SJean-Jacques Hiblot 		break;
1540c744b6f6SJean-Jacques Hiblot 	case 5:
1541c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_41;
1542c744b6f6SJean-Jacques Hiblot 		break;
1543c744b6f6SJean-Jacques Hiblot 	case 6:
1544c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_5;
1545c744b6f6SJean-Jacques Hiblot 		break;
1546c744b6f6SJean-Jacques Hiblot 	case 7:
1547c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_5_0;
1548c744b6f6SJean-Jacques Hiblot 		break;
1549c744b6f6SJean-Jacques Hiblot 	case 8:
1550c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_5_1;
1551c744b6f6SJean-Jacques Hiblot 		break;
1552c744b6f6SJean-Jacques Hiblot 	}
1553c744b6f6SJean-Jacques Hiblot 
1554c744b6f6SJean-Jacques Hiblot 	/* The partition data may be non-zero but it is only
1555c744b6f6SJean-Jacques Hiblot 	 * effective if PARTITION_SETTING_COMPLETED is set in
1556c744b6f6SJean-Jacques Hiblot 	 * EXT_CSD, so ignore any data if this bit is not set,
1557c744b6f6SJean-Jacques Hiblot 	 * except for enabling the high-capacity group size
1558c744b6f6SJean-Jacques Hiblot 	 * definition (see below).
1559c744b6f6SJean-Jacques Hiblot 	 */
1560c744b6f6SJean-Jacques Hiblot 	part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
1561c744b6f6SJean-Jacques Hiblot 			    EXT_CSD_PARTITION_SETTING_COMPLETED);
1562c744b6f6SJean-Jacques Hiblot 
1563c744b6f6SJean-Jacques Hiblot 	/* store the partition info of emmc */
1564c744b6f6SJean-Jacques Hiblot 	mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
1565c744b6f6SJean-Jacques Hiblot 	if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
1566c744b6f6SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_BOOT_MULT])
1567c744b6f6SJean-Jacques Hiblot 		mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
1568c744b6f6SJean-Jacques Hiblot 	if (part_completed &&
1569c744b6f6SJean-Jacques Hiblot 	    (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
1570c744b6f6SJean-Jacques Hiblot 		mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
1571c744b6f6SJean-Jacques Hiblot 
1572c744b6f6SJean-Jacques Hiblot 	mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
1573c744b6f6SJean-Jacques Hiblot 
1574c744b6f6SJean-Jacques Hiblot 	mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
1575c744b6f6SJean-Jacques Hiblot 
1576c744b6f6SJean-Jacques Hiblot 	for (i = 0; i < 4; i++) {
1577c744b6f6SJean-Jacques Hiblot 		int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
1578c744b6f6SJean-Jacques Hiblot 		uint mult = (ext_csd[idx + 2] << 16) +
1579c744b6f6SJean-Jacques Hiblot 			(ext_csd[idx + 1] << 8) + ext_csd[idx];
1580c744b6f6SJean-Jacques Hiblot 		if (mult)
1581c744b6f6SJean-Jacques Hiblot 			has_parts = true;
1582c744b6f6SJean-Jacques Hiblot 		if (!part_completed)
1583c744b6f6SJean-Jacques Hiblot 			continue;
1584c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] = mult;
1585c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] *=
1586c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1587c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1588c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] <<= 19;
1589c744b6f6SJean-Jacques Hiblot 	}
1590c744b6f6SJean-Jacques Hiblot 
1591c744b6f6SJean-Jacques Hiblot 	if (part_completed) {
1592c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size =
1593c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) +
1594c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) +
1595c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_ENH_SIZE_MULT];
1596c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1597c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1598c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size <<= 19;
1599c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_start =
1600c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) +
1601c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) +
1602c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) +
1603c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_ENH_START_ADDR];
1604c744b6f6SJean-Jacques Hiblot 		if (mmc->high_capacity)
1605c744b6f6SJean-Jacques Hiblot 			mmc->enh_user_start <<= 9;
1606c744b6f6SJean-Jacques Hiblot 	}
1607c744b6f6SJean-Jacques Hiblot 
1608c744b6f6SJean-Jacques Hiblot 	/*
1609c744b6f6SJean-Jacques Hiblot 	 * Host needs to enable ERASE_GRP_DEF bit if device is
1610c744b6f6SJean-Jacques Hiblot 	 * partitioned. This bit will be lost every time after a reset
1611c744b6f6SJean-Jacques Hiblot 	 * or power off. This will affect erase size.
1612c744b6f6SJean-Jacques Hiblot 	 */
1613c744b6f6SJean-Jacques Hiblot 	if (part_completed)
1614c744b6f6SJean-Jacques Hiblot 		has_parts = true;
1615c744b6f6SJean-Jacques Hiblot 	if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
1616c744b6f6SJean-Jacques Hiblot 	    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
1617c744b6f6SJean-Jacques Hiblot 		has_parts = true;
1618c744b6f6SJean-Jacques Hiblot 	if (has_parts) {
1619c744b6f6SJean-Jacques Hiblot 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1620c744b6f6SJean-Jacques Hiblot 				 EXT_CSD_ERASE_GROUP_DEF, 1);
1621c744b6f6SJean-Jacques Hiblot 
1622c744b6f6SJean-Jacques Hiblot 		if (err)
1623c744b6f6SJean-Jacques Hiblot 			return err;
1624c744b6f6SJean-Jacques Hiblot 
1625c744b6f6SJean-Jacques Hiblot 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1626c744b6f6SJean-Jacques Hiblot 	}
1627c744b6f6SJean-Jacques Hiblot 
1628c744b6f6SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
1629c744b6f6SJean-Jacques Hiblot 		/* Read out group size from ext_csd */
1630c744b6f6SJean-Jacques Hiblot 		mmc->erase_grp_size =
1631c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1632c744b6f6SJean-Jacques Hiblot 		/*
1633c744b6f6SJean-Jacques Hiblot 		 * if high capacity and partition setting completed
1634c744b6f6SJean-Jacques Hiblot 		 * SEC_COUNT is valid even if it is smaller than 2 GiB
1635c744b6f6SJean-Jacques Hiblot 		 * JEDEC Standard JESD84-B45, 6.2.4
1636c744b6f6SJean-Jacques Hiblot 		 */
1637c744b6f6SJean-Jacques Hiblot 		if (mmc->high_capacity && part_completed) {
1638c744b6f6SJean-Jacques Hiblot 			capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
1639c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
1640c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
1641c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
1642c744b6f6SJean-Jacques Hiblot 			capacity *= MMC_MAX_BLOCK_LEN;
1643c744b6f6SJean-Jacques Hiblot 			mmc->capacity_user = capacity;
1644c744b6f6SJean-Jacques Hiblot 		}
1645c744b6f6SJean-Jacques Hiblot 	} else {
1646c744b6f6SJean-Jacques Hiblot 		/* Calculate the group size from the csd value. */
1647c744b6f6SJean-Jacques Hiblot 		int erase_gsz, erase_gmul;
1648c744b6f6SJean-Jacques Hiblot 
1649c744b6f6SJean-Jacques Hiblot 		erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
1650c744b6f6SJean-Jacques Hiblot 		erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
1651c744b6f6SJean-Jacques Hiblot 		mmc->erase_grp_size = (erase_gsz + 1)
1652c744b6f6SJean-Jacques Hiblot 			* (erase_gmul + 1);
1653c744b6f6SJean-Jacques Hiblot 	}
1654c744b6f6SJean-Jacques Hiblot 
1655c744b6f6SJean-Jacques Hiblot 	mmc->hc_wp_grp_size = 1024
1656c744b6f6SJean-Jacques Hiblot 		* ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
1657c744b6f6SJean-Jacques Hiblot 		* ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1658c744b6f6SJean-Jacques Hiblot 
1659c744b6f6SJean-Jacques Hiblot 	mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
1660c744b6f6SJean-Jacques Hiblot 
1661c744b6f6SJean-Jacques Hiblot 	return 0;
1662c744b6f6SJean-Jacques Hiblot }
1663c744b6f6SJean-Jacques Hiblot 
1664fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc)
1665272cc70bSAndy Fleming {
1666f866a46dSStephen Warren 	int err, i;
1667272cc70bSAndy Fleming 	uint mult, freq;
1668c744b6f6SJean-Jacques Hiblot 	u64 cmult, csize;
1669272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1670c40fdca6SSimon Glass 	struct blk_desc *bdesc;
1671272cc70bSAndy Fleming 
1672d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
1673d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
1674d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
1675d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
1676d52ebf10SThomas Chou 		cmd.cmdarg = 1;
1677d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
1678d52ebf10SThomas Chou 
1679d52ebf10SThomas Chou 		if (err)
1680d52ebf10SThomas Chou 			return err;
1681d52ebf10SThomas Chou 	}
1682d52ebf10SThomas Chou #endif
1683d52ebf10SThomas Chou 
1684272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
1685d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
1686d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
1687272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1688272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1689272cc70bSAndy Fleming 
1690272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1691272cc70bSAndy Fleming 
1692272cc70bSAndy Fleming 	if (err)
1693272cc70bSAndy Fleming 		return err;
1694272cc70bSAndy Fleming 
1695272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
1696272cc70bSAndy Fleming 
1697272cc70bSAndy Fleming 	/*
1698272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
1699272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
1700272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
1701272cc70bSAndy Fleming 	 */
1702d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1703272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
1704272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1705272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
1706272cc70bSAndy Fleming 
1707272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1708272cc70bSAndy Fleming 
1709272cc70bSAndy Fleming 		if (err)
1710272cc70bSAndy Fleming 			return err;
1711272cc70bSAndy Fleming 
1712272cc70bSAndy Fleming 		if (IS_SD(mmc))
1713998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
1714d52ebf10SThomas Chou 	}
1715272cc70bSAndy Fleming 
1716272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
1717272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
1718272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1719272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1720272cc70bSAndy Fleming 
1721272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1722272cc70bSAndy Fleming 
1723272cc70bSAndy Fleming 	if (err)
1724272cc70bSAndy Fleming 		return err;
1725272cc70bSAndy Fleming 
1726998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
1727998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
1728998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
1729998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
1730272cc70bSAndy Fleming 
1731272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
17320b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
1733272cc70bSAndy Fleming 
1734272cc70bSAndy Fleming 		switch (version) {
1735272cc70bSAndy Fleming 		case 0:
1736272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1737272cc70bSAndy Fleming 			break;
1738272cc70bSAndy Fleming 		case 1:
1739272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_4;
1740272cc70bSAndy Fleming 			break;
1741272cc70bSAndy Fleming 		case 2:
1742272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_2_2;
1743272cc70bSAndy Fleming 			break;
1744272cc70bSAndy Fleming 		case 3:
1745272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_3;
1746272cc70bSAndy Fleming 			break;
1747272cc70bSAndy Fleming 		case 4:
1748272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_4;
1749272cc70bSAndy Fleming 			break;
1750272cc70bSAndy Fleming 		default:
1751272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1752272cc70bSAndy Fleming 			break;
1753272cc70bSAndy Fleming 		}
1754272cc70bSAndy Fleming 	}
1755272cc70bSAndy Fleming 
1756272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
17570b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
17580b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
1759272cc70bSAndy Fleming 
176035f9e196SJean-Jacques Hiblot 	mmc->legacy_speed = freq * mult;
176135f9e196SJean-Jacques Hiblot 	mmc_select_mode(mmc, MMC_LEGACY);
1762272cc70bSAndy Fleming 
1763ab71188cSMarkus Niebel 	mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
1764998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
1765272cc70bSAndy Fleming 
1766272cc70bSAndy Fleming 	if (IS_SD(mmc))
1767272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
1768272cc70bSAndy Fleming 	else
1769998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
1770272cc70bSAndy Fleming 
1771272cc70bSAndy Fleming 	if (mmc->high_capacity) {
1772272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
1773272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
1774272cc70bSAndy Fleming 		cmult = 8;
1775272cc70bSAndy Fleming 	} else {
1776272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
1777272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
1778272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
1779272cc70bSAndy Fleming 	}
1780272cc70bSAndy Fleming 
1781f866a46dSStephen Warren 	mmc->capacity_user = (csize + 1) << (cmult + 2);
1782f866a46dSStephen Warren 	mmc->capacity_user *= mmc->read_bl_len;
1783f866a46dSStephen Warren 	mmc->capacity_boot = 0;
1784f866a46dSStephen Warren 	mmc->capacity_rpmb = 0;
1785f866a46dSStephen Warren 	for (i = 0; i < 4; i++)
1786f866a46dSStephen Warren 		mmc->capacity_gp[i] = 0;
1787272cc70bSAndy Fleming 
17888bfa195eSSimon Glass 	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
17898bfa195eSSimon Glass 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
1790272cc70bSAndy Fleming 
17918bfa195eSSimon Glass 	if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
17928bfa195eSSimon Glass 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
1793272cc70bSAndy Fleming 
1794ab71188cSMarkus Niebel 	if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
1795ab71188cSMarkus Niebel 		cmd.cmdidx = MMC_CMD_SET_DSR;
1796ab71188cSMarkus Niebel 		cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
1797ab71188cSMarkus Niebel 		cmd.resp_type = MMC_RSP_NONE;
1798ab71188cSMarkus Niebel 		if (mmc_send_cmd(mmc, &cmd, NULL))
1799ab71188cSMarkus Niebel 			printf("MMC: SET_DSR failed\n");
1800ab71188cSMarkus Niebel 	}
1801ab71188cSMarkus Niebel 
1802272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
1803d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1804272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
1805fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
1806272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1807272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1808272cc70bSAndy Fleming 
1809272cc70bSAndy Fleming 		if (err)
1810272cc70bSAndy Fleming 			return err;
1811d52ebf10SThomas Chou 	}
1812272cc70bSAndy Fleming 
1813e6f99a56SLei Wen 	/*
1814e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
1815e6f99a56SLei Wen 	 */
1816e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
1817bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
1818c744b6f6SJean-Jacques Hiblot 
1819dfda9d88SJean-Jacques Hiblot 	err = mmc_startup_v4(mmc);
18209cf199ebSDiego Santa Cruz 	if (err)
18219cf199ebSDiego Santa Cruz 		return err;
1822f866a46dSStephen Warren 
1823c40fdca6SSimon Glass 	err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart);
1824f866a46dSStephen Warren 	if (err)
1825f866a46dSStephen Warren 		return err;
1826d23e2c09SSukumar Ghorai 
1827272cc70bSAndy Fleming 	if (IS_SD(mmc))
1828d0c221feSJean-Jacques Hiblot 		err = sd_select_mode_and_width(mmc);
1829272cc70bSAndy Fleming 	else
18303862b854SJean-Jacques Hiblot 		err = mmc_select_mode_and_width(mmc);
1831272cc70bSAndy Fleming 
1832272cc70bSAndy Fleming 	if (err)
1833272cc70bSAndy Fleming 		return err;
1834272cc70bSAndy Fleming 
1835272cc70bSAndy Fleming 
18365af8f45cSAndrew Gabbasov 	/* Fix the block length for DDR mode */
18375af8f45cSAndrew Gabbasov 	if (mmc->ddr_mode) {
18385af8f45cSAndrew Gabbasov 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
18395af8f45cSAndrew Gabbasov 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
18405af8f45cSAndrew Gabbasov 	}
18415af8f45cSAndrew Gabbasov 
1842272cc70bSAndy Fleming 	/* fill in device description */
1843c40fdca6SSimon Glass 	bdesc = mmc_get_blk_desc(mmc);
1844c40fdca6SSimon Glass 	bdesc->lun = 0;
1845c40fdca6SSimon Glass 	bdesc->hwpart = 0;
1846c40fdca6SSimon Glass 	bdesc->type = 0;
1847c40fdca6SSimon Glass 	bdesc->blksz = mmc->read_bl_len;
1848c40fdca6SSimon Glass 	bdesc->log2blksz = LOG2(bdesc->blksz);
1849c40fdca6SSimon Glass 	bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len);
1850fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \
1851fc011f64SSjoerd Simons 		(defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \
1852fc011f64SSjoerd Simons 		!defined(CONFIG_USE_TINY_PRINTF))
1853c40fdca6SSimon Glass 	sprintf(bdesc->vendor, "Man %06x Snr %04x%04x",
1854babce5f6STaylor Hutt 		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
1855babce5f6STaylor Hutt 		(mmc->cid[3] >> 16) & 0xffff);
1856c40fdca6SSimon Glass 	sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
18570b453ffeSRabin Vincent 		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
1858babce5f6STaylor Hutt 		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
1859babce5f6STaylor Hutt 		(mmc->cid[2] >> 24) & 0xff);
1860c40fdca6SSimon Glass 	sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
1861babce5f6STaylor Hutt 		(mmc->cid[2] >> 16) & 0xf);
186256196826SPaul Burton #else
1863c40fdca6SSimon Glass 	bdesc->vendor[0] = 0;
1864c40fdca6SSimon Glass 	bdesc->product[0] = 0;
1865c40fdca6SSimon Glass 	bdesc->revision[0] = 0;
186656196826SPaul Burton #endif
1867122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
1868c40fdca6SSimon Glass 	part_init(bdesc);
1869122efd43SMikhail Kshevetskiy #endif
1870272cc70bSAndy Fleming 
1871272cc70bSAndy Fleming 	return 0;
1872272cc70bSAndy Fleming }
1873272cc70bSAndy Fleming 
1874fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc)
1875272cc70bSAndy Fleming {
1876272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1877272cc70bSAndy Fleming 	int err;
1878272cc70bSAndy Fleming 
1879272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
1880272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
188193bfd616SPantelis Antoniou 	cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa;
1882272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
1883272cc70bSAndy Fleming 
1884272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1885272cc70bSAndy Fleming 
1886272cc70bSAndy Fleming 	if (err)
1887272cc70bSAndy Fleming 		return err;
1888272cc70bSAndy Fleming 
1889998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
1890915ffa52SJaehoon Chung 		return -EOPNOTSUPP;
1891272cc70bSAndy Fleming 	else
1892272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
1893272cc70bSAndy Fleming 
1894272cc70bSAndy Fleming 	return 0;
1895272cc70bSAndy Fleming }
1896272cc70bSAndy Fleming 
1897c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
189895de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */
189995de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void)
190095de9ab2SPaul Kocialkowski {
190195de9ab2SPaul Kocialkowski }
190205cbeb7cSSimon Glass #endif
190395de9ab2SPaul Kocialkowski 
19042051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc)
19052051aefeSPeng Fan {
1906c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
190706ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR)
19082051aefeSPeng Fan 	int ret;
19092051aefeSPeng Fan 
19102051aefeSPeng Fan 	ret = device_get_supply_regulator(mmc->dev, "vmmc-supply",
191106ec045fSJean-Jacques Hiblot 					  &mmc->vmmc_supply);
191206ec045fSJean-Jacques Hiblot 	if (ret)
1913288db7c7SJaehoon Chung 		debug("%s: No vmmc supply\n", mmc->dev->name);
19142051aefeSPeng Fan 
191506ec045fSJean-Jacques Hiblot 	ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply",
191606ec045fSJean-Jacques Hiblot 					  &mmc->vqmmc_supply);
191706ec045fSJean-Jacques Hiblot 	if (ret)
191806ec045fSJean-Jacques Hiblot 		debug("%s: No vqmmc supply\n", mmc->dev->name);
191906ec045fSJean-Jacques Hiblot 
192006ec045fSJean-Jacques Hiblot 	if (mmc->vmmc_supply) {
192106ec045fSJean-Jacques Hiblot 		ret = regulator_set_enable(mmc->vmmc_supply, true);
19222051aefeSPeng Fan 		if (ret) {
19232051aefeSPeng Fan 			puts("Error enabling VMMC supply\n");
19242051aefeSPeng Fan 			return ret;
19252051aefeSPeng Fan 		}
192606ec045fSJean-Jacques Hiblot 	}
19272051aefeSPeng Fan #endif
192805cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */
192905cbeb7cSSimon Glass 	/*
193005cbeb7cSSimon Glass 	 * Driver model should use a regulator, as above, rather than calling
193105cbeb7cSSimon Glass 	 * out to board code.
193205cbeb7cSSimon Glass 	 */
193305cbeb7cSSimon Glass 	board_mmc_power_init();
193405cbeb7cSSimon Glass #endif
19352051aefeSPeng Fan 	return 0;
19362051aefeSPeng Fan }
19372051aefeSPeng Fan 
1938e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc)
1939272cc70bSAndy Fleming {
19408ca51e51SSimon Glass 	bool no_card;
1941afd5932bSMacpaul Lin 	int err;
1942272cc70bSAndy Fleming 
1943ab769f22SPantelis Antoniou 	/* we pretend there's no card when init is NULL */
19448ca51e51SSimon Glass 	no_card = mmc_getcd(mmc) == 0;
1945e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
19468ca51e51SSimon Glass 	no_card = no_card || (mmc->cfg->ops->init == NULL);
19478ca51e51SSimon Glass #endif
19488ca51e51SSimon Glass 	if (no_card) {
194948972d90SThierry Reding 		mmc->has_init = 0;
195056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
195148972d90SThierry Reding 		printf("MMC: no card present\n");
195256196826SPaul Burton #endif
1953915ffa52SJaehoon Chung 		return -ENOMEDIUM;
195448972d90SThierry Reding 	}
195548972d90SThierry Reding 
1956bc897b1dSLei Wen 	if (mmc->has_init)
1957bc897b1dSLei Wen 		return 0;
1958bc897b1dSLei Wen 
19595a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
19605a8dbdc6SYangbo Lu 	mmc_adapter_card_type_ident();
19615a8dbdc6SYangbo Lu #endif
19622051aefeSPeng Fan 	err = mmc_power_init(mmc);
19632051aefeSPeng Fan 	if (err)
19642051aefeSPeng Fan 		return err;
196595de9ab2SPaul Kocialkowski 
1966e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
19678ca51e51SSimon Glass 	/* The device has already been probed ready for use */
19688ca51e51SSimon Glass #else
1969ab769f22SPantelis Antoniou 	/* made sure it's not NULL earlier */
197093bfd616SPantelis Antoniou 	err = mmc->cfg->ops->init(mmc);
1971272cc70bSAndy Fleming 	if (err)
1972272cc70bSAndy Fleming 		return err;
19738ca51e51SSimon Glass #endif
1974786e8f81SAndrew Gabbasov 	mmc->ddr_mode = 0;
1975*aff5d3c8SKishon Vijay Abraham I 
1976*aff5d3c8SKishon Vijay Abraham I 	/* First try to set 3.3V. If it fails set to 1.8V */
1977*aff5d3c8SKishon Vijay Abraham I 	err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_330);
1978*aff5d3c8SKishon Vijay Abraham I 	if (err != 0)
1979*aff5d3c8SKishon Vijay Abraham I 		err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_180);
1980*aff5d3c8SKishon Vijay Abraham I 	if (err != 0)
1981*aff5d3c8SKishon Vijay Abraham I 		printf("failed to set signal voltage\n");
1982*aff5d3c8SKishon Vijay Abraham I 
1983b86b85e2SIlya Yanok 	mmc_set_bus_width(mmc, 1);
1984b86b85e2SIlya Yanok 	mmc_set_clock(mmc, 1);
1985b86b85e2SIlya Yanok 
1986272cc70bSAndy Fleming 	/* Reset the Card */
1987272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
1988272cc70bSAndy Fleming 
1989272cc70bSAndy Fleming 	if (err)
1990272cc70bSAndy Fleming 		return err;
1991272cc70bSAndy Fleming 
1992bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
1993c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->hwpart = 0;
1994bc897b1dSLei Wen 
1995272cc70bSAndy Fleming 	/* Test for SD version 2 */
1996272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
1997272cc70bSAndy Fleming 
1998272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
1999272cc70bSAndy Fleming 	err = sd_send_op_cond(mmc);
2000272cc70bSAndy Fleming 
2001272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
2002915ffa52SJaehoon Chung 	if (err == -ETIMEDOUT) {
2003272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
2004272cc70bSAndy Fleming 
2005bd47c135SAndrew Gabbasov 		if (err) {
200656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2007272cc70bSAndy Fleming 			printf("Card did not respond to voltage select!\n");
200856196826SPaul Burton #endif
2009915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
2010272cc70bSAndy Fleming 		}
2011272cc70bSAndy Fleming 	}
2012272cc70bSAndy Fleming 
2013bd47c135SAndrew Gabbasov 	if (!err)
2014e9550449SChe-Liang Chiou 		mmc->init_in_progress = 1;
2015e9550449SChe-Liang Chiou 
2016e9550449SChe-Liang Chiou 	return err;
2017e9550449SChe-Liang Chiou }
2018e9550449SChe-Liang Chiou 
2019e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc)
2020e9550449SChe-Liang Chiou {
2021e9550449SChe-Liang Chiou 	int err = 0;
2022e9550449SChe-Liang Chiou 
2023bd47c135SAndrew Gabbasov 	mmc->init_in_progress = 0;
2024e9550449SChe-Liang Chiou 	if (mmc->op_cond_pending)
2025e9550449SChe-Liang Chiou 		err = mmc_complete_op_cond(mmc);
2026e9550449SChe-Liang Chiou 
2027e9550449SChe-Liang Chiou 	if (!err)
2028bc897b1dSLei Wen 		err = mmc_startup(mmc);
2029bc897b1dSLei Wen 	if (err)
2030bc897b1dSLei Wen 		mmc->has_init = 0;
2031bc897b1dSLei Wen 	else
2032bc897b1dSLei Wen 		mmc->has_init = 1;
2033e9550449SChe-Liang Chiou 	return err;
2034e9550449SChe-Liang Chiou }
2035e9550449SChe-Liang Chiou 
2036e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc)
2037e9550449SChe-Liang Chiou {
2038bd47c135SAndrew Gabbasov 	int err = 0;
2039ce9eca94SMarek Vasut 	__maybe_unused unsigned start;
2040c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
204133fb211dSSimon Glass 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev);
2042e9550449SChe-Liang Chiou 
204333fb211dSSimon Glass 	upriv->mmc = mmc;
204433fb211dSSimon Glass #endif
2045e9550449SChe-Liang Chiou 	if (mmc->has_init)
2046e9550449SChe-Liang Chiou 		return 0;
2047d803fea5SMateusz Zalega 
2048d803fea5SMateusz Zalega 	start = get_timer(0);
2049d803fea5SMateusz Zalega 
2050e9550449SChe-Liang Chiou 	if (!mmc->init_in_progress)
2051e9550449SChe-Liang Chiou 		err = mmc_start_init(mmc);
2052e9550449SChe-Liang Chiou 
2053bd47c135SAndrew Gabbasov 	if (!err)
2054e9550449SChe-Liang Chiou 		err = mmc_complete_init(mmc);
2055919b4858SJagan Teki 	if (err)
2056919b4858SJagan Teki 		printf("%s: %d, time %lu\n", __func__, err, get_timer(start));
2057919b4858SJagan Teki 
2058bc897b1dSLei Wen 	return err;
2059272cc70bSAndy Fleming }
2060272cc70bSAndy Fleming 
2061ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val)
2062ab71188cSMarkus Niebel {
2063ab71188cSMarkus Niebel 	mmc->dsr = val;
2064ab71188cSMarkus Niebel 	return 0;
2065ab71188cSMarkus Niebel }
2066ab71188cSMarkus Niebel 
2067cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */
2068cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis)
2069272cc70bSAndy Fleming {
2070272cc70bSAndy Fleming 	return -1;
2071272cc70bSAndy Fleming }
2072272cc70bSAndy Fleming 
2073cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */
2074cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis)
2075cee9ab7cSJeroen Hofstee {
2076cee9ab7cSJeroen Hofstee 	return -1;
2077cee9ab7cSJeroen Hofstee }
2078272cc70bSAndy Fleming 
2079e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit)
2080e9550449SChe-Liang Chiou {
2081e9550449SChe-Liang Chiou 	mmc->preinit = preinit;
2082e9550449SChe-Liang Chiou }
2083e9550449SChe-Liang Chiou 
2084c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD)
20858e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
20868e3332e2SSjoerd Simons {
20878e3332e2SSjoerd Simons 	return 0;
20888e3332e2SSjoerd Simons }
2089c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC)
20908e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
20918e3332e2SSjoerd Simons {
20924a1db6d8SSimon Glass 	int ret, i;
20938e3332e2SSjoerd Simons 	struct uclass *uc;
20944a1db6d8SSimon Glass 	struct udevice *dev;
20958e3332e2SSjoerd Simons 
20968e3332e2SSjoerd Simons 	ret = uclass_get(UCLASS_MMC, &uc);
20978e3332e2SSjoerd Simons 	if (ret)
20988e3332e2SSjoerd Simons 		return ret;
20998e3332e2SSjoerd Simons 
21004a1db6d8SSimon Glass 	/*
21014a1db6d8SSimon Glass 	 * Try to add them in sequence order. Really with driver model we
21024a1db6d8SSimon Glass 	 * should allow holes, but the current MMC list does not allow that.
21034a1db6d8SSimon Glass 	 * So if we request 0, 1, 3 we will get 0, 1, 2.
21044a1db6d8SSimon Glass 	 */
21054a1db6d8SSimon Glass 	for (i = 0; ; i++) {
21064a1db6d8SSimon Glass 		ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev);
21074a1db6d8SSimon Glass 		if (ret == -ENODEV)
21084a1db6d8SSimon Glass 			break;
21094a1db6d8SSimon Glass 	}
21104a1db6d8SSimon Glass 	uclass_foreach_dev(dev, uc) {
21114a1db6d8SSimon Glass 		ret = device_probe(dev);
21128e3332e2SSjoerd Simons 		if (ret)
21134a1db6d8SSimon Glass 			printf("%s - probe failed: %d\n", dev->name, ret);
21148e3332e2SSjoerd Simons 	}
21158e3332e2SSjoerd Simons 
21168e3332e2SSjoerd Simons 	return 0;
21178e3332e2SSjoerd Simons }
21188e3332e2SSjoerd Simons #else
21198e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
21208e3332e2SSjoerd Simons {
21218e3332e2SSjoerd Simons 	if (board_mmc_init(bis) < 0)
21228e3332e2SSjoerd Simons 		cpu_mmc_init(bis);
21238e3332e2SSjoerd Simons 
21248e3332e2SSjoerd Simons 	return 0;
21258e3332e2SSjoerd Simons }
21268e3332e2SSjoerd Simons #endif
2127e9550449SChe-Liang Chiou 
2128272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
2129272cc70bSAndy Fleming {
21301b26bab1SDaniel Kochmański 	static int initialized = 0;
21318e3332e2SSjoerd Simons 	int ret;
21321b26bab1SDaniel Kochmański 	if (initialized)	/* Avoid initializing mmc multiple times */
21331b26bab1SDaniel Kochmański 		return 0;
21341b26bab1SDaniel Kochmański 	initialized = 1;
21351b26bab1SDaniel Kochmański 
2136c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK)
2137b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY)
2138c40fdca6SSimon Glass 	mmc_list_init();
2139c40fdca6SSimon Glass #endif
2140b5b838f1SMarek Vasut #endif
21418e3332e2SSjoerd Simons 	ret = mmc_probe(bis);
21428e3332e2SSjoerd Simons 	if (ret)
21438e3332e2SSjoerd Simons 		return ret;
2144272cc70bSAndy Fleming 
2145bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD
2146272cc70bSAndy Fleming 	print_mmc_devices(',');
2147bb0dc108SYing Zhang #endif
2148272cc70bSAndy Fleming 
2149c40fdca6SSimon Glass 	mmc_do_preinit();
2150272cc70bSAndy Fleming 	return 0;
2151272cc70bSAndy Fleming }
2152cd3d4880STomas Melin 
2153cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE
2154cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc)
2155cd3d4880STomas Melin {
2156cd3d4880STomas Melin 	int err;
2157cd3d4880STomas Melin 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
2158cd3d4880STomas Melin 
2159cd3d4880STomas Melin 	err = mmc_send_ext_csd(mmc, ext_csd);
2160cd3d4880STomas Melin 	if (err) {
2161cd3d4880STomas Melin 		puts("Could not get ext_csd register values\n");
2162cd3d4880STomas Melin 		return err;
2163cd3d4880STomas Melin 	}
2164cd3d4880STomas Melin 
2165cd3d4880STomas Melin 	if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) {
2166cd3d4880STomas Melin 		puts("Background operations not supported on device\n");
2167cd3d4880STomas Melin 		return -EMEDIUMTYPE;
2168cd3d4880STomas Melin 	}
2169cd3d4880STomas Melin 
2170cd3d4880STomas Melin 	if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) {
2171cd3d4880STomas Melin 		puts("Background operations already enabled\n");
2172cd3d4880STomas Melin 		return 0;
2173cd3d4880STomas Melin 	}
2174cd3d4880STomas Melin 
2175cd3d4880STomas Melin 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1);
2176cd3d4880STomas Melin 	if (err) {
2177cd3d4880STomas Melin 		puts("Failed to enable manual background operations\n");
2178cd3d4880STomas Melin 		return err;
2179cd3d4880STomas Melin 	}
2180cd3d4880STomas Melin 
2181cd3d4880STomas Melin 	puts("Enabled manual background operations\n");
2182cd3d4880STomas Melin 
2183cd3d4880STomas Melin 	return 0;
2184cd3d4880STomas Melin }
2185cd3d4880STomas Melin #endif
2186