xref: /openbmc/u-boot/drivers/mmc/mmc.c (revision d0c221fe7336fc7d9ada57d96f4a8911a3aac041)
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 
33b5b838f1SMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY)
34b5b838f1SMarek Vasut static struct mmc mmc_static;
35b5b838f1SMarek Vasut struct mmc *find_mmc_device(int dev_num)
36b5b838f1SMarek Vasut {
37b5b838f1SMarek Vasut 	return &mmc_static;
38b5b838f1SMarek Vasut }
39b5b838f1SMarek Vasut 
40b5b838f1SMarek Vasut void mmc_do_preinit(void)
41b5b838f1SMarek Vasut {
42b5b838f1SMarek Vasut 	struct mmc *m = &mmc_static;
43b5b838f1SMarek Vasut #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
44b5b838f1SMarek Vasut 	mmc_set_preinit(m, 1);
45b5b838f1SMarek Vasut #endif
46b5b838f1SMarek Vasut 	if (m->preinit)
47b5b838f1SMarek Vasut 		mmc_start_init(m);
48b5b838f1SMarek Vasut }
49b5b838f1SMarek Vasut 
50b5b838f1SMarek Vasut struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
51b5b838f1SMarek Vasut {
52b5b838f1SMarek Vasut 	return &mmc->block_dev;
53b5b838f1SMarek Vasut }
54b5b838f1SMarek Vasut #endif
55b5b838f1SMarek Vasut 
56e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
57750121c3SJeroen Hofstee __weak int board_mmc_getwp(struct mmc *mmc)
58d23d8d7eSNikita Kiryanov {
59d23d8d7eSNikita Kiryanov 	return -1;
60d23d8d7eSNikita Kiryanov }
61d23d8d7eSNikita Kiryanov 
62d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc)
63d23d8d7eSNikita Kiryanov {
64d23d8d7eSNikita Kiryanov 	int wp;
65d23d8d7eSNikita Kiryanov 
66d23d8d7eSNikita Kiryanov 	wp = board_mmc_getwp(mmc);
67d23d8d7eSNikita Kiryanov 
68d4e1da4eSPeter Korsgaard 	if (wp < 0) {
6993bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getwp)
7093bfd616SPantelis Antoniou 			wp = mmc->cfg->ops->getwp(mmc);
71d4e1da4eSPeter Korsgaard 		else
72d4e1da4eSPeter Korsgaard 			wp = 0;
73d4e1da4eSPeter Korsgaard 	}
74d23d8d7eSNikita Kiryanov 
75d23d8d7eSNikita Kiryanov 	return wp;
76d23d8d7eSNikita Kiryanov }
77d23d8d7eSNikita Kiryanov 
78cee9ab7cSJeroen Hofstee __weak int board_mmc_getcd(struct mmc *mmc)
79cee9ab7cSJeroen Hofstee {
8011fdade2SStefano Babic 	return -1;
8111fdade2SStefano Babic }
828ca51e51SSimon Glass #endif
8311fdade2SStefano Babic 
848635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE
85c0c76ebaSSimon Glass void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd)
86c0c76ebaSSimon Glass {
87c0c76ebaSSimon Glass 	printf("CMD_SEND:%d\n", cmd->cmdidx);
88c0c76ebaSSimon Glass 	printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg);
89c0c76ebaSSimon Glass }
90c0c76ebaSSimon Glass 
91c0c76ebaSSimon Glass void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret)
92c0c76ebaSSimon Glass {
935db2fe3aSRaffaele Recalcati 	int i;
945db2fe3aSRaffaele Recalcati 	u8 *ptr;
955db2fe3aSRaffaele Recalcati 
967863ce58SBin Meng 	if (ret) {
977863ce58SBin Meng 		printf("\t\tRET\t\t\t %d\n", ret);
987863ce58SBin Meng 	} else {
995db2fe3aSRaffaele Recalcati 		switch (cmd->resp_type) {
1005db2fe3aSRaffaele Recalcati 		case MMC_RSP_NONE:
1015db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_NONE\n");
1025db2fe3aSRaffaele Recalcati 			break;
1035db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1:
1045db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n",
1055db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1065db2fe3aSRaffaele Recalcati 			break;
1075db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1b:
1085db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n",
1095db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1105db2fe3aSRaffaele Recalcati 			break;
1115db2fe3aSRaffaele Recalcati 		case MMC_RSP_R2:
1125db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R2\t\t 0x%08X \n",
1135db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1145db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1155db2fe3aSRaffaele Recalcati 				cmd->response[1]);
1165db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1175db2fe3aSRaffaele Recalcati 				cmd->response[2]);
1185db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1195db2fe3aSRaffaele Recalcati 				cmd->response[3]);
1205db2fe3aSRaffaele Recalcati 			printf("\n");
1215db2fe3aSRaffaele Recalcati 			printf("\t\t\t\t\tDUMPING DATA\n");
1225db2fe3aSRaffaele Recalcati 			for (i = 0; i < 4; i++) {
1235db2fe3aSRaffaele Recalcati 				int j;
1245db2fe3aSRaffaele Recalcati 				printf("\t\t\t\t\t%03d - ", i*4);
125146bec79SDirk Behme 				ptr = (u8 *)&cmd->response[i];
1265db2fe3aSRaffaele Recalcati 				ptr += 3;
1275db2fe3aSRaffaele Recalcati 				for (j = 0; j < 4; j++)
1285db2fe3aSRaffaele Recalcati 					printf("%02X ", *ptr--);
1295db2fe3aSRaffaele Recalcati 				printf("\n");
1305db2fe3aSRaffaele Recalcati 			}
1315db2fe3aSRaffaele Recalcati 			break;
1325db2fe3aSRaffaele Recalcati 		case MMC_RSP_R3:
1335db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n",
1345db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1355db2fe3aSRaffaele Recalcati 			break;
1365db2fe3aSRaffaele Recalcati 		default:
1375db2fe3aSRaffaele Recalcati 			printf("\t\tERROR MMC rsp not supported\n");
1385db2fe3aSRaffaele Recalcati 			break;
1395db2fe3aSRaffaele Recalcati 		}
1407863ce58SBin Meng 	}
141c0c76ebaSSimon Glass }
142c0c76ebaSSimon Glass 
143c0c76ebaSSimon Glass void mmc_trace_state(struct mmc *mmc, struct mmc_cmd *cmd)
144c0c76ebaSSimon Glass {
145c0c76ebaSSimon Glass 	int status;
146c0c76ebaSSimon Glass 
147c0c76ebaSSimon Glass 	status = (cmd->response[0] & MMC_STATUS_CURR_STATE) >> 9;
148c0c76ebaSSimon Glass 	printf("CURR STATE:%d\n", status);
149c0c76ebaSSimon Glass }
1505db2fe3aSRaffaele Recalcati #endif
151c0c76ebaSSimon Glass 
15235f9e196SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG)
15335f9e196SJean-Jacques Hiblot const char *mmc_mode_name(enum bus_mode mode)
15435f9e196SJean-Jacques Hiblot {
15535f9e196SJean-Jacques Hiblot 	static const char *const names[] = {
15635f9e196SJean-Jacques Hiblot 	      [MMC_LEGACY]	= "MMC legacy",
15735f9e196SJean-Jacques Hiblot 	      [SD_LEGACY]	= "SD Legacy",
15835f9e196SJean-Jacques Hiblot 	      [MMC_HS]		= "MMC High Speed (26MHz)",
15935f9e196SJean-Jacques Hiblot 	      [SD_HS]		= "SD High Speed (50MHz)",
16035f9e196SJean-Jacques Hiblot 	      [UHS_SDR12]	= "UHS SDR12 (25MHz)",
16135f9e196SJean-Jacques Hiblot 	      [UHS_SDR25]	= "UHS SDR25 (50MHz)",
16235f9e196SJean-Jacques Hiblot 	      [UHS_SDR50]	= "UHS SDR50 (100MHz)",
16335f9e196SJean-Jacques Hiblot 	      [UHS_SDR104]	= "UHS SDR104 (208MHz)",
16435f9e196SJean-Jacques Hiblot 	      [UHS_DDR50]	= "UHS DDR50 (50MHz)",
16535f9e196SJean-Jacques Hiblot 	      [MMC_HS_52]	= "MMC High Speed (52MHz)",
16635f9e196SJean-Jacques Hiblot 	      [MMC_DDR_52]	= "MMC DDR52 (52MHz)",
16735f9e196SJean-Jacques Hiblot 	      [MMC_HS_200]	= "HS200 (200MHz)",
16835f9e196SJean-Jacques Hiblot 	};
16935f9e196SJean-Jacques Hiblot 
17035f9e196SJean-Jacques Hiblot 	if (mode >= MMC_MODES_END)
17135f9e196SJean-Jacques Hiblot 		return "Unknown mode";
17235f9e196SJean-Jacques Hiblot 	else
17335f9e196SJean-Jacques Hiblot 		return names[mode];
17435f9e196SJean-Jacques Hiblot }
17535f9e196SJean-Jacques Hiblot #endif
17635f9e196SJean-Jacques Hiblot 
17705038576SJean-Jacques Hiblot static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode)
17805038576SJean-Jacques Hiblot {
17905038576SJean-Jacques Hiblot 	static const int freqs[] = {
18005038576SJean-Jacques Hiblot 	      [SD_LEGACY]	= 25000000,
18105038576SJean-Jacques Hiblot 	      [MMC_HS]		= 26000000,
18205038576SJean-Jacques Hiblot 	      [SD_HS]		= 50000000,
18305038576SJean-Jacques Hiblot 	      [UHS_SDR12]	= 25000000,
18405038576SJean-Jacques Hiblot 	      [UHS_SDR25]	= 50000000,
18505038576SJean-Jacques Hiblot 	      [UHS_SDR50]	= 100000000,
18605038576SJean-Jacques Hiblot 	      [UHS_SDR104]	= 208000000,
18705038576SJean-Jacques Hiblot 	      [UHS_DDR50]	= 50000000,
18805038576SJean-Jacques Hiblot 	      [MMC_HS_52]	= 52000000,
18905038576SJean-Jacques Hiblot 	      [MMC_DDR_52]	= 52000000,
19005038576SJean-Jacques Hiblot 	      [MMC_HS_200]	= 200000000,
19105038576SJean-Jacques Hiblot 	};
19205038576SJean-Jacques Hiblot 
19305038576SJean-Jacques Hiblot 	if (mode == MMC_LEGACY)
19405038576SJean-Jacques Hiblot 		return mmc->legacy_speed;
19505038576SJean-Jacques Hiblot 	else if (mode >= MMC_MODES_END)
19605038576SJean-Jacques Hiblot 		return 0;
19705038576SJean-Jacques Hiblot 	else
19805038576SJean-Jacques Hiblot 		return freqs[mode];
19905038576SJean-Jacques Hiblot }
20005038576SJean-Jacques Hiblot 
20135f9e196SJean-Jacques Hiblot static int mmc_select_mode(struct mmc *mmc, enum bus_mode mode)
20235f9e196SJean-Jacques Hiblot {
20335f9e196SJean-Jacques Hiblot 	mmc->selected_mode = mode;
20405038576SJean-Jacques Hiblot 	mmc->tran_speed = mmc_mode2freq(mmc, mode);
20535f9e196SJean-Jacques Hiblot 	debug("selecting mode %s (freq : %d MHz)\n", mmc_mode_name(mode),
20635f9e196SJean-Jacques Hiblot 	      mmc->tran_speed / 1000000);
20735f9e196SJean-Jacques Hiblot 	return 0;
20835f9e196SJean-Jacques Hiblot }
20935f9e196SJean-Jacques Hiblot 
210e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
211c0c76ebaSSimon Glass int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
212c0c76ebaSSimon Glass {
213c0c76ebaSSimon Glass 	int ret;
214c0c76ebaSSimon Glass 
215c0c76ebaSSimon Glass 	mmmc_trace_before_send(mmc, cmd);
216c0c76ebaSSimon Glass 	ret = mmc->cfg->ops->send_cmd(mmc, cmd, data);
217c0c76ebaSSimon Glass 	mmmc_trace_after_send(mmc, cmd, ret);
218c0c76ebaSSimon Glass 
2198635ff9eSMarek Vasut 	return ret;
220272cc70bSAndy Fleming }
2218ca51e51SSimon Glass #endif
222272cc70bSAndy Fleming 
223da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout)
2245d4fc8d9SRaffaele Recalcati {
2255d4fc8d9SRaffaele Recalcati 	struct mmc_cmd cmd;
226d617c426SJan Kloetzke 	int err, retries = 5;
2275d4fc8d9SRaffaele Recalcati 
2285d4fc8d9SRaffaele Recalcati 	cmd.cmdidx = MMC_CMD_SEND_STATUS;
2295d4fc8d9SRaffaele Recalcati 	cmd.resp_type = MMC_RSP_R1;
230aaf3d41aSMarek Vasut 	if (!mmc_host_is_spi(mmc))
231aaf3d41aSMarek Vasut 		cmd.cmdarg = mmc->rca << 16;
2325d4fc8d9SRaffaele Recalcati 
2331677eef4SAndrew Gabbasov 	while (1) {
2345d4fc8d9SRaffaele Recalcati 		err = mmc_send_cmd(mmc, &cmd, NULL);
235d617c426SJan Kloetzke 		if (!err) {
236d617c426SJan Kloetzke 			if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) &&
237d617c426SJan Kloetzke 			    (cmd.response[0] & MMC_STATUS_CURR_STATE) !=
238d617c426SJan Kloetzke 			     MMC_STATE_PRG)
2395d4fc8d9SRaffaele Recalcati 				break;
240*d0c221feSJean-Jacques Hiblot 
241*d0c221feSJean-Jacques Hiblot 			if (cmd.response[0] & MMC_STATUS_MASK) {
24256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
243d617c426SJan Kloetzke 				printf("Status Error: 0x%08X\n",
244d617c426SJan Kloetzke 					cmd.response[0]);
24556196826SPaul Burton #endif
246915ffa52SJaehoon Chung 				return -ECOMM;
247d617c426SJan Kloetzke 			}
248d617c426SJan Kloetzke 		} else if (--retries < 0)
249d617c426SJan Kloetzke 			return err;
2505d4fc8d9SRaffaele Recalcati 
2511677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
2521677eef4SAndrew Gabbasov 			break;
2535d4fc8d9SRaffaele Recalcati 
2541677eef4SAndrew Gabbasov 		udelay(1000);
2551677eef4SAndrew Gabbasov 	}
2565d4fc8d9SRaffaele Recalcati 
257c0c76ebaSSimon Glass 	mmc_trace_state(mmc, &cmd);
2585b0c942fSJongman Heo 	if (timeout <= 0) {
25956196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2605d4fc8d9SRaffaele Recalcati 		printf("Timeout waiting card ready\n");
26156196826SPaul Burton #endif
262915ffa52SJaehoon Chung 		return -ETIMEDOUT;
2635d4fc8d9SRaffaele Recalcati 	}
2645d4fc8d9SRaffaele Recalcati 
2655d4fc8d9SRaffaele Recalcati 	return 0;
2665d4fc8d9SRaffaele Recalcati }
2675d4fc8d9SRaffaele Recalcati 
268da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len)
269272cc70bSAndy Fleming {
270272cc70bSAndy Fleming 	struct mmc_cmd cmd;
271272cc70bSAndy Fleming 
272786e8f81SAndrew Gabbasov 	if (mmc->ddr_mode)
273d22e3d46SJaehoon Chung 		return 0;
274d22e3d46SJaehoon Chung 
275272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
276272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
277272cc70bSAndy Fleming 	cmd.cmdarg = len;
278272cc70bSAndy Fleming 
279272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, NULL);
280272cc70bSAndy Fleming }
281272cc70bSAndy Fleming 
282ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
283fdbb873eSKim Phillips 			   lbaint_t blkcnt)
284272cc70bSAndy Fleming {
285272cc70bSAndy Fleming 	struct mmc_cmd cmd;
286272cc70bSAndy Fleming 	struct mmc_data data;
287272cc70bSAndy Fleming 
2884a1a06bcSAlagu Sankar 	if (blkcnt > 1)
2894a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
2904a1a06bcSAlagu Sankar 	else
291272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
292272cc70bSAndy Fleming 
293272cc70bSAndy Fleming 	if (mmc->high_capacity)
2944a1a06bcSAlagu Sankar 		cmd.cmdarg = start;
295272cc70bSAndy Fleming 	else
2964a1a06bcSAlagu Sankar 		cmd.cmdarg = start * mmc->read_bl_len;
297272cc70bSAndy Fleming 
298272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
299272cc70bSAndy Fleming 
300272cc70bSAndy Fleming 	data.dest = dst;
3014a1a06bcSAlagu Sankar 	data.blocks = blkcnt;
302272cc70bSAndy Fleming 	data.blocksize = mmc->read_bl_len;
303272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
304272cc70bSAndy Fleming 
3054a1a06bcSAlagu Sankar 	if (mmc_send_cmd(mmc, &cmd, &data))
3064a1a06bcSAlagu Sankar 		return 0;
3074a1a06bcSAlagu Sankar 
3084a1a06bcSAlagu Sankar 	if (blkcnt > 1) {
3094a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
3104a1a06bcSAlagu Sankar 		cmd.cmdarg = 0;
3114a1a06bcSAlagu Sankar 		cmd.resp_type = MMC_RSP_R1b;
3124a1a06bcSAlagu Sankar 		if (mmc_send_cmd(mmc, &cmd, NULL)) {
31356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
3144a1a06bcSAlagu Sankar 			printf("mmc fail to send stop cmd\n");
31556196826SPaul Burton #endif
3164a1a06bcSAlagu Sankar 			return 0;
3174a1a06bcSAlagu Sankar 		}
318272cc70bSAndy Fleming 	}
319272cc70bSAndy Fleming 
3204a1a06bcSAlagu Sankar 	return blkcnt;
321272cc70bSAndy Fleming }
322272cc70bSAndy Fleming 
323c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
3247dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst)
32533fb211dSSimon Glass #else
3267dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
3277dba0b93SSimon Glass 		void *dst)
32833fb211dSSimon Glass #endif
329272cc70bSAndy Fleming {
330c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
33133fb211dSSimon Glass 	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
33233fb211dSSimon Glass #endif
333bcce53d0SSimon Glass 	int dev_num = block_dev->devnum;
334873cc1d7SStephen Warren 	int err;
3354a1a06bcSAlagu Sankar 	lbaint_t cur, blocks_todo = blkcnt;
336272cc70bSAndy Fleming 
3374a1a06bcSAlagu Sankar 	if (blkcnt == 0)
3384a1a06bcSAlagu Sankar 		return 0;
3394a1a06bcSAlagu Sankar 
3404a1a06bcSAlagu Sankar 	struct mmc *mmc = find_mmc_device(dev_num);
341272cc70bSAndy Fleming 	if (!mmc)
342272cc70bSAndy Fleming 		return 0;
343272cc70bSAndy Fleming 
344b5b838f1SMarek Vasut 	if (CONFIG_IS_ENABLED(MMC_TINY))
345b5b838f1SMarek Vasut 		err = mmc_switch_part(mmc, block_dev->hwpart);
346b5b838f1SMarek Vasut 	else
34769f45cd5SSimon Glass 		err = blk_dselect_hwpart(block_dev, block_dev->hwpart);
348b5b838f1SMarek Vasut 
349873cc1d7SStephen Warren 	if (err < 0)
350873cc1d7SStephen Warren 		return 0;
351873cc1d7SStephen Warren 
352c40fdca6SSimon Glass 	if ((start + blkcnt) > block_dev->lba) {
35356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
354ff8fef56SSascha Silbe 		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
355c40fdca6SSimon Glass 			start + blkcnt, block_dev->lba);
35656196826SPaul Burton #endif
357d2bf29e3SLei Wen 		return 0;
358d2bf29e3SLei Wen 	}
359272cc70bSAndy Fleming 
36011692991SSimon Glass 	if (mmc_set_blocklen(mmc, mmc->read_bl_len)) {
36111692991SSimon Glass 		debug("%s: Failed to set blocklen\n", __func__);
362272cc70bSAndy Fleming 		return 0;
36311692991SSimon Glass 	}
364272cc70bSAndy Fleming 
3654a1a06bcSAlagu Sankar 	do {
36693bfd616SPantelis Antoniou 		cur = (blocks_todo > mmc->cfg->b_max) ?
36793bfd616SPantelis Antoniou 			mmc->cfg->b_max : blocks_todo;
36811692991SSimon Glass 		if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
36911692991SSimon Glass 			debug("%s: Failed to read blocks\n", __func__);
3704a1a06bcSAlagu Sankar 			return 0;
37111692991SSimon Glass 		}
3724a1a06bcSAlagu Sankar 		blocks_todo -= cur;
3734a1a06bcSAlagu Sankar 		start += cur;
3744a1a06bcSAlagu Sankar 		dst += cur * mmc->read_bl_len;
3754a1a06bcSAlagu Sankar 	} while (blocks_todo > 0);
376272cc70bSAndy Fleming 
377272cc70bSAndy Fleming 	return blkcnt;
378272cc70bSAndy Fleming }
379272cc70bSAndy Fleming 
380fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc)
381272cc70bSAndy Fleming {
382272cc70bSAndy Fleming 	struct mmc_cmd cmd;
383272cc70bSAndy Fleming 	int err;
384272cc70bSAndy Fleming 
385272cc70bSAndy Fleming 	udelay(1000);
386272cc70bSAndy Fleming 
387272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
388272cc70bSAndy Fleming 	cmd.cmdarg = 0;
389272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_NONE;
390272cc70bSAndy Fleming 
391272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
392272cc70bSAndy Fleming 
393272cc70bSAndy Fleming 	if (err)
394272cc70bSAndy Fleming 		return err;
395272cc70bSAndy Fleming 
396272cc70bSAndy Fleming 	udelay(2000);
397272cc70bSAndy Fleming 
398272cc70bSAndy Fleming 	return 0;
399272cc70bSAndy Fleming }
400272cc70bSAndy Fleming 
401fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc)
402272cc70bSAndy Fleming {
403272cc70bSAndy Fleming 	int timeout = 1000;
404272cc70bSAndy Fleming 	int err;
405272cc70bSAndy Fleming 	struct mmc_cmd cmd;
406272cc70bSAndy Fleming 
4071677eef4SAndrew Gabbasov 	while (1) {
408272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_APP_CMD;
409272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1;
410272cc70bSAndy Fleming 		cmd.cmdarg = 0;
411272cc70bSAndy Fleming 
412272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
413272cc70bSAndy Fleming 
414272cc70bSAndy Fleming 		if (err)
415272cc70bSAndy Fleming 			return err;
416272cc70bSAndy Fleming 
417272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
418272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
419250de12bSStefano Babic 
420250de12bSStefano Babic 		/*
421250de12bSStefano Babic 		 * Most cards do not answer if some reserved bits
422250de12bSStefano Babic 		 * in the ocr are set. However, Some controller
423250de12bSStefano Babic 		 * can set bit 7 (reserved for low voltages), but
424250de12bSStefano Babic 		 * how to manage low voltages SD card is not yet
425250de12bSStefano Babic 		 * specified.
426250de12bSStefano Babic 		 */
427d52ebf10SThomas Chou 		cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
42893bfd616SPantelis Antoniou 			(mmc->cfg->voltages & 0xff8000);
429272cc70bSAndy Fleming 
430272cc70bSAndy Fleming 		if (mmc->version == SD_VERSION_2)
431272cc70bSAndy Fleming 			cmd.cmdarg |= OCR_HCS;
432272cc70bSAndy Fleming 
433272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
434272cc70bSAndy Fleming 
435272cc70bSAndy Fleming 		if (err)
436272cc70bSAndy Fleming 			return err;
437272cc70bSAndy Fleming 
4381677eef4SAndrew Gabbasov 		if (cmd.response[0] & OCR_BUSY)
4391677eef4SAndrew Gabbasov 			break;
440272cc70bSAndy Fleming 
4411677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
442915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
443272cc70bSAndy Fleming 
4441677eef4SAndrew Gabbasov 		udelay(1000);
4451677eef4SAndrew Gabbasov 	}
4461677eef4SAndrew Gabbasov 
447272cc70bSAndy Fleming 	if (mmc->version != SD_VERSION_2)
448272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
449272cc70bSAndy Fleming 
450d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
451d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
452d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
453d52ebf10SThomas Chou 		cmd.cmdarg = 0;
454d52ebf10SThomas Chou 
455d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
456d52ebf10SThomas Chou 
457d52ebf10SThomas Chou 		if (err)
458d52ebf10SThomas Chou 			return err;
459d52ebf10SThomas Chou 	}
460d52ebf10SThomas Chou 
461998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
462272cc70bSAndy Fleming 
463272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
464272cc70bSAndy Fleming 	mmc->rca = 0;
465272cc70bSAndy Fleming 
466272cc70bSAndy Fleming 	return 0;
467272cc70bSAndy Fleming }
468272cc70bSAndy Fleming 
4695289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg)
470272cc70bSAndy Fleming {
4715289b535SAndrew Gabbasov 	struct mmc_cmd cmd;
472272cc70bSAndy Fleming 	int err;
473272cc70bSAndy Fleming 
4745289b535SAndrew Gabbasov 	cmd.cmdidx = MMC_CMD_SEND_OP_COND;
4755289b535SAndrew Gabbasov 	cmd.resp_type = MMC_RSP_R3;
4765289b535SAndrew Gabbasov 	cmd.cmdarg = 0;
4775a20397bSRob Herring 	if (use_arg && !mmc_host_is_spi(mmc))
4785a20397bSRob Herring 		cmd.cmdarg = OCR_HCS |
47993bfd616SPantelis Antoniou 			(mmc->cfg->voltages &
480a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_VOLTAGE_MASK)) |
481a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_ACCESS_MODE);
482e9550449SChe-Liang Chiou 
4835289b535SAndrew Gabbasov 	err = mmc_send_cmd(mmc, &cmd, NULL);
484e9550449SChe-Liang Chiou 	if (err)
485e9550449SChe-Liang Chiou 		return err;
4865289b535SAndrew Gabbasov 	mmc->ocr = cmd.response[0];
487e9550449SChe-Liang Chiou 	return 0;
488e9550449SChe-Liang Chiou }
489e9550449SChe-Liang Chiou 
490750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc)
491e9550449SChe-Liang Chiou {
492e9550449SChe-Liang Chiou 	int err, i;
493e9550449SChe-Liang Chiou 
494272cc70bSAndy Fleming 	/* Some cards seem to need this */
495272cc70bSAndy Fleming 	mmc_go_idle(mmc);
496272cc70bSAndy Fleming 
49731cacbabSRaffaele Recalcati  	/* Asking to the card its capabilities */
498e9550449SChe-Liang Chiou 	for (i = 0; i < 2; i++) {
4995289b535SAndrew Gabbasov 		err = mmc_send_op_cond_iter(mmc, i != 0);
50031cacbabSRaffaele Recalcati 		if (err)
50131cacbabSRaffaele Recalcati 			return err;
50231cacbabSRaffaele Recalcati 
503e9550449SChe-Liang Chiou 		/* exit if not busy (flag seems to be inverted) */
504a626c8d4SAndrew Gabbasov 		if (mmc->ocr & OCR_BUSY)
505bd47c135SAndrew Gabbasov 			break;
506e9550449SChe-Liang Chiou 	}
507bd47c135SAndrew Gabbasov 	mmc->op_cond_pending = 1;
508bd47c135SAndrew Gabbasov 	return 0;
509e9550449SChe-Liang Chiou }
51031cacbabSRaffaele Recalcati 
511750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc)
512e9550449SChe-Liang Chiou {
513e9550449SChe-Liang Chiou 	struct mmc_cmd cmd;
514e9550449SChe-Liang Chiou 	int timeout = 1000;
515e9550449SChe-Liang Chiou 	uint start;
516e9550449SChe-Liang Chiou 	int err;
517e9550449SChe-Liang Chiou 
518e9550449SChe-Liang Chiou 	mmc->op_cond_pending = 0;
519cc17c01fSAndrew Gabbasov 	if (!(mmc->ocr & OCR_BUSY)) {
520d188b113SYangbo Lu 		/* Some cards seem to need this */
521d188b113SYangbo Lu 		mmc_go_idle(mmc);
522d188b113SYangbo Lu 
523e9550449SChe-Liang Chiou 		start = get_timer(0);
5241677eef4SAndrew Gabbasov 		while (1) {
5255289b535SAndrew Gabbasov 			err = mmc_send_op_cond_iter(mmc, 1);
526272cc70bSAndy Fleming 			if (err)
527272cc70bSAndy Fleming 				return err;
5281677eef4SAndrew Gabbasov 			if (mmc->ocr & OCR_BUSY)
5291677eef4SAndrew Gabbasov 				break;
530e9550449SChe-Liang Chiou 			if (get_timer(start) > timeout)
531915ffa52SJaehoon Chung 				return -EOPNOTSUPP;
532e9550449SChe-Liang Chiou 			udelay(100);
5331677eef4SAndrew Gabbasov 		}
534cc17c01fSAndrew Gabbasov 	}
535272cc70bSAndy Fleming 
536d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
537d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
538d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
539d52ebf10SThomas Chou 		cmd.cmdarg = 0;
540d52ebf10SThomas Chou 
541d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
542d52ebf10SThomas Chou 
543d52ebf10SThomas Chou 		if (err)
544d52ebf10SThomas Chou 			return err;
545a626c8d4SAndrew Gabbasov 
546a626c8d4SAndrew Gabbasov 		mmc->ocr = cmd.response[0];
547d52ebf10SThomas Chou 	}
548d52ebf10SThomas Chou 
549272cc70bSAndy Fleming 	mmc->version = MMC_VERSION_UNKNOWN;
550272cc70bSAndy Fleming 
551272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
552def816a2SStephen Warren 	mmc->rca = 1;
553272cc70bSAndy Fleming 
554272cc70bSAndy Fleming 	return 0;
555272cc70bSAndy Fleming }
556272cc70bSAndy Fleming 
557272cc70bSAndy Fleming 
558fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
559272cc70bSAndy Fleming {
560272cc70bSAndy Fleming 	struct mmc_cmd cmd;
561272cc70bSAndy Fleming 	struct mmc_data data;
562272cc70bSAndy Fleming 	int err;
563272cc70bSAndy Fleming 
564272cc70bSAndy Fleming 	/* Get the Card Status Register */
565272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
566272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
567272cc70bSAndy Fleming 	cmd.cmdarg = 0;
568272cc70bSAndy Fleming 
569cdfd1ac6SYoshihiro Shimoda 	data.dest = (char *)ext_csd;
570272cc70bSAndy Fleming 	data.blocks = 1;
5718bfa195eSSimon Glass 	data.blocksize = MMC_MAX_BLOCK_LEN;
572272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
573272cc70bSAndy Fleming 
574272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
575272cc70bSAndy Fleming 
576272cc70bSAndy Fleming 	return err;
577272cc70bSAndy Fleming }
578272cc70bSAndy Fleming 
579c40704f4SSimon Glass int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
580272cc70bSAndy Fleming {
581272cc70bSAndy Fleming 	struct mmc_cmd cmd;
5825d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
583a9003dc6SMaxime Ripard 	int retries = 3;
5845d4fc8d9SRaffaele Recalcati 	int ret;
585272cc70bSAndy Fleming 
586272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SWITCH;
587272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1b;
588272cc70bSAndy Fleming 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
589272cc70bSAndy Fleming 				 (index << 16) |
590272cc70bSAndy Fleming 				 (value << 8);
591272cc70bSAndy Fleming 
592a9003dc6SMaxime Ripard 	while (retries > 0) {
5935d4fc8d9SRaffaele Recalcati 		ret = mmc_send_cmd(mmc, &cmd, NULL);
5945d4fc8d9SRaffaele Recalcati 
5955d4fc8d9SRaffaele Recalcati 		/* Waiting for the ready status */
596a9003dc6SMaxime Ripard 		if (!ret) {
59793ad0d18SJan Kloetzke 			ret = mmc_send_status(mmc, timeout);
598a9003dc6SMaxime Ripard 			return ret;
599a9003dc6SMaxime Ripard 		}
600a9003dc6SMaxime Ripard 
601a9003dc6SMaxime Ripard 		retries--;
602a9003dc6SMaxime Ripard 	}
6035d4fc8d9SRaffaele Recalcati 
6045d4fc8d9SRaffaele Recalcati 	return ret;
6055d4fc8d9SRaffaele Recalcati 
606272cc70bSAndy Fleming }
607272cc70bSAndy Fleming 
608fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc)
609272cc70bSAndy Fleming {
6108bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
611272cc70bSAndy Fleming 	char cardtype;
612272cc70bSAndy Fleming 	int err;
613272cc70bSAndy Fleming 
614*d0c221feSJean-Jacques Hiblot 	mmc->card_caps = MMC_MODE_1BIT;
615272cc70bSAndy Fleming 
616d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
617d52ebf10SThomas Chou 		return 0;
618d52ebf10SThomas Chou 
619272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
620272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
621272cc70bSAndy Fleming 		return 0;
622272cc70bSAndy Fleming 
623fc5b32fbSAndrew Gabbasov 	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
624fc5b32fbSAndrew Gabbasov 
625272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
626272cc70bSAndy Fleming 
627272cc70bSAndy Fleming 	if (err)
628272cc70bSAndy Fleming 		return err;
629272cc70bSAndy Fleming 
6300560db18SLei Wen 	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf;
631272cc70bSAndy Fleming 
632272cc70bSAndy Fleming 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
633272cc70bSAndy Fleming 
634272cc70bSAndy Fleming 	if (err)
635a5e27b41SHeiko Schocher 		return err;
636272cc70bSAndy Fleming 
637272cc70bSAndy Fleming 	/* Now check to see that it worked */
638272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
639272cc70bSAndy Fleming 
640272cc70bSAndy Fleming 	if (err)
641272cc70bSAndy Fleming 		return err;
642272cc70bSAndy Fleming 
643272cc70bSAndy Fleming 	/* No high-speed support */
6440560db18SLei Wen 	if (!ext_csd[EXT_CSD_HS_TIMING])
645272cc70bSAndy Fleming 		return 0;
646272cc70bSAndy Fleming 
647272cc70bSAndy Fleming 	/* High Speed is set, there are two types: 52MHz and 26MHz */
648d22e3d46SJaehoon Chung 	if (cardtype & EXT_CSD_CARD_TYPE_52) {
649201d5ac4SAndrew Gabbasov 		if (cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V)
650d22e3d46SJaehoon Chung 			mmc->card_caps |= MMC_MODE_DDR_52MHz;
651272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
652d22e3d46SJaehoon Chung 	} else {
653272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
654d22e3d46SJaehoon Chung 	}
655272cc70bSAndy Fleming 
656272cc70bSAndy Fleming 	return 0;
657272cc70bSAndy Fleming }
658272cc70bSAndy Fleming 
659f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num)
660f866a46dSStephen Warren {
661f866a46dSStephen Warren 	switch (part_num) {
662f866a46dSStephen Warren 	case 0:
663f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_user;
664f866a46dSStephen Warren 		break;
665f866a46dSStephen Warren 	case 1:
666f866a46dSStephen Warren 	case 2:
667f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_boot;
668f866a46dSStephen Warren 		break;
669f866a46dSStephen Warren 	case 3:
670f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_rpmb;
671f866a46dSStephen Warren 		break;
672f866a46dSStephen Warren 	case 4:
673f866a46dSStephen Warren 	case 5:
674f866a46dSStephen Warren 	case 6:
675f866a46dSStephen Warren 	case 7:
676f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_gp[part_num - 4];
677f866a46dSStephen Warren 		break;
678f866a46dSStephen Warren 	default:
679f866a46dSStephen Warren 		return -1;
680f866a46dSStephen Warren 	}
681f866a46dSStephen Warren 
682c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len);
683f866a46dSStephen Warren 
684f866a46dSStephen Warren 	return 0;
685f866a46dSStephen Warren }
686f866a46dSStephen Warren 
6877dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num)
688bc897b1dSLei Wen {
689f866a46dSStephen Warren 	int ret;
690bc897b1dSLei Wen 
691f866a46dSStephen Warren 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
692bc897b1dSLei Wen 			 (mmc->part_config & ~PART_ACCESS_MASK)
693bc897b1dSLei Wen 			 | (part_num & PART_ACCESS_MASK));
694f866a46dSStephen Warren 
6956dc93e70SPeter Bigot 	/*
6966dc93e70SPeter Bigot 	 * Set the capacity if the switch succeeded or was intended
6976dc93e70SPeter Bigot 	 * to return to representing the raw device.
6986dc93e70SPeter Bigot 	 */
699873cc1d7SStephen Warren 	if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) {
7006dc93e70SPeter Bigot 		ret = mmc_set_capacity(mmc, part_num);
701fdbb139fSSimon Glass 		mmc_get_blk_desc(mmc)->hwpart = part_num;
702873cc1d7SStephen Warren 	}
7036dc93e70SPeter Bigot 
7046dc93e70SPeter Bigot 	return ret;
705bc897b1dSLei Wen }
706bc897b1dSLei Wen 
707ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc,
708ac9da0e0SDiego Santa Cruz 		      const struct mmc_hwpart_conf *conf,
709ac9da0e0SDiego Santa Cruz 		      enum mmc_hwpart_conf_mode mode)
710ac9da0e0SDiego Santa Cruz {
711ac9da0e0SDiego Santa Cruz 	u8 part_attrs = 0;
712ac9da0e0SDiego Santa Cruz 	u32 enh_size_mult;
713ac9da0e0SDiego Santa Cruz 	u32 enh_start_addr;
714ac9da0e0SDiego Santa Cruz 	u32 gp_size_mult[4];
715ac9da0e0SDiego Santa Cruz 	u32 max_enh_size_mult;
716ac9da0e0SDiego Santa Cruz 	u32 tot_enh_size_mult = 0;
7178dda5b0eSDiego Santa Cruz 	u8 wr_rel_set;
718ac9da0e0SDiego Santa Cruz 	int i, pidx, err;
719ac9da0e0SDiego Santa Cruz 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
720ac9da0e0SDiego Santa Cruz 
721ac9da0e0SDiego Santa Cruz 	if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE)
722ac9da0e0SDiego Santa Cruz 		return -EINVAL;
723ac9da0e0SDiego Santa Cruz 
724ac9da0e0SDiego Santa Cruz 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) {
725ac9da0e0SDiego Santa Cruz 		printf("eMMC >= 4.4 required for enhanced user data area\n");
726ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
727ac9da0e0SDiego Santa Cruz 	}
728ac9da0e0SDiego Santa Cruz 
729ac9da0e0SDiego Santa Cruz 	if (!(mmc->part_support & PART_SUPPORT)) {
730ac9da0e0SDiego Santa Cruz 		printf("Card does not support partitioning\n");
731ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
732ac9da0e0SDiego Santa Cruz 	}
733ac9da0e0SDiego Santa Cruz 
734ac9da0e0SDiego Santa Cruz 	if (!mmc->hc_wp_grp_size) {
735ac9da0e0SDiego Santa Cruz 		printf("Card does not define HC WP group size\n");
736ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
737ac9da0e0SDiego Santa Cruz 	}
738ac9da0e0SDiego Santa Cruz 
739ac9da0e0SDiego Santa Cruz 	/* check partition alignment and total enhanced size */
740ac9da0e0SDiego Santa Cruz 	if (conf->user.enh_size) {
741ac9da0e0SDiego Santa Cruz 		if (conf->user.enh_size % mmc->hc_wp_grp_size ||
742ac9da0e0SDiego Santa Cruz 		    conf->user.enh_start % mmc->hc_wp_grp_size) {
743ac9da0e0SDiego Santa Cruz 			printf("User data enhanced area not HC WP group "
744ac9da0e0SDiego Santa Cruz 			       "size aligned\n");
745ac9da0e0SDiego Santa Cruz 			return -EINVAL;
746ac9da0e0SDiego Santa Cruz 		}
747ac9da0e0SDiego Santa Cruz 		part_attrs |= EXT_CSD_ENH_USR;
748ac9da0e0SDiego Santa Cruz 		enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size;
749ac9da0e0SDiego Santa Cruz 		if (mmc->high_capacity) {
750ac9da0e0SDiego Santa Cruz 			enh_start_addr = conf->user.enh_start;
751ac9da0e0SDiego Santa Cruz 		} else {
752ac9da0e0SDiego Santa Cruz 			enh_start_addr = (conf->user.enh_start << 9);
753ac9da0e0SDiego Santa Cruz 		}
754ac9da0e0SDiego Santa Cruz 	} else {
755ac9da0e0SDiego Santa Cruz 		enh_size_mult = 0;
756ac9da0e0SDiego Santa Cruz 		enh_start_addr = 0;
757ac9da0e0SDiego Santa Cruz 	}
758ac9da0e0SDiego Santa Cruz 	tot_enh_size_mult += enh_size_mult;
759ac9da0e0SDiego Santa Cruz 
760ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
761ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) {
762ac9da0e0SDiego Santa Cruz 			printf("GP%i partition not HC WP group size "
763ac9da0e0SDiego Santa Cruz 			       "aligned\n", pidx+1);
764ac9da0e0SDiego Santa Cruz 			return -EINVAL;
765ac9da0e0SDiego Santa Cruz 		}
766ac9da0e0SDiego Santa Cruz 		gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size;
767ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) {
768ac9da0e0SDiego Santa Cruz 			part_attrs |= EXT_CSD_ENH_GP(pidx);
769ac9da0e0SDiego Santa Cruz 			tot_enh_size_mult += gp_size_mult[pidx];
770ac9da0e0SDiego Santa Cruz 		}
771ac9da0e0SDiego Santa Cruz 	}
772ac9da0e0SDiego Santa Cruz 
773ac9da0e0SDiego Santa Cruz 	if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) {
774ac9da0e0SDiego Santa Cruz 		printf("Card does not support enhanced attribute\n");
775ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
776ac9da0e0SDiego Santa Cruz 	}
777ac9da0e0SDiego Santa Cruz 
778ac9da0e0SDiego Santa Cruz 	err = mmc_send_ext_csd(mmc, ext_csd);
779ac9da0e0SDiego Santa Cruz 	if (err)
780ac9da0e0SDiego Santa Cruz 		return err;
781ac9da0e0SDiego Santa Cruz 
782ac9da0e0SDiego Santa Cruz 	max_enh_size_mult =
783ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) +
784ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) +
785ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT];
786ac9da0e0SDiego Santa Cruz 	if (tot_enh_size_mult > max_enh_size_mult) {
787ac9da0e0SDiego Santa Cruz 		printf("Total enhanced size exceeds maximum (%u > %u)\n",
788ac9da0e0SDiego Santa Cruz 		       tot_enh_size_mult, max_enh_size_mult);
789ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
790ac9da0e0SDiego Santa Cruz 	}
791ac9da0e0SDiego Santa Cruz 
7928dda5b0eSDiego Santa Cruz 	/* The default value of EXT_CSD_WR_REL_SET is device
7938dda5b0eSDiego Santa Cruz 	 * dependent, the values can only be changed if the
7948dda5b0eSDiego Santa Cruz 	 * EXT_CSD_HS_CTRL_REL bit is set. The values can be
7958dda5b0eSDiego Santa Cruz 	 * changed only once and before partitioning is completed. */
7968dda5b0eSDiego Santa Cruz 	wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
7978dda5b0eSDiego Santa Cruz 	if (conf->user.wr_rel_change) {
7988dda5b0eSDiego Santa Cruz 		if (conf->user.wr_rel_set)
7998dda5b0eSDiego Santa Cruz 			wr_rel_set |= EXT_CSD_WR_DATA_REL_USR;
8008dda5b0eSDiego Santa Cruz 		else
8018dda5b0eSDiego Santa Cruz 			wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR;
8028dda5b0eSDiego Santa Cruz 	}
8038dda5b0eSDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
8048dda5b0eSDiego Santa Cruz 		if (conf->gp_part[pidx].wr_rel_change) {
8058dda5b0eSDiego Santa Cruz 			if (conf->gp_part[pidx].wr_rel_set)
8068dda5b0eSDiego Santa Cruz 				wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx);
8078dda5b0eSDiego Santa Cruz 			else
8088dda5b0eSDiego Santa Cruz 				wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx);
8098dda5b0eSDiego Santa Cruz 		}
8108dda5b0eSDiego Santa Cruz 	}
8118dda5b0eSDiego Santa Cruz 
8128dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] &&
8138dda5b0eSDiego Santa Cruz 	    !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) {
8148dda5b0eSDiego Santa Cruz 		puts("Card does not support host controlled partition write "
8158dda5b0eSDiego Santa Cruz 		     "reliability settings\n");
8168dda5b0eSDiego Santa Cruz 		return -EMEDIUMTYPE;
8178dda5b0eSDiego Santa Cruz 	}
8188dda5b0eSDiego Santa Cruz 
819ac9da0e0SDiego Santa Cruz 	if (ext_csd[EXT_CSD_PARTITION_SETTING] &
820ac9da0e0SDiego Santa Cruz 	    EXT_CSD_PARTITION_SETTING_COMPLETED) {
821ac9da0e0SDiego Santa Cruz 		printf("Card already partitioned\n");
822ac9da0e0SDiego Santa Cruz 		return -EPERM;
823ac9da0e0SDiego Santa Cruz 	}
824ac9da0e0SDiego Santa Cruz 
825ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_CHECK)
826ac9da0e0SDiego Santa Cruz 		return 0;
827ac9da0e0SDiego Santa Cruz 
828ac9da0e0SDiego Santa Cruz 	/* Partitioning requires high-capacity size definitions */
829ac9da0e0SDiego Santa Cruz 	if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) {
830ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
831ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ERASE_GROUP_DEF, 1);
832ac9da0e0SDiego Santa Cruz 
833ac9da0e0SDiego Santa Cruz 		if (err)
834ac9da0e0SDiego Santa Cruz 			return err;
835ac9da0e0SDiego Santa Cruz 
836ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
837ac9da0e0SDiego Santa Cruz 
838ac9da0e0SDiego Santa Cruz 		/* update erase group size to be high-capacity */
839ac9da0e0SDiego Santa Cruz 		mmc->erase_grp_size =
840ac9da0e0SDiego Santa Cruz 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
841ac9da0e0SDiego Santa Cruz 
842ac9da0e0SDiego Santa Cruz 	}
843ac9da0e0SDiego Santa Cruz 
844ac9da0e0SDiego Santa Cruz 	/* all OK, write the configuration */
845ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 4; i++) {
846ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
847ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_START_ADDR+i,
848ac9da0e0SDiego Santa Cruz 				 (enh_start_addr >> (i*8)) & 0xFF);
849ac9da0e0SDiego Santa Cruz 		if (err)
850ac9da0e0SDiego Santa Cruz 			return err;
851ac9da0e0SDiego Santa Cruz 	}
852ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 3; i++) {
853ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
854ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_SIZE_MULT+i,
855ac9da0e0SDiego Santa Cruz 				 (enh_size_mult >> (i*8)) & 0xFF);
856ac9da0e0SDiego Santa Cruz 		if (err)
857ac9da0e0SDiego Santa Cruz 			return err;
858ac9da0e0SDiego Santa Cruz 	}
859ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
860ac9da0e0SDiego Santa Cruz 		for (i = 0; i < 3; i++) {
861ac9da0e0SDiego Santa Cruz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
862ac9da0e0SDiego Santa Cruz 					 EXT_CSD_GP_SIZE_MULT+pidx*3+i,
863ac9da0e0SDiego Santa Cruz 					 (gp_size_mult[pidx] >> (i*8)) & 0xFF);
864ac9da0e0SDiego Santa Cruz 			if (err)
865ac9da0e0SDiego Santa Cruz 				return err;
866ac9da0e0SDiego Santa Cruz 		}
867ac9da0e0SDiego Santa Cruz 	}
868ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
869ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs);
870ac9da0e0SDiego Santa Cruz 	if (err)
871ac9da0e0SDiego Santa Cruz 		return err;
872ac9da0e0SDiego Santa Cruz 
873ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_SET)
874ac9da0e0SDiego Santa Cruz 		return 0;
875ac9da0e0SDiego Santa Cruz 
8768dda5b0eSDiego Santa Cruz 	/* The WR_REL_SET is a write-once register but shall be
8778dda5b0eSDiego Santa Cruz 	 * written before setting PART_SETTING_COMPLETED. As it is
8788dda5b0eSDiego Santa Cruz 	 * write-once we can only write it when completing the
8798dda5b0eSDiego Santa Cruz 	 * partitioning. */
8808dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) {
8818dda5b0eSDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
8828dda5b0eSDiego Santa Cruz 				 EXT_CSD_WR_REL_SET, wr_rel_set);
8838dda5b0eSDiego Santa Cruz 		if (err)
8848dda5b0eSDiego Santa Cruz 			return err;
8858dda5b0eSDiego Santa Cruz 	}
8868dda5b0eSDiego Santa Cruz 
887ac9da0e0SDiego Santa Cruz 	/* Setting PART_SETTING_COMPLETED confirms the partition
888ac9da0e0SDiego Santa Cruz 	 * configuration but it only becomes effective after power
889ac9da0e0SDiego Santa Cruz 	 * cycle, so we do not adjust the partition related settings
890ac9da0e0SDiego Santa Cruz 	 * in the mmc struct. */
891ac9da0e0SDiego Santa Cruz 
892ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
893ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING,
894ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING_COMPLETED);
895ac9da0e0SDiego Santa Cruz 	if (err)
896ac9da0e0SDiego Santa Cruz 		return err;
897ac9da0e0SDiego Santa Cruz 
898ac9da0e0SDiego Santa Cruz 	return 0;
899ac9da0e0SDiego Santa Cruz }
900ac9da0e0SDiego Santa Cruz 
901e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
90248972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
90348972d90SThierry Reding {
90448972d90SThierry Reding 	int cd;
90548972d90SThierry Reding 
90648972d90SThierry Reding 	cd = board_mmc_getcd(mmc);
90748972d90SThierry Reding 
908d4e1da4eSPeter Korsgaard 	if (cd < 0) {
90993bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getcd)
91093bfd616SPantelis Antoniou 			cd = mmc->cfg->ops->getcd(mmc);
911d4e1da4eSPeter Korsgaard 		else
912d4e1da4eSPeter Korsgaard 			cd = 1;
913d4e1da4eSPeter Korsgaard 	}
91448972d90SThierry Reding 
91548972d90SThierry Reding 	return cd;
91648972d90SThierry Reding }
9178ca51e51SSimon Glass #endif
91848972d90SThierry Reding 
919fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
920272cc70bSAndy Fleming {
921272cc70bSAndy Fleming 	struct mmc_cmd cmd;
922272cc70bSAndy Fleming 	struct mmc_data data;
923272cc70bSAndy Fleming 
924272cc70bSAndy Fleming 	/* Switch the frequency */
925272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
926272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
927272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
928272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
929272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
930272cc70bSAndy Fleming 
931272cc70bSAndy Fleming 	data.dest = (char *)resp;
932272cc70bSAndy Fleming 	data.blocksize = 64;
933272cc70bSAndy Fleming 	data.blocks = 1;
934272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
935272cc70bSAndy Fleming 
936272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
937272cc70bSAndy Fleming }
938272cc70bSAndy Fleming 
939272cc70bSAndy Fleming 
940*d0c221feSJean-Jacques Hiblot static int sd_get_capabilities(struct mmc *mmc)
941272cc70bSAndy Fleming {
942272cc70bSAndy Fleming 	int err;
943272cc70bSAndy Fleming 	struct mmc_cmd cmd;
94418e7c8f6SSuniel Mahesh 	ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2);
94518e7c8f6SSuniel Mahesh 	ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16);
946272cc70bSAndy Fleming 	struct mmc_data data;
947272cc70bSAndy Fleming 	int timeout;
948272cc70bSAndy Fleming 
949*d0c221feSJean-Jacques Hiblot 	mmc->card_caps = MMC_MODE_1BIT;
950272cc70bSAndy Fleming 
951d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
952d52ebf10SThomas Chou 		return 0;
953d52ebf10SThomas Chou 
954272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
955272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
956272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
957272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
958272cc70bSAndy Fleming 
959272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
960272cc70bSAndy Fleming 
961272cc70bSAndy Fleming 	if (err)
962272cc70bSAndy Fleming 		return err;
963272cc70bSAndy Fleming 
964272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
965272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
966272cc70bSAndy Fleming 	cmd.cmdarg = 0;
967272cc70bSAndy Fleming 
968272cc70bSAndy Fleming 	timeout = 3;
969272cc70bSAndy Fleming 
970272cc70bSAndy Fleming retry_scr:
971f781dd38SAnton staaf 	data.dest = (char *)scr;
972272cc70bSAndy Fleming 	data.blocksize = 8;
973272cc70bSAndy Fleming 	data.blocks = 1;
974272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
975272cc70bSAndy Fleming 
976272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
977272cc70bSAndy Fleming 
978272cc70bSAndy Fleming 	if (err) {
979272cc70bSAndy Fleming 		if (timeout--)
980272cc70bSAndy Fleming 			goto retry_scr;
981272cc70bSAndy Fleming 
982272cc70bSAndy Fleming 		return err;
983272cc70bSAndy Fleming 	}
984272cc70bSAndy Fleming 
9854e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
9864e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
987272cc70bSAndy Fleming 
988272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
989272cc70bSAndy Fleming 	case 0:
990272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
991272cc70bSAndy Fleming 		break;
992272cc70bSAndy Fleming 	case 1:
993272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_10;
994272cc70bSAndy Fleming 		break;
995272cc70bSAndy Fleming 	case 2:
996272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
9971741c64dSJaehoon Chung 		if ((mmc->scr[0] >> 15) & 0x1)
9981741c64dSJaehoon Chung 			mmc->version = SD_VERSION_3;
999272cc70bSAndy Fleming 		break;
1000272cc70bSAndy Fleming 	default:
1001272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1002272cc70bSAndy Fleming 		break;
1003272cc70bSAndy Fleming 	}
1004272cc70bSAndy Fleming 
1005b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
1006b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
1007b44c7083SAlagu Sankar 
1008272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
1009272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
1010272cc70bSAndy Fleming 		return 0;
1011272cc70bSAndy Fleming 
1012272cc70bSAndy Fleming 	timeout = 4;
1013272cc70bSAndy Fleming 	while (timeout--) {
1014272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
1015f781dd38SAnton staaf 				(u8 *)switch_status);
1016272cc70bSAndy Fleming 
1017272cc70bSAndy Fleming 		if (err)
1018272cc70bSAndy Fleming 			return err;
1019272cc70bSAndy Fleming 
1020272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
10214e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
1022272cc70bSAndy Fleming 			break;
1023272cc70bSAndy Fleming 	}
1024272cc70bSAndy Fleming 
1025272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
1026*d0c221feSJean-Jacques Hiblot 	if (__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)
1027*d0c221feSJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(SD_HS);
1028272cc70bSAndy Fleming 
10292c3fbf4cSMacpaul Lin 	return 0;
1030*d0c221feSJean-Jacques Hiblot }
1031*d0c221feSJean-Jacques Hiblot 
1032*d0c221feSJean-Jacques Hiblot static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode)
1033*d0c221feSJean-Jacques Hiblot {
1034*d0c221feSJean-Jacques Hiblot 	int err;
1035*d0c221feSJean-Jacques Hiblot 
1036*d0c221feSJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
10372c3fbf4cSMacpaul Lin 
1038f781dd38SAnton staaf 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status);
1039272cc70bSAndy Fleming 	if (err)
1040272cc70bSAndy Fleming 		return err;
1041272cc70bSAndy Fleming 
1042*d0c221feSJean-Jacques Hiblot 	if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) != 0x01000000)
1043*d0c221feSJean-Jacques Hiblot 		return -ENOTSUPP;
1044*d0c221feSJean-Jacques Hiblot 
1045*d0c221feSJean-Jacques Hiblot 	return 0;
1046*d0c221feSJean-Jacques Hiblot }
1047*d0c221feSJean-Jacques Hiblot 
1048*d0c221feSJean-Jacques Hiblot int sd_select_bus_width(struct mmc *mmc, int w)
1049*d0c221feSJean-Jacques Hiblot {
1050*d0c221feSJean-Jacques Hiblot 	int err;
1051*d0c221feSJean-Jacques Hiblot 	struct mmc_cmd cmd;
1052*d0c221feSJean-Jacques Hiblot 
1053*d0c221feSJean-Jacques Hiblot 	if ((w != 4) && (w != 1))
1054*d0c221feSJean-Jacques Hiblot 		return -EINVAL;
1055*d0c221feSJean-Jacques Hiblot 
1056*d0c221feSJean-Jacques Hiblot 	cmd.cmdidx = MMC_CMD_APP_CMD;
1057*d0c221feSJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
1058*d0c221feSJean-Jacques Hiblot 	cmd.cmdarg = mmc->rca << 16;
1059*d0c221feSJean-Jacques Hiblot 
1060*d0c221feSJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
1061*d0c221feSJean-Jacques Hiblot 	if (err)
1062*d0c221feSJean-Jacques Hiblot 		return err;
1063*d0c221feSJean-Jacques Hiblot 
1064*d0c221feSJean-Jacques Hiblot 	cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
1065*d0c221feSJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
1066*d0c221feSJean-Jacques Hiblot 	if (w == 4)
1067*d0c221feSJean-Jacques Hiblot 		cmd.cmdarg = 2;
1068*d0c221feSJean-Jacques Hiblot 	else if (w == 1)
1069*d0c221feSJean-Jacques Hiblot 		cmd.cmdarg = 0;
1070*d0c221feSJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
1071*d0c221feSJean-Jacques Hiblot 	if (err)
1072*d0c221feSJean-Jacques Hiblot 		return err;
1073272cc70bSAndy Fleming 
1074272cc70bSAndy Fleming 	return 0;
1075272cc70bSAndy Fleming }
1076272cc70bSAndy Fleming 
10773697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc)
10783697e599SPeng Fan {
10793697e599SPeng Fan 	int err, i;
10803697e599SPeng Fan 	struct mmc_cmd cmd;
10813697e599SPeng Fan 	ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16);
10823697e599SPeng Fan 	struct mmc_data data;
10833697e599SPeng Fan 	int timeout = 3;
10843697e599SPeng Fan 	unsigned int au, eo, et, es;
10853697e599SPeng Fan 
10863697e599SPeng Fan 	cmd.cmdidx = MMC_CMD_APP_CMD;
10873697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
10883697e599SPeng Fan 	cmd.cmdarg = mmc->rca << 16;
10893697e599SPeng Fan 
10903697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, NULL);
10913697e599SPeng Fan 	if (err)
10923697e599SPeng Fan 		return err;
10933697e599SPeng Fan 
10943697e599SPeng Fan 	cmd.cmdidx = SD_CMD_APP_SD_STATUS;
10953697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
10963697e599SPeng Fan 	cmd.cmdarg = 0;
10973697e599SPeng Fan 
10983697e599SPeng Fan retry_ssr:
10993697e599SPeng Fan 	data.dest = (char *)ssr;
11003697e599SPeng Fan 	data.blocksize = 64;
11013697e599SPeng Fan 	data.blocks = 1;
11023697e599SPeng Fan 	data.flags = MMC_DATA_READ;
11033697e599SPeng Fan 
11043697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, &data);
11053697e599SPeng Fan 	if (err) {
11063697e599SPeng Fan 		if (timeout--)
11073697e599SPeng Fan 			goto retry_ssr;
11083697e599SPeng Fan 
11093697e599SPeng Fan 		return err;
11103697e599SPeng Fan 	}
11113697e599SPeng Fan 
11123697e599SPeng Fan 	for (i = 0; i < 16; i++)
11133697e599SPeng Fan 		ssr[i] = be32_to_cpu(ssr[i]);
11143697e599SPeng Fan 
11153697e599SPeng Fan 	au = (ssr[2] >> 12) & 0xF;
11163697e599SPeng Fan 	if ((au <= 9) || (mmc->version == SD_VERSION_3)) {
11173697e599SPeng Fan 		mmc->ssr.au = sd_au_size[au];
11183697e599SPeng Fan 		es = (ssr[3] >> 24) & 0xFF;
11193697e599SPeng Fan 		es |= (ssr[2] & 0xFF) << 8;
11203697e599SPeng Fan 		et = (ssr[3] >> 18) & 0x3F;
11213697e599SPeng Fan 		if (es && et) {
11223697e599SPeng Fan 			eo = (ssr[3] >> 16) & 0x3;
11233697e599SPeng Fan 			mmc->ssr.erase_timeout = (et * 1000) / es;
11243697e599SPeng Fan 			mmc->ssr.erase_offset = eo * 1000;
11253697e599SPeng Fan 		}
11263697e599SPeng Fan 	} else {
11273697e599SPeng Fan 		debug("Invalid Allocation Unit Size.\n");
11283697e599SPeng Fan 	}
11293697e599SPeng Fan 
11303697e599SPeng Fan 	return 0;
11313697e599SPeng Fan }
11323697e599SPeng Fan 
1133272cc70bSAndy Fleming /* frequency bases */
1134272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
11355f837c2cSMike Frysinger static const int fbase[] = {
1136272cc70bSAndy Fleming 	10000,
1137272cc70bSAndy Fleming 	100000,
1138272cc70bSAndy Fleming 	1000000,
1139272cc70bSAndy Fleming 	10000000,
1140272cc70bSAndy Fleming };
1141272cc70bSAndy Fleming 
1142272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
1143272cc70bSAndy Fleming  * to platforms without floating point.
1144272cc70bSAndy Fleming  */
114561fe076fSSimon Glass static const u8 multipliers[] = {
1146272cc70bSAndy Fleming 	0,	/* reserved */
1147272cc70bSAndy Fleming 	10,
1148272cc70bSAndy Fleming 	12,
1149272cc70bSAndy Fleming 	13,
1150272cc70bSAndy Fleming 	15,
1151272cc70bSAndy Fleming 	20,
1152272cc70bSAndy Fleming 	25,
1153272cc70bSAndy Fleming 	30,
1154272cc70bSAndy Fleming 	35,
1155272cc70bSAndy Fleming 	40,
1156272cc70bSAndy Fleming 	45,
1157272cc70bSAndy Fleming 	50,
1158272cc70bSAndy Fleming 	55,
1159272cc70bSAndy Fleming 	60,
1160272cc70bSAndy Fleming 	70,
1161272cc70bSAndy Fleming 	80,
1162272cc70bSAndy Fleming };
1163272cc70bSAndy Fleming 
1164*d0c221feSJean-Jacques Hiblot static inline int bus_width(uint cap)
1165*d0c221feSJean-Jacques Hiblot {
1166*d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_8BIT)
1167*d0c221feSJean-Jacques Hiblot 		return 8;
1168*d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_4BIT)
1169*d0c221feSJean-Jacques Hiblot 		return 4;
1170*d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_1BIT)
1171*d0c221feSJean-Jacques Hiblot 		return 1;
1172*d0c221feSJean-Jacques Hiblot 	printf("invalid bus witdh capability 0x%x\n", cap);
1173*d0c221feSJean-Jacques Hiblot 	return 0;
1174*d0c221feSJean-Jacques Hiblot }
1175*d0c221feSJean-Jacques Hiblot 
1176e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
1177fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc)
1178272cc70bSAndy Fleming {
117993bfd616SPantelis Antoniou 	if (mmc->cfg->ops->set_ios)
118093bfd616SPantelis Antoniou 		mmc->cfg->ops->set_ios(mmc);
1181272cc70bSAndy Fleming }
11828ca51e51SSimon Glass #endif
1183272cc70bSAndy Fleming 
1184272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock)
1185272cc70bSAndy Fleming {
118693bfd616SPantelis Antoniou 	if (clock > mmc->cfg->f_max)
118793bfd616SPantelis Antoniou 		clock = mmc->cfg->f_max;
1188272cc70bSAndy Fleming 
118993bfd616SPantelis Antoniou 	if (clock < mmc->cfg->f_min)
119093bfd616SPantelis Antoniou 		clock = mmc->cfg->f_min;
1191272cc70bSAndy Fleming 
1192272cc70bSAndy Fleming 	mmc->clock = clock;
1193272cc70bSAndy Fleming 
1194272cc70bSAndy Fleming 	mmc_set_ios(mmc);
1195272cc70bSAndy Fleming }
1196272cc70bSAndy Fleming 
1197fdbb873eSKim Phillips static void mmc_set_bus_width(struct mmc *mmc, uint width)
1198272cc70bSAndy Fleming {
1199272cc70bSAndy Fleming 	mmc->bus_width = width;
1200272cc70bSAndy Fleming 
1201272cc70bSAndy Fleming 	mmc_set_ios(mmc);
1202272cc70bSAndy Fleming }
1203272cc70bSAndy Fleming 
12044c9d2aaaSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG)
12054c9d2aaaSJean-Jacques Hiblot /*
12064c9d2aaaSJean-Jacques Hiblot  * helper function to display the capabilities in a human
12074c9d2aaaSJean-Jacques Hiblot  * friendly manner. The capabilities include bus width and
12084c9d2aaaSJean-Jacques Hiblot  * supported modes.
12094c9d2aaaSJean-Jacques Hiblot  */
12104c9d2aaaSJean-Jacques Hiblot void mmc_dump_capabilities(const char *text, uint caps)
12114c9d2aaaSJean-Jacques Hiblot {
12124c9d2aaaSJean-Jacques Hiblot 	enum bus_mode mode;
12134c9d2aaaSJean-Jacques Hiblot 
12144c9d2aaaSJean-Jacques Hiblot 	printf("%s: widths [", text);
12154c9d2aaaSJean-Jacques Hiblot 	if (caps & MMC_MODE_8BIT)
12164c9d2aaaSJean-Jacques Hiblot 		printf("8, ");
12174c9d2aaaSJean-Jacques Hiblot 	if (caps & MMC_MODE_4BIT)
12184c9d2aaaSJean-Jacques Hiblot 		printf("4, ");
1219*d0c221feSJean-Jacques Hiblot 	if (caps & MMC_MODE_1BIT)
1220*d0c221feSJean-Jacques Hiblot 		printf("1, ");
1221*d0c221feSJean-Jacques Hiblot 	printf("\b\b] modes [");
12224c9d2aaaSJean-Jacques Hiblot 	for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++)
12234c9d2aaaSJean-Jacques Hiblot 		if (MMC_CAP(mode) & caps)
12244c9d2aaaSJean-Jacques Hiblot 			printf("%s, ", mmc_mode_name(mode));
12254c9d2aaaSJean-Jacques Hiblot 	printf("\b\b]\n");
12264c9d2aaaSJean-Jacques Hiblot }
12274c9d2aaaSJean-Jacques Hiblot #endif
12284c9d2aaaSJean-Jacques Hiblot 
1229*d0c221feSJean-Jacques Hiblot struct mode_width_tuning {
1230*d0c221feSJean-Jacques Hiblot 	enum bus_mode mode;
1231*d0c221feSJean-Jacques Hiblot 	uint widths;
1232*d0c221feSJean-Jacques Hiblot };
1233*d0c221feSJean-Jacques Hiblot 
1234*d0c221feSJean-Jacques Hiblot static const struct mode_width_tuning sd_modes_by_pref[] = {
1235*d0c221feSJean-Jacques Hiblot 	{
1236*d0c221feSJean-Jacques Hiblot 		.mode = SD_HS,
1237*d0c221feSJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1238*d0c221feSJean-Jacques Hiblot 	},
1239*d0c221feSJean-Jacques Hiblot 	{
1240*d0c221feSJean-Jacques Hiblot 		.mode = SD_LEGACY,
1241*d0c221feSJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1242*d0c221feSJean-Jacques Hiblot 	}
1243*d0c221feSJean-Jacques Hiblot };
1244*d0c221feSJean-Jacques Hiblot 
1245*d0c221feSJean-Jacques Hiblot #define for_each_sd_mode_by_pref(caps, mwt) \
1246*d0c221feSJean-Jacques Hiblot 	for (mwt = sd_modes_by_pref;\
1247*d0c221feSJean-Jacques Hiblot 	     mwt < sd_modes_by_pref + ARRAY_SIZE(sd_modes_by_pref);\
1248*d0c221feSJean-Jacques Hiblot 	     mwt++) \
1249*d0c221feSJean-Jacques Hiblot 		if (caps & MMC_CAP(mwt->mode))
1250*d0c221feSJean-Jacques Hiblot 
1251*d0c221feSJean-Jacques Hiblot static int sd_select_mode_and_width(struct mmc *mmc)
12528ac8a263SJean-Jacques Hiblot {
12538ac8a263SJean-Jacques Hiblot 	int err;
1254*d0c221feSJean-Jacques Hiblot 	uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT};
1255*d0c221feSJean-Jacques Hiblot 	const struct mode_width_tuning *mwt;
12568ac8a263SJean-Jacques Hiblot 
1257*d0c221feSJean-Jacques Hiblot 	err = sd_get_capabilities(mmc);
12588ac8a263SJean-Jacques Hiblot 	if (err)
12598ac8a263SJean-Jacques Hiblot 		return err;
12608ac8a263SJean-Jacques Hiblot 	/* Restrict card's capabilities by what the host can do */
1261*d0c221feSJean-Jacques Hiblot 	mmc->card_caps &= (mmc->cfg->host_caps | MMC_MODE_1BIT);
12628ac8a263SJean-Jacques Hiblot 
1263*d0c221feSJean-Jacques Hiblot 	for_each_sd_mode_by_pref(mmc->card_caps, mwt) {
1264*d0c221feSJean-Jacques Hiblot 		uint *w;
12658ac8a263SJean-Jacques Hiblot 
1266*d0c221feSJean-Jacques Hiblot 		for (w = widths; w < widths + ARRAY_SIZE(widths); w++) {
1267*d0c221feSJean-Jacques Hiblot 			if (*w & mmc->card_caps & mwt->widths) {
1268*d0c221feSJean-Jacques Hiblot 				debug("trying mode %s width %d (at %d MHz)\n",
1269*d0c221feSJean-Jacques Hiblot 				      mmc_mode_name(mwt->mode),
1270*d0c221feSJean-Jacques Hiblot 				      bus_width(*w),
1271*d0c221feSJean-Jacques Hiblot 				      mmc_mode2freq(mmc, mwt->mode) / 1000000);
1272*d0c221feSJean-Jacques Hiblot 
1273*d0c221feSJean-Jacques Hiblot 				/* configure the bus width (card + host) */
1274*d0c221feSJean-Jacques Hiblot 				err = sd_select_bus_width(mmc, bus_width(*w));
12758ac8a263SJean-Jacques Hiblot 				if (err)
1276*d0c221feSJean-Jacques Hiblot 					goto error;
1277*d0c221feSJean-Jacques Hiblot 				mmc_set_bus_width(mmc, bus_width(*w));
12788ac8a263SJean-Jacques Hiblot 
1279*d0c221feSJean-Jacques Hiblot 				/* configure the bus mode (card) */
1280*d0c221feSJean-Jacques Hiblot 				err = sd_set_card_speed(mmc, mwt->mode);
12818ac8a263SJean-Jacques Hiblot 				if (err)
1282*d0c221feSJean-Jacques Hiblot 					goto error;
12838ac8a263SJean-Jacques Hiblot 
1284*d0c221feSJean-Jacques Hiblot 				/* configure the bus mode (host) */
1285*d0c221feSJean-Jacques Hiblot 				mmc_select_mode(mmc, mwt->mode);
1286*d0c221feSJean-Jacques Hiblot 				mmc_set_clock(mmc, mmc->tran_speed);
12878ac8a263SJean-Jacques Hiblot 
12888ac8a263SJean-Jacques Hiblot 				err = sd_read_ssr(mmc);
1289*d0c221feSJean-Jacques Hiblot 				if (!err)
12908ac8a263SJean-Jacques Hiblot 					return 0;
1291*d0c221feSJean-Jacques Hiblot 
1292*d0c221feSJean-Jacques Hiblot 				printf("bad ssr\n");
1293*d0c221feSJean-Jacques Hiblot 
1294*d0c221feSJean-Jacques Hiblot error:
1295*d0c221feSJean-Jacques Hiblot 				/* revert to a safer bus speed */
1296*d0c221feSJean-Jacques Hiblot 				mmc_select_mode(mmc, SD_LEGACY);
1297*d0c221feSJean-Jacques Hiblot 				mmc_set_clock(mmc, mmc->tran_speed);
1298*d0c221feSJean-Jacques Hiblot 			}
1299*d0c221feSJean-Jacques Hiblot 		}
1300*d0c221feSJean-Jacques Hiblot 	}
1301*d0c221feSJean-Jacques Hiblot 
1302*d0c221feSJean-Jacques Hiblot 	printf("unable to select a mode\n");
1303*d0c221feSJean-Jacques Hiblot 	return -ENOTSUPP;
13048ac8a263SJean-Jacques Hiblot }
13058ac8a263SJean-Jacques Hiblot 
13067382e691SJean-Jacques Hiblot /*
13077382e691SJean-Jacques Hiblot  * read the compare the part of ext csd that is constant.
13087382e691SJean-Jacques Hiblot  * This can be used to check that the transfer is working
13097382e691SJean-Jacques Hiblot  * as expected.
13107382e691SJean-Jacques Hiblot  */
13117382e691SJean-Jacques Hiblot static int mmc_read_and_compare_ext_csd(struct mmc *mmc)
13127382e691SJean-Jacques Hiblot {
13137382e691SJean-Jacques Hiblot 	int err;
13147382e691SJean-Jacques Hiblot 	const u8 *ext_csd = mmc->ext_csd;
13157382e691SJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
13167382e691SJean-Jacques Hiblot 
13177382e691SJean-Jacques Hiblot 	err = mmc_send_ext_csd(mmc, test_csd);
13187382e691SJean-Jacques Hiblot 	if (err)
13197382e691SJean-Jacques Hiblot 		return err;
13207382e691SJean-Jacques Hiblot 
13217382e691SJean-Jacques Hiblot 	/* Only compare read only fields */
13227382e691SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT]
13237382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_PARTITIONING_SUPPORT] &&
13247382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_HC_WP_GRP_SIZE]
13257382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_HC_WP_GRP_SIZE] &&
13267382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_REV]
13277382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_REV] &&
13287382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
13297382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] &&
13307382e691SJean-Jacques Hiblot 	    memcmp(&ext_csd[EXT_CSD_SEC_CNT],
13317382e691SJean-Jacques Hiblot 		   &test_csd[EXT_CSD_SEC_CNT], 4) == 0)
13327382e691SJean-Jacques Hiblot 		return 0;
13337382e691SJean-Jacques Hiblot 
13347382e691SJean-Jacques Hiblot 	return -EBADMSG;
13357382e691SJean-Jacques Hiblot }
13367382e691SJean-Jacques Hiblot 
1337dfda9d88SJean-Jacques Hiblot static int mmc_select_bus_freq_width(struct mmc *mmc)
13388ac8a263SJean-Jacques Hiblot {
13398ac8a263SJean-Jacques Hiblot 	/* An array of possible bus widths in order of preference */
13408ac8a263SJean-Jacques Hiblot 	static const unsigned int ext_csd_bits[] = {
13418ac8a263SJean-Jacques Hiblot 		EXT_CSD_DDR_BUS_WIDTH_8,
13428ac8a263SJean-Jacques Hiblot 		EXT_CSD_DDR_BUS_WIDTH_4,
13438ac8a263SJean-Jacques Hiblot 		EXT_CSD_BUS_WIDTH_8,
13448ac8a263SJean-Jacques Hiblot 		EXT_CSD_BUS_WIDTH_4,
13458ac8a263SJean-Jacques Hiblot 		EXT_CSD_BUS_WIDTH_1,
13468ac8a263SJean-Jacques Hiblot 	};
13478ac8a263SJean-Jacques Hiblot 	/* An array to map CSD bus widths to host cap bits */
13488ac8a263SJean-Jacques Hiblot 	static const unsigned int ext_to_hostcaps[] = {
13498ac8a263SJean-Jacques Hiblot 		[EXT_CSD_DDR_BUS_WIDTH_4] =
13508ac8a263SJean-Jacques Hiblot 			MMC_MODE_DDR_52MHz | MMC_MODE_4BIT,
13518ac8a263SJean-Jacques Hiblot 		[EXT_CSD_DDR_BUS_WIDTH_8] =
13528ac8a263SJean-Jacques Hiblot 			MMC_MODE_DDR_52MHz | MMC_MODE_8BIT,
13538ac8a263SJean-Jacques Hiblot 		[EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT,
13548ac8a263SJean-Jacques Hiblot 		[EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT,
13558ac8a263SJean-Jacques Hiblot 	};
13568ac8a263SJean-Jacques Hiblot 	/* An array to map chosen bus width to an integer */
13578ac8a263SJean-Jacques Hiblot 	static const unsigned int widths[] = {
13588ac8a263SJean-Jacques Hiblot 		8, 4, 8, 4, 1,
13598ac8a263SJean-Jacques Hiblot 	};
13608ac8a263SJean-Jacques Hiblot 	int err;
13618ac8a263SJean-Jacques Hiblot 	int idx;
13628ac8a263SJean-Jacques Hiblot 
13638ac8a263SJean-Jacques Hiblot 	err = mmc_change_freq(mmc);
13648ac8a263SJean-Jacques Hiblot 	if (err)
13658ac8a263SJean-Jacques Hiblot 		return err;
13668ac8a263SJean-Jacques Hiblot 
13678ac8a263SJean-Jacques Hiblot 	/* Restrict card's capabilities by what the host can do */
1368*d0c221feSJean-Jacques Hiblot 	mmc->card_caps &= (mmc->cfg->host_caps | MMC_MODE_1BIT);
13698ac8a263SJean-Jacques Hiblot 
13708ac8a263SJean-Jacques Hiblot 	/* Only version 4 of MMC supports wider bus widths */
13718ac8a263SJean-Jacques Hiblot 	if (mmc->version < MMC_VERSION_4)
13728ac8a263SJean-Jacques Hiblot 		return 0;
13738ac8a263SJean-Jacques Hiblot 
1374dfda9d88SJean-Jacques Hiblot 	if (!mmc->ext_csd) {
1375dfda9d88SJean-Jacques Hiblot 		debug("No ext_csd found!\n"); /* this should enver happen */
1376dfda9d88SJean-Jacques Hiblot 		return -ENOTSUPP;
1377dfda9d88SJean-Jacques Hiblot 	}
1378dfda9d88SJean-Jacques Hiblot 
13798ac8a263SJean-Jacques Hiblot 	for (idx = 0; idx < ARRAY_SIZE(ext_csd_bits); idx++) {
13808ac8a263SJean-Jacques Hiblot 		unsigned int extw = ext_csd_bits[idx];
13818ac8a263SJean-Jacques Hiblot 		unsigned int caps = ext_to_hostcaps[extw];
13828ac8a263SJean-Jacques Hiblot 		/*
13838ac8a263SJean-Jacques Hiblot 		 * If the bus width is still not changed,
13848ac8a263SJean-Jacques Hiblot 		 * don't try to set the default again.
13858ac8a263SJean-Jacques Hiblot 		 * Otherwise, recover from switch attempts
13868ac8a263SJean-Jacques Hiblot 		 * by switching to 1-bit bus width.
13878ac8a263SJean-Jacques Hiblot 		 */
13888ac8a263SJean-Jacques Hiblot 		if (extw == EXT_CSD_BUS_WIDTH_1 &&
13898ac8a263SJean-Jacques Hiblot 		    mmc->bus_width == 1) {
13908ac8a263SJean-Jacques Hiblot 			err = 0;
13918ac8a263SJean-Jacques Hiblot 			break;
13928ac8a263SJean-Jacques Hiblot 		}
13938ac8a263SJean-Jacques Hiblot 
13948ac8a263SJean-Jacques Hiblot 		/*
13958ac8a263SJean-Jacques Hiblot 		 * Check to make sure the card and controller support
13968ac8a263SJean-Jacques Hiblot 		 * these capabilities
13978ac8a263SJean-Jacques Hiblot 		 */
13988ac8a263SJean-Jacques Hiblot 		if ((mmc->card_caps & caps) != caps)
13998ac8a263SJean-Jacques Hiblot 			continue;
14008ac8a263SJean-Jacques Hiblot 
14018ac8a263SJean-Jacques Hiblot 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
14028ac8a263SJean-Jacques Hiblot 				 EXT_CSD_BUS_WIDTH, extw);
14038ac8a263SJean-Jacques Hiblot 
14048ac8a263SJean-Jacques Hiblot 		if (err)
14058ac8a263SJean-Jacques Hiblot 			continue;
14068ac8a263SJean-Jacques Hiblot 
14078ac8a263SJean-Jacques Hiblot 		mmc->ddr_mode = (caps & MMC_MODE_DDR_52MHz) ? 1 : 0;
14088ac8a263SJean-Jacques Hiblot 		mmc_set_bus_width(mmc, widths[idx]);
14098ac8a263SJean-Jacques Hiblot 
14107382e691SJean-Jacques Hiblot 		err = mmc_read_and_compare_ext_csd(mmc);
14117382e691SJean-Jacques Hiblot 		if (!err)
14128ac8a263SJean-Jacques Hiblot 			break;
14138ac8a263SJean-Jacques Hiblot 	}
14148ac8a263SJean-Jacques Hiblot 
14158ac8a263SJean-Jacques Hiblot 	if (err)
14168ac8a263SJean-Jacques Hiblot 		return err;
14178ac8a263SJean-Jacques Hiblot 
141835f9e196SJean-Jacques Hiblot 	if (mmc->card_caps & MMC_MODE_HS_52MHz) {
141935f9e196SJean-Jacques Hiblot 		if (mmc->ddr_mode)
142035f9e196SJean-Jacques Hiblot 			mmc_select_mode(mmc, MMC_DDR_52);
14218ac8a263SJean-Jacques Hiblot 		else
142235f9e196SJean-Jacques Hiblot 			mmc_select_mode(mmc, MMC_HS_52);
142305038576SJean-Jacques Hiblot 	} else if (mmc->card_caps & MMC_MODE_HS)
142435f9e196SJean-Jacques Hiblot 		mmc_select_mode(mmc, MMC_HS);
14258ac8a263SJean-Jacques Hiblot 
14268ac8a263SJean-Jacques Hiblot 	return err;
14278ac8a263SJean-Jacques Hiblot }
14288ac8a263SJean-Jacques Hiblot 
1429dfda9d88SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc)
1430c744b6f6SJean-Jacques Hiblot {
1431c744b6f6SJean-Jacques Hiblot 	int err, i;
1432c744b6f6SJean-Jacques Hiblot 	u64 capacity;
1433c744b6f6SJean-Jacques Hiblot 	bool has_parts = false;
1434c744b6f6SJean-Jacques Hiblot 	bool part_completed;
1435dfda9d88SJean-Jacques Hiblot 	u8 *ext_csd;
1436c744b6f6SJean-Jacques Hiblot 
1437c744b6f6SJean-Jacques Hiblot 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4))
1438c744b6f6SJean-Jacques Hiblot 		return 0;
1439c744b6f6SJean-Jacques Hiblot 
1440dfda9d88SJean-Jacques Hiblot 	ext_csd = malloc_cache_aligned(MMC_MAX_BLOCK_LEN);
1441dfda9d88SJean-Jacques Hiblot 	if (!ext_csd)
1442dfda9d88SJean-Jacques Hiblot 		return -ENOMEM;
1443dfda9d88SJean-Jacques Hiblot 
1444dfda9d88SJean-Jacques Hiblot 	mmc->ext_csd = ext_csd;
1445dfda9d88SJean-Jacques Hiblot 
1446c744b6f6SJean-Jacques Hiblot 	/* check  ext_csd version and capacity */
1447c744b6f6SJean-Jacques Hiblot 	err = mmc_send_ext_csd(mmc, ext_csd);
1448c744b6f6SJean-Jacques Hiblot 	if (err)
1449c744b6f6SJean-Jacques Hiblot 		return err;
1450c744b6f6SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_REV] >= 2) {
1451c744b6f6SJean-Jacques Hiblot 		/*
1452c744b6f6SJean-Jacques Hiblot 		 * According to the JEDEC Standard, the value of
1453c744b6f6SJean-Jacques Hiblot 		 * ext_csd's capacity is valid if the value is more
1454c744b6f6SJean-Jacques Hiblot 		 * than 2GB
1455c744b6f6SJean-Jacques Hiblot 		 */
1456c744b6f6SJean-Jacques Hiblot 		capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
1457c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
1458c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
1459c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
1460c744b6f6SJean-Jacques Hiblot 		capacity *= MMC_MAX_BLOCK_LEN;
1461c744b6f6SJean-Jacques Hiblot 		if ((capacity >> 20) > 2 * 1024)
1462c744b6f6SJean-Jacques Hiblot 			mmc->capacity_user = capacity;
1463c744b6f6SJean-Jacques Hiblot 	}
1464c744b6f6SJean-Jacques Hiblot 
1465c744b6f6SJean-Jacques Hiblot 	switch (ext_csd[EXT_CSD_REV]) {
1466c744b6f6SJean-Jacques Hiblot 	case 1:
1467c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_1;
1468c744b6f6SJean-Jacques Hiblot 		break;
1469c744b6f6SJean-Jacques Hiblot 	case 2:
1470c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_2;
1471c744b6f6SJean-Jacques Hiblot 		break;
1472c744b6f6SJean-Jacques Hiblot 	case 3:
1473c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_3;
1474c744b6f6SJean-Jacques Hiblot 		break;
1475c744b6f6SJean-Jacques Hiblot 	case 5:
1476c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_41;
1477c744b6f6SJean-Jacques Hiblot 		break;
1478c744b6f6SJean-Jacques Hiblot 	case 6:
1479c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_5;
1480c744b6f6SJean-Jacques Hiblot 		break;
1481c744b6f6SJean-Jacques Hiblot 	case 7:
1482c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_5_0;
1483c744b6f6SJean-Jacques Hiblot 		break;
1484c744b6f6SJean-Jacques Hiblot 	case 8:
1485c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_5_1;
1486c744b6f6SJean-Jacques Hiblot 		break;
1487c744b6f6SJean-Jacques Hiblot 	}
1488c744b6f6SJean-Jacques Hiblot 
1489c744b6f6SJean-Jacques Hiblot 	/* The partition data may be non-zero but it is only
1490c744b6f6SJean-Jacques Hiblot 	 * effective if PARTITION_SETTING_COMPLETED is set in
1491c744b6f6SJean-Jacques Hiblot 	 * EXT_CSD, so ignore any data if this bit is not set,
1492c744b6f6SJean-Jacques Hiblot 	 * except for enabling the high-capacity group size
1493c744b6f6SJean-Jacques Hiblot 	 * definition (see below).
1494c744b6f6SJean-Jacques Hiblot 	 */
1495c744b6f6SJean-Jacques Hiblot 	part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
1496c744b6f6SJean-Jacques Hiblot 			    EXT_CSD_PARTITION_SETTING_COMPLETED);
1497c744b6f6SJean-Jacques Hiblot 
1498c744b6f6SJean-Jacques Hiblot 	/* store the partition info of emmc */
1499c744b6f6SJean-Jacques Hiblot 	mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
1500c744b6f6SJean-Jacques Hiblot 	if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
1501c744b6f6SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_BOOT_MULT])
1502c744b6f6SJean-Jacques Hiblot 		mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
1503c744b6f6SJean-Jacques Hiblot 	if (part_completed &&
1504c744b6f6SJean-Jacques Hiblot 	    (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
1505c744b6f6SJean-Jacques Hiblot 		mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
1506c744b6f6SJean-Jacques Hiblot 
1507c744b6f6SJean-Jacques Hiblot 	mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
1508c744b6f6SJean-Jacques Hiblot 
1509c744b6f6SJean-Jacques Hiblot 	mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
1510c744b6f6SJean-Jacques Hiblot 
1511c744b6f6SJean-Jacques Hiblot 	for (i = 0; i < 4; i++) {
1512c744b6f6SJean-Jacques Hiblot 		int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
1513c744b6f6SJean-Jacques Hiblot 		uint mult = (ext_csd[idx + 2] << 16) +
1514c744b6f6SJean-Jacques Hiblot 			(ext_csd[idx + 1] << 8) + ext_csd[idx];
1515c744b6f6SJean-Jacques Hiblot 		if (mult)
1516c744b6f6SJean-Jacques Hiblot 			has_parts = true;
1517c744b6f6SJean-Jacques Hiblot 		if (!part_completed)
1518c744b6f6SJean-Jacques Hiblot 			continue;
1519c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] = mult;
1520c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] *=
1521c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1522c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1523c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] <<= 19;
1524c744b6f6SJean-Jacques Hiblot 	}
1525c744b6f6SJean-Jacques Hiblot 
1526c744b6f6SJean-Jacques Hiblot 	if (part_completed) {
1527c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size =
1528c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) +
1529c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) +
1530c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_ENH_SIZE_MULT];
1531c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1532c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1533c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size <<= 19;
1534c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_start =
1535c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) +
1536c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) +
1537c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) +
1538c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_ENH_START_ADDR];
1539c744b6f6SJean-Jacques Hiblot 		if (mmc->high_capacity)
1540c744b6f6SJean-Jacques Hiblot 			mmc->enh_user_start <<= 9;
1541c744b6f6SJean-Jacques Hiblot 	}
1542c744b6f6SJean-Jacques Hiblot 
1543c744b6f6SJean-Jacques Hiblot 	/*
1544c744b6f6SJean-Jacques Hiblot 	 * Host needs to enable ERASE_GRP_DEF bit if device is
1545c744b6f6SJean-Jacques Hiblot 	 * partitioned. This bit will be lost every time after a reset
1546c744b6f6SJean-Jacques Hiblot 	 * or power off. This will affect erase size.
1547c744b6f6SJean-Jacques Hiblot 	 */
1548c744b6f6SJean-Jacques Hiblot 	if (part_completed)
1549c744b6f6SJean-Jacques Hiblot 		has_parts = true;
1550c744b6f6SJean-Jacques Hiblot 	if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
1551c744b6f6SJean-Jacques Hiblot 	    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
1552c744b6f6SJean-Jacques Hiblot 		has_parts = true;
1553c744b6f6SJean-Jacques Hiblot 	if (has_parts) {
1554c744b6f6SJean-Jacques Hiblot 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1555c744b6f6SJean-Jacques Hiblot 				 EXT_CSD_ERASE_GROUP_DEF, 1);
1556c744b6f6SJean-Jacques Hiblot 
1557c744b6f6SJean-Jacques Hiblot 		if (err)
1558c744b6f6SJean-Jacques Hiblot 			return err;
1559c744b6f6SJean-Jacques Hiblot 
1560c744b6f6SJean-Jacques Hiblot 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1561c744b6f6SJean-Jacques Hiblot 	}
1562c744b6f6SJean-Jacques Hiblot 
1563c744b6f6SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
1564c744b6f6SJean-Jacques Hiblot 		/* Read out group size from ext_csd */
1565c744b6f6SJean-Jacques Hiblot 		mmc->erase_grp_size =
1566c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1567c744b6f6SJean-Jacques Hiblot 		/*
1568c744b6f6SJean-Jacques Hiblot 		 * if high capacity and partition setting completed
1569c744b6f6SJean-Jacques Hiblot 		 * SEC_COUNT is valid even if it is smaller than 2 GiB
1570c744b6f6SJean-Jacques Hiblot 		 * JEDEC Standard JESD84-B45, 6.2.4
1571c744b6f6SJean-Jacques Hiblot 		 */
1572c744b6f6SJean-Jacques Hiblot 		if (mmc->high_capacity && part_completed) {
1573c744b6f6SJean-Jacques Hiblot 			capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
1574c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
1575c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
1576c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
1577c744b6f6SJean-Jacques Hiblot 			capacity *= MMC_MAX_BLOCK_LEN;
1578c744b6f6SJean-Jacques Hiblot 			mmc->capacity_user = capacity;
1579c744b6f6SJean-Jacques Hiblot 		}
1580c744b6f6SJean-Jacques Hiblot 	} else {
1581c744b6f6SJean-Jacques Hiblot 		/* Calculate the group size from the csd value. */
1582c744b6f6SJean-Jacques Hiblot 		int erase_gsz, erase_gmul;
1583c744b6f6SJean-Jacques Hiblot 
1584c744b6f6SJean-Jacques Hiblot 		erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
1585c744b6f6SJean-Jacques Hiblot 		erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
1586c744b6f6SJean-Jacques Hiblot 		mmc->erase_grp_size = (erase_gsz + 1)
1587c744b6f6SJean-Jacques Hiblot 			* (erase_gmul + 1);
1588c744b6f6SJean-Jacques Hiblot 	}
1589c744b6f6SJean-Jacques Hiblot 
1590c744b6f6SJean-Jacques Hiblot 	mmc->hc_wp_grp_size = 1024
1591c744b6f6SJean-Jacques Hiblot 		* ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
1592c744b6f6SJean-Jacques Hiblot 		* ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1593c744b6f6SJean-Jacques Hiblot 
1594c744b6f6SJean-Jacques Hiblot 	mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
1595c744b6f6SJean-Jacques Hiblot 
1596c744b6f6SJean-Jacques Hiblot 	return 0;
1597c744b6f6SJean-Jacques Hiblot }
1598c744b6f6SJean-Jacques Hiblot 
1599fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc)
1600272cc70bSAndy Fleming {
1601f866a46dSStephen Warren 	int err, i;
1602272cc70bSAndy Fleming 	uint mult, freq;
1603c744b6f6SJean-Jacques Hiblot 	u64 cmult, csize;
1604272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1605c40fdca6SSimon Glass 	struct blk_desc *bdesc;
1606272cc70bSAndy Fleming 
1607d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
1608d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
1609d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
1610d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
1611d52ebf10SThomas Chou 		cmd.cmdarg = 1;
1612d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
1613d52ebf10SThomas Chou 
1614d52ebf10SThomas Chou 		if (err)
1615d52ebf10SThomas Chou 			return err;
1616d52ebf10SThomas Chou 	}
1617d52ebf10SThomas Chou #endif
1618d52ebf10SThomas Chou 
1619272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
1620d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
1621d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
1622272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1623272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1624272cc70bSAndy Fleming 
1625272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1626272cc70bSAndy Fleming 
1627272cc70bSAndy Fleming 	if (err)
1628272cc70bSAndy Fleming 		return err;
1629272cc70bSAndy Fleming 
1630272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
1631272cc70bSAndy Fleming 
1632272cc70bSAndy Fleming 	/*
1633272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
1634272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
1635272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
1636272cc70bSAndy Fleming 	 */
1637d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1638272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
1639272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1640272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
1641272cc70bSAndy Fleming 
1642272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1643272cc70bSAndy Fleming 
1644272cc70bSAndy Fleming 		if (err)
1645272cc70bSAndy Fleming 			return err;
1646272cc70bSAndy Fleming 
1647272cc70bSAndy Fleming 		if (IS_SD(mmc))
1648998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
1649d52ebf10SThomas Chou 	}
1650272cc70bSAndy Fleming 
1651272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
1652272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
1653272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1654272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1655272cc70bSAndy Fleming 
1656272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1657272cc70bSAndy Fleming 
1658272cc70bSAndy Fleming 	if (err)
1659272cc70bSAndy Fleming 		return err;
1660272cc70bSAndy Fleming 
1661998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
1662998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
1663998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
1664998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
1665272cc70bSAndy Fleming 
1666272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
16670b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
1668272cc70bSAndy Fleming 
1669272cc70bSAndy Fleming 		switch (version) {
1670272cc70bSAndy Fleming 		case 0:
1671272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1672272cc70bSAndy Fleming 			break;
1673272cc70bSAndy Fleming 		case 1:
1674272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_4;
1675272cc70bSAndy Fleming 			break;
1676272cc70bSAndy Fleming 		case 2:
1677272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_2_2;
1678272cc70bSAndy Fleming 			break;
1679272cc70bSAndy Fleming 		case 3:
1680272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_3;
1681272cc70bSAndy Fleming 			break;
1682272cc70bSAndy Fleming 		case 4:
1683272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_4;
1684272cc70bSAndy Fleming 			break;
1685272cc70bSAndy Fleming 		default:
1686272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1687272cc70bSAndy Fleming 			break;
1688272cc70bSAndy Fleming 		}
1689272cc70bSAndy Fleming 	}
1690272cc70bSAndy Fleming 
1691272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
16920b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
16930b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
1694272cc70bSAndy Fleming 
169535f9e196SJean-Jacques Hiblot 	mmc->legacy_speed = freq * mult;
169635f9e196SJean-Jacques Hiblot 	mmc_select_mode(mmc, MMC_LEGACY);
1697272cc70bSAndy Fleming 
1698ab71188cSMarkus Niebel 	mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
1699998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
1700272cc70bSAndy Fleming 
1701272cc70bSAndy Fleming 	if (IS_SD(mmc))
1702272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
1703272cc70bSAndy Fleming 	else
1704998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
1705272cc70bSAndy Fleming 
1706272cc70bSAndy Fleming 	if (mmc->high_capacity) {
1707272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
1708272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
1709272cc70bSAndy Fleming 		cmult = 8;
1710272cc70bSAndy Fleming 	} else {
1711272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
1712272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
1713272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
1714272cc70bSAndy Fleming 	}
1715272cc70bSAndy Fleming 
1716f866a46dSStephen Warren 	mmc->capacity_user = (csize + 1) << (cmult + 2);
1717f866a46dSStephen Warren 	mmc->capacity_user *= mmc->read_bl_len;
1718f866a46dSStephen Warren 	mmc->capacity_boot = 0;
1719f866a46dSStephen Warren 	mmc->capacity_rpmb = 0;
1720f866a46dSStephen Warren 	for (i = 0; i < 4; i++)
1721f866a46dSStephen Warren 		mmc->capacity_gp[i] = 0;
1722272cc70bSAndy Fleming 
17238bfa195eSSimon Glass 	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
17248bfa195eSSimon Glass 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
1725272cc70bSAndy Fleming 
17268bfa195eSSimon Glass 	if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
17278bfa195eSSimon Glass 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
1728272cc70bSAndy Fleming 
1729ab71188cSMarkus Niebel 	if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
1730ab71188cSMarkus Niebel 		cmd.cmdidx = MMC_CMD_SET_DSR;
1731ab71188cSMarkus Niebel 		cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
1732ab71188cSMarkus Niebel 		cmd.resp_type = MMC_RSP_NONE;
1733ab71188cSMarkus Niebel 		if (mmc_send_cmd(mmc, &cmd, NULL))
1734ab71188cSMarkus Niebel 			printf("MMC: SET_DSR failed\n");
1735ab71188cSMarkus Niebel 	}
1736ab71188cSMarkus Niebel 
1737272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
1738d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1739272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
1740fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
1741272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1742272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1743272cc70bSAndy Fleming 
1744272cc70bSAndy Fleming 		if (err)
1745272cc70bSAndy Fleming 			return err;
1746d52ebf10SThomas Chou 	}
1747272cc70bSAndy Fleming 
1748e6f99a56SLei Wen 	/*
1749e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
1750e6f99a56SLei Wen 	 */
1751e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
1752bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
1753c744b6f6SJean-Jacques Hiblot 
1754dfda9d88SJean-Jacques Hiblot 	err = mmc_startup_v4(mmc);
17559cf199ebSDiego Santa Cruz 	if (err)
17569cf199ebSDiego Santa Cruz 		return err;
1757f866a46dSStephen Warren 
1758c40fdca6SSimon Glass 	err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart);
1759f866a46dSStephen Warren 	if (err)
1760f866a46dSStephen Warren 		return err;
1761d23e2c09SSukumar Ghorai 
1762272cc70bSAndy Fleming 	if (IS_SD(mmc))
1763*d0c221feSJean-Jacques Hiblot 		err = sd_select_mode_and_width(mmc);
1764272cc70bSAndy Fleming 	else
1765dfda9d88SJean-Jacques Hiblot 		err = mmc_select_bus_freq_width(mmc);
1766272cc70bSAndy Fleming 
1767272cc70bSAndy Fleming 	if (err)
1768272cc70bSAndy Fleming 		return err;
1769272cc70bSAndy Fleming 
1770272cc70bSAndy Fleming 
17715af8f45cSAndrew Gabbasov 	/* Fix the block length for DDR mode */
17725af8f45cSAndrew Gabbasov 	if (mmc->ddr_mode) {
17735af8f45cSAndrew Gabbasov 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
17745af8f45cSAndrew Gabbasov 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
17755af8f45cSAndrew Gabbasov 	}
17765af8f45cSAndrew Gabbasov 
1777272cc70bSAndy Fleming 	/* fill in device description */
1778c40fdca6SSimon Glass 	bdesc = mmc_get_blk_desc(mmc);
1779c40fdca6SSimon Glass 	bdesc->lun = 0;
1780c40fdca6SSimon Glass 	bdesc->hwpart = 0;
1781c40fdca6SSimon Glass 	bdesc->type = 0;
1782c40fdca6SSimon Glass 	bdesc->blksz = mmc->read_bl_len;
1783c40fdca6SSimon Glass 	bdesc->log2blksz = LOG2(bdesc->blksz);
1784c40fdca6SSimon Glass 	bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len);
1785fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \
1786fc011f64SSjoerd Simons 		(defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \
1787fc011f64SSjoerd Simons 		!defined(CONFIG_USE_TINY_PRINTF))
1788c40fdca6SSimon Glass 	sprintf(bdesc->vendor, "Man %06x Snr %04x%04x",
1789babce5f6STaylor Hutt 		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
1790babce5f6STaylor Hutt 		(mmc->cid[3] >> 16) & 0xffff);
1791c40fdca6SSimon Glass 	sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
17920b453ffeSRabin Vincent 		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
1793babce5f6STaylor Hutt 		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
1794babce5f6STaylor Hutt 		(mmc->cid[2] >> 24) & 0xff);
1795c40fdca6SSimon Glass 	sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
1796babce5f6STaylor Hutt 		(mmc->cid[2] >> 16) & 0xf);
179756196826SPaul Burton #else
1798c40fdca6SSimon Glass 	bdesc->vendor[0] = 0;
1799c40fdca6SSimon Glass 	bdesc->product[0] = 0;
1800c40fdca6SSimon Glass 	bdesc->revision[0] = 0;
180156196826SPaul Burton #endif
1802122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
1803c40fdca6SSimon Glass 	part_init(bdesc);
1804122efd43SMikhail Kshevetskiy #endif
1805272cc70bSAndy Fleming 
1806272cc70bSAndy Fleming 	return 0;
1807272cc70bSAndy Fleming }
1808272cc70bSAndy Fleming 
1809fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc)
1810272cc70bSAndy Fleming {
1811272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1812272cc70bSAndy Fleming 	int err;
1813272cc70bSAndy Fleming 
1814272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
1815272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
181693bfd616SPantelis Antoniou 	cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa;
1817272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
1818272cc70bSAndy Fleming 
1819272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1820272cc70bSAndy Fleming 
1821272cc70bSAndy Fleming 	if (err)
1822272cc70bSAndy Fleming 		return err;
1823272cc70bSAndy Fleming 
1824998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
1825915ffa52SJaehoon Chung 		return -EOPNOTSUPP;
1826272cc70bSAndy Fleming 	else
1827272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
1828272cc70bSAndy Fleming 
1829272cc70bSAndy Fleming 	return 0;
1830272cc70bSAndy Fleming }
1831272cc70bSAndy Fleming 
1832c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
183395de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */
183495de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void)
183595de9ab2SPaul Kocialkowski {
183695de9ab2SPaul Kocialkowski }
183705cbeb7cSSimon Glass #endif
183895de9ab2SPaul Kocialkowski 
18392051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc)
18402051aefeSPeng Fan {
1841c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
184206ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR)
18432051aefeSPeng Fan 	int ret;
18442051aefeSPeng Fan 
18452051aefeSPeng Fan 	ret = device_get_supply_regulator(mmc->dev, "vmmc-supply",
184606ec045fSJean-Jacques Hiblot 					  &mmc->vmmc_supply);
184706ec045fSJean-Jacques Hiblot 	if (ret)
1848288db7c7SJaehoon Chung 		debug("%s: No vmmc supply\n", mmc->dev->name);
18492051aefeSPeng Fan 
185006ec045fSJean-Jacques Hiblot 	ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply",
185106ec045fSJean-Jacques Hiblot 					  &mmc->vqmmc_supply);
185206ec045fSJean-Jacques Hiblot 	if (ret)
185306ec045fSJean-Jacques Hiblot 		debug("%s: No vqmmc supply\n", mmc->dev->name);
185406ec045fSJean-Jacques Hiblot 
185506ec045fSJean-Jacques Hiblot 	if (mmc->vmmc_supply) {
185606ec045fSJean-Jacques Hiblot 		ret = regulator_set_enable(mmc->vmmc_supply, true);
18572051aefeSPeng Fan 		if (ret) {
18582051aefeSPeng Fan 			puts("Error enabling VMMC supply\n");
18592051aefeSPeng Fan 			return ret;
18602051aefeSPeng Fan 		}
186106ec045fSJean-Jacques Hiblot 	}
18622051aefeSPeng Fan #endif
186305cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */
186405cbeb7cSSimon Glass 	/*
186505cbeb7cSSimon Glass 	 * Driver model should use a regulator, as above, rather than calling
186605cbeb7cSSimon Glass 	 * out to board code.
186705cbeb7cSSimon Glass 	 */
186805cbeb7cSSimon Glass 	board_mmc_power_init();
186905cbeb7cSSimon Glass #endif
18702051aefeSPeng Fan 	return 0;
18712051aefeSPeng Fan }
18722051aefeSPeng Fan 
1873e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc)
1874272cc70bSAndy Fleming {
18758ca51e51SSimon Glass 	bool no_card;
1876afd5932bSMacpaul Lin 	int err;
1877272cc70bSAndy Fleming 
1878ab769f22SPantelis Antoniou 	/* we pretend there's no card when init is NULL */
18798ca51e51SSimon Glass 	no_card = mmc_getcd(mmc) == 0;
1880e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
18818ca51e51SSimon Glass 	no_card = no_card || (mmc->cfg->ops->init == NULL);
18828ca51e51SSimon Glass #endif
18838ca51e51SSimon Glass 	if (no_card) {
188448972d90SThierry Reding 		mmc->has_init = 0;
188556196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
188648972d90SThierry Reding 		printf("MMC: no card present\n");
188756196826SPaul Burton #endif
1888915ffa52SJaehoon Chung 		return -ENOMEDIUM;
188948972d90SThierry Reding 	}
189048972d90SThierry Reding 
1891bc897b1dSLei Wen 	if (mmc->has_init)
1892bc897b1dSLei Wen 		return 0;
1893bc897b1dSLei Wen 
18945a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
18955a8dbdc6SYangbo Lu 	mmc_adapter_card_type_ident();
18965a8dbdc6SYangbo Lu #endif
18972051aefeSPeng Fan 	err = mmc_power_init(mmc);
18982051aefeSPeng Fan 	if (err)
18992051aefeSPeng Fan 		return err;
190095de9ab2SPaul Kocialkowski 
1901e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
19028ca51e51SSimon Glass 	/* The device has already been probed ready for use */
19038ca51e51SSimon Glass #else
1904ab769f22SPantelis Antoniou 	/* made sure it's not NULL earlier */
190593bfd616SPantelis Antoniou 	err = mmc->cfg->ops->init(mmc);
1906272cc70bSAndy Fleming 	if (err)
1907272cc70bSAndy Fleming 		return err;
19088ca51e51SSimon Glass #endif
1909786e8f81SAndrew Gabbasov 	mmc->ddr_mode = 0;
1910b86b85e2SIlya Yanok 	mmc_set_bus_width(mmc, 1);
1911b86b85e2SIlya Yanok 	mmc_set_clock(mmc, 1);
1912b86b85e2SIlya Yanok 
1913272cc70bSAndy Fleming 	/* Reset the Card */
1914272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
1915272cc70bSAndy Fleming 
1916272cc70bSAndy Fleming 	if (err)
1917272cc70bSAndy Fleming 		return err;
1918272cc70bSAndy Fleming 
1919bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
1920c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->hwpart = 0;
1921bc897b1dSLei Wen 
1922272cc70bSAndy Fleming 	/* Test for SD version 2 */
1923272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
1924272cc70bSAndy Fleming 
1925272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
1926272cc70bSAndy Fleming 	err = sd_send_op_cond(mmc);
1927272cc70bSAndy Fleming 
1928272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
1929915ffa52SJaehoon Chung 	if (err == -ETIMEDOUT) {
1930272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
1931272cc70bSAndy Fleming 
1932bd47c135SAndrew Gabbasov 		if (err) {
193356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
1934272cc70bSAndy Fleming 			printf("Card did not respond to voltage select!\n");
193556196826SPaul Burton #endif
1936915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
1937272cc70bSAndy Fleming 		}
1938272cc70bSAndy Fleming 	}
1939272cc70bSAndy Fleming 
1940bd47c135SAndrew Gabbasov 	if (!err)
1941e9550449SChe-Liang Chiou 		mmc->init_in_progress = 1;
1942e9550449SChe-Liang Chiou 
1943e9550449SChe-Liang Chiou 	return err;
1944e9550449SChe-Liang Chiou }
1945e9550449SChe-Liang Chiou 
1946e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc)
1947e9550449SChe-Liang Chiou {
1948e9550449SChe-Liang Chiou 	int err = 0;
1949e9550449SChe-Liang Chiou 
1950bd47c135SAndrew Gabbasov 	mmc->init_in_progress = 0;
1951e9550449SChe-Liang Chiou 	if (mmc->op_cond_pending)
1952e9550449SChe-Liang Chiou 		err = mmc_complete_op_cond(mmc);
1953e9550449SChe-Liang Chiou 
1954e9550449SChe-Liang Chiou 	if (!err)
1955bc897b1dSLei Wen 		err = mmc_startup(mmc);
1956bc897b1dSLei Wen 	if (err)
1957bc897b1dSLei Wen 		mmc->has_init = 0;
1958bc897b1dSLei Wen 	else
1959bc897b1dSLei Wen 		mmc->has_init = 1;
1960e9550449SChe-Liang Chiou 	return err;
1961e9550449SChe-Liang Chiou }
1962e9550449SChe-Liang Chiou 
1963e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc)
1964e9550449SChe-Liang Chiou {
1965bd47c135SAndrew Gabbasov 	int err = 0;
1966ce9eca94SMarek Vasut 	__maybe_unused unsigned start;
1967c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
196833fb211dSSimon Glass 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev);
1969e9550449SChe-Liang Chiou 
197033fb211dSSimon Glass 	upriv->mmc = mmc;
197133fb211dSSimon Glass #endif
1972e9550449SChe-Liang Chiou 	if (mmc->has_init)
1973e9550449SChe-Liang Chiou 		return 0;
1974d803fea5SMateusz Zalega 
1975d803fea5SMateusz Zalega 	start = get_timer(0);
1976d803fea5SMateusz Zalega 
1977e9550449SChe-Liang Chiou 	if (!mmc->init_in_progress)
1978e9550449SChe-Liang Chiou 		err = mmc_start_init(mmc);
1979e9550449SChe-Liang Chiou 
1980bd47c135SAndrew Gabbasov 	if (!err)
1981e9550449SChe-Liang Chiou 		err = mmc_complete_init(mmc);
1982919b4858SJagan Teki 	if (err)
1983919b4858SJagan Teki 		printf("%s: %d, time %lu\n", __func__, err, get_timer(start));
1984919b4858SJagan Teki 
1985bc897b1dSLei Wen 	return err;
1986272cc70bSAndy Fleming }
1987272cc70bSAndy Fleming 
1988ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val)
1989ab71188cSMarkus Niebel {
1990ab71188cSMarkus Niebel 	mmc->dsr = val;
1991ab71188cSMarkus Niebel 	return 0;
1992ab71188cSMarkus Niebel }
1993ab71188cSMarkus Niebel 
1994cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */
1995cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis)
1996272cc70bSAndy Fleming {
1997272cc70bSAndy Fleming 	return -1;
1998272cc70bSAndy Fleming }
1999272cc70bSAndy Fleming 
2000cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */
2001cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis)
2002cee9ab7cSJeroen Hofstee {
2003cee9ab7cSJeroen Hofstee 	return -1;
2004cee9ab7cSJeroen Hofstee }
2005272cc70bSAndy Fleming 
2006e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit)
2007e9550449SChe-Liang Chiou {
2008e9550449SChe-Liang Chiou 	mmc->preinit = preinit;
2009e9550449SChe-Liang Chiou }
2010e9550449SChe-Liang Chiou 
2011c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD)
20128e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
20138e3332e2SSjoerd Simons {
20148e3332e2SSjoerd Simons 	return 0;
20158e3332e2SSjoerd Simons }
2016c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC)
20178e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
20188e3332e2SSjoerd Simons {
20194a1db6d8SSimon Glass 	int ret, i;
20208e3332e2SSjoerd Simons 	struct uclass *uc;
20214a1db6d8SSimon Glass 	struct udevice *dev;
20228e3332e2SSjoerd Simons 
20238e3332e2SSjoerd Simons 	ret = uclass_get(UCLASS_MMC, &uc);
20248e3332e2SSjoerd Simons 	if (ret)
20258e3332e2SSjoerd Simons 		return ret;
20268e3332e2SSjoerd Simons 
20274a1db6d8SSimon Glass 	/*
20284a1db6d8SSimon Glass 	 * Try to add them in sequence order. Really with driver model we
20294a1db6d8SSimon Glass 	 * should allow holes, but the current MMC list does not allow that.
20304a1db6d8SSimon Glass 	 * So if we request 0, 1, 3 we will get 0, 1, 2.
20314a1db6d8SSimon Glass 	 */
20324a1db6d8SSimon Glass 	for (i = 0; ; i++) {
20334a1db6d8SSimon Glass 		ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev);
20344a1db6d8SSimon Glass 		if (ret == -ENODEV)
20354a1db6d8SSimon Glass 			break;
20364a1db6d8SSimon Glass 	}
20374a1db6d8SSimon Glass 	uclass_foreach_dev(dev, uc) {
20384a1db6d8SSimon Glass 		ret = device_probe(dev);
20398e3332e2SSjoerd Simons 		if (ret)
20404a1db6d8SSimon Glass 			printf("%s - probe failed: %d\n", dev->name, ret);
20418e3332e2SSjoerd Simons 	}
20428e3332e2SSjoerd Simons 
20438e3332e2SSjoerd Simons 	return 0;
20448e3332e2SSjoerd Simons }
20458e3332e2SSjoerd Simons #else
20468e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
20478e3332e2SSjoerd Simons {
20488e3332e2SSjoerd Simons 	if (board_mmc_init(bis) < 0)
20498e3332e2SSjoerd Simons 		cpu_mmc_init(bis);
20508e3332e2SSjoerd Simons 
20518e3332e2SSjoerd Simons 	return 0;
20528e3332e2SSjoerd Simons }
20538e3332e2SSjoerd Simons #endif
2054e9550449SChe-Liang Chiou 
2055272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
2056272cc70bSAndy Fleming {
20571b26bab1SDaniel Kochmański 	static int initialized = 0;
20588e3332e2SSjoerd Simons 	int ret;
20591b26bab1SDaniel Kochmański 	if (initialized)	/* Avoid initializing mmc multiple times */
20601b26bab1SDaniel Kochmański 		return 0;
20611b26bab1SDaniel Kochmański 	initialized = 1;
20621b26bab1SDaniel Kochmański 
2063c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK)
2064b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY)
2065c40fdca6SSimon Glass 	mmc_list_init();
2066c40fdca6SSimon Glass #endif
2067b5b838f1SMarek Vasut #endif
20688e3332e2SSjoerd Simons 	ret = mmc_probe(bis);
20698e3332e2SSjoerd Simons 	if (ret)
20708e3332e2SSjoerd Simons 		return ret;
2071272cc70bSAndy Fleming 
2072bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD
2073272cc70bSAndy Fleming 	print_mmc_devices(',');
2074bb0dc108SYing Zhang #endif
2075272cc70bSAndy Fleming 
2076c40fdca6SSimon Glass 	mmc_do_preinit();
2077272cc70bSAndy Fleming 	return 0;
2078272cc70bSAndy Fleming }
2079cd3d4880STomas Melin 
2080cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE
2081cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc)
2082cd3d4880STomas Melin {
2083cd3d4880STomas Melin 	int err;
2084cd3d4880STomas Melin 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
2085cd3d4880STomas Melin 
2086cd3d4880STomas Melin 	err = mmc_send_ext_csd(mmc, ext_csd);
2087cd3d4880STomas Melin 	if (err) {
2088cd3d4880STomas Melin 		puts("Could not get ext_csd register values\n");
2089cd3d4880STomas Melin 		return err;
2090cd3d4880STomas Melin 	}
2091cd3d4880STomas Melin 
2092cd3d4880STomas Melin 	if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) {
2093cd3d4880STomas Melin 		puts("Background operations not supported on device\n");
2094cd3d4880STomas Melin 		return -EMEDIUMTYPE;
2095cd3d4880STomas Melin 	}
2096cd3d4880STomas Melin 
2097cd3d4880STomas Melin 	if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) {
2098cd3d4880STomas Melin 		puts("Background operations already enabled\n");
2099cd3d4880STomas Melin 		return 0;
2100cd3d4880STomas Melin 	}
2101cd3d4880STomas Melin 
2102cd3d4880STomas Melin 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1);
2103cd3d4880STomas Melin 	if (err) {
2104cd3d4880STomas Melin 		puts("Failed to enable manual background operations\n");
2105cd3d4880STomas Melin 		return err;
2106cd3d4880STomas Melin 	}
2107cd3d4880STomas Melin 
2108cd3d4880STomas Melin 	puts("Enabled manual background operations\n");
2109cd3d4880STomas Melin 
2110cd3d4880STomas Melin 	return 0;
2111cd3d4880STomas Melin }
2112cd3d4880STomas Melin #endif
2113