xref: /rk3399_rockchip-uboot/drivers/mmc/mmc.c (revision 479fbf72ee0660f74652da35a9f837b0e0ee06e8)
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 
33e531136eSJason Zhu static char mmc_ext_csd[512];
34e531136eSJason Zhu 
35b5b838f1SMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY)
36b5b838f1SMarek Vasut static struct mmc mmc_static;
37b5b838f1SMarek Vasut struct mmc *find_mmc_device(int dev_num)
38b5b838f1SMarek Vasut {
39b5b838f1SMarek Vasut 	return &mmc_static;
40b5b838f1SMarek Vasut }
41b5b838f1SMarek Vasut 
42b5b838f1SMarek Vasut void mmc_do_preinit(void)
43b5b838f1SMarek Vasut {
44b5b838f1SMarek Vasut 	struct mmc *m = &mmc_static;
45b5b838f1SMarek Vasut #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
46b5b838f1SMarek Vasut 	mmc_set_preinit(m, 1);
47b5b838f1SMarek Vasut #endif
48b5b838f1SMarek Vasut 	if (m->preinit)
49b5b838f1SMarek Vasut 		mmc_start_init(m);
50b5b838f1SMarek Vasut }
51b5b838f1SMarek Vasut 
52b5b838f1SMarek Vasut struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
53b5b838f1SMarek Vasut {
54b5b838f1SMarek Vasut 	return &mmc->block_dev;
55b5b838f1SMarek Vasut }
56b5b838f1SMarek Vasut #endif
57b5b838f1SMarek Vasut 
58e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
59750121c3SJeroen Hofstee __weak int board_mmc_getwp(struct mmc *mmc)
60d23d8d7eSNikita Kiryanov {
61d23d8d7eSNikita Kiryanov 	return -1;
62d23d8d7eSNikita Kiryanov }
63d23d8d7eSNikita Kiryanov 
64d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc)
65d23d8d7eSNikita Kiryanov {
66d23d8d7eSNikita Kiryanov 	int wp;
67d23d8d7eSNikita Kiryanov 
68d23d8d7eSNikita Kiryanov 	wp = board_mmc_getwp(mmc);
69d23d8d7eSNikita Kiryanov 
70d4e1da4eSPeter Korsgaard 	if (wp < 0) {
7193bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getwp)
7293bfd616SPantelis Antoniou 			wp = mmc->cfg->ops->getwp(mmc);
73d4e1da4eSPeter Korsgaard 		else
74d4e1da4eSPeter Korsgaard 			wp = 0;
75d4e1da4eSPeter Korsgaard 	}
76d23d8d7eSNikita Kiryanov 
77d23d8d7eSNikita Kiryanov 	return wp;
78d23d8d7eSNikita Kiryanov }
79d23d8d7eSNikita Kiryanov 
80cee9ab7cSJeroen Hofstee __weak int board_mmc_getcd(struct mmc *mmc)
81cee9ab7cSJeroen Hofstee {
8211fdade2SStefano Babic 	return -1;
8311fdade2SStefano Babic }
848ca51e51SSimon Glass #endif
8511fdade2SStefano Babic 
868635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE
87c0c76ebaSSimon Glass void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd)
88c0c76ebaSSimon Glass {
89c0c76ebaSSimon Glass 	printf("CMD_SEND:%d\n", cmd->cmdidx);
90c0c76ebaSSimon Glass 	printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg);
91c0c76ebaSSimon Glass }
92c0c76ebaSSimon Glass 
93c0c76ebaSSimon Glass void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret)
94c0c76ebaSSimon Glass {
955db2fe3aSRaffaele Recalcati 	int i;
965db2fe3aSRaffaele Recalcati 	u8 *ptr;
975db2fe3aSRaffaele Recalcati 
987863ce58SBin Meng 	if (ret) {
997863ce58SBin Meng 		printf("\t\tRET\t\t\t %d\n", ret);
1007863ce58SBin Meng 	} else {
1015db2fe3aSRaffaele Recalcati 		switch (cmd->resp_type) {
1025db2fe3aSRaffaele Recalcati 		case MMC_RSP_NONE:
1035db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_NONE\n");
1045db2fe3aSRaffaele Recalcati 			break;
1055db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1:
1065db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n",
1075db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1085db2fe3aSRaffaele Recalcati 			break;
1095db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1b:
1105db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n",
1115db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1125db2fe3aSRaffaele Recalcati 			break;
1135db2fe3aSRaffaele Recalcati 		case MMC_RSP_R2:
1145db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R2\t\t 0x%08X \n",
1155db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1165db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1175db2fe3aSRaffaele Recalcati 				cmd->response[1]);
1185db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1195db2fe3aSRaffaele Recalcati 				cmd->response[2]);
1205db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1215db2fe3aSRaffaele Recalcati 				cmd->response[3]);
1225db2fe3aSRaffaele Recalcati 			printf("\n");
1235db2fe3aSRaffaele Recalcati 			printf("\t\t\t\t\tDUMPING DATA\n");
1245db2fe3aSRaffaele Recalcati 			for (i = 0; i < 4; i++) {
1255db2fe3aSRaffaele Recalcati 				int j;
1265db2fe3aSRaffaele Recalcati 				printf("\t\t\t\t\t%03d - ", i*4);
127146bec79SDirk Behme 				ptr = (u8 *)&cmd->response[i];
1285db2fe3aSRaffaele Recalcati 				ptr += 3;
1295db2fe3aSRaffaele Recalcati 				for (j = 0; j < 4; j++)
1305db2fe3aSRaffaele Recalcati 					printf("%02X ", *ptr--);
1315db2fe3aSRaffaele Recalcati 				printf("\n");
1325db2fe3aSRaffaele Recalcati 			}
1335db2fe3aSRaffaele Recalcati 			break;
1345db2fe3aSRaffaele Recalcati 		case MMC_RSP_R3:
1355db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n",
1365db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1375db2fe3aSRaffaele Recalcati 			break;
1385db2fe3aSRaffaele Recalcati 		default:
1395db2fe3aSRaffaele Recalcati 			printf("\t\tERROR MMC rsp not supported\n");
1405db2fe3aSRaffaele Recalcati 			break;
1415db2fe3aSRaffaele Recalcati 		}
1427863ce58SBin Meng 	}
143c0c76ebaSSimon Glass }
144c0c76ebaSSimon Glass 
145c0c76ebaSSimon Glass void mmc_trace_state(struct mmc *mmc, struct mmc_cmd *cmd)
146c0c76ebaSSimon Glass {
147c0c76ebaSSimon Glass 	int status;
148c0c76ebaSSimon Glass 
149c0c76ebaSSimon Glass 	status = (cmd->response[0] & MMC_STATUS_CURR_STATE) >> 9;
150c0c76ebaSSimon Glass 	printf("CURR STATE:%d\n", status);
151c0c76ebaSSimon Glass }
1525db2fe3aSRaffaele Recalcati #endif
153c0c76ebaSSimon Glass 
154e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
155c0c76ebaSSimon Glass int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
156c0c76ebaSSimon Glass {
157c0c76ebaSSimon Glass 	int ret;
158c0c76ebaSSimon Glass 
159c0c76ebaSSimon Glass 	mmmc_trace_before_send(mmc, cmd);
160c0c76ebaSSimon Glass 	ret = mmc->cfg->ops->send_cmd(mmc, cmd, data);
161c0c76ebaSSimon Glass 	mmmc_trace_after_send(mmc, cmd, ret);
162c0c76ebaSSimon Glass 
1638635ff9eSMarek Vasut 	return ret;
164272cc70bSAndy Fleming }
1658ca51e51SSimon Glass #endif
166272cc70bSAndy Fleming 
167da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout)
1685d4fc8d9SRaffaele Recalcati {
1695d4fc8d9SRaffaele Recalcati 	struct mmc_cmd cmd;
170d617c426SJan Kloetzke 	int err, retries = 5;
1715d4fc8d9SRaffaele Recalcati 
1725d4fc8d9SRaffaele Recalcati 	cmd.cmdidx = MMC_CMD_SEND_STATUS;
1735d4fc8d9SRaffaele Recalcati 	cmd.resp_type = MMC_RSP_R1;
174aaf3d41aSMarek Vasut 	if (!mmc_host_is_spi(mmc))
175aaf3d41aSMarek Vasut 		cmd.cmdarg = mmc->rca << 16;
1765d4fc8d9SRaffaele Recalcati 
1771677eef4SAndrew Gabbasov 	while (1) {
1785d4fc8d9SRaffaele Recalcati 		err = mmc_send_cmd(mmc, &cmd, NULL);
179d617c426SJan Kloetzke 		if (!err) {
180d617c426SJan Kloetzke 			if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) &&
181d617c426SJan Kloetzke 			    (cmd.response[0] & MMC_STATUS_CURR_STATE) !=
182d617c426SJan Kloetzke 			     MMC_STATE_PRG)
1835d4fc8d9SRaffaele Recalcati 				break;
184d617c426SJan Kloetzke 			else if (cmd.response[0] & MMC_STATUS_MASK) {
18556196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
186d617c426SJan Kloetzke 				printf("Status Error: 0x%08X\n",
187d617c426SJan Kloetzke 					cmd.response[0]);
18856196826SPaul Burton #endif
189915ffa52SJaehoon Chung 				return -ECOMM;
190d617c426SJan Kloetzke 			}
191d617c426SJan Kloetzke 		} else if (--retries < 0)
192d617c426SJan Kloetzke 			return err;
1935d4fc8d9SRaffaele Recalcati 
1941677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
1951677eef4SAndrew Gabbasov 			break;
1965d4fc8d9SRaffaele Recalcati 
1971677eef4SAndrew Gabbasov 		udelay(1000);
1981677eef4SAndrew Gabbasov 	}
1995d4fc8d9SRaffaele Recalcati 
200c0c76ebaSSimon Glass 	mmc_trace_state(mmc, &cmd);
2015b0c942fSJongman Heo 	if (timeout <= 0) {
20256196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2035d4fc8d9SRaffaele Recalcati 		printf("Timeout waiting card ready\n");
20456196826SPaul Burton #endif
205915ffa52SJaehoon Chung 		return -ETIMEDOUT;
2065d4fc8d9SRaffaele Recalcati 	}
2075d4fc8d9SRaffaele Recalcati 
2085d4fc8d9SRaffaele Recalcati 	return 0;
2095d4fc8d9SRaffaele Recalcati }
2105d4fc8d9SRaffaele Recalcati 
211da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len)
212272cc70bSAndy Fleming {
213272cc70bSAndy Fleming 	struct mmc_cmd cmd;
214272cc70bSAndy Fleming 
215caa21a21SZiyuan Xu 	if (mmc_card_ddr(mmc))
216d22e3d46SJaehoon Chung 		return 0;
217d22e3d46SJaehoon Chung 
218272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
219272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
220272cc70bSAndy Fleming 	cmd.cmdarg = len;
221272cc70bSAndy Fleming 
222272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, NULL);
223272cc70bSAndy Fleming }
224272cc70bSAndy Fleming 
225ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
226fdbb873eSKim Phillips 			   lbaint_t blkcnt)
227272cc70bSAndy Fleming {
228272cc70bSAndy Fleming 	struct mmc_cmd cmd;
229272cc70bSAndy Fleming 	struct mmc_data data;
230272cc70bSAndy Fleming 
2314a1a06bcSAlagu Sankar 	if (blkcnt > 1)
2324a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
2334a1a06bcSAlagu Sankar 	else
234272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
235272cc70bSAndy Fleming 
236272cc70bSAndy Fleming 	if (mmc->high_capacity)
2374a1a06bcSAlagu Sankar 		cmd.cmdarg = start;
238272cc70bSAndy Fleming 	else
2394a1a06bcSAlagu Sankar 		cmd.cmdarg = start * mmc->read_bl_len;
240272cc70bSAndy Fleming 
241272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
242272cc70bSAndy Fleming 
243272cc70bSAndy Fleming 	data.dest = dst;
2444a1a06bcSAlagu Sankar 	data.blocks = blkcnt;
245272cc70bSAndy Fleming 	data.blocksize = mmc->read_bl_len;
246272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
247272cc70bSAndy Fleming 
2484a1a06bcSAlagu Sankar 	if (mmc_send_cmd(mmc, &cmd, &data))
2494a1a06bcSAlagu Sankar 		return 0;
2504a1a06bcSAlagu Sankar 
2514a1a06bcSAlagu Sankar 	if (blkcnt > 1) {
2524a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
2534a1a06bcSAlagu Sankar 		cmd.cmdarg = 0;
2544a1a06bcSAlagu Sankar 		cmd.resp_type = MMC_RSP_R1b;
2554a1a06bcSAlagu Sankar 		if (mmc_send_cmd(mmc, &cmd, NULL)) {
25656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2574a1a06bcSAlagu Sankar 			printf("mmc fail to send stop cmd\n");
25856196826SPaul Burton #endif
2594a1a06bcSAlagu Sankar 			return 0;
2604a1a06bcSAlagu Sankar 		}
261272cc70bSAndy Fleming 	}
262272cc70bSAndy Fleming 
2634a1a06bcSAlagu Sankar 	return blkcnt;
264272cc70bSAndy Fleming }
265272cc70bSAndy Fleming 
266c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
2677dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst)
26833fb211dSSimon Glass #else
2697dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
2707dba0b93SSimon Glass 		void *dst)
27133fb211dSSimon Glass #endif
272272cc70bSAndy Fleming {
273c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
27433fb211dSSimon Glass 	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
27533fb211dSSimon Glass #endif
276bcce53d0SSimon Glass 	int dev_num = block_dev->devnum;
277873cc1d7SStephen Warren 	int err;
2784a1a06bcSAlagu Sankar 	lbaint_t cur, blocks_todo = blkcnt;
279272cc70bSAndy Fleming 
2804a1a06bcSAlagu Sankar 	if (blkcnt == 0)
2814a1a06bcSAlagu Sankar 		return 0;
2824a1a06bcSAlagu Sankar 
2834a1a06bcSAlagu Sankar 	struct mmc *mmc = find_mmc_device(dev_num);
284272cc70bSAndy Fleming 	if (!mmc)
285272cc70bSAndy Fleming 		return 0;
286272cc70bSAndy Fleming 
287b5b838f1SMarek Vasut 	if (CONFIG_IS_ENABLED(MMC_TINY))
288b5b838f1SMarek Vasut 		err = mmc_switch_part(mmc, block_dev->hwpart);
289b5b838f1SMarek Vasut 	else
29069f45cd5SSimon Glass 		err = blk_dselect_hwpart(block_dev, block_dev->hwpart);
291b5b838f1SMarek Vasut 
292873cc1d7SStephen Warren 	if (err < 0)
293873cc1d7SStephen Warren 		return 0;
294873cc1d7SStephen Warren 
295c40fdca6SSimon Glass 	if ((start + blkcnt) > block_dev->lba) {
29656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
297ff8fef56SSascha Silbe 		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
298c40fdca6SSimon Glass 			start + blkcnt, block_dev->lba);
29956196826SPaul Burton #endif
300d2bf29e3SLei Wen 		return 0;
301d2bf29e3SLei Wen 	}
302272cc70bSAndy Fleming 
30311692991SSimon Glass 	if (mmc_set_blocklen(mmc, mmc->read_bl_len)) {
30411692991SSimon Glass 		debug("%s: Failed to set blocklen\n", __func__);
305272cc70bSAndy Fleming 		return 0;
30611692991SSimon Glass 	}
307272cc70bSAndy Fleming 
3084a1a06bcSAlagu Sankar 	do {
30993bfd616SPantelis Antoniou 		cur = (blocks_todo > mmc->cfg->b_max) ?
31093bfd616SPantelis Antoniou 			mmc->cfg->b_max : blocks_todo;
31111692991SSimon Glass 		if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
31211692991SSimon Glass 			debug("%s: Failed to read blocks\n", __func__);
313c30b5115SJason Zhu 			int timeout = 0;
314c30b5115SJason Zhu re_init_retry:
315c30b5115SJason Zhu 			timeout++;
316c30b5115SJason Zhu 			/*
317c30b5115SJason Zhu 			 * Try re-init seven times.
318c30b5115SJason Zhu 			 */
319c30b5115SJason Zhu 			if (timeout > 7) {
320c30b5115SJason Zhu 				printf("Re-init retry timeout\n");
3214a1a06bcSAlagu Sankar 				return 0;
32211692991SSimon Glass 			}
323c30b5115SJason Zhu 
324c30b5115SJason Zhu 			mmc->has_init = 0;
325c30b5115SJason Zhu 			if (mmc_init(mmc))
326c30b5115SJason Zhu 				return 0;
327c30b5115SJason Zhu 
328c30b5115SJason Zhu 			if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
329c30b5115SJason Zhu 				printf("%s: Re-init mmc_read_blocks error\n",
330c30b5115SJason Zhu 				       __func__);
331c30b5115SJason Zhu 				goto re_init_retry;
332c30b5115SJason Zhu 			}
333c30b5115SJason Zhu 		}
3344a1a06bcSAlagu Sankar 		blocks_todo -= cur;
3354a1a06bcSAlagu Sankar 		start += cur;
3364a1a06bcSAlagu Sankar 		dst += cur * mmc->read_bl_len;
3374a1a06bcSAlagu Sankar 	} while (blocks_todo > 0);
338272cc70bSAndy Fleming 
339272cc70bSAndy Fleming 	return blkcnt;
340272cc70bSAndy Fleming }
341272cc70bSAndy Fleming 
34249dba033SZiyuan Xu void mmc_set_clock(struct mmc *mmc, uint clock)
34349dba033SZiyuan Xu {
34449dba033SZiyuan Xu 	if (clock > mmc->cfg->f_max)
34549dba033SZiyuan Xu 		clock = mmc->cfg->f_max;
34649dba033SZiyuan Xu 
34749dba033SZiyuan Xu 	if (clock < mmc->cfg->f_min)
34849dba033SZiyuan Xu 		clock = mmc->cfg->f_min;
34949dba033SZiyuan Xu 
35049dba033SZiyuan Xu 	mmc->clock = clock;
35149dba033SZiyuan Xu 
35249dba033SZiyuan Xu 	mmc_set_ios(mmc);
35349dba033SZiyuan Xu }
35449dba033SZiyuan Xu 
35549dba033SZiyuan Xu static void mmc_set_bus_width(struct mmc *mmc, uint width)
35649dba033SZiyuan Xu {
35749dba033SZiyuan Xu 	mmc->bus_width = width;
35849dba033SZiyuan Xu 
35949dba033SZiyuan Xu 	mmc_set_ios(mmc);
36049dba033SZiyuan Xu }
36149dba033SZiyuan Xu 
36281db2d36SZiyuan Xu static void mmc_set_timing(struct mmc *mmc, uint timing)
36381db2d36SZiyuan Xu {
36481db2d36SZiyuan Xu 	mmc->timing = timing;
36581db2d36SZiyuan Xu 	mmc_set_ios(mmc);
36681db2d36SZiyuan Xu }
36781db2d36SZiyuan Xu 
368fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc)
369272cc70bSAndy Fleming {
370272cc70bSAndy Fleming 	struct mmc_cmd cmd;
371272cc70bSAndy Fleming 	int err;
372272cc70bSAndy Fleming 
373272cc70bSAndy Fleming 	udelay(1000);
374272cc70bSAndy Fleming 
375272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
376272cc70bSAndy Fleming 	cmd.cmdarg = 0;
377272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_NONE;
378272cc70bSAndy Fleming 
379272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
380272cc70bSAndy Fleming 
381272cc70bSAndy Fleming 	if (err)
382272cc70bSAndy Fleming 		return err;
383272cc70bSAndy Fleming 
384272cc70bSAndy Fleming 	udelay(2000);
385272cc70bSAndy Fleming 
386272cc70bSAndy Fleming 	return 0;
387272cc70bSAndy Fleming }
388272cc70bSAndy Fleming 
389*479fbf72SJason Zhu #ifndef CONFIG_MMC_USE_PRE_CONFIG
390fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc)
391272cc70bSAndy Fleming {
392272cc70bSAndy Fleming 	int timeout = 1000;
393272cc70bSAndy Fleming 	int err;
394272cc70bSAndy Fleming 	struct mmc_cmd cmd;
395272cc70bSAndy Fleming 
3961677eef4SAndrew Gabbasov 	while (1) {
397272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_APP_CMD;
398272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1;
399272cc70bSAndy Fleming 		cmd.cmdarg = 0;
400272cc70bSAndy Fleming 
401272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
402272cc70bSAndy Fleming 
403272cc70bSAndy Fleming 		if (err)
404272cc70bSAndy Fleming 			return err;
405272cc70bSAndy Fleming 
406272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
407272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
408250de12bSStefano Babic 
409250de12bSStefano Babic 		/*
410250de12bSStefano Babic 		 * Most cards do not answer if some reserved bits
411250de12bSStefano Babic 		 * in the ocr are set. However, Some controller
412250de12bSStefano Babic 		 * can set bit 7 (reserved for low voltages), but
413250de12bSStefano Babic 		 * how to manage low voltages SD card is not yet
414250de12bSStefano Babic 		 * specified.
415250de12bSStefano Babic 		 */
416d52ebf10SThomas Chou 		cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
41793bfd616SPantelis Antoniou 			(mmc->cfg->voltages & 0xff8000);
418272cc70bSAndy Fleming 
419272cc70bSAndy Fleming 		if (mmc->version == SD_VERSION_2)
420272cc70bSAndy Fleming 			cmd.cmdarg |= OCR_HCS;
421272cc70bSAndy Fleming 
422272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
423272cc70bSAndy Fleming 
424272cc70bSAndy Fleming 		if (err)
425272cc70bSAndy Fleming 			return err;
426272cc70bSAndy Fleming 
4271677eef4SAndrew Gabbasov 		if (cmd.response[0] & OCR_BUSY)
4281677eef4SAndrew Gabbasov 			break;
429272cc70bSAndy Fleming 
4301677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
431915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
432272cc70bSAndy Fleming 
4331677eef4SAndrew Gabbasov 		udelay(1000);
4341677eef4SAndrew Gabbasov 	}
4351677eef4SAndrew Gabbasov 
436272cc70bSAndy Fleming 	if (mmc->version != SD_VERSION_2)
437272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
438272cc70bSAndy Fleming 
439d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
440d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
441d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
442d52ebf10SThomas Chou 		cmd.cmdarg = 0;
443d52ebf10SThomas Chou 
444d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
445d52ebf10SThomas Chou 
446d52ebf10SThomas Chou 		if (err)
447d52ebf10SThomas Chou 			return err;
448d52ebf10SThomas Chou 	}
449d52ebf10SThomas Chou 
450998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
451272cc70bSAndy Fleming 
452272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
453272cc70bSAndy Fleming 	mmc->rca = 0;
454272cc70bSAndy Fleming 
455272cc70bSAndy Fleming 	return 0;
456272cc70bSAndy Fleming }
457*479fbf72SJason Zhu #endif
458272cc70bSAndy Fleming 
4595289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg)
460272cc70bSAndy Fleming {
4615289b535SAndrew Gabbasov 	struct mmc_cmd cmd;
462272cc70bSAndy Fleming 	int err;
463272cc70bSAndy Fleming 
4645289b535SAndrew Gabbasov 	cmd.cmdidx = MMC_CMD_SEND_OP_COND;
4655289b535SAndrew Gabbasov 	cmd.resp_type = MMC_RSP_R3;
4665289b535SAndrew Gabbasov 	cmd.cmdarg = 0;
4675a20397bSRob Herring 	if (use_arg && !mmc_host_is_spi(mmc))
4685a20397bSRob Herring 		cmd.cmdarg = OCR_HCS |
46993bfd616SPantelis Antoniou 			(mmc->cfg->voltages &
470a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_VOLTAGE_MASK)) |
471a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_ACCESS_MODE);
472e9550449SChe-Liang Chiou 
4735289b535SAndrew Gabbasov 	err = mmc_send_cmd(mmc, &cmd, NULL);
474e9550449SChe-Liang Chiou 	if (err)
475e9550449SChe-Liang Chiou 		return err;
4765289b535SAndrew Gabbasov 	mmc->ocr = cmd.response[0];
477e9550449SChe-Liang Chiou 	return 0;
478e9550449SChe-Liang Chiou }
479e9550449SChe-Liang Chiou 
480*479fbf72SJason Zhu #ifndef CONFIG_MMC_USE_PRE_CONFIG
481750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc)
482e9550449SChe-Liang Chiou {
483e9550449SChe-Liang Chiou 	int err, i;
484e9550449SChe-Liang Chiou 
485272cc70bSAndy Fleming 	/* Some cards seem to need this */
486272cc70bSAndy Fleming 	mmc_go_idle(mmc);
487272cc70bSAndy Fleming 
48831cacbabSRaffaele Recalcati  	/* Asking to the card its capabilities */
489e9550449SChe-Liang Chiou 	for (i = 0; i < 2; i++) {
4905289b535SAndrew Gabbasov 		err = mmc_send_op_cond_iter(mmc, i != 0);
49131cacbabSRaffaele Recalcati 		if (err)
49231cacbabSRaffaele Recalcati 			return err;
49331cacbabSRaffaele Recalcati 
494e9550449SChe-Liang Chiou 		/* exit if not busy (flag seems to be inverted) */
495a626c8d4SAndrew Gabbasov 		if (mmc->ocr & OCR_BUSY)
496bd47c135SAndrew Gabbasov 			break;
497e9550449SChe-Liang Chiou 	}
498bd47c135SAndrew Gabbasov 	mmc->op_cond_pending = 1;
499bd47c135SAndrew Gabbasov 	return 0;
500e9550449SChe-Liang Chiou }
501*479fbf72SJason Zhu #endif
502750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc)
503e9550449SChe-Liang Chiou {
504e9550449SChe-Liang Chiou 	struct mmc_cmd cmd;
505e9550449SChe-Liang Chiou 	int timeout = 1000;
506e9550449SChe-Liang Chiou 	uint start;
507e9550449SChe-Liang Chiou 	int err;
508e9550449SChe-Liang Chiou 
509e9550449SChe-Liang Chiou 	mmc->op_cond_pending = 0;
510cc17c01fSAndrew Gabbasov 	if (!(mmc->ocr & OCR_BUSY)) {
511d188b113SYangbo Lu 		/* Some cards seem to need this */
512d188b113SYangbo Lu 		mmc_go_idle(mmc);
513d188b113SYangbo Lu 
514e9550449SChe-Liang Chiou 		start = get_timer(0);
5151677eef4SAndrew Gabbasov 		while (1) {
5165289b535SAndrew Gabbasov 			err = mmc_send_op_cond_iter(mmc, 1);
517272cc70bSAndy Fleming 			if (err)
518272cc70bSAndy Fleming 				return err;
5191677eef4SAndrew Gabbasov 			if (mmc->ocr & OCR_BUSY)
5201677eef4SAndrew Gabbasov 				break;
521e9550449SChe-Liang Chiou 			if (get_timer(start) > timeout)
522915ffa52SJaehoon Chung 				return -EOPNOTSUPP;
523e9550449SChe-Liang Chiou 			udelay(100);
5241677eef4SAndrew Gabbasov 		}
525cc17c01fSAndrew Gabbasov 	}
526272cc70bSAndy Fleming 
527d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
528d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
529d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
530d52ebf10SThomas Chou 		cmd.cmdarg = 0;
531d52ebf10SThomas Chou 
532d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
533d52ebf10SThomas Chou 
534d52ebf10SThomas Chou 		if (err)
535d52ebf10SThomas Chou 			return err;
536a626c8d4SAndrew Gabbasov 
537a626c8d4SAndrew Gabbasov 		mmc->ocr = cmd.response[0];
538d52ebf10SThomas Chou 	}
539d52ebf10SThomas Chou 
540272cc70bSAndy Fleming 	mmc->version = MMC_VERSION_UNKNOWN;
541272cc70bSAndy Fleming 
542272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
543def816a2SStephen Warren 	mmc->rca = 1;
544272cc70bSAndy Fleming 
545272cc70bSAndy Fleming 	return 0;
546272cc70bSAndy Fleming }
547272cc70bSAndy Fleming 
548272cc70bSAndy Fleming 
549fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
550272cc70bSAndy Fleming {
551e531136eSJason Zhu 	static int initialized;
552272cc70bSAndy Fleming 	struct mmc_cmd cmd;
553272cc70bSAndy Fleming 	struct mmc_data data;
554272cc70bSAndy Fleming 	int err;
555272cc70bSAndy Fleming 
556e531136eSJason Zhu 	if (initialized) {
557e531136eSJason Zhu 		memcpy(ext_csd, mmc_ext_csd, 512);
558e531136eSJason Zhu 		return 0;
559e531136eSJason Zhu 	}
560e531136eSJason Zhu 
561e531136eSJason Zhu 	initialized = 1;
562e531136eSJason Zhu 
563272cc70bSAndy Fleming 	/* Get the Card Status Register */
564272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
565272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
566272cc70bSAndy Fleming 	cmd.cmdarg = 0;
567272cc70bSAndy Fleming 
568cdfd1ac6SYoshihiro Shimoda 	data.dest = (char *)ext_csd;
569272cc70bSAndy Fleming 	data.blocks = 1;
5708bfa195eSSimon Glass 	data.blocksize = MMC_MAX_BLOCK_LEN;
571272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
572272cc70bSAndy Fleming 
573272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
574e531136eSJason Zhu 	memcpy(mmc_ext_csd, ext_csd, 512);
575272cc70bSAndy Fleming 
576272cc70bSAndy Fleming 	return err;
577272cc70bSAndy Fleming }
578272cc70bSAndy Fleming 
5799e8ce816SZiyuan Xu static int mmc_poll_for_busy(struct mmc *mmc, u8 send_status)
580272cc70bSAndy Fleming {
581272cc70bSAndy Fleming 	struct mmc_cmd cmd;
58255e5defdSZiyuan Xu 	u8 busy = true;
58355e5defdSZiyuan Xu 	uint start;
58455e5defdSZiyuan Xu 	int ret;
5855d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
58655e5defdSZiyuan Xu 
58755e5defdSZiyuan Xu 	cmd.cmdidx = MMC_CMD_SEND_STATUS;
58855e5defdSZiyuan Xu 	cmd.resp_type = MMC_RSP_R1;
58955e5defdSZiyuan Xu 	cmd.cmdarg = mmc->rca << 16;
59055e5defdSZiyuan Xu 
59155e5defdSZiyuan Xu 	start = get_timer(0);
59255e5defdSZiyuan Xu 
5939e8ce816SZiyuan Xu 	if (!send_status && !mmc_can_card_busy(mmc)) {
5949e8ce816SZiyuan Xu 		mdelay(timeout);
5959e8ce816SZiyuan Xu 		return 0;
5969e8ce816SZiyuan Xu 	}
5979e8ce816SZiyuan Xu 
59855e5defdSZiyuan Xu 	do {
5999e8ce816SZiyuan Xu 		if (!send_status) {
60055e5defdSZiyuan Xu 			busy = mmc_card_busy(mmc);
60155e5defdSZiyuan Xu 		} else {
60255e5defdSZiyuan Xu 			ret = mmc_send_cmd(mmc, &cmd, NULL);
60355e5defdSZiyuan Xu 
60455e5defdSZiyuan Xu 			if (ret)
60555e5defdSZiyuan Xu 				return ret;
60655e5defdSZiyuan Xu 
60755e5defdSZiyuan Xu 			if (cmd.response[0] & MMC_STATUS_SWITCH_ERROR)
60855e5defdSZiyuan Xu 				return -EBADMSG;
60955e5defdSZiyuan Xu 			busy = (cmd.response[0] & MMC_STATUS_CURR_STATE) ==
61055e5defdSZiyuan Xu 				MMC_STATE_PRG;
61155e5defdSZiyuan Xu 		}
61255e5defdSZiyuan Xu 
61355e5defdSZiyuan Xu 		if (get_timer(start) > timeout && busy)
61455e5defdSZiyuan Xu 			return -ETIMEDOUT;
61555e5defdSZiyuan Xu 	} while (busy);
61655e5defdSZiyuan Xu 
61755e5defdSZiyuan Xu 	return 0;
61855e5defdSZiyuan Xu }
61955e5defdSZiyuan Xu 
62055e5defdSZiyuan Xu static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value,
62155e5defdSZiyuan Xu 			u8 send_status)
62255e5defdSZiyuan Xu {
62355e5defdSZiyuan Xu 	struct mmc_cmd cmd;
624a9003dc6SMaxime Ripard 	int retries = 3;
6255d4fc8d9SRaffaele Recalcati 	int ret;
626272cc70bSAndy Fleming 
627272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SWITCH;
628272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1b;
629272cc70bSAndy Fleming 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
630272cc70bSAndy Fleming 				 (index << 16) |
631272cc70bSAndy Fleming 				 (value << 8);
632272cc70bSAndy Fleming 
63355e5defdSZiyuan Xu 	do {
6345d4fc8d9SRaffaele Recalcati 		ret = mmc_send_cmd(mmc, &cmd, NULL);
6355d4fc8d9SRaffaele Recalcati 
6369e8ce816SZiyuan Xu 		if (!ret)
6379e8ce816SZiyuan Xu 			return mmc_poll_for_busy(mmc, send_status);
63855e5defdSZiyuan Xu 	} while (--retries > 0 && ret);
63955e5defdSZiyuan Xu 
640a9003dc6SMaxime Ripard 	return ret;
641a9003dc6SMaxime Ripard }
642a9003dc6SMaxime Ripard 
64355e5defdSZiyuan Xu int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
64455e5defdSZiyuan Xu {
64555e5defdSZiyuan Xu 	return __mmc_switch(mmc, set, index, value, true);
646272cc70bSAndy Fleming }
647272cc70bSAndy Fleming 
64849dba033SZiyuan Xu static int mmc_select_bus_width(struct mmc *mmc)
64949dba033SZiyuan Xu {
65049dba033SZiyuan Xu 	u32 ext_csd_bits[] = {
65149dba033SZiyuan Xu 		EXT_CSD_BUS_WIDTH_8,
65249dba033SZiyuan Xu 		EXT_CSD_BUS_WIDTH_4,
65349dba033SZiyuan Xu 	};
65449dba033SZiyuan Xu 	u32 bus_widths[] = {
65549dba033SZiyuan Xu 		MMC_BUS_WIDTH_8BIT,
65649dba033SZiyuan Xu 		MMC_BUS_WIDTH_4BIT,
65749dba033SZiyuan Xu 	};
65849dba033SZiyuan Xu 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
65949dba033SZiyuan Xu 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
66049dba033SZiyuan Xu 	u32 idx, bus_width = 0;
66149dba033SZiyuan Xu 	int err = 0;
66249dba033SZiyuan Xu 
66349dba033SZiyuan Xu 	if (mmc->version < MMC_VERSION_4 ||
66449dba033SZiyuan Xu 	    !(mmc->cfg->host_caps & (MMC_MODE_4BIT | MMC_MODE_8BIT)))
66549dba033SZiyuan Xu 		return 0;
66649dba033SZiyuan Xu 
66749dba033SZiyuan Xu 	err = mmc_send_ext_csd(mmc, ext_csd);
66849dba033SZiyuan Xu 
66949dba033SZiyuan Xu 	if (err)
67049dba033SZiyuan Xu 		return err;
67149dba033SZiyuan Xu 
67249dba033SZiyuan Xu 	idx = (mmc->cfg->host_caps & MMC_MODE_8BIT) ? 0 : 1;
67349dba033SZiyuan Xu 
67449dba033SZiyuan Xu 	/*
67549dba033SZiyuan Xu 	 * Unlike SD, MMC cards dont have a configuration register to notify
67649dba033SZiyuan Xu 	 * supported bus width. So bus test command should be run to identify
67749dba033SZiyuan Xu 	 * the supported bus width or compare the ext csd values of current
67849dba033SZiyuan Xu 	 * bus width and ext csd values of 1 bit mode read earlier.
67949dba033SZiyuan Xu 	 */
68049dba033SZiyuan Xu 	for (; idx < ARRAY_SIZE(bus_widths); idx++) {
68149dba033SZiyuan Xu 		/*
68249dba033SZiyuan Xu 		 * Host is capable of 8bit transfer, then switch
68349dba033SZiyuan Xu 		 * the device to work in 8bit transfer mode. If the
68449dba033SZiyuan Xu 		 * mmc switch command returns error then switch to
68549dba033SZiyuan Xu 		 * 4bit transfer mode. On success set the corresponding
68649dba033SZiyuan Xu 		 * bus width on the host.
68749dba033SZiyuan Xu 		 */
68849dba033SZiyuan Xu 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
68949dba033SZiyuan Xu 				 EXT_CSD_BUS_WIDTH, ext_csd_bits[idx]);
69049dba033SZiyuan Xu 		if (err)
69149dba033SZiyuan Xu 			continue;
69249dba033SZiyuan Xu 
69349dba033SZiyuan Xu 		bus_width = bus_widths[idx];
69449dba033SZiyuan Xu 		mmc_set_bus_width(mmc, bus_width);
69549dba033SZiyuan Xu 
69649dba033SZiyuan Xu 		err = mmc_send_ext_csd(mmc, test_csd);
69749dba033SZiyuan Xu 
69849dba033SZiyuan Xu 		if (err)
69949dba033SZiyuan Xu 			continue;
70049dba033SZiyuan Xu 
70149dba033SZiyuan Xu 		/* Only compare read only fields */
70249dba033SZiyuan Xu 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] ==
70349dba033SZiyuan Xu 			test_csd[EXT_CSD_PARTITIONING_SUPPORT]) &&
70449dba033SZiyuan Xu 		    (ext_csd[EXT_CSD_HC_WP_GRP_SIZE] ==
70549dba033SZiyuan Xu 			test_csd[EXT_CSD_HC_WP_GRP_SIZE]) &&
70649dba033SZiyuan Xu 		    (ext_csd[EXT_CSD_REV] == test_csd[EXT_CSD_REV]) &&
70749dba033SZiyuan Xu 			(ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] ==
70849dba033SZiyuan Xu 			test_csd[EXT_CSD_HC_ERASE_GRP_SIZE]) &&
70949dba033SZiyuan Xu 		    !memcmp(&ext_csd[EXT_CSD_SEC_CNT],
71049dba033SZiyuan Xu 			&test_csd[EXT_CSD_SEC_CNT], 4)) {
71149dba033SZiyuan Xu 			err = bus_width;
71249dba033SZiyuan Xu 			break;
71349dba033SZiyuan Xu 		} else {
71449dba033SZiyuan Xu 			err = -EBADMSG;
71549dba033SZiyuan Xu 		}
71649dba033SZiyuan Xu 	}
71749dba033SZiyuan Xu 
71849dba033SZiyuan Xu 	return err;
71949dba033SZiyuan Xu }
72049dba033SZiyuan Xu 
72149dba033SZiyuan Xu static const u8 tuning_blk_pattern_4bit[] = {
72249dba033SZiyuan Xu 	0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
72349dba033SZiyuan Xu 	0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
72449dba033SZiyuan Xu 	0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
72549dba033SZiyuan Xu 	0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
72649dba033SZiyuan Xu 	0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
72749dba033SZiyuan Xu 	0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
72849dba033SZiyuan Xu 	0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
72949dba033SZiyuan Xu 	0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
73049dba033SZiyuan Xu };
73149dba033SZiyuan Xu 
73249dba033SZiyuan Xu static const u8 tuning_blk_pattern_8bit[] = {
73349dba033SZiyuan Xu 	0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
73449dba033SZiyuan Xu 	0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
73549dba033SZiyuan Xu 	0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
73649dba033SZiyuan Xu 	0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
73749dba033SZiyuan Xu 	0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
73849dba033SZiyuan Xu 	0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
73949dba033SZiyuan Xu 	0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
74049dba033SZiyuan Xu 	0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
74149dba033SZiyuan Xu 	0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
74249dba033SZiyuan Xu 	0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
74349dba033SZiyuan Xu 	0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
74449dba033SZiyuan Xu 	0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
74549dba033SZiyuan Xu 	0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
74649dba033SZiyuan Xu 	0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
74749dba033SZiyuan Xu 	0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
74849dba033SZiyuan Xu 	0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
74949dba033SZiyuan Xu };
75049dba033SZiyuan Xu 
75149dba033SZiyuan Xu int mmc_send_tuning(struct mmc *mmc, u32 opcode)
75249dba033SZiyuan Xu {
75349dba033SZiyuan Xu 	struct mmc_cmd cmd;
75449dba033SZiyuan Xu 	struct mmc_data data;
75549dba033SZiyuan Xu 	const u8 *tuning_block_pattern;
75649dba033SZiyuan Xu 	int size, err = 0;
75749dba033SZiyuan Xu 	u8 *data_buf;
75849dba033SZiyuan Xu 
75949dba033SZiyuan Xu 	if (mmc->bus_width == MMC_BUS_WIDTH_8BIT) {
76049dba033SZiyuan Xu 		tuning_block_pattern = tuning_blk_pattern_8bit;
76149dba033SZiyuan Xu 		size = sizeof(tuning_blk_pattern_8bit);
76249dba033SZiyuan Xu 	} else if (mmc->bus_width == MMC_BUS_WIDTH_4BIT) {
76349dba033SZiyuan Xu 		tuning_block_pattern = tuning_blk_pattern_4bit;
76449dba033SZiyuan Xu 		size = sizeof(tuning_blk_pattern_4bit);
76549dba033SZiyuan Xu 	} else {
76649dba033SZiyuan Xu 		return -EINVAL;
76749dba033SZiyuan Xu 	}
76849dba033SZiyuan Xu 
76949dba033SZiyuan Xu 	data_buf = calloc(1, size);
77049dba033SZiyuan Xu 	if (!data_buf)
77149dba033SZiyuan Xu 		return -ENOMEM;
77249dba033SZiyuan Xu 
77349dba033SZiyuan Xu 	cmd.cmdidx = opcode;
77449dba033SZiyuan Xu 	cmd.resp_type = MMC_RSP_R1;
77549dba033SZiyuan Xu 	cmd.cmdarg = 0;
77649dba033SZiyuan Xu 
77749dba033SZiyuan Xu 	data.dest = (char *)data_buf;
77849dba033SZiyuan Xu 	data.blocksize = size;
77949dba033SZiyuan Xu 	data.blocks = 1;
78049dba033SZiyuan Xu 	data.flags = MMC_DATA_READ;
78149dba033SZiyuan Xu 
78249dba033SZiyuan Xu 	err = mmc_send_cmd(mmc, &cmd, &data);
78349dba033SZiyuan Xu 	if (err)
78449dba033SZiyuan Xu 		goto out;
78549dba033SZiyuan Xu 
78649dba033SZiyuan Xu 	if (memcmp(data_buf, tuning_block_pattern, size))
78749dba033SZiyuan Xu 		err = -EIO;
78849dba033SZiyuan Xu out:
78949dba033SZiyuan Xu 	free(data_buf);
79049dba033SZiyuan Xu 	return err;
79149dba033SZiyuan Xu }
79249dba033SZiyuan Xu 
79349dba033SZiyuan Xu static int mmc_execute_tuning(struct mmc *mmc)
79449dba033SZiyuan Xu {
79549dba033SZiyuan Xu #ifdef CONFIG_DM_MMC
79649dba033SZiyuan Xu 	struct dm_mmc_ops *ops = mmc_get_ops(mmc->dev);
79749dba033SZiyuan Xu #endif
79849dba033SZiyuan Xu 	u32 opcode;
79949dba033SZiyuan Xu 
80049dba033SZiyuan Xu 	if (IS_SD(mmc))
80149dba033SZiyuan Xu 		opcode = MMC_SEND_TUNING_BLOCK;
80249dba033SZiyuan Xu 	else
80349dba033SZiyuan Xu 		opcode = MMC_SEND_TUNING_BLOCK_HS200;
80449dba033SZiyuan Xu 
80549dba033SZiyuan Xu #ifndef CONFIG_DM_MMC
80649dba033SZiyuan Xu 	if (mmc->cfg->ops->execute_tuning) {
80749dba033SZiyuan Xu 		return mmc->cfg->ops->execute_tuning(mmc, opcode);
80849dba033SZiyuan Xu #else
80949dba033SZiyuan Xu 	if (ops->execute_tuning) {
81049dba033SZiyuan Xu 		return ops->execute_tuning(mmc->dev, opcode);
81149dba033SZiyuan Xu #endif
81249dba033SZiyuan Xu 	} else {
81349dba033SZiyuan Xu 		debug("Tuning feature required for HS200 mode.\n");
81449dba033SZiyuan Xu 		return -EIO;
81549dba033SZiyuan Xu 	}
81649dba033SZiyuan Xu }
81749dba033SZiyuan Xu 
81849dba033SZiyuan Xu static int mmc_hs200_tuning(struct mmc *mmc)
81949dba033SZiyuan Xu {
82049dba033SZiyuan Xu 	return mmc_execute_tuning(mmc);
82149dba033SZiyuan Xu }
82249dba033SZiyuan Xu 
823e61cd3d7SZiyuan Xu static int mmc_select_hs(struct mmc *mmc)
824e61cd3d7SZiyuan Xu {
825e61cd3d7SZiyuan Xu 	int ret;
826e61cd3d7SZiyuan Xu 
827e61cd3d7SZiyuan Xu 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
828e61cd3d7SZiyuan Xu 			 EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS);
829e61cd3d7SZiyuan Xu 
830e61cd3d7SZiyuan Xu 	if (!ret)
831e61cd3d7SZiyuan Xu 		mmc_set_timing(mmc, MMC_TIMING_MMC_HS);
832e61cd3d7SZiyuan Xu 
833e61cd3d7SZiyuan Xu 	return ret;
834e61cd3d7SZiyuan Xu }
835e61cd3d7SZiyuan Xu 
8365545757fSZiyuan Xu static int mmc_select_hs_ddr(struct mmc *mmc)
8375545757fSZiyuan Xu {
8385545757fSZiyuan Xu 	u32 ext_csd_bits;
8395545757fSZiyuan Xu 	int err = 0;
8405545757fSZiyuan Xu 
8415545757fSZiyuan Xu 	if (mmc->bus_width == MMC_BUS_WIDTH_1BIT)
8425545757fSZiyuan Xu 		return 0;
8435545757fSZiyuan Xu 
8445545757fSZiyuan Xu 	ext_csd_bits = (mmc->bus_width == MMC_BUS_WIDTH_8BIT) ?
8455545757fSZiyuan Xu 			EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
8465545757fSZiyuan Xu 
8475545757fSZiyuan Xu 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
8485545757fSZiyuan Xu 			 EXT_CSD_BUS_WIDTH, ext_csd_bits);
8495545757fSZiyuan Xu 	if (err)
8505545757fSZiyuan Xu 		return err;
8515545757fSZiyuan Xu 
8525545757fSZiyuan Xu 	mmc_set_timing(mmc, MMC_TIMING_MMC_DDR52);
8535545757fSZiyuan Xu 
8545545757fSZiyuan Xu 	return 0;
8555545757fSZiyuan Xu }
8565545757fSZiyuan Xu 
85749dba033SZiyuan Xu static int mmc_select_hs200(struct mmc *mmc)
85849dba033SZiyuan Xu {
85949dba033SZiyuan Xu 	int ret;
86049dba033SZiyuan Xu 
86149dba033SZiyuan Xu 	/*
86249dba033SZiyuan Xu 	 * Set the bus width(4 or 8) with host's support and
86349dba033SZiyuan Xu 	 * switch to HS200 mode if bus width is set successfully.
86449dba033SZiyuan Xu 	 */
86549dba033SZiyuan Xu 	ret = mmc_select_bus_width(mmc);
86649dba033SZiyuan Xu 
86749dba033SZiyuan Xu 	if (ret > 0) {
86849dba033SZiyuan Xu 		ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
86949dba033SZiyuan Xu 				   EXT_CSD_HS_TIMING,
87049dba033SZiyuan Xu 				   EXT_CSD_TIMING_HS200, false);
87149dba033SZiyuan Xu 
87249dba033SZiyuan Xu 		if (ret)
87349dba033SZiyuan Xu 			return ret;
87449dba033SZiyuan Xu 
87549dba033SZiyuan Xu 		mmc_set_timing(mmc, MMC_TIMING_MMC_HS200);
87649dba033SZiyuan Xu 	}
87749dba033SZiyuan Xu 
87849dba033SZiyuan Xu 	return ret;
87949dba033SZiyuan Xu }
88049dba033SZiyuan Xu 
881b673f29aSZiyuan Xu static int mmc_select_hs400(struct mmc *mmc)
882b673f29aSZiyuan Xu {
883b673f29aSZiyuan Xu 	int ret;
884b673f29aSZiyuan Xu 
885b673f29aSZiyuan Xu 	/* Switch card to HS mode */
886b673f29aSZiyuan Xu 	ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
887b673f29aSZiyuan Xu 			   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS, false);
888b673f29aSZiyuan Xu 	if (ret)
889b673f29aSZiyuan Xu 		return ret;
890b673f29aSZiyuan Xu 
891b673f29aSZiyuan Xu 	/* Set host controller to HS timing */
892b673f29aSZiyuan Xu 	mmc_set_timing(mmc, MMC_TIMING_MMC_HS);
893b673f29aSZiyuan Xu 
894b673f29aSZiyuan Xu 	/* Reduce frequency to HS frequency */
895b673f29aSZiyuan Xu 	mmc_set_clock(mmc, MMC_HIGH_52_MAX_DTR);
896b673f29aSZiyuan Xu 
897b673f29aSZiyuan Xu 	ret = mmc_send_status(mmc, 1000);
898b673f29aSZiyuan Xu 	if (ret)
899b673f29aSZiyuan Xu 		return ret;
900b673f29aSZiyuan Xu 
901b673f29aSZiyuan Xu 	/* Switch card to DDR */
902b673f29aSZiyuan Xu 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
903b673f29aSZiyuan Xu 			 EXT_CSD_BUS_WIDTH,
904b673f29aSZiyuan Xu 			 EXT_CSD_DDR_BUS_WIDTH_8);
905b673f29aSZiyuan Xu 	if (ret)
906b673f29aSZiyuan Xu 		return ret;
907b673f29aSZiyuan Xu 
908b673f29aSZiyuan Xu 	/* Switch card to HS400 */
909b673f29aSZiyuan Xu 	ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
910b673f29aSZiyuan Xu 			   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400, false);
911b673f29aSZiyuan Xu 	if (ret)
912b673f29aSZiyuan Xu 		return ret;
913b673f29aSZiyuan Xu 
914b673f29aSZiyuan Xu 	/* Set host controller to HS400 timing and frequency */
915b673f29aSZiyuan Xu 	mmc_set_timing(mmc, MMC_TIMING_MMC_HS400);
916b673f29aSZiyuan Xu 
917b673f29aSZiyuan Xu 	return ret;
918b673f29aSZiyuan Xu }
919b673f29aSZiyuan Xu 
920227f658eSZiyuan Xu static u32 mmc_select_card_type(struct mmc *mmc, u8 *ext_csd)
921227f658eSZiyuan Xu {
922227f658eSZiyuan Xu 	u8 card_type;
923227f658eSZiyuan Xu 	u32 host_caps, avail_type = 0;
924227f658eSZiyuan Xu 
925227f658eSZiyuan Xu 	card_type = ext_csd[EXT_CSD_CARD_TYPE];
926227f658eSZiyuan Xu 	host_caps = mmc->cfg->host_caps;
927227f658eSZiyuan Xu 
928227f658eSZiyuan Xu 	if ((host_caps & MMC_MODE_HS) &&
929227f658eSZiyuan Xu 	    (card_type & EXT_CSD_CARD_TYPE_26))
930227f658eSZiyuan Xu 		avail_type |= EXT_CSD_CARD_TYPE_26;
931227f658eSZiyuan Xu 
932227f658eSZiyuan Xu 	if ((host_caps & MMC_MODE_HS) &&
933227f658eSZiyuan Xu 	    (card_type & EXT_CSD_CARD_TYPE_52))
934227f658eSZiyuan Xu 		avail_type |= EXT_CSD_CARD_TYPE_52;
935227f658eSZiyuan Xu 
936227f658eSZiyuan Xu 	/*
937227f658eSZiyuan Xu 	 * For the moment, u-boot doesn't support signal voltage
938227f658eSZiyuan Xu 	 * switch, therefor we assume that host support ddr52
939227f658eSZiyuan Xu 	 * at 1.8v or 3.3v I/O(1.2v I/O not supported, hs200 and
940227f658eSZiyuan Xu 	 * hs400 are the same).
941227f658eSZiyuan Xu 	 */
942227f658eSZiyuan Xu 	if ((host_caps & MMC_MODE_DDR_52MHz) &&
943227f658eSZiyuan Xu 	    (card_type & EXT_CSD_CARD_TYPE_DDR_1_8V))
944227f658eSZiyuan Xu 		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
945227f658eSZiyuan Xu 
946227f658eSZiyuan Xu 	if ((host_caps & MMC_MODE_HS200) &&
947227f658eSZiyuan Xu 	    (card_type & EXT_CSD_CARD_TYPE_HS200_1_8V))
948227f658eSZiyuan Xu 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
949227f658eSZiyuan Xu 
950227f658eSZiyuan Xu 	/*
951227f658eSZiyuan Xu 	 * If host can support HS400, it means that host can also
952227f658eSZiyuan Xu 	 * support HS200.
953227f658eSZiyuan Xu 	 */
954227f658eSZiyuan Xu 	if ((host_caps & MMC_MODE_HS400) &&
955227f658eSZiyuan Xu 	    (host_caps & MMC_MODE_8BIT) &&
956227f658eSZiyuan Xu 	    (card_type & EXT_CSD_CARD_TYPE_HS400_1_8V))
957227f658eSZiyuan Xu 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V |
958227f658eSZiyuan Xu 				EXT_CSD_CARD_TYPE_HS400_1_8V;
959227f658eSZiyuan Xu 
960227f658eSZiyuan Xu 	if ((host_caps & MMC_MODE_HS400ES) &&
961227f658eSZiyuan Xu 	    (host_caps & MMC_MODE_8BIT) &&
962227f658eSZiyuan Xu 	    ext_csd[EXT_CSD_STROBE_SUPPORT] &&
963227f658eSZiyuan Xu 	    (avail_type & EXT_CSD_CARD_TYPE_HS400_1_8V))
964227f658eSZiyuan Xu 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V |
965227f658eSZiyuan Xu 				EXT_CSD_CARD_TYPE_HS400_1_8V |
966227f658eSZiyuan Xu 				EXT_CSD_CARD_TYPE_HS400ES;
967227f658eSZiyuan Xu 
968227f658eSZiyuan Xu 	return avail_type;
969227f658eSZiyuan Xu }
970227f658eSZiyuan Xu 
97149dba033SZiyuan Xu static void mmc_set_bus_speed(struct mmc *mmc, u8 avail_type)
97249dba033SZiyuan Xu {
97349dba033SZiyuan Xu 	int clock = 0;
97449dba033SZiyuan Xu 
97549dba033SZiyuan Xu 	if (mmc_card_hs(mmc))
97649dba033SZiyuan Xu 		clock = (avail_type & EXT_CSD_CARD_TYPE_52) ?
97749dba033SZiyuan Xu 			MMC_HIGH_52_MAX_DTR : MMC_HIGH_26_MAX_DTR;
97849dba033SZiyuan Xu 	else if (mmc_card_hs200(mmc) ||
97949dba033SZiyuan Xu 		 mmc_card_hs400(mmc) ||
98049dba033SZiyuan Xu 		 mmc_card_hs400es(mmc))
98149dba033SZiyuan Xu 		clock = MMC_HS200_MAX_DTR;
98249dba033SZiyuan Xu 
98349dba033SZiyuan Xu 	mmc_set_clock(mmc, clock);
98449dba033SZiyuan Xu }
98549dba033SZiyuan Xu 
986fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc)
987272cc70bSAndy Fleming {
9888bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
989227f658eSZiyuan Xu 	u32 avail_type;
990272cc70bSAndy Fleming 	int err;
991272cc70bSAndy Fleming 
992fc5b32fbSAndrew Gabbasov 	mmc->card_caps = 0;
993272cc70bSAndy Fleming 
994d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
995d52ebf10SThomas Chou 		return 0;
996d52ebf10SThomas Chou 
997272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
998272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
999272cc70bSAndy Fleming 		return 0;
1000272cc70bSAndy Fleming 
1001fc5b32fbSAndrew Gabbasov 	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
1002fc5b32fbSAndrew Gabbasov 
1003272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
1004272cc70bSAndy Fleming 
1005272cc70bSAndy Fleming 	if (err)
1006272cc70bSAndy Fleming 		return err;
1007272cc70bSAndy Fleming 
1008227f658eSZiyuan Xu 	avail_type = mmc_select_card_type(mmc, ext_csd);
1009272cc70bSAndy Fleming 
101049dba033SZiyuan Xu 	if (avail_type & EXT_CSD_CARD_TYPE_HS200)
101149dba033SZiyuan Xu 		err = mmc_select_hs200(mmc);
10121f250d0aSJason Zhu 	else if (avail_type & EXT_CSD_CARD_TYPE_HS)
1013e61cd3d7SZiyuan Xu 		err = mmc_select_hs(mmc);
1014227f658eSZiyuan Xu 	else
1015227f658eSZiyuan Xu 		err = -EINVAL;
1016272cc70bSAndy Fleming 
1017272cc70bSAndy Fleming 	if (err)
1018a5e27b41SHeiko Schocher 		return err;
1019272cc70bSAndy Fleming 
102049dba033SZiyuan Xu 	mmc_set_bus_speed(mmc, avail_type);
1021272cc70bSAndy Fleming 
1022b673f29aSZiyuan Xu 	if (mmc_card_hs200(mmc)) {
102349dba033SZiyuan Xu 		err = mmc_hs200_tuning(mmc);
1024b673f29aSZiyuan Xu 		if (avail_type & EXT_CSD_CARD_TYPE_HS400 &&
1025b673f29aSZiyuan Xu 		    mmc->bus_width == MMC_BUS_WIDTH_8BIT) {
1026b673f29aSZiyuan Xu 			err = mmc_select_hs400(mmc);
1027b673f29aSZiyuan Xu 			mmc_set_bus_speed(mmc, avail_type);
1028b673f29aSZiyuan Xu 		}
1029b673f29aSZiyuan Xu 	} else if (!mmc_card_hs400es(mmc)) {
103049dba033SZiyuan Xu 		err = mmc_select_bus_width(mmc) > 0 ? 0 : err;
10315545757fSZiyuan Xu 		if (!err && avail_type & EXT_CSD_CARD_TYPE_DDR_52)
10325545757fSZiyuan Xu 			err = mmc_select_hs_ddr(mmc);
10335545757fSZiyuan Xu 	}
103449dba033SZiyuan Xu 
1035272cc70bSAndy Fleming 	return err;
1036272cc70bSAndy Fleming }
1037272cc70bSAndy Fleming 
1038f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num)
1039f866a46dSStephen Warren {
1040f866a46dSStephen Warren 	switch (part_num) {
1041f866a46dSStephen Warren 	case 0:
1042f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_user;
1043f866a46dSStephen Warren 		break;
1044f866a46dSStephen Warren 	case 1:
1045f866a46dSStephen Warren 	case 2:
1046f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_boot;
1047f866a46dSStephen Warren 		break;
1048f866a46dSStephen Warren 	case 3:
1049f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_rpmb;
1050f866a46dSStephen Warren 		break;
1051f866a46dSStephen Warren 	case 4:
1052f866a46dSStephen Warren 	case 5:
1053f866a46dSStephen Warren 	case 6:
1054f866a46dSStephen Warren 	case 7:
1055f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_gp[part_num - 4];
1056f866a46dSStephen Warren 		break;
1057f866a46dSStephen Warren 	default:
1058f866a46dSStephen Warren 		return -1;
1059f866a46dSStephen Warren 	}
1060f866a46dSStephen Warren 
1061c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len);
1062f866a46dSStephen Warren 
1063f866a46dSStephen Warren 	return 0;
1064f866a46dSStephen Warren }
1065f866a46dSStephen Warren 
10667dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num)
1067bc897b1dSLei Wen {
1068f866a46dSStephen Warren 	int ret;
1069bc897b1dSLei Wen 
1070f866a46dSStephen Warren 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
1071bc897b1dSLei Wen 			 (mmc->part_config & ~PART_ACCESS_MASK)
1072bc897b1dSLei Wen 			 | (part_num & PART_ACCESS_MASK));
1073f866a46dSStephen Warren 
10746dc93e70SPeter Bigot 	/*
10756dc93e70SPeter Bigot 	 * Set the capacity if the switch succeeded or was intended
10766dc93e70SPeter Bigot 	 * to return to representing the raw device.
10776dc93e70SPeter Bigot 	 */
1078873cc1d7SStephen Warren 	if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) {
10796dc93e70SPeter Bigot 		ret = mmc_set_capacity(mmc, part_num);
1080fdbb139fSSimon Glass 		mmc_get_blk_desc(mmc)->hwpart = part_num;
1081873cc1d7SStephen Warren 	}
10826dc93e70SPeter Bigot 
10836dc93e70SPeter Bigot 	return ret;
1084bc897b1dSLei Wen }
1085bc897b1dSLei Wen 
1086ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc,
1087ac9da0e0SDiego Santa Cruz 		      const struct mmc_hwpart_conf *conf,
1088ac9da0e0SDiego Santa Cruz 		      enum mmc_hwpart_conf_mode mode)
1089ac9da0e0SDiego Santa Cruz {
1090ac9da0e0SDiego Santa Cruz 	u8 part_attrs = 0;
1091ac9da0e0SDiego Santa Cruz 	u32 enh_size_mult;
1092ac9da0e0SDiego Santa Cruz 	u32 enh_start_addr;
1093ac9da0e0SDiego Santa Cruz 	u32 gp_size_mult[4];
1094ac9da0e0SDiego Santa Cruz 	u32 max_enh_size_mult;
1095ac9da0e0SDiego Santa Cruz 	u32 tot_enh_size_mult = 0;
10968dda5b0eSDiego Santa Cruz 	u8 wr_rel_set;
1097ac9da0e0SDiego Santa Cruz 	int i, pidx, err;
1098ac9da0e0SDiego Santa Cruz 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
1099ac9da0e0SDiego Santa Cruz 
1100ac9da0e0SDiego Santa Cruz 	if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE)
1101ac9da0e0SDiego Santa Cruz 		return -EINVAL;
1102ac9da0e0SDiego Santa Cruz 
1103ac9da0e0SDiego Santa Cruz 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) {
1104ac9da0e0SDiego Santa Cruz 		printf("eMMC >= 4.4 required for enhanced user data area\n");
1105ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1106ac9da0e0SDiego Santa Cruz 	}
1107ac9da0e0SDiego Santa Cruz 
1108ac9da0e0SDiego Santa Cruz 	if (!(mmc->part_support & PART_SUPPORT)) {
1109ac9da0e0SDiego Santa Cruz 		printf("Card does not support partitioning\n");
1110ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1111ac9da0e0SDiego Santa Cruz 	}
1112ac9da0e0SDiego Santa Cruz 
1113ac9da0e0SDiego Santa Cruz 	if (!mmc->hc_wp_grp_size) {
1114ac9da0e0SDiego Santa Cruz 		printf("Card does not define HC WP group size\n");
1115ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1116ac9da0e0SDiego Santa Cruz 	}
1117ac9da0e0SDiego Santa Cruz 
1118ac9da0e0SDiego Santa Cruz 	/* check partition alignment and total enhanced size */
1119ac9da0e0SDiego Santa Cruz 	if (conf->user.enh_size) {
1120ac9da0e0SDiego Santa Cruz 		if (conf->user.enh_size % mmc->hc_wp_grp_size ||
1121ac9da0e0SDiego Santa Cruz 		    conf->user.enh_start % mmc->hc_wp_grp_size) {
1122ac9da0e0SDiego Santa Cruz 			printf("User data enhanced area not HC WP group "
1123ac9da0e0SDiego Santa Cruz 			       "size aligned\n");
1124ac9da0e0SDiego Santa Cruz 			return -EINVAL;
1125ac9da0e0SDiego Santa Cruz 		}
1126ac9da0e0SDiego Santa Cruz 		part_attrs |= EXT_CSD_ENH_USR;
1127ac9da0e0SDiego Santa Cruz 		enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size;
1128ac9da0e0SDiego Santa Cruz 		if (mmc->high_capacity) {
1129ac9da0e0SDiego Santa Cruz 			enh_start_addr = conf->user.enh_start;
1130ac9da0e0SDiego Santa Cruz 		} else {
1131ac9da0e0SDiego Santa Cruz 			enh_start_addr = (conf->user.enh_start << 9);
1132ac9da0e0SDiego Santa Cruz 		}
1133ac9da0e0SDiego Santa Cruz 	} else {
1134ac9da0e0SDiego Santa Cruz 		enh_size_mult = 0;
1135ac9da0e0SDiego Santa Cruz 		enh_start_addr = 0;
1136ac9da0e0SDiego Santa Cruz 	}
1137ac9da0e0SDiego Santa Cruz 	tot_enh_size_mult += enh_size_mult;
1138ac9da0e0SDiego Santa Cruz 
1139ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
1140ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) {
1141ac9da0e0SDiego Santa Cruz 			printf("GP%i partition not HC WP group size "
1142ac9da0e0SDiego Santa Cruz 			       "aligned\n", pidx+1);
1143ac9da0e0SDiego Santa Cruz 			return -EINVAL;
1144ac9da0e0SDiego Santa Cruz 		}
1145ac9da0e0SDiego Santa Cruz 		gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size;
1146ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) {
1147ac9da0e0SDiego Santa Cruz 			part_attrs |= EXT_CSD_ENH_GP(pidx);
1148ac9da0e0SDiego Santa Cruz 			tot_enh_size_mult += gp_size_mult[pidx];
1149ac9da0e0SDiego Santa Cruz 		}
1150ac9da0e0SDiego Santa Cruz 	}
1151ac9da0e0SDiego Santa Cruz 
1152ac9da0e0SDiego Santa Cruz 	if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) {
1153ac9da0e0SDiego Santa Cruz 		printf("Card does not support enhanced attribute\n");
1154ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1155ac9da0e0SDiego Santa Cruz 	}
1156ac9da0e0SDiego Santa Cruz 
1157ac9da0e0SDiego Santa Cruz 	err = mmc_send_ext_csd(mmc, ext_csd);
1158ac9da0e0SDiego Santa Cruz 	if (err)
1159ac9da0e0SDiego Santa Cruz 		return err;
1160ac9da0e0SDiego Santa Cruz 
1161ac9da0e0SDiego Santa Cruz 	max_enh_size_mult =
1162ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) +
1163ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) +
1164ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT];
1165ac9da0e0SDiego Santa Cruz 	if (tot_enh_size_mult > max_enh_size_mult) {
1166ac9da0e0SDiego Santa Cruz 		printf("Total enhanced size exceeds maximum (%u > %u)\n",
1167ac9da0e0SDiego Santa Cruz 		       tot_enh_size_mult, max_enh_size_mult);
1168ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1169ac9da0e0SDiego Santa Cruz 	}
1170ac9da0e0SDiego Santa Cruz 
11718dda5b0eSDiego Santa Cruz 	/* The default value of EXT_CSD_WR_REL_SET is device
11728dda5b0eSDiego Santa Cruz 	 * dependent, the values can only be changed if the
11738dda5b0eSDiego Santa Cruz 	 * EXT_CSD_HS_CTRL_REL bit is set. The values can be
11748dda5b0eSDiego Santa Cruz 	 * changed only once and before partitioning is completed. */
11758dda5b0eSDiego Santa Cruz 	wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
11768dda5b0eSDiego Santa Cruz 	if (conf->user.wr_rel_change) {
11778dda5b0eSDiego Santa Cruz 		if (conf->user.wr_rel_set)
11788dda5b0eSDiego Santa Cruz 			wr_rel_set |= EXT_CSD_WR_DATA_REL_USR;
11798dda5b0eSDiego Santa Cruz 		else
11808dda5b0eSDiego Santa Cruz 			wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR;
11818dda5b0eSDiego Santa Cruz 	}
11828dda5b0eSDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
11838dda5b0eSDiego Santa Cruz 		if (conf->gp_part[pidx].wr_rel_change) {
11848dda5b0eSDiego Santa Cruz 			if (conf->gp_part[pidx].wr_rel_set)
11858dda5b0eSDiego Santa Cruz 				wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx);
11868dda5b0eSDiego Santa Cruz 			else
11878dda5b0eSDiego Santa Cruz 				wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx);
11888dda5b0eSDiego Santa Cruz 		}
11898dda5b0eSDiego Santa Cruz 	}
11908dda5b0eSDiego Santa Cruz 
11918dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] &&
11928dda5b0eSDiego Santa Cruz 	    !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) {
11938dda5b0eSDiego Santa Cruz 		puts("Card does not support host controlled partition write "
11948dda5b0eSDiego Santa Cruz 		     "reliability settings\n");
11958dda5b0eSDiego Santa Cruz 		return -EMEDIUMTYPE;
11968dda5b0eSDiego Santa Cruz 	}
11978dda5b0eSDiego Santa Cruz 
1198ac9da0e0SDiego Santa Cruz 	if (ext_csd[EXT_CSD_PARTITION_SETTING] &
1199ac9da0e0SDiego Santa Cruz 	    EXT_CSD_PARTITION_SETTING_COMPLETED) {
1200ac9da0e0SDiego Santa Cruz 		printf("Card already partitioned\n");
1201ac9da0e0SDiego Santa Cruz 		return -EPERM;
1202ac9da0e0SDiego Santa Cruz 	}
1203ac9da0e0SDiego Santa Cruz 
1204ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_CHECK)
1205ac9da0e0SDiego Santa Cruz 		return 0;
1206ac9da0e0SDiego Santa Cruz 
1207ac9da0e0SDiego Santa Cruz 	/* Partitioning requires high-capacity size definitions */
1208ac9da0e0SDiego Santa Cruz 	if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) {
1209ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1210ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ERASE_GROUP_DEF, 1);
1211ac9da0e0SDiego Santa Cruz 
1212ac9da0e0SDiego Santa Cruz 		if (err)
1213ac9da0e0SDiego Santa Cruz 			return err;
1214ac9da0e0SDiego Santa Cruz 
1215ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1216ac9da0e0SDiego Santa Cruz 
1217ac9da0e0SDiego Santa Cruz 		/* update erase group size to be high-capacity */
1218ac9da0e0SDiego Santa Cruz 		mmc->erase_grp_size =
1219ac9da0e0SDiego Santa Cruz 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1220ac9da0e0SDiego Santa Cruz 
1221ac9da0e0SDiego Santa Cruz 	}
1222ac9da0e0SDiego Santa Cruz 
1223ac9da0e0SDiego Santa Cruz 	/* all OK, write the configuration */
1224ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 4; i++) {
1225ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1226ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_START_ADDR+i,
1227ac9da0e0SDiego Santa Cruz 				 (enh_start_addr >> (i*8)) & 0xFF);
1228ac9da0e0SDiego Santa Cruz 		if (err)
1229ac9da0e0SDiego Santa Cruz 			return err;
1230ac9da0e0SDiego Santa Cruz 	}
1231ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 3; i++) {
1232ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1233ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_SIZE_MULT+i,
1234ac9da0e0SDiego Santa Cruz 				 (enh_size_mult >> (i*8)) & 0xFF);
1235ac9da0e0SDiego Santa Cruz 		if (err)
1236ac9da0e0SDiego Santa Cruz 			return err;
1237ac9da0e0SDiego Santa Cruz 	}
1238ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
1239ac9da0e0SDiego Santa Cruz 		for (i = 0; i < 3; i++) {
1240ac9da0e0SDiego Santa Cruz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1241ac9da0e0SDiego Santa Cruz 					 EXT_CSD_GP_SIZE_MULT+pidx*3+i,
1242ac9da0e0SDiego Santa Cruz 					 (gp_size_mult[pidx] >> (i*8)) & 0xFF);
1243ac9da0e0SDiego Santa Cruz 			if (err)
1244ac9da0e0SDiego Santa Cruz 				return err;
1245ac9da0e0SDiego Santa Cruz 		}
1246ac9da0e0SDiego Santa Cruz 	}
1247ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1248ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs);
1249ac9da0e0SDiego Santa Cruz 	if (err)
1250ac9da0e0SDiego Santa Cruz 		return err;
1251ac9da0e0SDiego Santa Cruz 
1252ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_SET)
1253ac9da0e0SDiego Santa Cruz 		return 0;
1254ac9da0e0SDiego Santa Cruz 
12558dda5b0eSDiego Santa Cruz 	/* The WR_REL_SET is a write-once register but shall be
12568dda5b0eSDiego Santa Cruz 	 * written before setting PART_SETTING_COMPLETED. As it is
12578dda5b0eSDiego Santa Cruz 	 * write-once we can only write it when completing the
12588dda5b0eSDiego Santa Cruz 	 * partitioning. */
12598dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) {
12608dda5b0eSDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
12618dda5b0eSDiego Santa Cruz 				 EXT_CSD_WR_REL_SET, wr_rel_set);
12628dda5b0eSDiego Santa Cruz 		if (err)
12638dda5b0eSDiego Santa Cruz 			return err;
12648dda5b0eSDiego Santa Cruz 	}
12658dda5b0eSDiego Santa Cruz 
1266ac9da0e0SDiego Santa Cruz 	/* Setting PART_SETTING_COMPLETED confirms the partition
1267ac9da0e0SDiego Santa Cruz 	 * configuration but it only becomes effective after power
1268ac9da0e0SDiego Santa Cruz 	 * cycle, so we do not adjust the partition related settings
1269ac9da0e0SDiego Santa Cruz 	 * in the mmc struct. */
1270ac9da0e0SDiego Santa Cruz 
1271ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1272ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING,
1273ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING_COMPLETED);
1274ac9da0e0SDiego Santa Cruz 	if (err)
1275ac9da0e0SDiego Santa Cruz 		return err;
1276ac9da0e0SDiego Santa Cruz 
1277ac9da0e0SDiego Santa Cruz 	return 0;
1278ac9da0e0SDiego Santa Cruz }
1279ac9da0e0SDiego Santa Cruz 
1280e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
128148972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
128248972d90SThierry Reding {
128348972d90SThierry Reding 	int cd;
128448972d90SThierry Reding 
128548972d90SThierry Reding 	cd = board_mmc_getcd(mmc);
128648972d90SThierry Reding 
1287d4e1da4eSPeter Korsgaard 	if (cd < 0) {
128893bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getcd)
128993bfd616SPantelis Antoniou 			cd = mmc->cfg->ops->getcd(mmc);
1290d4e1da4eSPeter Korsgaard 		else
1291d4e1da4eSPeter Korsgaard 			cd = 1;
1292d4e1da4eSPeter Korsgaard 	}
129348972d90SThierry Reding 
129448972d90SThierry Reding 	return cd;
129548972d90SThierry Reding }
12968ca51e51SSimon Glass #endif
129748972d90SThierry Reding 
1298fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
1299272cc70bSAndy Fleming {
1300272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1301272cc70bSAndy Fleming 	struct mmc_data data;
1302272cc70bSAndy Fleming 
1303272cc70bSAndy Fleming 	/* Switch the frequency */
1304272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
1305272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1306272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
1307272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
1308272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
1309272cc70bSAndy Fleming 
1310272cc70bSAndy Fleming 	data.dest = (char *)resp;
1311272cc70bSAndy Fleming 	data.blocksize = 64;
1312272cc70bSAndy Fleming 	data.blocks = 1;
1313272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
1314272cc70bSAndy Fleming 
1315272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
1316272cc70bSAndy Fleming }
1317272cc70bSAndy Fleming 
1318272cc70bSAndy Fleming 
1319fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc)
1320272cc70bSAndy Fleming {
1321272cc70bSAndy Fleming 	int err;
1322272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1323f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2);
1324f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
1325272cc70bSAndy Fleming 	struct mmc_data data;
1326272cc70bSAndy Fleming 	int timeout;
1327272cc70bSAndy Fleming 
1328272cc70bSAndy Fleming 	mmc->card_caps = 0;
1329272cc70bSAndy Fleming 
1330d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
1331d52ebf10SThomas Chou 		return 0;
1332d52ebf10SThomas Chou 
1333272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
1334272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
1335272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1336272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1337272cc70bSAndy Fleming 
1338272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1339272cc70bSAndy Fleming 
1340272cc70bSAndy Fleming 	if (err)
1341272cc70bSAndy Fleming 		return err;
1342272cc70bSAndy Fleming 
1343272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
1344272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1345272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1346272cc70bSAndy Fleming 
1347272cc70bSAndy Fleming 	timeout = 3;
1348272cc70bSAndy Fleming 
1349272cc70bSAndy Fleming retry_scr:
1350f781dd38SAnton staaf 	data.dest = (char *)scr;
1351272cc70bSAndy Fleming 	data.blocksize = 8;
1352272cc70bSAndy Fleming 	data.blocks = 1;
1353272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
1354272cc70bSAndy Fleming 
1355272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
1356272cc70bSAndy Fleming 
1357272cc70bSAndy Fleming 	if (err) {
1358272cc70bSAndy Fleming 		if (timeout--)
1359272cc70bSAndy Fleming 			goto retry_scr;
1360272cc70bSAndy Fleming 
1361272cc70bSAndy Fleming 		return err;
1362272cc70bSAndy Fleming 	}
1363272cc70bSAndy Fleming 
13644e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
13654e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
1366272cc70bSAndy Fleming 
1367272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
1368272cc70bSAndy Fleming 	case 0:
1369272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1370272cc70bSAndy Fleming 		break;
1371272cc70bSAndy Fleming 	case 1:
1372272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_10;
1373272cc70bSAndy Fleming 		break;
1374272cc70bSAndy Fleming 	case 2:
1375272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
13761741c64dSJaehoon Chung 		if ((mmc->scr[0] >> 15) & 0x1)
13771741c64dSJaehoon Chung 			mmc->version = SD_VERSION_3;
1378272cc70bSAndy Fleming 		break;
1379272cc70bSAndy Fleming 	default:
1380272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1381272cc70bSAndy Fleming 		break;
1382272cc70bSAndy Fleming 	}
1383272cc70bSAndy Fleming 
1384b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
1385b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
1386b44c7083SAlagu Sankar 
1387272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
1388272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
1389272cc70bSAndy Fleming 		return 0;
1390272cc70bSAndy Fleming 
1391272cc70bSAndy Fleming 	timeout = 4;
1392272cc70bSAndy Fleming 	while (timeout--) {
1393272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
1394f781dd38SAnton staaf 				(u8 *)switch_status);
1395272cc70bSAndy Fleming 
1396272cc70bSAndy Fleming 		if (err)
1397272cc70bSAndy Fleming 			return err;
1398272cc70bSAndy Fleming 
1399272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
14004e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
1401272cc70bSAndy Fleming 			break;
1402272cc70bSAndy Fleming 	}
1403272cc70bSAndy Fleming 
1404272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
14054e3d89baSYauhen Kharuzhy 	if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED))
1406272cc70bSAndy Fleming 		return 0;
1407272cc70bSAndy Fleming 
14082c3fbf4cSMacpaul Lin 	/*
14092c3fbf4cSMacpaul Lin 	 * If the host doesn't support SD_HIGHSPEED, do not switch card to
14102c3fbf4cSMacpaul Lin 	 * HIGHSPEED mode even if the card support SD_HIGHSPPED.
14112c3fbf4cSMacpaul Lin 	 * This can avoid furthur problem when the card runs in different
14122c3fbf4cSMacpaul Lin 	 * mode between the host.
14132c3fbf4cSMacpaul Lin 	 */
141493bfd616SPantelis Antoniou 	if (!((mmc->cfg->host_caps & MMC_MODE_HS_52MHz) &&
141593bfd616SPantelis Antoniou 		(mmc->cfg->host_caps & MMC_MODE_HS)))
14162c3fbf4cSMacpaul Lin 		return 0;
14172c3fbf4cSMacpaul Lin 
1418f781dd38SAnton staaf 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status);
1419272cc70bSAndy Fleming 
1420272cc70bSAndy Fleming 	if (err)
1421272cc70bSAndy Fleming 		return err;
1422272cc70bSAndy Fleming 
14234e3d89baSYauhen Kharuzhy 	if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000)
1424272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
1425272cc70bSAndy Fleming 
1426272cc70bSAndy Fleming 	return 0;
1427272cc70bSAndy Fleming }
1428272cc70bSAndy Fleming 
14293697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc)
14303697e599SPeng Fan {
14313697e599SPeng Fan 	int err, i;
14323697e599SPeng Fan 	struct mmc_cmd cmd;
14333697e599SPeng Fan 	ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16);
14343697e599SPeng Fan 	struct mmc_data data;
14353697e599SPeng Fan 	int timeout = 3;
14363697e599SPeng Fan 	unsigned int au, eo, et, es;
14373697e599SPeng Fan 
14383697e599SPeng Fan 	cmd.cmdidx = MMC_CMD_APP_CMD;
14393697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
14403697e599SPeng Fan 	cmd.cmdarg = mmc->rca << 16;
14413697e599SPeng Fan 
14423697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, NULL);
14433697e599SPeng Fan 	if (err)
14443697e599SPeng Fan 		return err;
14453697e599SPeng Fan 
14463697e599SPeng Fan 	cmd.cmdidx = SD_CMD_APP_SD_STATUS;
14473697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
14483697e599SPeng Fan 	cmd.cmdarg = 0;
14493697e599SPeng Fan 
14503697e599SPeng Fan retry_ssr:
14513697e599SPeng Fan 	data.dest = (char *)ssr;
14523697e599SPeng Fan 	data.blocksize = 64;
14533697e599SPeng Fan 	data.blocks = 1;
14543697e599SPeng Fan 	data.flags = MMC_DATA_READ;
14553697e599SPeng Fan 
14563697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, &data);
14573697e599SPeng Fan 	if (err) {
14583697e599SPeng Fan 		if (timeout--)
14593697e599SPeng Fan 			goto retry_ssr;
14603697e599SPeng Fan 
14613697e599SPeng Fan 		return err;
14623697e599SPeng Fan 	}
14633697e599SPeng Fan 
14643697e599SPeng Fan 	for (i = 0; i < 16; i++)
14653697e599SPeng Fan 		ssr[i] = be32_to_cpu(ssr[i]);
14663697e599SPeng Fan 
14673697e599SPeng Fan 	au = (ssr[2] >> 12) & 0xF;
14683697e599SPeng Fan 	if ((au <= 9) || (mmc->version == SD_VERSION_3)) {
14693697e599SPeng Fan 		mmc->ssr.au = sd_au_size[au];
14703697e599SPeng Fan 		es = (ssr[3] >> 24) & 0xFF;
14713697e599SPeng Fan 		es |= (ssr[2] & 0xFF) << 8;
14723697e599SPeng Fan 		et = (ssr[3] >> 18) & 0x3F;
14733697e599SPeng Fan 		if (es && et) {
14743697e599SPeng Fan 			eo = (ssr[3] >> 16) & 0x3;
14753697e599SPeng Fan 			mmc->ssr.erase_timeout = (et * 1000) / es;
14763697e599SPeng Fan 			mmc->ssr.erase_offset = eo * 1000;
14773697e599SPeng Fan 		}
14783697e599SPeng Fan 	} else {
14793697e599SPeng Fan 		debug("Invalid Allocation Unit Size.\n");
14803697e599SPeng Fan 	}
14813697e599SPeng Fan 
14823697e599SPeng Fan 	return 0;
14833697e599SPeng Fan }
14843697e599SPeng Fan 
1485272cc70bSAndy Fleming /* frequency bases */
1486272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
14875f837c2cSMike Frysinger static const int fbase[] = {
1488272cc70bSAndy Fleming 	10000,
1489272cc70bSAndy Fleming 	100000,
1490272cc70bSAndy Fleming 	1000000,
1491272cc70bSAndy Fleming 	10000000,
1492272cc70bSAndy Fleming };
1493272cc70bSAndy Fleming 
1494272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
1495272cc70bSAndy Fleming  * to platforms without floating point.
1496272cc70bSAndy Fleming  */
149761fe076fSSimon Glass static const u8 multipliers[] = {
1498272cc70bSAndy Fleming 	0,	/* reserved */
1499272cc70bSAndy Fleming 	10,
1500272cc70bSAndy Fleming 	12,
1501272cc70bSAndy Fleming 	13,
1502272cc70bSAndy Fleming 	15,
1503272cc70bSAndy Fleming 	20,
1504272cc70bSAndy Fleming 	25,
1505272cc70bSAndy Fleming 	30,
1506272cc70bSAndy Fleming 	35,
1507272cc70bSAndy Fleming 	40,
1508272cc70bSAndy Fleming 	45,
1509272cc70bSAndy Fleming 	50,
1510272cc70bSAndy Fleming 	55,
1511272cc70bSAndy Fleming 	60,
1512272cc70bSAndy Fleming 	70,
1513272cc70bSAndy Fleming 	80,
1514272cc70bSAndy Fleming };
1515272cc70bSAndy Fleming 
1516e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
1517fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc)
1518272cc70bSAndy Fleming {
151993bfd616SPantelis Antoniou 	if (mmc->cfg->ops->set_ios)
152093bfd616SPantelis Antoniou 		mmc->cfg->ops->set_ios(mmc);
1521272cc70bSAndy Fleming }
1522ad77484aSZiyuan Xu 
1523ad77484aSZiyuan Xu static bool mmc_card_busy(struct mmc *mmc)
1524ad77484aSZiyuan Xu {
1525ad77484aSZiyuan Xu 	if (!mmc->cfg->ops->card_busy)
1526ad77484aSZiyuan Xu 		return -ENOSYS;
1527ad77484aSZiyuan Xu 
1528ad77484aSZiyuan Xu 	return mmc->cfg->ops->card_busy(mmc);
1529ad77484aSZiyuan Xu }
1530ad77484aSZiyuan Xu 
1531ad77484aSZiyuan Xu static bool mmc_can_card_busy(struct mmc *)
1532ad77484aSZiyuan Xu {
1533ad77484aSZiyuan Xu 	return !!mmc->cfg->ops->card_busy;
1534ad77484aSZiyuan Xu }
15358ca51e51SSimon Glass #endif
1536272cc70bSAndy Fleming 
1537fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc)
1538272cc70bSAndy Fleming {
1539f866a46dSStephen Warren 	int err, i;
15403e3ff0acSZiyuan Xu 	uint mult, freq, tran_speed;
1541639b7827SYoshihiro Shimoda 	u64 cmult, csize, capacity;
1542272cc70bSAndy Fleming 	struct mmc_cmd cmd;
15438bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
15440c453bb7SDiego Santa Cruz 	bool has_parts = false;
15458a0cf490SDiego Santa Cruz 	bool part_completed;
1546c40fdca6SSimon Glass 	struct blk_desc *bdesc;
1547272cc70bSAndy Fleming 
1548d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
1549d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
1550d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
1551d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
1552d52ebf10SThomas Chou 		cmd.cmdarg = 1;
1553d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
1554d52ebf10SThomas Chou 
1555d52ebf10SThomas Chou 		if (err)
1556d52ebf10SThomas Chou 			return err;
1557d52ebf10SThomas Chou 	}
1558d52ebf10SThomas Chou #endif
1559*479fbf72SJason Zhu #ifndef CONFIG_MMC_USE_PRE_CONFIG
1560272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
1561d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
1562d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
1563272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1564272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1565272cc70bSAndy Fleming 
1566272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1567272cc70bSAndy Fleming 
1568272cc70bSAndy Fleming 	if (err)
1569272cc70bSAndy Fleming 		return err;
1570272cc70bSAndy Fleming 
1571272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
1572272cc70bSAndy Fleming 
1573272cc70bSAndy Fleming 	/*
1574272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
1575272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
1576272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
1577272cc70bSAndy Fleming 	 */
1578d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1579272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
1580272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1581272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
1582272cc70bSAndy Fleming 
1583272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1584272cc70bSAndy Fleming 
1585272cc70bSAndy Fleming 		if (err)
1586272cc70bSAndy Fleming 			return err;
1587272cc70bSAndy Fleming 
1588272cc70bSAndy Fleming 		if (IS_SD(mmc))
1589998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
1590d52ebf10SThomas Chou 	}
1591*479fbf72SJason Zhu #endif
1592272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
1593272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
1594272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1595272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1596272cc70bSAndy Fleming 
1597272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1598272cc70bSAndy Fleming 
1599272cc70bSAndy Fleming 	if (err)
1600272cc70bSAndy Fleming 		return err;
1601272cc70bSAndy Fleming 
1602998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
1603998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
1604998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
1605998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
1606272cc70bSAndy Fleming 
1607272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
16080b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
1609272cc70bSAndy Fleming 
1610272cc70bSAndy Fleming 		switch (version) {
1611272cc70bSAndy Fleming 		case 0:
1612272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1613272cc70bSAndy Fleming 			break;
1614272cc70bSAndy Fleming 		case 1:
1615272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_4;
1616272cc70bSAndy Fleming 			break;
1617272cc70bSAndy Fleming 		case 2:
1618272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_2_2;
1619272cc70bSAndy Fleming 			break;
1620272cc70bSAndy Fleming 		case 3:
1621272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_3;
1622272cc70bSAndy Fleming 			break;
1623272cc70bSAndy Fleming 		case 4:
1624272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_4;
1625272cc70bSAndy Fleming 			break;
1626272cc70bSAndy Fleming 		default:
1627272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1628272cc70bSAndy Fleming 			break;
1629272cc70bSAndy Fleming 		}
1630272cc70bSAndy Fleming 	}
1631272cc70bSAndy Fleming 
1632272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
16330b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
16340b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
1635272cc70bSAndy Fleming 
16363e3ff0acSZiyuan Xu 	tran_speed = freq * mult;
1637272cc70bSAndy Fleming 
1638ab71188cSMarkus Niebel 	mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
1639998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
1640272cc70bSAndy Fleming 
1641272cc70bSAndy Fleming 	if (IS_SD(mmc))
1642272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
1643272cc70bSAndy Fleming 	else
1644998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
1645272cc70bSAndy Fleming 
1646272cc70bSAndy Fleming 	if (mmc->high_capacity) {
1647272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
1648272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
1649272cc70bSAndy Fleming 		cmult = 8;
1650272cc70bSAndy Fleming 	} else {
1651272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
1652272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
1653272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
1654272cc70bSAndy Fleming 	}
1655272cc70bSAndy Fleming 
1656f866a46dSStephen Warren 	mmc->capacity_user = (csize + 1) << (cmult + 2);
1657f866a46dSStephen Warren 	mmc->capacity_user *= mmc->read_bl_len;
1658f866a46dSStephen Warren 	mmc->capacity_boot = 0;
1659f866a46dSStephen Warren 	mmc->capacity_rpmb = 0;
1660f866a46dSStephen Warren 	for (i = 0; i < 4; i++)
1661f866a46dSStephen Warren 		mmc->capacity_gp[i] = 0;
1662272cc70bSAndy Fleming 
16638bfa195eSSimon Glass 	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
16648bfa195eSSimon Glass 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
1665272cc70bSAndy Fleming 
16668bfa195eSSimon Glass 	if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
16678bfa195eSSimon Glass 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
1668272cc70bSAndy Fleming 
1669ab71188cSMarkus Niebel 	if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
1670ab71188cSMarkus Niebel 		cmd.cmdidx = MMC_CMD_SET_DSR;
1671ab71188cSMarkus Niebel 		cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
1672ab71188cSMarkus Niebel 		cmd.resp_type = MMC_RSP_NONE;
1673ab71188cSMarkus Niebel 		if (mmc_send_cmd(mmc, &cmd, NULL))
1674ab71188cSMarkus Niebel 			printf("MMC: SET_DSR failed\n");
1675ab71188cSMarkus Niebel 	}
1676ab71188cSMarkus Niebel 
1677272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
1678d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1679272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
1680fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
1681272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1682272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1683272cc70bSAndy Fleming 
1684272cc70bSAndy Fleming 		if (err)
1685272cc70bSAndy Fleming 			return err;
1686d52ebf10SThomas Chou 	}
1687272cc70bSAndy Fleming 
1688e6f99a56SLei Wen 	/*
1689e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
1690e6f99a56SLei Wen 	 */
1691e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
1692bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
1693d23e2c09SSukumar Ghorai 	if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
1694d23e2c09SSukumar Ghorai 		/* check  ext_csd version and capacity */
1695d23e2c09SSukumar Ghorai 		err = mmc_send_ext_csd(mmc, ext_csd);
16969cf199ebSDiego Santa Cruz 		if (err)
16979cf199ebSDiego Santa Cruz 			return err;
16989cf199ebSDiego Santa Cruz 		if (ext_csd[EXT_CSD_REV] >= 2) {
1699639b7827SYoshihiro Shimoda 			/*
1700639b7827SYoshihiro Shimoda 			 * According to the JEDEC Standard, the value of
1701639b7827SYoshihiro Shimoda 			 * ext_csd's capacity is valid if the value is more
1702639b7827SYoshihiro Shimoda 			 * than 2GB
1703639b7827SYoshihiro Shimoda 			 */
17040560db18SLei Wen 			capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
17050560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
17060560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
17070560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
17088bfa195eSSimon Glass 			capacity *= MMC_MAX_BLOCK_LEN;
1709b1f1e821SŁukasz Majewski 			if ((capacity >> 20) > 2 * 1024)
1710f866a46dSStephen Warren 				mmc->capacity_user = capacity;
1711d23e2c09SSukumar Ghorai 		}
1712bc897b1dSLei Wen 
171364f4a619SJaehoon Chung 		switch (ext_csd[EXT_CSD_REV]) {
171464f4a619SJaehoon Chung 		case 1:
171564f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_1;
171664f4a619SJaehoon Chung 			break;
171764f4a619SJaehoon Chung 		case 2:
171864f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_2;
171964f4a619SJaehoon Chung 			break;
172064f4a619SJaehoon Chung 		case 3:
172164f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_3;
172264f4a619SJaehoon Chung 			break;
172364f4a619SJaehoon Chung 		case 5:
172464f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_41;
172564f4a619SJaehoon Chung 			break;
172664f4a619SJaehoon Chung 		case 6:
172764f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_5;
172864f4a619SJaehoon Chung 			break;
1729edab723bSMarkus Niebel 		case 7:
1730edab723bSMarkus Niebel 			mmc->version = MMC_VERSION_5_0;
1731edab723bSMarkus Niebel 			break;
17321a3619cfSStefan Wahren 		case 8:
17331a3619cfSStefan Wahren 			mmc->version = MMC_VERSION_5_1;
17341a3619cfSStefan Wahren 			break;
173564f4a619SJaehoon Chung 		}
173664f4a619SJaehoon Chung 
17378a0cf490SDiego Santa Cruz 		/* The partition data may be non-zero but it is only
17388a0cf490SDiego Santa Cruz 		 * effective if PARTITION_SETTING_COMPLETED is set in
17398a0cf490SDiego Santa Cruz 		 * EXT_CSD, so ignore any data if this bit is not set,
17408a0cf490SDiego Santa Cruz 		 * except for enabling the high-capacity group size
17418a0cf490SDiego Santa Cruz 		 * definition (see below). */
17428a0cf490SDiego Santa Cruz 		part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
17438a0cf490SDiego Santa Cruz 				    EXT_CSD_PARTITION_SETTING_COMPLETED);
17448a0cf490SDiego Santa Cruz 
17450c453bb7SDiego Santa Cruz 		/* store the partition info of emmc */
17460c453bb7SDiego Santa Cruz 		mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
17470c453bb7SDiego Santa Cruz 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
17480c453bb7SDiego Santa Cruz 		    ext_csd[EXT_CSD_BOOT_MULT])
17490c453bb7SDiego Santa Cruz 			mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
17508a0cf490SDiego Santa Cruz 		if (part_completed &&
17518a0cf490SDiego Santa Cruz 		    (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
17520c453bb7SDiego Santa Cruz 			mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
1753a6a1f5f8SJason Zhu 		if (ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] & EXT_CSD_SEC_GB_CL_EN)
1754a6a1f5f8SJason Zhu 			mmc->esr.mmc_can_trim = 1;
17550c453bb7SDiego Santa Cruz 
17560c453bb7SDiego Santa Cruz 		mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
17570c453bb7SDiego Santa Cruz 
17580c453bb7SDiego Santa Cruz 		mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
17590c453bb7SDiego Santa Cruz 
17600c453bb7SDiego Santa Cruz 		for (i = 0; i < 4; i++) {
17610c453bb7SDiego Santa Cruz 			int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
17628a0cf490SDiego Santa Cruz 			uint mult = (ext_csd[idx + 2] << 16) +
17630c453bb7SDiego Santa Cruz 				(ext_csd[idx + 1] << 8) + ext_csd[idx];
17648a0cf490SDiego Santa Cruz 			if (mult)
17658a0cf490SDiego Santa Cruz 				has_parts = true;
17668a0cf490SDiego Santa Cruz 			if (!part_completed)
17678a0cf490SDiego Santa Cruz 				continue;
17688a0cf490SDiego Santa Cruz 			mmc->capacity_gp[i] = mult;
17690c453bb7SDiego Santa Cruz 			mmc->capacity_gp[i] *=
17700c453bb7SDiego Santa Cruz 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
17710c453bb7SDiego Santa Cruz 			mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1772f8e89d67SDiego Santa Cruz 			mmc->capacity_gp[i] <<= 19;
17730c453bb7SDiego Santa Cruz 		}
17740c453bb7SDiego Santa Cruz 
17758a0cf490SDiego Santa Cruz 		if (part_completed) {
1776a7f852b6SDiego Santa Cruz 			mmc->enh_user_size =
1777a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_SIZE_MULT+2] << 16) +
1778a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_SIZE_MULT+1] << 8) +
1779a7f852b6SDiego Santa Cruz 				ext_csd[EXT_CSD_ENH_SIZE_MULT];
1780a7f852b6SDiego Santa Cruz 			mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1781a7f852b6SDiego Santa Cruz 			mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1782a7f852b6SDiego Santa Cruz 			mmc->enh_user_size <<= 19;
1783a7f852b6SDiego Santa Cruz 			mmc->enh_user_start =
1784a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+3] << 24) +
1785a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+2] << 16) +
1786a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+1] << 8) +
1787a7f852b6SDiego Santa Cruz 				ext_csd[EXT_CSD_ENH_START_ADDR];
1788a7f852b6SDiego Santa Cruz 			if (mmc->high_capacity)
1789a7f852b6SDiego Santa Cruz 				mmc->enh_user_start <<= 9;
17908a0cf490SDiego Santa Cruz 		}
1791a7f852b6SDiego Santa Cruz 
1792e6f99a56SLei Wen 		/*
17931937e5aaSOliver Metz 		 * Host needs to enable ERASE_GRP_DEF bit if device is
17941937e5aaSOliver Metz 		 * partitioned. This bit will be lost every time after a reset
17951937e5aaSOliver Metz 		 * or power off. This will affect erase size.
1796e6f99a56SLei Wen 		 */
17978a0cf490SDiego Santa Cruz 		if (part_completed)
17980c453bb7SDiego Santa Cruz 			has_parts = true;
17991937e5aaSOliver Metz 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
18000c453bb7SDiego Santa Cruz 		    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
18010c453bb7SDiego Santa Cruz 			has_parts = true;
18020c453bb7SDiego Santa Cruz 		if (has_parts) {
18031937e5aaSOliver Metz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
18041937e5aaSOliver Metz 				EXT_CSD_ERASE_GROUP_DEF, 1);
18051937e5aaSOliver Metz 
18061937e5aaSOliver Metz 			if (err)
18071937e5aaSOliver Metz 				return err;
1808021a8055SHannes Petermaier 			else
1809021a8055SHannes Petermaier 				ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1810037dc0abSDiego Santa Cruz 		}
18111937e5aaSOliver Metz 
1812037dc0abSDiego Santa Cruz 		if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
18131937e5aaSOliver Metz 			/* Read out group size from ext_csd */
18140560db18SLei Wen 			mmc->erase_grp_size =
1815a4ff9f83SDiego Santa Cruz 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1816d7b29129SMarkus Niebel 			/*
1817d7b29129SMarkus Niebel 			 * if high capacity and partition setting completed
1818d7b29129SMarkus Niebel 			 * SEC_COUNT is valid even if it is smaller than 2 GiB
1819d7b29129SMarkus Niebel 			 * JEDEC Standard JESD84-B45, 6.2.4
1820d7b29129SMarkus Niebel 			 */
18218a0cf490SDiego Santa Cruz 			if (mmc->high_capacity && part_completed) {
1822d7b29129SMarkus Niebel 				capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
1823d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
1824d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
1825d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
1826d7b29129SMarkus Niebel 				capacity *= MMC_MAX_BLOCK_LEN;
1827d7b29129SMarkus Niebel 				mmc->capacity_user = capacity;
1828d7b29129SMarkus Niebel 			}
18298bfa195eSSimon Glass 		} else {
18301937e5aaSOliver Metz 			/* Calculate the group size from the csd value. */
1831e6f99a56SLei Wen 			int erase_gsz, erase_gmul;
1832e6f99a56SLei Wen 			erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
1833e6f99a56SLei Wen 			erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
1834e6f99a56SLei Wen 			mmc->erase_grp_size = (erase_gsz + 1)
1835e6f99a56SLei Wen 				* (erase_gmul + 1);
1836e6f99a56SLei Wen 		}
1837037dc0abSDiego Santa Cruz 
1838037dc0abSDiego Santa Cruz 		mmc->hc_wp_grp_size = 1024
1839037dc0abSDiego Santa Cruz 			* ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
1840037dc0abSDiego Santa Cruz 			* ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
18419e41a00bSDiego Santa Cruz 
18429e41a00bSDiego Santa Cruz 		mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
1843f866a46dSStephen Warren 	}
1844f866a46dSStephen Warren 
1845c40fdca6SSimon Glass 	err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart);
1846f866a46dSStephen Warren 	if (err)
1847f866a46dSStephen Warren 		return err;
1848d23e2c09SSukumar Ghorai 
1849272cc70bSAndy Fleming 	if (IS_SD(mmc))
1850272cc70bSAndy Fleming 		err = sd_change_freq(mmc);
1851272cc70bSAndy Fleming 	else
1852272cc70bSAndy Fleming 		err = mmc_change_freq(mmc);
1853272cc70bSAndy Fleming 
1854272cc70bSAndy Fleming 	if (err)
1855272cc70bSAndy Fleming 		return err;
1856272cc70bSAndy Fleming 
1857272cc70bSAndy Fleming 	/* Restrict card's capabilities by what the host can do */
185893bfd616SPantelis Antoniou 	mmc->card_caps &= mmc->cfg->host_caps;
1859272cc70bSAndy Fleming 
1860272cc70bSAndy Fleming 	if (IS_SD(mmc)) {
1861272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_4BIT) {
1862272cc70bSAndy Fleming 			cmd.cmdidx = MMC_CMD_APP_CMD;
1863272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1864272cc70bSAndy Fleming 			cmd.cmdarg = mmc->rca << 16;
1865272cc70bSAndy Fleming 
1866272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1867272cc70bSAndy Fleming 			if (err)
1868272cc70bSAndy Fleming 				return err;
1869272cc70bSAndy Fleming 
1870272cc70bSAndy Fleming 			cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
1871272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1872272cc70bSAndy Fleming 			cmd.cmdarg = 2;
1873272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1874272cc70bSAndy Fleming 			if (err)
1875272cc70bSAndy Fleming 				return err;
1876272cc70bSAndy Fleming 
1877272cc70bSAndy Fleming 			mmc_set_bus_width(mmc, 4);
1878272cc70bSAndy Fleming 		}
1879272cc70bSAndy Fleming 
18803697e599SPeng Fan 		err = sd_read_ssr(mmc);
18813697e599SPeng Fan 		if (err)
18823697e599SPeng Fan 			return err;
18833697e599SPeng Fan 
1884272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS)
18853e3ff0acSZiyuan Xu 			tran_speed = 50000000;
1886272cc70bSAndy Fleming 		else
18873e3ff0acSZiyuan Xu 			tran_speed = 25000000;
1888ad5fd922SJaehoon Chung 
18893e3ff0acSZiyuan Xu 		mmc_set_clock(mmc, tran_speed);
189049dba033SZiyuan Xu 	}
1891272cc70bSAndy Fleming 
18925af8f45cSAndrew Gabbasov 	/* Fix the block length for DDR mode */
189349dba033SZiyuan Xu 	if (mmc_card_ddr(mmc)) {
18945af8f45cSAndrew Gabbasov 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
18955af8f45cSAndrew Gabbasov 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
18965af8f45cSAndrew Gabbasov 	}
18975af8f45cSAndrew Gabbasov 
1898272cc70bSAndy Fleming 	/* fill in device description */
1899c40fdca6SSimon Glass 	bdesc = mmc_get_blk_desc(mmc);
1900c40fdca6SSimon Glass 	bdesc->lun = 0;
1901c40fdca6SSimon Glass 	bdesc->hwpart = 0;
1902c40fdca6SSimon Glass 	bdesc->type = 0;
1903c40fdca6SSimon Glass 	bdesc->blksz = mmc->read_bl_len;
1904c40fdca6SSimon Glass 	bdesc->log2blksz = LOG2(bdesc->blksz);
1905c40fdca6SSimon Glass 	bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len);
1906fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \
1907fc011f64SSjoerd Simons 		(defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \
1908fc011f64SSjoerd Simons 		!defined(CONFIG_USE_TINY_PRINTF))
1909c40fdca6SSimon Glass 	sprintf(bdesc->vendor, "Man %06x Snr %04x%04x",
1910babce5f6STaylor Hutt 		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
1911babce5f6STaylor Hutt 		(mmc->cid[3] >> 16) & 0xffff);
1912c40fdca6SSimon Glass 	sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
19130b453ffeSRabin Vincent 		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
1914babce5f6STaylor Hutt 		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
1915babce5f6STaylor Hutt 		(mmc->cid[2] >> 24) & 0xff);
1916c40fdca6SSimon Glass 	sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
1917babce5f6STaylor Hutt 		(mmc->cid[2] >> 16) & 0xf);
191856196826SPaul Burton #else
1919c40fdca6SSimon Glass 	bdesc->vendor[0] = 0;
1920c40fdca6SSimon Glass 	bdesc->product[0] = 0;
1921c40fdca6SSimon Glass 	bdesc->revision[0] = 0;
192256196826SPaul Burton #endif
1923122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
1924c40fdca6SSimon Glass 	part_init(bdesc);
1925122efd43SMikhail Kshevetskiy #endif
1926272cc70bSAndy Fleming 
1927272cc70bSAndy Fleming 	return 0;
1928272cc70bSAndy Fleming }
1929272cc70bSAndy Fleming 
1930*479fbf72SJason Zhu #ifndef CONFIG_MMC_USE_PRE_CONFIG
1931fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc)
1932272cc70bSAndy Fleming {
1933272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1934272cc70bSAndy Fleming 	int err;
1935272cc70bSAndy Fleming 
1936272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
1937272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
193893bfd616SPantelis Antoniou 	cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa;
1939272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
1940272cc70bSAndy Fleming 
1941272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1942272cc70bSAndy Fleming 
1943272cc70bSAndy Fleming 	if (err)
1944272cc70bSAndy Fleming 		return err;
1945272cc70bSAndy Fleming 
1946998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
1947915ffa52SJaehoon Chung 		return -EOPNOTSUPP;
1948272cc70bSAndy Fleming 	else
1949272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
1950272cc70bSAndy Fleming 
1951272cc70bSAndy Fleming 	return 0;
1952272cc70bSAndy Fleming }
1953*479fbf72SJason Zhu #endif
1954272cc70bSAndy Fleming 
1955c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
195695de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */
195795de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void)
195895de9ab2SPaul Kocialkowski {
195995de9ab2SPaul Kocialkowski }
196005cbeb7cSSimon Glass #endif
196195de9ab2SPaul Kocialkowski 
1962*479fbf72SJason Zhu #ifndef CONFIG_MMC_USE_PRE_CONFIG
19632051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc)
19642051aefeSPeng Fan {
1965c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
196605cbeb7cSSimon Glass #if defined(CONFIG_DM_REGULATOR) && !defined(CONFIG_SPL_BUILD)
19672051aefeSPeng Fan 	struct udevice *vmmc_supply;
19682051aefeSPeng Fan 	int ret;
19692051aefeSPeng Fan 
19702051aefeSPeng Fan 	ret = device_get_supply_regulator(mmc->dev, "vmmc-supply",
19712051aefeSPeng Fan 					  &vmmc_supply);
19722051aefeSPeng Fan 	if (ret) {
1973288db7c7SJaehoon Chung 		debug("%s: No vmmc supply\n", mmc->dev->name);
19742051aefeSPeng Fan 		return 0;
19752051aefeSPeng Fan 	}
19762051aefeSPeng Fan 
19772051aefeSPeng Fan 	ret = regulator_set_enable(vmmc_supply, true);
19782051aefeSPeng Fan 	if (ret) {
19792051aefeSPeng Fan 		puts("Error enabling VMMC supply\n");
19802051aefeSPeng Fan 		return ret;
19812051aefeSPeng Fan 	}
19822051aefeSPeng Fan #endif
198305cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */
198405cbeb7cSSimon Glass 	/*
198505cbeb7cSSimon Glass 	 * Driver model should use a regulator, as above, rather than calling
198605cbeb7cSSimon Glass 	 * out to board code.
198705cbeb7cSSimon Glass 	 */
198805cbeb7cSSimon Glass 	board_mmc_power_init();
198905cbeb7cSSimon Glass #endif
19902051aefeSPeng Fan 	return 0;
19912051aefeSPeng Fan }
1992*479fbf72SJason Zhu #endif
1993*479fbf72SJason Zhu #ifdef CONFIG_MMC_USE_PRE_CONFIG
1994*479fbf72SJason Zhu static int mmc_select_card(struct mmc *mmc, int n)
1995*479fbf72SJason Zhu {
1996*479fbf72SJason Zhu 	struct mmc_cmd cmd;
1997*479fbf72SJason Zhu 	int err = 0;
19982051aefeSPeng Fan 
1999*479fbf72SJason Zhu 	memset(&cmd, 0, sizeof(struct mmc_cmd));
2000*479fbf72SJason Zhu 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
2001*479fbf72SJason Zhu 		mmc->rca = n;
2002*479fbf72SJason Zhu 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
2003*479fbf72SJason Zhu 		cmd.resp_type = MMC_RSP_R1;
2004*479fbf72SJason Zhu 		cmd.cmdarg = mmc->rca << 16;
2005*479fbf72SJason Zhu 		err = mmc_send_cmd(mmc, &cmd, NULL);
2006*479fbf72SJason Zhu 	}
2007*479fbf72SJason Zhu 
2008*479fbf72SJason Zhu 	return err;
2009*479fbf72SJason Zhu }
2010*479fbf72SJason Zhu 
2011*479fbf72SJason Zhu int mmc_start_init(struct mmc *mmc)
2012*479fbf72SJason Zhu {
2013*479fbf72SJason Zhu 	/*
2014*479fbf72SJason Zhu 	 * We use the MMC config set by the bootrom.
2015*479fbf72SJason Zhu 	 * So it is no need to reset the eMMC device.
2016*479fbf72SJason Zhu 	 */
2017*479fbf72SJason Zhu 	mmc_set_bus_width(mmc, 8);
2018*479fbf72SJason Zhu 	mmc_set_clock(mmc, 1);
2019*479fbf72SJason Zhu 	mmc_set_timing(mmc, MMC_TIMING_LEGACY);
2020*479fbf72SJason Zhu 	/* Send cmd7 to return stand-by state*/
2021*479fbf72SJason Zhu 	mmc_select_card(mmc, 0);
2022*479fbf72SJason Zhu 	mmc->version = MMC_VERSION_UNKNOWN;
2023*479fbf72SJason Zhu 	mmc->high_capacity = 1;
2024*479fbf72SJason Zhu 	/*
2025*479fbf72SJason Zhu 	 * The RCA is set to 2 by rockchip bootrom, use the default
2026*479fbf72SJason Zhu 	 * value here.
2027*479fbf72SJason Zhu 	 */
2028*479fbf72SJason Zhu #ifdef CONFIG_ARCH_ROCKCHIP
2029*479fbf72SJason Zhu 	mmc->rca = 2;
2030*479fbf72SJason Zhu #else
2031*479fbf72SJason Zhu 	mmc->rca = 1;
2032*479fbf72SJason Zhu #endif
2033*479fbf72SJason Zhu 	return 0;
2034*479fbf72SJason Zhu }
2035*479fbf72SJason Zhu #else
2036e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc)
2037272cc70bSAndy Fleming {
20388ca51e51SSimon Glass 	bool no_card;
2039afd5932bSMacpaul Lin 	int err;
2040272cc70bSAndy Fleming 
2041ab769f22SPantelis Antoniou 	/* we pretend there's no card when init is NULL */
20428ca51e51SSimon Glass 	no_card = mmc_getcd(mmc) == 0;
2043e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
20448ca51e51SSimon Glass 	no_card = no_card || (mmc->cfg->ops->init == NULL);
20458ca51e51SSimon Glass #endif
20468ca51e51SSimon Glass 	if (no_card) {
204748972d90SThierry Reding 		mmc->has_init = 0;
204856196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
204948972d90SThierry Reding 		printf("MMC: no card present\n");
205056196826SPaul Burton #endif
2051915ffa52SJaehoon Chung 		return -ENOMEDIUM;
205248972d90SThierry Reding 	}
205348972d90SThierry Reding 
2054bc897b1dSLei Wen 	if (mmc->has_init)
2055bc897b1dSLei Wen 		return 0;
2056bc897b1dSLei Wen 
20575a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
20585a8dbdc6SYangbo Lu 	mmc_adapter_card_type_ident();
20595a8dbdc6SYangbo Lu #endif
20602051aefeSPeng Fan 	err = mmc_power_init(mmc);
20612051aefeSPeng Fan 	if (err)
20622051aefeSPeng Fan 		return err;
206395de9ab2SPaul Kocialkowski 
2064e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
20658ca51e51SSimon Glass 	/* The device has already been probed ready for use */
20668ca51e51SSimon Glass #else
2067ab769f22SPantelis Antoniou 	/* made sure it's not NULL earlier */
206893bfd616SPantelis Antoniou 	err = mmc->cfg->ops->init(mmc);
2069272cc70bSAndy Fleming 	if (err)
2070272cc70bSAndy Fleming 		return err;
20718ca51e51SSimon Glass #endif
2072b86b85e2SIlya Yanok 	mmc_set_bus_width(mmc, 1);
2073b86b85e2SIlya Yanok 	mmc_set_clock(mmc, 1);
207481db2d36SZiyuan Xu 	mmc_set_timing(mmc, MMC_TIMING_LEGACY);
2075b86b85e2SIlya Yanok 
2076272cc70bSAndy Fleming 	/* Reset the Card */
2077272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
2078272cc70bSAndy Fleming 
2079272cc70bSAndy Fleming 	if (err)
2080272cc70bSAndy Fleming 		return err;
2081272cc70bSAndy Fleming 
2082bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
2083c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->hwpart = 0;
2084bc897b1dSLei Wen 
2085272cc70bSAndy Fleming 	/* Test for SD version 2 */
2086272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
2087272cc70bSAndy Fleming 
2088272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
2089272cc70bSAndy Fleming 	err = sd_send_op_cond(mmc);
2090272cc70bSAndy Fleming 
2091272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
2092915ffa52SJaehoon Chung 	if (err == -ETIMEDOUT) {
2093272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
2094272cc70bSAndy Fleming 
2095bd47c135SAndrew Gabbasov 		if (err) {
209656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2097272cc70bSAndy Fleming 			printf("Card did not respond to voltage select!\n");
209856196826SPaul Burton #endif
2099915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
2100272cc70bSAndy Fleming 		}
2101272cc70bSAndy Fleming 	}
2102272cc70bSAndy Fleming 
2103bd47c135SAndrew Gabbasov 	if (!err)
2104e9550449SChe-Liang Chiou 		mmc->init_in_progress = 1;
2105e9550449SChe-Liang Chiou 
2106e9550449SChe-Liang Chiou 	return err;
2107e9550449SChe-Liang Chiou }
2108*479fbf72SJason Zhu #endif
2109e9550449SChe-Liang Chiou 
2110e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc)
2111e9550449SChe-Liang Chiou {
2112e9550449SChe-Liang Chiou 	int err = 0;
2113e9550449SChe-Liang Chiou 
2114bd47c135SAndrew Gabbasov 	mmc->init_in_progress = 0;
2115e9550449SChe-Liang Chiou 	if (mmc->op_cond_pending)
2116e9550449SChe-Liang Chiou 		err = mmc_complete_op_cond(mmc);
2117e9550449SChe-Liang Chiou 
2118e9550449SChe-Liang Chiou 	if (!err)
2119bc897b1dSLei Wen 		err = mmc_startup(mmc);
2120bc897b1dSLei Wen 	if (err)
2121bc897b1dSLei Wen 		mmc->has_init = 0;
2122bc897b1dSLei Wen 	else
2123bc897b1dSLei Wen 		mmc->has_init = 1;
2124e9550449SChe-Liang Chiou 	return err;
2125e9550449SChe-Liang Chiou }
2126e9550449SChe-Liang Chiou 
2127e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc)
2128e9550449SChe-Liang Chiou {
2129bd47c135SAndrew Gabbasov 	int err = 0;
2130ce9eca94SMarek Vasut 	__maybe_unused unsigned start;
2131c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
213233fb211dSSimon Glass 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev);
2133e9550449SChe-Liang Chiou 
213433fb211dSSimon Glass 	upriv->mmc = mmc;
213533fb211dSSimon Glass #endif
2136e9550449SChe-Liang Chiou 	if (mmc->has_init)
2137e9550449SChe-Liang Chiou 		return 0;
2138d803fea5SMateusz Zalega 
2139d803fea5SMateusz Zalega 	start = get_timer(0);
2140d803fea5SMateusz Zalega 
2141e9550449SChe-Liang Chiou 	if (!mmc->init_in_progress)
2142e9550449SChe-Liang Chiou 		err = mmc_start_init(mmc);
2143e9550449SChe-Liang Chiou 
2144bd47c135SAndrew Gabbasov 	if (!err)
2145e9550449SChe-Liang Chiou 		err = mmc_complete_init(mmc);
2146919b4858SJagan Teki 	if (err)
2147919b4858SJagan Teki 		printf("%s: %d, time %lu\n", __func__, err, get_timer(start));
2148919b4858SJagan Teki 
2149bc897b1dSLei Wen 	return err;
2150272cc70bSAndy Fleming }
2151272cc70bSAndy Fleming 
2152ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val)
2153ab71188cSMarkus Niebel {
2154ab71188cSMarkus Niebel 	mmc->dsr = val;
2155ab71188cSMarkus Niebel 	return 0;
2156ab71188cSMarkus Niebel }
2157ab71188cSMarkus Niebel 
2158cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */
2159cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis)
2160272cc70bSAndy Fleming {
2161272cc70bSAndy Fleming 	return -1;
2162272cc70bSAndy Fleming }
2163272cc70bSAndy Fleming 
2164cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */
2165cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis)
2166cee9ab7cSJeroen Hofstee {
2167cee9ab7cSJeroen Hofstee 	return -1;
2168cee9ab7cSJeroen Hofstee }
2169272cc70bSAndy Fleming 
2170e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit)
2171e9550449SChe-Liang Chiou {
2172e9550449SChe-Liang Chiou 	mmc->preinit = preinit;
2173e9550449SChe-Liang Chiou }
2174e9550449SChe-Liang Chiou 
2175c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD)
21768e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
21778e3332e2SSjoerd Simons {
21788e3332e2SSjoerd Simons 	return 0;
21798e3332e2SSjoerd Simons }
2180c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC)
21818e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
21828e3332e2SSjoerd Simons {
21834a1db6d8SSimon Glass 	int ret, i;
21848e3332e2SSjoerd Simons 	struct uclass *uc;
21854a1db6d8SSimon Glass 	struct udevice *dev;
21868e3332e2SSjoerd Simons 
21878e3332e2SSjoerd Simons 	ret = uclass_get(UCLASS_MMC, &uc);
21888e3332e2SSjoerd Simons 	if (ret)
21898e3332e2SSjoerd Simons 		return ret;
21908e3332e2SSjoerd Simons 
21914a1db6d8SSimon Glass 	/*
21924a1db6d8SSimon Glass 	 * Try to add them in sequence order. Really with driver model we
21934a1db6d8SSimon Glass 	 * should allow holes, but the current MMC list does not allow that.
21944a1db6d8SSimon Glass 	 * So if we request 0, 1, 3 we will get 0, 1, 2.
21954a1db6d8SSimon Glass 	 */
21964a1db6d8SSimon Glass 	for (i = 0; ; i++) {
21974a1db6d8SSimon Glass 		ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev);
21984a1db6d8SSimon Glass 		if (ret == -ENODEV)
21994a1db6d8SSimon Glass 			break;
22004a1db6d8SSimon Glass 	}
22014a1db6d8SSimon Glass 	uclass_foreach_dev(dev, uc) {
22024a1db6d8SSimon Glass 		ret = device_probe(dev);
22038e3332e2SSjoerd Simons 		if (ret)
22044a1db6d8SSimon Glass 			printf("%s - probe failed: %d\n", dev->name, ret);
22058e3332e2SSjoerd Simons 	}
22068e3332e2SSjoerd Simons 
22078e3332e2SSjoerd Simons 	return 0;
22088e3332e2SSjoerd Simons }
22098e3332e2SSjoerd Simons #else
22108e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
22118e3332e2SSjoerd Simons {
22128e3332e2SSjoerd Simons 	if (board_mmc_init(bis) < 0)
22138e3332e2SSjoerd Simons 		cpu_mmc_init(bis);
22148e3332e2SSjoerd Simons 
22158e3332e2SSjoerd Simons 	return 0;
22168e3332e2SSjoerd Simons }
22178e3332e2SSjoerd Simons #endif
2218e9550449SChe-Liang Chiou 
2219272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
2220272cc70bSAndy Fleming {
22211b26bab1SDaniel Kochmański 	static int initialized = 0;
22228e3332e2SSjoerd Simons 	int ret;
22231b26bab1SDaniel Kochmański 	if (initialized)	/* Avoid initializing mmc multiple times */
22241b26bab1SDaniel Kochmański 		return 0;
22251b26bab1SDaniel Kochmański 	initialized = 1;
22261b26bab1SDaniel Kochmański 
2227c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK)
2228b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY)
2229c40fdca6SSimon Glass 	mmc_list_init();
2230c40fdca6SSimon Glass #endif
2231b5b838f1SMarek Vasut #endif
22328e3332e2SSjoerd Simons 	ret = mmc_probe(bis);
22338e3332e2SSjoerd Simons 	if (ret)
22348e3332e2SSjoerd Simons 		return ret;
2235272cc70bSAndy Fleming 
2236bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD
2237272cc70bSAndy Fleming 	print_mmc_devices(',');
2238bb0dc108SYing Zhang #endif
2239272cc70bSAndy Fleming 
2240c40fdca6SSimon Glass 	mmc_do_preinit();
2241272cc70bSAndy Fleming 	return 0;
2242272cc70bSAndy Fleming }
2243cd3d4880STomas Melin 
2244cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE
2245cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc)
2246cd3d4880STomas Melin {
2247cd3d4880STomas Melin 	int err;
2248cd3d4880STomas Melin 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
2249cd3d4880STomas Melin 
2250cd3d4880STomas Melin 	err = mmc_send_ext_csd(mmc, ext_csd);
2251cd3d4880STomas Melin 	if (err) {
2252cd3d4880STomas Melin 		puts("Could not get ext_csd register values\n");
2253cd3d4880STomas Melin 		return err;
2254cd3d4880STomas Melin 	}
2255cd3d4880STomas Melin 
2256cd3d4880STomas Melin 	if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) {
2257cd3d4880STomas Melin 		puts("Background operations not supported on device\n");
2258cd3d4880STomas Melin 		return -EMEDIUMTYPE;
2259cd3d4880STomas Melin 	}
2260cd3d4880STomas Melin 
2261cd3d4880STomas Melin 	if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) {
2262cd3d4880STomas Melin 		puts("Background operations already enabled\n");
2263cd3d4880STomas Melin 		return 0;
2264cd3d4880STomas Melin 	}
2265cd3d4880STomas Melin 
2266cd3d4880STomas Melin 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1);
2267cd3d4880STomas Melin 	if (err) {
2268cd3d4880STomas Melin 		puts("Failed to enable manual background operations\n");
2269cd3d4880STomas Melin 		return err;
2270cd3d4880STomas Melin 	}
2271cd3d4880STomas Melin 
2272cd3d4880STomas Melin 	puts("Enabled manual background operations\n");
2273cd3d4880STomas Melin 
2274cd3d4880STomas Melin 	return 0;
2275cd3d4880STomas Melin }
2276cd3d4880STomas Melin #endif
2277