xref: /openbmc/u-boot/drivers/mmc/mmc.c (revision 35f9e196f9573af4091076c19aaa6d5afeb91338)
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 
152*35f9e196SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(MMC_VERBOSE) || defined(DEBUG)
153*35f9e196SJean-Jacques Hiblot const char *mmc_mode_name(enum bus_mode mode)
154*35f9e196SJean-Jacques Hiblot {
155*35f9e196SJean-Jacques Hiblot 	static const char *const names[] = {
156*35f9e196SJean-Jacques Hiblot 	      [MMC_LEGACY]	= "MMC legacy",
157*35f9e196SJean-Jacques Hiblot 	      [SD_LEGACY]	= "SD Legacy",
158*35f9e196SJean-Jacques Hiblot 	      [MMC_HS]		= "MMC High Speed (26MHz)",
159*35f9e196SJean-Jacques Hiblot 	      [SD_HS]		= "SD High Speed (50MHz)",
160*35f9e196SJean-Jacques Hiblot 	      [UHS_SDR12]	= "UHS SDR12 (25MHz)",
161*35f9e196SJean-Jacques Hiblot 	      [UHS_SDR25]	= "UHS SDR25 (50MHz)",
162*35f9e196SJean-Jacques Hiblot 	      [UHS_SDR50]	= "UHS SDR50 (100MHz)",
163*35f9e196SJean-Jacques Hiblot 	      [UHS_SDR104]	= "UHS SDR104 (208MHz)",
164*35f9e196SJean-Jacques Hiblot 	      [UHS_DDR50]	= "UHS DDR50 (50MHz)",
165*35f9e196SJean-Jacques Hiblot 	      [MMC_HS_52]	= "MMC High Speed (52MHz)",
166*35f9e196SJean-Jacques Hiblot 	      [MMC_DDR_52]	= "MMC DDR52 (52MHz)",
167*35f9e196SJean-Jacques Hiblot 	      [MMC_HS_200]	= "HS200 (200MHz)",
168*35f9e196SJean-Jacques Hiblot 	};
169*35f9e196SJean-Jacques Hiblot 
170*35f9e196SJean-Jacques Hiblot 	if (mode >= MMC_MODES_END)
171*35f9e196SJean-Jacques Hiblot 		return "Unknown mode";
172*35f9e196SJean-Jacques Hiblot 	else
173*35f9e196SJean-Jacques Hiblot 		return names[mode];
174*35f9e196SJean-Jacques Hiblot }
175*35f9e196SJean-Jacques Hiblot #endif
176*35f9e196SJean-Jacques Hiblot 
177*35f9e196SJean-Jacques Hiblot static int mmc_select_mode(struct mmc *mmc, enum bus_mode mode)
178*35f9e196SJean-Jacques Hiblot {
179*35f9e196SJean-Jacques Hiblot 	mmc->selected_mode = mode;
180*35f9e196SJean-Jacques Hiblot 	debug("selecting mode %s (freq : %d MHz)\n", mmc_mode_name(mode),
181*35f9e196SJean-Jacques Hiblot 	      mmc->tran_speed / 1000000);
182*35f9e196SJean-Jacques Hiblot 	return 0;
183*35f9e196SJean-Jacques Hiblot }
184*35f9e196SJean-Jacques Hiblot 
185e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
186c0c76ebaSSimon Glass int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
187c0c76ebaSSimon Glass {
188c0c76ebaSSimon Glass 	int ret;
189c0c76ebaSSimon Glass 
190c0c76ebaSSimon Glass 	mmmc_trace_before_send(mmc, cmd);
191c0c76ebaSSimon Glass 	ret = mmc->cfg->ops->send_cmd(mmc, cmd, data);
192c0c76ebaSSimon Glass 	mmmc_trace_after_send(mmc, cmd, ret);
193c0c76ebaSSimon Glass 
1948635ff9eSMarek Vasut 	return ret;
195272cc70bSAndy Fleming }
1968ca51e51SSimon Glass #endif
197272cc70bSAndy Fleming 
198da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout)
1995d4fc8d9SRaffaele Recalcati {
2005d4fc8d9SRaffaele Recalcati 	struct mmc_cmd cmd;
201d617c426SJan Kloetzke 	int err, retries = 5;
2025d4fc8d9SRaffaele Recalcati 
2035d4fc8d9SRaffaele Recalcati 	cmd.cmdidx = MMC_CMD_SEND_STATUS;
2045d4fc8d9SRaffaele Recalcati 	cmd.resp_type = MMC_RSP_R1;
205aaf3d41aSMarek Vasut 	if (!mmc_host_is_spi(mmc))
206aaf3d41aSMarek Vasut 		cmd.cmdarg = mmc->rca << 16;
2075d4fc8d9SRaffaele Recalcati 
2081677eef4SAndrew Gabbasov 	while (1) {
2095d4fc8d9SRaffaele Recalcati 		err = mmc_send_cmd(mmc, &cmd, NULL);
210d617c426SJan Kloetzke 		if (!err) {
211d617c426SJan Kloetzke 			if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) &&
212d617c426SJan Kloetzke 			    (cmd.response[0] & MMC_STATUS_CURR_STATE) !=
213d617c426SJan Kloetzke 			     MMC_STATE_PRG)
2145d4fc8d9SRaffaele Recalcati 				break;
215d617c426SJan Kloetzke 			else if (cmd.response[0] & MMC_STATUS_MASK) {
21656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
217d617c426SJan Kloetzke 				printf("Status Error: 0x%08X\n",
218d617c426SJan Kloetzke 					cmd.response[0]);
21956196826SPaul Burton #endif
220915ffa52SJaehoon Chung 				return -ECOMM;
221d617c426SJan Kloetzke 			}
222d617c426SJan Kloetzke 		} else if (--retries < 0)
223d617c426SJan Kloetzke 			return err;
2245d4fc8d9SRaffaele Recalcati 
2251677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
2261677eef4SAndrew Gabbasov 			break;
2275d4fc8d9SRaffaele Recalcati 
2281677eef4SAndrew Gabbasov 		udelay(1000);
2291677eef4SAndrew Gabbasov 	}
2305d4fc8d9SRaffaele Recalcati 
231c0c76ebaSSimon Glass 	mmc_trace_state(mmc, &cmd);
2325b0c942fSJongman Heo 	if (timeout <= 0) {
23356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2345d4fc8d9SRaffaele Recalcati 		printf("Timeout waiting card ready\n");
23556196826SPaul Burton #endif
236915ffa52SJaehoon Chung 		return -ETIMEDOUT;
2375d4fc8d9SRaffaele Recalcati 	}
2385d4fc8d9SRaffaele Recalcati 
2395d4fc8d9SRaffaele Recalcati 	return 0;
2405d4fc8d9SRaffaele Recalcati }
2415d4fc8d9SRaffaele Recalcati 
242da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len)
243272cc70bSAndy Fleming {
244272cc70bSAndy Fleming 	struct mmc_cmd cmd;
245272cc70bSAndy Fleming 
246786e8f81SAndrew Gabbasov 	if (mmc->ddr_mode)
247d22e3d46SJaehoon Chung 		return 0;
248d22e3d46SJaehoon Chung 
249272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
250272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
251272cc70bSAndy Fleming 	cmd.cmdarg = len;
252272cc70bSAndy Fleming 
253272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, NULL);
254272cc70bSAndy Fleming }
255272cc70bSAndy Fleming 
256ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
257fdbb873eSKim Phillips 			   lbaint_t blkcnt)
258272cc70bSAndy Fleming {
259272cc70bSAndy Fleming 	struct mmc_cmd cmd;
260272cc70bSAndy Fleming 	struct mmc_data data;
261272cc70bSAndy Fleming 
2624a1a06bcSAlagu Sankar 	if (blkcnt > 1)
2634a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
2644a1a06bcSAlagu Sankar 	else
265272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
266272cc70bSAndy Fleming 
267272cc70bSAndy Fleming 	if (mmc->high_capacity)
2684a1a06bcSAlagu Sankar 		cmd.cmdarg = start;
269272cc70bSAndy Fleming 	else
2704a1a06bcSAlagu Sankar 		cmd.cmdarg = start * mmc->read_bl_len;
271272cc70bSAndy Fleming 
272272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
273272cc70bSAndy Fleming 
274272cc70bSAndy Fleming 	data.dest = dst;
2754a1a06bcSAlagu Sankar 	data.blocks = blkcnt;
276272cc70bSAndy Fleming 	data.blocksize = mmc->read_bl_len;
277272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
278272cc70bSAndy Fleming 
2794a1a06bcSAlagu Sankar 	if (mmc_send_cmd(mmc, &cmd, &data))
2804a1a06bcSAlagu Sankar 		return 0;
2814a1a06bcSAlagu Sankar 
2824a1a06bcSAlagu Sankar 	if (blkcnt > 1) {
2834a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
2844a1a06bcSAlagu Sankar 		cmd.cmdarg = 0;
2854a1a06bcSAlagu Sankar 		cmd.resp_type = MMC_RSP_R1b;
2864a1a06bcSAlagu Sankar 		if (mmc_send_cmd(mmc, &cmd, NULL)) {
28756196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2884a1a06bcSAlagu Sankar 			printf("mmc fail to send stop cmd\n");
28956196826SPaul Burton #endif
2904a1a06bcSAlagu Sankar 			return 0;
2914a1a06bcSAlagu Sankar 		}
292272cc70bSAndy Fleming 	}
293272cc70bSAndy Fleming 
2944a1a06bcSAlagu Sankar 	return blkcnt;
295272cc70bSAndy Fleming }
296272cc70bSAndy Fleming 
297c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
2987dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst)
29933fb211dSSimon Glass #else
3007dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
3017dba0b93SSimon Glass 		void *dst)
30233fb211dSSimon Glass #endif
303272cc70bSAndy Fleming {
304c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
30533fb211dSSimon Glass 	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
30633fb211dSSimon Glass #endif
307bcce53d0SSimon Glass 	int dev_num = block_dev->devnum;
308873cc1d7SStephen Warren 	int err;
3094a1a06bcSAlagu Sankar 	lbaint_t cur, blocks_todo = blkcnt;
310272cc70bSAndy Fleming 
3114a1a06bcSAlagu Sankar 	if (blkcnt == 0)
3124a1a06bcSAlagu Sankar 		return 0;
3134a1a06bcSAlagu Sankar 
3144a1a06bcSAlagu Sankar 	struct mmc *mmc = find_mmc_device(dev_num);
315272cc70bSAndy Fleming 	if (!mmc)
316272cc70bSAndy Fleming 		return 0;
317272cc70bSAndy Fleming 
318b5b838f1SMarek Vasut 	if (CONFIG_IS_ENABLED(MMC_TINY))
319b5b838f1SMarek Vasut 		err = mmc_switch_part(mmc, block_dev->hwpart);
320b5b838f1SMarek Vasut 	else
32169f45cd5SSimon Glass 		err = blk_dselect_hwpart(block_dev, block_dev->hwpart);
322b5b838f1SMarek Vasut 
323873cc1d7SStephen Warren 	if (err < 0)
324873cc1d7SStephen Warren 		return 0;
325873cc1d7SStephen Warren 
326c40fdca6SSimon Glass 	if ((start + blkcnt) > block_dev->lba) {
32756196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
328ff8fef56SSascha Silbe 		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
329c40fdca6SSimon Glass 			start + blkcnt, block_dev->lba);
33056196826SPaul Burton #endif
331d2bf29e3SLei Wen 		return 0;
332d2bf29e3SLei Wen 	}
333272cc70bSAndy Fleming 
33411692991SSimon Glass 	if (mmc_set_blocklen(mmc, mmc->read_bl_len)) {
33511692991SSimon Glass 		debug("%s: Failed to set blocklen\n", __func__);
336272cc70bSAndy Fleming 		return 0;
33711692991SSimon Glass 	}
338272cc70bSAndy Fleming 
3394a1a06bcSAlagu Sankar 	do {
34093bfd616SPantelis Antoniou 		cur = (blocks_todo > mmc->cfg->b_max) ?
34193bfd616SPantelis Antoniou 			mmc->cfg->b_max : blocks_todo;
34211692991SSimon Glass 		if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
34311692991SSimon Glass 			debug("%s: Failed to read blocks\n", __func__);
3444a1a06bcSAlagu Sankar 			return 0;
34511692991SSimon Glass 		}
3464a1a06bcSAlagu Sankar 		blocks_todo -= cur;
3474a1a06bcSAlagu Sankar 		start += cur;
3484a1a06bcSAlagu Sankar 		dst += cur * mmc->read_bl_len;
3494a1a06bcSAlagu Sankar 	} while (blocks_todo > 0);
350272cc70bSAndy Fleming 
351272cc70bSAndy Fleming 	return blkcnt;
352272cc70bSAndy Fleming }
353272cc70bSAndy Fleming 
354fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc)
355272cc70bSAndy Fleming {
356272cc70bSAndy Fleming 	struct mmc_cmd cmd;
357272cc70bSAndy Fleming 	int err;
358272cc70bSAndy Fleming 
359272cc70bSAndy Fleming 	udelay(1000);
360272cc70bSAndy Fleming 
361272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
362272cc70bSAndy Fleming 	cmd.cmdarg = 0;
363272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_NONE;
364272cc70bSAndy Fleming 
365272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
366272cc70bSAndy Fleming 
367272cc70bSAndy Fleming 	if (err)
368272cc70bSAndy Fleming 		return err;
369272cc70bSAndy Fleming 
370272cc70bSAndy Fleming 	udelay(2000);
371272cc70bSAndy Fleming 
372272cc70bSAndy Fleming 	return 0;
373272cc70bSAndy Fleming }
374272cc70bSAndy Fleming 
375fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc)
376272cc70bSAndy Fleming {
377272cc70bSAndy Fleming 	int timeout = 1000;
378272cc70bSAndy Fleming 	int err;
379272cc70bSAndy Fleming 	struct mmc_cmd cmd;
380272cc70bSAndy Fleming 
3811677eef4SAndrew Gabbasov 	while (1) {
382272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_APP_CMD;
383272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1;
384272cc70bSAndy Fleming 		cmd.cmdarg = 0;
385272cc70bSAndy Fleming 
386272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
387272cc70bSAndy Fleming 
388272cc70bSAndy Fleming 		if (err)
389272cc70bSAndy Fleming 			return err;
390272cc70bSAndy Fleming 
391272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
392272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
393250de12bSStefano Babic 
394250de12bSStefano Babic 		/*
395250de12bSStefano Babic 		 * Most cards do not answer if some reserved bits
396250de12bSStefano Babic 		 * in the ocr are set. However, Some controller
397250de12bSStefano Babic 		 * can set bit 7 (reserved for low voltages), but
398250de12bSStefano Babic 		 * how to manage low voltages SD card is not yet
399250de12bSStefano Babic 		 * specified.
400250de12bSStefano Babic 		 */
401d52ebf10SThomas Chou 		cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
40293bfd616SPantelis Antoniou 			(mmc->cfg->voltages & 0xff8000);
403272cc70bSAndy Fleming 
404272cc70bSAndy Fleming 		if (mmc->version == SD_VERSION_2)
405272cc70bSAndy Fleming 			cmd.cmdarg |= OCR_HCS;
406272cc70bSAndy Fleming 
407272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
408272cc70bSAndy Fleming 
409272cc70bSAndy Fleming 		if (err)
410272cc70bSAndy Fleming 			return err;
411272cc70bSAndy Fleming 
4121677eef4SAndrew Gabbasov 		if (cmd.response[0] & OCR_BUSY)
4131677eef4SAndrew Gabbasov 			break;
414272cc70bSAndy Fleming 
4151677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
416915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
417272cc70bSAndy Fleming 
4181677eef4SAndrew Gabbasov 		udelay(1000);
4191677eef4SAndrew Gabbasov 	}
4201677eef4SAndrew Gabbasov 
421272cc70bSAndy Fleming 	if (mmc->version != SD_VERSION_2)
422272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
423272cc70bSAndy Fleming 
424d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
425d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
426d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
427d52ebf10SThomas Chou 		cmd.cmdarg = 0;
428d52ebf10SThomas Chou 
429d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
430d52ebf10SThomas Chou 
431d52ebf10SThomas Chou 		if (err)
432d52ebf10SThomas Chou 			return err;
433d52ebf10SThomas Chou 	}
434d52ebf10SThomas Chou 
435998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
436272cc70bSAndy Fleming 
437272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
438272cc70bSAndy Fleming 	mmc->rca = 0;
439272cc70bSAndy Fleming 
440272cc70bSAndy Fleming 	return 0;
441272cc70bSAndy Fleming }
442272cc70bSAndy Fleming 
4435289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg)
444272cc70bSAndy Fleming {
4455289b535SAndrew Gabbasov 	struct mmc_cmd cmd;
446272cc70bSAndy Fleming 	int err;
447272cc70bSAndy Fleming 
4485289b535SAndrew Gabbasov 	cmd.cmdidx = MMC_CMD_SEND_OP_COND;
4495289b535SAndrew Gabbasov 	cmd.resp_type = MMC_RSP_R3;
4505289b535SAndrew Gabbasov 	cmd.cmdarg = 0;
4515a20397bSRob Herring 	if (use_arg && !mmc_host_is_spi(mmc))
4525a20397bSRob Herring 		cmd.cmdarg = OCR_HCS |
45393bfd616SPantelis Antoniou 			(mmc->cfg->voltages &
454a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_VOLTAGE_MASK)) |
455a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_ACCESS_MODE);
456e9550449SChe-Liang Chiou 
4575289b535SAndrew Gabbasov 	err = mmc_send_cmd(mmc, &cmd, NULL);
458e9550449SChe-Liang Chiou 	if (err)
459e9550449SChe-Liang Chiou 		return err;
4605289b535SAndrew Gabbasov 	mmc->ocr = cmd.response[0];
461e9550449SChe-Liang Chiou 	return 0;
462e9550449SChe-Liang Chiou }
463e9550449SChe-Liang Chiou 
464750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc)
465e9550449SChe-Liang Chiou {
466e9550449SChe-Liang Chiou 	int err, i;
467e9550449SChe-Liang Chiou 
468272cc70bSAndy Fleming 	/* Some cards seem to need this */
469272cc70bSAndy Fleming 	mmc_go_idle(mmc);
470272cc70bSAndy Fleming 
47131cacbabSRaffaele Recalcati  	/* Asking to the card its capabilities */
472e9550449SChe-Liang Chiou 	for (i = 0; i < 2; i++) {
4735289b535SAndrew Gabbasov 		err = mmc_send_op_cond_iter(mmc, i != 0);
47431cacbabSRaffaele Recalcati 		if (err)
47531cacbabSRaffaele Recalcati 			return err;
47631cacbabSRaffaele Recalcati 
477e9550449SChe-Liang Chiou 		/* exit if not busy (flag seems to be inverted) */
478a626c8d4SAndrew Gabbasov 		if (mmc->ocr & OCR_BUSY)
479bd47c135SAndrew Gabbasov 			break;
480e9550449SChe-Liang Chiou 	}
481bd47c135SAndrew Gabbasov 	mmc->op_cond_pending = 1;
482bd47c135SAndrew Gabbasov 	return 0;
483e9550449SChe-Liang Chiou }
48431cacbabSRaffaele Recalcati 
485750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc)
486e9550449SChe-Liang Chiou {
487e9550449SChe-Liang Chiou 	struct mmc_cmd cmd;
488e9550449SChe-Liang Chiou 	int timeout = 1000;
489e9550449SChe-Liang Chiou 	uint start;
490e9550449SChe-Liang Chiou 	int err;
491e9550449SChe-Liang Chiou 
492e9550449SChe-Liang Chiou 	mmc->op_cond_pending = 0;
493cc17c01fSAndrew Gabbasov 	if (!(mmc->ocr & OCR_BUSY)) {
494d188b113SYangbo Lu 		/* Some cards seem to need this */
495d188b113SYangbo Lu 		mmc_go_idle(mmc);
496d188b113SYangbo Lu 
497e9550449SChe-Liang Chiou 		start = get_timer(0);
4981677eef4SAndrew Gabbasov 		while (1) {
4995289b535SAndrew Gabbasov 			err = mmc_send_op_cond_iter(mmc, 1);
500272cc70bSAndy Fleming 			if (err)
501272cc70bSAndy Fleming 				return err;
5021677eef4SAndrew Gabbasov 			if (mmc->ocr & OCR_BUSY)
5031677eef4SAndrew Gabbasov 				break;
504e9550449SChe-Liang Chiou 			if (get_timer(start) > timeout)
505915ffa52SJaehoon Chung 				return -EOPNOTSUPP;
506e9550449SChe-Liang Chiou 			udelay(100);
5071677eef4SAndrew Gabbasov 		}
508cc17c01fSAndrew Gabbasov 	}
509272cc70bSAndy Fleming 
510d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
511d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
512d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
513d52ebf10SThomas Chou 		cmd.cmdarg = 0;
514d52ebf10SThomas Chou 
515d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
516d52ebf10SThomas Chou 
517d52ebf10SThomas Chou 		if (err)
518d52ebf10SThomas Chou 			return err;
519a626c8d4SAndrew Gabbasov 
520a626c8d4SAndrew Gabbasov 		mmc->ocr = cmd.response[0];
521d52ebf10SThomas Chou 	}
522d52ebf10SThomas Chou 
523272cc70bSAndy Fleming 	mmc->version = MMC_VERSION_UNKNOWN;
524272cc70bSAndy Fleming 
525272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
526def816a2SStephen Warren 	mmc->rca = 1;
527272cc70bSAndy Fleming 
528272cc70bSAndy Fleming 	return 0;
529272cc70bSAndy Fleming }
530272cc70bSAndy Fleming 
531272cc70bSAndy Fleming 
532fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
533272cc70bSAndy Fleming {
534272cc70bSAndy Fleming 	struct mmc_cmd cmd;
535272cc70bSAndy Fleming 	struct mmc_data data;
536272cc70bSAndy Fleming 	int err;
537272cc70bSAndy Fleming 
538272cc70bSAndy Fleming 	/* Get the Card Status Register */
539272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
540272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
541272cc70bSAndy Fleming 	cmd.cmdarg = 0;
542272cc70bSAndy Fleming 
543cdfd1ac6SYoshihiro Shimoda 	data.dest = (char *)ext_csd;
544272cc70bSAndy Fleming 	data.blocks = 1;
5458bfa195eSSimon Glass 	data.blocksize = MMC_MAX_BLOCK_LEN;
546272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
547272cc70bSAndy Fleming 
548272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
549272cc70bSAndy Fleming 
550272cc70bSAndy Fleming 	return err;
551272cc70bSAndy Fleming }
552272cc70bSAndy Fleming 
553c40704f4SSimon Glass int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
554272cc70bSAndy Fleming {
555272cc70bSAndy Fleming 	struct mmc_cmd cmd;
5565d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
557a9003dc6SMaxime Ripard 	int retries = 3;
5585d4fc8d9SRaffaele Recalcati 	int ret;
559272cc70bSAndy Fleming 
560272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SWITCH;
561272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1b;
562272cc70bSAndy Fleming 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
563272cc70bSAndy Fleming 				 (index << 16) |
564272cc70bSAndy Fleming 				 (value << 8);
565272cc70bSAndy Fleming 
566a9003dc6SMaxime Ripard 	while (retries > 0) {
5675d4fc8d9SRaffaele Recalcati 		ret = mmc_send_cmd(mmc, &cmd, NULL);
5685d4fc8d9SRaffaele Recalcati 
5695d4fc8d9SRaffaele Recalcati 		/* Waiting for the ready status */
570a9003dc6SMaxime Ripard 		if (!ret) {
57193ad0d18SJan Kloetzke 			ret = mmc_send_status(mmc, timeout);
572a9003dc6SMaxime Ripard 			return ret;
573a9003dc6SMaxime Ripard 		}
574a9003dc6SMaxime Ripard 
575a9003dc6SMaxime Ripard 		retries--;
576a9003dc6SMaxime Ripard 	}
5775d4fc8d9SRaffaele Recalcati 
5785d4fc8d9SRaffaele Recalcati 	return ret;
5795d4fc8d9SRaffaele Recalcati 
580272cc70bSAndy Fleming }
581272cc70bSAndy Fleming 
582fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc)
583272cc70bSAndy Fleming {
5848bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
585272cc70bSAndy Fleming 	char cardtype;
586272cc70bSAndy Fleming 	int err;
587272cc70bSAndy Fleming 
588fc5b32fbSAndrew Gabbasov 	mmc->card_caps = 0;
589272cc70bSAndy Fleming 
590d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
591d52ebf10SThomas Chou 		return 0;
592d52ebf10SThomas Chou 
593272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
594272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
595272cc70bSAndy Fleming 		return 0;
596272cc70bSAndy Fleming 
597fc5b32fbSAndrew Gabbasov 	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
598fc5b32fbSAndrew Gabbasov 
599272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
600272cc70bSAndy Fleming 
601272cc70bSAndy Fleming 	if (err)
602272cc70bSAndy Fleming 		return err;
603272cc70bSAndy Fleming 
6040560db18SLei Wen 	cardtype = ext_csd[EXT_CSD_CARD_TYPE] & 0xf;
605272cc70bSAndy Fleming 
606272cc70bSAndy Fleming 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING, 1);
607272cc70bSAndy Fleming 
608272cc70bSAndy Fleming 	if (err)
609a5e27b41SHeiko Schocher 		return err;
610272cc70bSAndy Fleming 
611272cc70bSAndy Fleming 	/* Now check to see that it worked */
612272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
613272cc70bSAndy Fleming 
614272cc70bSAndy Fleming 	if (err)
615272cc70bSAndy Fleming 		return err;
616272cc70bSAndy Fleming 
617272cc70bSAndy Fleming 	/* No high-speed support */
6180560db18SLei Wen 	if (!ext_csd[EXT_CSD_HS_TIMING])
619272cc70bSAndy Fleming 		return 0;
620272cc70bSAndy Fleming 
621272cc70bSAndy Fleming 	/* High Speed is set, there are two types: 52MHz and 26MHz */
622d22e3d46SJaehoon Chung 	if (cardtype & EXT_CSD_CARD_TYPE_52) {
623201d5ac4SAndrew Gabbasov 		if (cardtype & EXT_CSD_CARD_TYPE_DDR_1_8V)
624d22e3d46SJaehoon Chung 			mmc->card_caps |= MMC_MODE_DDR_52MHz;
625272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS;
626d22e3d46SJaehoon Chung 	} else {
627272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
628d22e3d46SJaehoon Chung 	}
629272cc70bSAndy Fleming 
630272cc70bSAndy Fleming 	return 0;
631272cc70bSAndy Fleming }
632272cc70bSAndy Fleming 
633f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num)
634f866a46dSStephen Warren {
635f866a46dSStephen Warren 	switch (part_num) {
636f866a46dSStephen Warren 	case 0:
637f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_user;
638f866a46dSStephen Warren 		break;
639f866a46dSStephen Warren 	case 1:
640f866a46dSStephen Warren 	case 2:
641f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_boot;
642f866a46dSStephen Warren 		break;
643f866a46dSStephen Warren 	case 3:
644f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_rpmb;
645f866a46dSStephen Warren 		break;
646f866a46dSStephen Warren 	case 4:
647f866a46dSStephen Warren 	case 5:
648f866a46dSStephen Warren 	case 6:
649f866a46dSStephen Warren 	case 7:
650f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_gp[part_num - 4];
651f866a46dSStephen Warren 		break;
652f866a46dSStephen Warren 	default:
653f866a46dSStephen Warren 		return -1;
654f866a46dSStephen Warren 	}
655f866a46dSStephen Warren 
656c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len);
657f866a46dSStephen Warren 
658f866a46dSStephen Warren 	return 0;
659f866a46dSStephen Warren }
660f866a46dSStephen Warren 
6617dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num)
662bc897b1dSLei Wen {
663f866a46dSStephen Warren 	int ret;
664bc897b1dSLei Wen 
665f866a46dSStephen Warren 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
666bc897b1dSLei Wen 			 (mmc->part_config & ~PART_ACCESS_MASK)
667bc897b1dSLei Wen 			 | (part_num & PART_ACCESS_MASK));
668f866a46dSStephen Warren 
6696dc93e70SPeter Bigot 	/*
6706dc93e70SPeter Bigot 	 * Set the capacity if the switch succeeded or was intended
6716dc93e70SPeter Bigot 	 * to return to representing the raw device.
6726dc93e70SPeter Bigot 	 */
673873cc1d7SStephen Warren 	if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) {
6746dc93e70SPeter Bigot 		ret = mmc_set_capacity(mmc, part_num);
675fdbb139fSSimon Glass 		mmc_get_blk_desc(mmc)->hwpart = part_num;
676873cc1d7SStephen Warren 	}
6776dc93e70SPeter Bigot 
6786dc93e70SPeter Bigot 	return ret;
679bc897b1dSLei Wen }
680bc897b1dSLei Wen 
681ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc,
682ac9da0e0SDiego Santa Cruz 		      const struct mmc_hwpart_conf *conf,
683ac9da0e0SDiego Santa Cruz 		      enum mmc_hwpart_conf_mode mode)
684ac9da0e0SDiego Santa Cruz {
685ac9da0e0SDiego Santa Cruz 	u8 part_attrs = 0;
686ac9da0e0SDiego Santa Cruz 	u32 enh_size_mult;
687ac9da0e0SDiego Santa Cruz 	u32 enh_start_addr;
688ac9da0e0SDiego Santa Cruz 	u32 gp_size_mult[4];
689ac9da0e0SDiego Santa Cruz 	u32 max_enh_size_mult;
690ac9da0e0SDiego Santa Cruz 	u32 tot_enh_size_mult = 0;
6918dda5b0eSDiego Santa Cruz 	u8 wr_rel_set;
692ac9da0e0SDiego Santa Cruz 	int i, pidx, err;
693ac9da0e0SDiego Santa Cruz 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
694ac9da0e0SDiego Santa Cruz 
695ac9da0e0SDiego Santa Cruz 	if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE)
696ac9da0e0SDiego Santa Cruz 		return -EINVAL;
697ac9da0e0SDiego Santa Cruz 
698ac9da0e0SDiego Santa Cruz 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) {
699ac9da0e0SDiego Santa Cruz 		printf("eMMC >= 4.4 required for enhanced user data area\n");
700ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
701ac9da0e0SDiego Santa Cruz 	}
702ac9da0e0SDiego Santa Cruz 
703ac9da0e0SDiego Santa Cruz 	if (!(mmc->part_support & PART_SUPPORT)) {
704ac9da0e0SDiego Santa Cruz 		printf("Card does not support partitioning\n");
705ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
706ac9da0e0SDiego Santa Cruz 	}
707ac9da0e0SDiego Santa Cruz 
708ac9da0e0SDiego Santa Cruz 	if (!mmc->hc_wp_grp_size) {
709ac9da0e0SDiego Santa Cruz 		printf("Card does not define HC WP group size\n");
710ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
711ac9da0e0SDiego Santa Cruz 	}
712ac9da0e0SDiego Santa Cruz 
713ac9da0e0SDiego Santa Cruz 	/* check partition alignment and total enhanced size */
714ac9da0e0SDiego Santa Cruz 	if (conf->user.enh_size) {
715ac9da0e0SDiego Santa Cruz 		if (conf->user.enh_size % mmc->hc_wp_grp_size ||
716ac9da0e0SDiego Santa Cruz 		    conf->user.enh_start % mmc->hc_wp_grp_size) {
717ac9da0e0SDiego Santa Cruz 			printf("User data enhanced area not HC WP group "
718ac9da0e0SDiego Santa Cruz 			       "size aligned\n");
719ac9da0e0SDiego Santa Cruz 			return -EINVAL;
720ac9da0e0SDiego Santa Cruz 		}
721ac9da0e0SDiego Santa Cruz 		part_attrs |= EXT_CSD_ENH_USR;
722ac9da0e0SDiego Santa Cruz 		enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size;
723ac9da0e0SDiego Santa Cruz 		if (mmc->high_capacity) {
724ac9da0e0SDiego Santa Cruz 			enh_start_addr = conf->user.enh_start;
725ac9da0e0SDiego Santa Cruz 		} else {
726ac9da0e0SDiego Santa Cruz 			enh_start_addr = (conf->user.enh_start << 9);
727ac9da0e0SDiego Santa Cruz 		}
728ac9da0e0SDiego Santa Cruz 	} else {
729ac9da0e0SDiego Santa Cruz 		enh_size_mult = 0;
730ac9da0e0SDiego Santa Cruz 		enh_start_addr = 0;
731ac9da0e0SDiego Santa Cruz 	}
732ac9da0e0SDiego Santa Cruz 	tot_enh_size_mult += enh_size_mult;
733ac9da0e0SDiego Santa Cruz 
734ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
735ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) {
736ac9da0e0SDiego Santa Cruz 			printf("GP%i partition not HC WP group size "
737ac9da0e0SDiego Santa Cruz 			       "aligned\n", pidx+1);
738ac9da0e0SDiego Santa Cruz 			return -EINVAL;
739ac9da0e0SDiego Santa Cruz 		}
740ac9da0e0SDiego Santa Cruz 		gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size;
741ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) {
742ac9da0e0SDiego Santa Cruz 			part_attrs |= EXT_CSD_ENH_GP(pidx);
743ac9da0e0SDiego Santa Cruz 			tot_enh_size_mult += gp_size_mult[pidx];
744ac9da0e0SDiego Santa Cruz 		}
745ac9da0e0SDiego Santa Cruz 	}
746ac9da0e0SDiego Santa Cruz 
747ac9da0e0SDiego Santa Cruz 	if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) {
748ac9da0e0SDiego Santa Cruz 		printf("Card does not support enhanced attribute\n");
749ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
750ac9da0e0SDiego Santa Cruz 	}
751ac9da0e0SDiego Santa Cruz 
752ac9da0e0SDiego Santa Cruz 	err = mmc_send_ext_csd(mmc, ext_csd);
753ac9da0e0SDiego Santa Cruz 	if (err)
754ac9da0e0SDiego Santa Cruz 		return err;
755ac9da0e0SDiego Santa Cruz 
756ac9da0e0SDiego Santa Cruz 	max_enh_size_mult =
757ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) +
758ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) +
759ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT];
760ac9da0e0SDiego Santa Cruz 	if (tot_enh_size_mult > max_enh_size_mult) {
761ac9da0e0SDiego Santa Cruz 		printf("Total enhanced size exceeds maximum (%u > %u)\n",
762ac9da0e0SDiego Santa Cruz 		       tot_enh_size_mult, max_enh_size_mult);
763ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
764ac9da0e0SDiego Santa Cruz 	}
765ac9da0e0SDiego Santa Cruz 
7668dda5b0eSDiego Santa Cruz 	/* The default value of EXT_CSD_WR_REL_SET is device
7678dda5b0eSDiego Santa Cruz 	 * dependent, the values can only be changed if the
7688dda5b0eSDiego Santa Cruz 	 * EXT_CSD_HS_CTRL_REL bit is set. The values can be
7698dda5b0eSDiego Santa Cruz 	 * changed only once and before partitioning is completed. */
7708dda5b0eSDiego Santa Cruz 	wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
7718dda5b0eSDiego Santa Cruz 	if (conf->user.wr_rel_change) {
7728dda5b0eSDiego Santa Cruz 		if (conf->user.wr_rel_set)
7738dda5b0eSDiego Santa Cruz 			wr_rel_set |= EXT_CSD_WR_DATA_REL_USR;
7748dda5b0eSDiego Santa Cruz 		else
7758dda5b0eSDiego Santa Cruz 			wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR;
7768dda5b0eSDiego Santa Cruz 	}
7778dda5b0eSDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
7788dda5b0eSDiego Santa Cruz 		if (conf->gp_part[pidx].wr_rel_change) {
7798dda5b0eSDiego Santa Cruz 			if (conf->gp_part[pidx].wr_rel_set)
7808dda5b0eSDiego Santa Cruz 				wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx);
7818dda5b0eSDiego Santa Cruz 			else
7828dda5b0eSDiego Santa Cruz 				wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx);
7838dda5b0eSDiego Santa Cruz 		}
7848dda5b0eSDiego Santa Cruz 	}
7858dda5b0eSDiego Santa Cruz 
7868dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] &&
7878dda5b0eSDiego Santa Cruz 	    !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) {
7888dda5b0eSDiego Santa Cruz 		puts("Card does not support host controlled partition write "
7898dda5b0eSDiego Santa Cruz 		     "reliability settings\n");
7908dda5b0eSDiego Santa Cruz 		return -EMEDIUMTYPE;
7918dda5b0eSDiego Santa Cruz 	}
7928dda5b0eSDiego Santa Cruz 
793ac9da0e0SDiego Santa Cruz 	if (ext_csd[EXT_CSD_PARTITION_SETTING] &
794ac9da0e0SDiego Santa Cruz 	    EXT_CSD_PARTITION_SETTING_COMPLETED) {
795ac9da0e0SDiego Santa Cruz 		printf("Card already partitioned\n");
796ac9da0e0SDiego Santa Cruz 		return -EPERM;
797ac9da0e0SDiego Santa Cruz 	}
798ac9da0e0SDiego Santa Cruz 
799ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_CHECK)
800ac9da0e0SDiego Santa Cruz 		return 0;
801ac9da0e0SDiego Santa Cruz 
802ac9da0e0SDiego Santa Cruz 	/* Partitioning requires high-capacity size definitions */
803ac9da0e0SDiego Santa Cruz 	if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) {
804ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
805ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ERASE_GROUP_DEF, 1);
806ac9da0e0SDiego Santa Cruz 
807ac9da0e0SDiego Santa Cruz 		if (err)
808ac9da0e0SDiego Santa Cruz 			return err;
809ac9da0e0SDiego Santa Cruz 
810ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
811ac9da0e0SDiego Santa Cruz 
812ac9da0e0SDiego Santa Cruz 		/* update erase group size to be high-capacity */
813ac9da0e0SDiego Santa Cruz 		mmc->erase_grp_size =
814ac9da0e0SDiego Santa Cruz 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
815ac9da0e0SDiego Santa Cruz 
816ac9da0e0SDiego Santa Cruz 	}
817ac9da0e0SDiego Santa Cruz 
818ac9da0e0SDiego Santa Cruz 	/* all OK, write the configuration */
819ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 4; i++) {
820ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
821ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_START_ADDR+i,
822ac9da0e0SDiego Santa Cruz 				 (enh_start_addr >> (i*8)) & 0xFF);
823ac9da0e0SDiego Santa Cruz 		if (err)
824ac9da0e0SDiego Santa Cruz 			return err;
825ac9da0e0SDiego Santa Cruz 	}
826ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 3; i++) {
827ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
828ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_SIZE_MULT+i,
829ac9da0e0SDiego Santa Cruz 				 (enh_size_mult >> (i*8)) & 0xFF);
830ac9da0e0SDiego Santa Cruz 		if (err)
831ac9da0e0SDiego Santa Cruz 			return err;
832ac9da0e0SDiego Santa Cruz 	}
833ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
834ac9da0e0SDiego Santa Cruz 		for (i = 0; i < 3; i++) {
835ac9da0e0SDiego Santa Cruz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
836ac9da0e0SDiego Santa Cruz 					 EXT_CSD_GP_SIZE_MULT+pidx*3+i,
837ac9da0e0SDiego Santa Cruz 					 (gp_size_mult[pidx] >> (i*8)) & 0xFF);
838ac9da0e0SDiego Santa Cruz 			if (err)
839ac9da0e0SDiego Santa Cruz 				return err;
840ac9da0e0SDiego Santa Cruz 		}
841ac9da0e0SDiego Santa Cruz 	}
842ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
843ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs);
844ac9da0e0SDiego Santa Cruz 	if (err)
845ac9da0e0SDiego Santa Cruz 		return err;
846ac9da0e0SDiego Santa Cruz 
847ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_SET)
848ac9da0e0SDiego Santa Cruz 		return 0;
849ac9da0e0SDiego Santa Cruz 
8508dda5b0eSDiego Santa Cruz 	/* The WR_REL_SET is a write-once register but shall be
8518dda5b0eSDiego Santa Cruz 	 * written before setting PART_SETTING_COMPLETED. As it is
8528dda5b0eSDiego Santa Cruz 	 * write-once we can only write it when completing the
8538dda5b0eSDiego Santa Cruz 	 * partitioning. */
8548dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) {
8558dda5b0eSDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
8568dda5b0eSDiego Santa Cruz 				 EXT_CSD_WR_REL_SET, wr_rel_set);
8578dda5b0eSDiego Santa Cruz 		if (err)
8588dda5b0eSDiego Santa Cruz 			return err;
8598dda5b0eSDiego Santa Cruz 	}
8608dda5b0eSDiego Santa Cruz 
861ac9da0e0SDiego Santa Cruz 	/* Setting PART_SETTING_COMPLETED confirms the partition
862ac9da0e0SDiego Santa Cruz 	 * configuration but it only becomes effective after power
863ac9da0e0SDiego Santa Cruz 	 * cycle, so we do not adjust the partition related settings
864ac9da0e0SDiego Santa Cruz 	 * in the mmc struct. */
865ac9da0e0SDiego Santa Cruz 
866ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
867ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING,
868ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING_COMPLETED);
869ac9da0e0SDiego Santa Cruz 	if (err)
870ac9da0e0SDiego Santa Cruz 		return err;
871ac9da0e0SDiego Santa Cruz 
872ac9da0e0SDiego Santa Cruz 	return 0;
873ac9da0e0SDiego Santa Cruz }
874ac9da0e0SDiego Santa Cruz 
875e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
87648972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
87748972d90SThierry Reding {
87848972d90SThierry Reding 	int cd;
87948972d90SThierry Reding 
88048972d90SThierry Reding 	cd = board_mmc_getcd(mmc);
88148972d90SThierry Reding 
882d4e1da4eSPeter Korsgaard 	if (cd < 0) {
88393bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getcd)
88493bfd616SPantelis Antoniou 			cd = mmc->cfg->ops->getcd(mmc);
885d4e1da4eSPeter Korsgaard 		else
886d4e1da4eSPeter Korsgaard 			cd = 1;
887d4e1da4eSPeter Korsgaard 	}
88848972d90SThierry Reding 
88948972d90SThierry Reding 	return cd;
89048972d90SThierry Reding }
8918ca51e51SSimon Glass #endif
89248972d90SThierry Reding 
893fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
894272cc70bSAndy Fleming {
895272cc70bSAndy Fleming 	struct mmc_cmd cmd;
896272cc70bSAndy Fleming 	struct mmc_data data;
897272cc70bSAndy Fleming 
898272cc70bSAndy Fleming 	/* Switch the frequency */
899272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
900272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
901272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
902272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
903272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
904272cc70bSAndy Fleming 
905272cc70bSAndy Fleming 	data.dest = (char *)resp;
906272cc70bSAndy Fleming 	data.blocksize = 64;
907272cc70bSAndy Fleming 	data.blocks = 1;
908272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
909272cc70bSAndy Fleming 
910272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
911272cc70bSAndy Fleming }
912272cc70bSAndy Fleming 
913272cc70bSAndy Fleming 
914fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc)
915272cc70bSAndy Fleming {
916272cc70bSAndy Fleming 	int err;
917272cc70bSAndy Fleming 	struct mmc_cmd cmd;
91818e7c8f6SSuniel Mahesh 	ALLOC_CACHE_ALIGN_BUFFER(__be32, scr, 2);
91918e7c8f6SSuniel Mahesh 	ALLOC_CACHE_ALIGN_BUFFER(__be32, switch_status, 16);
920272cc70bSAndy Fleming 	struct mmc_data data;
921272cc70bSAndy Fleming 	int timeout;
922272cc70bSAndy Fleming 
923272cc70bSAndy Fleming 	mmc->card_caps = 0;
924272cc70bSAndy Fleming 
925d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
926d52ebf10SThomas Chou 		return 0;
927d52ebf10SThomas Chou 
928272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
929272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
930272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
931272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
932272cc70bSAndy Fleming 
933272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
934272cc70bSAndy Fleming 
935272cc70bSAndy Fleming 	if (err)
936272cc70bSAndy Fleming 		return err;
937272cc70bSAndy Fleming 
938272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
939272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
940272cc70bSAndy Fleming 	cmd.cmdarg = 0;
941272cc70bSAndy Fleming 
942272cc70bSAndy Fleming 	timeout = 3;
943272cc70bSAndy Fleming 
944272cc70bSAndy Fleming retry_scr:
945f781dd38SAnton staaf 	data.dest = (char *)scr;
946272cc70bSAndy Fleming 	data.blocksize = 8;
947272cc70bSAndy Fleming 	data.blocks = 1;
948272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
949272cc70bSAndy Fleming 
950272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
951272cc70bSAndy Fleming 
952272cc70bSAndy Fleming 	if (err) {
953272cc70bSAndy Fleming 		if (timeout--)
954272cc70bSAndy Fleming 			goto retry_scr;
955272cc70bSAndy Fleming 
956272cc70bSAndy Fleming 		return err;
957272cc70bSAndy Fleming 	}
958272cc70bSAndy Fleming 
9594e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
9604e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
961272cc70bSAndy Fleming 
962272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
963272cc70bSAndy Fleming 	case 0:
964272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
965272cc70bSAndy Fleming 		break;
966272cc70bSAndy Fleming 	case 1:
967272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_10;
968272cc70bSAndy Fleming 		break;
969272cc70bSAndy Fleming 	case 2:
970272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
9711741c64dSJaehoon Chung 		if ((mmc->scr[0] >> 15) & 0x1)
9721741c64dSJaehoon Chung 			mmc->version = SD_VERSION_3;
973272cc70bSAndy Fleming 		break;
974272cc70bSAndy Fleming 	default:
975272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
976272cc70bSAndy Fleming 		break;
977272cc70bSAndy Fleming 	}
978272cc70bSAndy Fleming 
979b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
980b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
981b44c7083SAlagu Sankar 
982272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
983272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
984272cc70bSAndy Fleming 		return 0;
985272cc70bSAndy Fleming 
986272cc70bSAndy Fleming 	timeout = 4;
987272cc70bSAndy Fleming 	while (timeout--) {
988272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
989f781dd38SAnton staaf 				(u8 *)switch_status);
990272cc70bSAndy Fleming 
991272cc70bSAndy Fleming 		if (err)
992272cc70bSAndy Fleming 			return err;
993272cc70bSAndy Fleming 
994272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
9954e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
996272cc70bSAndy Fleming 			break;
997272cc70bSAndy Fleming 	}
998272cc70bSAndy Fleming 
999272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
10004e3d89baSYauhen Kharuzhy 	if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED))
1001272cc70bSAndy Fleming 		return 0;
1002272cc70bSAndy Fleming 
10032c3fbf4cSMacpaul Lin 	/*
10042c3fbf4cSMacpaul Lin 	 * If the host doesn't support SD_HIGHSPEED, do not switch card to
10052c3fbf4cSMacpaul Lin 	 * HIGHSPEED mode even if the card support SD_HIGHSPPED.
10062c3fbf4cSMacpaul Lin 	 * This can avoid furthur problem when the card runs in different
10072c3fbf4cSMacpaul Lin 	 * mode between the host.
10082c3fbf4cSMacpaul Lin 	 */
100993bfd616SPantelis Antoniou 	if (!((mmc->cfg->host_caps & MMC_MODE_HS_52MHz) &&
101093bfd616SPantelis Antoniou 		(mmc->cfg->host_caps & MMC_MODE_HS)))
10112c3fbf4cSMacpaul Lin 		return 0;
10122c3fbf4cSMacpaul Lin 
1013f781dd38SAnton staaf 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status);
1014272cc70bSAndy Fleming 
1015272cc70bSAndy Fleming 	if (err)
1016272cc70bSAndy Fleming 		return err;
1017272cc70bSAndy Fleming 
10184e3d89baSYauhen Kharuzhy 	if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000)
1019272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
1020272cc70bSAndy Fleming 
1021272cc70bSAndy Fleming 	return 0;
1022272cc70bSAndy Fleming }
1023272cc70bSAndy Fleming 
10243697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc)
10253697e599SPeng Fan {
10263697e599SPeng Fan 	int err, i;
10273697e599SPeng Fan 	struct mmc_cmd cmd;
10283697e599SPeng Fan 	ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16);
10293697e599SPeng Fan 	struct mmc_data data;
10303697e599SPeng Fan 	int timeout = 3;
10313697e599SPeng Fan 	unsigned int au, eo, et, es;
10323697e599SPeng Fan 
10333697e599SPeng Fan 	cmd.cmdidx = MMC_CMD_APP_CMD;
10343697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
10353697e599SPeng Fan 	cmd.cmdarg = mmc->rca << 16;
10363697e599SPeng Fan 
10373697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, NULL);
10383697e599SPeng Fan 	if (err)
10393697e599SPeng Fan 		return err;
10403697e599SPeng Fan 
10413697e599SPeng Fan 	cmd.cmdidx = SD_CMD_APP_SD_STATUS;
10423697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
10433697e599SPeng Fan 	cmd.cmdarg = 0;
10443697e599SPeng Fan 
10453697e599SPeng Fan retry_ssr:
10463697e599SPeng Fan 	data.dest = (char *)ssr;
10473697e599SPeng Fan 	data.blocksize = 64;
10483697e599SPeng Fan 	data.blocks = 1;
10493697e599SPeng Fan 	data.flags = MMC_DATA_READ;
10503697e599SPeng Fan 
10513697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, &data);
10523697e599SPeng Fan 	if (err) {
10533697e599SPeng Fan 		if (timeout--)
10543697e599SPeng Fan 			goto retry_ssr;
10553697e599SPeng Fan 
10563697e599SPeng Fan 		return err;
10573697e599SPeng Fan 	}
10583697e599SPeng Fan 
10593697e599SPeng Fan 	for (i = 0; i < 16; i++)
10603697e599SPeng Fan 		ssr[i] = be32_to_cpu(ssr[i]);
10613697e599SPeng Fan 
10623697e599SPeng Fan 	au = (ssr[2] >> 12) & 0xF;
10633697e599SPeng Fan 	if ((au <= 9) || (mmc->version == SD_VERSION_3)) {
10643697e599SPeng Fan 		mmc->ssr.au = sd_au_size[au];
10653697e599SPeng Fan 		es = (ssr[3] >> 24) & 0xFF;
10663697e599SPeng Fan 		es |= (ssr[2] & 0xFF) << 8;
10673697e599SPeng Fan 		et = (ssr[3] >> 18) & 0x3F;
10683697e599SPeng Fan 		if (es && et) {
10693697e599SPeng Fan 			eo = (ssr[3] >> 16) & 0x3;
10703697e599SPeng Fan 			mmc->ssr.erase_timeout = (et * 1000) / es;
10713697e599SPeng Fan 			mmc->ssr.erase_offset = eo * 1000;
10723697e599SPeng Fan 		}
10733697e599SPeng Fan 	} else {
10743697e599SPeng Fan 		debug("Invalid Allocation Unit Size.\n");
10753697e599SPeng Fan 	}
10763697e599SPeng Fan 
10773697e599SPeng Fan 	return 0;
10783697e599SPeng Fan }
10793697e599SPeng Fan 
1080272cc70bSAndy Fleming /* frequency bases */
1081272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
10825f837c2cSMike Frysinger static const int fbase[] = {
1083272cc70bSAndy Fleming 	10000,
1084272cc70bSAndy Fleming 	100000,
1085272cc70bSAndy Fleming 	1000000,
1086272cc70bSAndy Fleming 	10000000,
1087272cc70bSAndy Fleming };
1088272cc70bSAndy Fleming 
1089272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
1090272cc70bSAndy Fleming  * to platforms without floating point.
1091272cc70bSAndy Fleming  */
109261fe076fSSimon Glass static const u8 multipliers[] = {
1093272cc70bSAndy Fleming 	0,	/* reserved */
1094272cc70bSAndy Fleming 	10,
1095272cc70bSAndy Fleming 	12,
1096272cc70bSAndy Fleming 	13,
1097272cc70bSAndy Fleming 	15,
1098272cc70bSAndy Fleming 	20,
1099272cc70bSAndy Fleming 	25,
1100272cc70bSAndy Fleming 	30,
1101272cc70bSAndy Fleming 	35,
1102272cc70bSAndy Fleming 	40,
1103272cc70bSAndy Fleming 	45,
1104272cc70bSAndy Fleming 	50,
1105272cc70bSAndy Fleming 	55,
1106272cc70bSAndy Fleming 	60,
1107272cc70bSAndy Fleming 	70,
1108272cc70bSAndy Fleming 	80,
1109272cc70bSAndy Fleming };
1110272cc70bSAndy Fleming 
1111e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
1112fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc)
1113272cc70bSAndy Fleming {
111493bfd616SPantelis Antoniou 	if (mmc->cfg->ops->set_ios)
111593bfd616SPantelis Antoniou 		mmc->cfg->ops->set_ios(mmc);
1116272cc70bSAndy Fleming }
11178ca51e51SSimon Glass #endif
1118272cc70bSAndy Fleming 
1119272cc70bSAndy Fleming void mmc_set_clock(struct mmc *mmc, uint clock)
1120272cc70bSAndy Fleming {
112193bfd616SPantelis Antoniou 	if (clock > mmc->cfg->f_max)
112293bfd616SPantelis Antoniou 		clock = mmc->cfg->f_max;
1123272cc70bSAndy Fleming 
112493bfd616SPantelis Antoniou 	if (clock < mmc->cfg->f_min)
112593bfd616SPantelis Antoniou 		clock = mmc->cfg->f_min;
1126272cc70bSAndy Fleming 
1127272cc70bSAndy Fleming 	mmc->clock = clock;
1128272cc70bSAndy Fleming 
1129272cc70bSAndy Fleming 	mmc_set_ios(mmc);
1130272cc70bSAndy Fleming }
1131272cc70bSAndy Fleming 
1132fdbb873eSKim Phillips static void mmc_set_bus_width(struct mmc *mmc, uint width)
1133272cc70bSAndy Fleming {
1134272cc70bSAndy Fleming 	mmc->bus_width = width;
1135272cc70bSAndy Fleming 
1136272cc70bSAndy Fleming 	mmc_set_ios(mmc);
1137272cc70bSAndy Fleming }
1138272cc70bSAndy Fleming 
11398ac8a263SJean-Jacques Hiblot static int sd_select_bus_freq_width(struct mmc *mmc)
11408ac8a263SJean-Jacques Hiblot {
11418ac8a263SJean-Jacques Hiblot 	int err;
11428ac8a263SJean-Jacques Hiblot 	struct mmc_cmd cmd;
11438ac8a263SJean-Jacques Hiblot 
11448ac8a263SJean-Jacques Hiblot 	err = sd_change_freq(mmc);
11458ac8a263SJean-Jacques Hiblot 	if (err)
11468ac8a263SJean-Jacques Hiblot 		return err;
11478ac8a263SJean-Jacques Hiblot 
11488ac8a263SJean-Jacques Hiblot 	/* Restrict card's capabilities by what the host can do */
11498ac8a263SJean-Jacques Hiblot 	mmc->card_caps &= mmc->cfg->host_caps;
11508ac8a263SJean-Jacques Hiblot 
11518ac8a263SJean-Jacques Hiblot 	if (mmc->card_caps & MMC_MODE_4BIT) {
11528ac8a263SJean-Jacques Hiblot 		cmd.cmdidx = MMC_CMD_APP_CMD;
11538ac8a263SJean-Jacques Hiblot 		cmd.resp_type = MMC_RSP_R1;
11548ac8a263SJean-Jacques Hiblot 		cmd.cmdarg = mmc->rca << 16;
11558ac8a263SJean-Jacques Hiblot 
11568ac8a263SJean-Jacques Hiblot 		err = mmc_send_cmd(mmc, &cmd, NULL);
11578ac8a263SJean-Jacques Hiblot 		if (err)
11588ac8a263SJean-Jacques Hiblot 			return err;
11598ac8a263SJean-Jacques Hiblot 
11608ac8a263SJean-Jacques Hiblot 		cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
11618ac8a263SJean-Jacques Hiblot 		cmd.resp_type = MMC_RSP_R1;
11628ac8a263SJean-Jacques Hiblot 		cmd.cmdarg = 2;
11638ac8a263SJean-Jacques Hiblot 		err = mmc_send_cmd(mmc, &cmd, NULL);
11648ac8a263SJean-Jacques Hiblot 		if (err)
11658ac8a263SJean-Jacques Hiblot 			return err;
11668ac8a263SJean-Jacques Hiblot 
11678ac8a263SJean-Jacques Hiblot 		mmc_set_bus_width(mmc, 4);
11688ac8a263SJean-Jacques Hiblot 	}
11698ac8a263SJean-Jacques Hiblot 
11708ac8a263SJean-Jacques Hiblot 	err = sd_read_ssr(mmc);
11718ac8a263SJean-Jacques Hiblot 	if (err)
11728ac8a263SJean-Jacques Hiblot 		return err;
11738ac8a263SJean-Jacques Hiblot 
1174*35f9e196SJean-Jacques Hiblot 	if (mmc->card_caps & MMC_MODE_HS) {
1175*35f9e196SJean-Jacques Hiblot 		mmc_select_mode(mmc, SD_HS);
11768ac8a263SJean-Jacques Hiblot 		mmc->tran_speed = 50000000;
1177*35f9e196SJean-Jacques Hiblot 	} else {
1178*35f9e196SJean-Jacques Hiblot 		mmc_select_mode(mmc, SD_LEGACY);
11798ac8a263SJean-Jacques Hiblot 		mmc->tran_speed = 25000000;
1180*35f9e196SJean-Jacques Hiblot 	}
11818ac8a263SJean-Jacques Hiblot 
11828ac8a263SJean-Jacques Hiblot 	return 0;
11838ac8a263SJean-Jacques Hiblot }
11848ac8a263SJean-Jacques Hiblot 
11857382e691SJean-Jacques Hiblot /*
11867382e691SJean-Jacques Hiblot  * read the compare the part of ext csd that is constant.
11877382e691SJean-Jacques Hiblot  * This can be used to check that the transfer is working
11887382e691SJean-Jacques Hiblot  * as expected.
11897382e691SJean-Jacques Hiblot  */
11907382e691SJean-Jacques Hiblot static int mmc_read_and_compare_ext_csd(struct mmc *mmc)
11917382e691SJean-Jacques Hiblot {
11927382e691SJean-Jacques Hiblot 	int err;
11937382e691SJean-Jacques Hiblot 	const u8 *ext_csd = mmc->ext_csd;
11947382e691SJean-Jacques Hiblot 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
11957382e691SJean-Jacques Hiblot 
11967382e691SJean-Jacques Hiblot 	err = mmc_send_ext_csd(mmc, test_csd);
11977382e691SJean-Jacques Hiblot 	if (err)
11987382e691SJean-Jacques Hiblot 		return err;
11997382e691SJean-Jacques Hiblot 
12007382e691SJean-Jacques Hiblot 	/* Only compare read only fields */
12017382e691SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_PARTITIONING_SUPPORT]
12027382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_PARTITIONING_SUPPORT] &&
12037382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_HC_WP_GRP_SIZE]
12047382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_HC_WP_GRP_SIZE] &&
12057382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_REV]
12067382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_REV] &&
12077382e691SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
12087382e691SJean-Jacques Hiblot 		== test_csd[EXT_CSD_HC_ERASE_GRP_SIZE] &&
12097382e691SJean-Jacques Hiblot 	    memcmp(&ext_csd[EXT_CSD_SEC_CNT],
12107382e691SJean-Jacques Hiblot 		   &test_csd[EXT_CSD_SEC_CNT], 4) == 0)
12117382e691SJean-Jacques Hiblot 		return 0;
12127382e691SJean-Jacques Hiblot 
12137382e691SJean-Jacques Hiblot 	return -EBADMSG;
12147382e691SJean-Jacques Hiblot }
12157382e691SJean-Jacques Hiblot 
1216dfda9d88SJean-Jacques Hiblot static int mmc_select_bus_freq_width(struct mmc *mmc)
12178ac8a263SJean-Jacques Hiblot {
12188ac8a263SJean-Jacques Hiblot 	/* An array of possible bus widths in order of preference */
12198ac8a263SJean-Jacques Hiblot 	static const unsigned int ext_csd_bits[] = {
12208ac8a263SJean-Jacques Hiblot 		EXT_CSD_DDR_BUS_WIDTH_8,
12218ac8a263SJean-Jacques Hiblot 		EXT_CSD_DDR_BUS_WIDTH_4,
12228ac8a263SJean-Jacques Hiblot 		EXT_CSD_BUS_WIDTH_8,
12238ac8a263SJean-Jacques Hiblot 		EXT_CSD_BUS_WIDTH_4,
12248ac8a263SJean-Jacques Hiblot 		EXT_CSD_BUS_WIDTH_1,
12258ac8a263SJean-Jacques Hiblot 	};
12268ac8a263SJean-Jacques Hiblot 	/* An array to map CSD bus widths to host cap bits */
12278ac8a263SJean-Jacques Hiblot 	static const unsigned int ext_to_hostcaps[] = {
12288ac8a263SJean-Jacques Hiblot 		[EXT_CSD_DDR_BUS_WIDTH_4] =
12298ac8a263SJean-Jacques Hiblot 			MMC_MODE_DDR_52MHz | MMC_MODE_4BIT,
12308ac8a263SJean-Jacques Hiblot 		[EXT_CSD_DDR_BUS_WIDTH_8] =
12318ac8a263SJean-Jacques Hiblot 			MMC_MODE_DDR_52MHz | MMC_MODE_8BIT,
12328ac8a263SJean-Jacques Hiblot 		[EXT_CSD_BUS_WIDTH_4] = MMC_MODE_4BIT,
12338ac8a263SJean-Jacques Hiblot 		[EXT_CSD_BUS_WIDTH_8] = MMC_MODE_8BIT,
12348ac8a263SJean-Jacques Hiblot 	};
12358ac8a263SJean-Jacques Hiblot 	/* An array to map chosen bus width to an integer */
12368ac8a263SJean-Jacques Hiblot 	static const unsigned int widths[] = {
12378ac8a263SJean-Jacques Hiblot 		8, 4, 8, 4, 1,
12388ac8a263SJean-Jacques Hiblot 	};
12398ac8a263SJean-Jacques Hiblot 	int err;
12408ac8a263SJean-Jacques Hiblot 	int idx;
12418ac8a263SJean-Jacques Hiblot 
12428ac8a263SJean-Jacques Hiblot 	err = mmc_change_freq(mmc);
12438ac8a263SJean-Jacques Hiblot 	if (err)
12448ac8a263SJean-Jacques Hiblot 		return err;
12458ac8a263SJean-Jacques Hiblot 
12468ac8a263SJean-Jacques Hiblot 	/* Restrict card's capabilities by what the host can do */
12478ac8a263SJean-Jacques Hiblot 	mmc->card_caps &= mmc->cfg->host_caps;
12488ac8a263SJean-Jacques Hiblot 
12498ac8a263SJean-Jacques Hiblot 	/* Only version 4 of MMC supports wider bus widths */
12508ac8a263SJean-Jacques Hiblot 	if (mmc->version < MMC_VERSION_4)
12518ac8a263SJean-Jacques Hiblot 		return 0;
12528ac8a263SJean-Jacques Hiblot 
1253dfda9d88SJean-Jacques Hiblot 	if (!mmc->ext_csd) {
1254dfda9d88SJean-Jacques Hiblot 		debug("No ext_csd found!\n"); /* this should enver happen */
1255dfda9d88SJean-Jacques Hiblot 		return -ENOTSUPP;
1256dfda9d88SJean-Jacques Hiblot 	}
1257dfda9d88SJean-Jacques Hiblot 
12588ac8a263SJean-Jacques Hiblot 	for (idx = 0; idx < ARRAY_SIZE(ext_csd_bits); idx++) {
12598ac8a263SJean-Jacques Hiblot 		unsigned int extw = ext_csd_bits[idx];
12608ac8a263SJean-Jacques Hiblot 		unsigned int caps = ext_to_hostcaps[extw];
12618ac8a263SJean-Jacques Hiblot 		/*
12628ac8a263SJean-Jacques Hiblot 		 * If the bus width is still not changed,
12638ac8a263SJean-Jacques Hiblot 		 * don't try to set the default again.
12648ac8a263SJean-Jacques Hiblot 		 * Otherwise, recover from switch attempts
12658ac8a263SJean-Jacques Hiblot 		 * by switching to 1-bit bus width.
12668ac8a263SJean-Jacques Hiblot 		 */
12678ac8a263SJean-Jacques Hiblot 		if (extw == EXT_CSD_BUS_WIDTH_1 &&
12688ac8a263SJean-Jacques Hiblot 		    mmc->bus_width == 1) {
12698ac8a263SJean-Jacques Hiblot 			err = 0;
12708ac8a263SJean-Jacques Hiblot 			break;
12718ac8a263SJean-Jacques Hiblot 		}
12728ac8a263SJean-Jacques Hiblot 
12738ac8a263SJean-Jacques Hiblot 		/*
12748ac8a263SJean-Jacques Hiblot 		 * Check to make sure the card and controller support
12758ac8a263SJean-Jacques Hiblot 		 * these capabilities
12768ac8a263SJean-Jacques Hiblot 		 */
12778ac8a263SJean-Jacques Hiblot 		if ((mmc->card_caps & caps) != caps)
12788ac8a263SJean-Jacques Hiblot 			continue;
12798ac8a263SJean-Jacques Hiblot 
12808ac8a263SJean-Jacques Hiblot 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
12818ac8a263SJean-Jacques Hiblot 				 EXT_CSD_BUS_WIDTH, extw);
12828ac8a263SJean-Jacques Hiblot 
12838ac8a263SJean-Jacques Hiblot 		if (err)
12848ac8a263SJean-Jacques Hiblot 			continue;
12858ac8a263SJean-Jacques Hiblot 
12868ac8a263SJean-Jacques Hiblot 		mmc->ddr_mode = (caps & MMC_MODE_DDR_52MHz) ? 1 : 0;
12878ac8a263SJean-Jacques Hiblot 		mmc_set_bus_width(mmc, widths[idx]);
12888ac8a263SJean-Jacques Hiblot 
12897382e691SJean-Jacques Hiblot 		err = mmc_read_and_compare_ext_csd(mmc);
12907382e691SJean-Jacques Hiblot 		if (!err)
12918ac8a263SJean-Jacques Hiblot 			break;
12928ac8a263SJean-Jacques Hiblot 	}
12938ac8a263SJean-Jacques Hiblot 
12948ac8a263SJean-Jacques Hiblot 	if (err)
12958ac8a263SJean-Jacques Hiblot 		return err;
12968ac8a263SJean-Jacques Hiblot 
1297*35f9e196SJean-Jacques Hiblot 	if (mmc->card_caps & MMC_MODE_HS_52MHz) {
1298*35f9e196SJean-Jacques Hiblot 		if (mmc->ddr_mode)
1299*35f9e196SJean-Jacques Hiblot 			mmc_select_mode(mmc, MMC_DDR_52);
13008ac8a263SJean-Jacques Hiblot 		else
1301*35f9e196SJean-Jacques Hiblot 			mmc_select_mode(mmc, MMC_HS_52);
1302*35f9e196SJean-Jacques Hiblot 		mmc->tran_speed = 52000000;
1303*35f9e196SJean-Jacques Hiblot 	} else if (mmc->card_caps & MMC_MODE_HS) {
1304*35f9e196SJean-Jacques Hiblot 		mmc_select_mode(mmc, MMC_HS);
13058ac8a263SJean-Jacques Hiblot 		mmc->tran_speed = 26000000;
13068ac8a263SJean-Jacques Hiblot 	}
13078ac8a263SJean-Jacques Hiblot 
13088ac8a263SJean-Jacques Hiblot 	return err;
13098ac8a263SJean-Jacques Hiblot }
13108ac8a263SJean-Jacques Hiblot 
1311dfda9d88SJean-Jacques Hiblot static int mmc_startup_v4(struct mmc *mmc)
1312c744b6f6SJean-Jacques Hiblot {
1313c744b6f6SJean-Jacques Hiblot 	int err, i;
1314c744b6f6SJean-Jacques Hiblot 	u64 capacity;
1315c744b6f6SJean-Jacques Hiblot 	bool has_parts = false;
1316c744b6f6SJean-Jacques Hiblot 	bool part_completed;
1317dfda9d88SJean-Jacques Hiblot 	u8 *ext_csd;
1318c744b6f6SJean-Jacques Hiblot 
1319c744b6f6SJean-Jacques Hiblot 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4))
1320c744b6f6SJean-Jacques Hiblot 		return 0;
1321c744b6f6SJean-Jacques Hiblot 
1322dfda9d88SJean-Jacques Hiblot 	ext_csd = malloc_cache_aligned(MMC_MAX_BLOCK_LEN);
1323dfda9d88SJean-Jacques Hiblot 	if (!ext_csd)
1324dfda9d88SJean-Jacques Hiblot 		return -ENOMEM;
1325dfda9d88SJean-Jacques Hiblot 
1326dfda9d88SJean-Jacques Hiblot 	mmc->ext_csd = ext_csd;
1327dfda9d88SJean-Jacques Hiblot 
1328c744b6f6SJean-Jacques Hiblot 	/* check  ext_csd version and capacity */
1329c744b6f6SJean-Jacques Hiblot 	err = mmc_send_ext_csd(mmc, ext_csd);
1330c744b6f6SJean-Jacques Hiblot 	if (err)
1331c744b6f6SJean-Jacques Hiblot 		return err;
1332c744b6f6SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_REV] >= 2) {
1333c744b6f6SJean-Jacques Hiblot 		/*
1334c744b6f6SJean-Jacques Hiblot 		 * According to the JEDEC Standard, the value of
1335c744b6f6SJean-Jacques Hiblot 		 * ext_csd's capacity is valid if the value is more
1336c744b6f6SJean-Jacques Hiblot 		 * than 2GB
1337c744b6f6SJean-Jacques Hiblot 		 */
1338c744b6f6SJean-Jacques Hiblot 		capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
1339c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
1340c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
1341c744b6f6SJean-Jacques Hiblot 				| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
1342c744b6f6SJean-Jacques Hiblot 		capacity *= MMC_MAX_BLOCK_LEN;
1343c744b6f6SJean-Jacques Hiblot 		if ((capacity >> 20) > 2 * 1024)
1344c744b6f6SJean-Jacques Hiblot 			mmc->capacity_user = capacity;
1345c744b6f6SJean-Jacques Hiblot 	}
1346c744b6f6SJean-Jacques Hiblot 
1347c744b6f6SJean-Jacques Hiblot 	switch (ext_csd[EXT_CSD_REV]) {
1348c744b6f6SJean-Jacques Hiblot 	case 1:
1349c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_1;
1350c744b6f6SJean-Jacques Hiblot 		break;
1351c744b6f6SJean-Jacques Hiblot 	case 2:
1352c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_2;
1353c744b6f6SJean-Jacques Hiblot 		break;
1354c744b6f6SJean-Jacques Hiblot 	case 3:
1355c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_3;
1356c744b6f6SJean-Jacques Hiblot 		break;
1357c744b6f6SJean-Jacques Hiblot 	case 5:
1358c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_41;
1359c744b6f6SJean-Jacques Hiblot 		break;
1360c744b6f6SJean-Jacques Hiblot 	case 6:
1361c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_4_5;
1362c744b6f6SJean-Jacques Hiblot 		break;
1363c744b6f6SJean-Jacques Hiblot 	case 7:
1364c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_5_0;
1365c744b6f6SJean-Jacques Hiblot 		break;
1366c744b6f6SJean-Jacques Hiblot 	case 8:
1367c744b6f6SJean-Jacques Hiblot 		mmc->version = MMC_VERSION_5_1;
1368c744b6f6SJean-Jacques Hiblot 		break;
1369c744b6f6SJean-Jacques Hiblot 	}
1370c744b6f6SJean-Jacques Hiblot 
1371c744b6f6SJean-Jacques Hiblot 	/* The partition data may be non-zero but it is only
1372c744b6f6SJean-Jacques Hiblot 	 * effective if PARTITION_SETTING_COMPLETED is set in
1373c744b6f6SJean-Jacques Hiblot 	 * EXT_CSD, so ignore any data if this bit is not set,
1374c744b6f6SJean-Jacques Hiblot 	 * except for enabling the high-capacity group size
1375c744b6f6SJean-Jacques Hiblot 	 * definition (see below).
1376c744b6f6SJean-Jacques Hiblot 	 */
1377c744b6f6SJean-Jacques Hiblot 	part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
1378c744b6f6SJean-Jacques Hiblot 			    EXT_CSD_PARTITION_SETTING_COMPLETED);
1379c744b6f6SJean-Jacques Hiblot 
1380c744b6f6SJean-Jacques Hiblot 	/* store the partition info of emmc */
1381c744b6f6SJean-Jacques Hiblot 	mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
1382c744b6f6SJean-Jacques Hiblot 	if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
1383c744b6f6SJean-Jacques Hiblot 	    ext_csd[EXT_CSD_BOOT_MULT])
1384c744b6f6SJean-Jacques Hiblot 		mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
1385c744b6f6SJean-Jacques Hiblot 	if (part_completed &&
1386c744b6f6SJean-Jacques Hiblot 	    (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
1387c744b6f6SJean-Jacques Hiblot 		mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
1388c744b6f6SJean-Jacques Hiblot 
1389c744b6f6SJean-Jacques Hiblot 	mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
1390c744b6f6SJean-Jacques Hiblot 
1391c744b6f6SJean-Jacques Hiblot 	mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
1392c744b6f6SJean-Jacques Hiblot 
1393c744b6f6SJean-Jacques Hiblot 	for (i = 0; i < 4; i++) {
1394c744b6f6SJean-Jacques Hiblot 		int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
1395c744b6f6SJean-Jacques Hiblot 		uint mult = (ext_csd[idx + 2] << 16) +
1396c744b6f6SJean-Jacques Hiblot 			(ext_csd[idx + 1] << 8) + ext_csd[idx];
1397c744b6f6SJean-Jacques Hiblot 		if (mult)
1398c744b6f6SJean-Jacques Hiblot 			has_parts = true;
1399c744b6f6SJean-Jacques Hiblot 		if (!part_completed)
1400c744b6f6SJean-Jacques Hiblot 			continue;
1401c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] = mult;
1402c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] *=
1403c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1404c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1405c744b6f6SJean-Jacques Hiblot 		mmc->capacity_gp[i] <<= 19;
1406c744b6f6SJean-Jacques Hiblot 	}
1407c744b6f6SJean-Jacques Hiblot 
1408c744b6f6SJean-Jacques Hiblot 	if (part_completed) {
1409c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size =
1410c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_SIZE_MULT + 2] << 16) +
1411c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_SIZE_MULT + 1] << 8) +
1412c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_ENH_SIZE_MULT];
1413c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1414c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1415c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_size <<= 19;
1416c744b6f6SJean-Jacques Hiblot 		mmc->enh_user_start =
1417c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 3] << 24) +
1418c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 2] << 16) +
1419c744b6f6SJean-Jacques Hiblot 			(ext_csd[EXT_CSD_ENH_START_ADDR + 1] << 8) +
1420c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_ENH_START_ADDR];
1421c744b6f6SJean-Jacques Hiblot 		if (mmc->high_capacity)
1422c744b6f6SJean-Jacques Hiblot 			mmc->enh_user_start <<= 9;
1423c744b6f6SJean-Jacques Hiblot 	}
1424c744b6f6SJean-Jacques Hiblot 
1425c744b6f6SJean-Jacques Hiblot 	/*
1426c744b6f6SJean-Jacques Hiblot 	 * Host needs to enable ERASE_GRP_DEF bit if device is
1427c744b6f6SJean-Jacques Hiblot 	 * partitioned. This bit will be lost every time after a reset
1428c744b6f6SJean-Jacques Hiblot 	 * or power off. This will affect erase size.
1429c744b6f6SJean-Jacques Hiblot 	 */
1430c744b6f6SJean-Jacques Hiblot 	if (part_completed)
1431c744b6f6SJean-Jacques Hiblot 		has_parts = true;
1432c744b6f6SJean-Jacques Hiblot 	if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
1433c744b6f6SJean-Jacques Hiblot 	    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
1434c744b6f6SJean-Jacques Hiblot 		has_parts = true;
1435c744b6f6SJean-Jacques Hiblot 	if (has_parts) {
1436c744b6f6SJean-Jacques Hiblot 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1437c744b6f6SJean-Jacques Hiblot 				 EXT_CSD_ERASE_GROUP_DEF, 1);
1438c744b6f6SJean-Jacques Hiblot 
1439c744b6f6SJean-Jacques Hiblot 		if (err)
1440c744b6f6SJean-Jacques Hiblot 			return err;
1441c744b6f6SJean-Jacques Hiblot 
1442c744b6f6SJean-Jacques Hiblot 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1443c744b6f6SJean-Jacques Hiblot 	}
1444c744b6f6SJean-Jacques Hiblot 
1445c744b6f6SJean-Jacques Hiblot 	if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
1446c744b6f6SJean-Jacques Hiblot 		/* Read out group size from ext_csd */
1447c744b6f6SJean-Jacques Hiblot 		mmc->erase_grp_size =
1448c744b6f6SJean-Jacques Hiblot 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1449c744b6f6SJean-Jacques Hiblot 		/*
1450c744b6f6SJean-Jacques Hiblot 		 * if high capacity and partition setting completed
1451c744b6f6SJean-Jacques Hiblot 		 * SEC_COUNT is valid even if it is smaller than 2 GiB
1452c744b6f6SJean-Jacques Hiblot 		 * JEDEC Standard JESD84-B45, 6.2.4
1453c744b6f6SJean-Jacques Hiblot 		 */
1454c744b6f6SJean-Jacques Hiblot 		if (mmc->high_capacity && part_completed) {
1455c744b6f6SJean-Jacques Hiblot 			capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
1456c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
1457c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
1458c744b6f6SJean-Jacques Hiblot 				(ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
1459c744b6f6SJean-Jacques Hiblot 			capacity *= MMC_MAX_BLOCK_LEN;
1460c744b6f6SJean-Jacques Hiblot 			mmc->capacity_user = capacity;
1461c744b6f6SJean-Jacques Hiblot 		}
1462c744b6f6SJean-Jacques Hiblot 	} else {
1463c744b6f6SJean-Jacques Hiblot 		/* Calculate the group size from the csd value. */
1464c744b6f6SJean-Jacques Hiblot 		int erase_gsz, erase_gmul;
1465c744b6f6SJean-Jacques Hiblot 
1466c744b6f6SJean-Jacques Hiblot 		erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
1467c744b6f6SJean-Jacques Hiblot 		erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
1468c744b6f6SJean-Jacques Hiblot 		mmc->erase_grp_size = (erase_gsz + 1)
1469c744b6f6SJean-Jacques Hiblot 			* (erase_gmul + 1);
1470c744b6f6SJean-Jacques Hiblot 	}
1471c744b6f6SJean-Jacques Hiblot 
1472c744b6f6SJean-Jacques Hiblot 	mmc->hc_wp_grp_size = 1024
1473c744b6f6SJean-Jacques Hiblot 		* ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
1474c744b6f6SJean-Jacques Hiblot 		* ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1475c744b6f6SJean-Jacques Hiblot 
1476c744b6f6SJean-Jacques Hiblot 	mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
1477c744b6f6SJean-Jacques Hiblot 
1478c744b6f6SJean-Jacques Hiblot 	return 0;
1479c744b6f6SJean-Jacques Hiblot }
1480c744b6f6SJean-Jacques Hiblot 
1481fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc)
1482272cc70bSAndy Fleming {
1483f866a46dSStephen Warren 	int err, i;
1484272cc70bSAndy Fleming 	uint mult, freq;
1485c744b6f6SJean-Jacques Hiblot 	u64 cmult, csize;
1486272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1487c40fdca6SSimon Glass 	struct blk_desc *bdesc;
1488272cc70bSAndy Fleming 
1489d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
1490d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
1491d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
1492d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
1493d52ebf10SThomas Chou 		cmd.cmdarg = 1;
1494d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
1495d52ebf10SThomas Chou 
1496d52ebf10SThomas Chou 		if (err)
1497d52ebf10SThomas Chou 			return err;
1498d52ebf10SThomas Chou 	}
1499d52ebf10SThomas Chou #endif
1500d52ebf10SThomas Chou 
1501272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
1502d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
1503d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
1504272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1505272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1506272cc70bSAndy Fleming 
1507272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1508272cc70bSAndy Fleming 
1509272cc70bSAndy Fleming 	if (err)
1510272cc70bSAndy Fleming 		return err;
1511272cc70bSAndy Fleming 
1512272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
1513272cc70bSAndy Fleming 
1514272cc70bSAndy Fleming 	/*
1515272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
1516272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
1517272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
1518272cc70bSAndy Fleming 	 */
1519d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1520272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
1521272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1522272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
1523272cc70bSAndy Fleming 
1524272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1525272cc70bSAndy Fleming 
1526272cc70bSAndy Fleming 		if (err)
1527272cc70bSAndy Fleming 			return err;
1528272cc70bSAndy Fleming 
1529272cc70bSAndy Fleming 		if (IS_SD(mmc))
1530998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
1531d52ebf10SThomas Chou 	}
1532272cc70bSAndy Fleming 
1533272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
1534272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
1535272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1536272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1537272cc70bSAndy Fleming 
1538272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1539272cc70bSAndy Fleming 
1540272cc70bSAndy Fleming 	if (err)
1541272cc70bSAndy Fleming 		return err;
1542272cc70bSAndy Fleming 
1543998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
1544998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
1545998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
1546998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
1547272cc70bSAndy Fleming 
1548272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
15490b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
1550272cc70bSAndy Fleming 
1551272cc70bSAndy Fleming 		switch (version) {
1552272cc70bSAndy Fleming 		case 0:
1553272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1554272cc70bSAndy Fleming 			break;
1555272cc70bSAndy Fleming 		case 1:
1556272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_4;
1557272cc70bSAndy Fleming 			break;
1558272cc70bSAndy Fleming 		case 2:
1559272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_2_2;
1560272cc70bSAndy Fleming 			break;
1561272cc70bSAndy Fleming 		case 3:
1562272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_3;
1563272cc70bSAndy Fleming 			break;
1564272cc70bSAndy Fleming 		case 4:
1565272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_4;
1566272cc70bSAndy Fleming 			break;
1567272cc70bSAndy Fleming 		default:
1568272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1569272cc70bSAndy Fleming 			break;
1570272cc70bSAndy Fleming 		}
1571272cc70bSAndy Fleming 	}
1572272cc70bSAndy Fleming 
1573272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
15740b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
15750b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
1576272cc70bSAndy Fleming 
1577*35f9e196SJean-Jacques Hiblot 	mmc->legacy_speed = freq * mult;
1578*35f9e196SJean-Jacques Hiblot 	mmc->tran_speed = mmc->legacy_speed;
1579*35f9e196SJean-Jacques Hiblot 	mmc_select_mode(mmc, MMC_LEGACY);
1580272cc70bSAndy Fleming 
1581ab71188cSMarkus Niebel 	mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
1582998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
1583272cc70bSAndy Fleming 
1584272cc70bSAndy Fleming 	if (IS_SD(mmc))
1585272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
1586272cc70bSAndy Fleming 	else
1587998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
1588272cc70bSAndy Fleming 
1589272cc70bSAndy Fleming 	if (mmc->high_capacity) {
1590272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
1591272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
1592272cc70bSAndy Fleming 		cmult = 8;
1593272cc70bSAndy Fleming 	} else {
1594272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
1595272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
1596272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
1597272cc70bSAndy Fleming 	}
1598272cc70bSAndy Fleming 
1599f866a46dSStephen Warren 	mmc->capacity_user = (csize + 1) << (cmult + 2);
1600f866a46dSStephen Warren 	mmc->capacity_user *= mmc->read_bl_len;
1601f866a46dSStephen Warren 	mmc->capacity_boot = 0;
1602f866a46dSStephen Warren 	mmc->capacity_rpmb = 0;
1603f866a46dSStephen Warren 	for (i = 0; i < 4; i++)
1604f866a46dSStephen Warren 		mmc->capacity_gp[i] = 0;
1605272cc70bSAndy Fleming 
16068bfa195eSSimon Glass 	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
16078bfa195eSSimon Glass 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
1608272cc70bSAndy Fleming 
16098bfa195eSSimon Glass 	if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
16108bfa195eSSimon Glass 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
1611272cc70bSAndy Fleming 
1612ab71188cSMarkus Niebel 	if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
1613ab71188cSMarkus Niebel 		cmd.cmdidx = MMC_CMD_SET_DSR;
1614ab71188cSMarkus Niebel 		cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
1615ab71188cSMarkus Niebel 		cmd.resp_type = MMC_RSP_NONE;
1616ab71188cSMarkus Niebel 		if (mmc_send_cmd(mmc, &cmd, NULL))
1617ab71188cSMarkus Niebel 			printf("MMC: SET_DSR failed\n");
1618ab71188cSMarkus Niebel 	}
1619ab71188cSMarkus Niebel 
1620272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
1621d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1622272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
1623fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
1624272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1625272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1626272cc70bSAndy Fleming 
1627272cc70bSAndy Fleming 		if (err)
1628272cc70bSAndy Fleming 			return err;
1629d52ebf10SThomas Chou 	}
1630272cc70bSAndy Fleming 
1631e6f99a56SLei Wen 	/*
1632e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
1633e6f99a56SLei Wen 	 */
1634e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
1635bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
1636c744b6f6SJean-Jacques Hiblot 
1637dfda9d88SJean-Jacques Hiblot 	err = mmc_startup_v4(mmc);
16389cf199ebSDiego Santa Cruz 	if (err)
16399cf199ebSDiego Santa Cruz 		return err;
1640f866a46dSStephen Warren 
1641c40fdca6SSimon Glass 	err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart);
1642f866a46dSStephen Warren 	if (err)
1643f866a46dSStephen Warren 		return err;
1644d23e2c09SSukumar Ghorai 
1645272cc70bSAndy Fleming 	if (IS_SD(mmc))
16468ac8a263SJean-Jacques Hiblot 		err = sd_select_bus_freq_width(mmc);
1647272cc70bSAndy Fleming 	else
1648dfda9d88SJean-Jacques Hiblot 		err = mmc_select_bus_freq_width(mmc);
1649272cc70bSAndy Fleming 
1650272cc70bSAndy Fleming 	if (err)
1651272cc70bSAndy Fleming 		return err;
1652272cc70bSAndy Fleming 
1653ad5fd922SJaehoon Chung 	mmc_set_clock(mmc, mmc->tran_speed);
1654272cc70bSAndy Fleming 
16555af8f45cSAndrew Gabbasov 	/* Fix the block length for DDR mode */
16565af8f45cSAndrew Gabbasov 	if (mmc->ddr_mode) {
16575af8f45cSAndrew Gabbasov 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
16585af8f45cSAndrew Gabbasov 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
16595af8f45cSAndrew Gabbasov 	}
16605af8f45cSAndrew Gabbasov 
1661272cc70bSAndy Fleming 	/* fill in device description */
1662c40fdca6SSimon Glass 	bdesc = mmc_get_blk_desc(mmc);
1663c40fdca6SSimon Glass 	bdesc->lun = 0;
1664c40fdca6SSimon Glass 	bdesc->hwpart = 0;
1665c40fdca6SSimon Glass 	bdesc->type = 0;
1666c40fdca6SSimon Glass 	bdesc->blksz = mmc->read_bl_len;
1667c40fdca6SSimon Glass 	bdesc->log2blksz = LOG2(bdesc->blksz);
1668c40fdca6SSimon Glass 	bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len);
1669fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \
1670fc011f64SSjoerd Simons 		(defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \
1671fc011f64SSjoerd Simons 		!defined(CONFIG_USE_TINY_PRINTF))
1672c40fdca6SSimon Glass 	sprintf(bdesc->vendor, "Man %06x Snr %04x%04x",
1673babce5f6STaylor Hutt 		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
1674babce5f6STaylor Hutt 		(mmc->cid[3] >> 16) & 0xffff);
1675c40fdca6SSimon Glass 	sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
16760b453ffeSRabin Vincent 		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
1677babce5f6STaylor Hutt 		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
1678babce5f6STaylor Hutt 		(mmc->cid[2] >> 24) & 0xff);
1679c40fdca6SSimon Glass 	sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
1680babce5f6STaylor Hutt 		(mmc->cid[2] >> 16) & 0xf);
168156196826SPaul Burton #else
1682c40fdca6SSimon Glass 	bdesc->vendor[0] = 0;
1683c40fdca6SSimon Glass 	bdesc->product[0] = 0;
1684c40fdca6SSimon Glass 	bdesc->revision[0] = 0;
168556196826SPaul Burton #endif
1686122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
1687c40fdca6SSimon Glass 	part_init(bdesc);
1688122efd43SMikhail Kshevetskiy #endif
1689272cc70bSAndy Fleming 
1690272cc70bSAndy Fleming 	return 0;
1691272cc70bSAndy Fleming }
1692272cc70bSAndy Fleming 
1693fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc)
1694272cc70bSAndy Fleming {
1695272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1696272cc70bSAndy Fleming 	int err;
1697272cc70bSAndy Fleming 
1698272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
1699272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
170093bfd616SPantelis Antoniou 	cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa;
1701272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
1702272cc70bSAndy Fleming 
1703272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1704272cc70bSAndy Fleming 
1705272cc70bSAndy Fleming 	if (err)
1706272cc70bSAndy Fleming 		return err;
1707272cc70bSAndy Fleming 
1708998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
1709915ffa52SJaehoon Chung 		return -EOPNOTSUPP;
1710272cc70bSAndy Fleming 	else
1711272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
1712272cc70bSAndy Fleming 
1713272cc70bSAndy Fleming 	return 0;
1714272cc70bSAndy Fleming }
1715272cc70bSAndy Fleming 
1716c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
171795de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */
171895de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void)
171995de9ab2SPaul Kocialkowski {
172095de9ab2SPaul Kocialkowski }
172105cbeb7cSSimon Glass #endif
172295de9ab2SPaul Kocialkowski 
17232051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc)
17242051aefeSPeng Fan {
1725c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
172606ec045fSJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_REGULATOR)
17272051aefeSPeng Fan 	int ret;
17282051aefeSPeng Fan 
17292051aefeSPeng Fan 	ret = device_get_supply_regulator(mmc->dev, "vmmc-supply",
173006ec045fSJean-Jacques Hiblot 					  &mmc->vmmc_supply);
173106ec045fSJean-Jacques Hiblot 	if (ret)
1732288db7c7SJaehoon Chung 		debug("%s: No vmmc supply\n", mmc->dev->name);
17332051aefeSPeng Fan 
173406ec045fSJean-Jacques Hiblot 	ret = device_get_supply_regulator(mmc->dev, "vqmmc-supply",
173506ec045fSJean-Jacques Hiblot 					  &mmc->vqmmc_supply);
173606ec045fSJean-Jacques Hiblot 	if (ret)
173706ec045fSJean-Jacques Hiblot 		debug("%s: No vqmmc supply\n", mmc->dev->name);
173806ec045fSJean-Jacques Hiblot 
173906ec045fSJean-Jacques Hiblot 	if (mmc->vmmc_supply) {
174006ec045fSJean-Jacques Hiblot 		ret = regulator_set_enable(mmc->vmmc_supply, true);
17412051aefeSPeng Fan 		if (ret) {
17422051aefeSPeng Fan 			puts("Error enabling VMMC supply\n");
17432051aefeSPeng Fan 			return ret;
17442051aefeSPeng Fan 		}
174506ec045fSJean-Jacques Hiblot 	}
17462051aefeSPeng Fan #endif
174705cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */
174805cbeb7cSSimon Glass 	/*
174905cbeb7cSSimon Glass 	 * Driver model should use a regulator, as above, rather than calling
175005cbeb7cSSimon Glass 	 * out to board code.
175105cbeb7cSSimon Glass 	 */
175205cbeb7cSSimon Glass 	board_mmc_power_init();
175305cbeb7cSSimon Glass #endif
17542051aefeSPeng Fan 	return 0;
17552051aefeSPeng Fan }
17562051aefeSPeng Fan 
1757e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc)
1758272cc70bSAndy Fleming {
17598ca51e51SSimon Glass 	bool no_card;
1760afd5932bSMacpaul Lin 	int err;
1761272cc70bSAndy Fleming 
1762ab769f22SPantelis Antoniou 	/* we pretend there's no card when init is NULL */
17638ca51e51SSimon Glass 	no_card = mmc_getcd(mmc) == 0;
1764e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
17658ca51e51SSimon Glass 	no_card = no_card || (mmc->cfg->ops->init == NULL);
17668ca51e51SSimon Glass #endif
17678ca51e51SSimon Glass 	if (no_card) {
176848972d90SThierry Reding 		mmc->has_init = 0;
176956196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
177048972d90SThierry Reding 		printf("MMC: no card present\n");
177156196826SPaul Burton #endif
1772915ffa52SJaehoon Chung 		return -ENOMEDIUM;
177348972d90SThierry Reding 	}
177448972d90SThierry Reding 
1775bc897b1dSLei Wen 	if (mmc->has_init)
1776bc897b1dSLei Wen 		return 0;
1777bc897b1dSLei Wen 
17785a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
17795a8dbdc6SYangbo Lu 	mmc_adapter_card_type_ident();
17805a8dbdc6SYangbo Lu #endif
17812051aefeSPeng Fan 	err = mmc_power_init(mmc);
17822051aefeSPeng Fan 	if (err)
17832051aefeSPeng Fan 		return err;
178495de9ab2SPaul Kocialkowski 
1785e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
17868ca51e51SSimon Glass 	/* The device has already been probed ready for use */
17878ca51e51SSimon Glass #else
1788ab769f22SPantelis Antoniou 	/* made sure it's not NULL earlier */
178993bfd616SPantelis Antoniou 	err = mmc->cfg->ops->init(mmc);
1790272cc70bSAndy Fleming 	if (err)
1791272cc70bSAndy Fleming 		return err;
17928ca51e51SSimon Glass #endif
1793786e8f81SAndrew Gabbasov 	mmc->ddr_mode = 0;
1794b86b85e2SIlya Yanok 	mmc_set_bus_width(mmc, 1);
1795b86b85e2SIlya Yanok 	mmc_set_clock(mmc, 1);
1796b86b85e2SIlya Yanok 
1797272cc70bSAndy Fleming 	/* Reset the Card */
1798272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
1799272cc70bSAndy Fleming 
1800272cc70bSAndy Fleming 	if (err)
1801272cc70bSAndy Fleming 		return err;
1802272cc70bSAndy Fleming 
1803bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
1804c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->hwpart = 0;
1805bc897b1dSLei Wen 
1806272cc70bSAndy Fleming 	/* Test for SD version 2 */
1807272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
1808272cc70bSAndy Fleming 
1809272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
1810272cc70bSAndy Fleming 	err = sd_send_op_cond(mmc);
1811272cc70bSAndy Fleming 
1812272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
1813915ffa52SJaehoon Chung 	if (err == -ETIMEDOUT) {
1814272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
1815272cc70bSAndy Fleming 
1816bd47c135SAndrew Gabbasov 		if (err) {
181756196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
1818272cc70bSAndy Fleming 			printf("Card did not respond to voltage select!\n");
181956196826SPaul Burton #endif
1820915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
1821272cc70bSAndy Fleming 		}
1822272cc70bSAndy Fleming 	}
1823272cc70bSAndy Fleming 
1824bd47c135SAndrew Gabbasov 	if (!err)
1825e9550449SChe-Liang Chiou 		mmc->init_in_progress = 1;
1826e9550449SChe-Liang Chiou 
1827e9550449SChe-Liang Chiou 	return err;
1828e9550449SChe-Liang Chiou }
1829e9550449SChe-Liang Chiou 
1830e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc)
1831e9550449SChe-Liang Chiou {
1832e9550449SChe-Liang Chiou 	int err = 0;
1833e9550449SChe-Liang Chiou 
1834bd47c135SAndrew Gabbasov 	mmc->init_in_progress = 0;
1835e9550449SChe-Liang Chiou 	if (mmc->op_cond_pending)
1836e9550449SChe-Liang Chiou 		err = mmc_complete_op_cond(mmc);
1837e9550449SChe-Liang Chiou 
1838e9550449SChe-Liang Chiou 	if (!err)
1839bc897b1dSLei Wen 		err = mmc_startup(mmc);
1840bc897b1dSLei Wen 	if (err)
1841bc897b1dSLei Wen 		mmc->has_init = 0;
1842bc897b1dSLei Wen 	else
1843bc897b1dSLei Wen 		mmc->has_init = 1;
1844e9550449SChe-Liang Chiou 	return err;
1845e9550449SChe-Liang Chiou }
1846e9550449SChe-Liang Chiou 
1847e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc)
1848e9550449SChe-Liang Chiou {
1849bd47c135SAndrew Gabbasov 	int err = 0;
1850ce9eca94SMarek Vasut 	__maybe_unused unsigned start;
1851c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
185233fb211dSSimon Glass 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev);
1853e9550449SChe-Liang Chiou 
185433fb211dSSimon Glass 	upriv->mmc = mmc;
185533fb211dSSimon Glass #endif
1856e9550449SChe-Liang Chiou 	if (mmc->has_init)
1857e9550449SChe-Liang Chiou 		return 0;
1858d803fea5SMateusz Zalega 
1859d803fea5SMateusz Zalega 	start = get_timer(0);
1860d803fea5SMateusz Zalega 
1861e9550449SChe-Liang Chiou 	if (!mmc->init_in_progress)
1862e9550449SChe-Liang Chiou 		err = mmc_start_init(mmc);
1863e9550449SChe-Liang Chiou 
1864bd47c135SAndrew Gabbasov 	if (!err)
1865e9550449SChe-Liang Chiou 		err = mmc_complete_init(mmc);
1866919b4858SJagan Teki 	if (err)
1867919b4858SJagan Teki 		printf("%s: %d, time %lu\n", __func__, err, get_timer(start));
1868919b4858SJagan Teki 
1869bc897b1dSLei Wen 	return err;
1870272cc70bSAndy Fleming }
1871272cc70bSAndy Fleming 
1872ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val)
1873ab71188cSMarkus Niebel {
1874ab71188cSMarkus Niebel 	mmc->dsr = val;
1875ab71188cSMarkus Niebel 	return 0;
1876ab71188cSMarkus Niebel }
1877ab71188cSMarkus Niebel 
1878cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */
1879cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis)
1880272cc70bSAndy Fleming {
1881272cc70bSAndy Fleming 	return -1;
1882272cc70bSAndy Fleming }
1883272cc70bSAndy Fleming 
1884cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */
1885cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis)
1886cee9ab7cSJeroen Hofstee {
1887cee9ab7cSJeroen Hofstee 	return -1;
1888cee9ab7cSJeroen Hofstee }
1889272cc70bSAndy Fleming 
1890e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit)
1891e9550449SChe-Liang Chiou {
1892e9550449SChe-Liang Chiou 	mmc->preinit = preinit;
1893e9550449SChe-Liang Chiou }
1894e9550449SChe-Liang Chiou 
1895c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD)
18968e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
18978e3332e2SSjoerd Simons {
18988e3332e2SSjoerd Simons 	return 0;
18998e3332e2SSjoerd Simons }
1900c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC)
19018e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
19028e3332e2SSjoerd Simons {
19034a1db6d8SSimon Glass 	int ret, i;
19048e3332e2SSjoerd Simons 	struct uclass *uc;
19054a1db6d8SSimon Glass 	struct udevice *dev;
19068e3332e2SSjoerd Simons 
19078e3332e2SSjoerd Simons 	ret = uclass_get(UCLASS_MMC, &uc);
19088e3332e2SSjoerd Simons 	if (ret)
19098e3332e2SSjoerd Simons 		return ret;
19108e3332e2SSjoerd Simons 
19114a1db6d8SSimon Glass 	/*
19124a1db6d8SSimon Glass 	 * Try to add them in sequence order. Really with driver model we
19134a1db6d8SSimon Glass 	 * should allow holes, but the current MMC list does not allow that.
19144a1db6d8SSimon Glass 	 * So if we request 0, 1, 3 we will get 0, 1, 2.
19154a1db6d8SSimon Glass 	 */
19164a1db6d8SSimon Glass 	for (i = 0; ; i++) {
19174a1db6d8SSimon Glass 		ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev);
19184a1db6d8SSimon Glass 		if (ret == -ENODEV)
19194a1db6d8SSimon Glass 			break;
19204a1db6d8SSimon Glass 	}
19214a1db6d8SSimon Glass 	uclass_foreach_dev(dev, uc) {
19224a1db6d8SSimon Glass 		ret = device_probe(dev);
19238e3332e2SSjoerd Simons 		if (ret)
19244a1db6d8SSimon Glass 			printf("%s - probe failed: %d\n", dev->name, ret);
19258e3332e2SSjoerd Simons 	}
19268e3332e2SSjoerd Simons 
19278e3332e2SSjoerd Simons 	return 0;
19288e3332e2SSjoerd Simons }
19298e3332e2SSjoerd Simons #else
19308e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
19318e3332e2SSjoerd Simons {
19328e3332e2SSjoerd Simons 	if (board_mmc_init(bis) < 0)
19338e3332e2SSjoerd Simons 		cpu_mmc_init(bis);
19348e3332e2SSjoerd Simons 
19358e3332e2SSjoerd Simons 	return 0;
19368e3332e2SSjoerd Simons }
19378e3332e2SSjoerd Simons #endif
1938e9550449SChe-Liang Chiou 
1939272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
1940272cc70bSAndy Fleming {
19411b26bab1SDaniel Kochmański 	static int initialized = 0;
19428e3332e2SSjoerd Simons 	int ret;
19431b26bab1SDaniel Kochmański 	if (initialized)	/* Avoid initializing mmc multiple times */
19441b26bab1SDaniel Kochmański 		return 0;
19451b26bab1SDaniel Kochmański 	initialized = 1;
19461b26bab1SDaniel Kochmański 
1947c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK)
1948b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY)
1949c40fdca6SSimon Glass 	mmc_list_init();
1950c40fdca6SSimon Glass #endif
1951b5b838f1SMarek Vasut #endif
19528e3332e2SSjoerd Simons 	ret = mmc_probe(bis);
19538e3332e2SSjoerd Simons 	if (ret)
19548e3332e2SSjoerd Simons 		return ret;
1955272cc70bSAndy Fleming 
1956bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD
1957272cc70bSAndy Fleming 	print_mmc_devices(',');
1958bb0dc108SYing Zhang #endif
1959272cc70bSAndy Fleming 
1960c40fdca6SSimon Glass 	mmc_do_preinit();
1961272cc70bSAndy Fleming 	return 0;
1962272cc70bSAndy Fleming }
1963cd3d4880STomas Melin 
1964cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE
1965cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc)
1966cd3d4880STomas Melin {
1967cd3d4880STomas Melin 	int err;
1968cd3d4880STomas Melin 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
1969cd3d4880STomas Melin 
1970cd3d4880STomas Melin 	err = mmc_send_ext_csd(mmc, ext_csd);
1971cd3d4880STomas Melin 	if (err) {
1972cd3d4880STomas Melin 		puts("Could not get ext_csd register values\n");
1973cd3d4880STomas Melin 		return err;
1974cd3d4880STomas Melin 	}
1975cd3d4880STomas Melin 
1976cd3d4880STomas Melin 	if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) {
1977cd3d4880STomas Melin 		puts("Background operations not supported on device\n");
1978cd3d4880STomas Melin 		return -EMEDIUMTYPE;
1979cd3d4880STomas Melin 	}
1980cd3d4880STomas Melin 
1981cd3d4880STomas Melin 	if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) {
1982cd3d4880STomas Melin 		puts("Background operations already enabled\n");
1983cd3d4880STomas Melin 		return 0;
1984cd3d4880STomas Melin 	}
1985cd3d4880STomas Melin 
1986cd3d4880STomas Melin 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1);
1987cd3d4880STomas Melin 	if (err) {
1988cd3d4880STomas Melin 		puts("Failed to enable manual background operations\n");
1989cd3d4880STomas Melin 		return err;
1990cd3d4880STomas Melin 	}
1991cd3d4880STomas Melin 
1992cd3d4880STomas Melin 	puts("Enabled manual background operations\n");
1993cd3d4880STomas Melin 
1994cd3d4880STomas Melin 	return 0;
1995cd3d4880STomas Melin }
1996cd3d4880STomas Melin #endif
1997