xref: /openbmc/u-boot/drivers/mmc/mmc.c (revision 05038576e0112a1547f1833bc17b70c34ce006bd)
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 
177*05038576SJean-Jacques Hiblot static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode)
178*05038576SJean-Jacques Hiblot {
179*05038576SJean-Jacques Hiblot 	static const int freqs[] = {
180*05038576SJean-Jacques Hiblot 	      [SD_LEGACY]	= 25000000,
181*05038576SJean-Jacques Hiblot 	      [MMC_HS]		= 26000000,
182*05038576SJean-Jacques Hiblot 	      [SD_HS]		= 50000000,
183*05038576SJean-Jacques Hiblot 	      [UHS_SDR12]	= 25000000,
184*05038576SJean-Jacques Hiblot 	      [UHS_SDR25]	= 50000000,
185*05038576SJean-Jacques Hiblot 	      [UHS_SDR50]	= 100000000,
186*05038576SJean-Jacques Hiblot 	      [UHS_SDR104]	= 208000000,
187*05038576SJean-Jacques Hiblot 	      [UHS_DDR50]	= 50000000,
188*05038576SJean-Jacques Hiblot 	      [MMC_HS_52]	= 52000000,
189*05038576SJean-Jacques Hiblot 	      [MMC_DDR_52]	= 52000000,
190*05038576SJean-Jacques Hiblot 	      [MMC_HS_200]	= 200000000,
191*05038576SJean-Jacques Hiblot 	};
192*05038576SJean-Jacques Hiblot 
193*05038576SJean-Jacques Hiblot 	if (mode == MMC_LEGACY)
194*05038576SJean-Jacques Hiblot 		return mmc->legacy_speed;
195*05038576SJean-Jacques Hiblot 	else if (mode >= MMC_MODES_END)
196*05038576SJean-Jacques Hiblot 		return 0;
197*05038576SJean-Jacques Hiblot 	else
198*05038576SJean-Jacques Hiblot 		return freqs[mode];
199*05038576SJean-Jacques Hiblot }
200*05038576SJean-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;
204*05038576SJean-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;
240d617c426SJan Kloetzke 			else if (cmd.response[0] & MMC_STATUS_MASK) {
24156196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
242d617c426SJan Kloetzke 				printf("Status Error: 0x%08X\n",
243d617c426SJan Kloetzke 					cmd.response[0]);
24456196826SPaul Burton #endif
245915ffa52SJaehoon Chung 				return -ECOMM;
246d617c426SJan Kloetzke 			}
247d617c426SJan Kloetzke 		} else if (--retries < 0)
248d617c426SJan Kloetzke 			return err;
2495d4fc8d9SRaffaele Recalcati 
2501677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
2511677eef4SAndrew Gabbasov 			break;
2525d4fc8d9SRaffaele Recalcati 
2531677eef4SAndrew Gabbasov 		udelay(1000);
2541677eef4SAndrew Gabbasov 	}
2555d4fc8d9SRaffaele Recalcati 
256c0c76ebaSSimon Glass 	mmc_trace_state(mmc, &cmd);
2575b0c942fSJongman Heo 	if (timeout <= 0) {
25856196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2595d4fc8d9SRaffaele Recalcati 		printf("Timeout waiting card ready\n");
26056196826SPaul Burton #endif
261915ffa52SJaehoon Chung 		return -ETIMEDOUT;
2625d4fc8d9SRaffaele Recalcati 	}
2635d4fc8d9SRaffaele Recalcati 
2645d4fc8d9SRaffaele Recalcati 	return 0;
2655d4fc8d9SRaffaele Recalcati }
2665d4fc8d9SRaffaele Recalcati 
267da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len)
268272cc70bSAndy Fleming {
269272cc70bSAndy Fleming 	struct mmc_cmd cmd;
270272cc70bSAndy Fleming 
271786e8f81SAndrew Gabbasov 	if (mmc->ddr_mode)
272d22e3d46SJaehoon Chung 		return 0;
273d22e3d46SJaehoon Chung 
274272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
275272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
276272cc70bSAndy Fleming 	cmd.cmdarg = len;
277272cc70bSAndy Fleming 
278272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, NULL);
279272cc70bSAndy Fleming }
280272cc70bSAndy Fleming 
281ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
282fdbb873eSKim Phillips 			   lbaint_t blkcnt)
283272cc70bSAndy Fleming {
284272cc70bSAndy Fleming 	struct mmc_cmd cmd;
285272cc70bSAndy Fleming 	struct mmc_data data;
286272cc70bSAndy Fleming 
2874a1a06bcSAlagu Sankar 	if (blkcnt > 1)
2884a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
2894a1a06bcSAlagu Sankar 	else
290272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
291272cc70bSAndy Fleming 
292272cc70bSAndy Fleming 	if (mmc->high_capacity)
2934a1a06bcSAlagu Sankar 		cmd.cmdarg = start;
294272cc70bSAndy Fleming 	else
2954a1a06bcSAlagu Sankar 		cmd.cmdarg = start * mmc->read_bl_len;
296272cc70bSAndy Fleming 
297272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
298272cc70bSAndy Fleming 
299272cc70bSAndy Fleming 	data.dest = dst;
3004a1a06bcSAlagu Sankar 	data.blocks = blkcnt;
301272cc70bSAndy Fleming 	data.blocksize = mmc->read_bl_len;
302272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
303272cc70bSAndy Fleming 
3044a1a06bcSAlagu Sankar 	if (mmc_send_cmd(mmc, &cmd, &data))
3054a1a06bcSAlagu Sankar 		return 0;
3064a1a06bcSAlagu Sankar 
3074a1a06bcSAlagu Sankar 	if (blkcnt > 1) {
3084a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
3094a1a06bcSAlagu Sankar 		cmd.cmdarg = 0;
3104a1a06bcSAlagu Sankar 		cmd.resp_type = MMC_RSP_R1b;
3114a1a06bcSAlagu Sankar 		if (mmc_send_cmd(mmc, &cmd, NULL)) {
31256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
3134a1a06bcSAlagu Sankar 			printf("mmc fail to send stop cmd\n");
31456196826SPaul Burton #endif
3154a1a06bcSAlagu Sankar 			return 0;
3164a1a06bcSAlagu Sankar 		}
317272cc70bSAndy Fleming 	}
318272cc70bSAndy Fleming 
3194a1a06bcSAlagu Sankar 	return blkcnt;
320272cc70bSAndy Fleming }
321272cc70bSAndy Fleming 
322c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
3237dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst)
32433fb211dSSimon Glass #else
3257dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
3267dba0b93SSimon Glass 		void *dst)
32733fb211dSSimon Glass #endif
328272cc70bSAndy Fleming {
329c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
33033fb211dSSimon Glass 	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
33133fb211dSSimon Glass #endif
332bcce53d0SSimon Glass 	int dev_num = block_dev->devnum;
333873cc1d7SStephen Warren 	int err;
3344a1a06bcSAlagu Sankar 	lbaint_t cur, blocks_todo = blkcnt;
335272cc70bSAndy Fleming 
3364a1a06bcSAlagu Sankar 	if (blkcnt == 0)
3374a1a06bcSAlagu Sankar 		return 0;
3384a1a06bcSAlagu Sankar 
3394a1a06bcSAlagu Sankar 	struct mmc *mmc = find_mmc_device(dev_num);
340272cc70bSAndy Fleming 	if (!mmc)
341272cc70bSAndy Fleming 		return 0;
342272cc70bSAndy Fleming 
343b5b838f1SMarek Vasut 	if (CONFIG_IS_ENABLED(MMC_TINY))
344b5b838f1SMarek Vasut 		err = mmc_switch_part(mmc, block_dev->hwpart);
345b5b838f1SMarek Vasut 	else
34669f45cd5SSimon Glass 		err = blk_dselect_hwpart(block_dev, block_dev->hwpart);
347b5b838f1SMarek Vasut 
348873cc1d7SStephen Warren 	if (err < 0)
349873cc1d7SStephen Warren 		return 0;
350873cc1d7SStephen Warren 
351c40fdca6SSimon Glass 	if ((start + blkcnt) > block_dev->lba) {
35256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
353ff8fef56SSascha Silbe 		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
354c40fdca6SSimon Glass 			start + blkcnt, block_dev->lba);
35556196826SPaul Burton #endif
356d2bf29e3SLei Wen 		return 0;
357d2bf29e3SLei Wen 	}
358272cc70bSAndy Fleming 
35911692991SSimon Glass 	if (mmc_set_blocklen(mmc, mmc->read_bl_len)) {
36011692991SSimon Glass 		debug("%s: Failed to set blocklen\n", __func__);
361272cc70bSAndy Fleming 		return 0;
36211692991SSimon Glass 	}
363272cc70bSAndy Fleming 
3644a1a06bcSAlagu Sankar 	do {
36593bfd616SPantelis Antoniou 		cur = (blocks_todo > mmc->cfg->b_max) ?
36693bfd616SPantelis Antoniou 			mmc->cfg->b_max : blocks_todo;
36711692991SSimon Glass 		if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
36811692991SSimon Glass 			debug("%s: Failed to read blocks\n", __func__);
3694a1a06bcSAlagu Sankar 			return 0;
37011692991SSimon Glass 		}
3714a1a06bcSAlagu Sankar 		blocks_todo -= cur;
3724a1a06bcSAlagu Sankar 		start += cur;
3734a1a06bcSAlagu Sankar 		dst += cur * mmc->read_bl_len;
3744a1a06bcSAlagu Sankar 	} while (blocks_todo > 0);
375272cc70bSAndy Fleming 
376272cc70bSAndy Fleming 	return blkcnt;
377272cc70bSAndy Fleming }
378272cc70bSAndy Fleming 
379fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc)
380272cc70bSAndy Fleming {
381272cc70bSAndy Fleming 	struct mmc_cmd cmd;
382272cc70bSAndy Fleming 	int err;
383272cc70bSAndy Fleming 
384272cc70bSAndy Fleming 	udelay(1000);
385272cc70bSAndy Fleming 
386272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
387272cc70bSAndy Fleming 	cmd.cmdarg = 0;
388272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_NONE;
389272cc70bSAndy Fleming 
390272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
391272cc70bSAndy Fleming 
392272cc70bSAndy Fleming 	if (err)
393272cc70bSAndy Fleming 		return err;
394272cc70bSAndy Fleming 
395272cc70bSAndy Fleming 	udelay(2000);
396272cc70bSAndy Fleming 
397272cc70bSAndy Fleming 	return 0;
398272cc70bSAndy Fleming }
399272cc70bSAndy Fleming 
400fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc)
401272cc70bSAndy Fleming {
402272cc70bSAndy Fleming 	int timeout = 1000;
403272cc70bSAndy Fleming 	int err;
404272cc70bSAndy Fleming 	struct mmc_cmd cmd;
405272cc70bSAndy Fleming 
4061677eef4SAndrew Gabbasov 	while (1) {
407272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_APP_CMD;
408272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1;
409272cc70bSAndy Fleming 		cmd.cmdarg = 0;
410272cc70bSAndy Fleming 
411272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
412272cc70bSAndy Fleming 
413272cc70bSAndy Fleming 		if (err)
414272cc70bSAndy Fleming 			return err;
415272cc70bSAndy Fleming 
416272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
417272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
418250de12bSStefano Babic 
419250de12bSStefano Babic 		/*
420250de12bSStefano Babic 		 * Most cards do not answer if some reserved bits
421250de12bSStefano Babic 		 * in the ocr are set. However, Some controller
422250de12bSStefano Babic 		 * can set bit 7 (reserved for low voltages), but
423250de12bSStefano Babic 		 * how to manage low voltages SD card is not yet
424250de12bSStefano Babic 		 * specified.
425250de12bSStefano Babic 		 */
426d52ebf10SThomas Chou 		cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
42793bfd616SPantelis Antoniou 			(mmc->cfg->voltages & 0xff8000);
428272cc70bSAndy Fleming 
429272cc70bSAndy Fleming 		if (mmc->version == SD_VERSION_2)
430272cc70bSAndy Fleming 			cmd.cmdarg |= OCR_HCS;
431272cc70bSAndy Fleming 
432272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
433272cc70bSAndy Fleming 
434272cc70bSAndy Fleming 		if (err)
435272cc70bSAndy Fleming 			return err;
436272cc70bSAndy Fleming 
4371677eef4SAndrew Gabbasov 		if (cmd.response[0] & OCR_BUSY)
4381677eef4SAndrew Gabbasov 			break;
439272cc70bSAndy Fleming 
4401677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
441915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
442272cc70bSAndy Fleming 
4431677eef4SAndrew Gabbasov 		udelay(1000);
4441677eef4SAndrew Gabbasov 	}
4451677eef4SAndrew Gabbasov 
446272cc70bSAndy Fleming 	if (mmc->version != SD_VERSION_2)
447272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
448272cc70bSAndy Fleming 
449d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
450d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
451d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
452d52ebf10SThomas Chou 		cmd.cmdarg = 0;
453d52ebf10SThomas Chou 
454d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
455d52ebf10SThomas Chou 
456d52ebf10SThomas Chou 		if (err)
457d52ebf10SThomas Chou 			return err;
458d52ebf10SThomas Chou 	}
459d52ebf10SThomas Chou 
460998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
461272cc70bSAndy Fleming 
462272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
463272cc70bSAndy Fleming 	mmc->rca = 0;
464272cc70bSAndy Fleming 
465272cc70bSAndy Fleming 	return 0;
466272cc70bSAndy Fleming }
467272cc70bSAndy Fleming 
4685289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg)
469272cc70bSAndy Fleming {
4705289b535SAndrew Gabbasov 	struct mmc_cmd cmd;
471272cc70bSAndy Fleming 	int err;
472272cc70bSAndy Fleming 
4735289b535SAndrew Gabbasov 	cmd.cmdidx = MMC_CMD_SEND_OP_COND;
4745289b535SAndrew Gabbasov 	cmd.resp_type = MMC_RSP_R3;
4755289b535SAndrew Gabbasov 	cmd.cmdarg = 0;
4765a20397bSRob Herring 	if (use_arg && !mmc_host_is_spi(mmc))
4775a20397bSRob Herring 		cmd.cmdarg = OCR_HCS |
47893bfd616SPantelis Antoniou 			(mmc->cfg->voltages &
479a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_VOLTAGE_MASK)) |
480a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_ACCESS_MODE);
481e9550449SChe-Liang Chiou 
4825289b535SAndrew Gabbasov 	err = mmc_send_cmd(mmc, &cmd, NULL);
483e9550449SChe-Liang Chiou 	if (err)
484e9550449SChe-Liang Chiou 		return err;
4855289b535SAndrew Gabbasov 	mmc->ocr = cmd.response[0];
486e9550449SChe-Liang Chiou 	return 0;
487e9550449SChe-Liang Chiou }
488e9550449SChe-Liang Chiou 
489750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc)
490e9550449SChe-Liang Chiou {
491e9550449SChe-Liang Chiou 	int err, i;
492e9550449SChe-Liang Chiou 
493272cc70bSAndy Fleming 	/* Some cards seem to need this */
494272cc70bSAndy Fleming 	mmc_go_idle(mmc);
495272cc70bSAndy Fleming 
49631cacbabSRaffaele Recalcati  	/* Asking to the card its capabilities */
497e9550449SChe-Liang Chiou 	for (i = 0; i < 2; i++) {
4985289b535SAndrew Gabbasov 		err = mmc_send_op_cond_iter(mmc, i != 0);
49931cacbabSRaffaele Recalcati 		if (err)
50031cacbabSRaffaele Recalcati 			return err;
50131cacbabSRaffaele Recalcati 
502e9550449SChe-Liang Chiou 		/* exit if not busy (flag seems to be inverted) */
503a626c8d4SAndrew Gabbasov 		if (mmc->ocr & OCR_BUSY)
504bd47c135SAndrew Gabbasov 			break;
505e9550449SChe-Liang Chiou 	}
506bd47c135SAndrew Gabbasov 	mmc->op_cond_pending = 1;
507bd47c135SAndrew Gabbasov 	return 0;
508e9550449SChe-Liang Chiou }
50931cacbabSRaffaele Recalcati 
510750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc)
511e9550449SChe-Liang Chiou {
512e9550449SChe-Liang Chiou 	struct mmc_cmd cmd;
513e9550449SChe-Liang Chiou 	int timeout = 1000;
514e9550449SChe-Liang Chiou 	uint start;
515e9550449SChe-Liang Chiou 	int err;
516e9550449SChe-Liang Chiou 
517e9550449SChe-Liang Chiou 	mmc->op_cond_pending = 0;
518cc17c01fSAndrew Gabbasov 	if (!(mmc->ocr & OCR_BUSY)) {
519d188b113SYangbo Lu 		/* Some cards seem to need this */
520d188b113SYangbo Lu 		mmc_go_idle(mmc);
521d188b113SYangbo Lu 
522e9550449SChe-Liang Chiou 		start = get_timer(0);
5231677eef4SAndrew Gabbasov 		while (1) {
5245289b535SAndrew Gabbasov 			err = mmc_send_op_cond_iter(mmc, 1);
525272cc70bSAndy Fleming 			if (err)
526272cc70bSAndy Fleming 				return err;
5271677eef4SAndrew Gabbasov 			if (mmc->ocr & OCR_BUSY)
5281677eef4SAndrew Gabbasov 				break;
529e9550449SChe-Liang Chiou 			if (get_timer(start) > timeout)
530915ffa52SJaehoon Chung 				return -EOPNOTSUPP;
531e9550449SChe-Liang Chiou 			udelay(100);
5321677eef4SAndrew Gabbasov 		}
533cc17c01fSAndrew Gabbasov 	}
534272cc70bSAndy Fleming 
535d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
536d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
537d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
538d52ebf10SThomas Chou 		cmd.cmdarg = 0;
539d52ebf10SThomas Chou 
540d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
541d52ebf10SThomas Chou 
542d52ebf10SThomas Chou 		if (err)
543d52ebf10SThomas Chou 			return err;
544a626c8d4SAndrew Gabbasov 
545a626c8d4SAndrew Gabbasov 		mmc->ocr = cmd.response[0];
546d52ebf10SThomas Chou 	}
547d52ebf10SThomas Chou 
548272cc70bSAndy Fleming 	mmc->version = MMC_VERSION_UNKNOWN;
549272cc70bSAndy Fleming 
550272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
551def816a2SStephen Warren 	mmc->rca = 1;
552272cc70bSAndy Fleming 
553272cc70bSAndy Fleming 	return 0;
554272cc70bSAndy Fleming }
555272cc70bSAndy Fleming 
556272cc70bSAndy Fleming 
557fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
558272cc70bSAndy Fleming {
559272cc70bSAndy Fleming 	struct mmc_cmd cmd;
560272cc70bSAndy Fleming 	struct mmc_data data;
561272cc70bSAndy Fleming 	int err;
562272cc70bSAndy Fleming 
563272cc70bSAndy Fleming 	/* Get the Card Status Register */
564272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
565272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
566272cc70bSAndy Fleming 	cmd.cmdarg = 0;
567272cc70bSAndy Fleming 
568cdfd1ac6SYoshihiro Shimoda 	data.dest = (char *)ext_csd;
569272cc70bSAndy Fleming 	data.blocks = 1;
5708bfa195eSSimon Glass 	data.blocksize = MMC_MAX_BLOCK_LEN;
571272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
572272cc70bSAndy Fleming 
573272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
574272cc70bSAndy Fleming 
575272cc70bSAndy Fleming 	return err;
576272cc70bSAndy Fleming }
577272cc70bSAndy Fleming 
578c40704f4SSimon Glass int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
579272cc70bSAndy Fleming {
580272cc70bSAndy Fleming 	struct mmc_cmd cmd;
5815d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
582a9003dc6SMaxime Ripard 	int retries = 3;
5835d4fc8d9SRaffaele Recalcati 	int ret;
584272cc70bSAndy Fleming 
585272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SWITCH;
586272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1b;
587272cc70bSAndy Fleming 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
588272cc70bSAndy Fleming 				 (index << 16) |
589272cc70bSAndy Fleming 				 (value << 8);
590272cc70bSAndy Fleming 
591a9003dc6SMaxime Ripard 	while (retries > 0) {
5925d4fc8d9SRaffaele Recalcati 		ret = mmc_send_cmd(mmc, &cmd, NULL);
5935d4fc8d9SRaffaele Recalcati 
5945d4fc8d9SRaffaele Recalcati 		/* Waiting for the ready status */
595a9003dc6SMaxime Ripard 		if (!ret) {
59693ad0d18SJan Kloetzke 			ret = mmc_send_status(mmc, timeout);
597a9003dc6SMaxime Ripard 			return ret;
598a9003dc6SMaxime Ripard 		}
599a9003dc6SMaxime Ripard 
600a9003dc6SMaxime Ripard 		retries--;
601a9003dc6SMaxime Ripard 	}
6025d4fc8d9SRaffaele Recalcati 
6035d4fc8d9SRaffaele Recalcati 	return ret;
6045d4fc8d9SRaffaele Recalcati 
605272cc70bSAndy Fleming }
606272cc70bSAndy Fleming 
607fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc)
608272cc70bSAndy Fleming {
6098bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
610272cc70bSAndy Fleming 	char cardtype;
611272cc70bSAndy Fleming 	int err;
612272cc70bSAndy Fleming 
613fc5b32fbSAndrew Gabbasov 	mmc->card_caps = 0;
614272cc70bSAndy Fleming 
615d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
616d52ebf10SThomas Chou 		return 0;
617d52ebf10SThomas Chou 
618272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
619272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
620272cc70bSAndy Fleming 		return 0;
621272cc70bSAndy Fleming 
622fc5b32fbSAndrew Gabbasov 	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
623fc5b32fbSAndrew Gabbasov 
624272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
625272cc70bSAndy Fleming 
626272cc70bSAndy Fleming 	if (err)
627272cc70bSAndy Fleming 		return err;
628272cc70bSAndy Fleming 
6290560db18SLei Wen 	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf;
630272cc70bSAndy Fleming 
631272cc70bSAndy Fleming 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
632272cc70bSAndy Fleming 
633272cc70bSAndy Fleming 	if (err)
634a5e27b41SHeiko Schocher 		return err;
635272cc70bSAndy Fleming 
636272cc70bSAndy Fleming 	/* Now check to see that it worked */
637272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
638272cc70bSAndy Fleming 
639272cc70bSAndy Fleming 	if (err)
640272cc70bSAndy Fleming 		return err;
641272cc70bSAndy Fleming 
642272cc70bSAndy Fleming 	/* No high-speed support */
6430560db18SLei Wen 	if (!ext_csd[EXT_CSD_HS_TIMING])
644272cc70bSAndy Fleming 		return 0;
645272cc70bSAndy Fleming 
646272cc70bSAndy Fleming 	/* High Speed is set, there are two types: 52MHz and 26MHz */
647d22e3d46SJaehoon Chung 	if (cardtype & EXT_CSD_CARD_TYPE_52) {
648201d5ac4SAndrew Gabbasov 		if (cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V)
649d22e3d46SJaehoon Chung 			mmc->card_caps |= MMC_MODE_DDR_52MHz;
650272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
651d22e3d46SJaehoon Chung 	} else {
652272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
653d22e3d46SJaehoon Chung 	}
654272cc70bSAndy Fleming 
655272cc70bSAndy Fleming 	return 0;
656272cc70bSAndy Fleming }
657272cc70bSAndy Fleming 
658f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num)
659f866a46dSStephen Warren {
660f866a46dSStephen Warren 	switch (part_num) {
661f866a46dSStephen Warren 	case 0:
662f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_user;
663f866a46dSStephen Warren 		break;
664f866a46dSStephen Warren 	case 1:
665f866a46dSStephen Warren 	case 2:
666f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_boot;
667f866a46dSStephen Warren 		break;
668f866a46dSStephen Warren 	case 3:
669f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_rpmb;
670f866a46dSStephen Warren 		break;
671f866a46dSStephen Warren 	case 4:
672f866a46dSStephen Warren 	case 5:
673f866a46dSStephen Warren 	case 6:
674f866a46dSStephen Warren 	case 7:
675f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_gp[part_num - 4];
676f866a46dSStephen Warren 		break;
677f866a46dSStephen Warren 	default:
678f866a46dSStephen Warren 		return -1;
679f866a46dSStephen Warren 	}
680f866a46dSStephen Warren 
681c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len);
682f866a46dSStephen Warren 
683f866a46dSStephen Warren 	return 0;
684f866a46dSStephen Warren }
685f866a46dSStephen Warren 
6867dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num)
687bc897b1dSLei Wen {
688f866a46dSStephen Warren 	int ret;
689bc897b1dSLei Wen 
690f866a46dSStephen Warren 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
691bc897b1dSLei Wen 			 (mmc->part_config & ~PART_ACCESS_MASK)
692bc897b1dSLei Wen 			 | (part_num & PART_ACCESS_MASK));
693f866a46dSStephen Warren 
6946dc93e70SPeter Bigot 	/*
6956dc93e70SPeter Bigot 	 * Set the capacity if the switch succeeded or was intended
6966dc93e70SPeter Bigot 	 * to return to representing the raw device.
6976dc93e70SPeter Bigot 	 */
698873cc1d7SStephen Warren 	if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) {
6996dc93e70SPeter Bigot 		ret = mmc_set_capacity(mmc, part_num);
700fdbb139fSSimon Glass 		mmc_get_blk_desc(mmc)->hwpart = part_num;
701873cc1d7SStephen Warren 	}
7026dc93e70SPeter Bigot 
7036dc93e70SPeter Bigot 	return ret;
704bc897b1dSLei Wen }
705bc897b1dSLei Wen 
706ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc,
707ac9da0e0SDiego Santa Cruz 		      const struct mmc_hwpart_conf *conf,
708ac9da0e0SDiego Santa Cruz 		      enum mmc_hwpart_conf_mode mode)
709ac9da0e0SDiego Santa Cruz {
710ac9da0e0SDiego Santa Cruz 	u8 part_attrs = 0;
711ac9da0e0SDiego Santa Cruz 	u32 enh_size_mult;
712ac9da0e0SDiego Santa Cruz 	u32 enh_start_addr;
713ac9da0e0SDiego Santa Cruz 	u32 gp_size_mult[4];
714ac9da0e0SDiego Santa Cruz 	u32 max_enh_size_mult;
715ac9da0e0SDiego Santa Cruz 	u32 tot_enh_size_mult = 0;
7168dda5b0eSDiego Santa Cruz 	u8 wr_rel_set;
717ac9da0e0SDiego Santa Cruz 	int i, pidx, err;
718ac9da0e0SDiego Santa Cruz 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
719ac9da0e0SDiego Santa Cruz 
720ac9da0e0SDiego Santa Cruz 	if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE)
721ac9da0e0SDiego Santa Cruz 		return -EINVAL;
722ac9da0e0SDiego Santa Cruz 
723ac9da0e0SDiego Santa Cruz 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) {
724ac9da0e0SDiego Santa Cruz 		printf("eMMC >= 4.4 required for enhanced user data area\n");
725ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
726ac9da0e0SDiego Santa Cruz 	}
727ac9da0e0SDiego Santa Cruz 
728ac9da0e0SDiego Santa Cruz 	if (!(mmc->part_support & PART_SUPPORT)) {
729ac9da0e0SDiego Santa Cruz 		printf("Card does not support partitioning\n");
730ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
731ac9da0e0SDiego Santa Cruz 	}
732ac9da0e0SDiego Santa Cruz 
733ac9da0e0SDiego Santa Cruz 	if (!mmc->hc_wp_grp_size) {
734ac9da0e0SDiego Santa Cruz 		printf("Card does not define HC WP group size\n");
735ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
736ac9da0e0SDiego Santa Cruz 	}
737ac9da0e0SDiego Santa Cruz 
738ac9da0e0SDiego Santa Cruz 	/* check partition alignment and total enhanced size */
739ac9da0e0SDiego Santa Cruz 	if (conf->user.enh_size) {
740ac9da0e0SDiego Santa Cruz 		if (conf->user.enh_size % mmc->hc_wp_grp_size ||
741ac9da0e0SDiego Santa Cruz 		    conf->user.enh_start % mmc->hc_wp_grp_size) {
742ac9da0e0SDiego Santa Cruz 			printf("User data enhanced area not HC WP group "
743ac9da0e0SDiego Santa Cruz 			       "size aligned\n");
744ac9da0e0SDiego Santa Cruz 			return -EINVAL;
745ac9da0e0SDiego Santa Cruz 		}
746ac9da0e0SDiego Santa Cruz 		part_attrs |= EXT_CSD_ENH_USR;
747ac9da0e0SDiego Santa Cruz 		enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size;
748ac9da0e0SDiego Santa Cruz 		if (mmc->high_capacity) {
749ac9da0e0SDiego Santa Cruz 			enh_start_addr = conf->user.enh_start;
750ac9da0e0SDiego Santa Cruz 		} else {
751ac9da0e0SDiego Santa Cruz 			enh_start_addr = (conf->user.enh_start << 9);
752ac9da0e0SDiego Santa Cruz 		}
753ac9da0e0SDiego Santa Cruz 	} else {
754ac9da0e0SDiego Santa Cruz 		enh_size_mult = 0;
755ac9da0e0SDiego Santa Cruz 		enh_start_addr = 0;
756ac9da0e0SDiego Santa Cruz 	}
757ac9da0e0SDiego Santa Cruz 	tot_enh_size_mult += enh_size_mult;
758ac9da0e0SDiego Santa Cruz 
759ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
760ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) {
761ac9da0e0SDiego Santa Cruz 			printf("GP%i partition not HC WP group size "
762ac9da0e0SDiego Santa Cruz 			       "aligned\n", pidx+1);
763ac9da0e0SDiego Santa Cruz 			return -EINVAL;
764ac9da0e0SDiego Santa Cruz 		}
765ac9da0e0SDiego Santa Cruz 		gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size;
766ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) {
767ac9da0e0SDiego Santa Cruz 			part_attrs |= EXT_CSD_ENH_GP(pidx);
768ac9da0e0SDiego Santa Cruz 			tot_enh_size_mult += gp_size_mult[pidx];
769ac9da0e0SDiego Santa Cruz 		}
770ac9da0e0SDiego Santa Cruz 	}
771ac9da0e0SDiego Santa Cruz 
772ac9da0e0SDiego Santa Cruz 	if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) {
773ac9da0e0SDiego Santa Cruz 		printf("Card does not support enhanced attribute\n");
774ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
775ac9da0e0SDiego Santa Cruz 	}
776ac9da0e0SDiego Santa Cruz 
777ac9da0e0SDiego Santa Cruz 	err = mmc_send_ext_csd(mmc, ext_csd);
778ac9da0e0SDiego Santa Cruz 	if (err)
779ac9da0e0SDiego Santa Cruz 		return err;
780ac9da0e0SDiego Santa Cruz 
781ac9da0e0SDiego Santa Cruz 	max_enh_size_mult =
782ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) +
783ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) +
784ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT];
785ac9da0e0SDiego Santa Cruz 	if (tot_enh_size_mult > max_enh_size_mult) {
786ac9da0e0SDiego Santa Cruz 		printf("Total enhanced size exceeds maximum (%u > %u)\n",
787ac9da0e0SDiego Santa Cruz 		       tot_enh_size_mult, max_enh_size_mult);
788ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
789ac9da0e0SDiego Santa Cruz 	}
790ac9da0e0SDiego Santa Cruz 
7918dda5b0eSDiego Santa Cruz 	/* The default value of EXT_CSD_WR_REL_SET is device
7928dda5b0eSDiego Santa Cruz 	 * dependent, the values can only be changed if the
7938dda5b0eSDiego Santa Cruz 	 * EXT_CSD_HS_CTRL_REL bit is set. The values can be
7948dda5b0eSDiego Santa Cruz 	 * changed only once and before partitioning is completed. */
7958dda5b0eSDiego Santa Cruz 	wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
7968dda5b0eSDiego Santa Cruz 	if (conf->user.wr_rel_change) {
7978dda5b0eSDiego Santa Cruz 		if (conf->user.wr_rel_set)
7988dda5b0eSDiego Santa Cruz 			wr_rel_set |= EXT_CSD_WR_DATA_REL_USR;
7998dda5b0eSDiego Santa Cruz 		else
8008dda5b0eSDiego Santa Cruz 			wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR;
8018dda5b0eSDiego Santa Cruz 	}
8028dda5b0eSDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
8038dda5b0eSDiego Santa Cruz 		if (conf->gp_part[pidx].wr_rel_change) {
8048dda5b0eSDiego Santa Cruz 			if (conf->gp_part[pidx].wr_rel_set)
8058dda5b0eSDiego Santa Cruz 				wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx);
8068dda5b0eSDiego Santa Cruz 			else
8078dda5b0eSDiego Santa Cruz 				wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx);
8088dda5b0eSDiego Santa Cruz 		}
8098dda5b0eSDiego Santa Cruz 	}
8108dda5b0eSDiego Santa Cruz 
8118dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] &&
8128dda5b0eSDiego Santa Cruz 	    !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) {
8138dda5b0eSDiego Santa Cruz 		puts("Card does not support host controlled partition write "
8148dda5b0eSDiego Santa Cruz 		     "reliability settings\n");
8158dda5b0eSDiego Santa Cruz 		return -EMEDIUMTYPE;
8168dda5b0eSDiego Santa Cruz 	}
8178dda5b0eSDiego Santa Cruz 
818ac9da0e0SDiego Santa Cruz 	if (ext_csd[EXT_CSD_PARTITION_SETTING] &
819ac9da0e0SDiego Santa Cruz 	    EXT_CSD_PARTITION_SETTING_COMPLETED) {
820ac9da0e0SDiego Santa Cruz 		printf("Card already partitioned\n");
821ac9da0e0SDiego Santa Cruz 		return -EPERM;
822ac9da0e0SDiego Santa Cruz 	}
823ac9da0e0SDiego Santa Cruz 
824ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_CHECK)
825ac9da0e0SDiego Santa Cruz 		return 0;
826ac9da0e0SDiego Santa Cruz 
827ac9da0e0SDiego Santa Cruz 	/* Partitioning requires high-capacity size definitions */
828ac9da0e0SDiego Santa Cruz 	if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) {
829ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
830ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ERASE_GROUP_DEF, 1);
831ac9da0e0SDiego Santa Cruz 
832ac9da0e0SDiego Santa Cruz 		if (err)
833ac9da0e0SDiego Santa Cruz 			return err;
834ac9da0e0SDiego Santa Cruz 
835ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
836ac9da0e0SDiego Santa Cruz 
837ac9da0e0SDiego Santa Cruz 		/* update erase group size to be high-capacity */
838ac9da0e0SDiego Santa Cruz 		mmc->erase_grp_size =
839ac9da0e0SDiego Santa Cruz 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
840ac9da0e0SDiego Santa Cruz 
841ac9da0e0SDiego Santa Cruz 	}
842ac9da0e0SDiego Santa Cruz 
843ac9da0e0SDiego Santa Cruz 	/* all OK, write the configuration */
844ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 4; i++) {
845ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
846ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_START_ADDR+i,
847ac9da0e0SDiego Santa Cruz 				 (enh_start_addr >> (i*8)) & 0xFF);
848ac9da0e0SDiego Santa Cruz 		if (err)
849ac9da0e0SDiego Santa Cruz 			return err;
850ac9da0e0SDiego Santa Cruz 	}
851ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 3; i++) {
852ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
853ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_SIZE_MULT+i,
854ac9da0e0SDiego Santa Cruz 				 (enh_size_mult >> (i*8)) & 0xFF);
855ac9da0e0SDiego Santa Cruz 		if (err)
856ac9da0e0SDiego Santa Cruz 			return err;
857ac9da0e0SDiego Santa Cruz 	}
858ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
859ac9da0e0SDiego Santa Cruz 		for (i = 0; i < 3; i++) {
860ac9da0e0SDiego Santa Cruz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
861ac9da0e0SDiego Santa Cruz 					 EXT_CSD_GP_SIZE_MULT+pidx*3+i,
862ac9da0e0SDiego Santa Cruz 					 (gp_size_mult[pidx] >> (i*8)) & 0xFF);
863ac9da0e0SDiego Santa Cruz 			if (err)
864ac9da0e0SDiego Santa Cruz 				return err;
865ac9da0e0SDiego Santa Cruz 		}
866ac9da0e0SDiego Santa Cruz 	}
867ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
868ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs);
869ac9da0e0SDiego Santa Cruz 	if (err)
870ac9da0e0SDiego Santa Cruz 		return err;
871ac9da0e0SDiego Santa Cruz 
872ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_SET)
873ac9da0e0SDiego Santa Cruz 		return 0;
874ac9da0e0SDiego Santa Cruz 
8758dda5b0eSDiego Santa Cruz 	/* The WR_REL_SET is a write-once register but shall be
8768dda5b0eSDiego Santa Cruz 	 * written before setting PART_SETTING_COMPLETED. As it is
8778dda5b0eSDiego Santa Cruz 	 * write-once we can only write it when completing the
8788dda5b0eSDiego Santa Cruz 	 * partitioning. */
8798dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) {
8808dda5b0eSDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
8818dda5b0eSDiego Santa Cruz 				 EXT_CSD_WR_REL_SET, wr_rel_set);
8828dda5b0eSDiego Santa Cruz 		if (err)
8838dda5b0eSDiego Santa Cruz 			return err;
8848dda5b0eSDiego Santa Cruz 	}
8858dda5b0eSDiego Santa Cruz 
886ac9da0e0SDiego Santa Cruz 	/* Setting PART_SETTING_COMPLETED confirms the partition
887ac9da0e0SDiego Santa Cruz 	 * configuration but it only becomes effective after power
888ac9da0e0SDiego Santa Cruz 	 * cycle, so we do not adjust the partition related settings
889ac9da0e0SDiego Santa Cruz 	 * in the mmc struct. */
890ac9da0e0SDiego Santa Cruz 
891ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
892ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING,
893ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING_COMPLETED);
894ac9da0e0SDiego Santa Cruz 	if (err)
895ac9da0e0SDiego Santa Cruz 		return err;
896ac9da0e0SDiego Santa Cruz 
897ac9da0e0SDiego Santa Cruz 	return 0;
898ac9da0e0SDiego Santa Cruz }
899ac9da0e0SDiego Santa Cruz 
900e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
90148972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
90248972d90SThierry Reding {
90348972d90SThierry Reding 	int cd;
90448972d90SThierry Reding 
90548972d90SThierry Reding 	cd = board_mmc_getcd(mmc);
90648972d90SThierry Reding 
907d4e1da4eSPeter Korsgaard 	if (cd < 0) {
90893bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getcd)
90993bfd616SPantelis Antoniou 			cd = mmc->cfg->ops->getcd(mmc);
910d4e1da4eSPeter Korsgaard 		else
911d4e1da4eSPeter Korsgaard 			cd = 1;
912d4e1da4eSPeter Korsgaard 	}
91348972d90SThierry Reding 
91448972d90SThierry Reding 	return cd;
91548972d90SThierry Reding }
9168ca51e51SSimon Glass #endif
91748972d90SThierry Reding 
918fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
919272cc70bSAndy Fleming {
920272cc70bSAndy Fleming 	struct mmc_cmd cmd;
921272cc70bSAndy Fleming 	struct mmc_data data;
922272cc70bSAndy Fleming 
923272cc70bSAndy Fleming 	/* Switch the frequency */
924272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
925272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
926272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
927272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
928272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
929272cc70bSAndy Fleming 
930272cc70bSAndy Fleming 	data.dest = (char *)resp;
931272cc70bSAndy Fleming 	data.blocksize = 64;
932272cc70bSAndy Fleming 	data.blocks = 1;
933272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
934272cc70bSAndy Fleming 
935272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
936272cc70bSAndy Fleming }
937272cc70bSAndy Fleming 
938272cc70bSAndy Fleming 
939fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc)
940272cc70bSAndy Fleming {
941272cc70bSAndy Fleming 	int err;
942272cc70bSAndy Fleming 	struct mmc_cmd cmd;
94318e7c8f6SSuniel Mahesh 	ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2);
94418e7c8f6SSuniel Mahesh 	ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16);
945272cc70bSAndy Fleming 	struct mmc_data data;
946272cc70bSAndy Fleming 	int timeout;
947272cc70bSAndy Fleming 
948272cc70bSAndy Fleming 	mmc->card_caps = 0;
949272cc70bSAndy Fleming 
950d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
951d52ebf10SThomas Chou 		return 0;
952d52ebf10SThomas Chou 
953272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
954272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
955272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
956272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
957272cc70bSAndy Fleming 
958272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
959272cc70bSAndy Fleming 
960272cc70bSAndy Fleming 	if (err)
961272cc70bSAndy Fleming 		return err;
962272cc70bSAndy Fleming 
963272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
964272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
965272cc70bSAndy Fleming 	cmd.cmdarg = 0;
966272cc70bSAndy Fleming 
967272cc70bSAndy Fleming 	timeout = 3;
968272cc70bSAndy Fleming 
969272cc70bSAndy Fleming retry_scr:
970f781dd38SAnton staaf 	data.dest = (char *)scr;
971272cc70bSAndy Fleming 	data.blocksize = 8;
972272cc70bSAndy Fleming 	data.blocks = 1;
973272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
974272cc70bSAndy Fleming 
975272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
976272cc70bSAndy Fleming 
977272cc70bSAndy Fleming 	if (err) {
978272cc70bSAndy Fleming 		if (timeout--)
979272cc70bSAndy Fleming 			goto retry_scr;
980272cc70bSAndy Fleming 
981272cc70bSAndy Fleming 		return err;
982272cc70bSAndy Fleming 	}
983272cc70bSAndy Fleming 
9844e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
9854e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
986272cc70bSAndy Fleming 
987272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
988272cc70bSAndy Fleming 	case 0:
989272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
990272cc70bSAndy Fleming 		break;
991272cc70bSAndy Fleming 	case 1:
992272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_10;
993272cc70bSAndy Fleming 		break;
994272cc70bSAndy Fleming 	case 2:
995272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
9961741c64dSJaehoon Chung 		if ((mmc->scr[0] >> 15) & 0x1)
9971741c64dSJaehoon Chung 			mmc->version = SD_VERSION_3;
998272cc70bSAndy Fleming 		break;
999272cc70bSAndy Fleming 	default:
1000272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1001272cc70bSAndy Fleming 		break;
1002272cc70bSAndy Fleming 	}
1003272cc70bSAndy Fleming 
1004b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
1005b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
1006b44c7083SAlagu Sankar 
1007272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
1008272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
1009272cc70bSAndy Fleming 		return 0;
1010272cc70bSAndy Fleming 
1011272cc70bSAndy Fleming 	timeout = 4;
1012272cc70bSAndy Fleming 	while (timeout--) {
1013272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
1014f781dd38SAnton staaf 				(u8 *)switch_status);
1015272cc70bSAndy Fleming 
1016272cc70bSAndy Fleming 		if (err)
1017272cc70bSAndy Fleming 			return err;
1018272cc70bSAndy Fleming 
1019272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
10204e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
1021272cc70bSAndy Fleming 			break;
1022272cc70bSAndy Fleming 	}
1023272cc70bSAndy Fleming 
1024272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
10254e3d89baSYauhen Kharuzhy 	if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED))
1026272cc70bSAndy Fleming 		return 0;
1027272cc70bSAndy Fleming 
10282c3fbf4cSMacpaul Lin 	/*
10292c3fbf4cSMacpaul Lin 	 * If the host doesn't support SD_HIGHSPEED, do not switch card to
10302c3fbf4cSMacpaul Lin 	 * HIGHSPEED mode even if the card support SD_HIGHSPPED.
10312c3fbf4cSMacpaul Lin 	 * This can avoid furthur problem when the card runs in different
10322c3fbf4cSMacpaul Lin 	 * mode between the host.
10332c3fbf4cSMacpaul Lin 	 */
103493bfd616SPantelis Antoniou 	if (!((mmc->cfg->host_caps & MMC_MODE_HS_52MHz) &&
103593bfd616SPantelis Antoniou 		(mmc->cfg->host_caps & MMC_MODE_HS)))
10362c3fbf4cSMacpaul Lin 		return 0;
10372c3fbf4cSMacpaul Lin 
1038f781dd38SAnton staaf 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status);
1039272cc70bSAndy Fleming 
1040272cc70bSAndy Fleming 	if (err)
1041272cc70bSAndy Fleming 		return err;
1042272cc70bSAndy Fleming 
10434e3d89baSYauhen Kharuzhy 	if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000)
1044272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
1045272cc70bSAndy Fleming 
1046272cc70bSAndy Fleming 	return 0;
1047272cc70bSAndy Fleming }
1048272cc70bSAndy Fleming 
10493697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc)
10503697e599SPeng Fan {
10513697e599SPeng Fan 	int err, i;
10523697e599SPeng Fan 	struct mmc_cmd cmd;
10533697e599SPeng Fan 	ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16);
10543697e599SPeng Fan 	struct mmc_data data;
10553697e599SPeng Fan 	int timeout = 3;
10563697e599SPeng Fan 	unsigned int au, eo, et, es;
10573697e599SPeng Fan 
10583697e599SPeng Fan 	cmd.cmdidx = MMC_CMD_APP_CMD;
10593697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
10603697e599SPeng Fan 	cmd.cmdarg = mmc->rca << 16;
10613697e599SPeng Fan 
10623697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, NULL);
10633697e599SPeng Fan 	if (err)
10643697e599SPeng Fan 		return err;
10653697e599SPeng Fan 
10663697e599SPeng Fan 	cmd.cmdidx = SD_CMD_APP_SD_STATUS;
10673697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
10683697e599SPeng Fan 	cmd.cmdarg = 0;
10693697e599SPeng Fan 
10703697e599SPeng Fan retry_ssr:
10713697e599SPeng Fan 	data.dest = (char *)ssr;
10723697e599SPeng Fan 	data.blocksize = 64;
10733697e599SPeng Fan 	data.blocks = 1;
10743697e599SPeng Fan 	data.flags = MMC_DATA_READ;
10753697e599SPeng Fan 
10763697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, &data);
10773697e599SPeng Fan 	if (err) {
10783697e599SPeng Fan 		if (timeout--)
10793697e599SPeng Fan 			goto retry_ssr;
10803697e599SPeng Fan 
10813697e599SPeng Fan 		return err;
10823697e599SPeng Fan 	}
10833697e599SPeng Fan 
10843697e599SPeng Fan 	for (i = 0; i < 16; i++)
10853697e599SPeng Fan 		ssr[i] = be32_to_cpu(ssr[i]);
10863697e599SPeng Fan 
10873697e599SPeng Fan 	au = (ssr[2] >> 12) & 0xF;
10883697e599SPeng Fan 	if ((au <= 9) || (mmc->version == SD_VERSION_3)) {
10893697e599SPeng Fan 		mmc->ssr.au = sd_au_size[au];
10903697e599SPeng Fan 		es = (ssr[3] >> 24) & 0xFF;
10913697e599SPeng Fan 		es |= (ssr[2] & 0xFF) << 8;
10923697e599SPeng Fan 		et = (ssr[3] >> 18) & 0x3F;
10933697e599SPeng Fan 		if (es && et) {
10943697e599SPeng Fan 			eo = (ssr[3] >> 16) & 0x3;
10953697e599SPeng Fan 			mmc->ssr.erase_timeout = (et * 1000) / es;
10963697e599SPeng Fan 			mmc->ssr.erase_offset = eo * 1000;
10973697e599SPeng Fan 		}
10983697e599SPeng Fan 	} else {
10993697e599SPeng Fan 		debug("Invalid Allocation Unit Size.\n");
11003697e599SPeng Fan 	}
11013697e599SPeng Fan 
11023697e599SPeng Fan 	return 0;
11033697e599SPeng Fan }
11043697e599SPeng Fan 
1105272cc70bSAndy Fleming /* frequency bases */
1106272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
11075f837c2cSMike Frysinger static const int fbase[] = {
1108272cc70bSAndy Fleming 	10000,
1109272cc70bSAndy Fleming 	100000,
1110272cc70bSAndy Fleming 	1000000,
1111272cc70bSAndy Fleming 	10000000,
1112272cc70bSAndy Fleming };
1113272cc70bSAndy Fleming 
1114272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
1115272cc70bSAndy Fleming  * to platforms without floating point.
1116272cc70bSAndy Fleming  */
111761fe076fSSimon Glass static const u8 multipliers[] = {
1118272cc70bSAndy Fleming 	0,	/* reserved */
1119272cc70bSAndy Fleming 	10,
1120272cc70bSAndy Fleming 	12,
1121272cc70bSAndy Fleming 	13,
1122272cc70bSAndy Fleming 	15,
1123272cc70bSAndy Fleming 	20,
1124272cc70bSAndy Fleming 	25,
1125272cc70bSAndy Fleming 	30,
1126272cc70bSAndy Fleming 	35,
1127272cc70bSAndy Fleming 	40,
1128272cc70bSAndy Fleming 	45,
1129272cc70bSAndy Fleming 	50,
1130272cc70bSAndy Fleming 	55,
1131272cc70bSAndy Fleming 	60,
1132272cc70bSAndy Fleming 	70,
1133272cc70bSAndy Fleming 	80,
1134272cc70bSAndy Fleming };
1135272cc70bSAndy Fleming 
1136e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
1137fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc)
1138272cc70bSAndy Fleming {
113993bfd616SPantelis Antoniou 	if (mmc->cfg->ops->set_ios)
114093bfd616SPantelis Antoniou 		mmc->cfg->ops->set_ios(mmc);
1141272cc70bSAndy Fleming }
11428ca51e51SSimon Glass #endif
1143272cc70bSAndy Fleming 
1144272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock)
1145272cc70bSAndy Fleming {
114693bfd616SPantelis Antoniou 	if (clock > mmc->cfg->f_max)
114793bfd616SPantelis Antoniou 		clock = mmc->cfg->f_max;
1148272cc70bSAndy Fleming 
114993bfd616SPantelis Antoniou 	if (clock < mmc->cfg->f_min)
115093bfd616SPantelis Antoniou 		clock = mmc->cfg->f_min;
1151272cc70bSAndy Fleming 
1152272cc70bSAndy Fleming 	mmc->clock = clock;
1153272cc70bSAndy Fleming 
1154272cc70bSAndy Fleming 	mmc_set_ios(mmc);
1155272cc70bSAndy Fleming }
1156272cc70bSAndy Fleming 
1157fdbb873eSKim Phillips static void mmc_set_bus_width(struct mmc *mmc, uint width)
1158272cc70bSAndy Fleming {
1159272cc70bSAndy Fleming 	mmc->bus_width = width;
1160272cc70bSAndy Fleming 
1161272cc70bSAndy Fleming 	mmc_set_ios(mmc);
1162272cc70bSAndy Fleming }
1163272cc70bSAndy Fleming 
11644c9d2aaaSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG)
11654c9d2aaaSJean-Jacques Hiblot /*
11664c9d2aaaSJean-Jacques Hiblot  * helper function to display the capabilities in a human
11674c9d2aaaSJean-Jacques Hiblot  * friendly manner. The capabilities include bus width and
11684c9d2aaaSJean-Jacques Hiblot  * supported modes.
11694c9d2aaaSJean-Jacques Hiblot  */
11704c9d2aaaSJean-Jacques Hiblot void mmc_dump_capabilities(const char *text, uint caps)
11714c9d2aaaSJean-Jacques Hiblot {
11724c9d2aaaSJean-Jacques Hiblot 	enum bus_mode mode;
11734c9d2aaaSJean-Jacques Hiblot 
11744c9d2aaaSJean-Jacques Hiblot 	printf("%s: widths [", text);
11754c9d2aaaSJean-Jacques Hiblot 	if (caps & MMC_MODE_8BIT)
11764c9d2aaaSJean-Jacques Hiblot 		printf("8, ");
11774c9d2aaaSJean-Jacques Hiblot 	if (caps & MMC_MODE_4BIT)
11784c9d2aaaSJean-Jacques Hiblot 		printf("4, ");
11794c9d2aaaSJean-Jacques Hiblot 	printf("1] modes [");
11804c9d2aaaSJean-Jacques Hiblot 
11814c9d2aaaSJean-Jacques Hiblot 	for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++)
11824c9d2aaaSJean-Jacques Hiblot 		if (MMC_CAP(mode) & caps)
11834c9d2aaaSJean-Jacques Hiblot 			printf("%s, ", mmc_mode_name(mode));
11844c9d2aaaSJean-Jacques Hiblot 	printf("\b\b]\n");
11854c9d2aaaSJean-Jacques Hiblot }
11864c9d2aaaSJean-Jacques Hiblot #endif
11874c9d2aaaSJean-Jacques Hiblot 
11888ac8a263SJean-Jacques Hiblot static int sd_select_bus_freq_width(struct mmc *mmc)
11898ac8a263SJean-Jacques Hiblot {
11908ac8a263SJean-Jacques Hiblot 	int err;
11918ac8a263SJean-Jacques Hiblot 	struct mmc_cmd cmd;
11928ac8a263SJean-Jacques Hiblot 
11938ac8a263SJean-Jacques Hiblot 	err = sd_change_freq(mmc);
11948ac8a263SJean-Jacques Hiblot 	if (err)
11958ac8a263SJean-Jacques Hiblot 		return err;
11968ac8a263SJean-Jacques Hiblot 
11978ac8a263SJean-Jacques Hiblot 	/* Restrict card's capabilities by what the host can do */
11988ac8a263SJean-Jacques Hiblot 	mmc->card_caps &= mmc->cfg->host_caps;
11998ac8a263SJean-Jacques Hiblot 
12008ac8a263SJean-Jacques Hiblot 	if (mmc->card_caps & MMC_MODE_4BIT) {
12018ac8a263SJean-Jacques Hiblot 		cmd.cmdidx = MMC_CMD_APP_CMD;
12028ac8a263SJean-Jacques Hiblot 		cmd.resp_type = MMC_RSP_R1;
12038ac8a263SJean-Jacques Hiblot 		cmd.cmdarg = mmc->rca << 16;
12048ac8a263SJean-Jacques Hiblot 
12058ac8a263SJean-Jacques Hiblot 		err = mmc_send_cmd(mmc, &cmd, NULL);
12068ac8a263SJean-Jacques Hiblot 		if (err)
12078ac8a263SJean-Jacques Hiblot 			return err;
12088ac8a263SJean-Jacques Hiblot 
12098ac8a263SJean-Jacques Hiblot 		cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
12108ac8a263SJean-Jacques Hiblot 		cmd.resp_type = MMC_RSP_R1;
12118ac8a263SJean-Jacques Hiblot 		cmd.cmdarg = 2;
12128ac8a263SJean-Jacques Hiblot 		err = mmc_send_cmd(mmc, &cmd, NULL);
12138ac8a263SJean-Jacques Hiblot 		if (err)
12148ac8a263SJean-Jacques Hiblot 			return err;
12158ac8a263SJean-Jacques Hiblot 
12168ac8a263SJean-Jacques Hiblot 		mmc_set_bus_width(mmc, 4);
12178ac8a263SJean-Jacques Hiblot 	}
12188ac8a263SJean-Jacques Hiblot 
12198ac8a263SJean-Jacques Hiblot 	err = sd_read_ssr(mmc);
12208ac8a263SJean-Jacques Hiblot 	if (err)
12218ac8a263SJean-Jacques Hiblot 		return err;
12228ac8a263SJean-Jacques Hiblot 
1223*05038576SJean-Jacques Hiblot 	if (mmc->card_caps & MMC_MODE_HS)
122435f9e196SJean-Jacques Hiblot 		mmc_select_mode(mmc, SD_HS);
1225*05038576SJean-Jacques Hiblot 	else
122635f9e196SJean-Jacques Hiblot 		mmc_select_mode(mmc, SD_LEGACY);
12278ac8a263SJean-Jacques Hiblot 
12288ac8a263SJean-Jacques Hiblot 	return 0;
12298ac8a263SJean-Jacques Hiblot }
12308ac8a263SJean-Jacques Hiblot 
12317382e691SJean-Jacques Hiblot /*
12327382e691SJean-Jacques Hiblot  * read the compare the part of ext csd that is constant.
12337382e691SJean-Jacques Hiblot  * This can be used to check that the transfer is working
12347382e691SJean-Jacques Hiblot  * as expected.
12357382e691SJean-Jacques Hiblot  */
12367382e691SJean-Jacques Hiblot static int mmc_read_and_compare_ext_csd(struct mmc *mmc)
12377382e691SJean-Jacques Hiblot {
12387382e691SJean-Jacques Hiblot 	int err;
12397382e691SJean-Jacques Hiblot 	const u8 *ext_csd = mmc->ext_csd;
12407382e691SJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
12417382e691SJean-Jacques Hiblot 
12427382e691SJean-Jacques Hiblot 	err = mmc_send_ext_csd(mmc, test_csd);
12437382e691SJean-Jacques Hiblot 	if (err)
12447382e691SJean-Jacques Hiblot 		return err;
12457382e691SJean-Jacques Hiblot 
12467382e691SJean-Jacques Hiblot 	/* Only compare read only fields */
12477382e691SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT]
12487382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_PARTITIONING_SUPPORT] &&
12497382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_HC_WP_GRP_SIZE]
12507382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_HC_WP_GRP_SIZE] &&
12517382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_REV]
12527382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_REV] &&
12537382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
12547382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] &&
12557382e691SJean-Jacques Hiblot 	    memcmp(&ext_csd[EXT_CSD_SEC_CNT],
12567382e691SJean-Jacques Hiblot 		   &test_csd[EXT_CSD_SEC_CNT], 4) == 0)
12577382e691SJean-Jacques Hiblot 		return 0;
12587382e691SJean-Jacques Hiblot 
12597382e691SJean-Jacques Hiblot 	return -EBADMSG;
12607382e691SJean-Jacques Hiblot }
12617382e691SJean-Jacques Hiblot 
1262dfda9d88SJean-Jacques Hiblot static int mmc_select_bus_freq_width(struct mmc *mmc)
12638ac8a263SJean-Jacques Hiblot {
12648ac8a263SJean-Jacques Hiblot 	/* An array of possible bus widths in order of preference */
12658ac8a263SJean-Jacques Hiblot 	static const unsigned int ext_csd_bits[] = {
12668ac8a263SJean-Jacques Hiblot 		EXT_CSD_DDR_BUS_WIDTH_8,
12678ac8a263SJean-Jacques Hiblot 		EXT_CSD_DDR_BUS_WIDTH_4,
12688ac8a263SJean-Jacques Hiblot 		EXT_CSD_BUS_WIDTH_8,
12698ac8a263SJean-Jacques Hiblot 		EXT_CSD_BUS_WIDTH_4,
12708ac8a263SJean-Jacques Hiblot 		EXT_CSD_BUS_WIDTH_1,
12718ac8a263SJean-Jacques Hiblot 	};
12728ac8a263SJean-Jacques Hiblot 	/* An array to map CSD bus widths to host cap bits */
12738ac8a263SJean-Jacques Hiblot 	static const unsigned int ext_to_hostcaps[] = {
12748ac8a263SJean-Jacques Hiblot 		[EXT_CSD_DDR_BUS_WIDTH_4] =
12758ac8a263SJean-Jacques Hiblot 			MMC_MODE_DDR_52MHz | MMC_MODE_4BIT,
12768ac8a263SJean-Jacques Hiblot 		[EXT_CSD_DDR_BUS_WIDTH_8] =
12778ac8a263SJean-Jacques Hiblot 			MMC_MODE_DDR_52MHz | MMC_MODE_8BIT,
12788ac8a263SJean-Jacques Hiblot 		[EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT,
12798ac8a263SJean-Jacques Hiblot 		[EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT,
12808ac8a263SJean-Jacques Hiblot 	};
12818ac8a263SJean-Jacques Hiblot 	/* An array to map chosen bus width to an integer */
12828ac8a263SJean-Jacques Hiblot 	static const unsigned int widths[] = {
12838ac8a263SJean-Jacques Hiblot 		8, 4, 8, 4, 1,
12848ac8a263SJean-Jacques Hiblot 	};
12858ac8a263SJean-Jacques Hiblot 	int err;
12868ac8a263SJean-Jacques Hiblot 	int idx;
12878ac8a263SJean-Jacques Hiblot 
12888ac8a263SJean-Jacques Hiblot 	err = mmc_change_freq(mmc);
12898ac8a263SJean-Jacques Hiblot 	if (err)
12908ac8a263SJean-Jacques Hiblot 		return err;
12918ac8a263SJean-Jacques Hiblot 
12928ac8a263SJean-Jacques Hiblot 	/* Restrict card's capabilities by what the host can do */
12938ac8a263SJean-Jacques Hiblot 	mmc->card_caps &= mmc->cfg->host_caps;
12948ac8a263SJean-Jacques Hiblot 
12958ac8a263SJean-Jacques Hiblot 	/* Only version 4 of MMC supports wider bus widths */
12968ac8a263SJean-Jacques Hiblot 	if (mmc->version < MMC_VERSION_4)
12978ac8a263SJean-Jacques Hiblot 		return 0;
12988ac8a263SJean-Jacques Hiblot 
1299dfda9d88SJean-Jacques Hiblot 	if (!mmc->ext_csd) {
1300dfda9d88SJean-Jacques Hiblot 		debug("No ext_csd found!\n"); /* this should enver happen */
1301dfda9d88SJean-Jacques Hiblot 		return -ENOTSUPP;
1302dfda9d88SJean-Jacques Hiblot 	}
1303dfda9d88SJean-Jacques Hiblot 
13048ac8a263SJean-Jacques Hiblot 	for (idx = 0; idx < ARRAY_SIZE(ext_csd_bits); idx++) {
13058ac8a263SJean-Jacques Hiblot 		unsigned int extw = ext_csd_bits[idx];
13068ac8a263SJean-Jacques Hiblot 		unsigned int caps = ext_to_hostcaps[extw];
13078ac8a263SJean-Jacques Hiblot 		/*
13088ac8a263SJean-Jacques Hiblot 		 * If the bus width is still not changed,
13098ac8a263SJean-Jacques Hiblot 		 * don't try to set the default again.
13108ac8a263SJean-Jacques Hiblot 		 * Otherwise, recover from switch attempts
13118ac8a263SJean-Jacques Hiblot 		 * by switching to 1-bit bus width.
13128ac8a263SJean-Jacques Hiblot 		 */
13138ac8a263SJean-Jacques Hiblot 		if (extw == EXT_CSD_BUS_WIDTH_1 &&
13148ac8a263SJean-Jacques Hiblot 		    mmc->bus_width == 1) {
13158ac8a263SJean-Jacques Hiblot 			err = 0;
13168ac8a263SJean-Jacques Hiblot 			break;
13178ac8a263SJean-Jacques Hiblot 		}
13188ac8a263SJean-Jacques Hiblot 
13198ac8a263SJean-Jacques Hiblot 		/*
13208ac8a263SJean-Jacques Hiblot 		 * Check to make sure the card and controller support
13218ac8a263SJean-Jacques Hiblot 		 * these capabilities
13228ac8a263SJean-Jacques Hiblot 		 */
13238ac8a263SJean-Jacques Hiblot 		if ((mmc->card_caps & caps) != caps)
13248ac8a263SJean-Jacques Hiblot 			continue;
13258ac8a263SJean-Jacques Hiblot 
13268ac8a263SJean-Jacques Hiblot 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
13278ac8a263SJean-Jacques Hiblot 				 EXT_CSD_BUS_WIDTH, extw);
13288ac8a263SJean-Jacques Hiblot 
13298ac8a263SJean-Jacques Hiblot 		if (err)
13308ac8a263SJean-Jacques Hiblot 			continue;
13318ac8a263SJean-Jacques Hiblot 
13328ac8a263SJean-Jacques Hiblot 		mmc->ddr_mode = (caps & MMC_MODE_DDR_52MHz) ? 1 : 0;
13338ac8a263SJean-Jacques Hiblot 		mmc_set_bus_width(mmc, widths[idx]);
13348ac8a263SJean-Jacques Hiblot 
13357382e691SJean-Jacques Hiblot 		err = mmc_read_and_compare_ext_csd(mmc);
13367382e691SJean-Jacques Hiblot 		if (!err)
13378ac8a263SJean-Jacques Hiblot 			break;
13388ac8a263SJean-Jacques Hiblot 	}
13398ac8a263SJean-Jacques Hiblot 
13408ac8a263SJean-Jacques Hiblot 	if (err)
13418ac8a263SJean-Jacques Hiblot 		return err;
13428ac8a263SJean-Jacques Hiblot 
134335f9e196SJean-Jacques Hiblot 	if (mmc->card_caps & MMC_MODE_HS_52MHz) {
134435f9e196SJean-Jacques Hiblot 		if (mmc->ddr_mode)
134535f9e196SJean-Jacques Hiblot 			mmc_select_mode(mmc, MMC_DDR_52);
13468ac8a263SJean-Jacques Hiblot 		else
134735f9e196SJean-Jacques Hiblot 			mmc_select_mode(mmc, MMC_HS_52);
1348*05038576SJean-Jacques Hiblot 	} else if (mmc->card_caps & MMC_MODE_HS)
134935f9e196SJean-Jacques Hiblot 		mmc_select_mode(mmc, MMC_HS);
13508ac8a263SJean-Jacques Hiblot 
13518ac8a263SJean-Jacques Hiblot 	return err;
13528ac8a263SJean-Jacques Hiblot }
13538ac8a263SJean-Jacques Hiblot 
1354dfda9d88SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc)
1355c744b6f6SJean-Jacques Hiblot {
1356c744b6f6SJean-Jacques Hiblot 	int err, i;
1357c744b6f6SJean-Jacques Hiblot 	u64 capacity;
1358c744b6f6SJean-Jacques Hiblot 	bool has_parts = false;
1359c744b6f6SJean-Jacques Hiblot 	bool part_completed;
1360dfda9d88SJean-Jacques Hiblot 	u8 *ext_csd;
1361c744b6f6SJean-Jacques Hiblot 
1362c744b6f6SJean-Jacques Hiblot 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4))
1363c744b6f6SJean-Jacques Hiblot 		return 0;
1364c744b6f6SJean-Jacques Hiblot 
1365dfda9d88SJean-Jacques Hiblot 	ext_csd = malloc_cache_aligned(MMC_MAX_BLOCK_LEN);
1366dfda9d88SJean-Jacques Hiblot 	if (!ext_csd)
1367dfda9d88SJean-Jacques Hiblot 		return -ENOMEM;
1368dfda9d88SJean-Jacques Hiblot 
1369dfda9d88SJean-Jacques Hiblot 	mmc->ext_csd = ext_csd;
1370dfda9d88SJean-Jacques Hiblot 
1371c744b6f6SJean-Jacques Hiblot 	/* check  ext_csd version and capacity */
1372c744b6f6SJean-Jacques Hiblot 	err = mmc_send_ext_csd(mmc, ext_csd);
1373c744b6f6SJean-Jacques Hiblot 	if (err)
1374c744b6f6SJean-Jacques Hiblot 		return err;
1375c744b6f6SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_REV] >= 2) {
1376c744b6f6SJean-Jacques Hiblot 		/*
1377c744b6f6SJean-Jacques Hiblot 		 * According to the JEDEC Standard, the value of
1378c744b6f6SJean-Jacques Hiblot 		 * ext_csd's capacity is valid if the value is more
1379c744b6f6SJean-Jacques Hiblot 		 * than 2GB
1380c744b6f6SJean-Jacques Hiblot 		 */
1381c744b6f6SJean-Jacques Hiblot 		capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
1382c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
1383c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
1384c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
1385c744b6f6SJean-Jacques Hiblot 		capacity *= MMC_MAX_BLOCK_LEN;
1386c744b6f6SJean-Jacques Hiblot 		if ((capacity >> 20) > 2 * 1024)
1387c744b6f6SJean-Jacques Hiblot 			mmc->capacity_user = capacity;
1388c744b6f6SJean-Jacques Hiblot 	}
1389c744b6f6SJean-Jacques Hiblot 
1390c744b6f6SJean-Jacques Hiblot 	switch (ext_csd[EXT_CSD_REV]) {
1391c744b6f6SJean-Jacques Hiblot 	case 1:
1392c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_1;
1393c744b6f6SJean-Jacques Hiblot 		break;
1394c744b6f6SJean-Jacques Hiblot 	case 2:
1395c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_2;
1396c744b6f6SJean-Jacques Hiblot 		break;
1397c744b6f6SJean-Jacques Hiblot 	case 3:
1398c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_3;
1399c744b6f6SJean-Jacques Hiblot 		break;
1400c744b6f6SJean-Jacques Hiblot 	case 5:
1401c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_41;
1402c744b6f6SJean-Jacques Hiblot 		break;
1403c744b6f6SJean-Jacques Hiblot 	case 6:
1404c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_5;
1405c744b6f6SJean-Jacques Hiblot 		break;
1406c744b6f6SJean-Jacques Hiblot 	case 7:
1407c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_5_0;
1408c744b6f6SJean-Jacques Hiblot 		break;
1409c744b6f6SJean-Jacques Hiblot 	case 8:
1410c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_5_1;
1411c744b6f6SJean-Jacques Hiblot 		break;
1412c744b6f6SJean-Jacques Hiblot 	}
1413c744b6f6SJean-Jacques Hiblot 
1414c744b6f6SJean-Jacques Hiblot 	/* The partition data may be non-zero but it is only
1415c744b6f6SJean-Jacques Hiblot 	 * effective if PARTITION_SETTING_COMPLETED is set in
1416c744b6f6SJean-Jacques Hiblot 	 * EXT_CSD, so ignore any data if this bit is not set,
1417c744b6f6SJean-Jacques Hiblot 	 * except for enabling the high-capacity group size
1418c744b6f6SJean-Jacques Hiblot 	 * definition (see below).
1419c744b6f6SJean-Jacques Hiblot 	 */
1420c744b6f6SJean-Jacques Hiblot 	part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
1421c744b6f6SJean-Jacques Hiblot 			    EXT_CSD_PARTITION_SETTING_COMPLETED);
1422c744b6f6SJean-Jacques Hiblot 
1423c744b6f6SJean-Jacques Hiblot 	/* store the partition info of emmc */
1424c744b6f6SJean-Jacques Hiblot 	mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
1425c744b6f6SJean-Jacques Hiblot 	if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
1426c744b6f6SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_BOOT_MULT])
1427c744b6f6SJean-Jacques Hiblot 		mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
1428c744b6f6SJean-Jacques Hiblot 	if (part_completed &&
1429c744b6f6SJean-Jacques Hiblot 	    (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
1430c744b6f6SJean-Jacques Hiblot 		mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
1431c744b6f6SJean-Jacques Hiblot 
1432c744b6f6SJean-Jacques Hiblot 	mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
1433c744b6f6SJean-Jacques Hiblot 
1434c744b6f6SJean-Jacques Hiblot 	mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
1435c744b6f6SJean-Jacques Hiblot 
1436c744b6f6SJean-Jacques Hiblot 	for (i = 0; i < 4; i++) {
1437c744b6f6SJean-Jacques Hiblot 		int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
1438c744b6f6SJean-Jacques Hiblot 		uint mult = (ext_csd[idx + 2] << 16) +
1439c744b6f6SJean-Jacques Hiblot 			(ext_csd[idx + 1] << 8) + ext_csd[idx];
1440c744b6f6SJean-Jacques Hiblot 		if (mult)
1441c744b6f6SJean-Jacques Hiblot 			has_parts = true;
1442c744b6f6SJean-Jacques Hiblot 		if (!part_completed)
1443c744b6f6SJean-Jacques Hiblot 			continue;
1444c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] = mult;
1445c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] *=
1446c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1447c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1448c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] <<= 19;
1449c744b6f6SJean-Jacques Hiblot 	}
1450c744b6f6SJean-Jacques Hiblot 
1451c744b6f6SJean-Jacques Hiblot 	if (part_completed) {
1452c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size =
1453c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) +
1454c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) +
1455c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_ENH_SIZE_MULT];
1456c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1457c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1458c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size <<= 19;
1459c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_start =
1460c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) +
1461c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) +
1462c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) +
1463c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_ENH_START_ADDR];
1464c744b6f6SJean-Jacques Hiblot 		if (mmc->high_capacity)
1465c744b6f6SJean-Jacques Hiblot 			mmc->enh_user_start <<= 9;
1466c744b6f6SJean-Jacques Hiblot 	}
1467c744b6f6SJean-Jacques Hiblot 
1468c744b6f6SJean-Jacques Hiblot 	/*
1469c744b6f6SJean-Jacques Hiblot 	 * Host needs to enable ERASE_GRP_DEF bit if device is
1470c744b6f6SJean-Jacques Hiblot 	 * partitioned. This bit will be lost every time after a reset
1471c744b6f6SJean-Jacques Hiblot 	 * or power off. This will affect erase size.
1472c744b6f6SJean-Jacques Hiblot 	 */
1473c744b6f6SJean-Jacques Hiblot 	if (part_completed)
1474c744b6f6SJean-Jacques Hiblot 		has_parts = true;
1475c744b6f6SJean-Jacques Hiblot 	if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
1476c744b6f6SJean-Jacques Hiblot 	    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
1477c744b6f6SJean-Jacques Hiblot 		has_parts = true;
1478c744b6f6SJean-Jacques Hiblot 	if (has_parts) {
1479c744b6f6SJean-Jacques Hiblot 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1480c744b6f6SJean-Jacques Hiblot 				 EXT_CSD_ERASE_GROUP_DEF, 1);
1481c744b6f6SJean-Jacques Hiblot 
1482c744b6f6SJean-Jacques Hiblot 		if (err)
1483c744b6f6SJean-Jacques Hiblot 			return err;
1484c744b6f6SJean-Jacques Hiblot 
1485c744b6f6SJean-Jacques Hiblot 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1486c744b6f6SJean-Jacques Hiblot 	}
1487c744b6f6SJean-Jacques Hiblot 
1488c744b6f6SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
1489c744b6f6SJean-Jacques Hiblot 		/* Read out group size from ext_csd */
1490c744b6f6SJean-Jacques Hiblot 		mmc->erase_grp_size =
1491c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1492c744b6f6SJean-Jacques Hiblot 		/*
1493c744b6f6SJean-Jacques Hiblot 		 * if high capacity and partition setting completed
1494c744b6f6SJean-Jacques Hiblot 		 * SEC_COUNT is valid even if it is smaller than 2 GiB
1495c744b6f6SJean-Jacques Hiblot 		 * JEDEC Standard JESD84-B45, 6.2.4
1496c744b6f6SJean-Jacques Hiblot 		 */
1497c744b6f6SJean-Jacques Hiblot 		if (mmc->high_capacity && part_completed) {
1498c744b6f6SJean-Jacques Hiblot 			capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
1499c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
1500c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
1501c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
1502c744b6f6SJean-Jacques Hiblot 			capacity *= MMC_MAX_BLOCK_LEN;
1503c744b6f6SJean-Jacques Hiblot 			mmc->capacity_user = capacity;
1504c744b6f6SJean-Jacques Hiblot 		}
1505c744b6f6SJean-Jacques Hiblot 	} else {
1506c744b6f6SJean-Jacques Hiblot 		/* Calculate the group size from the csd value. */
1507c744b6f6SJean-Jacques Hiblot 		int erase_gsz, erase_gmul;
1508c744b6f6SJean-Jacques Hiblot 
1509c744b6f6SJean-Jacques Hiblot 		erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
1510c744b6f6SJean-Jacques Hiblot 		erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
1511c744b6f6SJean-Jacques Hiblot 		mmc->erase_grp_size = (erase_gsz + 1)
1512c744b6f6SJean-Jacques Hiblot 			* (erase_gmul + 1);
1513c744b6f6SJean-Jacques Hiblot 	}
1514c744b6f6SJean-Jacques Hiblot 
1515c744b6f6SJean-Jacques Hiblot 	mmc->hc_wp_grp_size = 1024
1516c744b6f6SJean-Jacques Hiblot 		* ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
1517c744b6f6SJean-Jacques Hiblot 		* ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1518c744b6f6SJean-Jacques Hiblot 
1519c744b6f6SJean-Jacques Hiblot 	mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
1520c744b6f6SJean-Jacques Hiblot 
1521c744b6f6SJean-Jacques Hiblot 	return 0;
1522c744b6f6SJean-Jacques Hiblot }
1523c744b6f6SJean-Jacques Hiblot 
1524fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc)
1525272cc70bSAndy Fleming {
1526f866a46dSStephen Warren 	int err, i;
1527272cc70bSAndy Fleming 	uint mult, freq;
1528c744b6f6SJean-Jacques Hiblot 	u64 cmult, csize;
1529272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1530c40fdca6SSimon Glass 	struct blk_desc *bdesc;
1531272cc70bSAndy Fleming 
1532d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
1533d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
1534d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
1535d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
1536d52ebf10SThomas Chou 		cmd.cmdarg = 1;
1537d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
1538d52ebf10SThomas Chou 
1539d52ebf10SThomas Chou 		if (err)
1540d52ebf10SThomas Chou 			return err;
1541d52ebf10SThomas Chou 	}
1542d52ebf10SThomas Chou #endif
1543d52ebf10SThomas Chou 
1544272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
1545d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
1546d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
1547272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1548272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1549272cc70bSAndy Fleming 
1550272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1551272cc70bSAndy Fleming 
1552272cc70bSAndy Fleming 	if (err)
1553272cc70bSAndy Fleming 		return err;
1554272cc70bSAndy Fleming 
1555272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
1556272cc70bSAndy Fleming 
1557272cc70bSAndy Fleming 	/*
1558272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
1559272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
1560272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
1561272cc70bSAndy Fleming 	 */
1562d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1563272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
1564272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1565272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
1566272cc70bSAndy Fleming 
1567272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1568272cc70bSAndy Fleming 
1569272cc70bSAndy Fleming 		if (err)
1570272cc70bSAndy Fleming 			return err;
1571272cc70bSAndy Fleming 
1572272cc70bSAndy Fleming 		if (IS_SD(mmc))
1573998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
1574d52ebf10SThomas Chou 	}
1575272cc70bSAndy Fleming 
1576272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
1577272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
1578272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1579272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1580272cc70bSAndy Fleming 
1581272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1582272cc70bSAndy Fleming 
1583272cc70bSAndy Fleming 	if (err)
1584272cc70bSAndy Fleming 		return err;
1585272cc70bSAndy Fleming 
1586998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
1587998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
1588998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
1589998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
1590272cc70bSAndy Fleming 
1591272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
15920b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
1593272cc70bSAndy Fleming 
1594272cc70bSAndy Fleming 		switch (version) {
1595272cc70bSAndy Fleming 		case 0:
1596272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1597272cc70bSAndy Fleming 			break;
1598272cc70bSAndy Fleming 		case 1:
1599272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_4;
1600272cc70bSAndy Fleming 			break;
1601272cc70bSAndy Fleming 		case 2:
1602272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_2_2;
1603272cc70bSAndy Fleming 			break;
1604272cc70bSAndy Fleming 		case 3:
1605272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_3;
1606272cc70bSAndy Fleming 			break;
1607272cc70bSAndy Fleming 		case 4:
1608272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_4;
1609272cc70bSAndy Fleming 			break;
1610272cc70bSAndy Fleming 		default:
1611272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1612272cc70bSAndy Fleming 			break;
1613272cc70bSAndy Fleming 		}
1614272cc70bSAndy Fleming 	}
1615272cc70bSAndy Fleming 
1616272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
16170b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
16180b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
1619272cc70bSAndy Fleming 
162035f9e196SJean-Jacques Hiblot 	mmc->legacy_speed = freq * mult;
162135f9e196SJean-Jacques Hiblot 	mmc_select_mode(mmc, MMC_LEGACY);
1622272cc70bSAndy Fleming 
1623ab71188cSMarkus Niebel 	mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
1624998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
1625272cc70bSAndy Fleming 
1626272cc70bSAndy Fleming 	if (IS_SD(mmc))
1627272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
1628272cc70bSAndy Fleming 	else
1629998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
1630272cc70bSAndy Fleming 
1631272cc70bSAndy Fleming 	if (mmc->high_capacity) {
1632272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
1633272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
1634272cc70bSAndy Fleming 		cmult = 8;
1635272cc70bSAndy Fleming 	} else {
1636272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
1637272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
1638272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
1639272cc70bSAndy Fleming 	}
1640272cc70bSAndy Fleming 
1641f866a46dSStephen Warren 	mmc->capacity_user = (csize + 1) << (cmult + 2);
1642f866a46dSStephen Warren 	mmc->capacity_user *= mmc->read_bl_len;
1643f866a46dSStephen Warren 	mmc->capacity_boot = 0;
1644f866a46dSStephen Warren 	mmc->capacity_rpmb = 0;
1645f866a46dSStephen Warren 	for (i = 0; i < 4; i++)
1646f866a46dSStephen Warren 		mmc->capacity_gp[i] = 0;
1647272cc70bSAndy Fleming 
16488bfa195eSSimon Glass 	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
16498bfa195eSSimon Glass 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
1650272cc70bSAndy Fleming 
16518bfa195eSSimon Glass 	if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
16528bfa195eSSimon Glass 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
1653272cc70bSAndy Fleming 
1654ab71188cSMarkus Niebel 	if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
1655ab71188cSMarkus Niebel 		cmd.cmdidx = MMC_CMD_SET_DSR;
1656ab71188cSMarkus Niebel 		cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
1657ab71188cSMarkus Niebel 		cmd.resp_type = MMC_RSP_NONE;
1658ab71188cSMarkus Niebel 		if (mmc_send_cmd(mmc, &cmd, NULL))
1659ab71188cSMarkus Niebel 			printf("MMC: SET_DSR failed\n");
1660ab71188cSMarkus Niebel 	}
1661ab71188cSMarkus Niebel 
1662272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
1663d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1664272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
1665fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
1666272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1667272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1668272cc70bSAndy Fleming 
1669272cc70bSAndy Fleming 		if (err)
1670272cc70bSAndy Fleming 			return err;
1671d52ebf10SThomas Chou 	}
1672272cc70bSAndy Fleming 
1673e6f99a56SLei Wen 	/*
1674e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
1675e6f99a56SLei Wen 	 */
1676e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
1677bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
1678c744b6f6SJean-Jacques Hiblot 
1679dfda9d88SJean-Jacques Hiblot 	err = mmc_startup_v4(mmc);
16809cf199ebSDiego Santa Cruz 	if (err)
16819cf199ebSDiego Santa Cruz 		return err;
1682f866a46dSStephen Warren 
1683c40fdca6SSimon Glass 	err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart);
1684f866a46dSStephen Warren 	if (err)
1685f866a46dSStephen Warren 		return err;
1686d23e2c09SSukumar Ghorai 
1687272cc70bSAndy Fleming 	if (IS_SD(mmc))
16888ac8a263SJean-Jacques Hiblot 		err = sd_select_bus_freq_width(mmc);
1689272cc70bSAndy Fleming 	else
1690dfda9d88SJean-Jacques Hiblot 		err = mmc_select_bus_freq_width(mmc);
1691272cc70bSAndy Fleming 
1692272cc70bSAndy Fleming 	if (err)
1693272cc70bSAndy Fleming 		return err;
1694272cc70bSAndy Fleming 
1695272cc70bSAndy Fleming 
16965af8f45cSAndrew Gabbasov 	/* Fix the block length for DDR mode */
16975af8f45cSAndrew Gabbasov 	if (mmc->ddr_mode) {
16985af8f45cSAndrew Gabbasov 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
16995af8f45cSAndrew Gabbasov 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
17005af8f45cSAndrew Gabbasov 	}
17015af8f45cSAndrew Gabbasov 
1702272cc70bSAndy Fleming 	/* fill in device description */
1703c40fdca6SSimon Glass 	bdesc = mmc_get_blk_desc(mmc);
1704c40fdca6SSimon Glass 	bdesc->lun = 0;
1705c40fdca6SSimon Glass 	bdesc->hwpart = 0;
1706c40fdca6SSimon Glass 	bdesc->type = 0;
1707c40fdca6SSimon Glass 	bdesc->blksz = mmc->read_bl_len;
1708c40fdca6SSimon Glass 	bdesc->log2blksz = LOG2(bdesc->blksz);
1709c40fdca6SSimon Glass 	bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len);
1710fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \
1711fc011f64SSjoerd Simons 		(defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \
1712fc011f64SSjoerd Simons 		!defined(CONFIG_USE_TINY_PRINTF))
1713c40fdca6SSimon Glass 	sprintf(bdesc->vendor, "Man %06x Snr %04x%04x",
1714babce5f6STaylor Hutt 		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
1715babce5f6STaylor Hutt 		(mmc->cid[3] >> 16) & 0xffff);
1716c40fdca6SSimon Glass 	sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
17170b453ffeSRabin Vincent 		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
1718babce5f6STaylor Hutt 		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
1719babce5f6STaylor Hutt 		(mmc->cid[2] >> 24) & 0xff);
1720c40fdca6SSimon Glass 	sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
1721babce5f6STaylor Hutt 		(mmc->cid[2] >> 16) & 0xf);
172256196826SPaul Burton #else
1723c40fdca6SSimon Glass 	bdesc->vendor[0] = 0;
1724c40fdca6SSimon Glass 	bdesc->product[0] = 0;
1725c40fdca6SSimon Glass 	bdesc->revision[0] = 0;
172656196826SPaul Burton #endif
1727122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
1728c40fdca6SSimon Glass 	part_init(bdesc);
1729122efd43SMikhail Kshevetskiy #endif
1730272cc70bSAndy Fleming 
1731272cc70bSAndy Fleming 	return 0;
1732272cc70bSAndy Fleming }
1733272cc70bSAndy Fleming 
1734fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc)
1735272cc70bSAndy Fleming {
1736272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1737272cc70bSAndy Fleming 	int err;
1738272cc70bSAndy Fleming 
1739272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
1740272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
174193bfd616SPantelis Antoniou 	cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa;
1742272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
1743272cc70bSAndy Fleming 
1744272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1745272cc70bSAndy Fleming 
1746272cc70bSAndy Fleming 	if (err)
1747272cc70bSAndy Fleming 		return err;
1748272cc70bSAndy Fleming 
1749998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
1750915ffa52SJaehoon Chung 		return -EOPNOTSUPP;
1751272cc70bSAndy Fleming 	else
1752272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
1753272cc70bSAndy Fleming 
1754272cc70bSAndy Fleming 	return 0;
1755272cc70bSAndy Fleming }
1756272cc70bSAndy Fleming 
1757c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
175895de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */
175995de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void)
176095de9ab2SPaul Kocialkowski {
176195de9ab2SPaul Kocialkowski }
176205cbeb7cSSimon Glass #endif
176395de9ab2SPaul Kocialkowski 
17642051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc)
17652051aefeSPeng Fan {
1766c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
176706ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR)
17682051aefeSPeng Fan 	int ret;
17692051aefeSPeng Fan 
17702051aefeSPeng Fan 	ret = device_get_supply_regulator(mmc->dev, "vmmc-supply",
177106ec045fSJean-Jacques Hiblot 					  &mmc->vmmc_supply);
177206ec045fSJean-Jacques Hiblot 	if (ret)
1773288db7c7SJaehoon Chung 		debug("%s: No vmmc supply\n", mmc->dev->name);
17742051aefeSPeng Fan 
177506ec045fSJean-Jacques Hiblot 	ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply",
177606ec045fSJean-Jacques Hiblot 					  &mmc->vqmmc_supply);
177706ec045fSJean-Jacques Hiblot 	if (ret)
177806ec045fSJean-Jacques Hiblot 		debug("%s: No vqmmc supply\n", mmc->dev->name);
177906ec045fSJean-Jacques Hiblot 
178006ec045fSJean-Jacques Hiblot 	if (mmc->vmmc_supply) {
178106ec045fSJean-Jacques Hiblot 		ret = regulator_set_enable(mmc->vmmc_supply, true);
17822051aefeSPeng Fan 		if (ret) {
17832051aefeSPeng Fan 			puts("Error enabling VMMC supply\n");
17842051aefeSPeng Fan 			return ret;
17852051aefeSPeng Fan 		}
178606ec045fSJean-Jacques Hiblot 	}
17872051aefeSPeng Fan #endif
178805cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */
178905cbeb7cSSimon Glass 	/*
179005cbeb7cSSimon Glass 	 * Driver model should use a regulator, as above, rather than calling
179105cbeb7cSSimon Glass 	 * out to board code.
179205cbeb7cSSimon Glass 	 */
179305cbeb7cSSimon Glass 	board_mmc_power_init();
179405cbeb7cSSimon Glass #endif
17952051aefeSPeng Fan 	return 0;
17962051aefeSPeng Fan }
17972051aefeSPeng Fan 
1798e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc)
1799272cc70bSAndy Fleming {
18008ca51e51SSimon Glass 	bool no_card;
1801afd5932bSMacpaul Lin 	int err;
1802272cc70bSAndy Fleming 
1803ab769f22SPantelis Antoniou 	/* we pretend there's no card when init is NULL */
18048ca51e51SSimon Glass 	no_card = mmc_getcd(mmc) == 0;
1805e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
18068ca51e51SSimon Glass 	no_card = no_card || (mmc->cfg->ops->init == NULL);
18078ca51e51SSimon Glass #endif
18088ca51e51SSimon Glass 	if (no_card) {
180948972d90SThierry Reding 		mmc->has_init = 0;
181056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
181148972d90SThierry Reding 		printf("MMC: no card present\n");
181256196826SPaul Burton #endif
1813915ffa52SJaehoon Chung 		return -ENOMEDIUM;
181448972d90SThierry Reding 	}
181548972d90SThierry Reding 
1816bc897b1dSLei Wen 	if (mmc->has_init)
1817bc897b1dSLei Wen 		return 0;
1818bc897b1dSLei Wen 
18195a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
18205a8dbdc6SYangbo Lu 	mmc_adapter_card_type_ident();
18215a8dbdc6SYangbo Lu #endif
18222051aefeSPeng Fan 	err = mmc_power_init(mmc);
18232051aefeSPeng Fan 	if (err)
18242051aefeSPeng Fan 		return err;
182595de9ab2SPaul Kocialkowski 
1826e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
18278ca51e51SSimon Glass 	/* The device has already been probed ready for use */
18288ca51e51SSimon Glass #else
1829ab769f22SPantelis Antoniou 	/* made sure it's not NULL earlier */
183093bfd616SPantelis Antoniou 	err = mmc->cfg->ops->init(mmc);
1831272cc70bSAndy Fleming 	if (err)
1832272cc70bSAndy Fleming 		return err;
18338ca51e51SSimon Glass #endif
1834786e8f81SAndrew Gabbasov 	mmc->ddr_mode = 0;
1835b86b85e2SIlya Yanok 	mmc_set_bus_width(mmc, 1);
1836b86b85e2SIlya Yanok 	mmc_set_clock(mmc, 1);
1837b86b85e2SIlya Yanok 
1838272cc70bSAndy Fleming 	/* Reset the Card */
1839272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
1840272cc70bSAndy Fleming 
1841272cc70bSAndy Fleming 	if (err)
1842272cc70bSAndy Fleming 		return err;
1843272cc70bSAndy Fleming 
1844bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
1845c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->hwpart = 0;
1846bc897b1dSLei Wen 
1847272cc70bSAndy Fleming 	/* Test for SD version 2 */
1848272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
1849272cc70bSAndy Fleming 
1850272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
1851272cc70bSAndy Fleming 	err = sd_send_op_cond(mmc);
1852272cc70bSAndy Fleming 
1853272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
1854915ffa52SJaehoon Chung 	if (err == -ETIMEDOUT) {
1855272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
1856272cc70bSAndy Fleming 
1857bd47c135SAndrew Gabbasov 		if (err) {
185856196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
1859272cc70bSAndy Fleming 			printf("Card did not respond to voltage select!\n");
186056196826SPaul Burton #endif
1861915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
1862272cc70bSAndy Fleming 		}
1863272cc70bSAndy Fleming 	}
1864272cc70bSAndy Fleming 
1865bd47c135SAndrew Gabbasov 	if (!err)
1866e9550449SChe-Liang Chiou 		mmc->init_in_progress = 1;
1867e9550449SChe-Liang Chiou 
1868e9550449SChe-Liang Chiou 	return err;
1869e9550449SChe-Liang Chiou }
1870e9550449SChe-Liang Chiou 
1871e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc)
1872e9550449SChe-Liang Chiou {
1873e9550449SChe-Liang Chiou 	int err = 0;
1874e9550449SChe-Liang Chiou 
1875bd47c135SAndrew Gabbasov 	mmc->init_in_progress = 0;
1876e9550449SChe-Liang Chiou 	if (mmc->op_cond_pending)
1877e9550449SChe-Liang Chiou 		err = mmc_complete_op_cond(mmc);
1878e9550449SChe-Liang Chiou 
1879e9550449SChe-Liang Chiou 	if (!err)
1880bc897b1dSLei Wen 		err = mmc_startup(mmc);
1881bc897b1dSLei Wen 	if (err)
1882bc897b1dSLei Wen 		mmc->has_init = 0;
1883bc897b1dSLei Wen 	else
1884bc897b1dSLei Wen 		mmc->has_init = 1;
1885e9550449SChe-Liang Chiou 	return err;
1886e9550449SChe-Liang Chiou }
1887e9550449SChe-Liang Chiou 
1888e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc)
1889e9550449SChe-Liang Chiou {
1890bd47c135SAndrew Gabbasov 	int err = 0;
1891ce9eca94SMarek Vasut 	__maybe_unused unsigned start;
1892c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
189333fb211dSSimon Glass 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev);
1894e9550449SChe-Liang Chiou 
189533fb211dSSimon Glass 	upriv->mmc = mmc;
189633fb211dSSimon Glass #endif
1897e9550449SChe-Liang Chiou 	if (mmc->has_init)
1898e9550449SChe-Liang Chiou 		return 0;
1899d803fea5SMateusz Zalega 
1900d803fea5SMateusz Zalega 	start = get_timer(0);
1901d803fea5SMateusz Zalega 
1902e9550449SChe-Liang Chiou 	if (!mmc->init_in_progress)
1903e9550449SChe-Liang Chiou 		err = mmc_start_init(mmc);
1904e9550449SChe-Liang Chiou 
1905bd47c135SAndrew Gabbasov 	if (!err)
1906e9550449SChe-Liang Chiou 		err = mmc_complete_init(mmc);
1907919b4858SJagan Teki 	if (err)
1908919b4858SJagan Teki 		printf("%s: %d, time %lu\n", __func__, err, get_timer(start));
1909919b4858SJagan Teki 
1910bc897b1dSLei Wen 	return err;
1911272cc70bSAndy Fleming }
1912272cc70bSAndy Fleming 
1913ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val)
1914ab71188cSMarkus Niebel {
1915ab71188cSMarkus Niebel 	mmc->dsr = val;
1916ab71188cSMarkus Niebel 	return 0;
1917ab71188cSMarkus Niebel }
1918ab71188cSMarkus Niebel 
1919cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */
1920cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis)
1921272cc70bSAndy Fleming {
1922272cc70bSAndy Fleming 	return -1;
1923272cc70bSAndy Fleming }
1924272cc70bSAndy Fleming 
1925cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */
1926cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis)
1927cee9ab7cSJeroen Hofstee {
1928cee9ab7cSJeroen Hofstee 	return -1;
1929cee9ab7cSJeroen Hofstee }
1930272cc70bSAndy Fleming 
1931e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit)
1932e9550449SChe-Liang Chiou {
1933e9550449SChe-Liang Chiou 	mmc->preinit = preinit;
1934e9550449SChe-Liang Chiou }
1935e9550449SChe-Liang Chiou 
1936c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD)
19378e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
19388e3332e2SSjoerd Simons {
19398e3332e2SSjoerd Simons 	return 0;
19408e3332e2SSjoerd Simons }
1941c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC)
19428e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
19438e3332e2SSjoerd Simons {
19444a1db6d8SSimon Glass 	int ret, i;
19458e3332e2SSjoerd Simons 	struct uclass *uc;
19464a1db6d8SSimon Glass 	struct udevice *dev;
19478e3332e2SSjoerd Simons 
19488e3332e2SSjoerd Simons 	ret = uclass_get(UCLASS_MMC, &uc);
19498e3332e2SSjoerd Simons 	if (ret)
19508e3332e2SSjoerd Simons 		return ret;
19518e3332e2SSjoerd Simons 
19524a1db6d8SSimon Glass 	/*
19534a1db6d8SSimon Glass 	 * Try to add them in sequence order. Really with driver model we
19544a1db6d8SSimon Glass 	 * should allow holes, but the current MMC list does not allow that.
19554a1db6d8SSimon Glass 	 * So if we request 0, 1, 3 we will get 0, 1, 2.
19564a1db6d8SSimon Glass 	 */
19574a1db6d8SSimon Glass 	for (i = 0; ; i++) {
19584a1db6d8SSimon Glass 		ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev);
19594a1db6d8SSimon Glass 		if (ret == -ENODEV)
19604a1db6d8SSimon Glass 			break;
19614a1db6d8SSimon Glass 	}
19624a1db6d8SSimon Glass 	uclass_foreach_dev(dev, uc) {
19634a1db6d8SSimon Glass 		ret = device_probe(dev);
19648e3332e2SSjoerd Simons 		if (ret)
19654a1db6d8SSimon Glass 			printf("%s - probe failed: %d\n", dev->name, ret);
19668e3332e2SSjoerd Simons 	}
19678e3332e2SSjoerd Simons 
19688e3332e2SSjoerd Simons 	return 0;
19698e3332e2SSjoerd Simons }
19708e3332e2SSjoerd Simons #else
19718e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
19728e3332e2SSjoerd Simons {
19738e3332e2SSjoerd Simons 	if (board_mmc_init(bis) < 0)
19748e3332e2SSjoerd Simons 		cpu_mmc_init(bis);
19758e3332e2SSjoerd Simons 
19768e3332e2SSjoerd Simons 	return 0;
19778e3332e2SSjoerd Simons }
19788e3332e2SSjoerd Simons #endif
1979e9550449SChe-Liang Chiou 
1980272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
1981272cc70bSAndy Fleming {
19821b26bab1SDaniel Kochmański 	static int initialized = 0;
19838e3332e2SSjoerd Simons 	int ret;
19841b26bab1SDaniel Kochmański 	if (initialized)	/* Avoid initializing mmc multiple times */
19851b26bab1SDaniel Kochmański 		return 0;
19861b26bab1SDaniel Kochmański 	initialized = 1;
19871b26bab1SDaniel Kochmański 
1988c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK)
1989b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY)
1990c40fdca6SSimon Glass 	mmc_list_init();
1991c40fdca6SSimon Glass #endif
1992b5b838f1SMarek Vasut #endif
19938e3332e2SSjoerd Simons 	ret = mmc_probe(bis);
19948e3332e2SSjoerd Simons 	if (ret)
19958e3332e2SSjoerd Simons 		return ret;
1996272cc70bSAndy Fleming 
1997bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD
1998272cc70bSAndy Fleming 	print_mmc_devices(',');
1999bb0dc108SYing Zhang #endif
2000272cc70bSAndy Fleming 
2001c40fdca6SSimon Glass 	mmc_do_preinit();
2002272cc70bSAndy Fleming 	return 0;
2003272cc70bSAndy Fleming }
2004cd3d4880STomas Melin 
2005cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE
2006cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc)
2007cd3d4880STomas Melin {
2008cd3d4880STomas Melin 	int err;
2009cd3d4880STomas Melin 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
2010cd3d4880STomas Melin 
2011cd3d4880STomas Melin 	err = mmc_send_ext_csd(mmc, ext_csd);
2012cd3d4880STomas Melin 	if (err) {
2013cd3d4880STomas Melin 		puts("Could not get ext_csd register values\n");
2014cd3d4880STomas Melin 		return err;
2015cd3d4880STomas Melin 	}
2016cd3d4880STomas Melin 
2017cd3d4880STomas Melin 	if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) {
2018cd3d4880STomas Melin 		puts("Background operations not supported on device\n");
2019cd3d4880STomas Melin 		return -EMEDIUMTYPE;
2020cd3d4880STomas Melin 	}
2021cd3d4880STomas Melin 
2022cd3d4880STomas Melin 	if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) {
2023cd3d4880STomas Melin 		puts("Background operations already enabled\n");
2024cd3d4880STomas Melin 		return 0;
2025cd3d4880STomas Melin 	}
2026cd3d4880STomas Melin 
2027cd3d4880STomas Melin 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1);
2028cd3d4880STomas Melin 	if (err) {
2029cd3d4880STomas Melin 		puts("Failed to enable manual background operations\n");
2030cd3d4880STomas Melin 		return err;
2031cd3d4880STomas Melin 	}
2032cd3d4880STomas Melin 
2033cd3d4880STomas Melin 	puts("Enabled manual background operations\n");
2034cd3d4880STomas Melin 
2035cd3d4880STomas Melin 	return 0;
2036cd3d4880STomas Melin }
2037cd3d4880STomas Melin #endif
2038