xref: /openbmc/u-boot/drivers/mmc/mmc.c (revision 3862b854740d296356a5cfd3146b270ad3501d97)
1272cc70bSAndy Fleming /*
2272cc70bSAndy Fleming  * Copyright 2008, Freescale Semiconductor, Inc
3272cc70bSAndy Fleming  * Andy Fleming
4272cc70bSAndy Fleming  *
5272cc70bSAndy Fleming  * Based vaguely on the Linux code
6272cc70bSAndy Fleming  *
71a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
8272cc70bSAndy Fleming  */
9272cc70bSAndy Fleming 
10272cc70bSAndy Fleming #include <config.h>
11272cc70bSAndy Fleming #include <common.h>
12272cc70bSAndy Fleming #include <command.h>
138e3332e2SSjoerd Simons #include <dm.h>
148e3332e2SSjoerd Simons #include <dm/device-internal.h>
15d4622df3SStephen Warren #include <errno.h>
16272cc70bSAndy Fleming #include <mmc.h>
17272cc70bSAndy Fleming #include <part.h>
182051aefeSPeng Fan #include <power/regulator.h>
19272cc70bSAndy Fleming #include <malloc.h>
20cf92e05cSSimon Glass #include <memalign.h>
21272cc70bSAndy Fleming #include <linux/list.h>
229b1f942cSRabin Vincent #include <div64.h>
23da61fa5fSPaul Burton #include "mmc_private.h"
24272cc70bSAndy Fleming 
253697e599SPeng Fan static const unsigned int sd_au_size[] = {
263697e599SPeng Fan 	0,		SZ_16K / 512,		SZ_32K / 512,
273697e599SPeng Fan 	SZ_64K / 512,	SZ_128K / 512,		SZ_256K / 512,
283697e599SPeng Fan 	SZ_512K / 512,	SZ_1M / 512,		SZ_2M / 512,
293697e599SPeng Fan 	SZ_4M / 512,	SZ_8M / 512,		(SZ_8M + SZ_4M) / 512,
303697e599SPeng Fan 	SZ_16M / 512,	(SZ_16M + SZ_8M) / 512,	SZ_32M / 512,	SZ_64M / 512,
313697e599SPeng Fan };
323697e599SPeng Fan 
33b5b838f1SMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY)
34b5b838f1SMarek Vasut static struct mmc mmc_static;
35b5b838f1SMarek Vasut struct mmc *find_mmc_device(int dev_num)
36b5b838f1SMarek Vasut {
37b5b838f1SMarek Vasut 	return &mmc_static;
38b5b838f1SMarek Vasut }
39b5b838f1SMarek Vasut 
40b5b838f1SMarek Vasut void mmc_do_preinit(void)
41b5b838f1SMarek Vasut {
42b5b838f1SMarek Vasut 	struct mmc *m = &mmc_static;
43b5b838f1SMarek Vasut #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
44b5b838f1SMarek Vasut 	mmc_set_preinit(m, 1);
45b5b838f1SMarek Vasut #endif
46b5b838f1SMarek Vasut 	if (m->preinit)
47b5b838f1SMarek Vasut 		mmc_start_init(m);
48b5b838f1SMarek Vasut }
49b5b838f1SMarek Vasut 
50b5b838f1SMarek Vasut struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
51b5b838f1SMarek Vasut {
52b5b838f1SMarek Vasut 	return &mmc->block_dev;
53b5b838f1SMarek Vasut }
54b5b838f1SMarek Vasut #endif
55b5b838f1SMarek Vasut 
56e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
57750121c3SJeroen Hofstee __weak int board_mmc_getwp(struct mmc *mmc)
58d23d8d7eSNikita Kiryanov {
59d23d8d7eSNikita Kiryanov 	return -1;
60d23d8d7eSNikita Kiryanov }
61d23d8d7eSNikita Kiryanov 
62d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc)
63d23d8d7eSNikita Kiryanov {
64d23d8d7eSNikita Kiryanov 	int wp;
65d23d8d7eSNikita Kiryanov 
66d23d8d7eSNikita Kiryanov 	wp = board_mmc_getwp(mmc);
67d23d8d7eSNikita Kiryanov 
68d4e1da4eSPeter Korsgaard 	if (wp < 0) {
6993bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getwp)
7093bfd616SPantelis Antoniou 			wp = mmc->cfg->ops->getwp(mmc);
71d4e1da4eSPeter Korsgaard 		else
72d4e1da4eSPeter Korsgaard 			wp = 0;
73d4e1da4eSPeter Korsgaard 	}
74d23d8d7eSNikita Kiryanov 
75d23d8d7eSNikita Kiryanov 	return wp;
76d23d8d7eSNikita Kiryanov }
77d23d8d7eSNikita Kiryanov 
78cee9ab7cSJeroen Hofstee __weak int board_mmc_getcd(struct mmc *mmc)
79cee9ab7cSJeroen Hofstee {
8011fdade2SStefano Babic 	return -1;
8111fdade2SStefano Babic }
828ca51e51SSimon Glass #endif
8311fdade2SStefano Babic 
848635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE
85c0c76ebaSSimon Glass void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd)
86c0c76ebaSSimon Glass {
87c0c76ebaSSimon Glass 	printf("CMD_SEND:%d\n", cmd->cmdidx);
88c0c76ebaSSimon Glass 	printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg);
89c0c76ebaSSimon Glass }
90c0c76ebaSSimon Glass 
91c0c76ebaSSimon Glass void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret)
92c0c76ebaSSimon Glass {
935db2fe3aSRaffaele Recalcati 	int i;
945db2fe3aSRaffaele Recalcati 	u8 *ptr;
955db2fe3aSRaffaele Recalcati 
967863ce58SBin Meng 	if (ret) {
977863ce58SBin Meng 		printf("\t\tRET\t\t\t %d\n", ret);
987863ce58SBin Meng 	} else {
995db2fe3aSRaffaele Recalcati 		switch (cmd->resp_type) {
1005db2fe3aSRaffaele Recalcati 		case MMC_RSP_NONE:
1015db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_NONE\n");
1025db2fe3aSRaffaele Recalcati 			break;
1035db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1:
1045db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n",
1055db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1065db2fe3aSRaffaele Recalcati 			break;
1075db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1b:
1085db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n",
1095db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1105db2fe3aSRaffaele Recalcati 			break;
1115db2fe3aSRaffaele Recalcati 		case MMC_RSP_R2:
1125db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R2\t\t 0x%08X \n",
1135db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1145db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1155db2fe3aSRaffaele Recalcati 				cmd->response[1]);
1165db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1175db2fe3aSRaffaele Recalcati 				cmd->response[2]);
1185db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1195db2fe3aSRaffaele Recalcati 				cmd->response[3]);
1205db2fe3aSRaffaele Recalcati 			printf("\n");
1215db2fe3aSRaffaele Recalcati 			printf("\t\t\t\t\tDUMPING DATA\n");
1225db2fe3aSRaffaele Recalcati 			for (i = 0; i < 4; i++) {
1235db2fe3aSRaffaele Recalcati 				int j;
1245db2fe3aSRaffaele Recalcati 				printf("\t\t\t\t\t%03d - ", i*4);
125146bec79SDirk Behme 				ptr = (u8 *)&cmd->response[i];
1265db2fe3aSRaffaele Recalcati 				ptr += 3;
1275db2fe3aSRaffaele Recalcati 				for (j = 0; j < 4; j++)
1285db2fe3aSRaffaele Recalcati 					printf("%02X ", *ptr--);
1295db2fe3aSRaffaele Recalcati 				printf("\n");
1305db2fe3aSRaffaele Recalcati 			}
1315db2fe3aSRaffaele Recalcati 			break;
1325db2fe3aSRaffaele Recalcati 		case MMC_RSP_R3:
1335db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n",
1345db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1355db2fe3aSRaffaele Recalcati 			break;
1365db2fe3aSRaffaele Recalcati 		default:
1375db2fe3aSRaffaele Recalcati 			printf("\t\tERROR MMC rsp not supported\n");
1385db2fe3aSRaffaele Recalcati 			break;
1395db2fe3aSRaffaele Recalcati 		}
1407863ce58SBin Meng 	}
141c0c76ebaSSimon Glass }
142c0c76ebaSSimon Glass 
143c0c76ebaSSimon Glass void mmc_trace_state(struct mmc *mmc, struct mmc_cmd *cmd)
144c0c76ebaSSimon Glass {
145c0c76ebaSSimon Glass 	int status;
146c0c76ebaSSimon Glass 
147c0c76ebaSSimon Glass 	status = (cmd->response[0] & MMC_STATUS_CURR_STATE) >> 9;
148c0c76ebaSSimon Glass 	printf("CURR STATE:%d\n", status);
149c0c76ebaSSimon Glass }
1505db2fe3aSRaffaele Recalcati #endif
151c0c76ebaSSimon Glass 
15235f9e196SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG)
15335f9e196SJean-Jacques Hiblot const char *mmc_mode_name(enum bus_mode mode)
15435f9e196SJean-Jacques Hiblot {
15535f9e196SJean-Jacques Hiblot 	static const char *const names[] = {
15635f9e196SJean-Jacques Hiblot 	      [MMC_LEGACY]	= "MMC legacy",
15735f9e196SJean-Jacques Hiblot 	      [SD_LEGACY]	= "SD Legacy",
15835f9e196SJean-Jacques Hiblot 	      [MMC_HS]		= "MMC High Speed (26MHz)",
15935f9e196SJean-Jacques Hiblot 	      [SD_HS]		= "SD High Speed (50MHz)",
16035f9e196SJean-Jacques Hiblot 	      [UHS_SDR12]	= "UHS SDR12 (25MHz)",
16135f9e196SJean-Jacques Hiblot 	      [UHS_SDR25]	= "UHS SDR25 (50MHz)",
16235f9e196SJean-Jacques Hiblot 	      [UHS_SDR50]	= "UHS SDR50 (100MHz)",
16335f9e196SJean-Jacques Hiblot 	      [UHS_SDR104]	= "UHS SDR104 (208MHz)",
16435f9e196SJean-Jacques Hiblot 	      [UHS_DDR50]	= "UHS DDR50 (50MHz)",
16535f9e196SJean-Jacques Hiblot 	      [MMC_HS_52]	= "MMC High Speed (52MHz)",
16635f9e196SJean-Jacques Hiblot 	      [MMC_DDR_52]	= "MMC DDR52 (52MHz)",
16735f9e196SJean-Jacques Hiblot 	      [MMC_HS_200]	= "HS200 (200MHz)",
16835f9e196SJean-Jacques Hiblot 	};
16935f9e196SJean-Jacques Hiblot 
17035f9e196SJean-Jacques Hiblot 	if (mode >= MMC_MODES_END)
17135f9e196SJean-Jacques Hiblot 		return "Unknown mode";
17235f9e196SJean-Jacques Hiblot 	else
17335f9e196SJean-Jacques Hiblot 		return names[mode];
17435f9e196SJean-Jacques Hiblot }
17535f9e196SJean-Jacques Hiblot #endif
17635f9e196SJean-Jacques Hiblot 
17705038576SJean-Jacques Hiblot static uint mmc_mode2freq(struct mmc *mmc, enum bus_mode mode)
17805038576SJean-Jacques Hiblot {
17905038576SJean-Jacques Hiblot 	static const int freqs[] = {
18005038576SJean-Jacques Hiblot 	      [SD_LEGACY]	= 25000000,
18105038576SJean-Jacques Hiblot 	      [MMC_HS]		= 26000000,
18205038576SJean-Jacques Hiblot 	      [SD_HS]		= 50000000,
18305038576SJean-Jacques Hiblot 	      [UHS_SDR12]	= 25000000,
18405038576SJean-Jacques Hiblot 	      [UHS_SDR25]	= 50000000,
18505038576SJean-Jacques Hiblot 	      [UHS_SDR50]	= 100000000,
18605038576SJean-Jacques Hiblot 	      [UHS_SDR104]	= 208000000,
18705038576SJean-Jacques Hiblot 	      [UHS_DDR50]	= 50000000,
18805038576SJean-Jacques Hiblot 	      [MMC_HS_52]	= 52000000,
18905038576SJean-Jacques Hiblot 	      [MMC_DDR_52]	= 52000000,
19005038576SJean-Jacques Hiblot 	      [MMC_HS_200]	= 200000000,
19105038576SJean-Jacques Hiblot 	};
19205038576SJean-Jacques Hiblot 
19305038576SJean-Jacques Hiblot 	if (mode == MMC_LEGACY)
19405038576SJean-Jacques Hiblot 		return mmc->legacy_speed;
19505038576SJean-Jacques Hiblot 	else if (mode >= MMC_MODES_END)
19605038576SJean-Jacques Hiblot 		return 0;
19705038576SJean-Jacques Hiblot 	else
19805038576SJean-Jacques Hiblot 		return freqs[mode];
19905038576SJean-Jacques Hiblot }
20005038576SJean-Jacques Hiblot 
20135f9e196SJean-Jacques Hiblot static int mmc_select_mode(struct mmc *mmc, enum bus_mode mode)
20235f9e196SJean-Jacques Hiblot {
20335f9e196SJean-Jacques Hiblot 	mmc->selected_mode = mode;
20405038576SJean-Jacques Hiblot 	mmc->tran_speed = mmc_mode2freq(mmc, mode);
205*3862b854SJean-Jacques Hiblot 	mmc->ddr_mode = mmc_is_mode_ddr(mode);
20635f9e196SJean-Jacques Hiblot 	debug("selecting mode %s (freq : %d MHz)\n", mmc_mode_name(mode),
20735f9e196SJean-Jacques Hiblot 	      mmc->tran_speed / 1000000);
20835f9e196SJean-Jacques Hiblot 	return 0;
20935f9e196SJean-Jacques Hiblot }
21035f9e196SJean-Jacques Hiblot 
211e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
212c0c76ebaSSimon Glass int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
213c0c76ebaSSimon Glass {
214c0c76ebaSSimon Glass 	int ret;
215c0c76ebaSSimon Glass 
216c0c76ebaSSimon Glass 	mmmc_trace_before_send(mmc, cmd);
217c0c76ebaSSimon Glass 	ret = mmc->cfg->ops->send_cmd(mmc, cmd, data);
218c0c76ebaSSimon Glass 	mmmc_trace_after_send(mmc, cmd, ret);
219c0c76ebaSSimon Glass 
2208635ff9eSMarek Vasut 	return ret;
221272cc70bSAndy Fleming }
2228ca51e51SSimon Glass #endif
223272cc70bSAndy Fleming 
224da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout)
2255d4fc8d9SRaffaele Recalcati {
2265d4fc8d9SRaffaele Recalcati 	struct mmc_cmd cmd;
227d617c426SJan Kloetzke 	int err, retries = 5;
2285d4fc8d9SRaffaele Recalcati 
2295d4fc8d9SRaffaele Recalcati 	cmd.cmdidx = MMC_CMD_SEND_STATUS;
2305d4fc8d9SRaffaele Recalcati 	cmd.resp_type = MMC_RSP_R1;
231aaf3d41aSMarek Vasut 	if (!mmc_host_is_spi(mmc))
232aaf3d41aSMarek Vasut 		cmd.cmdarg = mmc->rca << 16;
2335d4fc8d9SRaffaele Recalcati 
2341677eef4SAndrew Gabbasov 	while (1) {
2355d4fc8d9SRaffaele Recalcati 		err = mmc_send_cmd(mmc, &cmd, NULL);
236d617c426SJan Kloetzke 		if (!err) {
237d617c426SJan Kloetzke 			if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) &&
238d617c426SJan Kloetzke 			    (cmd.response[0] & MMC_STATUS_CURR_STATE) !=
239d617c426SJan Kloetzke 			     MMC_STATE_PRG)
2405d4fc8d9SRaffaele Recalcati 				break;
241d0c221feSJean-Jacques Hiblot 
242d0c221feSJean-Jacques Hiblot 			if (cmd.response[0] & MMC_STATUS_MASK) {
24356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
244d617c426SJan Kloetzke 				printf("Status Error: 0x%08X\n",
245d617c426SJan Kloetzke 					cmd.response[0]);
24656196826SPaul Burton #endif
247915ffa52SJaehoon Chung 				return -ECOMM;
248d617c426SJan Kloetzke 			}
249d617c426SJan Kloetzke 		} else if (--retries < 0)
250d617c426SJan Kloetzke 			return err;
2515d4fc8d9SRaffaele Recalcati 
2521677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
2531677eef4SAndrew Gabbasov 			break;
2545d4fc8d9SRaffaele Recalcati 
2551677eef4SAndrew Gabbasov 		udelay(1000);
2561677eef4SAndrew Gabbasov 	}
2575d4fc8d9SRaffaele Recalcati 
258c0c76ebaSSimon Glass 	mmc_trace_state(mmc, &cmd);
2595b0c942fSJongman Heo 	if (timeout <= 0) {
26056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2615d4fc8d9SRaffaele Recalcati 		printf("Timeout waiting card ready\n");
26256196826SPaul Burton #endif
263915ffa52SJaehoon Chung 		return -ETIMEDOUT;
2645d4fc8d9SRaffaele Recalcati 	}
2655d4fc8d9SRaffaele Recalcati 
2665d4fc8d9SRaffaele Recalcati 	return 0;
2675d4fc8d9SRaffaele Recalcati }
2685d4fc8d9SRaffaele Recalcati 
269da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len)
270272cc70bSAndy Fleming {
271272cc70bSAndy Fleming 	struct mmc_cmd cmd;
272272cc70bSAndy Fleming 
273786e8f81SAndrew Gabbasov 	if (mmc->ddr_mode)
274d22e3d46SJaehoon Chung 		return 0;
275d22e3d46SJaehoon Chung 
276272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
277272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
278272cc70bSAndy Fleming 	cmd.cmdarg = len;
279272cc70bSAndy Fleming 
280272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, NULL);
281272cc70bSAndy Fleming }
282272cc70bSAndy Fleming 
283ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
284fdbb873eSKim Phillips 			   lbaint_t blkcnt)
285272cc70bSAndy Fleming {
286272cc70bSAndy Fleming 	struct mmc_cmd cmd;
287272cc70bSAndy Fleming 	struct mmc_data data;
288272cc70bSAndy Fleming 
2894a1a06bcSAlagu Sankar 	if (blkcnt > 1)
2904a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
2914a1a06bcSAlagu Sankar 	else
292272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
293272cc70bSAndy Fleming 
294272cc70bSAndy Fleming 	if (mmc->high_capacity)
2954a1a06bcSAlagu Sankar 		cmd.cmdarg = start;
296272cc70bSAndy Fleming 	else
2974a1a06bcSAlagu Sankar 		cmd.cmdarg = start * mmc->read_bl_len;
298272cc70bSAndy Fleming 
299272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
300272cc70bSAndy Fleming 
301272cc70bSAndy Fleming 	data.dest = dst;
3024a1a06bcSAlagu Sankar 	data.blocks = blkcnt;
303272cc70bSAndy Fleming 	data.blocksize = mmc->read_bl_len;
304272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
305272cc70bSAndy Fleming 
3064a1a06bcSAlagu Sankar 	if (mmc_send_cmd(mmc, &cmd, &data))
3074a1a06bcSAlagu Sankar 		return 0;
3084a1a06bcSAlagu Sankar 
3094a1a06bcSAlagu Sankar 	if (blkcnt > 1) {
3104a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
3114a1a06bcSAlagu Sankar 		cmd.cmdarg = 0;
3124a1a06bcSAlagu Sankar 		cmd.resp_type = MMC_RSP_R1b;
3134a1a06bcSAlagu Sankar 		if (mmc_send_cmd(mmc, &cmd, NULL)) {
31456196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
3154a1a06bcSAlagu Sankar 			printf("mmc fail to send stop cmd\n");
31656196826SPaul Burton #endif
3174a1a06bcSAlagu Sankar 			return 0;
3184a1a06bcSAlagu Sankar 		}
319272cc70bSAndy Fleming 	}
320272cc70bSAndy Fleming 
3214a1a06bcSAlagu Sankar 	return blkcnt;
322272cc70bSAndy Fleming }
323272cc70bSAndy Fleming 
324c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
3257dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst)
32633fb211dSSimon Glass #else
3277dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
3287dba0b93SSimon Glass 		void *dst)
32933fb211dSSimon Glass #endif
330272cc70bSAndy Fleming {
331c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
33233fb211dSSimon Glass 	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
33333fb211dSSimon Glass #endif
334bcce53d0SSimon Glass 	int dev_num = block_dev->devnum;
335873cc1d7SStephen Warren 	int err;
3364a1a06bcSAlagu Sankar 	lbaint_t cur, blocks_todo = blkcnt;
337272cc70bSAndy Fleming 
3384a1a06bcSAlagu Sankar 	if (blkcnt == 0)
3394a1a06bcSAlagu Sankar 		return 0;
3404a1a06bcSAlagu Sankar 
3414a1a06bcSAlagu Sankar 	struct mmc *mmc = find_mmc_device(dev_num);
342272cc70bSAndy Fleming 	if (!mmc)
343272cc70bSAndy Fleming 		return 0;
344272cc70bSAndy Fleming 
345b5b838f1SMarek Vasut 	if (CONFIG_IS_ENABLED(MMC_TINY))
346b5b838f1SMarek Vasut 		err = mmc_switch_part(mmc, block_dev->hwpart);
347b5b838f1SMarek Vasut 	else
34869f45cd5SSimon Glass 		err = blk_dselect_hwpart(block_dev, block_dev->hwpart);
349b5b838f1SMarek Vasut 
350873cc1d7SStephen Warren 	if (err < 0)
351873cc1d7SStephen Warren 		return 0;
352873cc1d7SStephen Warren 
353c40fdca6SSimon Glass 	if ((start + blkcnt) > block_dev->lba) {
35456196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
355ff8fef56SSascha Silbe 		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
356c40fdca6SSimon Glass 			start + blkcnt, block_dev->lba);
35756196826SPaul Burton #endif
358d2bf29e3SLei Wen 		return 0;
359d2bf29e3SLei Wen 	}
360272cc70bSAndy Fleming 
36111692991SSimon Glass 	if (mmc_set_blocklen(mmc, mmc->read_bl_len)) {
36211692991SSimon Glass 		debug("%s: Failed to set blocklen\n", __func__);
363272cc70bSAndy Fleming 		return 0;
36411692991SSimon Glass 	}
365272cc70bSAndy Fleming 
3664a1a06bcSAlagu Sankar 	do {
36793bfd616SPantelis Antoniou 		cur = (blocks_todo > mmc->cfg->b_max) ?
36893bfd616SPantelis Antoniou 			mmc->cfg->b_max : blocks_todo;
36911692991SSimon Glass 		if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
37011692991SSimon Glass 			debug("%s: Failed to read blocks\n", __func__);
3714a1a06bcSAlagu Sankar 			return 0;
37211692991SSimon Glass 		}
3734a1a06bcSAlagu Sankar 		blocks_todo -= cur;
3744a1a06bcSAlagu Sankar 		start += cur;
3754a1a06bcSAlagu Sankar 		dst += cur * mmc->read_bl_len;
3764a1a06bcSAlagu Sankar 	} while (blocks_todo > 0);
377272cc70bSAndy Fleming 
378272cc70bSAndy Fleming 	return blkcnt;
379272cc70bSAndy Fleming }
380272cc70bSAndy Fleming 
381fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc)
382272cc70bSAndy Fleming {
383272cc70bSAndy Fleming 	struct mmc_cmd cmd;
384272cc70bSAndy Fleming 	int err;
385272cc70bSAndy Fleming 
386272cc70bSAndy Fleming 	udelay(1000);
387272cc70bSAndy Fleming 
388272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
389272cc70bSAndy Fleming 	cmd.cmdarg = 0;
390272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_NONE;
391272cc70bSAndy Fleming 
392272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
393272cc70bSAndy Fleming 
394272cc70bSAndy Fleming 	if (err)
395272cc70bSAndy Fleming 		return err;
396272cc70bSAndy Fleming 
397272cc70bSAndy Fleming 	udelay(2000);
398272cc70bSAndy Fleming 
399272cc70bSAndy Fleming 	return 0;
400272cc70bSAndy Fleming }
401272cc70bSAndy Fleming 
402fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc)
403272cc70bSAndy Fleming {
404272cc70bSAndy Fleming 	int timeout = 1000;
405272cc70bSAndy Fleming 	int err;
406272cc70bSAndy Fleming 	struct mmc_cmd cmd;
407272cc70bSAndy Fleming 
4081677eef4SAndrew Gabbasov 	while (1) {
409272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_APP_CMD;
410272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1;
411272cc70bSAndy Fleming 		cmd.cmdarg = 0;
412272cc70bSAndy Fleming 
413272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
414272cc70bSAndy Fleming 
415272cc70bSAndy Fleming 		if (err)
416272cc70bSAndy Fleming 			return err;
417272cc70bSAndy Fleming 
418272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
419272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
420250de12bSStefano Babic 
421250de12bSStefano Babic 		/*
422250de12bSStefano Babic 		 * Most cards do not answer if some reserved bits
423250de12bSStefano Babic 		 * in the ocr are set. However, Some controller
424250de12bSStefano Babic 		 * can set bit 7 (reserved for low voltages), but
425250de12bSStefano Babic 		 * how to manage low voltages SD card is not yet
426250de12bSStefano Babic 		 * specified.
427250de12bSStefano Babic 		 */
428d52ebf10SThomas Chou 		cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
42993bfd616SPantelis Antoniou 			(mmc->cfg->voltages & 0xff8000);
430272cc70bSAndy Fleming 
431272cc70bSAndy Fleming 		if (mmc->version == SD_VERSION_2)
432272cc70bSAndy Fleming 			cmd.cmdarg |= OCR_HCS;
433272cc70bSAndy Fleming 
434272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
435272cc70bSAndy Fleming 
436272cc70bSAndy Fleming 		if (err)
437272cc70bSAndy Fleming 			return err;
438272cc70bSAndy Fleming 
4391677eef4SAndrew Gabbasov 		if (cmd.response[0] & OCR_BUSY)
4401677eef4SAndrew Gabbasov 			break;
441272cc70bSAndy Fleming 
4421677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
443915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
444272cc70bSAndy Fleming 
4451677eef4SAndrew Gabbasov 		udelay(1000);
4461677eef4SAndrew Gabbasov 	}
4471677eef4SAndrew Gabbasov 
448272cc70bSAndy Fleming 	if (mmc->version != SD_VERSION_2)
449272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
450272cc70bSAndy Fleming 
451d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
452d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
453d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
454d52ebf10SThomas Chou 		cmd.cmdarg = 0;
455d52ebf10SThomas Chou 
456d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
457d52ebf10SThomas Chou 
458d52ebf10SThomas Chou 		if (err)
459d52ebf10SThomas Chou 			return err;
460d52ebf10SThomas Chou 	}
461d52ebf10SThomas Chou 
462998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
463272cc70bSAndy Fleming 
464272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
465272cc70bSAndy Fleming 	mmc->rca = 0;
466272cc70bSAndy Fleming 
467272cc70bSAndy Fleming 	return 0;
468272cc70bSAndy Fleming }
469272cc70bSAndy Fleming 
4705289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg)
471272cc70bSAndy Fleming {
4725289b535SAndrew Gabbasov 	struct mmc_cmd cmd;
473272cc70bSAndy Fleming 	int err;
474272cc70bSAndy Fleming 
4755289b535SAndrew Gabbasov 	cmd.cmdidx = MMC_CMD_SEND_OP_COND;
4765289b535SAndrew Gabbasov 	cmd.resp_type = MMC_RSP_R3;
4775289b535SAndrew Gabbasov 	cmd.cmdarg = 0;
4785a20397bSRob Herring 	if (use_arg && !mmc_host_is_spi(mmc))
4795a20397bSRob Herring 		cmd.cmdarg = OCR_HCS |
48093bfd616SPantelis Antoniou 			(mmc->cfg->voltages &
481a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_VOLTAGE_MASK)) |
482a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_ACCESS_MODE);
483e9550449SChe-Liang Chiou 
4845289b535SAndrew Gabbasov 	err = mmc_send_cmd(mmc, &cmd, NULL);
485e9550449SChe-Liang Chiou 	if (err)
486e9550449SChe-Liang Chiou 		return err;
4875289b535SAndrew Gabbasov 	mmc->ocr = cmd.response[0];
488e9550449SChe-Liang Chiou 	return 0;
489e9550449SChe-Liang Chiou }
490e9550449SChe-Liang Chiou 
491750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc)
492e9550449SChe-Liang Chiou {
493e9550449SChe-Liang Chiou 	int err, i;
494e9550449SChe-Liang Chiou 
495272cc70bSAndy Fleming 	/* Some cards seem to need this */
496272cc70bSAndy Fleming 	mmc_go_idle(mmc);
497272cc70bSAndy Fleming 
49831cacbabSRaffaele Recalcati  	/* Asking to the card its capabilities */
499e9550449SChe-Liang Chiou 	for (i = 0; i < 2; i++) {
5005289b535SAndrew Gabbasov 		err = mmc_send_op_cond_iter(mmc, i != 0);
50131cacbabSRaffaele Recalcati 		if (err)
50231cacbabSRaffaele Recalcati 			return err;
50331cacbabSRaffaele Recalcati 
504e9550449SChe-Liang Chiou 		/* exit if not busy (flag seems to be inverted) */
505a626c8d4SAndrew Gabbasov 		if (mmc->ocr & OCR_BUSY)
506bd47c135SAndrew Gabbasov 			break;
507e9550449SChe-Liang Chiou 	}
508bd47c135SAndrew Gabbasov 	mmc->op_cond_pending = 1;
509bd47c135SAndrew Gabbasov 	return 0;
510e9550449SChe-Liang Chiou }
51131cacbabSRaffaele Recalcati 
512750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc)
513e9550449SChe-Liang Chiou {
514e9550449SChe-Liang Chiou 	struct mmc_cmd cmd;
515e9550449SChe-Liang Chiou 	int timeout = 1000;
516e9550449SChe-Liang Chiou 	uint start;
517e9550449SChe-Liang Chiou 	int err;
518e9550449SChe-Liang Chiou 
519e9550449SChe-Liang Chiou 	mmc->op_cond_pending = 0;
520cc17c01fSAndrew Gabbasov 	if (!(mmc->ocr & OCR_BUSY)) {
521d188b113SYangbo Lu 		/* Some cards seem to need this */
522d188b113SYangbo Lu 		mmc_go_idle(mmc);
523d188b113SYangbo Lu 
524e9550449SChe-Liang Chiou 		start = get_timer(0);
5251677eef4SAndrew Gabbasov 		while (1) {
5265289b535SAndrew Gabbasov 			err = mmc_send_op_cond_iter(mmc, 1);
527272cc70bSAndy Fleming 			if (err)
528272cc70bSAndy Fleming 				return err;
5291677eef4SAndrew Gabbasov 			if (mmc->ocr & OCR_BUSY)
5301677eef4SAndrew Gabbasov 				break;
531e9550449SChe-Liang Chiou 			if (get_timer(start) > timeout)
532915ffa52SJaehoon Chung 				return -EOPNOTSUPP;
533e9550449SChe-Liang Chiou 			udelay(100);
5341677eef4SAndrew Gabbasov 		}
535cc17c01fSAndrew Gabbasov 	}
536272cc70bSAndy Fleming 
537d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
538d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
539d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
540d52ebf10SThomas Chou 		cmd.cmdarg = 0;
541d52ebf10SThomas Chou 
542d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
543d52ebf10SThomas Chou 
544d52ebf10SThomas Chou 		if (err)
545d52ebf10SThomas Chou 			return err;
546a626c8d4SAndrew Gabbasov 
547a626c8d4SAndrew Gabbasov 		mmc->ocr = cmd.response[0];
548d52ebf10SThomas Chou 	}
549d52ebf10SThomas Chou 
550272cc70bSAndy Fleming 	mmc->version = MMC_VERSION_UNKNOWN;
551272cc70bSAndy Fleming 
552272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
553def816a2SStephen Warren 	mmc->rca = 1;
554272cc70bSAndy Fleming 
555272cc70bSAndy Fleming 	return 0;
556272cc70bSAndy Fleming }
557272cc70bSAndy Fleming 
558272cc70bSAndy Fleming 
559fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
560272cc70bSAndy Fleming {
561272cc70bSAndy Fleming 	struct mmc_cmd cmd;
562272cc70bSAndy Fleming 	struct mmc_data data;
563272cc70bSAndy Fleming 	int err;
564272cc70bSAndy Fleming 
565272cc70bSAndy Fleming 	/* Get the Card Status Register */
566272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
567272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
568272cc70bSAndy Fleming 	cmd.cmdarg = 0;
569272cc70bSAndy Fleming 
570cdfd1ac6SYoshihiro Shimoda 	data.dest = (char *)ext_csd;
571272cc70bSAndy Fleming 	data.blocks = 1;
5728bfa195eSSimon Glass 	data.blocksize = MMC_MAX_BLOCK_LEN;
573272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
574272cc70bSAndy Fleming 
575272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
576272cc70bSAndy Fleming 
577272cc70bSAndy Fleming 	return err;
578272cc70bSAndy Fleming }
579272cc70bSAndy Fleming 
580c40704f4SSimon Glass int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
581272cc70bSAndy Fleming {
582272cc70bSAndy Fleming 	struct mmc_cmd cmd;
5835d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
584a9003dc6SMaxime Ripard 	int retries = 3;
5855d4fc8d9SRaffaele Recalcati 	int ret;
586272cc70bSAndy Fleming 
587272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SWITCH;
588272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1b;
589272cc70bSAndy Fleming 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
590272cc70bSAndy Fleming 				 (index << 16) |
591272cc70bSAndy Fleming 				 (value << 8);
592272cc70bSAndy Fleming 
593a9003dc6SMaxime Ripard 	while (retries > 0) {
5945d4fc8d9SRaffaele Recalcati 		ret = mmc_send_cmd(mmc, &cmd, NULL);
5955d4fc8d9SRaffaele Recalcati 
5965d4fc8d9SRaffaele Recalcati 		/* Waiting for the ready status */
597a9003dc6SMaxime Ripard 		if (!ret) {
59893ad0d18SJan Kloetzke 			ret = mmc_send_status(mmc, timeout);
599a9003dc6SMaxime Ripard 			return ret;
600a9003dc6SMaxime Ripard 		}
601a9003dc6SMaxime Ripard 
602a9003dc6SMaxime Ripard 		retries--;
603a9003dc6SMaxime Ripard 	}
6045d4fc8d9SRaffaele Recalcati 
6055d4fc8d9SRaffaele Recalcati 	return ret;
6065d4fc8d9SRaffaele Recalcati 
607272cc70bSAndy Fleming }
608272cc70bSAndy Fleming 
609*3862b854SJean-Jacques Hiblot static int mmc_set_card_speed(struct mmc *mmc, enum bus_mode mode)
610272cc70bSAndy Fleming {
611272cc70bSAndy Fleming 	int err;
612*3862b854SJean-Jacques Hiblot 	int speed_bits;
613*3862b854SJean-Jacques Hiblot 
614*3862b854SJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
615*3862b854SJean-Jacques Hiblot 
616*3862b854SJean-Jacques Hiblot 	switch (mode) {
617*3862b854SJean-Jacques Hiblot 	case MMC_HS:
618*3862b854SJean-Jacques Hiblot 	case MMC_HS_52:
619*3862b854SJean-Jacques Hiblot 	case MMC_DDR_52:
620*3862b854SJean-Jacques Hiblot 		speed_bits = EXT_CSD_TIMING_HS;
621*3862b854SJean-Jacques Hiblot 	case MMC_LEGACY:
622*3862b854SJean-Jacques Hiblot 		speed_bits = EXT_CSD_TIMING_LEGACY;
623*3862b854SJean-Jacques Hiblot 		break;
624*3862b854SJean-Jacques Hiblot 	default:
625*3862b854SJean-Jacques Hiblot 		return -EINVAL;
626*3862b854SJean-Jacques Hiblot 	}
627*3862b854SJean-Jacques Hiblot 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
628*3862b854SJean-Jacques Hiblot 			 speed_bits);
629*3862b854SJean-Jacques Hiblot 	if (err)
630*3862b854SJean-Jacques Hiblot 		return err;
631*3862b854SJean-Jacques Hiblot 
632*3862b854SJean-Jacques Hiblot 	if ((mode == MMC_HS) || (mode == MMC_HS_52)) {
633*3862b854SJean-Jacques Hiblot 		/* Now check to see that it worked */
634*3862b854SJean-Jacques Hiblot 		err = mmc_send_ext_csd(mmc, test_csd);
635*3862b854SJean-Jacques Hiblot 		if (err)
636*3862b854SJean-Jacques Hiblot 			return err;
637*3862b854SJean-Jacques Hiblot 
638*3862b854SJean-Jacques Hiblot 		/* No high-speed support */
639*3862b854SJean-Jacques Hiblot 		if (!test_csd[EXT_CSD_HS_TIMING])
640*3862b854SJean-Jacques Hiblot 			return -ENOTSUPP;
641*3862b854SJean-Jacques Hiblot 	}
642*3862b854SJean-Jacques Hiblot 
643*3862b854SJean-Jacques Hiblot 	return 0;
644*3862b854SJean-Jacques Hiblot }
645*3862b854SJean-Jacques Hiblot 
646*3862b854SJean-Jacques Hiblot static int mmc_get_capabilities(struct mmc *mmc)
647*3862b854SJean-Jacques Hiblot {
648*3862b854SJean-Jacques Hiblot 	u8 *ext_csd = mmc->ext_csd;
649*3862b854SJean-Jacques Hiblot 	char cardtype;
650272cc70bSAndy Fleming 
651d0c221feSJean-Jacques Hiblot 	mmc->card_caps = MMC_MODE_1BIT;
652272cc70bSAndy Fleming 
653d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
654d52ebf10SThomas Chou 		return 0;
655d52ebf10SThomas Chou 
656272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
657272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
658272cc70bSAndy Fleming 		return 0;
659272cc70bSAndy Fleming 
660*3862b854SJean-Jacques Hiblot 	if (!ext_csd) {
661*3862b854SJean-Jacques Hiblot 		printf("No ext_csd found!\n"); /* this should enver happen */
662*3862b854SJean-Jacques Hiblot 		return -ENOTSUPP;
663*3862b854SJean-Jacques Hiblot 	}
664*3862b854SJean-Jacques Hiblot 
665fc5b32fbSAndrew Gabbasov 	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
666fc5b32fbSAndrew Gabbasov 
6670560db18SLei Wen 	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf;
668272cc70bSAndy Fleming 
669272cc70bSAndy Fleming 	/* High Speed is set, there are two types: 52MHz and 26MHz */
670d22e3d46SJaehoon Chung 	if (cardtype & EXT_CSD_CARD_TYPE_52) {
671*3862b854SJean-Jacques Hiblot 		if (cardtype & EXT_CSD_CARD_TYPE_DDR_52)
672d22e3d46SJaehoon Chung 			mmc->card_caps |= MMC_MODE_DDR_52MHz;
673*3862b854SJean-Jacques Hiblot 		mmc->card_caps |= MMC_MODE_HS_52MHz;
674d22e3d46SJaehoon Chung 	}
675*3862b854SJean-Jacques Hiblot 	if (cardtype & EXT_CSD_CARD_TYPE_26)
676*3862b854SJean-Jacques Hiblot 		mmc->card_caps |= MMC_MODE_HS;
677272cc70bSAndy Fleming 
678272cc70bSAndy Fleming 	return 0;
679272cc70bSAndy Fleming }
680272cc70bSAndy Fleming 
681f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num)
682f866a46dSStephen Warren {
683f866a46dSStephen Warren 	switch (part_num) {
684f866a46dSStephen Warren 	case 0:
685f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_user;
686f866a46dSStephen Warren 		break;
687f866a46dSStephen Warren 	case 1:
688f866a46dSStephen Warren 	case 2:
689f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_boot;
690f866a46dSStephen Warren 		break;
691f866a46dSStephen Warren 	case 3:
692f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_rpmb;
693f866a46dSStephen Warren 		break;
694f866a46dSStephen Warren 	case 4:
695f866a46dSStephen Warren 	case 5:
696f866a46dSStephen Warren 	case 6:
697f866a46dSStephen Warren 	case 7:
698f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_gp[part_num - 4];
699f866a46dSStephen Warren 		break;
700f866a46dSStephen Warren 	default:
701f866a46dSStephen Warren 		return -1;
702f866a46dSStephen Warren 	}
703f866a46dSStephen Warren 
704c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len);
705f866a46dSStephen Warren 
706f866a46dSStephen Warren 	return 0;
707f866a46dSStephen Warren }
708f866a46dSStephen Warren 
7097dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num)
710bc897b1dSLei Wen {
711f866a46dSStephen Warren 	int ret;
712bc897b1dSLei Wen 
713f866a46dSStephen Warren 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
714bc897b1dSLei Wen 			 (mmc->part_config & ~PART_ACCESS_MASK)
715bc897b1dSLei Wen 			 | (part_num & PART_ACCESS_MASK));
716f866a46dSStephen Warren 
7176dc93e70SPeter Bigot 	/*
7186dc93e70SPeter Bigot 	 * Set the capacity if the switch succeeded or was intended
7196dc93e70SPeter Bigot 	 * to return to representing the raw device.
7206dc93e70SPeter Bigot 	 */
721873cc1d7SStephen Warren 	if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) {
7226dc93e70SPeter Bigot 		ret = mmc_set_capacity(mmc, part_num);
723fdbb139fSSimon Glass 		mmc_get_blk_desc(mmc)->hwpart = part_num;
724873cc1d7SStephen Warren 	}
7256dc93e70SPeter Bigot 
7266dc93e70SPeter Bigot 	return ret;
727bc897b1dSLei Wen }
728bc897b1dSLei Wen 
729ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc,
730ac9da0e0SDiego Santa Cruz 		      const struct mmc_hwpart_conf *conf,
731ac9da0e0SDiego Santa Cruz 		      enum mmc_hwpart_conf_mode mode)
732ac9da0e0SDiego Santa Cruz {
733ac9da0e0SDiego Santa Cruz 	u8 part_attrs = 0;
734ac9da0e0SDiego Santa Cruz 	u32 enh_size_mult;
735ac9da0e0SDiego Santa Cruz 	u32 enh_start_addr;
736ac9da0e0SDiego Santa Cruz 	u32 gp_size_mult[4];
737ac9da0e0SDiego Santa Cruz 	u32 max_enh_size_mult;
738ac9da0e0SDiego Santa Cruz 	u32 tot_enh_size_mult = 0;
7398dda5b0eSDiego Santa Cruz 	u8 wr_rel_set;
740ac9da0e0SDiego Santa Cruz 	int i, pidx, err;
741ac9da0e0SDiego Santa Cruz 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
742ac9da0e0SDiego Santa Cruz 
743ac9da0e0SDiego Santa Cruz 	if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE)
744ac9da0e0SDiego Santa Cruz 		return -EINVAL;
745ac9da0e0SDiego Santa Cruz 
746ac9da0e0SDiego Santa Cruz 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) {
747ac9da0e0SDiego Santa Cruz 		printf("eMMC >= 4.4 required for enhanced user data area\n");
748ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
749ac9da0e0SDiego Santa Cruz 	}
750ac9da0e0SDiego Santa Cruz 
751ac9da0e0SDiego Santa Cruz 	if (!(mmc->part_support & PART_SUPPORT)) {
752ac9da0e0SDiego Santa Cruz 		printf("Card does not support partitioning\n");
753ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
754ac9da0e0SDiego Santa Cruz 	}
755ac9da0e0SDiego Santa Cruz 
756ac9da0e0SDiego Santa Cruz 	if (!mmc->hc_wp_grp_size) {
757ac9da0e0SDiego Santa Cruz 		printf("Card does not define HC WP group size\n");
758ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
759ac9da0e0SDiego Santa Cruz 	}
760ac9da0e0SDiego Santa Cruz 
761ac9da0e0SDiego Santa Cruz 	/* check partition alignment and total enhanced size */
762ac9da0e0SDiego Santa Cruz 	if (conf->user.enh_size) {
763ac9da0e0SDiego Santa Cruz 		if (conf->user.enh_size % mmc->hc_wp_grp_size ||
764ac9da0e0SDiego Santa Cruz 		    conf->user.enh_start % mmc->hc_wp_grp_size) {
765ac9da0e0SDiego Santa Cruz 			printf("User data enhanced area not HC WP group "
766ac9da0e0SDiego Santa Cruz 			       "size aligned\n");
767ac9da0e0SDiego Santa Cruz 			return -EINVAL;
768ac9da0e0SDiego Santa Cruz 		}
769ac9da0e0SDiego Santa Cruz 		part_attrs |= EXT_CSD_ENH_USR;
770ac9da0e0SDiego Santa Cruz 		enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size;
771ac9da0e0SDiego Santa Cruz 		if (mmc->high_capacity) {
772ac9da0e0SDiego Santa Cruz 			enh_start_addr = conf->user.enh_start;
773ac9da0e0SDiego Santa Cruz 		} else {
774ac9da0e0SDiego Santa Cruz 			enh_start_addr = (conf->user.enh_start << 9);
775ac9da0e0SDiego Santa Cruz 		}
776ac9da0e0SDiego Santa Cruz 	} else {
777ac9da0e0SDiego Santa Cruz 		enh_size_mult = 0;
778ac9da0e0SDiego Santa Cruz 		enh_start_addr = 0;
779ac9da0e0SDiego Santa Cruz 	}
780ac9da0e0SDiego Santa Cruz 	tot_enh_size_mult += enh_size_mult;
781ac9da0e0SDiego Santa Cruz 
782ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
783ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) {
784ac9da0e0SDiego Santa Cruz 			printf("GP%i partition not HC WP group size "
785ac9da0e0SDiego Santa Cruz 			       "aligned\n", pidx+1);
786ac9da0e0SDiego Santa Cruz 			return -EINVAL;
787ac9da0e0SDiego Santa Cruz 		}
788ac9da0e0SDiego Santa Cruz 		gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size;
789ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) {
790ac9da0e0SDiego Santa Cruz 			part_attrs |= EXT_CSD_ENH_GP(pidx);
791ac9da0e0SDiego Santa Cruz 			tot_enh_size_mult += gp_size_mult[pidx];
792ac9da0e0SDiego Santa Cruz 		}
793ac9da0e0SDiego Santa Cruz 	}
794ac9da0e0SDiego Santa Cruz 
795ac9da0e0SDiego Santa Cruz 	if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) {
796ac9da0e0SDiego Santa Cruz 		printf("Card does not support enhanced attribute\n");
797ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
798ac9da0e0SDiego Santa Cruz 	}
799ac9da0e0SDiego Santa Cruz 
800ac9da0e0SDiego Santa Cruz 	err = mmc_send_ext_csd(mmc, ext_csd);
801ac9da0e0SDiego Santa Cruz 	if (err)
802ac9da0e0SDiego Santa Cruz 		return err;
803ac9da0e0SDiego Santa Cruz 
804ac9da0e0SDiego Santa Cruz 	max_enh_size_mult =
805ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) +
806ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) +
807ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT];
808ac9da0e0SDiego Santa Cruz 	if (tot_enh_size_mult > max_enh_size_mult) {
809ac9da0e0SDiego Santa Cruz 		printf("Total enhanced size exceeds maximum (%u > %u)\n",
810ac9da0e0SDiego Santa Cruz 		       tot_enh_size_mult, max_enh_size_mult);
811ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
812ac9da0e0SDiego Santa Cruz 	}
813ac9da0e0SDiego Santa Cruz 
8148dda5b0eSDiego Santa Cruz 	/* The default value of EXT_CSD_WR_REL_SET is device
8158dda5b0eSDiego Santa Cruz 	 * dependent, the values can only be changed if the
8168dda5b0eSDiego Santa Cruz 	 * EXT_CSD_HS_CTRL_REL bit is set. The values can be
8178dda5b0eSDiego Santa Cruz 	 * changed only once and before partitioning is completed. */
8188dda5b0eSDiego Santa Cruz 	wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
8198dda5b0eSDiego Santa Cruz 	if (conf->user.wr_rel_change) {
8208dda5b0eSDiego Santa Cruz 		if (conf->user.wr_rel_set)
8218dda5b0eSDiego Santa Cruz 			wr_rel_set |= EXT_CSD_WR_DATA_REL_USR;
8228dda5b0eSDiego Santa Cruz 		else
8238dda5b0eSDiego Santa Cruz 			wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR;
8248dda5b0eSDiego Santa Cruz 	}
8258dda5b0eSDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
8268dda5b0eSDiego Santa Cruz 		if (conf->gp_part[pidx].wr_rel_change) {
8278dda5b0eSDiego Santa Cruz 			if (conf->gp_part[pidx].wr_rel_set)
8288dda5b0eSDiego Santa Cruz 				wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx);
8298dda5b0eSDiego Santa Cruz 			else
8308dda5b0eSDiego Santa Cruz 				wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx);
8318dda5b0eSDiego Santa Cruz 		}
8328dda5b0eSDiego Santa Cruz 	}
8338dda5b0eSDiego Santa Cruz 
8348dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] &&
8358dda5b0eSDiego Santa Cruz 	    !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) {
8368dda5b0eSDiego Santa Cruz 		puts("Card does not support host controlled partition write "
8378dda5b0eSDiego Santa Cruz 		     "reliability settings\n");
8388dda5b0eSDiego Santa Cruz 		return -EMEDIUMTYPE;
8398dda5b0eSDiego Santa Cruz 	}
8408dda5b0eSDiego Santa Cruz 
841ac9da0e0SDiego Santa Cruz 	if (ext_csd[EXT_CSD_PARTITION_SETTING] &
842ac9da0e0SDiego Santa Cruz 	    EXT_CSD_PARTITION_SETTING_COMPLETED) {
843ac9da0e0SDiego Santa Cruz 		printf("Card already partitioned\n");
844ac9da0e0SDiego Santa Cruz 		return -EPERM;
845ac9da0e0SDiego Santa Cruz 	}
846ac9da0e0SDiego Santa Cruz 
847ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_CHECK)
848ac9da0e0SDiego Santa Cruz 		return 0;
849ac9da0e0SDiego Santa Cruz 
850ac9da0e0SDiego Santa Cruz 	/* Partitioning requires high-capacity size definitions */
851ac9da0e0SDiego Santa Cruz 	if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) {
852ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
853ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ERASE_GROUP_DEF, 1);
854ac9da0e0SDiego Santa Cruz 
855ac9da0e0SDiego Santa Cruz 		if (err)
856ac9da0e0SDiego Santa Cruz 			return err;
857ac9da0e0SDiego Santa Cruz 
858ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
859ac9da0e0SDiego Santa Cruz 
860ac9da0e0SDiego Santa Cruz 		/* update erase group size to be high-capacity */
861ac9da0e0SDiego Santa Cruz 		mmc->erase_grp_size =
862ac9da0e0SDiego Santa Cruz 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
863ac9da0e0SDiego Santa Cruz 
864ac9da0e0SDiego Santa Cruz 	}
865ac9da0e0SDiego Santa Cruz 
866ac9da0e0SDiego Santa Cruz 	/* all OK, write the configuration */
867ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 4; i++) {
868ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
869ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_START_ADDR+i,
870ac9da0e0SDiego Santa Cruz 				 (enh_start_addr >> (i*8)) & 0xFF);
871ac9da0e0SDiego Santa Cruz 		if (err)
872ac9da0e0SDiego Santa Cruz 			return err;
873ac9da0e0SDiego Santa Cruz 	}
874ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 3; i++) {
875ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
876ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_SIZE_MULT+i,
877ac9da0e0SDiego Santa Cruz 				 (enh_size_mult >> (i*8)) & 0xFF);
878ac9da0e0SDiego Santa Cruz 		if (err)
879ac9da0e0SDiego Santa Cruz 			return err;
880ac9da0e0SDiego Santa Cruz 	}
881ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
882ac9da0e0SDiego Santa Cruz 		for (i = 0; i < 3; i++) {
883ac9da0e0SDiego Santa Cruz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
884ac9da0e0SDiego Santa Cruz 					 EXT_CSD_GP_SIZE_MULT+pidx*3+i,
885ac9da0e0SDiego Santa Cruz 					 (gp_size_mult[pidx] >> (i*8)) & 0xFF);
886ac9da0e0SDiego Santa Cruz 			if (err)
887ac9da0e0SDiego Santa Cruz 				return err;
888ac9da0e0SDiego Santa Cruz 		}
889ac9da0e0SDiego Santa Cruz 	}
890ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
891ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs);
892ac9da0e0SDiego Santa Cruz 	if (err)
893ac9da0e0SDiego Santa Cruz 		return err;
894ac9da0e0SDiego Santa Cruz 
895ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_SET)
896ac9da0e0SDiego Santa Cruz 		return 0;
897ac9da0e0SDiego Santa Cruz 
8988dda5b0eSDiego Santa Cruz 	/* The WR_REL_SET is a write-once register but shall be
8998dda5b0eSDiego Santa Cruz 	 * written before setting PART_SETTING_COMPLETED. As it is
9008dda5b0eSDiego Santa Cruz 	 * write-once we can only write it when completing the
9018dda5b0eSDiego Santa Cruz 	 * partitioning. */
9028dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) {
9038dda5b0eSDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
9048dda5b0eSDiego Santa Cruz 				 EXT_CSD_WR_REL_SET, wr_rel_set);
9058dda5b0eSDiego Santa Cruz 		if (err)
9068dda5b0eSDiego Santa Cruz 			return err;
9078dda5b0eSDiego Santa Cruz 	}
9088dda5b0eSDiego Santa Cruz 
909ac9da0e0SDiego Santa Cruz 	/* Setting PART_SETTING_COMPLETED confirms the partition
910ac9da0e0SDiego Santa Cruz 	 * configuration but it only becomes effective after power
911ac9da0e0SDiego Santa Cruz 	 * cycle, so we do not adjust the partition related settings
912ac9da0e0SDiego Santa Cruz 	 * in the mmc struct. */
913ac9da0e0SDiego Santa Cruz 
914ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
915ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING,
916ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING_COMPLETED);
917ac9da0e0SDiego Santa Cruz 	if (err)
918ac9da0e0SDiego Santa Cruz 		return err;
919ac9da0e0SDiego Santa Cruz 
920ac9da0e0SDiego Santa Cruz 	return 0;
921ac9da0e0SDiego Santa Cruz }
922ac9da0e0SDiego Santa Cruz 
923e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
92448972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
92548972d90SThierry Reding {
92648972d90SThierry Reding 	int cd;
92748972d90SThierry Reding 
92848972d90SThierry Reding 	cd = board_mmc_getcd(mmc);
92948972d90SThierry Reding 
930d4e1da4eSPeter Korsgaard 	if (cd < 0) {
93193bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getcd)
93293bfd616SPantelis Antoniou 			cd = mmc->cfg->ops->getcd(mmc);
933d4e1da4eSPeter Korsgaard 		else
934d4e1da4eSPeter Korsgaard 			cd = 1;
935d4e1da4eSPeter Korsgaard 	}
93648972d90SThierry Reding 
93748972d90SThierry Reding 	return cd;
93848972d90SThierry Reding }
9398ca51e51SSimon Glass #endif
94048972d90SThierry Reding 
941fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
942272cc70bSAndy Fleming {
943272cc70bSAndy Fleming 	struct mmc_cmd cmd;
944272cc70bSAndy Fleming 	struct mmc_data data;
945272cc70bSAndy Fleming 
946272cc70bSAndy Fleming 	/* Switch the frequency */
947272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
948272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
949272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
950272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
951272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
952272cc70bSAndy Fleming 
953272cc70bSAndy Fleming 	data.dest = (char *)resp;
954272cc70bSAndy Fleming 	data.blocksize = 64;
955272cc70bSAndy Fleming 	data.blocks = 1;
956272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
957272cc70bSAndy Fleming 
958272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
959272cc70bSAndy Fleming }
960272cc70bSAndy Fleming 
961272cc70bSAndy Fleming 
962d0c221feSJean-Jacques Hiblot static int sd_get_capabilities(struct mmc *mmc)
963272cc70bSAndy Fleming {
964272cc70bSAndy Fleming 	int err;
965272cc70bSAndy Fleming 	struct mmc_cmd cmd;
96618e7c8f6SSuniel Mahesh 	ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2);
96718e7c8f6SSuniel Mahesh 	ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16);
968272cc70bSAndy Fleming 	struct mmc_data data;
969272cc70bSAndy Fleming 	int timeout;
970272cc70bSAndy Fleming 
971d0c221feSJean-Jacques Hiblot 	mmc->card_caps = MMC_MODE_1BIT;
972272cc70bSAndy Fleming 
973d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
974d52ebf10SThomas Chou 		return 0;
975d52ebf10SThomas Chou 
976272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
977272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
978272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
979272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
980272cc70bSAndy Fleming 
981272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
982272cc70bSAndy Fleming 
983272cc70bSAndy Fleming 	if (err)
984272cc70bSAndy Fleming 		return err;
985272cc70bSAndy Fleming 
986272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
987272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
988272cc70bSAndy Fleming 	cmd.cmdarg = 0;
989272cc70bSAndy Fleming 
990272cc70bSAndy Fleming 	timeout = 3;
991272cc70bSAndy Fleming 
992272cc70bSAndy Fleming retry_scr:
993f781dd38SAnton staaf 	data.dest = (char *)scr;
994272cc70bSAndy Fleming 	data.blocksize = 8;
995272cc70bSAndy Fleming 	data.blocks = 1;
996272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
997272cc70bSAndy Fleming 
998272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
999272cc70bSAndy Fleming 
1000272cc70bSAndy Fleming 	if (err) {
1001272cc70bSAndy Fleming 		if (timeout--)
1002272cc70bSAndy Fleming 			goto retry_scr;
1003272cc70bSAndy Fleming 
1004272cc70bSAndy Fleming 		return err;
1005272cc70bSAndy Fleming 	}
1006272cc70bSAndy Fleming 
10074e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
10084e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
1009272cc70bSAndy Fleming 
1010272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
1011272cc70bSAndy Fleming 	case 0:
1012272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1013272cc70bSAndy Fleming 		break;
1014272cc70bSAndy Fleming 	case 1:
1015272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_10;
1016272cc70bSAndy Fleming 		break;
1017272cc70bSAndy Fleming 	case 2:
1018272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
10191741c64dSJaehoon Chung 		if ((mmc->scr[0] >> 15) & 0x1)
10201741c64dSJaehoon Chung 			mmc->version = SD_VERSION_3;
1021272cc70bSAndy Fleming 		break;
1022272cc70bSAndy Fleming 	default:
1023272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1024272cc70bSAndy Fleming 		break;
1025272cc70bSAndy Fleming 	}
1026272cc70bSAndy Fleming 
1027b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
1028b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
1029b44c7083SAlagu Sankar 
1030272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
1031272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
1032272cc70bSAndy Fleming 		return 0;
1033272cc70bSAndy Fleming 
1034272cc70bSAndy Fleming 	timeout = 4;
1035272cc70bSAndy Fleming 	while (timeout--) {
1036272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
1037f781dd38SAnton staaf 				(u8 *)switch_status);
1038272cc70bSAndy Fleming 
1039272cc70bSAndy Fleming 		if (err)
1040272cc70bSAndy Fleming 			return err;
1041272cc70bSAndy Fleming 
1042272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
10434e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
1044272cc70bSAndy Fleming 			break;
1045272cc70bSAndy Fleming 	}
1046272cc70bSAndy Fleming 
1047272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
1048d0c221feSJean-Jacques Hiblot 	if (__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED)
1049d0c221feSJean-Jacques Hiblot 		mmc->card_caps |= MMC_CAP(SD_HS);
1050272cc70bSAndy Fleming 
10512c3fbf4cSMacpaul Lin 	return 0;
1052d0c221feSJean-Jacques Hiblot }
1053d0c221feSJean-Jacques Hiblot 
1054d0c221feSJean-Jacques Hiblot static int sd_set_card_speed(struct mmc *mmc, enum bus_mode mode)
1055d0c221feSJean-Jacques Hiblot {
1056d0c221feSJean-Jacques Hiblot 	int err;
1057d0c221feSJean-Jacques Hiblot 
1058d0c221feSJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
10592c3fbf4cSMacpaul Lin 
1060f781dd38SAnton staaf 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status);
1061272cc70bSAndy Fleming 	if (err)
1062272cc70bSAndy Fleming 		return err;
1063272cc70bSAndy Fleming 
1064d0c221feSJean-Jacques Hiblot 	if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) != 0x01000000)
1065d0c221feSJean-Jacques Hiblot 		return -ENOTSUPP;
1066d0c221feSJean-Jacques Hiblot 
1067d0c221feSJean-Jacques Hiblot 	return 0;
1068d0c221feSJean-Jacques Hiblot }
1069d0c221feSJean-Jacques Hiblot 
1070d0c221feSJean-Jacques Hiblot int sd_select_bus_width(struct mmc *mmc, int w)
1071d0c221feSJean-Jacques Hiblot {
1072d0c221feSJean-Jacques Hiblot 	int err;
1073d0c221feSJean-Jacques Hiblot 	struct mmc_cmd cmd;
1074d0c221feSJean-Jacques Hiblot 
1075d0c221feSJean-Jacques Hiblot 	if ((w != 4) && (w != 1))
1076d0c221feSJean-Jacques Hiblot 		return -EINVAL;
1077d0c221feSJean-Jacques Hiblot 
1078d0c221feSJean-Jacques Hiblot 	cmd.cmdidx = MMC_CMD_APP_CMD;
1079d0c221feSJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
1080d0c221feSJean-Jacques Hiblot 	cmd.cmdarg = mmc->rca << 16;
1081d0c221feSJean-Jacques Hiblot 
1082d0c221feSJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
1083d0c221feSJean-Jacques Hiblot 	if (err)
1084d0c221feSJean-Jacques Hiblot 		return err;
1085d0c221feSJean-Jacques Hiblot 
1086d0c221feSJean-Jacques Hiblot 	cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
1087d0c221feSJean-Jacques Hiblot 	cmd.resp_type = MMC_RSP_R1;
1088d0c221feSJean-Jacques Hiblot 	if (w == 4)
1089d0c221feSJean-Jacques Hiblot 		cmd.cmdarg = 2;
1090d0c221feSJean-Jacques Hiblot 	else if (w == 1)
1091d0c221feSJean-Jacques Hiblot 		cmd.cmdarg = 0;
1092d0c221feSJean-Jacques Hiblot 	err = mmc_send_cmd(mmc, &cmd, NULL);
1093d0c221feSJean-Jacques Hiblot 	if (err)
1094d0c221feSJean-Jacques Hiblot 		return err;
1095272cc70bSAndy Fleming 
1096272cc70bSAndy Fleming 	return 0;
1097272cc70bSAndy Fleming }
1098272cc70bSAndy Fleming 
10993697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc)
11003697e599SPeng Fan {
11013697e599SPeng Fan 	int err, i;
11023697e599SPeng Fan 	struct mmc_cmd cmd;
11033697e599SPeng Fan 	ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16);
11043697e599SPeng Fan 	struct mmc_data data;
11053697e599SPeng Fan 	int timeout = 3;
11063697e599SPeng Fan 	unsigned int au, eo, et, es;
11073697e599SPeng Fan 
11083697e599SPeng Fan 	cmd.cmdidx = MMC_CMD_APP_CMD;
11093697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
11103697e599SPeng Fan 	cmd.cmdarg = mmc->rca << 16;
11113697e599SPeng Fan 
11123697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, NULL);
11133697e599SPeng Fan 	if (err)
11143697e599SPeng Fan 		return err;
11153697e599SPeng Fan 
11163697e599SPeng Fan 	cmd.cmdidx = SD_CMD_APP_SD_STATUS;
11173697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
11183697e599SPeng Fan 	cmd.cmdarg = 0;
11193697e599SPeng Fan 
11203697e599SPeng Fan retry_ssr:
11213697e599SPeng Fan 	data.dest = (char *)ssr;
11223697e599SPeng Fan 	data.blocksize = 64;
11233697e599SPeng Fan 	data.blocks = 1;
11243697e599SPeng Fan 	data.flags = MMC_DATA_READ;
11253697e599SPeng Fan 
11263697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, &data);
11273697e599SPeng Fan 	if (err) {
11283697e599SPeng Fan 		if (timeout--)
11293697e599SPeng Fan 			goto retry_ssr;
11303697e599SPeng Fan 
11313697e599SPeng Fan 		return err;
11323697e599SPeng Fan 	}
11333697e599SPeng Fan 
11343697e599SPeng Fan 	for (i = 0; i < 16; i++)
11353697e599SPeng Fan 		ssr[i] = be32_to_cpu(ssr[i]);
11363697e599SPeng Fan 
11373697e599SPeng Fan 	au = (ssr[2] >> 12) & 0xF;
11383697e599SPeng Fan 	if ((au <= 9) || (mmc->version == SD_VERSION_3)) {
11393697e599SPeng Fan 		mmc->ssr.au = sd_au_size[au];
11403697e599SPeng Fan 		es = (ssr[3] >> 24) & 0xFF;
11413697e599SPeng Fan 		es |= (ssr[2] & 0xFF) << 8;
11423697e599SPeng Fan 		et = (ssr[3] >> 18) & 0x3F;
11433697e599SPeng Fan 		if (es && et) {
11443697e599SPeng Fan 			eo = (ssr[3] >> 16) & 0x3;
11453697e599SPeng Fan 			mmc->ssr.erase_timeout = (et * 1000) / es;
11463697e599SPeng Fan 			mmc->ssr.erase_offset = eo * 1000;
11473697e599SPeng Fan 		}
11483697e599SPeng Fan 	} else {
11493697e599SPeng Fan 		debug("Invalid Allocation Unit Size.\n");
11503697e599SPeng Fan 	}
11513697e599SPeng Fan 
11523697e599SPeng Fan 	return 0;
11533697e599SPeng Fan }
11543697e599SPeng Fan 
1155272cc70bSAndy Fleming /* frequency bases */
1156272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
11575f837c2cSMike Frysinger static const int fbase[] = {
1158272cc70bSAndy Fleming 	10000,
1159272cc70bSAndy Fleming 	100000,
1160272cc70bSAndy Fleming 	1000000,
1161272cc70bSAndy Fleming 	10000000,
1162272cc70bSAndy Fleming };
1163272cc70bSAndy Fleming 
1164272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
1165272cc70bSAndy Fleming  * to platforms without floating point.
1166272cc70bSAndy Fleming  */
116761fe076fSSimon Glass static const u8 multipliers[] = {
1168272cc70bSAndy Fleming 	0,	/* reserved */
1169272cc70bSAndy Fleming 	10,
1170272cc70bSAndy Fleming 	12,
1171272cc70bSAndy Fleming 	13,
1172272cc70bSAndy Fleming 	15,
1173272cc70bSAndy Fleming 	20,
1174272cc70bSAndy Fleming 	25,
1175272cc70bSAndy Fleming 	30,
1176272cc70bSAndy Fleming 	35,
1177272cc70bSAndy Fleming 	40,
1178272cc70bSAndy Fleming 	45,
1179272cc70bSAndy Fleming 	50,
1180272cc70bSAndy Fleming 	55,
1181272cc70bSAndy Fleming 	60,
1182272cc70bSAndy Fleming 	70,
1183272cc70bSAndy Fleming 	80,
1184272cc70bSAndy Fleming };
1185272cc70bSAndy Fleming 
1186d0c221feSJean-Jacques Hiblot static inline int bus_width(uint cap)
1187d0c221feSJean-Jacques Hiblot {
1188d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_8BIT)
1189d0c221feSJean-Jacques Hiblot 		return 8;
1190d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_4BIT)
1191d0c221feSJean-Jacques Hiblot 		return 4;
1192d0c221feSJean-Jacques Hiblot 	if (cap == MMC_MODE_1BIT)
1193d0c221feSJean-Jacques Hiblot 		return 1;
1194d0c221feSJean-Jacques Hiblot 	printf("invalid bus witdh capability 0x%x\n", cap);
1195d0c221feSJean-Jacques Hiblot 	return 0;
1196d0c221feSJean-Jacques Hiblot }
1197d0c221feSJean-Jacques Hiblot 
1198e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
1199fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc)
1200272cc70bSAndy Fleming {
120193bfd616SPantelis Antoniou 	if (mmc->cfg->ops->set_ios)
120293bfd616SPantelis Antoniou 		mmc->cfg->ops->set_ios(mmc);
1203272cc70bSAndy Fleming }
12048ca51e51SSimon Glass #endif
1205272cc70bSAndy Fleming 
1206272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock)
1207272cc70bSAndy Fleming {
120893bfd616SPantelis Antoniou 	if (clock > mmc->cfg->f_max)
120993bfd616SPantelis Antoniou 		clock = mmc->cfg->f_max;
1210272cc70bSAndy Fleming 
121193bfd616SPantelis Antoniou 	if (clock < mmc->cfg->f_min)
121293bfd616SPantelis Antoniou 		clock = mmc->cfg->f_min;
1213272cc70bSAndy Fleming 
1214272cc70bSAndy Fleming 	mmc->clock = clock;
1215272cc70bSAndy Fleming 
1216272cc70bSAndy Fleming 	mmc_set_ios(mmc);
1217272cc70bSAndy Fleming }
1218272cc70bSAndy Fleming 
1219fdbb873eSKim Phillips static void mmc_set_bus_width(struct mmc *mmc, uint width)
1220272cc70bSAndy Fleming {
1221272cc70bSAndy Fleming 	mmc->bus_width = width;
1222272cc70bSAndy Fleming 
1223272cc70bSAndy Fleming 	mmc_set_ios(mmc);
1224272cc70bSAndy Fleming }
1225272cc70bSAndy Fleming 
12264c9d2aaaSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG)
12274c9d2aaaSJean-Jacques Hiblot /*
12284c9d2aaaSJean-Jacques Hiblot  * helper function to display the capabilities in a human
12294c9d2aaaSJean-Jacques Hiblot  * friendly manner. The capabilities include bus width and
12304c9d2aaaSJean-Jacques Hiblot  * supported modes.
12314c9d2aaaSJean-Jacques Hiblot  */
12324c9d2aaaSJean-Jacques Hiblot void mmc_dump_capabilities(const char *text, uint caps)
12334c9d2aaaSJean-Jacques Hiblot {
12344c9d2aaaSJean-Jacques Hiblot 	enum bus_mode mode;
12354c9d2aaaSJean-Jacques Hiblot 
12364c9d2aaaSJean-Jacques Hiblot 	printf("%s: widths [", text);
12374c9d2aaaSJean-Jacques Hiblot 	if (caps & MMC_MODE_8BIT)
12384c9d2aaaSJean-Jacques Hiblot 		printf("8, ");
12394c9d2aaaSJean-Jacques Hiblot 	if (caps & MMC_MODE_4BIT)
12404c9d2aaaSJean-Jacques Hiblot 		printf("4, ");
1241d0c221feSJean-Jacques Hiblot 	if (caps & MMC_MODE_1BIT)
1242d0c221feSJean-Jacques Hiblot 		printf("1, ");
1243d0c221feSJean-Jacques Hiblot 	printf("\b\b] modes [");
12444c9d2aaaSJean-Jacques Hiblot 	for (mode = MMC_LEGACY; mode < MMC_MODES_END; mode++)
12454c9d2aaaSJean-Jacques Hiblot 		if (MMC_CAP(mode) & caps)
12464c9d2aaaSJean-Jacques Hiblot 			printf("%s, ", mmc_mode_name(mode));
12474c9d2aaaSJean-Jacques Hiblot 	printf("\b\b]\n");
12484c9d2aaaSJean-Jacques Hiblot }
12494c9d2aaaSJean-Jacques Hiblot #endif
12504c9d2aaaSJean-Jacques Hiblot 
1251d0c221feSJean-Jacques Hiblot struct mode_width_tuning {
1252d0c221feSJean-Jacques Hiblot 	enum bus_mode mode;
1253d0c221feSJean-Jacques Hiblot 	uint widths;
1254d0c221feSJean-Jacques Hiblot };
1255d0c221feSJean-Jacques Hiblot 
1256d0c221feSJean-Jacques Hiblot static const struct mode_width_tuning sd_modes_by_pref[] = {
1257d0c221feSJean-Jacques Hiblot 	{
1258d0c221feSJean-Jacques Hiblot 		.mode = SD_HS,
1259d0c221feSJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1260d0c221feSJean-Jacques Hiblot 	},
1261d0c221feSJean-Jacques Hiblot 	{
1262d0c221feSJean-Jacques Hiblot 		.mode = SD_LEGACY,
1263d0c221feSJean-Jacques Hiblot 		.widths = MMC_MODE_4BIT | MMC_MODE_1BIT,
1264d0c221feSJean-Jacques Hiblot 	}
1265d0c221feSJean-Jacques Hiblot };
1266d0c221feSJean-Jacques Hiblot 
1267d0c221feSJean-Jacques Hiblot #define for_each_sd_mode_by_pref(caps, mwt) \
1268d0c221feSJean-Jacques Hiblot 	for (mwt = sd_modes_by_pref;\
1269d0c221feSJean-Jacques Hiblot 	     mwt < sd_modes_by_pref + ARRAY_SIZE(sd_modes_by_pref);\
1270d0c221feSJean-Jacques Hiblot 	     mwt++) \
1271d0c221feSJean-Jacques Hiblot 		if (caps & MMC_CAP(mwt->mode))
1272d0c221feSJean-Jacques Hiblot 
1273d0c221feSJean-Jacques Hiblot static int sd_select_mode_and_width(struct mmc *mmc)
12748ac8a263SJean-Jacques Hiblot {
12758ac8a263SJean-Jacques Hiblot 	int err;
1276d0c221feSJean-Jacques Hiblot 	uint widths[] = {MMC_MODE_4BIT, MMC_MODE_1BIT};
1277d0c221feSJean-Jacques Hiblot 	const struct mode_width_tuning *mwt;
12788ac8a263SJean-Jacques Hiblot 
1279d0c221feSJean-Jacques Hiblot 	err = sd_get_capabilities(mmc);
12808ac8a263SJean-Jacques Hiblot 	if (err)
12818ac8a263SJean-Jacques Hiblot 		return err;
12828ac8a263SJean-Jacques Hiblot 	/* Restrict card's capabilities by what the host can do */
1283d0c221feSJean-Jacques Hiblot 	mmc->card_caps &= (mmc->cfg->host_caps | MMC_MODE_1BIT);
12848ac8a263SJean-Jacques Hiblot 
1285d0c221feSJean-Jacques Hiblot 	for_each_sd_mode_by_pref(mmc->card_caps, mwt) {
1286d0c221feSJean-Jacques Hiblot 		uint *w;
12878ac8a263SJean-Jacques Hiblot 
1288d0c221feSJean-Jacques Hiblot 		for (w = widths; w < widths + ARRAY_SIZE(widths); w++) {
1289d0c221feSJean-Jacques Hiblot 			if (*w & mmc->card_caps & mwt->widths) {
1290d0c221feSJean-Jacques Hiblot 				debug("trying mode %s width %d (at %d MHz)\n",
1291d0c221feSJean-Jacques Hiblot 				      mmc_mode_name(mwt->mode),
1292d0c221feSJean-Jacques Hiblot 				      bus_width(*w),
1293d0c221feSJean-Jacques Hiblot 				      mmc_mode2freq(mmc, mwt->mode) / 1000000);
1294d0c221feSJean-Jacques Hiblot 
1295d0c221feSJean-Jacques Hiblot 				/* configure the bus width (card + host) */
1296d0c221feSJean-Jacques Hiblot 				err = sd_select_bus_width(mmc, bus_width(*w));
12978ac8a263SJean-Jacques Hiblot 				if (err)
1298d0c221feSJean-Jacques Hiblot 					goto error;
1299d0c221feSJean-Jacques Hiblot 				mmc_set_bus_width(mmc, bus_width(*w));
13008ac8a263SJean-Jacques Hiblot 
1301d0c221feSJean-Jacques Hiblot 				/* configure the bus mode (card) */
1302d0c221feSJean-Jacques Hiblot 				err = sd_set_card_speed(mmc, mwt->mode);
13038ac8a263SJean-Jacques Hiblot 				if (err)
1304d0c221feSJean-Jacques Hiblot 					goto error;
13058ac8a263SJean-Jacques Hiblot 
1306d0c221feSJean-Jacques Hiblot 				/* configure the bus mode (host) */
1307d0c221feSJean-Jacques Hiblot 				mmc_select_mode(mmc, mwt->mode);
1308d0c221feSJean-Jacques Hiblot 				mmc_set_clock(mmc, mmc->tran_speed);
13098ac8a263SJean-Jacques Hiblot 
13108ac8a263SJean-Jacques Hiblot 				err = sd_read_ssr(mmc);
1311d0c221feSJean-Jacques Hiblot 				if (!err)
13128ac8a263SJean-Jacques Hiblot 					return 0;
1313d0c221feSJean-Jacques Hiblot 
1314d0c221feSJean-Jacques Hiblot 				printf("bad ssr\n");
1315d0c221feSJean-Jacques Hiblot 
1316d0c221feSJean-Jacques Hiblot error:
1317d0c221feSJean-Jacques Hiblot 				/* revert to a safer bus speed */
1318d0c221feSJean-Jacques Hiblot 				mmc_select_mode(mmc, SD_LEGACY);
1319d0c221feSJean-Jacques Hiblot 				mmc_set_clock(mmc, mmc->tran_speed);
1320d0c221feSJean-Jacques Hiblot 			}
1321d0c221feSJean-Jacques Hiblot 		}
1322d0c221feSJean-Jacques Hiblot 	}
1323d0c221feSJean-Jacques Hiblot 
1324d0c221feSJean-Jacques Hiblot 	printf("unable to select a mode\n");
1325d0c221feSJean-Jacques Hiblot 	return -ENOTSUPP;
13268ac8a263SJean-Jacques Hiblot }
13278ac8a263SJean-Jacques Hiblot 
13287382e691SJean-Jacques Hiblot /*
13297382e691SJean-Jacques Hiblot  * read the compare the part of ext csd that is constant.
13307382e691SJean-Jacques Hiblot  * This can be used to check that the transfer is working
13317382e691SJean-Jacques Hiblot  * as expected.
13327382e691SJean-Jacques Hiblot  */
13337382e691SJean-Jacques Hiblot static int mmc_read_and_compare_ext_csd(struct mmc *mmc)
13347382e691SJean-Jacques Hiblot {
13357382e691SJean-Jacques Hiblot 	int err;
13367382e691SJean-Jacques Hiblot 	const u8 *ext_csd = mmc->ext_csd;
13377382e691SJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
13387382e691SJean-Jacques Hiblot 
13397382e691SJean-Jacques Hiblot 	err = mmc_send_ext_csd(mmc, test_csd);
13407382e691SJean-Jacques Hiblot 	if (err)
13417382e691SJean-Jacques Hiblot 		return err;
13427382e691SJean-Jacques Hiblot 
13437382e691SJean-Jacques Hiblot 	/* Only compare read only fields */
13447382e691SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT]
13457382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_PARTITIONING_SUPPORT] &&
13467382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_HC_WP_GRP_SIZE]
13477382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_HC_WP_GRP_SIZE] &&
13487382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_REV]
13497382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_REV] &&
13507382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
13517382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] &&
13527382e691SJean-Jacques Hiblot 	    memcmp(&ext_csd[EXT_CSD_SEC_CNT],
13537382e691SJean-Jacques Hiblot 		   &test_csd[EXT_CSD_SEC_CNT], 4) == 0)
13547382e691SJean-Jacques Hiblot 		return 0;
13557382e691SJean-Jacques Hiblot 
13567382e691SJean-Jacques Hiblot 	return -EBADMSG;
13577382e691SJean-Jacques Hiblot }
13587382e691SJean-Jacques Hiblot 
1359*3862b854SJean-Jacques Hiblot static const struct mode_width_tuning mmc_modes_by_pref[] = {
13608ac8a263SJean-Jacques Hiblot 	{
1361*3862b854SJean-Jacques Hiblot 		.mode = MMC_HS_200,
1362*3862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
1363*3862b854SJean-Jacques Hiblot 	},
1364*3862b854SJean-Jacques Hiblot 	{
1365*3862b854SJean-Jacques Hiblot 		.mode = MMC_DDR_52,
1366*3862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT,
1367*3862b854SJean-Jacques Hiblot 	},
1368*3862b854SJean-Jacques Hiblot 	{
1369*3862b854SJean-Jacques Hiblot 		.mode = MMC_HS_52,
1370*3862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
1371*3862b854SJean-Jacques Hiblot 	},
1372*3862b854SJean-Jacques Hiblot 	{
1373*3862b854SJean-Jacques Hiblot 		.mode = MMC_HS,
1374*3862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
1375*3862b854SJean-Jacques Hiblot 	},
1376*3862b854SJean-Jacques Hiblot 	{
1377*3862b854SJean-Jacques Hiblot 		.mode = MMC_LEGACY,
1378*3862b854SJean-Jacques Hiblot 		.widths = MMC_MODE_8BIT | MMC_MODE_4BIT | MMC_MODE_1BIT,
1379*3862b854SJean-Jacques Hiblot 	}
13808ac8a263SJean-Jacques Hiblot };
13818ac8a263SJean-Jacques Hiblot 
1382*3862b854SJean-Jacques Hiblot #define for_each_mmc_mode_by_pref(caps, mwt) \
1383*3862b854SJean-Jacques Hiblot 	for (mwt = mmc_modes_by_pref;\
1384*3862b854SJean-Jacques Hiblot 	    mwt < mmc_modes_by_pref + ARRAY_SIZE(mmc_modes_by_pref);\
1385*3862b854SJean-Jacques Hiblot 	    mwt++) \
1386*3862b854SJean-Jacques Hiblot 		if (caps & MMC_CAP(mwt->mode))
1387*3862b854SJean-Jacques Hiblot 
1388*3862b854SJean-Jacques Hiblot static const struct ext_csd_bus_width {
1389*3862b854SJean-Jacques Hiblot 	uint cap;
1390*3862b854SJean-Jacques Hiblot 	bool is_ddr;
1391*3862b854SJean-Jacques Hiblot 	uint ext_csd_bits;
1392*3862b854SJean-Jacques Hiblot } ext_csd_bus_width[] = {
1393*3862b854SJean-Jacques Hiblot 	{MMC_MODE_8BIT, true, EXT_CSD_DDR_BUS_WIDTH_8},
1394*3862b854SJean-Jacques Hiblot 	{MMC_MODE_4BIT, true, EXT_CSD_DDR_BUS_WIDTH_4},
1395*3862b854SJean-Jacques Hiblot 	{MMC_MODE_8BIT, false, EXT_CSD_BUS_WIDTH_8},
1396*3862b854SJean-Jacques Hiblot 	{MMC_MODE_4BIT, false, EXT_CSD_BUS_WIDTH_4},
1397*3862b854SJean-Jacques Hiblot 	{MMC_MODE_1BIT, false, EXT_CSD_BUS_WIDTH_1},
1398*3862b854SJean-Jacques Hiblot };
1399*3862b854SJean-Jacques Hiblot 
1400*3862b854SJean-Jacques Hiblot #define for_each_supported_width(caps, ddr, ecbv) \
1401*3862b854SJean-Jacques Hiblot 	for (ecbv = ext_csd_bus_width;\
1402*3862b854SJean-Jacques Hiblot 	    ecbv < ext_csd_bus_width + ARRAY_SIZE(ext_csd_bus_width);\
1403*3862b854SJean-Jacques Hiblot 	    ecbv++) \
1404*3862b854SJean-Jacques Hiblot 		if ((ddr == ecbv->is_ddr) && (caps & ecbv->cap))
1405*3862b854SJean-Jacques Hiblot 
1406*3862b854SJean-Jacques Hiblot static int mmc_select_mode_and_width(struct mmc *mmc)
1407*3862b854SJean-Jacques Hiblot {
1408*3862b854SJean-Jacques Hiblot 	int err;
1409*3862b854SJean-Jacques Hiblot 	const struct mode_width_tuning *mwt;
1410*3862b854SJean-Jacques Hiblot 	const struct ext_csd_bus_width *ecbw;
1411*3862b854SJean-Jacques Hiblot 
1412*3862b854SJean-Jacques Hiblot 	err = mmc_get_capabilities(mmc);
14138ac8a263SJean-Jacques Hiblot 	if (err)
14148ac8a263SJean-Jacques Hiblot 		return err;
14158ac8a263SJean-Jacques Hiblot 
14168ac8a263SJean-Jacques Hiblot 	/* Restrict card's capabilities by what the host can do */
1417d0c221feSJean-Jacques Hiblot 	mmc->card_caps &= (mmc->cfg->host_caps | MMC_MODE_1BIT);
14188ac8a263SJean-Jacques Hiblot 
14198ac8a263SJean-Jacques Hiblot 	/* Only version 4 of MMC supports wider bus widths */
14208ac8a263SJean-Jacques Hiblot 	if (mmc->version < MMC_VERSION_4)
14218ac8a263SJean-Jacques Hiblot 		return 0;
14228ac8a263SJean-Jacques Hiblot 
1423dfda9d88SJean-Jacques Hiblot 	if (!mmc->ext_csd) {
1424dfda9d88SJean-Jacques Hiblot 		debug("No ext_csd found!\n"); /* this should enver happen */
1425dfda9d88SJean-Jacques Hiblot 		return -ENOTSUPP;
1426dfda9d88SJean-Jacques Hiblot 	}
1427dfda9d88SJean-Jacques Hiblot 
1428*3862b854SJean-Jacques Hiblot 	for_each_mmc_mode_by_pref(mmc->card_caps, mwt) {
1429*3862b854SJean-Jacques Hiblot 		for_each_supported_width(mmc->card_caps & mwt->widths,
1430*3862b854SJean-Jacques Hiblot 					 mmc_is_mode_ddr(mwt->mode), ecbw) {
1431*3862b854SJean-Jacques Hiblot 			debug("trying mode %s width %d (at %d MHz)\n",
1432*3862b854SJean-Jacques Hiblot 			      mmc_mode_name(mwt->mode),
1433*3862b854SJean-Jacques Hiblot 			      bus_width(ecbw->cap),
1434*3862b854SJean-Jacques Hiblot 			      mmc_mode2freq(mmc, mwt->mode) / 1000000);
1435*3862b854SJean-Jacques Hiblot 			/* configure the bus width (card + host) */
1436*3862b854SJean-Jacques Hiblot 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1437*3862b854SJean-Jacques Hiblot 				    EXT_CSD_BUS_WIDTH,
1438*3862b854SJean-Jacques Hiblot 				    ecbw->ext_csd_bits & ~EXT_CSD_DDR_FLAG);
1439*3862b854SJean-Jacques Hiblot 			if (err)
1440*3862b854SJean-Jacques Hiblot 				goto error;
1441*3862b854SJean-Jacques Hiblot 			mmc_set_bus_width(mmc, bus_width(ecbw->cap));
1442*3862b854SJean-Jacques Hiblot 
1443*3862b854SJean-Jacques Hiblot 			/* configure the bus speed (card) */
1444*3862b854SJean-Jacques Hiblot 			err = mmc_set_card_speed(mmc, mwt->mode);
1445*3862b854SJean-Jacques Hiblot 			if (err)
1446*3862b854SJean-Jacques Hiblot 				goto error;
1447*3862b854SJean-Jacques Hiblot 
14488ac8a263SJean-Jacques Hiblot 			/*
1449*3862b854SJean-Jacques Hiblot 			 * configure the bus width AND the ddr mode (card)
1450*3862b854SJean-Jacques Hiblot 			 * The host side will be taken care of in the next step
14518ac8a263SJean-Jacques Hiblot 			 */
1452*3862b854SJean-Jacques Hiblot 			if (ecbw->ext_csd_bits & EXT_CSD_DDR_FLAG) {
1453*3862b854SJean-Jacques Hiblot 				err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1454*3862b854SJean-Jacques Hiblot 						 EXT_CSD_BUS_WIDTH,
1455*3862b854SJean-Jacques Hiblot 						 ecbw->ext_csd_bits);
1456*3862b854SJean-Jacques Hiblot 				if (err)
1457*3862b854SJean-Jacques Hiblot 					goto error;
14588ac8a263SJean-Jacques Hiblot 			}
14598ac8a263SJean-Jacques Hiblot 
1460*3862b854SJean-Jacques Hiblot 			/* configure the bus mode (host) */
1461*3862b854SJean-Jacques Hiblot 			mmc_select_mode(mmc, mwt->mode);
1462*3862b854SJean-Jacques Hiblot 			mmc_set_clock(mmc, mmc->tran_speed);
14638ac8a263SJean-Jacques Hiblot 
1464*3862b854SJean-Jacques Hiblot 			/* do a transfer to check the configuration */
14657382e691SJean-Jacques Hiblot 			err = mmc_read_and_compare_ext_csd(mmc);
14667382e691SJean-Jacques Hiblot 			if (!err)
1467*3862b854SJean-Jacques Hiblot 				return 0;
1468*3862b854SJean-Jacques Hiblot error:
1469*3862b854SJean-Jacques Hiblot 			/* if an error occured, revert to a safer bus mode */
1470*3862b854SJean-Jacques Hiblot 			mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1471*3862b854SJean-Jacques Hiblot 				   EXT_CSD_BUS_WIDTH, EXT_CSD_BUS_WIDTH_1);
1472*3862b854SJean-Jacques Hiblot 			mmc_select_mode(mmc, MMC_LEGACY);
1473*3862b854SJean-Jacques Hiblot 			mmc_set_bus_width(mmc, 1);
1474*3862b854SJean-Jacques Hiblot 		}
14758ac8a263SJean-Jacques Hiblot 	}
14768ac8a263SJean-Jacques Hiblot 
1477*3862b854SJean-Jacques Hiblot 	printf("unable to select a mode\n");
14788ac8a263SJean-Jacques Hiblot 
1479*3862b854SJean-Jacques Hiblot 	return -ENOTSUPP;
14808ac8a263SJean-Jacques Hiblot }
14818ac8a263SJean-Jacques Hiblot 
1482dfda9d88SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc)
1483c744b6f6SJean-Jacques Hiblot {
1484c744b6f6SJean-Jacques Hiblot 	int err, i;
1485c744b6f6SJean-Jacques Hiblot 	u64 capacity;
1486c744b6f6SJean-Jacques Hiblot 	bool has_parts = false;
1487c744b6f6SJean-Jacques Hiblot 	bool part_completed;
1488dfda9d88SJean-Jacques Hiblot 	u8 *ext_csd;
1489c744b6f6SJean-Jacques Hiblot 
1490c744b6f6SJean-Jacques Hiblot 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4))
1491c744b6f6SJean-Jacques Hiblot 		return 0;
1492c744b6f6SJean-Jacques Hiblot 
1493dfda9d88SJean-Jacques Hiblot 	ext_csd = malloc_cache_aligned(MMC_MAX_BLOCK_LEN);
1494dfda9d88SJean-Jacques Hiblot 	if (!ext_csd)
1495dfda9d88SJean-Jacques Hiblot 		return -ENOMEM;
1496dfda9d88SJean-Jacques Hiblot 
1497dfda9d88SJean-Jacques Hiblot 	mmc->ext_csd = ext_csd;
1498dfda9d88SJean-Jacques Hiblot 
1499c744b6f6SJean-Jacques Hiblot 	/* check  ext_csd version and capacity */
1500c744b6f6SJean-Jacques Hiblot 	err = mmc_send_ext_csd(mmc, ext_csd);
1501c744b6f6SJean-Jacques Hiblot 	if (err)
1502c744b6f6SJean-Jacques Hiblot 		return err;
1503c744b6f6SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_REV] >= 2) {
1504c744b6f6SJean-Jacques Hiblot 		/*
1505c744b6f6SJean-Jacques Hiblot 		 * According to the JEDEC Standard, the value of
1506c744b6f6SJean-Jacques Hiblot 		 * ext_csd's capacity is valid if the value is more
1507c744b6f6SJean-Jacques Hiblot 		 * than 2GB
1508c744b6f6SJean-Jacques Hiblot 		 */
1509c744b6f6SJean-Jacques Hiblot 		capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
1510c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
1511c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
1512c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
1513c744b6f6SJean-Jacques Hiblot 		capacity *= MMC_MAX_BLOCK_LEN;
1514c744b6f6SJean-Jacques Hiblot 		if ((capacity >> 20) > 2 * 1024)
1515c744b6f6SJean-Jacques Hiblot 			mmc->capacity_user = capacity;
1516c744b6f6SJean-Jacques Hiblot 	}
1517c744b6f6SJean-Jacques Hiblot 
1518c744b6f6SJean-Jacques Hiblot 	switch (ext_csd[EXT_CSD_REV]) {
1519c744b6f6SJean-Jacques Hiblot 	case 1:
1520c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_1;
1521c744b6f6SJean-Jacques Hiblot 		break;
1522c744b6f6SJean-Jacques Hiblot 	case 2:
1523c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_2;
1524c744b6f6SJean-Jacques Hiblot 		break;
1525c744b6f6SJean-Jacques Hiblot 	case 3:
1526c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_3;
1527c744b6f6SJean-Jacques Hiblot 		break;
1528c744b6f6SJean-Jacques Hiblot 	case 5:
1529c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_41;
1530c744b6f6SJean-Jacques Hiblot 		break;
1531c744b6f6SJean-Jacques Hiblot 	case 6:
1532c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_5;
1533c744b6f6SJean-Jacques Hiblot 		break;
1534c744b6f6SJean-Jacques Hiblot 	case 7:
1535c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_5_0;
1536c744b6f6SJean-Jacques Hiblot 		break;
1537c744b6f6SJean-Jacques Hiblot 	case 8:
1538c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_5_1;
1539c744b6f6SJean-Jacques Hiblot 		break;
1540c744b6f6SJean-Jacques Hiblot 	}
1541c744b6f6SJean-Jacques Hiblot 
1542c744b6f6SJean-Jacques Hiblot 	/* The partition data may be non-zero but it is only
1543c744b6f6SJean-Jacques Hiblot 	 * effective if PARTITION_SETTING_COMPLETED is set in
1544c744b6f6SJean-Jacques Hiblot 	 * EXT_CSD, so ignore any data if this bit is not set,
1545c744b6f6SJean-Jacques Hiblot 	 * except for enabling the high-capacity group size
1546c744b6f6SJean-Jacques Hiblot 	 * definition (see below).
1547c744b6f6SJean-Jacques Hiblot 	 */
1548c744b6f6SJean-Jacques Hiblot 	part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
1549c744b6f6SJean-Jacques Hiblot 			    EXT_CSD_PARTITION_SETTING_COMPLETED);
1550c744b6f6SJean-Jacques Hiblot 
1551c744b6f6SJean-Jacques Hiblot 	/* store the partition info of emmc */
1552c744b6f6SJean-Jacques Hiblot 	mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
1553c744b6f6SJean-Jacques Hiblot 	if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
1554c744b6f6SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_BOOT_MULT])
1555c744b6f6SJean-Jacques Hiblot 		mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
1556c744b6f6SJean-Jacques Hiblot 	if (part_completed &&
1557c744b6f6SJean-Jacques Hiblot 	    (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
1558c744b6f6SJean-Jacques Hiblot 		mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
1559c744b6f6SJean-Jacques Hiblot 
1560c744b6f6SJean-Jacques Hiblot 	mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
1561c744b6f6SJean-Jacques Hiblot 
1562c744b6f6SJean-Jacques Hiblot 	mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
1563c744b6f6SJean-Jacques Hiblot 
1564c744b6f6SJean-Jacques Hiblot 	for (i = 0; i < 4; i++) {
1565c744b6f6SJean-Jacques Hiblot 		int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
1566c744b6f6SJean-Jacques Hiblot 		uint mult = (ext_csd[idx + 2] << 16) +
1567c744b6f6SJean-Jacques Hiblot 			(ext_csd[idx + 1] << 8) + ext_csd[idx];
1568c744b6f6SJean-Jacques Hiblot 		if (mult)
1569c744b6f6SJean-Jacques Hiblot 			has_parts = true;
1570c744b6f6SJean-Jacques Hiblot 		if (!part_completed)
1571c744b6f6SJean-Jacques Hiblot 			continue;
1572c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] = mult;
1573c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] *=
1574c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1575c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1576c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] <<= 19;
1577c744b6f6SJean-Jacques Hiblot 	}
1578c744b6f6SJean-Jacques Hiblot 
1579c744b6f6SJean-Jacques Hiblot 	if (part_completed) {
1580c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size =
1581c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) +
1582c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) +
1583c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_ENH_SIZE_MULT];
1584c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1585c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1586c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size <<= 19;
1587c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_start =
1588c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) +
1589c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) +
1590c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) +
1591c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_ENH_START_ADDR];
1592c744b6f6SJean-Jacques Hiblot 		if (mmc->high_capacity)
1593c744b6f6SJean-Jacques Hiblot 			mmc->enh_user_start <<= 9;
1594c744b6f6SJean-Jacques Hiblot 	}
1595c744b6f6SJean-Jacques Hiblot 
1596c744b6f6SJean-Jacques Hiblot 	/*
1597c744b6f6SJean-Jacques Hiblot 	 * Host needs to enable ERASE_GRP_DEF bit if device is
1598c744b6f6SJean-Jacques Hiblot 	 * partitioned. This bit will be lost every time after a reset
1599c744b6f6SJean-Jacques Hiblot 	 * or power off. This will affect erase size.
1600c744b6f6SJean-Jacques Hiblot 	 */
1601c744b6f6SJean-Jacques Hiblot 	if (part_completed)
1602c744b6f6SJean-Jacques Hiblot 		has_parts = true;
1603c744b6f6SJean-Jacques Hiblot 	if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
1604c744b6f6SJean-Jacques Hiblot 	    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
1605c744b6f6SJean-Jacques Hiblot 		has_parts = true;
1606c744b6f6SJean-Jacques Hiblot 	if (has_parts) {
1607c744b6f6SJean-Jacques Hiblot 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1608c744b6f6SJean-Jacques Hiblot 				 EXT_CSD_ERASE_GROUP_DEF, 1);
1609c744b6f6SJean-Jacques Hiblot 
1610c744b6f6SJean-Jacques Hiblot 		if (err)
1611c744b6f6SJean-Jacques Hiblot 			return err;
1612c744b6f6SJean-Jacques Hiblot 
1613c744b6f6SJean-Jacques Hiblot 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1614c744b6f6SJean-Jacques Hiblot 	}
1615c744b6f6SJean-Jacques Hiblot 
1616c744b6f6SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
1617c744b6f6SJean-Jacques Hiblot 		/* Read out group size from ext_csd */
1618c744b6f6SJean-Jacques Hiblot 		mmc->erase_grp_size =
1619c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1620c744b6f6SJean-Jacques Hiblot 		/*
1621c744b6f6SJean-Jacques Hiblot 		 * if high capacity and partition setting completed
1622c744b6f6SJean-Jacques Hiblot 		 * SEC_COUNT is valid even if it is smaller than 2 GiB
1623c744b6f6SJean-Jacques Hiblot 		 * JEDEC Standard JESD84-B45, 6.2.4
1624c744b6f6SJean-Jacques Hiblot 		 */
1625c744b6f6SJean-Jacques Hiblot 		if (mmc->high_capacity && part_completed) {
1626c744b6f6SJean-Jacques Hiblot 			capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
1627c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
1628c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
1629c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
1630c744b6f6SJean-Jacques Hiblot 			capacity *= MMC_MAX_BLOCK_LEN;
1631c744b6f6SJean-Jacques Hiblot 			mmc->capacity_user = capacity;
1632c744b6f6SJean-Jacques Hiblot 		}
1633c744b6f6SJean-Jacques Hiblot 	} else {
1634c744b6f6SJean-Jacques Hiblot 		/* Calculate the group size from the csd value. */
1635c744b6f6SJean-Jacques Hiblot 		int erase_gsz, erase_gmul;
1636c744b6f6SJean-Jacques Hiblot 
1637c744b6f6SJean-Jacques Hiblot 		erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
1638c744b6f6SJean-Jacques Hiblot 		erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
1639c744b6f6SJean-Jacques Hiblot 		mmc->erase_grp_size = (erase_gsz + 1)
1640c744b6f6SJean-Jacques Hiblot 			* (erase_gmul + 1);
1641c744b6f6SJean-Jacques Hiblot 	}
1642c744b6f6SJean-Jacques Hiblot 
1643c744b6f6SJean-Jacques Hiblot 	mmc->hc_wp_grp_size = 1024
1644c744b6f6SJean-Jacques Hiblot 		* ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
1645c744b6f6SJean-Jacques Hiblot 		* ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1646c744b6f6SJean-Jacques Hiblot 
1647c744b6f6SJean-Jacques Hiblot 	mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
1648c744b6f6SJean-Jacques Hiblot 
1649c744b6f6SJean-Jacques Hiblot 	return 0;
1650c744b6f6SJean-Jacques Hiblot }
1651c744b6f6SJean-Jacques Hiblot 
1652fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc)
1653272cc70bSAndy Fleming {
1654f866a46dSStephen Warren 	int err, i;
1655272cc70bSAndy Fleming 	uint mult, freq;
1656c744b6f6SJean-Jacques Hiblot 	u64 cmult, csize;
1657272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1658c40fdca6SSimon Glass 	struct blk_desc *bdesc;
1659272cc70bSAndy Fleming 
1660d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
1661d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
1662d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
1663d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
1664d52ebf10SThomas Chou 		cmd.cmdarg = 1;
1665d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
1666d52ebf10SThomas Chou 
1667d52ebf10SThomas Chou 		if (err)
1668d52ebf10SThomas Chou 			return err;
1669d52ebf10SThomas Chou 	}
1670d52ebf10SThomas Chou #endif
1671d52ebf10SThomas Chou 
1672272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
1673d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
1674d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
1675272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1676272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1677272cc70bSAndy Fleming 
1678272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1679272cc70bSAndy Fleming 
1680272cc70bSAndy Fleming 	if (err)
1681272cc70bSAndy Fleming 		return err;
1682272cc70bSAndy Fleming 
1683272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
1684272cc70bSAndy Fleming 
1685272cc70bSAndy Fleming 	/*
1686272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
1687272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
1688272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
1689272cc70bSAndy Fleming 	 */
1690d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1691272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
1692272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1693272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
1694272cc70bSAndy Fleming 
1695272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1696272cc70bSAndy Fleming 
1697272cc70bSAndy Fleming 		if (err)
1698272cc70bSAndy Fleming 			return err;
1699272cc70bSAndy Fleming 
1700272cc70bSAndy Fleming 		if (IS_SD(mmc))
1701998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
1702d52ebf10SThomas Chou 	}
1703272cc70bSAndy Fleming 
1704272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
1705272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
1706272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1707272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1708272cc70bSAndy Fleming 
1709272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1710272cc70bSAndy Fleming 
1711272cc70bSAndy Fleming 	if (err)
1712272cc70bSAndy Fleming 		return err;
1713272cc70bSAndy Fleming 
1714998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
1715998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
1716998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
1717998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
1718272cc70bSAndy Fleming 
1719272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
17200b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
1721272cc70bSAndy Fleming 
1722272cc70bSAndy Fleming 		switch (version) {
1723272cc70bSAndy Fleming 		case 0:
1724272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1725272cc70bSAndy Fleming 			break;
1726272cc70bSAndy Fleming 		case 1:
1727272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_4;
1728272cc70bSAndy Fleming 			break;
1729272cc70bSAndy Fleming 		case 2:
1730272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_2_2;
1731272cc70bSAndy Fleming 			break;
1732272cc70bSAndy Fleming 		case 3:
1733272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_3;
1734272cc70bSAndy Fleming 			break;
1735272cc70bSAndy Fleming 		case 4:
1736272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_4;
1737272cc70bSAndy Fleming 			break;
1738272cc70bSAndy Fleming 		default:
1739272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1740272cc70bSAndy Fleming 			break;
1741272cc70bSAndy Fleming 		}
1742272cc70bSAndy Fleming 	}
1743272cc70bSAndy Fleming 
1744272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
17450b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
17460b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
1747272cc70bSAndy Fleming 
174835f9e196SJean-Jacques Hiblot 	mmc->legacy_speed = freq * mult;
174935f9e196SJean-Jacques Hiblot 	mmc_select_mode(mmc, MMC_LEGACY);
1750272cc70bSAndy Fleming 
1751ab71188cSMarkus Niebel 	mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
1752998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
1753272cc70bSAndy Fleming 
1754272cc70bSAndy Fleming 	if (IS_SD(mmc))
1755272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
1756272cc70bSAndy Fleming 	else
1757998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
1758272cc70bSAndy Fleming 
1759272cc70bSAndy Fleming 	if (mmc->high_capacity) {
1760272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
1761272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
1762272cc70bSAndy Fleming 		cmult = 8;
1763272cc70bSAndy Fleming 	} else {
1764272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
1765272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
1766272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
1767272cc70bSAndy Fleming 	}
1768272cc70bSAndy Fleming 
1769f866a46dSStephen Warren 	mmc->capacity_user = (csize + 1) << (cmult + 2);
1770f866a46dSStephen Warren 	mmc->capacity_user *= mmc->read_bl_len;
1771f866a46dSStephen Warren 	mmc->capacity_boot = 0;
1772f866a46dSStephen Warren 	mmc->capacity_rpmb = 0;
1773f866a46dSStephen Warren 	for (i = 0; i < 4; i++)
1774f866a46dSStephen Warren 		mmc->capacity_gp[i] = 0;
1775272cc70bSAndy Fleming 
17768bfa195eSSimon Glass 	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
17778bfa195eSSimon Glass 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
1778272cc70bSAndy Fleming 
17798bfa195eSSimon Glass 	if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
17808bfa195eSSimon Glass 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
1781272cc70bSAndy Fleming 
1782ab71188cSMarkus Niebel 	if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
1783ab71188cSMarkus Niebel 		cmd.cmdidx = MMC_CMD_SET_DSR;
1784ab71188cSMarkus Niebel 		cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
1785ab71188cSMarkus Niebel 		cmd.resp_type = MMC_RSP_NONE;
1786ab71188cSMarkus Niebel 		if (mmc_send_cmd(mmc, &cmd, NULL))
1787ab71188cSMarkus Niebel 			printf("MMC: SET_DSR failed\n");
1788ab71188cSMarkus Niebel 	}
1789ab71188cSMarkus Niebel 
1790272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
1791d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1792272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
1793fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
1794272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1795272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1796272cc70bSAndy Fleming 
1797272cc70bSAndy Fleming 		if (err)
1798272cc70bSAndy Fleming 			return err;
1799d52ebf10SThomas Chou 	}
1800272cc70bSAndy Fleming 
1801e6f99a56SLei Wen 	/*
1802e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
1803e6f99a56SLei Wen 	 */
1804e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
1805bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
1806c744b6f6SJean-Jacques Hiblot 
1807dfda9d88SJean-Jacques Hiblot 	err = mmc_startup_v4(mmc);
18089cf199ebSDiego Santa Cruz 	if (err)
18099cf199ebSDiego Santa Cruz 		return err;
1810f866a46dSStephen Warren 
1811c40fdca6SSimon Glass 	err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart);
1812f866a46dSStephen Warren 	if (err)
1813f866a46dSStephen Warren 		return err;
1814d23e2c09SSukumar Ghorai 
1815272cc70bSAndy Fleming 	if (IS_SD(mmc))
1816d0c221feSJean-Jacques Hiblot 		err = sd_select_mode_and_width(mmc);
1817272cc70bSAndy Fleming 	else
1818*3862b854SJean-Jacques Hiblot 		err = mmc_select_mode_and_width(mmc);
1819272cc70bSAndy Fleming 
1820272cc70bSAndy Fleming 	if (err)
1821272cc70bSAndy Fleming 		return err;
1822272cc70bSAndy Fleming 
1823272cc70bSAndy Fleming 
18245af8f45cSAndrew Gabbasov 	/* Fix the block length for DDR mode */
18255af8f45cSAndrew Gabbasov 	if (mmc->ddr_mode) {
18265af8f45cSAndrew Gabbasov 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
18275af8f45cSAndrew Gabbasov 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
18285af8f45cSAndrew Gabbasov 	}
18295af8f45cSAndrew Gabbasov 
1830272cc70bSAndy Fleming 	/* fill in device description */
1831c40fdca6SSimon Glass 	bdesc = mmc_get_blk_desc(mmc);
1832c40fdca6SSimon Glass 	bdesc->lun = 0;
1833c40fdca6SSimon Glass 	bdesc->hwpart = 0;
1834c40fdca6SSimon Glass 	bdesc->type = 0;
1835c40fdca6SSimon Glass 	bdesc->blksz = mmc->read_bl_len;
1836c40fdca6SSimon Glass 	bdesc->log2blksz = LOG2(bdesc->blksz);
1837c40fdca6SSimon Glass 	bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len);
1838fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \
1839fc011f64SSjoerd Simons 		(defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \
1840fc011f64SSjoerd Simons 		!defined(CONFIG_USE_TINY_PRINTF))
1841c40fdca6SSimon Glass 	sprintf(bdesc->vendor, "Man %06x Snr %04x%04x",
1842babce5f6STaylor Hutt 		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
1843babce5f6STaylor Hutt 		(mmc->cid[3] >> 16) & 0xffff);
1844c40fdca6SSimon Glass 	sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
18450b453ffeSRabin Vincent 		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
1846babce5f6STaylor Hutt 		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
1847babce5f6STaylor Hutt 		(mmc->cid[2] >> 24) & 0xff);
1848c40fdca6SSimon Glass 	sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
1849babce5f6STaylor Hutt 		(mmc->cid[2] >> 16) & 0xf);
185056196826SPaul Burton #else
1851c40fdca6SSimon Glass 	bdesc->vendor[0] = 0;
1852c40fdca6SSimon Glass 	bdesc->product[0] = 0;
1853c40fdca6SSimon Glass 	bdesc->revision[0] = 0;
185456196826SPaul Burton #endif
1855122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
1856c40fdca6SSimon Glass 	part_init(bdesc);
1857122efd43SMikhail Kshevetskiy #endif
1858272cc70bSAndy Fleming 
1859272cc70bSAndy Fleming 	return 0;
1860272cc70bSAndy Fleming }
1861272cc70bSAndy Fleming 
1862fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc)
1863272cc70bSAndy Fleming {
1864272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1865272cc70bSAndy Fleming 	int err;
1866272cc70bSAndy Fleming 
1867272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
1868272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
186993bfd616SPantelis Antoniou 	cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa;
1870272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
1871272cc70bSAndy Fleming 
1872272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1873272cc70bSAndy Fleming 
1874272cc70bSAndy Fleming 	if (err)
1875272cc70bSAndy Fleming 		return err;
1876272cc70bSAndy Fleming 
1877998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
1878915ffa52SJaehoon Chung 		return -EOPNOTSUPP;
1879272cc70bSAndy Fleming 	else
1880272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
1881272cc70bSAndy Fleming 
1882272cc70bSAndy Fleming 	return 0;
1883272cc70bSAndy Fleming }
1884272cc70bSAndy Fleming 
1885c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
188695de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */
188795de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void)
188895de9ab2SPaul Kocialkowski {
188995de9ab2SPaul Kocialkowski }
189005cbeb7cSSimon Glass #endif
189195de9ab2SPaul Kocialkowski 
18922051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc)
18932051aefeSPeng Fan {
1894c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
189506ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR)
18962051aefeSPeng Fan 	int ret;
18972051aefeSPeng Fan 
18982051aefeSPeng Fan 	ret = device_get_supply_regulator(mmc->dev, "vmmc-supply",
189906ec045fSJean-Jacques Hiblot 					  &mmc->vmmc_supply);
190006ec045fSJean-Jacques Hiblot 	if (ret)
1901288db7c7SJaehoon Chung 		debug("%s: No vmmc supply\n", mmc->dev->name);
19022051aefeSPeng Fan 
190306ec045fSJean-Jacques Hiblot 	ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply",
190406ec045fSJean-Jacques Hiblot 					  &mmc->vqmmc_supply);
190506ec045fSJean-Jacques Hiblot 	if (ret)
190606ec045fSJean-Jacques Hiblot 		debug("%s: No vqmmc supply\n", mmc->dev->name);
190706ec045fSJean-Jacques Hiblot 
190806ec045fSJean-Jacques Hiblot 	if (mmc->vmmc_supply) {
190906ec045fSJean-Jacques Hiblot 		ret = regulator_set_enable(mmc->vmmc_supply, true);
19102051aefeSPeng Fan 		if (ret) {
19112051aefeSPeng Fan 			puts("Error enabling VMMC supply\n");
19122051aefeSPeng Fan 			return ret;
19132051aefeSPeng Fan 		}
191406ec045fSJean-Jacques Hiblot 	}
19152051aefeSPeng Fan #endif
191605cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */
191705cbeb7cSSimon Glass 	/*
191805cbeb7cSSimon Glass 	 * Driver model should use a regulator, as above, rather than calling
191905cbeb7cSSimon Glass 	 * out to board code.
192005cbeb7cSSimon Glass 	 */
192105cbeb7cSSimon Glass 	board_mmc_power_init();
192205cbeb7cSSimon Glass #endif
19232051aefeSPeng Fan 	return 0;
19242051aefeSPeng Fan }
19252051aefeSPeng Fan 
1926e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc)
1927272cc70bSAndy Fleming {
19288ca51e51SSimon Glass 	bool no_card;
1929afd5932bSMacpaul Lin 	int err;
1930272cc70bSAndy Fleming 
1931ab769f22SPantelis Antoniou 	/* we pretend there's no card when init is NULL */
19328ca51e51SSimon Glass 	no_card = mmc_getcd(mmc) == 0;
1933e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
19348ca51e51SSimon Glass 	no_card = no_card || (mmc->cfg->ops->init == NULL);
19358ca51e51SSimon Glass #endif
19368ca51e51SSimon Glass 	if (no_card) {
193748972d90SThierry Reding 		mmc->has_init = 0;
193856196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
193948972d90SThierry Reding 		printf("MMC: no card present\n");
194056196826SPaul Burton #endif
1941915ffa52SJaehoon Chung 		return -ENOMEDIUM;
194248972d90SThierry Reding 	}
194348972d90SThierry Reding 
1944bc897b1dSLei Wen 	if (mmc->has_init)
1945bc897b1dSLei Wen 		return 0;
1946bc897b1dSLei Wen 
19475a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
19485a8dbdc6SYangbo Lu 	mmc_adapter_card_type_ident();
19495a8dbdc6SYangbo Lu #endif
19502051aefeSPeng Fan 	err = mmc_power_init(mmc);
19512051aefeSPeng Fan 	if (err)
19522051aefeSPeng Fan 		return err;
195395de9ab2SPaul Kocialkowski 
1954e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
19558ca51e51SSimon Glass 	/* The device has already been probed ready for use */
19568ca51e51SSimon Glass #else
1957ab769f22SPantelis Antoniou 	/* made sure it's not NULL earlier */
195893bfd616SPantelis Antoniou 	err = mmc->cfg->ops->init(mmc);
1959272cc70bSAndy Fleming 	if (err)
1960272cc70bSAndy Fleming 		return err;
19618ca51e51SSimon Glass #endif
1962786e8f81SAndrew Gabbasov 	mmc->ddr_mode = 0;
1963b86b85e2SIlya Yanok 	mmc_set_bus_width(mmc, 1);
1964b86b85e2SIlya Yanok 	mmc_set_clock(mmc, 1);
1965b86b85e2SIlya Yanok 
1966272cc70bSAndy Fleming 	/* Reset the Card */
1967272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
1968272cc70bSAndy Fleming 
1969272cc70bSAndy Fleming 	if (err)
1970272cc70bSAndy Fleming 		return err;
1971272cc70bSAndy Fleming 
1972bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
1973c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->hwpart = 0;
1974bc897b1dSLei Wen 
1975272cc70bSAndy Fleming 	/* Test for SD version 2 */
1976272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
1977272cc70bSAndy Fleming 
1978272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
1979272cc70bSAndy Fleming 	err = sd_send_op_cond(mmc);
1980272cc70bSAndy Fleming 
1981272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
1982915ffa52SJaehoon Chung 	if (err == -ETIMEDOUT) {
1983272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
1984272cc70bSAndy Fleming 
1985bd47c135SAndrew Gabbasov 		if (err) {
198656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
1987272cc70bSAndy Fleming 			printf("Card did not respond to voltage select!\n");
198856196826SPaul Burton #endif
1989915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
1990272cc70bSAndy Fleming 		}
1991272cc70bSAndy Fleming 	}
1992272cc70bSAndy Fleming 
1993bd47c135SAndrew Gabbasov 	if (!err)
1994e9550449SChe-Liang Chiou 		mmc->init_in_progress = 1;
1995e9550449SChe-Liang Chiou 
1996e9550449SChe-Liang Chiou 	return err;
1997e9550449SChe-Liang Chiou }
1998e9550449SChe-Liang Chiou 
1999e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc)
2000e9550449SChe-Liang Chiou {
2001e9550449SChe-Liang Chiou 	int err = 0;
2002e9550449SChe-Liang Chiou 
2003bd47c135SAndrew Gabbasov 	mmc->init_in_progress = 0;
2004e9550449SChe-Liang Chiou 	if (mmc->op_cond_pending)
2005e9550449SChe-Liang Chiou 		err = mmc_complete_op_cond(mmc);
2006e9550449SChe-Liang Chiou 
2007e9550449SChe-Liang Chiou 	if (!err)
2008bc897b1dSLei Wen 		err = mmc_startup(mmc);
2009bc897b1dSLei Wen 	if (err)
2010bc897b1dSLei Wen 		mmc->has_init = 0;
2011bc897b1dSLei Wen 	else
2012bc897b1dSLei Wen 		mmc->has_init = 1;
2013e9550449SChe-Liang Chiou 	return err;
2014e9550449SChe-Liang Chiou }
2015e9550449SChe-Liang Chiou 
2016e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc)
2017e9550449SChe-Liang Chiou {
2018bd47c135SAndrew Gabbasov 	int err = 0;
2019ce9eca94SMarek Vasut 	__maybe_unused unsigned start;
2020c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
202133fb211dSSimon Glass 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev);
2022e9550449SChe-Liang Chiou 
202333fb211dSSimon Glass 	upriv->mmc = mmc;
202433fb211dSSimon Glass #endif
2025e9550449SChe-Liang Chiou 	if (mmc->has_init)
2026e9550449SChe-Liang Chiou 		return 0;
2027d803fea5SMateusz Zalega 
2028d803fea5SMateusz Zalega 	start = get_timer(0);
2029d803fea5SMateusz Zalega 
2030e9550449SChe-Liang Chiou 	if (!mmc->init_in_progress)
2031e9550449SChe-Liang Chiou 		err = mmc_start_init(mmc);
2032e9550449SChe-Liang Chiou 
2033bd47c135SAndrew Gabbasov 	if (!err)
2034e9550449SChe-Liang Chiou 		err = mmc_complete_init(mmc);
2035919b4858SJagan Teki 	if (err)
2036919b4858SJagan Teki 		printf("%s: %d, time %lu\n", __func__, err, get_timer(start));
2037919b4858SJagan Teki 
2038bc897b1dSLei Wen 	return err;
2039272cc70bSAndy Fleming }
2040272cc70bSAndy Fleming 
2041ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val)
2042ab71188cSMarkus Niebel {
2043ab71188cSMarkus Niebel 	mmc->dsr = val;
2044ab71188cSMarkus Niebel 	return 0;
2045ab71188cSMarkus Niebel }
2046ab71188cSMarkus Niebel 
2047cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */
2048cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis)
2049272cc70bSAndy Fleming {
2050272cc70bSAndy Fleming 	return -1;
2051272cc70bSAndy Fleming }
2052272cc70bSAndy Fleming 
2053cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */
2054cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis)
2055cee9ab7cSJeroen Hofstee {
2056cee9ab7cSJeroen Hofstee 	return -1;
2057cee9ab7cSJeroen Hofstee }
2058272cc70bSAndy Fleming 
2059e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit)
2060e9550449SChe-Liang Chiou {
2061e9550449SChe-Liang Chiou 	mmc->preinit = preinit;
2062e9550449SChe-Liang Chiou }
2063e9550449SChe-Liang Chiou 
2064c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD)
20658e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
20668e3332e2SSjoerd Simons {
20678e3332e2SSjoerd Simons 	return 0;
20688e3332e2SSjoerd Simons }
2069c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC)
20708e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
20718e3332e2SSjoerd Simons {
20724a1db6d8SSimon Glass 	int ret, i;
20738e3332e2SSjoerd Simons 	struct uclass *uc;
20744a1db6d8SSimon Glass 	struct udevice *dev;
20758e3332e2SSjoerd Simons 
20768e3332e2SSjoerd Simons 	ret = uclass_get(UCLASS_MMC, &uc);
20778e3332e2SSjoerd Simons 	if (ret)
20788e3332e2SSjoerd Simons 		return ret;
20798e3332e2SSjoerd Simons 
20804a1db6d8SSimon Glass 	/*
20814a1db6d8SSimon Glass 	 * Try to add them in sequence order. Really with driver model we
20824a1db6d8SSimon Glass 	 * should allow holes, but the current MMC list does not allow that.
20834a1db6d8SSimon Glass 	 * So if we request 0, 1, 3 we will get 0, 1, 2.
20844a1db6d8SSimon Glass 	 */
20854a1db6d8SSimon Glass 	for (i = 0; ; i++) {
20864a1db6d8SSimon Glass 		ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev);
20874a1db6d8SSimon Glass 		if (ret == -ENODEV)
20884a1db6d8SSimon Glass 			break;
20894a1db6d8SSimon Glass 	}
20904a1db6d8SSimon Glass 	uclass_foreach_dev(dev, uc) {
20914a1db6d8SSimon Glass 		ret = device_probe(dev);
20928e3332e2SSjoerd Simons 		if (ret)
20934a1db6d8SSimon Glass 			printf("%s - probe failed: %d\n", dev->name, ret);
20948e3332e2SSjoerd Simons 	}
20958e3332e2SSjoerd Simons 
20968e3332e2SSjoerd Simons 	return 0;
20978e3332e2SSjoerd Simons }
20988e3332e2SSjoerd Simons #else
20998e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
21008e3332e2SSjoerd Simons {
21018e3332e2SSjoerd Simons 	if (board_mmc_init(bis) < 0)
21028e3332e2SSjoerd Simons 		cpu_mmc_init(bis);
21038e3332e2SSjoerd Simons 
21048e3332e2SSjoerd Simons 	return 0;
21058e3332e2SSjoerd Simons }
21068e3332e2SSjoerd Simons #endif
2107e9550449SChe-Liang Chiou 
2108272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
2109272cc70bSAndy Fleming {
21101b26bab1SDaniel Kochmański 	static int initialized = 0;
21118e3332e2SSjoerd Simons 	int ret;
21121b26bab1SDaniel Kochmański 	if (initialized)	/* Avoid initializing mmc multiple times */
21131b26bab1SDaniel Kochmański 		return 0;
21141b26bab1SDaniel Kochmański 	initialized = 1;
21151b26bab1SDaniel Kochmański 
2116c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK)
2117b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY)
2118c40fdca6SSimon Glass 	mmc_list_init();
2119c40fdca6SSimon Glass #endif
2120b5b838f1SMarek Vasut #endif
21218e3332e2SSjoerd Simons 	ret = mmc_probe(bis);
21228e3332e2SSjoerd Simons 	if (ret)
21238e3332e2SSjoerd Simons 		return ret;
2124272cc70bSAndy Fleming 
2125bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD
2126272cc70bSAndy Fleming 	print_mmc_devices(',');
2127bb0dc108SYing Zhang #endif
2128272cc70bSAndy Fleming 
2129c40fdca6SSimon Glass 	mmc_do_preinit();
2130272cc70bSAndy Fleming 	return 0;
2131272cc70bSAndy Fleming }
2132cd3d4880STomas Melin 
2133cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE
2134cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc)
2135cd3d4880STomas Melin {
2136cd3d4880STomas Melin 	int err;
2137cd3d4880STomas Melin 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
2138cd3d4880STomas Melin 
2139cd3d4880STomas Melin 	err = mmc_send_ext_csd(mmc, ext_csd);
2140cd3d4880STomas Melin 	if (err) {
2141cd3d4880STomas Melin 		puts("Could not get ext_csd register values\n");
2142cd3d4880STomas Melin 		return err;
2143cd3d4880STomas Melin 	}
2144cd3d4880STomas Melin 
2145cd3d4880STomas Melin 	if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) {
2146cd3d4880STomas Melin 		puts("Background operations not supported on device\n");
2147cd3d4880STomas Melin 		return -EMEDIUMTYPE;
2148cd3d4880STomas Melin 	}
2149cd3d4880STomas Melin 
2150cd3d4880STomas Melin 	if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) {
2151cd3d4880STomas Melin 		puts("Background operations already enabled\n");
2152cd3d4880STomas Melin 		return 0;
2153cd3d4880STomas Melin 	}
2154cd3d4880STomas Melin 
2155cd3d4880STomas Melin 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1);
2156cd3d4880STomas Melin 	if (err) {
2157cd3d4880STomas Melin 		puts("Failed to enable manual background operations\n");
2158cd3d4880STomas Melin 		return err;
2159cd3d4880STomas Melin 	}
2160cd3d4880STomas Melin 
2161cd3d4880STomas Melin 	puts("Enabled manual background operations\n");
2162cd3d4880STomas Melin 
2163cd3d4880STomas Melin 	return 0;
2164cd3d4880STomas Melin }
2165cd3d4880STomas Melin #endif
2166