xref: /openbmc/u-boot/drivers/mmc/mmc.c (revision 2e7410d7)
1272cc70bSAndy Fleming /*
2272cc70bSAndy Fleming  * Copyright 2008, Freescale Semiconductor, Inc
3272cc70bSAndy Fleming  * Andy Fleming
4272cc70bSAndy Fleming  *
5272cc70bSAndy Fleming  * Based vaguely on the Linux code
6272cc70bSAndy Fleming  *
71a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
8272cc70bSAndy Fleming  */
9272cc70bSAndy Fleming 
10272cc70bSAndy Fleming #include <config.h>
11272cc70bSAndy Fleming #include <common.h>
12272cc70bSAndy Fleming #include <command.h>
138e3332e2SSjoerd Simons #include <dm.h>
148e3332e2SSjoerd Simons #include <dm/device-internal.h>
15d4622df3SStephen Warren #include <errno.h>
16272cc70bSAndy Fleming #include <mmc.h>
17272cc70bSAndy Fleming #include <part.h>
182051aefeSPeng Fan #include <power/regulator.h>
19272cc70bSAndy Fleming #include <malloc.h>
20cf92e05cSSimon Glass #include <memalign.h>
21272cc70bSAndy Fleming #include <linux/list.h>
229b1f942cSRabin Vincent #include <div64.h>
23da61fa5fSPaul Burton #include "mmc_private.h"
24272cc70bSAndy Fleming 
253697e599SPeng Fan static const unsigned int sd_au_size[] = {
263697e599SPeng Fan 	0,		SZ_16K / 512,		SZ_32K / 512,
273697e599SPeng Fan 	SZ_64K / 512,	SZ_128K / 512,		SZ_256K / 512,
283697e599SPeng Fan 	SZ_512K / 512,	SZ_1M / 512,		SZ_2M / 512,
293697e599SPeng Fan 	SZ_4M / 512,	SZ_8M / 512,		(SZ_8M + SZ_4M) / 512,
303697e599SPeng Fan 	SZ_16M / 512,	(SZ_16M + SZ_8M) / 512,	SZ_32M / 512,	SZ_64M / 512,
313697e599SPeng Fan };
323697e599SPeng Fan 
33aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage);
34fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc);
35aff5d3c8SKishon Vijay Abraham I 
36b5b838f1SMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY)
37b5b838f1SMarek Vasut static struct mmc mmc_static;
38b5b838f1SMarek Vasut struct mmc *find_mmc_device(int dev_num)
39b5b838f1SMarek Vasut {
40b5b838f1SMarek Vasut 	return &mmc_static;
41b5b838f1SMarek Vasut }
42b5b838f1SMarek Vasut 
43b5b838f1SMarek Vasut void mmc_do_preinit(void)
44b5b838f1SMarek Vasut {
45b5b838f1SMarek Vasut 	struct mmc *m = &mmc_static;
46b5b838f1SMarek Vasut #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
47b5b838f1SMarek Vasut 	mmc_set_preinit(m, 1);
48b5b838f1SMarek Vasut #endif
49b5b838f1SMarek Vasut 	if (m->preinit)
50b5b838f1SMarek Vasut 		mmc_start_init(m);
51b5b838f1SMarek Vasut }
52b5b838f1SMarek Vasut 
53b5b838f1SMarek Vasut struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
54b5b838f1SMarek Vasut {
55b5b838f1SMarek Vasut 	return &mmc->block_dev;
56b5b838f1SMarek Vasut }
57b5b838f1SMarek Vasut #endif
58b5b838f1SMarek Vasut 
59e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
60750121c3SJeroen Hofstee __weak int board_mmc_getwp(struct mmc *mmc)
61d23d8d7eSNikita Kiryanov {
62d23d8d7eSNikita Kiryanov 	return -1;
63d23d8d7eSNikita Kiryanov }
64d23d8d7eSNikita Kiryanov 
65d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc)
66d23d8d7eSNikita Kiryanov {
67d23d8d7eSNikita Kiryanov 	int wp;
68d23d8d7eSNikita Kiryanov 
69d23d8d7eSNikita Kiryanov 	wp = board_mmc_getwp(mmc);
70d23d8d7eSNikita Kiryanov 
71d4e1da4eSPeter Korsgaard 	if (wp < 0) {
7293bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getwp)
7393bfd616SPantelis Antoniou 			wp = mmc->cfg->ops->getwp(mmc);
74d4e1da4eSPeter Korsgaard 		else
75d4e1da4eSPeter Korsgaard 			wp = 0;
76d4e1da4eSPeter Korsgaard 	}
77d23d8d7eSNikita Kiryanov 
78d23d8d7eSNikita Kiryanov 	return wp;
79d23d8d7eSNikita Kiryanov }
80d23d8d7eSNikita Kiryanov 
81cee9ab7cSJeroen Hofstee __weak int board_mmc_getcd(struct mmc *mmc)
82cee9ab7cSJeroen Hofstee {
8311fdade2SStefano Babic 	return -1;
8411fdade2SStefano Babic }
858ca51e51SSimon Glass #endif
8611fdade2SStefano Babic 
878635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE
88c0c76ebaSSimon Glass void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd)
89c0c76ebaSSimon Glass {
90c0c76ebaSSimon Glass 	printf("CMD_SEND:%d\n", cmd->cmdidx);
91c0c76ebaSSimon Glass 	printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg);
92c0c76ebaSSimon Glass }
93c0c76ebaSSimon Glass 
94c0c76ebaSSimon Glass void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret)
95c0c76ebaSSimon Glass {
965db2fe3aSRaffaele Recalcati 	int i;
975db2fe3aSRaffaele Recalcati 	u8 *ptr;
985db2fe3aSRaffaele Recalcati 
997863ce58SBin Meng 	if (ret) {
1007863ce58SBin Meng 		printf("\t\tRET\t\t\t %d\n", ret);
1017863ce58SBin Meng 	} else {
1025db2fe3aSRaffaele Recalcati 		switch (cmd->resp_type) {
1035db2fe3aSRaffaele Recalcati 		case MMC_RSP_NONE:
1045db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_NONE\n");
1055db2fe3aSRaffaele Recalcati 			break;
1065db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1:
1075db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n",
1085db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1095db2fe3aSRaffaele Recalcati 			break;
1105db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1b:
1115db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n",
1125db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1135db2fe3aSRaffaele Recalcati 			break;
1145db2fe3aSRaffaele Recalcati 		case MMC_RSP_R2:
1155db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R2\t\t 0x%08X \n",
1165db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1175db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1185db2fe3aSRaffaele Recalcati 				cmd->response[1]);
1195db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1205db2fe3aSRaffaele Recalcati 				cmd->response[2]);
1215db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1225db2fe3aSRaffaele Recalcati 				cmd->response[3]);
1235db2fe3aSRaffaele Recalcati 			printf("\n");
1245db2fe3aSRaffaele Recalcati 			printf("\t\t\t\t\tDUMPING DATA\n");
1255db2fe3aSRaffaele Recalcati 			for (i = 0; i < 4; i++) {
1265db2fe3aSRaffaele Recalcati 				int j;
1275db2fe3aSRaffaele Recalcati 				printf("\t\t\t\t\t%03d - ", i*4);
128146bec79SDirk Behme 				ptr = (u8 *)&cmd->response[i];
1295db2fe3aSRaffaele Recalcati 				ptr += 3;
1305db2fe3aSRaffaele Recalcati 				for (j = 0; j < 4; j++)
1315db2fe3aSRaffaele Recalcati 					printf("%02X ", *ptr--);
1325db2fe3aSRaffaele Recalcati 				printf("\n");
1335db2fe3aSRaffaele Recalcati 			}
1345db2fe3aSRaffaele Recalcati 			break;
1355db2fe3aSRaffaele Recalcati 		case MMC_RSP_R3:
1365db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n",
1375db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1385db2fe3aSRaffaele Recalcati 			break;
1395db2fe3aSRaffaele Recalcati 		default:
1405db2fe3aSRaffaele Recalcati 			printf("\t\tERROR MMC rsp not supported\n");
1415db2fe3aSRaffaele Recalcati 			break;
1425db2fe3aSRaffaele Recalcati 		}
1437863ce58SBin Meng 	}
144c0c76ebaSSimon Glass }
145c0c76ebaSSimon Glass 
146c0c76ebaSSimon Glass void mmc_trace_state(struct mmc *mmc, struct mmc_cmd *cmd)
147c0c76ebaSSimon Glass {
148c0c76ebaSSimon Glass 	int status;
149c0c76ebaSSimon Glass 
150c0c76ebaSSimon Glass 	status = (cmd->response[0] & MMC_STATUS_CURR_STATE) >> 9;
151c0c76ebaSSimon Glass 	printf("CURR STATE:%d\n", status);
152c0c76ebaSSimon Glass }
1535db2fe3aSRaffaele Recalcati #endif
154c0c76ebaSSimon Glass 
15535f9e196SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG)
15635f9e196SJean-Jacques Hiblot const char *mmc_mode_name(enum bus_mode mode)
15735f9e196SJean-Jacques Hiblot {
15835f9e196SJean-Jacques Hiblot 	static const char *const names[] = {
15935f9e196SJean-Jacques Hiblot 	      [MMC_LEGACY]	= "MMC legacy",
16035f9e196SJean-Jacques Hiblot 	      [SD_LEGACY]	= "SD Legacy",
16135f9e196SJean-Jacques Hiblot 	      [MMC_HS]		= "MMC High Speed (26MHz)",
16235f9e196SJean-Jacques Hiblot 	      [SD_HS]		= "SD High Speed (50MHz)",
16335f9e196SJean-Jacques Hiblot 	      [UHS_SDR12]	= "UHS SDR12 (25MHz)",
16435f9e196SJean-Jacques Hiblot 	      [UHS_SDR25]	= "UHS SDR25 (50MHz)",
16535f9e196SJean-Jacques Hiblot 	      [UHS_SDR50]	= "UHS SDR50 (100MHz)",
16635f9e196SJean-Jacques Hiblot 	      [UHS_SDR104]	= "UHS SDR104 (208MHz)",
16735f9e196SJean-Jacques Hiblot 	      [UHS_DDR50]	= "UHS DDR50 (50MHz)",
16835f9e196SJean-Jacques Hiblot 	      [MMC_HS_52]	= "MMC High Speed (52MHz)",
16935f9e196SJean-Jacques Hiblot 	      [MMC_DDR_52]	= "MMC DDR52 (52MHz)",
17035f9e196SJean-Jacques Hiblot 	      [MMC_HS_200]	= "HS200 (200MHz)",
17135f9e196SJean-Jacques Hiblot 	};
17235f9e196SJean-Jacques Hiblot 
17335f9e196SJean-Jacques Hiblot 	if (mode >= MMC_MODES_END)
17435f9e196SJean-Jacques Hiblot 		return "Unknown mode";
17535f9e196SJean-Jacques Hiblot 	else
17635f9e196SJean-Jacques Hiblot 		return names[mode];
17735f9e196SJean-Jacques Hiblot }
17835f9e196SJean-Jacques Hiblot #endif
17935f9e196SJean-Jacques Hiblot 
18005038576SJean-Jacques Hiblot static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode)
18105038576SJean-Jacques Hiblot {
18205038576SJean-Jacques Hiblot 	static const int freqs[] = {
18305038576SJean-Jacques Hiblot 	      [SD_LEGACY]	= 25000000,
18405038576SJean-Jacques Hiblot 	      [MMC_HS]		= 26000000,
18505038576SJean-Jacques Hiblot 	      [SD_HS]		= 50000000,
18605038576SJean-Jacques Hiblot 	      [UHS_SDR12]	= 25000000,
18705038576SJean-Jacques Hiblot 	      [UHS_SDR25]	= 50000000,
18805038576SJean-Jacques Hiblot 	      [UHS_SDR50]	= 100000000,
18905038576SJean-Jacques Hiblot 	      [UHS_SDR104]	= 208000000,
19005038576SJean-Jacques Hiblot 	      [UHS_DDR50]	= 50000000,
19105038576SJean-Jacques Hiblot 	      [MMC_HS_52]	= 52000000,
19205038576SJean-Jacques Hiblot 	      [MMC_DDR_52]	= 52000000,
19305038576SJean-Jacques Hiblot 	      [MMC_HS_200]	= 200000000,
19405038576SJean-Jacques Hiblot 	};
19505038576SJean-Jacques Hiblot 
19605038576SJean-Jacques Hiblot 	if (mode == MMC_LEGACY)
19705038576SJean-Jacques Hiblot 		return mmc->legacy_speed;
19805038576SJean-Jacques Hiblot 	else if (mode >= MMC_MODES_END)
19905038576SJean-Jacques Hiblot 		return 0;
20005038576SJean-Jacques Hiblot 	else
20105038576SJean-Jacques Hiblot 		return freqs[mode];
20205038576SJean-Jacques Hiblot }
20305038576SJean-Jacques Hiblot 
20435f9e196SJean-Jacques Hiblot static int mmc_select_mode(struct mmc *mmc, enum bus_mode mode)
20535f9e196SJean-Jacques Hiblot {
20635f9e196SJean-Jacques Hiblot 	mmc->selected_mode = mode;
20705038576SJean-Jacques Hiblot 	mmc->tran_speed = mmc_mode2freq(mmc, mode);
2083862b854SJean-Jacques Hiblot 	mmc->ddr_mode = mmc_is_mode_ddr(mode);
20935f9e196SJean-Jacques Hiblot 	debug("selecting mode %s (freq : %d MHz)\n", mmc_mode_name(mode),
21035f9e196SJean-Jacques Hiblot 	      mmc->tran_speed / 1000000);
21135f9e196SJean-Jacques Hiblot 	return 0;
21235f9e196SJean-Jacques Hiblot }
21335f9e196SJean-Jacques Hiblot 
214e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
215c0c76ebaSSimon Glass int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
216c0c76ebaSSimon Glass {
217c0c76ebaSSimon Glass 	int ret;
218c0c76ebaSSimon Glass 
219c0c76ebaSSimon Glass 	mmmc_trace_before_send(mmc, cmd);
220c0c76ebaSSimon Glass 	ret = mmc->cfg->ops->send_cmd(mmc, cmd, data);
221c0c76ebaSSimon Glass 	mmmc_trace_after_send(mmc, cmd, ret);
222c0c76ebaSSimon Glass 
2238635ff9eSMarek Vasut 	return ret;
224272cc70bSAndy Fleming }
2258ca51e51SSimon Glass #endif
226272cc70bSAndy Fleming 
227da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout)
2285d4fc8d9SRaffaele Recalcati {
2295d4fc8d9SRaffaele Recalcati 	struct mmc_cmd cmd;
230d617c426SJan Kloetzke 	int err, retries = 5;
2315d4fc8d9SRaffaele Recalcati 
2325d4fc8d9SRaffaele Recalcati 	cmd.cmdidx = MMC_CMD_SEND_STATUS;
2335d4fc8d9SRaffaele Recalcati 	cmd.resp_type = MMC_RSP_R1;
234aaf3d41aSMarek Vasut 	if (!mmc_host_is_spi(mmc))
235aaf3d41aSMarek Vasut 		cmd.cmdarg = mmc->rca << 16;
2365d4fc8d9SRaffaele Recalcati 
2371677eef4SAndrew Gabbasov 	while (1) {
2385d4fc8d9SRaffaele Recalcati 		err = mmc_send_cmd(mmc, &cmd, NULL);
239d617c426SJan Kloetzke 		if (!err) {
240d617c426SJan Kloetzke 			if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) &&
241d617c426SJan Kloetzke 			    (cmd.response[0] & MMC_STATUS_CURR_STATE) !=
242d617c426SJan Kloetzke 			     MMC_STATE_PRG)
2435d4fc8d9SRaffaele Recalcati 				break;
244d0c221feSJean-Jacques Hiblot 
245d0c221feSJean-Jacques Hiblot 			if (cmd.response[0] & MMC_STATUS_MASK) {
24656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
247d617c426SJan Kloetzke 				printf("Status Error: 0x%08X\n",
248d617c426SJan Kloetzke 					cmd.response[0]);
24956196826SPaul Burton #endif
250915ffa52SJaehoon Chung 				return -ECOMM;
251d617c426SJan Kloetzke 			}
252d617c426SJan Kloetzke 		} else if (--retries < 0)
253d617c426SJan Kloetzke 			return err;
2545d4fc8d9SRaffaele Recalcati 
2551677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
2561677eef4SAndrew Gabbasov 			break;
2575d4fc8d9SRaffaele Recalcati 
2581677eef4SAndrew Gabbasov 		udelay(1000);
2591677eef4SAndrew Gabbasov 	}
2605d4fc8d9SRaffaele Recalcati 
261c0c76ebaSSimon Glass 	mmc_trace_state(mmc, &cmd);
2625b0c942fSJongman Heo 	if (timeout <= 0) {
26356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2645d4fc8d9SRaffaele Recalcati 		printf("Timeout waiting card ready\n");
26556196826SPaul Burton #endif
266915ffa52SJaehoon Chung 		return -ETIMEDOUT;
2675d4fc8d9SRaffaele Recalcati 	}
2685d4fc8d9SRaffaele Recalcati 
2695d4fc8d9SRaffaele Recalcati 	return 0;
2705d4fc8d9SRaffaele Recalcati }
2715d4fc8d9SRaffaele Recalcati 
272da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len)
273272cc70bSAndy Fleming {
274272cc70bSAndy Fleming 	struct mmc_cmd cmd;
275272cc70bSAndy Fleming 
276786e8f81SAndrew Gabbasov 	if (mmc->ddr_mode)
277d22e3d46SJaehoon Chung 		return 0;
278d22e3d46SJaehoon Chung 
279272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
280272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
281272cc70bSAndy Fleming 	cmd.cmdarg = len;
282272cc70bSAndy Fleming 
283272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, NULL);
284272cc70bSAndy Fleming }
285272cc70bSAndy Fleming 
286ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
287fdbb873eSKim Phillips 			   lbaint_t blkcnt)
288272cc70bSAndy Fleming {
289272cc70bSAndy Fleming 	struct mmc_cmd cmd;
290272cc70bSAndy Fleming 	struct mmc_data data;
291272cc70bSAndy Fleming 
2924a1a06bcSAlagu Sankar 	if (blkcnt > 1)
2934a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
2944a1a06bcSAlagu Sankar 	else
295272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
296272cc70bSAndy Fleming 
297272cc70bSAndy Fleming 	if (mmc->high_capacity)
2984a1a06bcSAlagu Sankar 		cmd.cmdarg = start;
299272cc70bSAndy Fleming 	else
3004a1a06bcSAlagu Sankar 		cmd.cmdarg = start * mmc->read_bl_len;
301272cc70bSAndy Fleming 
302272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
303272cc70bSAndy Fleming 
304272cc70bSAndy Fleming 	data.dest = dst;
3054a1a06bcSAlagu Sankar 	data.blocks = blkcnt;
306272cc70bSAndy Fleming 	data.blocksize = mmc->read_bl_len;
307272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
308272cc70bSAndy Fleming 
3094a1a06bcSAlagu Sankar 	if (mmc_send_cmd(mmc, &cmd, &data))
3104a1a06bcSAlagu Sankar 		return 0;
3114a1a06bcSAlagu Sankar 
3124a1a06bcSAlagu Sankar 	if (blkcnt > 1) {
3134a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
3144a1a06bcSAlagu Sankar 		cmd.cmdarg = 0;
3154a1a06bcSAlagu Sankar 		cmd.resp_type = MMC_RSP_R1b;
3164a1a06bcSAlagu Sankar 		if (mmc_send_cmd(mmc, &cmd, NULL)) {
31756196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
3184a1a06bcSAlagu Sankar 			printf("mmc fail to send stop cmd\n");
31956196826SPaul Burton #endif
3204a1a06bcSAlagu Sankar 			return 0;
3214a1a06bcSAlagu Sankar 		}
322272cc70bSAndy Fleming 	}
323272cc70bSAndy Fleming 
3244a1a06bcSAlagu Sankar 	return blkcnt;
325272cc70bSAndy Fleming }
326272cc70bSAndy Fleming 
327c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
3287dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst)
32933fb211dSSimon Glass #else
3307dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
3317dba0b93SSimon Glass 		void *dst)
33233fb211dSSimon Glass #endif
333272cc70bSAndy Fleming {
334c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
33533fb211dSSimon Glass 	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
33633fb211dSSimon Glass #endif
337bcce53d0SSimon Glass 	int dev_num = block_dev->devnum;
338873cc1d7SStephen Warren 	int err;
3394a1a06bcSAlagu Sankar 	lbaint_t cur, blocks_todo = blkcnt;
340272cc70bSAndy Fleming 
3414a1a06bcSAlagu Sankar 	if (blkcnt == 0)
3424a1a06bcSAlagu Sankar 		return 0;
3434a1a06bcSAlagu Sankar 
3444a1a06bcSAlagu Sankar 	struct mmc *mmc = find_mmc_device(dev_num);
345272cc70bSAndy Fleming 	if (!mmc)
346272cc70bSAndy Fleming 		return 0;
347272cc70bSAndy Fleming 
348b5b838f1SMarek Vasut 	if (CONFIG_IS_ENABLED(MMC_TINY))
349b5b838f1SMarek Vasut 		err = mmc_switch_part(mmc, block_dev->hwpart);
350b5b838f1SMarek Vasut 	else
35169f45cd5SSimon Glass 		err = blk_dselect_hwpart(block_dev, block_dev->hwpart);
352b5b838f1SMarek Vasut 
353873cc1d7SStephen Warren 	if (err < 0)
354873cc1d7SStephen Warren 		return 0;
355873cc1d7SStephen Warren 
356c40fdca6SSimon Glass 	if ((start + blkcnt) > block_dev->lba) {
35756196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
358ff8fef56SSascha Silbe 		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
359c40fdca6SSimon Glass 			start + blkcnt, block_dev->lba);
36056196826SPaul Burton #endif
361d2bf29e3SLei Wen 		return 0;
362d2bf29e3SLei Wen 	}
363272cc70bSAndy Fleming 
36411692991SSimon Glass 	if (mmc_set_blocklen(mmc, mmc->read_bl_len)) {
36511692991SSimon Glass 		debug("%s: Failed to set blocklen\n", __func__);
366272cc70bSAndy Fleming 		return 0;
36711692991SSimon Glass 	}
368272cc70bSAndy Fleming 
3694a1a06bcSAlagu Sankar 	do {
37093bfd616SPantelis Antoniou 		cur = (blocks_todo > mmc->cfg->b_max) ?
37193bfd616SPantelis Antoniou 			mmc->cfg->b_max : blocks_todo;
37211692991SSimon Glass 		if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
37311692991SSimon Glass 			debug("%s: Failed to read blocks\n", __func__);
3744a1a06bcSAlagu Sankar 			return 0;
37511692991SSimon Glass 		}
3764a1a06bcSAlagu Sankar 		blocks_todo -= cur;
3774a1a06bcSAlagu Sankar 		start += cur;
3784a1a06bcSAlagu Sankar 		dst += cur * mmc->read_bl_len;
3794a1a06bcSAlagu Sankar 	} while (blocks_todo > 0);
380272cc70bSAndy Fleming 
381272cc70bSAndy Fleming 	return blkcnt;
382272cc70bSAndy Fleming }
383272cc70bSAndy Fleming 
384fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc)
385272cc70bSAndy Fleming {
386272cc70bSAndy Fleming 	struct mmc_cmd cmd;
387272cc70bSAndy Fleming 	int err;
388272cc70bSAndy Fleming 
389272cc70bSAndy Fleming 	udelay(1000);
390272cc70bSAndy Fleming 
391272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
392272cc70bSAndy Fleming 	cmd.cmdarg = 0;
393272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_NONE;
394272cc70bSAndy Fleming 
395272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
396272cc70bSAndy Fleming 
397272cc70bSAndy Fleming 	if (err)
398272cc70bSAndy Fleming 		return err;
399272cc70bSAndy Fleming 
400272cc70bSAndy Fleming 	udelay(2000);
401272cc70bSAndy Fleming 
402272cc70bSAndy Fleming 	return 0;
403272cc70bSAndy Fleming }
404272cc70bSAndy Fleming 
405fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc)
406272cc70bSAndy Fleming {
407272cc70bSAndy Fleming 	int timeout = 1000;
408272cc70bSAndy Fleming 	int err;
409272cc70bSAndy Fleming 	struct mmc_cmd cmd;
410272cc70bSAndy Fleming 
4111677eef4SAndrew Gabbasov 	while (1) {
412272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_APP_CMD;
413272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1;
414272cc70bSAndy Fleming 		cmd.cmdarg = 0;
415272cc70bSAndy Fleming 
416272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
417272cc70bSAndy Fleming 
418272cc70bSAndy Fleming 		if (err)
419272cc70bSAndy Fleming 			return err;
420272cc70bSAndy Fleming 
421272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
422272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
423250de12bSStefano Babic 
424250de12bSStefano Babic 		/*
425250de12bSStefano Babic 		 * Most cards do not answer if some reserved bits
426250de12bSStefano Babic 		 * in the ocr are set. However, Some controller
427250de12bSStefano Babic 		 * can set bit 7 (reserved for low voltages), but
428250de12bSStefano Babic 		 * how to manage low voltages SD card is not yet
429250de12bSStefano Babic 		 * specified.
430250de12bSStefano Babic 		 */
431d52ebf10SThomas Chou 		cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
43293bfd616SPantelis Antoniou 			(mmc->cfg->voltages & 0xff8000);
433272cc70bSAndy Fleming 
434272cc70bSAndy Fleming 		if (mmc->version == SD_VERSION_2)
435272cc70bSAndy Fleming 			cmd.cmdarg |= OCR_HCS;
436272cc70bSAndy Fleming 
437272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
438272cc70bSAndy Fleming 
439272cc70bSAndy Fleming 		if (err)
440272cc70bSAndy Fleming 			return err;
441272cc70bSAndy Fleming 
4421677eef4SAndrew Gabbasov 		if (cmd.response[0] & OCR_BUSY)
4431677eef4SAndrew Gabbasov 			break;
444272cc70bSAndy Fleming 
4451677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
446915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
447272cc70bSAndy Fleming 
4481677eef4SAndrew Gabbasov 		udelay(1000);
4491677eef4SAndrew Gabbasov 	}
4501677eef4SAndrew Gabbasov 
451272cc70bSAndy Fleming 	if (mmc->version != SD_VERSION_2)
452272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
453272cc70bSAndy Fleming 
454d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
455d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
456d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
457d52ebf10SThomas Chou 		cmd.cmdarg = 0;
458d52ebf10SThomas Chou 
459d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
460d52ebf10SThomas Chou 
461d52ebf10SThomas Chou 		if (err)
462d52ebf10SThomas Chou 			return err;
463d52ebf10SThomas Chou 	}
464d52ebf10SThomas Chou 
465998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
466272cc70bSAndy Fleming 
467272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
468272cc70bSAndy Fleming 	mmc->rca = 0;
469272cc70bSAndy Fleming 
470272cc70bSAndy Fleming 	return 0;
471272cc70bSAndy Fleming }
472272cc70bSAndy Fleming 
4735289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg)
474272cc70bSAndy Fleming {
4755289b535SAndrew Gabbasov 	struct mmc_cmd cmd;
476272cc70bSAndy Fleming 	int err;
477272cc70bSAndy Fleming 
4785289b535SAndrew Gabbasov 	cmd.cmdidx = MMC_CMD_SEND_OP_COND;
4795289b535SAndrew Gabbasov 	cmd.resp_type = MMC_RSP_R3;
4805289b535SAndrew Gabbasov 	cmd.cmdarg = 0;
4815a20397bSRob Herring 	if (use_arg && !mmc_host_is_spi(mmc))
4825a20397bSRob Herring 		cmd.cmdarg = OCR_HCS |
48393bfd616SPantelis Antoniou 			(mmc->cfg->voltages &
484a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_VOLTAGE_MASK)) |
485a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_ACCESS_MODE);
486e9550449SChe-Liang Chiou 
4875289b535SAndrew Gabbasov 	err = mmc_send_cmd(mmc, &cmd, NULL);
488e9550449SChe-Liang Chiou 	if (err)
489e9550449SChe-Liang Chiou 		return err;
4905289b535SAndrew Gabbasov 	mmc->ocr = cmd.response[0];
491e9550449SChe-Liang Chiou 	return 0;
492e9550449SChe-Liang Chiou }
493e9550449SChe-Liang Chiou 
494750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc)
495e9550449SChe-Liang Chiou {
496e9550449SChe-Liang Chiou 	int err, i;
497e9550449SChe-Liang Chiou 
498272cc70bSAndy Fleming 	/* Some cards seem to need this */
499272cc70bSAndy Fleming 	mmc_go_idle(mmc);
500272cc70bSAndy Fleming 
50131cacbabSRaffaele Recalcati  	/* Asking to the card its capabilities */
502e9550449SChe-Liang Chiou 	for (i = 0; i < 2; i++) {
5035289b535SAndrew Gabbasov 		err = mmc_send_op_cond_iter(mmc, i != 0);
50431cacbabSRaffaele Recalcati 		if (err)
50531cacbabSRaffaele Recalcati 			return err;
50631cacbabSRaffaele Recalcati 
507e9550449SChe-Liang Chiou 		/* exit if not busy (flag seems to be inverted) */
508a626c8d4SAndrew Gabbasov 		if (mmc->ocr & OCR_BUSY)
509bd47c135SAndrew Gabbasov 			break;
510e9550449SChe-Liang Chiou 	}
511bd47c135SAndrew Gabbasov 	mmc->op_cond_pending = 1;
512bd47c135SAndrew Gabbasov 	return 0;
513e9550449SChe-Liang Chiou }
51431cacbabSRaffaele Recalcati 
515750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc)
516e9550449SChe-Liang Chiou {
517e9550449SChe-Liang Chiou 	struct mmc_cmd cmd;
518e9550449SChe-Liang Chiou 	int timeout = 1000;
519e9550449SChe-Liang Chiou 	uint start;
520e9550449SChe-Liang Chiou 	int err;
521e9550449SChe-Liang Chiou 
522e9550449SChe-Liang Chiou 	mmc->op_cond_pending = 0;
523cc17c01fSAndrew Gabbasov 	if (!(mmc->ocr & OCR_BUSY)) {
524d188b113SYangbo Lu 		/* Some cards seem to need this */
525d188b113SYangbo Lu 		mmc_go_idle(mmc);
526d188b113SYangbo Lu 
527e9550449SChe-Liang Chiou 		start = get_timer(0);
5281677eef4SAndrew Gabbasov 		while (1) {
5295289b535SAndrew Gabbasov 			err = mmc_send_op_cond_iter(mmc, 1);
530272cc70bSAndy Fleming 			if (err)
531272cc70bSAndy Fleming 				return err;
5321677eef4SAndrew Gabbasov 			if (mmc->ocr & OCR_BUSY)
5331677eef4SAndrew Gabbasov 				break;
534e9550449SChe-Liang Chiou 			if (get_timer(start) > timeout)
535915ffa52SJaehoon Chung 				return -EOPNOTSUPP;
536e9550449SChe-Liang Chiou 			udelay(100);
5371677eef4SAndrew Gabbasov 		}
538cc17c01fSAndrew Gabbasov 	}
539272cc70bSAndy Fleming 
540d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
541d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
542d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
543d52ebf10SThomas Chou 		cmd.cmdarg = 0;
544d52ebf10SThomas Chou 
545d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
546d52ebf10SThomas Chou 
547d52ebf10SThomas Chou 		if (err)
548d52ebf10SThomas Chou 			return err;
549a626c8d4SAndrew Gabbasov 
550a626c8d4SAndrew Gabbasov 		mmc->ocr = cmd.response[0];
551d52ebf10SThomas Chou 	}
552d52ebf10SThomas Chou 
553272cc70bSAndy Fleming 	mmc->version = MMC_VERSION_UNKNOWN;
554272cc70bSAndy Fleming 
555272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
556def816a2SStephen Warren 	mmc->rca = 1;
557272cc70bSAndy Fleming 
558272cc70bSAndy Fleming 	return 0;
559272cc70bSAndy Fleming }
560272cc70bSAndy Fleming 
561272cc70bSAndy Fleming 
562fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
563272cc70bSAndy Fleming {
564272cc70bSAndy Fleming 	struct mmc_cmd cmd;
565272cc70bSAndy Fleming 	struct mmc_data data;
566272cc70bSAndy Fleming 	int err;
567272cc70bSAndy Fleming 
568272cc70bSAndy Fleming 	/* Get the Card Status Register */
569272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
570272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
571272cc70bSAndy Fleming 	cmd.cmdarg = 0;
572272cc70bSAndy Fleming 
573cdfd1ac6SYoshihiro Shimoda 	data.dest = (char *)ext_csd;
574272cc70bSAndy Fleming 	data.blocks = 1;
5758bfa195eSSimon Glass 	data.blocksize = MMC_MAX_BLOCK_LEN;
576272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
577272cc70bSAndy Fleming 
578272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
579272cc70bSAndy Fleming 
580272cc70bSAndy Fleming 	return err;
581272cc70bSAndy Fleming }
582272cc70bSAndy Fleming 
583c40704f4SSimon Glass int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
584272cc70bSAndy Fleming {
585272cc70bSAndy Fleming 	struct mmc_cmd cmd;
5865d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
587a9003dc6SMaxime Ripard 	int retries = 3;
5885d4fc8d9SRaffaele Recalcati 	int ret;
589272cc70bSAndy Fleming 
590272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SWITCH;
591272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1b;
592272cc70bSAndy Fleming 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
593272cc70bSAndy Fleming 				 (index << 16) |
594272cc70bSAndy Fleming 				 (value << 8);
595272cc70bSAndy Fleming 
596a9003dc6SMaxime Ripard 	while (retries > 0) {
5975d4fc8d9SRaffaele Recalcati 		ret = mmc_send_cmd(mmc, &cmd, NULL);
5985d4fc8d9SRaffaele Recalcati 
5995d4fc8d9SRaffaele Recalcati 		/* Waiting for the ready status */
600a9003dc6SMaxime Ripard 		if (!ret) {
60193ad0d18SJan Kloetzke 			ret = mmc_send_status(mmc, timeout);
602a9003dc6SMaxime Ripard 			return ret;
603a9003dc6SMaxime Ripard 		}
604a9003dc6SMaxime Ripard 
605a9003dc6SMaxime Ripard 		retries--;
606a9003dc6SMaxime Ripard 	}
6075d4fc8d9SRaffaele Recalcati 
6085d4fc8d9SRaffaele Recalcati 	return ret;
6095d4fc8d9SRaffaele Recalcati 
610272cc70bSAndy Fleming }
611272cc70bSAndy Fleming 
6123862b854SJean-Jacques Hiblot static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode)
613272cc70bSAndy Fleming {
614272cc70bSAndy Fleming 	int err;
6153862b854SJean-Jacques Hiblot 	int speed_bits;
6163862b854SJean-Jacques Hiblot 
6173862b854SJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
6183862b854SJean-Jacques Hiblot 
6193862b854SJean-Jacques Hiblot 	switch (mode) {
6203862b854SJean-Jacques Hiblot 	case MMC_HS:
6213862b854SJean-Jacques Hiblot 	case MMC_HS_52:
6223862b854SJean-Jacques Hiblot 	case MMC_DDR_52:
6233862b854SJean-Jacques Hiblot 		speed_bits = EXT_CSD_TIMING_HS;
6243862b854SJean-Jacques Hiblot 	case MMC_LEGACY:
6253862b854SJean-Jacques Hiblot 		speed_bits = EXT_CSD_TIMING_LEGACY;
6263862b854SJean-Jacques Hiblot 		break;
6273862b854SJean-Jacques Hiblot 	default:
6283862b854SJean-Jacques Hiblot 		return -EINVAL;
6293862b854SJean-Jacques Hiblot 	}
6303862b854SJean-Jacques Hiblot 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
6313862b854SJean-Jacques Hiblot 			 speed_bits);
6323862b854SJean-Jacques Hiblot 	if (err)
6333862b854SJean-Jacques Hiblot 		return err;
6343862b854SJean-Jacques Hiblot 
6353862b854SJean-Jacques Hiblot 	if ((mode == MMC_HS) || (mode == MMC_HS_52)) {
6363862b854SJean-Jacques Hiblot 		/* Now check to see that it worked */
6373862b854SJean-Jacques Hiblot 		err = mmc_send_ext_csd(mmc, test_csd);
6383862b854SJean-Jacques Hiblot 		if (err)
6393862b854SJean-Jacques Hiblot 			return err;
6403862b854SJean-Jacques Hiblot 
6413862b854SJean-Jacques Hiblot 		/* No high-speed support */
6423862b854SJean-Jacques Hiblot 		if (!test_csd[EXT_CSD_HS_TIMING])
6433862b854SJean-Jacques Hiblot 			return -ENOTSUPP;
6443862b854SJean-Jacques Hiblot 	}
6453862b854SJean-Jacques Hiblot 
6463862b854SJean-Jacques Hiblot 	return 0;
6473862b854SJean-Jacques Hiblot }
6483862b854SJean-Jacques Hiblot 
6493862b854SJean-Jacques Hiblot static int mmc_get_capabilities(struct mmc *mmc)
6503862b854SJean-Jacques Hiblot {
6513862b854SJean-Jacques Hiblot 	u8 *ext_csd = mmc->ext_csd;
6523862b854SJean-Jacques Hiblot 	char cardtype;
653272cc70bSAndy Fleming 
654d0c221feSJean-Jacques Hiblot 	mmc->card_caps = MMC_MODE_1BIT;
655272cc70bSAndy Fleming 
656d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
657d52ebf10SThomas Chou 		return 0;
658d52ebf10SThomas Chou 
659272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
660272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
661272cc70bSAndy Fleming 		return 0;
662272cc70bSAndy Fleming 
6633862b854SJean-Jacques Hiblot 	if (!ext_csd) {
6643862b854SJean-Jacques Hiblot 		printf("No ext_csd found!\n"); /* this should enver happen */
6653862b854SJean-Jacques Hiblot 		return -ENOTSUPP;
6663862b854SJean-Jacques Hiblot 	}
6673862b854SJean-Jacques Hiblot 
668fc5b32fbSAndrew Gabbasov 	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
669fc5b32fbSAndrew Gabbasov 
6700560db18SLei Wen 	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf;
671272cc70bSAndy Fleming 
672272cc70bSAndy Fleming 	/* High Speed is set, there are two types: 52MHz and 26MHz */
673d22e3d46SJaehoon Chung 	if (cardtype & EXT_CSD_CARD_TYPE_52) {
6743862b854SJean-Jacques Hiblot 		if (cardtype & EXT_CSD_CARD_TYPE_DDR_52)
675d22e3d46SJaehoon Chung 			mmc->card_caps |= MMC_MODE_DDR_52MHz;
6763862b854SJean-Jacques Hiblot 		mmc->card_caps |= MMC_MODE_HS_52MHz;
677d22e3d46SJaehoon Chung 	}
6783862b854SJean-Jacques Hiblot 	if (cardtype & EXT_CSD_CARD_TYPE_26)
6793862b854SJean-Jacques Hiblot 		mmc->card_caps |= MMC_MODE_HS;
680272cc70bSAndy Fleming 
681272cc70bSAndy Fleming 	return 0;
682272cc70bSAndy Fleming }
683272cc70bSAndy Fleming 
684f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num)
685f866a46dSStephen Warren {
686f866a46dSStephen Warren 	switch (part_num) {
687f866a46dSStephen Warren 	case 0:
688f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_user;
689f866a46dSStephen Warren 		break;
690f866a46dSStephen Warren 	case 1:
691f866a46dSStephen Warren 	case 2:
692f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_boot;
693f866a46dSStephen Warren 		break;
694f866a46dSStephen Warren 	case 3:
695f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_rpmb;
696f866a46dSStephen Warren 		break;
697f866a46dSStephen Warren 	case 4:
698f866a46dSStephen Warren 	case 5:
699f866a46dSStephen Warren 	case 6:
700f866a46dSStephen Warren 	case 7:
701f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_gp[part_num - 4];
702f866a46dSStephen Warren 		break;
703f866a46dSStephen Warren 	default:
704f866a46dSStephen Warren 		return -1;
705f866a46dSStephen Warren 	}
706f866a46dSStephen Warren 
707c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len);
708f866a46dSStephen Warren 
709f866a46dSStephen Warren 	return 0;
710f866a46dSStephen Warren }
711f866a46dSStephen Warren 
7127dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num)
713bc897b1dSLei Wen {
714f866a46dSStephen Warren 	int ret;
715bc897b1dSLei Wen 
716f866a46dSStephen Warren 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
717bc897b1dSLei Wen 			 (mmc->part_config & ~PART_ACCESS_MASK)
718bc897b1dSLei Wen 			 | (part_num & PART_ACCESS_MASK));
719f866a46dSStephen Warren 
7206dc93e70SPeter Bigot 	/*
7216dc93e70SPeter Bigot 	 * Set the capacity if the switch succeeded or was intended
7226dc93e70SPeter Bigot 	 * to return to representing the raw device.
7236dc93e70SPeter Bigot 	 */
724873cc1d7SStephen Warren 	if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) {
7256dc93e70SPeter Bigot 		ret = mmc_set_capacity(mmc, part_num);
726fdbb139fSSimon Glass 		mmc_get_blk_desc(mmc)->hwpart = part_num;
727873cc1d7SStephen Warren 	}
7286dc93e70SPeter Bigot 
7296dc93e70SPeter Bigot 	return ret;
730bc897b1dSLei Wen }
731bc897b1dSLei Wen 
732ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc,
733ac9da0e0SDiego Santa Cruz 		      const struct mmc_hwpart_conf *conf,
734ac9da0e0SDiego Santa Cruz 		      enum mmc_hwpart_conf_mode mode)
735ac9da0e0SDiego Santa Cruz {
736ac9da0e0SDiego Santa Cruz 	u8 part_attrs = 0;
737ac9da0e0SDiego Santa Cruz 	u32 enh_size_mult;
738ac9da0e0SDiego Santa Cruz 	u32 enh_start_addr;
739ac9da0e0SDiego Santa Cruz 	u32 gp_size_mult[4];
740ac9da0e0SDiego Santa Cruz 	u32 max_enh_size_mult;
741ac9da0e0SDiego Santa Cruz 	u32 tot_enh_size_mult = 0;
7428dda5b0eSDiego Santa Cruz 	u8 wr_rel_set;
743ac9da0e0SDiego Santa Cruz 	int i, pidx, err;
744ac9da0e0SDiego Santa Cruz 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
745ac9da0e0SDiego Santa Cruz 
746ac9da0e0SDiego Santa Cruz 	if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE)
747ac9da0e0SDiego Santa Cruz 		return -EINVAL;
748ac9da0e0SDiego Santa Cruz 
749ac9da0e0SDiego Santa Cruz 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) {
750ac9da0e0SDiego Santa Cruz 		printf("eMMC >= 4.4 required for enhanced user data area\n");
751ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
752ac9da0e0SDiego Santa Cruz 	}
753ac9da0e0SDiego Santa Cruz 
754ac9da0e0SDiego Santa Cruz 	if (!(mmc->part_support & PART_SUPPORT)) {
755ac9da0e0SDiego Santa Cruz 		printf("Card does not support partitioning\n");
756ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
757ac9da0e0SDiego Santa Cruz 	}
758ac9da0e0SDiego Santa Cruz 
759ac9da0e0SDiego Santa Cruz 	if (!mmc->hc_wp_grp_size) {
760ac9da0e0SDiego Santa Cruz 		printf("Card does not define HC WP group size\n");
761ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
762ac9da0e0SDiego Santa Cruz 	}
763ac9da0e0SDiego Santa Cruz 
764ac9da0e0SDiego Santa Cruz 	/* check partition alignment and total enhanced size */
765ac9da0e0SDiego Santa Cruz 	if (conf->user.enh_size) {
766ac9da0e0SDiego Santa Cruz 		if (conf->user.enh_size % mmc->hc_wp_grp_size ||
767ac9da0e0SDiego Santa Cruz 		    conf->user.enh_start % mmc->hc_wp_grp_size) {
768ac9da0e0SDiego Santa Cruz 			printf("User data enhanced area not HC WP group "
769ac9da0e0SDiego Santa Cruz 			       "size aligned\n");
770ac9da0e0SDiego Santa Cruz 			return -EINVAL;
771ac9da0e0SDiego Santa Cruz 		}
772ac9da0e0SDiego Santa Cruz 		part_attrs |= EXT_CSD_ENH_USR;
773ac9da0e0SDiego Santa Cruz 		enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size;
774ac9da0e0SDiego Santa Cruz 		if (mmc->high_capacity) {
775ac9da0e0SDiego Santa Cruz 			enh_start_addr = conf->user.enh_start;
776ac9da0e0SDiego Santa Cruz 		} else {
777ac9da0e0SDiego Santa Cruz 			enh_start_addr = (conf->user.enh_start << 9);
778ac9da0e0SDiego Santa Cruz 		}
779ac9da0e0SDiego Santa Cruz 	} else {
780ac9da0e0SDiego Santa Cruz 		enh_size_mult = 0;
781ac9da0e0SDiego Santa Cruz 		enh_start_addr = 0;
782ac9da0e0SDiego Santa Cruz 	}
783ac9da0e0SDiego Santa Cruz 	tot_enh_size_mult += enh_size_mult;
784ac9da0e0SDiego Santa Cruz 
785ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
786ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) {
787ac9da0e0SDiego Santa Cruz 			printf("GP%i partition not HC WP group size "
788ac9da0e0SDiego Santa Cruz 			       "aligned\n", pidx+1);
789ac9da0e0SDiego Santa Cruz 			return -EINVAL;
790ac9da0e0SDiego Santa Cruz 		}
791ac9da0e0SDiego Santa Cruz 		gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size;
792ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) {
793ac9da0e0SDiego Santa Cruz 			part_attrs |= EXT_CSD_ENH_GP(pidx);
794ac9da0e0SDiego Santa Cruz 			tot_enh_size_mult += gp_size_mult[pidx];
795ac9da0e0SDiego Santa Cruz 		}
796ac9da0e0SDiego Santa Cruz 	}
797ac9da0e0SDiego Santa Cruz 
798ac9da0e0SDiego Santa Cruz 	if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) {
799ac9da0e0SDiego Santa Cruz 		printf("Card does not support enhanced attribute\n");
800ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
801ac9da0e0SDiego Santa Cruz 	}
802ac9da0e0SDiego Santa Cruz 
803ac9da0e0SDiego Santa Cruz 	err = mmc_send_ext_csd(mmc, ext_csd);
804ac9da0e0SDiego Santa Cruz 	if (err)
805ac9da0e0SDiego Santa Cruz 		return err;
806ac9da0e0SDiego Santa Cruz 
807ac9da0e0SDiego Santa Cruz 	max_enh_size_mult =
808ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) +
809ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) +
810ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT];
811ac9da0e0SDiego Santa Cruz 	if (tot_enh_size_mult > max_enh_size_mult) {
812ac9da0e0SDiego Santa Cruz 		printf("Total enhanced size exceeds maximum (%u > %u)\n",
813ac9da0e0SDiego Santa Cruz 		       tot_enh_size_mult, max_enh_size_mult);
814ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
815ac9da0e0SDiego Santa Cruz 	}
816ac9da0e0SDiego Santa Cruz 
8178dda5b0eSDiego Santa Cruz 	/* The default value of EXT_CSD_WR_REL_SET is device
8188dda5b0eSDiego Santa Cruz 	 * dependent, the values can only be changed if the
8198dda5b0eSDiego Santa Cruz 	 * EXT_CSD_HS_CTRL_REL bit is set. The values can be
8208dda5b0eSDiego Santa Cruz 	 * changed only once and before partitioning is completed. */
8218dda5b0eSDiego Santa Cruz 	wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
8228dda5b0eSDiego Santa Cruz 	if (conf->user.wr_rel_change) {
8238dda5b0eSDiego Santa Cruz 		if (conf->user.wr_rel_set)
8248dda5b0eSDiego Santa Cruz 			wr_rel_set |= EXT_CSD_WR_DATA_REL_USR;
8258dda5b0eSDiego Santa Cruz 		else
8268dda5b0eSDiego Santa Cruz 			wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR;
8278dda5b0eSDiego Santa Cruz 	}
8288dda5b0eSDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
8298dda5b0eSDiego Santa Cruz 		if (conf->gp_part[pidx].wr_rel_change) {
8308dda5b0eSDiego Santa Cruz 			if (conf->gp_part[pidx].wr_rel_set)
8318dda5b0eSDiego Santa Cruz 				wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx);
8328dda5b0eSDiego Santa Cruz 			else
8338dda5b0eSDiego Santa Cruz 				wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx);
8348dda5b0eSDiego Santa Cruz 		}
8358dda5b0eSDiego Santa Cruz 	}
8368dda5b0eSDiego Santa Cruz 
8378dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] &&
8388dda5b0eSDiego Santa Cruz 	    !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) {
8398dda5b0eSDiego Santa Cruz 		puts("Card does not support host controlled partition write "
8408dda5b0eSDiego Santa Cruz 		     "reliability settings\n");
8418dda5b0eSDiego Santa Cruz 		return -EMEDIUMTYPE;
8428dda5b0eSDiego Santa Cruz 	}
8438dda5b0eSDiego Santa Cruz 
844ac9da0e0SDiego Santa Cruz 	if (ext_csd[EXT_CSD_PARTITION_SETTING] &
845ac9da0e0SDiego Santa Cruz 	    EXT_CSD_PARTITION_SETTING_COMPLETED) {
846ac9da0e0SDiego Santa Cruz 		printf("Card already partitioned\n");
847ac9da0e0SDiego Santa Cruz 		return -EPERM;
848ac9da0e0SDiego Santa Cruz 	}
849ac9da0e0SDiego Santa Cruz 
850ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_CHECK)
851ac9da0e0SDiego Santa Cruz 		return 0;
852ac9da0e0SDiego Santa Cruz 
853ac9da0e0SDiego Santa Cruz 	/* Partitioning requires high-capacity size definitions */
854ac9da0e0SDiego Santa Cruz 	if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) {
855ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
856ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ERASE_GROUP_DEF, 1);
857ac9da0e0SDiego Santa Cruz 
858ac9da0e0SDiego Santa Cruz 		if (err)
859ac9da0e0SDiego Santa Cruz 			return err;
860ac9da0e0SDiego Santa Cruz 
861ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
862ac9da0e0SDiego Santa Cruz 
863ac9da0e0SDiego Santa Cruz 		/* update erase group size to be high-capacity */
864ac9da0e0SDiego Santa Cruz 		mmc->erase_grp_size =
865ac9da0e0SDiego Santa Cruz 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
866ac9da0e0SDiego Santa Cruz 
867ac9da0e0SDiego Santa Cruz 	}
868ac9da0e0SDiego Santa Cruz 
869ac9da0e0SDiego Santa Cruz 	/* all OK, write the configuration */
870ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 4; i++) {
871ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
872ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_START_ADDR+i,
873ac9da0e0SDiego Santa Cruz 				 (enh_start_addr >> (i*8)) & 0xFF);
874ac9da0e0SDiego Santa Cruz 		if (err)
875ac9da0e0SDiego Santa Cruz 			return err;
876ac9da0e0SDiego Santa Cruz 	}
877ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 3; i++) {
878ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
879ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_SIZE_MULT+i,
880ac9da0e0SDiego Santa Cruz 				 (enh_size_mult >> (i*8)) & 0xFF);
881ac9da0e0SDiego Santa Cruz 		if (err)
882ac9da0e0SDiego Santa Cruz 			return err;
883ac9da0e0SDiego Santa Cruz 	}
884ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
885ac9da0e0SDiego Santa Cruz 		for (i = 0; i < 3; i++) {
886ac9da0e0SDiego Santa Cruz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
887ac9da0e0SDiego Santa Cruz 					 EXT_CSD_GP_SIZE_MULT+pidx*3+i,
888ac9da0e0SDiego Santa Cruz 					 (gp_size_mult[pidx] >> (i*8)) & 0xFF);
889ac9da0e0SDiego Santa Cruz 			if (err)
890ac9da0e0SDiego Santa Cruz 				return err;
891ac9da0e0SDiego Santa Cruz 		}
892ac9da0e0SDiego Santa Cruz 	}
893ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
894ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs);
895ac9da0e0SDiego Santa Cruz 	if (err)
896ac9da0e0SDiego Santa Cruz 		return err;
897ac9da0e0SDiego Santa Cruz 
898ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_SET)
899ac9da0e0SDiego Santa Cruz 		return 0;
900ac9da0e0SDiego Santa Cruz 
9018dda5b0eSDiego Santa Cruz 	/* The WR_REL_SET is a write-once register but shall be
9028dda5b0eSDiego Santa Cruz 	 * written before setting PART_SETTING_COMPLETED. As it is
9038dda5b0eSDiego Santa Cruz 	 * write-once we can only write it when completing the
9048dda5b0eSDiego Santa Cruz 	 * partitioning. */
9058dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) {
9068dda5b0eSDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
9078dda5b0eSDiego Santa Cruz 				 EXT_CSD_WR_REL_SET, wr_rel_set);
9088dda5b0eSDiego Santa Cruz 		if (err)
9098dda5b0eSDiego Santa Cruz 			return err;
9108dda5b0eSDiego Santa Cruz 	}
9118dda5b0eSDiego Santa Cruz 
912ac9da0e0SDiego Santa Cruz 	/* Setting PART_SETTING_COMPLETED confirms the partition
913ac9da0e0SDiego Santa Cruz 	 * configuration but it only becomes effective after power
914ac9da0e0SDiego Santa Cruz 	 * cycle, so we do not adjust the partition related settings
915ac9da0e0SDiego Santa Cruz 	 * in the mmc struct. */
916ac9da0e0SDiego Santa Cruz 
917ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
918ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING,
919ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING_COMPLETED);
920ac9da0e0SDiego Santa Cruz 	if (err)
921ac9da0e0SDiego Santa Cruz 		return err;
922ac9da0e0SDiego Santa Cruz 
923ac9da0e0SDiego Santa Cruz 	return 0;
924ac9da0e0SDiego Santa Cruz }
925ac9da0e0SDiego Santa Cruz 
926e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
92748972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
92848972d90SThierry Reding {
92948972d90SThierry Reding 	int cd;
93048972d90SThierry Reding 
93148972d90SThierry Reding 	cd = board_mmc_getcd(mmc);
93248972d90SThierry Reding 
933d4e1da4eSPeter Korsgaard 	if (cd < 0) {
93493bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getcd)
93593bfd616SPantelis Antoniou 			cd = mmc->cfg->ops->getcd(mmc);
936d4e1da4eSPeter Korsgaard 		else
937d4e1da4eSPeter Korsgaard 			cd = 1;
938d4e1da4eSPeter Korsgaard 	}
93948972d90SThierry Reding 
94048972d90SThierry Reding 	return cd;
94148972d90SThierry Reding }
9428ca51e51SSimon Glass #endif
94348972d90SThierry Reding 
944fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
945272cc70bSAndy Fleming {
946272cc70bSAndy Fleming 	struct mmc_cmd cmd;
947272cc70bSAndy Fleming 	struct mmc_data data;
948272cc70bSAndy Fleming 
949272cc70bSAndy Fleming 	/* Switch the frequency */
950272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
951272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
952272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
953272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
954272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
955272cc70bSAndy Fleming 
956272cc70bSAndy Fleming 	data.dest = (char *)resp;
957272cc70bSAndy Fleming 	data.blocksize = 64;
958272cc70bSAndy Fleming 	data.blocks = 1;
959272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
960272cc70bSAndy Fleming 
961272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
962272cc70bSAndy Fleming }
963272cc70bSAndy Fleming 
964272cc70bSAndy Fleming 
965d0c221feSJean-Jacques Hiblot static int sd_get_capabilities(struct mmc *mmc)
966272cc70bSAndy Fleming {
967272cc70bSAndy Fleming 	int err;
968272cc70bSAndy Fleming 	struct mmc_cmd cmd;
96918e7c8f6SSuniel Mahesh 	ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2);
97018e7c8f6SSuniel Mahesh 	ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16);
971272cc70bSAndy Fleming 	struct mmc_data data;
972272cc70bSAndy Fleming 	int timeout;
973272cc70bSAndy Fleming 
974d0c221feSJean-Jacques Hiblot 	mmc->card_caps = MMC_MODE_1BIT;
975272cc70bSAndy Fleming 
976d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
977d52ebf10SThomas Chou 		return 0;
978d52ebf10SThomas Chou 
979272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
980272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
981272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
982272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
983272cc70bSAndy Fleming 
984272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
985272cc70bSAndy Fleming 
986272cc70bSAndy Fleming 	if (err)
987272cc70bSAndy Fleming 		return err;
988272cc70bSAndy Fleming 
989272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
990272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
991272cc70bSAndy Fleming 	cmd.cmdarg = 0;
992272cc70bSAndy Fleming 
993272cc70bSAndy Fleming 	timeout = 3;
994272cc70bSAndy Fleming 
995272cc70bSAndy Fleming retry_scr:
996f781dd38SAnton staaf 	data.dest = (char *)scr;
997272cc70bSAndy Fleming 	data.blocksize = 8;
998272cc70bSAndy Fleming 	data.blocks = 1;
999272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
1000272cc70bSAndy Fleming 
1001272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
1002272cc70bSAndy Fleming 
1003272cc70bSAndy Fleming 	if (err) {
1004272cc70bSAndy Fleming 		if (timeout--)
1005272cc70bSAndy Fleming 			goto retry_scr;
1006272cc70bSAndy Fleming 
1007272cc70bSAndy Fleming 		return err;
1008272cc70bSAndy Fleming 	}
1009272cc70bSAndy Fleming 
10104e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
10114e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
1012272cc70bSAndy Fleming 
1013272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
1014272cc70bSAndy Fleming 	case 0:
1015272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1016272cc70bSAndy Fleming 		break;
1017272cc70bSAndy Fleming 	case 1:
1018272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_10;
1019272cc70bSAndy Fleming 		break;
1020272cc70bSAndy Fleming 	case 2:
1021272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
10221741c64dSJaehoon Chung 		if ((mmc->scr[0] >> 15) & 0x1)
10231741c64dSJaehoon Chung 			mmc->version = SD_VERSION_3;
1024272cc70bSAndy Fleming 		break;
1025272cc70bSAndy Fleming 	default:
1026272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1027272cc70bSAndy Fleming 		break;
1028272cc70bSAndy Fleming 	}
1029272cc70bSAndy Fleming 
1030b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
1031b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
1032b44c7083SAlagu Sankar 
1033272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
1034272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
1035272cc70bSAndy Fleming 		return 0;
1036272cc70bSAndy Fleming 
1037272cc70bSAndy Fleming 	timeout = 4;
1038272cc70bSAndy Fleming 	while (timeout--) {
1039272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
1040f781dd38SAnton staaf 				(u8 *)switch_status);
1041272cc70bSAndy Fleming 
1042272cc70bSAndy Fleming 		if (err)
1043272cc70bSAndy Fleming 			return err;
1044272cc70bSAndy Fleming 
1045272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
10464e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
1047272cc70bSAndy Fleming 			break;
1048272cc70bSAndy Fleming 	}
1049272cc70bSAndy Fleming 
1050272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
1051d0c221feSJean-Jacques Hiblot 	if (__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)
1052d0c221feSJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(SD_HS);
1053272cc70bSAndy Fleming 
10542c3fbf4cSMacpaul Lin 	return 0;
1055d0c221feSJean-Jacques Hiblot }
1056d0c221feSJean-Jacques Hiblot 
1057d0c221feSJean-Jacques Hiblot static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode)
1058d0c221feSJean-Jacques Hiblot {
1059d0c221feSJean-Jacques Hiblot 	int err;
1060d0c221feSJean-Jacques Hiblot 
1061d0c221feSJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
10622c3fbf4cSMacpaul Lin 
1063f781dd38SAnton staaf 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status);
1064272cc70bSAndy Fleming 	if (err)
1065272cc70bSAndy Fleming 		return err;
1066272cc70bSAndy Fleming 
1067d0c221feSJean-Jacques Hiblot 	if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) != 0x01000000)
1068d0c221feSJean-Jacques Hiblot 		return -ENOTSUPP;
1069d0c221feSJean-Jacques Hiblot 
1070d0c221feSJean-Jacques Hiblot 	return 0;
1071d0c221feSJean-Jacques Hiblot }
1072d0c221feSJean-Jacques Hiblot 
1073d0c221feSJean-Jacques Hiblot int sd_select_bus_width(struct mmc *mmc, int w)
1074d0c221feSJean-Jacques Hiblot {
1075d0c221feSJean-Jacques Hiblot 	int err;
1076d0c221feSJean-Jacques Hiblot 	struct mmc_cmd cmd;
1077d0c221feSJean-Jacques Hiblot 
1078d0c221feSJean-Jacques Hiblot 	if ((w != 4) && (w != 1))
1079d0c221feSJean-Jacques Hiblot 		return -EINVAL;
1080d0c221feSJean-Jacques Hiblot 
1081d0c221feSJean-Jacques Hiblot 	cmd.cmdidx = MMC_CMD_APP_CMD;
1082d0c221feSJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
1083d0c221feSJean-Jacques Hiblot 	cmd.cmdarg = mmc->rca << 16;
1084d0c221feSJean-Jacques Hiblot 
1085d0c221feSJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
1086d0c221feSJean-Jacques Hiblot 	if (err)
1087d0c221feSJean-Jacques Hiblot 		return err;
1088d0c221feSJean-Jacques Hiblot 
1089d0c221feSJean-Jacques Hiblot 	cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
1090d0c221feSJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
1091d0c221feSJean-Jacques Hiblot 	if (w == 4)
1092d0c221feSJean-Jacques Hiblot 		cmd.cmdarg = 2;
1093d0c221feSJean-Jacques Hiblot 	else if (w == 1)
1094d0c221feSJean-Jacques Hiblot 		cmd.cmdarg = 0;
1095d0c221feSJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
1096d0c221feSJean-Jacques Hiblot 	if (err)
1097d0c221feSJean-Jacques Hiblot 		return err;
1098272cc70bSAndy Fleming 
1099272cc70bSAndy Fleming 	return 0;
1100272cc70bSAndy Fleming }
1101272cc70bSAndy Fleming 
11023697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc)
11033697e599SPeng Fan {
11043697e599SPeng Fan 	int err, i;
11053697e599SPeng Fan 	struct mmc_cmd cmd;
11063697e599SPeng Fan 	ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16);
11073697e599SPeng Fan 	struct mmc_data data;
11083697e599SPeng Fan 	int timeout = 3;
11093697e599SPeng Fan 	unsigned int au, eo, et, es;
11103697e599SPeng Fan 
11113697e599SPeng Fan 	cmd.cmdidx = MMC_CMD_APP_CMD;
11123697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
11133697e599SPeng Fan 	cmd.cmdarg = mmc->rca << 16;
11143697e599SPeng Fan 
11153697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, NULL);
11163697e599SPeng Fan 	if (err)
11173697e599SPeng Fan 		return err;
11183697e599SPeng Fan 
11193697e599SPeng Fan 	cmd.cmdidx = SD_CMD_APP_SD_STATUS;
11203697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
11213697e599SPeng Fan 	cmd.cmdarg = 0;
11223697e599SPeng Fan 
11233697e599SPeng Fan retry_ssr:
11243697e599SPeng Fan 	data.dest = (char *)ssr;
11253697e599SPeng Fan 	data.blocksize = 64;
11263697e599SPeng Fan 	data.blocks = 1;
11273697e599SPeng Fan 	data.flags = MMC_DATA_READ;
11283697e599SPeng Fan 
11293697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, &data);
11303697e599SPeng Fan 	if (err) {
11313697e599SPeng Fan 		if (timeout--)
11323697e599SPeng Fan 			goto retry_ssr;
11333697e599SPeng Fan 
11343697e599SPeng Fan 		return err;
11353697e599SPeng Fan 	}
11363697e599SPeng Fan 
11373697e599SPeng Fan 	for (i = 0; i < 16; i++)
11383697e599SPeng Fan 		ssr[i] = be32_to_cpu(ssr[i]);
11393697e599SPeng Fan 
11403697e599SPeng Fan 	au = (ssr[2] >> 12) & 0xF;
11413697e599SPeng Fan 	if ((au <= 9) || (mmc->version == SD_VERSION_3)) {
11423697e599SPeng Fan 		mmc->ssr.au = sd_au_size[au];
11433697e599SPeng Fan 		es = (ssr[3] >> 24) & 0xFF;
11443697e599SPeng Fan 		es |= (ssr[2] & 0xFF) << 8;
11453697e599SPeng Fan 		et = (ssr[3] >> 18) & 0x3F;
11463697e599SPeng Fan 		if (es && et) {
11473697e599SPeng Fan 			eo = (ssr[3] >> 16) & 0x3;
11483697e599SPeng Fan 			mmc->ssr.erase_timeout = (et * 1000) / es;
11493697e599SPeng Fan 			mmc->ssr.erase_offset = eo * 1000;
11503697e599SPeng Fan 		}
11513697e599SPeng Fan 	} else {
11523697e599SPeng Fan 		debug("Invalid Allocation Unit Size.\n");
11533697e599SPeng Fan 	}
11543697e599SPeng Fan 
11553697e599SPeng Fan 	return 0;
11563697e599SPeng Fan }
11573697e599SPeng Fan 
1158272cc70bSAndy Fleming /* frequency bases */
1159272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
11605f837c2cSMike Frysinger static const int fbase[] = {
1161272cc70bSAndy Fleming 	10000,
1162272cc70bSAndy Fleming 	100000,
1163272cc70bSAndy Fleming 	1000000,
1164272cc70bSAndy Fleming 	10000000,
1165272cc70bSAndy Fleming };
1166272cc70bSAndy Fleming 
1167272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
1168272cc70bSAndy Fleming  * to platforms without floating point.
1169272cc70bSAndy Fleming  */
117061fe076fSSimon Glass static const u8 multipliers[] = {
1171272cc70bSAndy Fleming 	0,	/* reserved */
1172272cc70bSAndy Fleming 	10,
1173272cc70bSAndy Fleming 	12,
1174272cc70bSAndy Fleming 	13,
1175272cc70bSAndy Fleming 	15,
1176272cc70bSAndy Fleming 	20,
1177272cc70bSAndy Fleming 	25,
1178272cc70bSAndy Fleming 	30,
1179272cc70bSAndy Fleming 	35,
1180272cc70bSAndy Fleming 	40,
1181272cc70bSAndy Fleming 	45,
1182272cc70bSAndy Fleming 	50,
1183272cc70bSAndy Fleming 	55,
1184272cc70bSAndy Fleming 	60,
1185272cc70bSAndy Fleming 	70,
1186272cc70bSAndy Fleming 	80,
1187272cc70bSAndy Fleming };
1188272cc70bSAndy Fleming 
1189d0c221feSJean-Jacques Hiblot static inline int bus_width(uint cap)
1190d0c221feSJean-Jacques Hiblot {
1191d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_8BIT)
1192d0c221feSJean-Jacques Hiblot 		return 8;
1193d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_4BIT)
1194d0c221feSJean-Jacques Hiblot 		return 4;
1195d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_1BIT)
1196d0c221feSJean-Jacques Hiblot 		return 1;
1197d0c221feSJean-Jacques Hiblot 	printf("invalid bus witdh capability 0x%x\n", cap);
1198d0c221feSJean-Jacques Hiblot 	return 0;
1199d0c221feSJean-Jacques Hiblot }
1200d0c221feSJean-Jacques Hiblot 
1201e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
1202318a7a57SJean-Jacques Hiblot static void mmc_send_init_stream(struct mmc *mmc)
1203318a7a57SJean-Jacques Hiblot {
1204318a7a57SJean-Jacques Hiblot }
1205318a7a57SJean-Jacques Hiblot 
12062a4d212fSKishon Vijay Abraham I static int mmc_set_ios(struct mmc *mmc)
1207272cc70bSAndy Fleming {
12082a4d212fSKishon Vijay Abraham I 	int ret = 0;
12092a4d212fSKishon Vijay Abraham I 
121093bfd616SPantelis Antoniou 	if (mmc->cfg->ops->set_ios)
12112a4d212fSKishon Vijay Abraham I 		ret = mmc->cfg->ops->set_ios(mmc);
12122a4d212fSKishon Vijay Abraham I 
12132a4d212fSKishon Vijay Abraham I 	return ret;
1214272cc70bSAndy Fleming }
12158ca51e51SSimon Glass #endif
1216272cc70bSAndy Fleming 
121735f67820SKishon Vijay Abraham I int mmc_set_clock(struct mmc *mmc, uint clock, bool disable)
1218272cc70bSAndy Fleming {
121993bfd616SPantelis Antoniou 	if (clock > mmc->cfg->f_max)
122093bfd616SPantelis Antoniou 		clock = mmc->cfg->f_max;
1221272cc70bSAndy Fleming 
122293bfd616SPantelis Antoniou 	if (clock < mmc->cfg->f_min)
122393bfd616SPantelis Antoniou 		clock = mmc->cfg->f_min;
1224272cc70bSAndy Fleming 
1225272cc70bSAndy Fleming 	mmc->clock = clock;
122635f67820SKishon Vijay Abraham I 	mmc->clk_disable = disable;
1227272cc70bSAndy Fleming 
12282a4d212fSKishon Vijay Abraham I 	return mmc_set_ios(mmc);
1229272cc70bSAndy Fleming }
1230272cc70bSAndy Fleming 
12312a4d212fSKishon Vijay Abraham I static int mmc_set_bus_width(struct mmc *mmc, uint width)
1232272cc70bSAndy Fleming {
1233272cc70bSAndy Fleming 	mmc->bus_width = width;
1234272cc70bSAndy Fleming 
12352a4d212fSKishon Vijay Abraham I 	return mmc_set_ios(mmc);
1236272cc70bSAndy Fleming }
1237272cc70bSAndy Fleming 
12384c9d2aaaSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG)
12394c9d2aaaSJean-Jacques Hiblot /*
12404c9d2aaaSJean-Jacques Hiblot  * helper function to display the capabilities in a human
12414c9d2aaaSJean-Jacques Hiblot  * friendly manner. The capabilities include bus width and
12424c9d2aaaSJean-Jacques Hiblot  * supported modes.
12434c9d2aaaSJean-Jacques Hiblot  */
12444c9d2aaaSJean-Jacques Hiblot void mmc_dump_capabilities(const char *text, uint caps)
12454c9d2aaaSJean-Jacques Hiblot {
12464c9d2aaaSJean-Jacques Hiblot 	enum bus_mode mode;
12474c9d2aaaSJean-Jacques Hiblot 
12484c9d2aaaSJean-Jacques Hiblot 	printf("%s: widths [", text);
12494c9d2aaaSJean-Jacques Hiblot 	if (caps & MMC_MODE_8BIT)
12504c9d2aaaSJean-Jacques Hiblot 		printf("8, ");
12514c9d2aaaSJean-Jacques Hiblot 	if (caps & MMC_MODE_4BIT)
12524c9d2aaaSJean-Jacques Hiblot 		printf("4, ");
1253d0c221feSJean-Jacques Hiblot 	if (caps & MMC_MODE_1BIT)
1254d0c221feSJean-Jacques Hiblot 		printf("1, ");
1255d0c221feSJean-Jacques Hiblot 	printf("\b\b] modes [");
12564c9d2aaaSJean-Jacques Hiblot 	for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++)
12574c9d2aaaSJean-Jacques Hiblot 		if (MMC_CAP(mode) & caps)
12584c9d2aaaSJean-Jacques Hiblot 			printf("%s, ", mmc_mode_name(mode));
12594c9d2aaaSJean-Jacques Hiblot 	printf("\b\b]\n");
12604c9d2aaaSJean-Jacques Hiblot }
12614c9d2aaaSJean-Jacques Hiblot #endif
12624c9d2aaaSJean-Jacques Hiblot 
1263d0c221feSJean-Jacques Hiblot struct mode_width_tuning {
1264d0c221feSJean-Jacques Hiblot 	enum bus_mode mode;
1265d0c221feSJean-Jacques Hiblot 	uint widths;
1266d0c221feSJean-Jacques Hiblot };
1267d0c221feSJean-Jacques Hiblot 
1268aff5d3c8SKishon Vijay Abraham I static int mmc_set_signal_voltage(struct mmc *mmc, uint signal_voltage)
1269aff5d3c8SKishon Vijay Abraham I {
1270aff5d3c8SKishon Vijay Abraham I 	mmc->signal_voltage = signal_voltage;
1271aff5d3c8SKishon Vijay Abraham I 	return mmc_set_ios(mmc);
1272aff5d3c8SKishon Vijay Abraham I }
1273aff5d3c8SKishon Vijay Abraham I 
1274d0c221feSJean-Jacques Hiblot static const struct mode_width_tuning sd_modes_by_pref[] = {
1275d0c221feSJean-Jacques Hiblot 	{
1276d0c221feSJean-Jacques Hiblot 		.mode = SD_HS,
1277d0c221feSJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1278d0c221feSJean-Jacques Hiblot 	},
1279d0c221feSJean-Jacques Hiblot 	{
1280d0c221feSJean-Jacques Hiblot 		.mode = SD_LEGACY,
1281d0c221feSJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1282d0c221feSJean-Jacques Hiblot 	}
1283d0c221feSJean-Jacques Hiblot };
1284d0c221feSJean-Jacques Hiblot 
1285d0c221feSJean-Jacques Hiblot #define for_each_sd_mode_by_pref(caps, mwt) \
1286d0c221feSJean-Jacques Hiblot 	for (mwt = sd_modes_by_pref;\
1287d0c221feSJean-Jacques Hiblot 	     mwt < sd_modes_by_pref + ARRAY_SIZE(sd_modes_by_pref);\
1288d0c221feSJean-Jacques Hiblot 	     mwt++) \
1289d0c221feSJean-Jacques Hiblot 		if (caps & MMC_CAP(mwt->mode))
1290d0c221feSJean-Jacques Hiblot 
1291d0c221feSJean-Jacques Hiblot static int sd_select_mode_and_width(struct mmc *mmc)
12928ac8a263SJean-Jacques Hiblot {
12938ac8a263SJean-Jacques Hiblot 	int err;
1294d0c221feSJean-Jacques Hiblot 	uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT};
1295d0c221feSJean-Jacques Hiblot 	const struct mode_width_tuning *mwt;
12968ac8a263SJean-Jacques Hiblot 
1297d0c221feSJean-Jacques Hiblot 	err = sd_get_capabilities(mmc);
12988ac8a263SJean-Jacques Hiblot 	if (err)
12998ac8a263SJean-Jacques Hiblot 		return err;
13008ac8a263SJean-Jacques Hiblot 	/* Restrict card's capabilities by what the host can do */
1301d0c221feSJean-Jacques Hiblot 	mmc->card_caps &= (mmc->cfg->host_caps | MMC_MODE_1BIT);
13028ac8a263SJean-Jacques Hiblot 
1303d0c221feSJean-Jacques Hiblot 	for_each_sd_mode_by_pref(mmc->card_caps, mwt) {
1304d0c221feSJean-Jacques Hiblot 		uint *w;
13058ac8a263SJean-Jacques Hiblot 
1306d0c221feSJean-Jacques Hiblot 		for (w = widths; w < widths + ARRAY_SIZE(widths); w++) {
1307d0c221feSJean-Jacques Hiblot 			if (*w & mmc->card_caps & mwt->widths) {
1308d0c221feSJean-Jacques Hiblot 				debug("trying mode %s width %d (at %d MHz)\n",
1309d0c221feSJean-Jacques Hiblot 				      mmc_mode_name(mwt->mode),
1310d0c221feSJean-Jacques Hiblot 				      bus_width(*w),
1311d0c221feSJean-Jacques Hiblot 				      mmc_mode2freq(mmc, mwt->mode) / 1000000);
1312d0c221feSJean-Jacques Hiblot 
1313d0c221feSJean-Jacques Hiblot 				/* configure the bus width (card + host) */
1314d0c221feSJean-Jacques Hiblot 				err = sd_select_bus_width(mmc, bus_width(*w));
13158ac8a263SJean-Jacques Hiblot 				if (err)
1316d0c221feSJean-Jacques Hiblot 					goto error;
1317d0c221feSJean-Jacques Hiblot 				mmc_set_bus_width(mmc, bus_width(*w));
13188ac8a263SJean-Jacques Hiblot 
1319d0c221feSJean-Jacques Hiblot 				/* configure the bus mode (card) */
1320d0c221feSJean-Jacques Hiblot 				err = sd_set_card_speed(mmc, mwt->mode);
13218ac8a263SJean-Jacques Hiblot 				if (err)
1322d0c221feSJean-Jacques Hiblot 					goto error;
13238ac8a263SJean-Jacques Hiblot 
1324d0c221feSJean-Jacques Hiblot 				/* configure the bus mode (host) */
1325d0c221feSJean-Jacques Hiblot 				mmc_select_mode(mmc, mwt->mode);
132635f67820SKishon Vijay Abraham I 				mmc_set_clock(mmc, mmc->tran_speed, false);
13278ac8a263SJean-Jacques Hiblot 
13288ac8a263SJean-Jacques Hiblot 				err = sd_read_ssr(mmc);
1329d0c221feSJean-Jacques Hiblot 				if (!err)
13308ac8a263SJean-Jacques Hiblot 					return 0;
1331d0c221feSJean-Jacques Hiblot 
1332d0c221feSJean-Jacques Hiblot 				printf("bad ssr\n");
1333d0c221feSJean-Jacques Hiblot 
1334d0c221feSJean-Jacques Hiblot error:
1335d0c221feSJean-Jacques Hiblot 				/* revert to a safer bus speed */
1336d0c221feSJean-Jacques Hiblot 				mmc_select_mode(mmc, SD_LEGACY);
133735f67820SKishon Vijay Abraham I 				mmc_set_clock(mmc, mmc->tran_speed, false);
1338d0c221feSJean-Jacques Hiblot 			}
1339d0c221feSJean-Jacques Hiblot 		}
1340d0c221feSJean-Jacques Hiblot 	}
1341d0c221feSJean-Jacques Hiblot 
1342d0c221feSJean-Jacques Hiblot 	printf("unable to select a mode\n");
1343d0c221feSJean-Jacques Hiblot 	return -ENOTSUPP;
13448ac8a263SJean-Jacques Hiblot }
13458ac8a263SJean-Jacques Hiblot 
13467382e691SJean-Jacques Hiblot /*
13477382e691SJean-Jacques Hiblot  * read the compare the part of ext csd that is constant.
13487382e691SJean-Jacques Hiblot  * This can be used to check that the transfer is working
13497382e691SJean-Jacques Hiblot  * as expected.
13507382e691SJean-Jacques Hiblot  */
13517382e691SJean-Jacques Hiblot static int mmc_read_and_compare_ext_csd(struct mmc *mmc)
13527382e691SJean-Jacques Hiblot {
13537382e691SJean-Jacques Hiblot 	int err;
13547382e691SJean-Jacques Hiblot 	const u8 *ext_csd = mmc->ext_csd;
13557382e691SJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
13567382e691SJean-Jacques Hiblot 
13577382e691SJean-Jacques Hiblot 	err = mmc_send_ext_csd(mmc, test_csd);
13587382e691SJean-Jacques Hiblot 	if (err)
13597382e691SJean-Jacques Hiblot 		return err;
13607382e691SJean-Jacques Hiblot 
13617382e691SJean-Jacques Hiblot 	/* Only compare read only fields */
13627382e691SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT]
13637382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_PARTITIONING_SUPPORT] &&
13647382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_HC_WP_GRP_SIZE]
13657382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_HC_WP_GRP_SIZE] &&
13667382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_REV]
13677382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_REV] &&
13687382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
13697382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] &&
13707382e691SJean-Jacques Hiblot 	    memcmp(&ext_csd[EXT_CSD_SEC_CNT],
13717382e691SJean-Jacques Hiblot 		   &test_csd[EXT_CSD_SEC_CNT], 4) == 0)
13727382e691SJean-Jacques Hiblot 		return 0;
13737382e691SJean-Jacques Hiblot 
13747382e691SJean-Jacques Hiblot 	return -EBADMSG;
13757382e691SJean-Jacques Hiblot }
13767382e691SJean-Jacques Hiblot 
13773862b854SJean-Jacques Hiblot static const struct mode_width_tuning mmc_modes_by_pref[] = {
13788ac8a263SJean-Jacques Hiblot 	{
13793862b854SJean-Jacques Hiblot 		.mode = MMC_HS_200,
13803862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
13813862b854SJean-Jacques Hiblot 	},
13823862b854SJean-Jacques Hiblot 	{
13833862b854SJean-Jacques Hiblot 		.mode = MMC_DDR_52,
13843862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
13853862b854SJean-Jacques Hiblot 	},
13863862b854SJean-Jacques Hiblot 	{
13873862b854SJean-Jacques Hiblot 		.mode = MMC_HS_52,
13883862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
13893862b854SJean-Jacques Hiblot 	},
13903862b854SJean-Jacques Hiblot 	{
13913862b854SJean-Jacques Hiblot 		.mode = MMC_HS,
13923862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
13933862b854SJean-Jacques Hiblot 	},
13943862b854SJean-Jacques Hiblot 	{
13953862b854SJean-Jacques Hiblot 		.mode = MMC_LEGACY,
13963862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
13973862b854SJean-Jacques Hiblot 	}
13988ac8a263SJean-Jacques Hiblot };
13998ac8a263SJean-Jacques Hiblot 
14003862b854SJean-Jacques Hiblot #define for_each_mmc_mode_by_pref(caps, mwt) \
14013862b854SJean-Jacques Hiblot 	for (mwt = mmc_modes_by_pref;\
14023862b854SJean-Jacques Hiblot 	    mwt < mmc_modes_by_pref + ARRAY_SIZE(mmc_modes_by_pref);\
14033862b854SJean-Jacques Hiblot 	    mwt++) \
14043862b854SJean-Jacques Hiblot 		if (caps & MMC_CAP(mwt->mode))
14053862b854SJean-Jacques Hiblot 
14063862b854SJean-Jacques Hiblot static const struct ext_csd_bus_width {
14073862b854SJean-Jacques Hiblot 	uint cap;
14083862b854SJean-Jacques Hiblot 	bool is_ddr;
14093862b854SJean-Jacques Hiblot 	uint ext_csd_bits;
14103862b854SJean-Jacques Hiblot } ext_csd_bus_width[] = {
14113862b854SJean-Jacques Hiblot 	{MMC_MODE_8BIT, true, EXT_CSD_DDR_BUS_WIDTH_8},
14123862b854SJean-Jacques Hiblot 	{MMC_MODE_4BIT, true, EXT_CSD_DDR_BUS_WIDTH_4},
14133862b854SJean-Jacques Hiblot 	{MMC_MODE_8BIT, false, EXT_CSD_BUS_WIDTH_8},
14143862b854SJean-Jacques Hiblot 	{MMC_MODE_4BIT, false, EXT_CSD_BUS_WIDTH_4},
14153862b854SJean-Jacques Hiblot 	{MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1},
14163862b854SJean-Jacques Hiblot };
14173862b854SJean-Jacques Hiblot 
14183862b854SJean-Jacques Hiblot #define for_each_supported_width(caps, ddr, ecbv) \
14193862b854SJean-Jacques Hiblot 	for (ecbv = ext_csd_bus_width;\
14203862b854SJean-Jacques Hiblot 	    ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\
14213862b854SJean-Jacques Hiblot 	    ecbv++) \
14223862b854SJean-Jacques Hiblot 		if ((ddr == ecbv->is_ddr) && (caps & ecbv->cap))
14233862b854SJean-Jacques Hiblot 
14243862b854SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc)
14253862b854SJean-Jacques Hiblot {
14263862b854SJean-Jacques Hiblot 	int err;
14273862b854SJean-Jacques Hiblot 	const struct mode_width_tuning *mwt;
14283862b854SJean-Jacques Hiblot 	const struct ext_csd_bus_width *ecbw;
14293862b854SJean-Jacques Hiblot 
14303862b854SJean-Jacques Hiblot 	err = mmc_get_capabilities(mmc);
14318ac8a263SJean-Jacques Hiblot 	if (err)
14328ac8a263SJean-Jacques Hiblot 		return err;
14338ac8a263SJean-Jacques Hiblot 
14348ac8a263SJean-Jacques Hiblot 	/* Restrict card's capabilities by what the host can do */
1435d0c221feSJean-Jacques Hiblot 	mmc->card_caps &= (mmc->cfg->host_caps | MMC_MODE_1BIT);
14368ac8a263SJean-Jacques Hiblot 
14378ac8a263SJean-Jacques Hiblot 	/* Only version 4 of MMC supports wider bus widths */
14388ac8a263SJean-Jacques Hiblot 	if (mmc->version < MMC_VERSION_4)
14398ac8a263SJean-Jacques Hiblot 		return 0;
14408ac8a263SJean-Jacques Hiblot 
1441dfda9d88SJean-Jacques Hiblot 	if (!mmc->ext_csd) {
1442dfda9d88SJean-Jacques Hiblot 		debug("No ext_csd found!\n"); /* this should enver happen */
1443dfda9d88SJean-Jacques Hiblot 		return -ENOTSUPP;
1444dfda9d88SJean-Jacques Hiblot 	}
1445dfda9d88SJean-Jacques Hiblot 
14463862b854SJean-Jacques Hiblot 	for_each_mmc_mode_by_pref(mmc->card_caps, mwt) {
14473862b854SJean-Jacques Hiblot 		for_each_supported_width(mmc->card_caps & mwt->widths,
14483862b854SJean-Jacques Hiblot 					 mmc_is_mode_ddr(mwt->mode), ecbw) {
14493862b854SJean-Jacques Hiblot 			debug("trying mode %s width %d (at %d MHz)\n",
14503862b854SJean-Jacques Hiblot 			      mmc_mode_name(mwt->mode),
14513862b854SJean-Jacques Hiblot 			      bus_width(ecbw->cap),
14523862b854SJean-Jacques Hiblot 			      mmc_mode2freq(mmc, mwt->mode) / 1000000);
14533862b854SJean-Jacques Hiblot 			/* configure the bus width (card + host) */
14543862b854SJean-Jacques Hiblot 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
14553862b854SJean-Jacques Hiblot 				    EXT_CSD_BUS_WIDTH,
14563862b854SJean-Jacques Hiblot 				    ecbw->ext_csd_bits & ~EXT_CSD_DDR_FLAG);
14573862b854SJean-Jacques Hiblot 			if (err)
14583862b854SJean-Jacques Hiblot 				goto error;
14593862b854SJean-Jacques Hiblot 			mmc_set_bus_width(mmc, bus_width(ecbw->cap));
14603862b854SJean-Jacques Hiblot 
14613862b854SJean-Jacques Hiblot 			/* configure the bus speed (card) */
14623862b854SJean-Jacques Hiblot 			err = mmc_set_card_speed(mmc, mwt->mode);
14633862b854SJean-Jacques Hiblot 			if (err)
14643862b854SJean-Jacques Hiblot 				goto error;
14653862b854SJean-Jacques Hiblot 
14668ac8a263SJean-Jacques Hiblot 			/*
14673862b854SJean-Jacques Hiblot 			 * configure the bus width AND the ddr mode (card)
14683862b854SJean-Jacques Hiblot 			 * The host side will be taken care of in the next step
14698ac8a263SJean-Jacques Hiblot 			 */
14703862b854SJean-Jacques Hiblot 			if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) {
14713862b854SJean-Jacques Hiblot 				err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
14723862b854SJean-Jacques Hiblot 						 EXT_CSD_BUS_WIDTH,
14733862b854SJean-Jacques Hiblot 						 ecbw->ext_csd_bits);
14743862b854SJean-Jacques Hiblot 				if (err)
14753862b854SJean-Jacques Hiblot 					goto error;
14768ac8a263SJean-Jacques Hiblot 			}
14778ac8a263SJean-Jacques Hiblot 
14783862b854SJean-Jacques Hiblot 			/* configure the bus mode (host) */
14793862b854SJean-Jacques Hiblot 			mmc_select_mode(mmc, mwt->mode);
148035f67820SKishon Vijay Abraham I 			mmc_set_clock(mmc, mmc->tran_speed, false);
14818ac8a263SJean-Jacques Hiblot 
14823862b854SJean-Jacques Hiblot 			/* do a transfer to check the configuration */
14837382e691SJean-Jacques Hiblot 			err = mmc_read_and_compare_ext_csd(mmc);
14847382e691SJean-Jacques Hiblot 			if (!err)
14853862b854SJean-Jacques Hiblot 				return 0;
14863862b854SJean-Jacques Hiblot error:
14873862b854SJean-Jacques Hiblot 			/* if an error occured, revert to a safer bus mode */
14883862b854SJean-Jacques Hiblot 			mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
14893862b854SJean-Jacques Hiblot 				   EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1);
14903862b854SJean-Jacques Hiblot 			mmc_select_mode(mmc, MMC_LEGACY);
14913862b854SJean-Jacques Hiblot 			mmc_set_bus_width(mmc, 1);
14923862b854SJean-Jacques Hiblot 		}
14938ac8a263SJean-Jacques Hiblot 	}
14948ac8a263SJean-Jacques Hiblot 
14953862b854SJean-Jacques Hiblot 	printf("unable to select a mode\n");
14968ac8a263SJean-Jacques Hiblot 
14973862b854SJean-Jacques Hiblot 	return -ENOTSUPP;
14988ac8a263SJean-Jacques Hiblot }
14998ac8a263SJean-Jacques Hiblot 
1500dfda9d88SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc)
1501c744b6f6SJean-Jacques Hiblot {
1502c744b6f6SJean-Jacques Hiblot 	int err, i;
1503c744b6f6SJean-Jacques Hiblot 	u64 capacity;
1504c744b6f6SJean-Jacques Hiblot 	bool has_parts = false;
1505c744b6f6SJean-Jacques Hiblot 	bool part_completed;
1506dfda9d88SJean-Jacques Hiblot 	u8 *ext_csd;
1507c744b6f6SJean-Jacques Hiblot 
1508c744b6f6SJean-Jacques Hiblot 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4))
1509c744b6f6SJean-Jacques Hiblot 		return 0;
1510c744b6f6SJean-Jacques Hiblot 
1511dfda9d88SJean-Jacques Hiblot 	ext_csd = malloc_cache_aligned(MMC_MAX_BLOCK_LEN);
1512dfda9d88SJean-Jacques Hiblot 	if (!ext_csd)
1513dfda9d88SJean-Jacques Hiblot 		return -ENOMEM;
1514dfda9d88SJean-Jacques Hiblot 
1515dfda9d88SJean-Jacques Hiblot 	mmc->ext_csd = ext_csd;
1516dfda9d88SJean-Jacques Hiblot 
1517c744b6f6SJean-Jacques Hiblot 	/* check  ext_csd version and capacity */
1518c744b6f6SJean-Jacques Hiblot 	err = mmc_send_ext_csd(mmc, ext_csd);
1519c744b6f6SJean-Jacques Hiblot 	if (err)
1520c744b6f6SJean-Jacques Hiblot 		return err;
1521c744b6f6SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_REV] >= 2) {
1522c744b6f6SJean-Jacques Hiblot 		/*
1523c744b6f6SJean-Jacques Hiblot 		 * According to the JEDEC Standard, the value of
1524c744b6f6SJean-Jacques Hiblot 		 * ext_csd's capacity is valid if the value is more
1525c744b6f6SJean-Jacques Hiblot 		 * than 2GB
1526c744b6f6SJean-Jacques Hiblot 		 */
1527c744b6f6SJean-Jacques Hiblot 		capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
1528c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
1529c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
1530c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
1531c744b6f6SJean-Jacques Hiblot 		capacity *= MMC_MAX_BLOCK_LEN;
1532c744b6f6SJean-Jacques Hiblot 		if ((capacity >> 20) > 2 * 1024)
1533c744b6f6SJean-Jacques Hiblot 			mmc->capacity_user = capacity;
1534c744b6f6SJean-Jacques Hiblot 	}
1535c744b6f6SJean-Jacques Hiblot 
1536c744b6f6SJean-Jacques Hiblot 	switch (ext_csd[EXT_CSD_REV]) {
1537c744b6f6SJean-Jacques Hiblot 	case 1:
1538c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_1;
1539c744b6f6SJean-Jacques Hiblot 		break;
1540c744b6f6SJean-Jacques Hiblot 	case 2:
1541c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_2;
1542c744b6f6SJean-Jacques Hiblot 		break;
1543c744b6f6SJean-Jacques Hiblot 	case 3:
1544c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_3;
1545c744b6f6SJean-Jacques Hiblot 		break;
1546c744b6f6SJean-Jacques Hiblot 	case 5:
1547c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_41;
1548c744b6f6SJean-Jacques Hiblot 		break;
1549c744b6f6SJean-Jacques Hiblot 	case 6:
1550c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_5;
1551c744b6f6SJean-Jacques Hiblot 		break;
1552c744b6f6SJean-Jacques Hiblot 	case 7:
1553c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_5_0;
1554c744b6f6SJean-Jacques Hiblot 		break;
1555c744b6f6SJean-Jacques Hiblot 	case 8:
1556c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_5_1;
1557c744b6f6SJean-Jacques Hiblot 		break;
1558c744b6f6SJean-Jacques Hiblot 	}
1559c744b6f6SJean-Jacques Hiblot 
1560c744b6f6SJean-Jacques Hiblot 	/* The partition data may be non-zero but it is only
1561c744b6f6SJean-Jacques Hiblot 	 * effective if PARTITION_SETTING_COMPLETED is set in
1562c744b6f6SJean-Jacques Hiblot 	 * EXT_CSD, so ignore any data if this bit is not set,
1563c744b6f6SJean-Jacques Hiblot 	 * except for enabling the high-capacity group size
1564c744b6f6SJean-Jacques Hiblot 	 * definition (see below).
1565c744b6f6SJean-Jacques Hiblot 	 */
1566c744b6f6SJean-Jacques Hiblot 	part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
1567c744b6f6SJean-Jacques Hiblot 			    EXT_CSD_PARTITION_SETTING_COMPLETED);
1568c744b6f6SJean-Jacques Hiblot 
1569c744b6f6SJean-Jacques Hiblot 	/* store the partition info of emmc */
1570c744b6f6SJean-Jacques Hiblot 	mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
1571c744b6f6SJean-Jacques Hiblot 	if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
1572c744b6f6SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_BOOT_MULT])
1573c744b6f6SJean-Jacques Hiblot 		mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
1574c744b6f6SJean-Jacques Hiblot 	if (part_completed &&
1575c744b6f6SJean-Jacques Hiblot 	    (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
1576c744b6f6SJean-Jacques Hiblot 		mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
1577c744b6f6SJean-Jacques Hiblot 
1578c744b6f6SJean-Jacques Hiblot 	mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
1579c744b6f6SJean-Jacques Hiblot 
1580c744b6f6SJean-Jacques Hiblot 	mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
1581c744b6f6SJean-Jacques Hiblot 
1582c744b6f6SJean-Jacques Hiblot 	for (i = 0; i < 4; i++) {
1583c744b6f6SJean-Jacques Hiblot 		int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
1584c744b6f6SJean-Jacques Hiblot 		uint mult = (ext_csd[idx + 2] << 16) +
1585c744b6f6SJean-Jacques Hiblot 			(ext_csd[idx + 1] << 8) + ext_csd[idx];
1586c744b6f6SJean-Jacques Hiblot 		if (mult)
1587c744b6f6SJean-Jacques Hiblot 			has_parts = true;
1588c744b6f6SJean-Jacques Hiblot 		if (!part_completed)
1589c744b6f6SJean-Jacques Hiblot 			continue;
1590c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] = mult;
1591c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] *=
1592c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1593c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1594c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] <<= 19;
1595c744b6f6SJean-Jacques Hiblot 	}
1596c744b6f6SJean-Jacques Hiblot 
1597c744b6f6SJean-Jacques Hiblot 	if (part_completed) {
1598c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size =
1599c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) +
1600c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) +
1601c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_ENH_SIZE_MULT];
1602c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1603c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1604c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size <<= 19;
1605c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_start =
1606c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) +
1607c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) +
1608c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) +
1609c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_ENH_START_ADDR];
1610c744b6f6SJean-Jacques Hiblot 		if (mmc->high_capacity)
1611c744b6f6SJean-Jacques Hiblot 			mmc->enh_user_start <<= 9;
1612c744b6f6SJean-Jacques Hiblot 	}
1613c744b6f6SJean-Jacques Hiblot 
1614c744b6f6SJean-Jacques Hiblot 	/*
1615c744b6f6SJean-Jacques Hiblot 	 * Host needs to enable ERASE_GRP_DEF bit if device is
1616c744b6f6SJean-Jacques Hiblot 	 * partitioned. This bit will be lost every time after a reset
1617c744b6f6SJean-Jacques Hiblot 	 * or power off. This will affect erase size.
1618c744b6f6SJean-Jacques Hiblot 	 */
1619c744b6f6SJean-Jacques Hiblot 	if (part_completed)
1620c744b6f6SJean-Jacques Hiblot 		has_parts = true;
1621c744b6f6SJean-Jacques Hiblot 	if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
1622c744b6f6SJean-Jacques Hiblot 	    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
1623c744b6f6SJean-Jacques Hiblot 		has_parts = true;
1624c744b6f6SJean-Jacques Hiblot 	if (has_parts) {
1625c744b6f6SJean-Jacques Hiblot 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1626c744b6f6SJean-Jacques Hiblot 				 EXT_CSD_ERASE_GROUP_DEF, 1);
1627c744b6f6SJean-Jacques Hiblot 
1628c744b6f6SJean-Jacques Hiblot 		if (err)
1629c744b6f6SJean-Jacques Hiblot 			return err;
1630c744b6f6SJean-Jacques Hiblot 
1631c744b6f6SJean-Jacques Hiblot 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1632c744b6f6SJean-Jacques Hiblot 	}
1633c744b6f6SJean-Jacques Hiblot 
1634c744b6f6SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
1635c744b6f6SJean-Jacques Hiblot 		/* Read out group size from ext_csd */
1636c744b6f6SJean-Jacques Hiblot 		mmc->erase_grp_size =
1637c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1638c744b6f6SJean-Jacques Hiblot 		/*
1639c744b6f6SJean-Jacques Hiblot 		 * if high capacity and partition setting completed
1640c744b6f6SJean-Jacques Hiblot 		 * SEC_COUNT is valid even if it is smaller than 2 GiB
1641c744b6f6SJean-Jacques Hiblot 		 * JEDEC Standard JESD84-B45, 6.2.4
1642c744b6f6SJean-Jacques Hiblot 		 */
1643c744b6f6SJean-Jacques Hiblot 		if (mmc->high_capacity && part_completed) {
1644c744b6f6SJean-Jacques Hiblot 			capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
1645c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
1646c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
1647c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
1648c744b6f6SJean-Jacques Hiblot 			capacity *= MMC_MAX_BLOCK_LEN;
1649c744b6f6SJean-Jacques Hiblot 			mmc->capacity_user = capacity;
1650c744b6f6SJean-Jacques Hiblot 		}
1651c744b6f6SJean-Jacques Hiblot 	} else {
1652c744b6f6SJean-Jacques Hiblot 		/* Calculate the group size from the csd value. */
1653c744b6f6SJean-Jacques Hiblot 		int erase_gsz, erase_gmul;
1654c744b6f6SJean-Jacques Hiblot 
1655c744b6f6SJean-Jacques Hiblot 		erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
1656c744b6f6SJean-Jacques Hiblot 		erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
1657c744b6f6SJean-Jacques Hiblot 		mmc->erase_grp_size = (erase_gsz + 1)
1658c744b6f6SJean-Jacques Hiblot 			* (erase_gmul + 1);
1659c744b6f6SJean-Jacques Hiblot 	}
1660c744b6f6SJean-Jacques Hiblot 
1661c744b6f6SJean-Jacques Hiblot 	mmc->hc_wp_grp_size = 1024
1662c744b6f6SJean-Jacques Hiblot 		* ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
1663c744b6f6SJean-Jacques Hiblot 		* ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1664c744b6f6SJean-Jacques Hiblot 
1665c744b6f6SJean-Jacques Hiblot 	mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
1666c744b6f6SJean-Jacques Hiblot 
1667c744b6f6SJean-Jacques Hiblot 	return 0;
1668c744b6f6SJean-Jacques Hiblot }
1669c744b6f6SJean-Jacques Hiblot 
1670fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc)
1671272cc70bSAndy Fleming {
1672f866a46dSStephen Warren 	int err, i;
1673272cc70bSAndy Fleming 	uint mult, freq;
1674c744b6f6SJean-Jacques Hiblot 	u64 cmult, csize;
1675272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1676c40fdca6SSimon Glass 	struct blk_desc *bdesc;
1677272cc70bSAndy Fleming 
1678d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
1679d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
1680d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
1681d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
1682d52ebf10SThomas Chou 		cmd.cmdarg = 1;
1683d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
1684d52ebf10SThomas Chou 
1685d52ebf10SThomas Chou 		if (err)
1686d52ebf10SThomas Chou 			return err;
1687d52ebf10SThomas Chou 	}
1688d52ebf10SThomas Chou #endif
1689d52ebf10SThomas Chou 
1690272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
1691d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
1692d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
1693272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1694272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1695272cc70bSAndy Fleming 
1696272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1697272cc70bSAndy Fleming 
1698272cc70bSAndy Fleming 	if (err)
1699272cc70bSAndy Fleming 		return err;
1700272cc70bSAndy Fleming 
1701272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
1702272cc70bSAndy Fleming 
1703272cc70bSAndy Fleming 	/*
1704272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
1705272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
1706272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
1707272cc70bSAndy Fleming 	 */
1708d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1709272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
1710272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1711272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
1712272cc70bSAndy Fleming 
1713272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1714272cc70bSAndy Fleming 
1715272cc70bSAndy Fleming 		if (err)
1716272cc70bSAndy Fleming 			return err;
1717272cc70bSAndy Fleming 
1718272cc70bSAndy Fleming 		if (IS_SD(mmc))
1719998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
1720d52ebf10SThomas Chou 	}
1721272cc70bSAndy Fleming 
1722272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
1723272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
1724272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1725272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1726272cc70bSAndy Fleming 
1727272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1728272cc70bSAndy Fleming 
1729272cc70bSAndy Fleming 	if (err)
1730272cc70bSAndy Fleming 		return err;
1731272cc70bSAndy Fleming 
1732998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
1733998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
1734998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
1735998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
1736272cc70bSAndy Fleming 
1737272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
17380b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
1739272cc70bSAndy Fleming 
1740272cc70bSAndy Fleming 		switch (version) {
1741272cc70bSAndy Fleming 		case 0:
1742272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1743272cc70bSAndy Fleming 			break;
1744272cc70bSAndy Fleming 		case 1:
1745272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_4;
1746272cc70bSAndy Fleming 			break;
1747272cc70bSAndy Fleming 		case 2:
1748272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_2_2;
1749272cc70bSAndy Fleming 			break;
1750272cc70bSAndy Fleming 		case 3:
1751272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_3;
1752272cc70bSAndy Fleming 			break;
1753272cc70bSAndy Fleming 		case 4:
1754272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_4;
1755272cc70bSAndy Fleming 			break;
1756272cc70bSAndy Fleming 		default:
1757272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1758272cc70bSAndy Fleming 			break;
1759272cc70bSAndy Fleming 		}
1760272cc70bSAndy Fleming 	}
1761272cc70bSAndy Fleming 
1762272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
17630b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
17640b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
1765272cc70bSAndy Fleming 
176635f9e196SJean-Jacques Hiblot 	mmc->legacy_speed = freq * mult;
176735f9e196SJean-Jacques Hiblot 	mmc_select_mode(mmc, MMC_LEGACY);
1768272cc70bSAndy Fleming 
1769ab71188cSMarkus Niebel 	mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
1770998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
1771272cc70bSAndy Fleming 
1772272cc70bSAndy Fleming 	if (IS_SD(mmc))
1773272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
1774272cc70bSAndy Fleming 	else
1775998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
1776272cc70bSAndy Fleming 
1777272cc70bSAndy Fleming 	if (mmc->high_capacity) {
1778272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
1779272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
1780272cc70bSAndy Fleming 		cmult = 8;
1781272cc70bSAndy Fleming 	} else {
1782272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
1783272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
1784272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
1785272cc70bSAndy Fleming 	}
1786272cc70bSAndy Fleming 
1787f866a46dSStephen Warren 	mmc->capacity_user = (csize + 1) << (cmult + 2);
1788f866a46dSStephen Warren 	mmc->capacity_user *= mmc->read_bl_len;
1789f866a46dSStephen Warren 	mmc->capacity_boot = 0;
1790f866a46dSStephen Warren 	mmc->capacity_rpmb = 0;
1791f866a46dSStephen Warren 	for (i = 0; i < 4; i++)
1792f866a46dSStephen Warren 		mmc->capacity_gp[i] = 0;
1793272cc70bSAndy Fleming 
17948bfa195eSSimon Glass 	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
17958bfa195eSSimon Glass 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
1796272cc70bSAndy Fleming 
17978bfa195eSSimon Glass 	if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
17988bfa195eSSimon Glass 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
1799272cc70bSAndy Fleming 
1800ab71188cSMarkus Niebel 	if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
1801ab71188cSMarkus Niebel 		cmd.cmdidx = MMC_CMD_SET_DSR;
1802ab71188cSMarkus Niebel 		cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
1803ab71188cSMarkus Niebel 		cmd.resp_type = MMC_RSP_NONE;
1804ab71188cSMarkus Niebel 		if (mmc_send_cmd(mmc, &cmd, NULL))
1805ab71188cSMarkus Niebel 			printf("MMC: SET_DSR failed\n");
1806ab71188cSMarkus Niebel 	}
1807ab71188cSMarkus Niebel 
1808272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
1809d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1810272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
1811fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
1812272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1813272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1814272cc70bSAndy Fleming 
1815272cc70bSAndy Fleming 		if (err)
1816272cc70bSAndy Fleming 			return err;
1817d52ebf10SThomas Chou 	}
1818272cc70bSAndy Fleming 
1819e6f99a56SLei Wen 	/*
1820e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
1821e6f99a56SLei Wen 	 */
1822e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
1823bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
1824c744b6f6SJean-Jacques Hiblot 
1825dfda9d88SJean-Jacques Hiblot 	err = mmc_startup_v4(mmc);
18269cf199ebSDiego Santa Cruz 	if (err)
18279cf199ebSDiego Santa Cruz 		return err;
1828f866a46dSStephen Warren 
1829c40fdca6SSimon Glass 	err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart);
1830f866a46dSStephen Warren 	if (err)
1831f866a46dSStephen Warren 		return err;
1832d23e2c09SSukumar Ghorai 
1833272cc70bSAndy Fleming 	if (IS_SD(mmc))
1834d0c221feSJean-Jacques Hiblot 		err = sd_select_mode_and_width(mmc);
1835272cc70bSAndy Fleming 	else
18363862b854SJean-Jacques Hiblot 		err = mmc_select_mode_and_width(mmc);
1837272cc70bSAndy Fleming 
1838272cc70bSAndy Fleming 	if (err)
1839272cc70bSAndy Fleming 		return err;
1840272cc70bSAndy Fleming 
1841272cc70bSAndy Fleming 
18425af8f45cSAndrew Gabbasov 	/* Fix the block length for DDR mode */
18435af8f45cSAndrew Gabbasov 	if (mmc->ddr_mode) {
18445af8f45cSAndrew Gabbasov 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
18455af8f45cSAndrew Gabbasov 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
18465af8f45cSAndrew Gabbasov 	}
18475af8f45cSAndrew Gabbasov 
1848272cc70bSAndy Fleming 	/* fill in device description */
1849c40fdca6SSimon Glass 	bdesc = mmc_get_blk_desc(mmc);
1850c40fdca6SSimon Glass 	bdesc->lun = 0;
1851c40fdca6SSimon Glass 	bdesc->hwpart = 0;
1852c40fdca6SSimon Glass 	bdesc->type = 0;
1853c40fdca6SSimon Glass 	bdesc->blksz = mmc->read_bl_len;
1854c40fdca6SSimon Glass 	bdesc->log2blksz = LOG2(bdesc->blksz);
1855c40fdca6SSimon Glass 	bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len);
1856fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \
1857fc011f64SSjoerd Simons 		(defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \
1858fc011f64SSjoerd Simons 		!defined(CONFIG_USE_TINY_PRINTF))
1859c40fdca6SSimon Glass 	sprintf(bdesc->vendor, "Man %06x Snr %04x%04x",
1860babce5f6STaylor Hutt 		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
1861babce5f6STaylor Hutt 		(mmc->cid[3] >> 16) & 0xffff);
1862c40fdca6SSimon Glass 	sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
18630b453ffeSRabin Vincent 		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
1864babce5f6STaylor Hutt 		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
1865babce5f6STaylor Hutt 		(mmc->cid[2] >> 24) & 0xff);
1866c40fdca6SSimon Glass 	sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
1867babce5f6STaylor Hutt 		(mmc->cid[2] >> 16) & 0xf);
186856196826SPaul Burton #else
1869c40fdca6SSimon Glass 	bdesc->vendor[0] = 0;
1870c40fdca6SSimon Glass 	bdesc->product[0] = 0;
1871c40fdca6SSimon Glass 	bdesc->revision[0] = 0;
187256196826SPaul Burton #endif
1873122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
1874c40fdca6SSimon Glass 	part_init(bdesc);
1875122efd43SMikhail Kshevetskiy #endif
1876272cc70bSAndy Fleming 
1877272cc70bSAndy Fleming 	return 0;
1878272cc70bSAndy Fleming }
1879272cc70bSAndy Fleming 
1880fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc)
1881272cc70bSAndy Fleming {
1882272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1883272cc70bSAndy Fleming 	int err;
1884272cc70bSAndy Fleming 
1885272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
1886272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
188793bfd616SPantelis Antoniou 	cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa;
1888272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
1889272cc70bSAndy Fleming 
1890272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1891272cc70bSAndy Fleming 
1892272cc70bSAndy Fleming 	if (err)
1893272cc70bSAndy Fleming 		return err;
1894272cc70bSAndy Fleming 
1895998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
1896915ffa52SJaehoon Chung 		return -EOPNOTSUPP;
1897272cc70bSAndy Fleming 	else
1898272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
1899272cc70bSAndy Fleming 
1900272cc70bSAndy Fleming 	return 0;
1901272cc70bSAndy Fleming }
1902272cc70bSAndy Fleming 
1903c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
190495de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */
190595de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void)
190695de9ab2SPaul Kocialkowski {
190795de9ab2SPaul Kocialkowski }
190805cbeb7cSSimon Glass #endif
190995de9ab2SPaul Kocialkowski 
19102051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc)
19112051aefeSPeng Fan {
1912c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
191306ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR)
19142051aefeSPeng Fan 	int ret;
19152051aefeSPeng Fan 
19162051aefeSPeng Fan 	ret = device_get_supply_regulator(mmc->dev, "vmmc-supply",
191706ec045fSJean-Jacques Hiblot 					  &mmc->vmmc_supply);
191806ec045fSJean-Jacques Hiblot 	if (ret)
1919288db7c7SJaehoon Chung 		debug("%s: No vmmc supply\n", mmc->dev->name);
19202051aefeSPeng Fan 
192106ec045fSJean-Jacques Hiblot 	ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply",
192206ec045fSJean-Jacques Hiblot 					  &mmc->vqmmc_supply);
192306ec045fSJean-Jacques Hiblot 	if (ret)
192406ec045fSJean-Jacques Hiblot 		debug("%s: No vqmmc supply\n", mmc->dev->name);
19252051aefeSPeng Fan #endif
192605cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */
192705cbeb7cSSimon Glass 	/*
192805cbeb7cSSimon Glass 	 * Driver model should use a regulator, as above, rather than calling
192905cbeb7cSSimon Glass 	 * out to board code.
193005cbeb7cSSimon Glass 	 */
193105cbeb7cSSimon Glass 	board_mmc_power_init();
193205cbeb7cSSimon Glass #endif
19332051aefeSPeng Fan 	return 0;
19342051aefeSPeng Fan }
19352051aefeSPeng Fan 
1936fb7c3bebSKishon Vijay Abraham I /*
1937fb7c3bebSKishon Vijay Abraham I  * put the host in the initial state:
1938fb7c3bebSKishon Vijay Abraham I  * - turn on Vdd (card power supply)
1939fb7c3bebSKishon Vijay Abraham I  * - configure the bus width and clock to minimal values
1940fb7c3bebSKishon Vijay Abraham I  */
1941fb7c3bebSKishon Vijay Abraham I static void mmc_set_initial_state(struct mmc *mmc)
1942fb7c3bebSKishon Vijay Abraham I {
1943fb7c3bebSKishon Vijay Abraham I 	int err;
1944fb7c3bebSKishon Vijay Abraham I 
1945fb7c3bebSKishon Vijay Abraham I 	/* First try to set 3.3V. If it fails set to 1.8V */
1946fb7c3bebSKishon Vijay Abraham I 	err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_330);
1947fb7c3bebSKishon Vijay Abraham I 	if (err != 0)
1948fb7c3bebSKishon Vijay Abraham I 		err = mmc_set_signal_voltage(mmc, MMC_SIGNAL_VOLTAGE_180);
1949fb7c3bebSKishon Vijay Abraham I 	if (err != 0)
1950fb7c3bebSKishon Vijay Abraham I 		printf("mmc: failed to set signal voltage\n");
1951fb7c3bebSKishon Vijay Abraham I 
1952fb7c3bebSKishon Vijay Abraham I 	mmc_select_mode(mmc, MMC_LEGACY);
1953fb7c3bebSKishon Vijay Abraham I 	mmc_set_bus_width(mmc, 1);
195435f67820SKishon Vijay Abraham I 	mmc_set_clock(mmc, 0, false);
1955fb7c3bebSKishon Vijay Abraham I }
1956fb7c3bebSKishon Vijay Abraham I 
1957fb7c3bebSKishon Vijay Abraham I static int mmc_power_on(struct mmc *mmc)
1958fb7c3bebSKishon Vijay Abraham I {
1959fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR)
1960fb7c3bebSKishon Vijay Abraham I 	if (mmc->vmmc_supply) {
1961fb7c3bebSKishon Vijay Abraham I 		int ret = regulator_set_enable(mmc->vmmc_supply, true);
1962fb7c3bebSKishon Vijay Abraham I 
1963fb7c3bebSKishon Vijay Abraham I 		if (ret) {
1964fb7c3bebSKishon Vijay Abraham I 			puts("Error enabling VMMC supply\n");
1965fb7c3bebSKishon Vijay Abraham I 			return ret;
1966fb7c3bebSKishon Vijay Abraham I 		}
1967fb7c3bebSKishon Vijay Abraham I 	}
1968fb7c3bebSKishon Vijay Abraham I #endif
1969fb7c3bebSKishon Vijay Abraham I 	return 0;
1970fb7c3bebSKishon Vijay Abraham I }
1971fb7c3bebSKishon Vijay Abraham I 
1972fb7c3bebSKishon Vijay Abraham I static int mmc_power_off(struct mmc *mmc)
1973fb7c3bebSKishon Vijay Abraham I {
1974*2e7410d7SKishon Vijay Abraham I 	mmc_set_clock(mmc, 1, true);
1975fb7c3bebSKishon Vijay Abraham I #if CONFIG_IS_ENABLED(DM_MMC) && CONFIG_IS_ENABLED(DM_REGULATOR)
1976fb7c3bebSKishon Vijay Abraham I 	if (mmc->vmmc_supply) {
1977fb7c3bebSKishon Vijay Abraham I 		int ret = regulator_set_enable(mmc->vmmc_supply, false);
1978fb7c3bebSKishon Vijay Abraham I 
1979fb7c3bebSKishon Vijay Abraham I 		if (ret) {
1980fb7c3bebSKishon Vijay Abraham I 			puts("Error disabling VMMC supply\n");
1981fb7c3bebSKishon Vijay Abraham I 			return ret;
1982fb7c3bebSKishon Vijay Abraham I 		}
1983fb7c3bebSKishon Vijay Abraham I 	}
1984fb7c3bebSKishon Vijay Abraham I #endif
1985fb7c3bebSKishon Vijay Abraham I 	return 0;
1986fb7c3bebSKishon Vijay Abraham I }
1987fb7c3bebSKishon Vijay Abraham I 
1988fb7c3bebSKishon Vijay Abraham I static int mmc_power_cycle(struct mmc *mmc)
1989fb7c3bebSKishon Vijay Abraham I {
1990fb7c3bebSKishon Vijay Abraham I 	int ret;
1991fb7c3bebSKishon Vijay Abraham I 
1992fb7c3bebSKishon Vijay Abraham I 	ret = mmc_power_off(mmc);
1993fb7c3bebSKishon Vijay Abraham I 	if (ret)
1994fb7c3bebSKishon Vijay Abraham I 		return ret;
1995fb7c3bebSKishon Vijay Abraham I 	/*
1996fb7c3bebSKishon Vijay Abraham I 	 * SD spec recommends at least 1ms of delay. Let's wait for 2ms
1997fb7c3bebSKishon Vijay Abraham I 	 * to be on the safer side.
1998fb7c3bebSKishon Vijay Abraham I 	 */
1999fb7c3bebSKishon Vijay Abraham I 	udelay(2000);
2000fb7c3bebSKishon Vijay Abraham I 	return mmc_power_on(mmc);
2001fb7c3bebSKishon Vijay Abraham I }
2002fb7c3bebSKishon Vijay Abraham I 
2003e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc)
2004272cc70bSAndy Fleming {
20058ca51e51SSimon Glass 	bool no_card;
2006afd5932bSMacpaul Lin 	int err;
2007272cc70bSAndy Fleming 
2008ab769f22SPantelis Antoniou 	/* we pretend there's no card when init is NULL */
20098ca51e51SSimon Glass 	no_card = mmc_getcd(mmc) == 0;
2010e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
20118ca51e51SSimon Glass 	no_card = no_card || (mmc->cfg->ops->init == NULL);
20128ca51e51SSimon Glass #endif
20138ca51e51SSimon Glass 	if (no_card) {
201448972d90SThierry Reding 		mmc->has_init = 0;
201556196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
201648972d90SThierry Reding 		printf("MMC: no card present\n");
201756196826SPaul Burton #endif
2018915ffa52SJaehoon Chung 		return -ENOMEDIUM;
201948972d90SThierry Reding 	}
202048972d90SThierry Reding 
2021bc897b1dSLei Wen 	if (mmc->has_init)
2022bc897b1dSLei Wen 		return 0;
2023bc897b1dSLei Wen 
20245a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
20255a8dbdc6SYangbo Lu 	mmc_adapter_card_type_ident();
20265a8dbdc6SYangbo Lu #endif
20272051aefeSPeng Fan 	err = mmc_power_init(mmc);
20282051aefeSPeng Fan 	if (err)
20292051aefeSPeng Fan 		return err;
203095de9ab2SPaul Kocialkowski 
2031fb7c3bebSKishon Vijay Abraham I 	err = mmc_power_on(mmc);
2032fb7c3bebSKishon Vijay Abraham I 	if (err)
2033fb7c3bebSKishon Vijay Abraham I 		return err;
2034fb7c3bebSKishon Vijay Abraham I 
2035e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
20368ca51e51SSimon Glass 	/* The device has already been probed ready for use */
20378ca51e51SSimon Glass #else
2038ab769f22SPantelis Antoniou 	/* made sure it's not NULL earlier */
203993bfd616SPantelis Antoniou 	err = mmc->cfg->ops->init(mmc);
2040272cc70bSAndy Fleming 	if (err)
2041272cc70bSAndy Fleming 		return err;
20428ca51e51SSimon Glass #endif
2043786e8f81SAndrew Gabbasov 	mmc->ddr_mode = 0;
2044aff5d3c8SKishon Vijay Abraham I 
2045fb7c3bebSKishon Vijay Abraham I 	mmc_set_initial_state(mmc);
2046318a7a57SJean-Jacques Hiblot 	mmc_send_init_stream(mmc);
2047318a7a57SJean-Jacques Hiblot 
2048272cc70bSAndy Fleming 	/* Reset the Card */
2049272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
2050272cc70bSAndy Fleming 
2051272cc70bSAndy Fleming 	if (err)
2052272cc70bSAndy Fleming 		return err;
2053272cc70bSAndy Fleming 
2054bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
2055c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->hwpart = 0;
2056bc897b1dSLei Wen 
2057272cc70bSAndy Fleming 	/* Test for SD version 2 */
2058272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
2059272cc70bSAndy Fleming 
2060272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
2061272cc70bSAndy Fleming 	err = sd_send_op_cond(mmc);
2062272cc70bSAndy Fleming 
2063272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
2064915ffa52SJaehoon Chung 	if (err == -ETIMEDOUT) {
2065272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
2066272cc70bSAndy Fleming 
2067bd47c135SAndrew Gabbasov 		if (err) {
206856196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2069272cc70bSAndy Fleming 			printf("Card did not respond to voltage select!\n");
207056196826SPaul Burton #endif
2071915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
2072272cc70bSAndy Fleming 		}
2073272cc70bSAndy Fleming 	}
2074272cc70bSAndy Fleming 
2075bd47c135SAndrew Gabbasov 	if (!err)
2076e9550449SChe-Liang Chiou 		mmc->init_in_progress = 1;
2077e9550449SChe-Liang Chiou 
2078e9550449SChe-Liang Chiou 	return err;
2079e9550449SChe-Liang Chiou }
2080e9550449SChe-Liang Chiou 
2081e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc)
2082e9550449SChe-Liang Chiou {
2083e9550449SChe-Liang Chiou 	int err = 0;
2084e9550449SChe-Liang Chiou 
2085bd47c135SAndrew Gabbasov 	mmc->init_in_progress = 0;
2086e9550449SChe-Liang Chiou 	if (mmc->op_cond_pending)
2087e9550449SChe-Liang Chiou 		err = mmc_complete_op_cond(mmc);
2088e9550449SChe-Liang Chiou 
2089e9550449SChe-Liang Chiou 	if (!err)
2090bc897b1dSLei Wen 		err = mmc_startup(mmc);
2091bc897b1dSLei Wen 	if (err)
2092bc897b1dSLei Wen 		mmc->has_init = 0;
2093bc897b1dSLei Wen 	else
2094bc897b1dSLei Wen 		mmc->has_init = 1;
2095e9550449SChe-Liang Chiou 	return err;
2096e9550449SChe-Liang Chiou }
2097e9550449SChe-Liang Chiou 
2098e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc)
2099e9550449SChe-Liang Chiou {
2100bd47c135SAndrew Gabbasov 	int err = 0;
2101ce9eca94SMarek Vasut 	__maybe_unused unsigned start;
2102c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
210333fb211dSSimon Glass 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev);
2104e9550449SChe-Liang Chiou 
210533fb211dSSimon Glass 	upriv->mmc = mmc;
210633fb211dSSimon Glass #endif
2107e9550449SChe-Liang Chiou 	if (mmc->has_init)
2108e9550449SChe-Liang Chiou 		return 0;
2109d803fea5SMateusz Zalega 
2110d803fea5SMateusz Zalega 	start = get_timer(0);
2111d803fea5SMateusz Zalega 
2112e9550449SChe-Liang Chiou 	if (!mmc->init_in_progress)
2113e9550449SChe-Liang Chiou 		err = mmc_start_init(mmc);
2114e9550449SChe-Liang Chiou 
2115bd47c135SAndrew Gabbasov 	if (!err)
2116e9550449SChe-Liang Chiou 		err = mmc_complete_init(mmc);
2117919b4858SJagan Teki 	if (err)
2118919b4858SJagan Teki 		printf("%s: %d, time %lu\n", __func__, err, get_timer(start));
2119919b4858SJagan Teki 
2120bc897b1dSLei Wen 	return err;
2121272cc70bSAndy Fleming }
2122272cc70bSAndy Fleming 
2123ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val)
2124ab71188cSMarkus Niebel {
2125ab71188cSMarkus Niebel 	mmc->dsr = val;
2126ab71188cSMarkus Niebel 	return 0;
2127ab71188cSMarkus Niebel }
2128ab71188cSMarkus Niebel 
2129cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */
2130cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis)
2131272cc70bSAndy Fleming {
2132272cc70bSAndy Fleming 	return -1;
2133272cc70bSAndy Fleming }
2134272cc70bSAndy Fleming 
2135cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */
2136cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis)
2137cee9ab7cSJeroen Hofstee {
2138cee9ab7cSJeroen Hofstee 	return -1;
2139cee9ab7cSJeroen Hofstee }
2140272cc70bSAndy Fleming 
2141e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit)
2142e9550449SChe-Liang Chiou {
2143e9550449SChe-Liang Chiou 	mmc->preinit = preinit;
2144e9550449SChe-Liang Chiou }
2145e9550449SChe-Liang Chiou 
2146c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD)
21478e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
21488e3332e2SSjoerd Simons {
21498e3332e2SSjoerd Simons 	return 0;
21508e3332e2SSjoerd Simons }
2151c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC)
21528e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
21538e3332e2SSjoerd Simons {
21544a1db6d8SSimon Glass 	int ret, i;
21558e3332e2SSjoerd Simons 	struct uclass *uc;
21564a1db6d8SSimon Glass 	struct udevice *dev;
21578e3332e2SSjoerd Simons 
21588e3332e2SSjoerd Simons 	ret = uclass_get(UCLASS_MMC, &uc);
21598e3332e2SSjoerd Simons 	if (ret)
21608e3332e2SSjoerd Simons 		return ret;
21618e3332e2SSjoerd Simons 
21624a1db6d8SSimon Glass 	/*
21634a1db6d8SSimon Glass 	 * Try to add them in sequence order. Really with driver model we
21644a1db6d8SSimon Glass 	 * should allow holes, but the current MMC list does not allow that.
21654a1db6d8SSimon Glass 	 * So if we request 0, 1, 3 we will get 0, 1, 2.
21664a1db6d8SSimon Glass 	 */
21674a1db6d8SSimon Glass 	for (i = 0; ; i++) {
21684a1db6d8SSimon Glass 		ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev);
21694a1db6d8SSimon Glass 		if (ret == -ENODEV)
21704a1db6d8SSimon Glass 			break;
21714a1db6d8SSimon Glass 	}
21724a1db6d8SSimon Glass 	uclass_foreach_dev(dev, uc) {
21734a1db6d8SSimon Glass 		ret = device_probe(dev);
21748e3332e2SSjoerd Simons 		if (ret)
21754a1db6d8SSimon Glass 			printf("%s - probe failed: %d\n", dev->name, ret);
21768e3332e2SSjoerd Simons 	}
21778e3332e2SSjoerd Simons 
21788e3332e2SSjoerd Simons 	return 0;
21798e3332e2SSjoerd Simons }
21808e3332e2SSjoerd Simons #else
21818e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
21828e3332e2SSjoerd Simons {
21838e3332e2SSjoerd Simons 	if (board_mmc_init(bis) < 0)
21848e3332e2SSjoerd Simons 		cpu_mmc_init(bis);
21858e3332e2SSjoerd Simons 
21868e3332e2SSjoerd Simons 	return 0;
21878e3332e2SSjoerd Simons }
21888e3332e2SSjoerd Simons #endif
2189e9550449SChe-Liang Chiou 
2190272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
2191272cc70bSAndy Fleming {
21921b26bab1SDaniel Kochmański 	static int initialized = 0;
21938e3332e2SSjoerd Simons 	int ret;
21941b26bab1SDaniel Kochmański 	if (initialized)	/* Avoid initializing mmc multiple times */
21951b26bab1SDaniel Kochmański 		return 0;
21961b26bab1SDaniel Kochmański 	initialized = 1;
21971b26bab1SDaniel Kochmański 
2198c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK)
2199b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY)
2200c40fdca6SSimon Glass 	mmc_list_init();
2201c40fdca6SSimon Glass #endif
2202b5b838f1SMarek Vasut #endif
22038e3332e2SSjoerd Simons 	ret = mmc_probe(bis);
22048e3332e2SSjoerd Simons 	if (ret)
22058e3332e2SSjoerd Simons 		return ret;
2206272cc70bSAndy Fleming 
2207bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD
2208272cc70bSAndy Fleming 	print_mmc_devices(',');
2209bb0dc108SYing Zhang #endif
2210272cc70bSAndy Fleming 
2211c40fdca6SSimon Glass 	mmc_do_preinit();
2212272cc70bSAndy Fleming 	return 0;
2213272cc70bSAndy Fleming }
2214cd3d4880STomas Melin 
2215cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE
2216cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc)
2217cd3d4880STomas Melin {
2218cd3d4880STomas Melin 	int err;
2219cd3d4880STomas Melin 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
2220cd3d4880STomas Melin 
2221cd3d4880STomas Melin 	err = mmc_send_ext_csd(mmc, ext_csd);
2222cd3d4880STomas Melin 	if (err) {
2223cd3d4880STomas Melin 		puts("Could not get ext_csd register values\n");
2224cd3d4880STomas Melin 		return err;
2225cd3d4880STomas Melin 	}
2226cd3d4880STomas Melin 
2227cd3d4880STomas Melin 	if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) {
2228cd3d4880STomas Melin 		puts("Background operations not supported on device\n");
2229cd3d4880STomas Melin 		return -EMEDIUMTYPE;
2230cd3d4880STomas Melin 	}
2231cd3d4880STomas Melin 
2232cd3d4880STomas Melin 	if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) {
2233cd3d4880STomas Melin 		puts("Background operations already enabled\n");
2234cd3d4880STomas Melin 		return 0;
2235cd3d4880STomas Melin 	}
2236cd3d4880STomas Melin 
2237cd3d4880STomas Melin 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1);
2238cd3d4880STomas Melin 	if (err) {
2239cd3d4880STomas Melin 		puts("Failed to enable manual background operations\n");
2240cd3d4880STomas Melin 		return err;
2241cd3d4880STomas Melin 	}
2242cd3d4880STomas Melin 
2243cd3d4880STomas Melin 	puts("Enabled manual background operations\n");
2244cd3d4880STomas Melin 
2245cd3d4880STomas Melin 	return 0;
2246cd3d4880STomas Melin }
2247cd3d4880STomas Melin #endif
2248