xref: /rk3399_rockchip-uboot/drivers/mmc/mmc.c (revision 1f250d0a05ad1f42e18fe409c339e4a98f28e73a)
1272cc70bSAndy Fleming /*
2272cc70bSAndy Fleming  * Copyright 2008, Freescale Semiconductor, Inc
3272cc70bSAndy Fleming  * Andy Fleming
4272cc70bSAndy Fleming  *
5272cc70bSAndy Fleming  * Based vaguely on the Linux code
6272cc70bSAndy Fleming  *
71a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
8272cc70bSAndy Fleming  */
9272cc70bSAndy Fleming 
10272cc70bSAndy Fleming #include <config.h>
11272cc70bSAndy Fleming #include <common.h>
12272cc70bSAndy Fleming #include <command.h>
138e3332e2SSjoerd Simons #include <dm.h>
148e3332e2SSjoerd Simons #include <dm/device-internal.h>
15d4622df3SStephen Warren #include <errno.h>
16272cc70bSAndy Fleming #include <mmc.h>
17272cc70bSAndy Fleming #include <part.h>
182051aefeSPeng Fan #include <power/regulator.h>
19272cc70bSAndy Fleming #include <malloc.h>
20cf92e05cSSimon Glass #include <memalign.h>
21272cc70bSAndy Fleming #include <linux/list.h>
229b1f942cSRabin Vincent #include <div64.h>
23da61fa5fSPaul Burton #include "mmc_private.h"
24272cc70bSAndy Fleming 
253697e599SPeng Fan static const unsigned int sd_au_size[] = {
263697e599SPeng Fan 	0,		SZ_16K / 512,		SZ_32K / 512,
273697e599SPeng Fan 	SZ_64K / 512,	SZ_128K / 512,		SZ_256K / 512,
283697e599SPeng Fan 	SZ_512K / 512,	SZ_1M / 512,		SZ_2M / 512,
293697e599SPeng Fan 	SZ_4M / 512,	SZ_8M / 512,		(SZ_8M + SZ_4M) / 512,
303697e599SPeng Fan 	SZ_16M / 512,	(SZ_16M + SZ_8M) / 512,	SZ_32M / 512,	SZ_64M / 512,
313697e599SPeng Fan };
323697e599SPeng Fan 
33b5b838f1SMarek Vasut #if CONFIG_IS_ENABLED(MMC_TINY)
34b5b838f1SMarek Vasut static struct mmc mmc_static;
35b5b838f1SMarek Vasut struct mmc *find_mmc_device(int dev_num)
36b5b838f1SMarek Vasut {
37b5b838f1SMarek Vasut 	return &mmc_static;
38b5b838f1SMarek Vasut }
39b5b838f1SMarek Vasut 
40b5b838f1SMarek Vasut void mmc_do_preinit(void)
41b5b838f1SMarek Vasut {
42b5b838f1SMarek Vasut 	struct mmc *m = &mmc_static;
43b5b838f1SMarek Vasut #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
44b5b838f1SMarek Vasut 	mmc_set_preinit(m, 1);
45b5b838f1SMarek Vasut #endif
46b5b838f1SMarek Vasut 	if (m->preinit)
47b5b838f1SMarek Vasut 		mmc_start_init(m);
48b5b838f1SMarek Vasut }
49b5b838f1SMarek Vasut 
50b5b838f1SMarek Vasut struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
51b5b838f1SMarek Vasut {
52b5b838f1SMarek Vasut 	return &mmc->block_dev;
53b5b838f1SMarek Vasut }
54b5b838f1SMarek Vasut #endif
55b5b838f1SMarek Vasut 
56e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
57750121c3SJeroen Hofstee __weak int board_mmc_getwp(struct mmc *mmc)
58d23d8d7eSNikita Kiryanov {
59d23d8d7eSNikita Kiryanov 	return -1;
60d23d8d7eSNikita Kiryanov }
61d23d8d7eSNikita Kiryanov 
62d23d8d7eSNikita Kiryanov int mmc_getwp(struct mmc *mmc)
63d23d8d7eSNikita Kiryanov {
64d23d8d7eSNikita Kiryanov 	int wp;
65d23d8d7eSNikita Kiryanov 
66d23d8d7eSNikita Kiryanov 	wp = board_mmc_getwp(mmc);
67d23d8d7eSNikita Kiryanov 
68d4e1da4eSPeter Korsgaard 	if (wp < 0) {
6993bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getwp)
7093bfd616SPantelis Antoniou 			wp = mmc->cfg->ops->getwp(mmc);
71d4e1da4eSPeter Korsgaard 		else
72d4e1da4eSPeter Korsgaard 			wp = 0;
73d4e1da4eSPeter Korsgaard 	}
74d23d8d7eSNikita Kiryanov 
75d23d8d7eSNikita Kiryanov 	return wp;
76d23d8d7eSNikita Kiryanov }
77d23d8d7eSNikita Kiryanov 
78cee9ab7cSJeroen Hofstee __weak int board_mmc_getcd(struct mmc *mmc)
79cee9ab7cSJeroen Hofstee {
8011fdade2SStefano Babic 	return -1;
8111fdade2SStefano Babic }
828ca51e51SSimon Glass #endif
8311fdade2SStefano Babic 
848635ff9eSMarek Vasut #ifdef CONFIG_MMC_TRACE
85c0c76ebaSSimon Glass void mmmc_trace_before_send(struct mmc *mmc, struct mmc_cmd *cmd)
86c0c76ebaSSimon Glass {
87c0c76ebaSSimon Glass 	printf("CMD_SEND:%d\n", cmd->cmdidx);
88c0c76ebaSSimon Glass 	printf("\t\tARG\t\t\t 0x%08X\n", cmd->cmdarg);
89c0c76ebaSSimon Glass }
90c0c76ebaSSimon Glass 
91c0c76ebaSSimon Glass void mmmc_trace_after_send(struct mmc *mmc, struct mmc_cmd *cmd, int ret)
92c0c76ebaSSimon Glass {
935db2fe3aSRaffaele Recalcati 	int i;
945db2fe3aSRaffaele Recalcati 	u8 *ptr;
955db2fe3aSRaffaele Recalcati 
967863ce58SBin Meng 	if (ret) {
977863ce58SBin Meng 		printf("\t\tRET\t\t\t %d\n", ret);
987863ce58SBin Meng 	} else {
995db2fe3aSRaffaele Recalcati 		switch (cmd->resp_type) {
1005db2fe3aSRaffaele Recalcati 		case MMC_RSP_NONE:
1015db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_NONE\n");
1025db2fe3aSRaffaele Recalcati 			break;
1035db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1:
1045db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1,5,6,7 \t 0x%08X \n",
1055db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1065db2fe3aSRaffaele Recalcati 			break;
1075db2fe3aSRaffaele Recalcati 		case MMC_RSP_R1b:
1085db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R1b\t\t 0x%08X \n",
1095db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1105db2fe3aSRaffaele Recalcati 			break;
1115db2fe3aSRaffaele Recalcati 		case MMC_RSP_R2:
1125db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R2\t\t 0x%08X \n",
1135db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1145db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1155db2fe3aSRaffaele Recalcati 				cmd->response[1]);
1165db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1175db2fe3aSRaffaele Recalcati 				cmd->response[2]);
1185db2fe3aSRaffaele Recalcati 			printf("\t\t          \t\t 0x%08X \n",
1195db2fe3aSRaffaele Recalcati 				cmd->response[3]);
1205db2fe3aSRaffaele Recalcati 			printf("\n");
1215db2fe3aSRaffaele Recalcati 			printf("\t\t\t\t\tDUMPING DATA\n");
1225db2fe3aSRaffaele Recalcati 			for (i = 0; i < 4; i++) {
1235db2fe3aSRaffaele Recalcati 				int j;
1245db2fe3aSRaffaele Recalcati 				printf("\t\t\t\t\t%03d - ", i*4);
125146bec79SDirk Behme 				ptr = (u8 *)&cmd->response[i];
1265db2fe3aSRaffaele Recalcati 				ptr += 3;
1275db2fe3aSRaffaele Recalcati 				for (j = 0; j < 4; j++)
1285db2fe3aSRaffaele Recalcati 					printf("%02X ", *ptr--);
1295db2fe3aSRaffaele Recalcati 				printf("\n");
1305db2fe3aSRaffaele Recalcati 			}
1315db2fe3aSRaffaele Recalcati 			break;
1325db2fe3aSRaffaele Recalcati 		case MMC_RSP_R3:
1335db2fe3aSRaffaele Recalcati 			printf("\t\tMMC_RSP_R3,4\t\t 0x%08X \n",
1345db2fe3aSRaffaele Recalcati 				cmd->response[0]);
1355db2fe3aSRaffaele Recalcati 			break;
1365db2fe3aSRaffaele Recalcati 		default:
1375db2fe3aSRaffaele Recalcati 			printf("\t\tERROR MMC rsp not supported\n");
1385db2fe3aSRaffaele Recalcati 			break;
1395db2fe3aSRaffaele Recalcati 		}
1407863ce58SBin Meng 	}
141c0c76ebaSSimon Glass }
142c0c76ebaSSimon Glass 
143c0c76ebaSSimon Glass void mmc_trace_state(struct mmc *mmc, struct mmc_cmd *cmd)
144c0c76ebaSSimon Glass {
145c0c76ebaSSimon Glass 	int status;
146c0c76ebaSSimon Glass 
147c0c76ebaSSimon Glass 	status = (cmd->response[0] & MMC_STATUS_CURR_STATE) >> 9;
148c0c76ebaSSimon Glass 	printf("CURR STATE:%d\n", status);
149c0c76ebaSSimon Glass }
1505db2fe3aSRaffaele Recalcati #endif
151c0c76ebaSSimon Glass 
152e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
153c0c76ebaSSimon Glass int mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
154c0c76ebaSSimon Glass {
155c0c76ebaSSimon Glass 	int ret;
156c0c76ebaSSimon Glass 
157c0c76ebaSSimon Glass 	mmmc_trace_before_send(mmc, cmd);
158c0c76ebaSSimon Glass 	ret = mmc->cfg->ops->send_cmd(mmc, cmd, data);
159c0c76ebaSSimon Glass 	mmmc_trace_after_send(mmc, cmd, ret);
160c0c76ebaSSimon Glass 
1618635ff9eSMarek Vasut 	return ret;
162272cc70bSAndy Fleming }
1638ca51e51SSimon Glass #endif
164272cc70bSAndy Fleming 
165da61fa5fSPaul Burton int mmc_send_status(struct mmc *mmc, int timeout)
1665d4fc8d9SRaffaele Recalcati {
1675d4fc8d9SRaffaele Recalcati 	struct mmc_cmd cmd;
168d617c426SJan Kloetzke 	int err, retries = 5;
1695d4fc8d9SRaffaele Recalcati 
1705d4fc8d9SRaffaele Recalcati 	cmd.cmdidx = MMC_CMD_SEND_STATUS;
1715d4fc8d9SRaffaele Recalcati 	cmd.resp_type = MMC_RSP_R1;
172aaf3d41aSMarek Vasut 	if (!mmc_host_is_spi(mmc))
173aaf3d41aSMarek Vasut 		cmd.cmdarg = mmc->rca << 16;
1745d4fc8d9SRaffaele Recalcati 
1751677eef4SAndrew Gabbasov 	while (1) {
1765d4fc8d9SRaffaele Recalcati 		err = mmc_send_cmd(mmc, &cmd, NULL);
177d617c426SJan Kloetzke 		if (!err) {
178d617c426SJan Kloetzke 			if ((cmd.response[0] & MMC_STATUS_RDY_FOR_DATA) &&
179d617c426SJan Kloetzke 			    (cmd.response[0] & MMC_STATUS_CURR_STATE) !=
180d617c426SJan Kloetzke 			     MMC_STATE_PRG)
1815d4fc8d9SRaffaele Recalcati 				break;
182d617c426SJan Kloetzke 			else if (cmd.response[0] & MMC_STATUS_MASK) {
18356196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
184d617c426SJan Kloetzke 				printf("Status Error: 0x%08X\n",
185d617c426SJan Kloetzke 					cmd.response[0]);
18656196826SPaul Burton #endif
187915ffa52SJaehoon Chung 				return -ECOMM;
188d617c426SJan Kloetzke 			}
189d617c426SJan Kloetzke 		} else if (--retries < 0)
190d617c426SJan Kloetzke 			return err;
1915d4fc8d9SRaffaele Recalcati 
1921677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
1931677eef4SAndrew Gabbasov 			break;
1945d4fc8d9SRaffaele Recalcati 
1951677eef4SAndrew Gabbasov 		udelay(1000);
1961677eef4SAndrew Gabbasov 	}
1975d4fc8d9SRaffaele Recalcati 
198c0c76ebaSSimon Glass 	mmc_trace_state(mmc, &cmd);
1995b0c942fSJongman Heo 	if (timeout <= 0) {
20056196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2015d4fc8d9SRaffaele Recalcati 		printf("Timeout waiting card ready\n");
20256196826SPaul Burton #endif
203915ffa52SJaehoon Chung 		return -ETIMEDOUT;
2045d4fc8d9SRaffaele Recalcati 	}
2055d4fc8d9SRaffaele Recalcati 
2065d4fc8d9SRaffaele Recalcati 	return 0;
2075d4fc8d9SRaffaele Recalcati }
2085d4fc8d9SRaffaele Recalcati 
209da61fa5fSPaul Burton int mmc_set_blocklen(struct mmc *mmc, int len)
210272cc70bSAndy Fleming {
211272cc70bSAndy Fleming 	struct mmc_cmd cmd;
212272cc70bSAndy Fleming 
213caa21a21SZiyuan Xu 	if (mmc_card_ddr(mmc))
214d22e3d46SJaehoon Chung 		return 0;
215d22e3d46SJaehoon Chung 
216272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SET_BLOCKLEN;
217272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
218272cc70bSAndy Fleming 	cmd.cmdarg = len;
219272cc70bSAndy Fleming 
220272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, NULL);
221272cc70bSAndy Fleming }
222272cc70bSAndy Fleming 
223ff8fef56SSascha Silbe static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
224fdbb873eSKim Phillips 			   lbaint_t blkcnt)
225272cc70bSAndy Fleming {
226272cc70bSAndy Fleming 	struct mmc_cmd cmd;
227272cc70bSAndy Fleming 	struct mmc_data data;
228272cc70bSAndy Fleming 
2294a1a06bcSAlagu Sankar 	if (blkcnt > 1)
2304a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK;
2314a1a06bcSAlagu Sankar 	else
232272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_READ_SINGLE_BLOCK;
233272cc70bSAndy Fleming 
234272cc70bSAndy Fleming 	if (mmc->high_capacity)
2354a1a06bcSAlagu Sankar 		cmd.cmdarg = start;
236272cc70bSAndy Fleming 	else
2374a1a06bcSAlagu Sankar 		cmd.cmdarg = start * mmc->read_bl_len;
238272cc70bSAndy Fleming 
239272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
240272cc70bSAndy Fleming 
241272cc70bSAndy Fleming 	data.dest = dst;
2424a1a06bcSAlagu Sankar 	data.blocks = blkcnt;
243272cc70bSAndy Fleming 	data.blocksize = mmc->read_bl_len;
244272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
245272cc70bSAndy Fleming 
2464a1a06bcSAlagu Sankar 	if (mmc_send_cmd(mmc, &cmd, &data))
2474a1a06bcSAlagu Sankar 		return 0;
2484a1a06bcSAlagu Sankar 
2494a1a06bcSAlagu Sankar 	if (blkcnt > 1) {
2504a1a06bcSAlagu Sankar 		cmd.cmdidx = MMC_CMD_STOP_TRANSMISSION;
2514a1a06bcSAlagu Sankar 		cmd.cmdarg = 0;
2524a1a06bcSAlagu Sankar 		cmd.resp_type = MMC_RSP_R1b;
2534a1a06bcSAlagu Sankar 		if (mmc_send_cmd(mmc, &cmd, NULL)) {
25456196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2554a1a06bcSAlagu Sankar 			printf("mmc fail to send stop cmd\n");
25656196826SPaul Burton #endif
2574a1a06bcSAlagu Sankar 			return 0;
2584a1a06bcSAlagu Sankar 		}
259272cc70bSAndy Fleming 	}
260272cc70bSAndy Fleming 
2614a1a06bcSAlagu Sankar 	return blkcnt;
262272cc70bSAndy Fleming }
263272cc70bSAndy Fleming 
264c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
2657dba0b93SSimon Glass ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *dst)
26633fb211dSSimon Glass #else
2677dba0b93SSimon Glass ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
2687dba0b93SSimon Glass 		void *dst)
26933fb211dSSimon Glass #endif
270272cc70bSAndy Fleming {
271c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(BLK)
27233fb211dSSimon Glass 	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
27333fb211dSSimon Glass #endif
274bcce53d0SSimon Glass 	int dev_num = block_dev->devnum;
275873cc1d7SStephen Warren 	int err;
2764a1a06bcSAlagu Sankar 	lbaint_t cur, blocks_todo = blkcnt;
277272cc70bSAndy Fleming 
2784a1a06bcSAlagu Sankar 	if (blkcnt == 0)
2794a1a06bcSAlagu Sankar 		return 0;
2804a1a06bcSAlagu Sankar 
2814a1a06bcSAlagu Sankar 	struct mmc *mmc = find_mmc_device(dev_num);
282272cc70bSAndy Fleming 	if (!mmc)
283272cc70bSAndy Fleming 		return 0;
284272cc70bSAndy Fleming 
285b5b838f1SMarek Vasut 	if (CONFIG_IS_ENABLED(MMC_TINY))
286b5b838f1SMarek Vasut 		err = mmc_switch_part(mmc, block_dev->hwpart);
287b5b838f1SMarek Vasut 	else
28869f45cd5SSimon Glass 		err = blk_dselect_hwpart(block_dev, block_dev->hwpart);
289b5b838f1SMarek Vasut 
290873cc1d7SStephen Warren 	if (err < 0)
291873cc1d7SStephen Warren 		return 0;
292873cc1d7SStephen Warren 
293c40fdca6SSimon Glass 	if ((start + blkcnt) > block_dev->lba) {
29456196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
295ff8fef56SSascha Silbe 		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
296c40fdca6SSimon Glass 			start + blkcnt, block_dev->lba);
29756196826SPaul Burton #endif
298d2bf29e3SLei Wen 		return 0;
299d2bf29e3SLei Wen 	}
300272cc70bSAndy Fleming 
30111692991SSimon Glass 	if (mmc_set_blocklen(mmc, mmc->read_bl_len)) {
30211692991SSimon Glass 		debug("%s: Failed to set blocklen\n", __func__);
303272cc70bSAndy Fleming 		return 0;
30411692991SSimon Glass 	}
305272cc70bSAndy Fleming 
3064a1a06bcSAlagu Sankar 	do {
30793bfd616SPantelis Antoniou 		cur = (blocks_todo > mmc->cfg->b_max) ?
30893bfd616SPantelis Antoniou 			mmc->cfg->b_max : blocks_todo;
30911692991SSimon Glass 		if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
31011692991SSimon Glass 			debug("%s: Failed to read blocks\n", __func__);
311c30b5115SJason Zhu 			int timeout = 0;
312c30b5115SJason Zhu re_init_retry:
313c30b5115SJason Zhu 			timeout++;
314c30b5115SJason Zhu 			/*
315c30b5115SJason Zhu 			 * Try re-init seven times.
316c30b5115SJason Zhu 			 */
317c30b5115SJason Zhu 			if (timeout > 7) {
318c30b5115SJason Zhu 				printf("Re-init retry timeout\n");
3194a1a06bcSAlagu Sankar 				return 0;
32011692991SSimon Glass 			}
321c30b5115SJason Zhu 
322c30b5115SJason Zhu 			mmc->has_init = 0;
323c30b5115SJason Zhu 			if (mmc_init(mmc))
324c30b5115SJason Zhu 				return 0;
325c30b5115SJason Zhu 
326c30b5115SJason Zhu 			if (mmc_read_blocks(mmc, dst, start, cur) != cur) {
327c30b5115SJason Zhu 				printf("%s: Re-init mmc_read_blocks error\n",
328c30b5115SJason Zhu 				       __func__);
329c30b5115SJason Zhu 				goto re_init_retry;
330c30b5115SJason Zhu 			}
331c30b5115SJason Zhu 		}
3324a1a06bcSAlagu Sankar 		blocks_todo -= cur;
3334a1a06bcSAlagu Sankar 		start += cur;
3344a1a06bcSAlagu Sankar 		dst += cur * mmc->read_bl_len;
3354a1a06bcSAlagu Sankar 	} while (blocks_todo > 0);
336272cc70bSAndy Fleming 
337272cc70bSAndy Fleming 	return blkcnt;
338272cc70bSAndy Fleming }
339272cc70bSAndy Fleming 
34049dba033SZiyuan Xu void mmc_set_clock(struct mmc *mmc, uint clock)
34149dba033SZiyuan Xu {
34249dba033SZiyuan Xu 	if (clock > mmc->cfg->f_max)
34349dba033SZiyuan Xu 		clock = mmc->cfg->f_max;
34449dba033SZiyuan Xu 
34549dba033SZiyuan Xu 	if (clock < mmc->cfg->f_min)
34649dba033SZiyuan Xu 		clock = mmc->cfg->f_min;
34749dba033SZiyuan Xu 
34849dba033SZiyuan Xu 	mmc->clock = clock;
34949dba033SZiyuan Xu 
35049dba033SZiyuan Xu 	mmc_set_ios(mmc);
35149dba033SZiyuan Xu }
35249dba033SZiyuan Xu 
35349dba033SZiyuan Xu static void mmc_set_bus_width(struct mmc *mmc, uint width)
35449dba033SZiyuan Xu {
35549dba033SZiyuan Xu 	mmc->bus_width = width;
35649dba033SZiyuan Xu 
35749dba033SZiyuan Xu 	mmc_set_ios(mmc);
35849dba033SZiyuan Xu }
35949dba033SZiyuan Xu 
36081db2d36SZiyuan Xu static void mmc_set_timing(struct mmc *mmc, uint timing)
36181db2d36SZiyuan Xu {
36281db2d36SZiyuan Xu 	mmc->timing = timing;
36381db2d36SZiyuan Xu 	mmc_set_ios(mmc);
36481db2d36SZiyuan Xu }
36581db2d36SZiyuan Xu 
366fdbb873eSKim Phillips static int mmc_go_idle(struct mmc *mmc)
367272cc70bSAndy Fleming {
368272cc70bSAndy Fleming 	struct mmc_cmd cmd;
369272cc70bSAndy Fleming 	int err;
370272cc70bSAndy Fleming 
371272cc70bSAndy Fleming 	udelay(1000);
372272cc70bSAndy Fleming 
373272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_GO_IDLE_STATE;
374272cc70bSAndy Fleming 	cmd.cmdarg = 0;
375272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_NONE;
376272cc70bSAndy Fleming 
377272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
378272cc70bSAndy Fleming 
379272cc70bSAndy Fleming 	if (err)
380272cc70bSAndy Fleming 		return err;
381272cc70bSAndy Fleming 
382272cc70bSAndy Fleming 	udelay(2000);
383272cc70bSAndy Fleming 
384272cc70bSAndy Fleming 	return 0;
385272cc70bSAndy Fleming }
386272cc70bSAndy Fleming 
387fdbb873eSKim Phillips static int sd_send_op_cond(struct mmc *mmc)
388272cc70bSAndy Fleming {
389272cc70bSAndy Fleming 	int timeout = 1000;
390272cc70bSAndy Fleming 	int err;
391272cc70bSAndy Fleming 	struct mmc_cmd cmd;
392272cc70bSAndy Fleming 
3931677eef4SAndrew Gabbasov 	while (1) {
394272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_APP_CMD;
395272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R1;
396272cc70bSAndy Fleming 		cmd.cmdarg = 0;
397272cc70bSAndy Fleming 
398272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
399272cc70bSAndy Fleming 
400272cc70bSAndy Fleming 		if (err)
401272cc70bSAndy Fleming 			return err;
402272cc70bSAndy Fleming 
403272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_APP_SEND_OP_COND;
404272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R3;
405250de12bSStefano Babic 
406250de12bSStefano Babic 		/*
407250de12bSStefano Babic 		 * Most cards do not answer if some reserved bits
408250de12bSStefano Babic 		 * in the ocr are set. However, Some controller
409250de12bSStefano Babic 		 * can set bit 7 (reserved for low voltages), but
410250de12bSStefano Babic 		 * how to manage low voltages SD card is not yet
411250de12bSStefano Babic 		 * specified.
412250de12bSStefano Babic 		 */
413d52ebf10SThomas Chou 		cmd.cmdarg = mmc_host_is_spi(mmc) ? 0 :
41493bfd616SPantelis Antoniou 			(mmc->cfg->voltages & 0xff8000);
415272cc70bSAndy Fleming 
416272cc70bSAndy Fleming 		if (mmc->version == SD_VERSION_2)
417272cc70bSAndy Fleming 			cmd.cmdarg |= OCR_HCS;
418272cc70bSAndy Fleming 
419272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
420272cc70bSAndy Fleming 
421272cc70bSAndy Fleming 		if (err)
422272cc70bSAndy Fleming 			return err;
423272cc70bSAndy Fleming 
4241677eef4SAndrew Gabbasov 		if (cmd.response[0] & OCR_BUSY)
4251677eef4SAndrew Gabbasov 			break;
426272cc70bSAndy Fleming 
4271677eef4SAndrew Gabbasov 		if (timeout-- <= 0)
428915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
429272cc70bSAndy Fleming 
4301677eef4SAndrew Gabbasov 		udelay(1000);
4311677eef4SAndrew Gabbasov 	}
4321677eef4SAndrew Gabbasov 
433272cc70bSAndy Fleming 	if (mmc->version != SD_VERSION_2)
434272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
435272cc70bSAndy Fleming 
436d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
437d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
438d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
439d52ebf10SThomas Chou 		cmd.cmdarg = 0;
440d52ebf10SThomas Chou 
441d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
442d52ebf10SThomas Chou 
443d52ebf10SThomas Chou 		if (err)
444d52ebf10SThomas Chou 			return err;
445d52ebf10SThomas Chou 	}
446d52ebf10SThomas Chou 
447998be3ddSRabin Vincent 	mmc->ocr = cmd.response[0];
448272cc70bSAndy Fleming 
449272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
450272cc70bSAndy Fleming 	mmc->rca = 0;
451272cc70bSAndy Fleming 
452272cc70bSAndy Fleming 	return 0;
453272cc70bSAndy Fleming }
454272cc70bSAndy Fleming 
4555289b535SAndrew Gabbasov static int mmc_send_op_cond_iter(struct mmc *mmc, int use_arg)
456272cc70bSAndy Fleming {
4575289b535SAndrew Gabbasov 	struct mmc_cmd cmd;
458272cc70bSAndy Fleming 	int err;
459272cc70bSAndy Fleming 
4605289b535SAndrew Gabbasov 	cmd.cmdidx = MMC_CMD_SEND_OP_COND;
4615289b535SAndrew Gabbasov 	cmd.resp_type = MMC_RSP_R3;
4625289b535SAndrew Gabbasov 	cmd.cmdarg = 0;
4635a20397bSRob Herring 	if (use_arg && !mmc_host_is_spi(mmc))
4645a20397bSRob Herring 		cmd.cmdarg = OCR_HCS |
46593bfd616SPantelis Antoniou 			(mmc->cfg->voltages &
466a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_VOLTAGE_MASK)) |
467a626c8d4SAndrew Gabbasov 			(mmc->ocr & OCR_ACCESS_MODE);
468e9550449SChe-Liang Chiou 
4695289b535SAndrew Gabbasov 	err = mmc_send_cmd(mmc, &cmd, NULL);
470e9550449SChe-Liang Chiou 	if (err)
471e9550449SChe-Liang Chiou 		return err;
4725289b535SAndrew Gabbasov 	mmc->ocr = cmd.response[0];
473e9550449SChe-Liang Chiou 	return 0;
474e9550449SChe-Liang Chiou }
475e9550449SChe-Liang Chiou 
476750121c3SJeroen Hofstee static int mmc_send_op_cond(struct mmc *mmc)
477e9550449SChe-Liang Chiou {
478e9550449SChe-Liang Chiou 	int err, i;
479e9550449SChe-Liang Chiou 
480272cc70bSAndy Fleming 	/* Some cards seem to need this */
481272cc70bSAndy Fleming 	mmc_go_idle(mmc);
482272cc70bSAndy Fleming 
48331cacbabSRaffaele Recalcati  	/* Asking to the card its capabilities */
484e9550449SChe-Liang Chiou 	for (i = 0; i < 2; i++) {
4855289b535SAndrew Gabbasov 		err = mmc_send_op_cond_iter(mmc, i != 0);
48631cacbabSRaffaele Recalcati 		if (err)
48731cacbabSRaffaele Recalcati 			return err;
48831cacbabSRaffaele Recalcati 
489e9550449SChe-Liang Chiou 		/* exit if not busy (flag seems to be inverted) */
490a626c8d4SAndrew Gabbasov 		if (mmc->ocr & OCR_BUSY)
491bd47c135SAndrew Gabbasov 			break;
492e9550449SChe-Liang Chiou 	}
493bd47c135SAndrew Gabbasov 	mmc->op_cond_pending = 1;
494bd47c135SAndrew Gabbasov 	return 0;
495e9550449SChe-Liang Chiou }
49631cacbabSRaffaele Recalcati 
497750121c3SJeroen Hofstee static int mmc_complete_op_cond(struct mmc *mmc)
498e9550449SChe-Liang Chiou {
499e9550449SChe-Liang Chiou 	struct mmc_cmd cmd;
500e9550449SChe-Liang Chiou 	int timeout = 1000;
501e9550449SChe-Liang Chiou 	uint start;
502e9550449SChe-Liang Chiou 	int err;
503e9550449SChe-Liang Chiou 
504e9550449SChe-Liang Chiou 	mmc->op_cond_pending = 0;
505cc17c01fSAndrew Gabbasov 	if (!(mmc->ocr & OCR_BUSY)) {
506d188b113SYangbo Lu 		/* Some cards seem to need this */
507d188b113SYangbo Lu 		mmc_go_idle(mmc);
508d188b113SYangbo Lu 
509e9550449SChe-Liang Chiou 		start = get_timer(0);
5101677eef4SAndrew Gabbasov 		while (1) {
5115289b535SAndrew Gabbasov 			err = mmc_send_op_cond_iter(mmc, 1);
512272cc70bSAndy Fleming 			if (err)
513272cc70bSAndy Fleming 				return err;
5141677eef4SAndrew Gabbasov 			if (mmc->ocr & OCR_BUSY)
5151677eef4SAndrew Gabbasov 				break;
516e9550449SChe-Liang Chiou 			if (get_timer(start) > timeout)
517915ffa52SJaehoon Chung 				return -EOPNOTSUPP;
518e9550449SChe-Liang Chiou 			udelay(100);
5191677eef4SAndrew Gabbasov 		}
520cc17c01fSAndrew Gabbasov 	}
521272cc70bSAndy Fleming 
522d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* read OCR for spi */
523d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_READ_OCR;
524d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R3;
525d52ebf10SThomas Chou 		cmd.cmdarg = 0;
526d52ebf10SThomas Chou 
527d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
528d52ebf10SThomas Chou 
529d52ebf10SThomas Chou 		if (err)
530d52ebf10SThomas Chou 			return err;
531a626c8d4SAndrew Gabbasov 
532a626c8d4SAndrew Gabbasov 		mmc->ocr = cmd.response[0];
533d52ebf10SThomas Chou 	}
534d52ebf10SThomas Chou 
535272cc70bSAndy Fleming 	mmc->version = MMC_VERSION_UNKNOWN;
536272cc70bSAndy Fleming 
537272cc70bSAndy Fleming 	mmc->high_capacity = ((mmc->ocr & OCR_HCS) == OCR_HCS);
538def816a2SStephen Warren 	mmc->rca = 1;
539272cc70bSAndy Fleming 
540272cc70bSAndy Fleming 	return 0;
541272cc70bSAndy Fleming }
542272cc70bSAndy Fleming 
543272cc70bSAndy Fleming 
544fdbb873eSKim Phillips static int mmc_send_ext_csd(struct mmc *mmc, u8 *ext_csd)
545272cc70bSAndy Fleming {
546272cc70bSAndy Fleming 	struct mmc_cmd cmd;
547272cc70bSAndy Fleming 	struct mmc_data data;
548272cc70bSAndy Fleming 	int err;
549272cc70bSAndy Fleming 
550272cc70bSAndy Fleming 	/* Get the Card Status Register */
551272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_EXT_CSD;
552272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
553272cc70bSAndy Fleming 	cmd.cmdarg = 0;
554272cc70bSAndy Fleming 
555cdfd1ac6SYoshihiro Shimoda 	data.dest = (char *)ext_csd;
556272cc70bSAndy Fleming 	data.blocks = 1;
5578bfa195eSSimon Glass 	data.blocksize = MMC_MAX_BLOCK_LEN;
558272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
559272cc70bSAndy Fleming 
560272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
561272cc70bSAndy Fleming 
562272cc70bSAndy Fleming 	return err;
563272cc70bSAndy Fleming }
564272cc70bSAndy Fleming 
5659e8ce816SZiyuan Xu static int mmc_poll_for_busy(struct mmc *mmc, u8 send_status)
566272cc70bSAndy Fleming {
567272cc70bSAndy Fleming 	struct mmc_cmd cmd;
56855e5defdSZiyuan Xu 	u8 busy = true;
56955e5defdSZiyuan Xu 	uint start;
57055e5defdSZiyuan Xu 	int ret;
5715d4fc8d9SRaffaele Recalcati 	int timeout = 1000;
57255e5defdSZiyuan Xu 
57355e5defdSZiyuan Xu 	cmd.cmdidx = MMC_CMD_SEND_STATUS;
57455e5defdSZiyuan Xu 	cmd.resp_type = MMC_RSP_R1;
57555e5defdSZiyuan Xu 	cmd.cmdarg = mmc->rca << 16;
57655e5defdSZiyuan Xu 
57755e5defdSZiyuan Xu 	start = get_timer(0);
57855e5defdSZiyuan Xu 
5799e8ce816SZiyuan Xu 	if (!send_status && !mmc_can_card_busy(mmc)) {
5809e8ce816SZiyuan Xu 		mdelay(timeout);
5819e8ce816SZiyuan Xu 		return 0;
5829e8ce816SZiyuan Xu 	}
5839e8ce816SZiyuan Xu 
58455e5defdSZiyuan Xu 	do {
5859e8ce816SZiyuan Xu 		if (!send_status) {
58655e5defdSZiyuan Xu 			busy = mmc_card_busy(mmc);
58755e5defdSZiyuan Xu 		} else {
58855e5defdSZiyuan Xu 			ret = mmc_send_cmd(mmc, &cmd, NULL);
58955e5defdSZiyuan Xu 
59055e5defdSZiyuan Xu 			if (ret)
59155e5defdSZiyuan Xu 				return ret;
59255e5defdSZiyuan Xu 
59355e5defdSZiyuan Xu 			if (cmd.response[0] & MMC_STATUS_SWITCH_ERROR)
59455e5defdSZiyuan Xu 				return -EBADMSG;
59555e5defdSZiyuan Xu 			busy = (cmd.response[0] & MMC_STATUS_CURR_STATE) ==
59655e5defdSZiyuan Xu 				MMC_STATE_PRG;
59755e5defdSZiyuan Xu 		}
59855e5defdSZiyuan Xu 
59955e5defdSZiyuan Xu 		if (get_timer(start) > timeout && busy)
60055e5defdSZiyuan Xu 			return -ETIMEDOUT;
60155e5defdSZiyuan Xu 	} while (busy);
60255e5defdSZiyuan Xu 
60355e5defdSZiyuan Xu 	return 0;
60455e5defdSZiyuan Xu }
60555e5defdSZiyuan Xu 
60655e5defdSZiyuan Xu static int __mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value,
60755e5defdSZiyuan Xu 			u8 send_status)
60855e5defdSZiyuan Xu {
60955e5defdSZiyuan Xu 	struct mmc_cmd cmd;
610a9003dc6SMaxime Ripard 	int retries = 3;
6115d4fc8d9SRaffaele Recalcati 	int ret;
612272cc70bSAndy Fleming 
613272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SWITCH;
614272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1b;
615272cc70bSAndy Fleming 	cmd.cmdarg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
616272cc70bSAndy Fleming 				 (index << 16) |
617272cc70bSAndy Fleming 				 (value << 8);
618272cc70bSAndy Fleming 
61955e5defdSZiyuan Xu 	do {
6205d4fc8d9SRaffaele Recalcati 		ret = mmc_send_cmd(mmc, &cmd, NULL);
6215d4fc8d9SRaffaele Recalcati 
6229e8ce816SZiyuan Xu 		if (!ret)
6239e8ce816SZiyuan Xu 			return mmc_poll_for_busy(mmc, send_status);
62455e5defdSZiyuan Xu 	} while (--retries > 0 && ret);
62555e5defdSZiyuan Xu 
626a9003dc6SMaxime Ripard 	return ret;
627a9003dc6SMaxime Ripard }
628a9003dc6SMaxime Ripard 
62955e5defdSZiyuan Xu int mmc_switch(struct mmc *mmc, u8 set, u8 index, u8 value)
63055e5defdSZiyuan Xu {
63155e5defdSZiyuan Xu 	return __mmc_switch(mmc, set, index, value, true);
632272cc70bSAndy Fleming }
633272cc70bSAndy Fleming 
63449dba033SZiyuan Xu static int mmc_select_bus_width(struct mmc *mmc)
63549dba033SZiyuan Xu {
63649dba033SZiyuan Xu 	u32 ext_csd_bits[] = {
63749dba033SZiyuan Xu 		EXT_CSD_BUS_WIDTH_8,
63849dba033SZiyuan Xu 		EXT_CSD_BUS_WIDTH_4,
63949dba033SZiyuan Xu 	};
64049dba033SZiyuan Xu 	u32 bus_widths[] = {
64149dba033SZiyuan Xu 		MMC_BUS_WIDTH_8BIT,
64249dba033SZiyuan Xu 		MMC_BUS_WIDTH_4BIT,
64349dba033SZiyuan Xu 	};
64449dba033SZiyuan Xu 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
64549dba033SZiyuan Xu 	ALLOC_CACHE_ALIGN_BUFFER(u8, test_csd, MMC_MAX_BLOCK_LEN);
64649dba033SZiyuan Xu 	u32 idx, bus_width = 0;
64749dba033SZiyuan Xu 	int err = 0;
64849dba033SZiyuan Xu 
64949dba033SZiyuan Xu 	if (mmc->version < MMC_VERSION_4 ||
65049dba033SZiyuan Xu 	    !(mmc->cfg->host_caps & (MMC_MODE_4BIT | MMC_MODE_8BIT)))
65149dba033SZiyuan Xu 		return 0;
65249dba033SZiyuan Xu 
65349dba033SZiyuan Xu 	err = mmc_send_ext_csd(mmc, ext_csd);
65449dba033SZiyuan Xu 
65549dba033SZiyuan Xu 	if (err)
65649dba033SZiyuan Xu 		return err;
65749dba033SZiyuan Xu 
65849dba033SZiyuan Xu 	idx = (mmc->cfg->host_caps & MMC_MODE_8BIT) ? 0 : 1;
65949dba033SZiyuan Xu 
66049dba033SZiyuan Xu 	/*
66149dba033SZiyuan Xu 	 * Unlike SD, MMC cards dont have a configuration register to notify
66249dba033SZiyuan Xu 	 * supported bus width. So bus test command should be run to identify
66349dba033SZiyuan Xu 	 * the supported bus width or compare the ext csd values of current
66449dba033SZiyuan Xu 	 * bus width and ext csd values of 1 bit mode read earlier.
66549dba033SZiyuan Xu 	 */
66649dba033SZiyuan Xu 	for (; idx < ARRAY_SIZE(bus_widths); idx++) {
66749dba033SZiyuan Xu 		/*
66849dba033SZiyuan Xu 		 * Host is capable of 8bit transfer, then switch
66949dba033SZiyuan Xu 		 * the device to work in 8bit transfer mode. If the
67049dba033SZiyuan Xu 		 * mmc switch command returns error then switch to
67149dba033SZiyuan Xu 		 * 4bit transfer mode. On success set the corresponding
67249dba033SZiyuan Xu 		 * bus width on the host.
67349dba033SZiyuan Xu 		 */
67449dba033SZiyuan Xu 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
67549dba033SZiyuan Xu 				 EXT_CSD_BUS_WIDTH, ext_csd_bits[idx]);
67649dba033SZiyuan Xu 		if (err)
67749dba033SZiyuan Xu 			continue;
67849dba033SZiyuan Xu 
67949dba033SZiyuan Xu 		bus_width = bus_widths[idx];
68049dba033SZiyuan Xu 		mmc_set_bus_width(mmc, bus_width);
68149dba033SZiyuan Xu 
68249dba033SZiyuan Xu 		err = mmc_send_ext_csd(mmc, test_csd);
68349dba033SZiyuan Xu 
68449dba033SZiyuan Xu 		if (err)
68549dba033SZiyuan Xu 			continue;
68649dba033SZiyuan Xu 
68749dba033SZiyuan Xu 		/* Only compare read only fields */
68849dba033SZiyuan Xu 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] ==
68949dba033SZiyuan Xu 			test_csd[EXT_CSD_PARTITIONING_SUPPORT]) &&
69049dba033SZiyuan Xu 		    (ext_csd[EXT_CSD_HC_WP_GRP_SIZE] ==
69149dba033SZiyuan Xu 			test_csd[EXT_CSD_HC_WP_GRP_SIZE]) &&
69249dba033SZiyuan Xu 		    (ext_csd[EXT_CSD_REV] == test_csd[EXT_CSD_REV]) &&
69349dba033SZiyuan Xu 			(ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] ==
69449dba033SZiyuan Xu 			test_csd[EXT_CSD_HC_ERASE_GRP_SIZE]) &&
69549dba033SZiyuan Xu 		    !memcmp(&ext_csd[EXT_CSD_SEC_CNT],
69649dba033SZiyuan Xu 			&test_csd[EXT_CSD_SEC_CNT], 4)) {
69749dba033SZiyuan Xu 			err = bus_width;
69849dba033SZiyuan Xu 			break;
69949dba033SZiyuan Xu 		} else {
70049dba033SZiyuan Xu 			err = -EBADMSG;
70149dba033SZiyuan Xu 		}
70249dba033SZiyuan Xu 	}
70349dba033SZiyuan Xu 
70449dba033SZiyuan Xu 	return err;
70549dba033SZiyuan Xu }
70649dba033SZiyuan Xu 
70749dba033SZiyuan Xu static const u8 tuning_blk_pattern_4bit[] = {
70849dba033SZiyuan Xu 	0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
70949dba033SZiyuan Xu 	0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
71049dba033SZiyuan Xu 	0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
71149dba033SZiyuan Xu 	0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
71249dba033SZiyuan Xu 	0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
71349dba033SZiyuan Xu 	0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
71449dba033SZiyuan Xu 	0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
71549dba033SZiyuan Xu 	0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
71649dba033SZiyuan Xu };
71749dba033SZiyuan Xu 
71849dba033SZiyuan Xu static const u8 tuning_blk_pattern_8bit[] = {
71949dba033SZiyuan Xu 	0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
72049dba033SZiyuan Xu 	0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
72149dba033SZiyuan Xu 	0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
72249dba033SZiyuan Xu 	0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
72349dba033SZiyuan Xu 	0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
72449dba033SZiyuan Xu 	0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
72549dba033SZiyuan Xu 	0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
72649dba033SZiyuan Xu 	0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
72749dba033SZiyuan Xu 	0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
72849dba033SZiyuan Xu 	0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
72949dba033SZiyuan Xu 	0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
73049dba033SZiyuan Xu 	0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
73149dba033SZiyuan Xu 	0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
73249dba033SZiyuan Xu 	0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
73349dba033SZiyuan Xu 	0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
73449dba033SZiyuan Xu 	0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
73549dba033SZiyuan Xu };
73649dba033SZiyuan Xu 
73749dba033SZiyuan Xu int mmc_send_tuning(struct mmc *mmc, u32 opcode)
73849dba033SZiyuan Xu {
73949dba033SZiyuan Xu 	struct mmc_cmd cmd;
74049dba033SZiyuan Xu 	struct mmc_data data;
74149dba033SZiyuan Xu 	const u8 *tuning_block_pattern;
74249dba033SZiyuan Xu 	int size, err = 0;
74349dba033SZiyuan Xu 	u8 *data_buf;
74449dba033SZiyuan Xu 
74549dba033SZiyuan Xu 	if (mmc->bus_width == MMC_BUS_WIDTH_8BIT) {
74649dba033SZiyuan Xu 		tuning_block_pattern = tuning_blk_pattern_8bit;
74749dba033SZiyuan Xu 		size = sizeof(tuning_blk_pattern_8bit);
74849dba033SZiyuan Xu 	} else if (mmc->bus_width == MMC_BUS_WIDTH_4BIT) {
74949dba033SZiyuan Xu 		tuning_block_pattern = tuning_blk_pattern_4bit;
75049dba033SZiyuan Xu 		size = sizeof(tuning_blk_pattern_4bit);
75149dba033SZiyuan Xu 	} else {
75249dba033SZiyuan Xu 		return -EINVAL;
75349dba033SZiyuan Xu 	}
75449dba033SZiyuan Xu 
75549dba033SZiyuan Xu 	data_buf = calloc(1, size);
75649dba033SZiyuan Xu 	if (!data_buf)
75749dba033SZiyuan Xu 		return -ENOMEM;
75849dba033SZiyuan Xu 
75949dba033SZiyuan Xu 	cmd.cmdidx = opcode;
76049dba033SZiyuan Xu 	cmd.resp_type = MMC_RSP_R1;
76149dba033SZiyuan Xu 	cmd.cmdarg = 0;
76249dba033SZiyuan Xu 
76349dba033SZiyuan Xu 	data.dest = (char *)data_buf;
76449dba033SZiyuan Xu 	data.blocksize = size;
76549dba033SZiyuan Xu 	data.blocks = 1;
76649dba033SZiyuan Xu 	data.flags = MMC_DATA_READ;
76749dba033SZiyuan Xu 
76849dba033SZiyuan Xu 	err = mmc_send_cmd(mmc, &cmd, &data);
76949dba033SZiyuan Xu 	if (err)
77049dba033SZiyuan Xu 		goto out;
77149dba033SZiyuan Xu 
77249dba033SZiyuan Xu 	if (memcmp(data_buf, tuning_block_pattern, size))
77349dba033SZiyuan Xu 		err = -EIO;
77449dba033SZiyuan Xu out:
77549dba033SZiyuan Xu 	free(data_buf);
77649dba033SZiyuan Xu 	return err;
77749dba033SZiyuan Xu }
77849dba033SZiyuan Xu 
77949dba033SZiyuan Xu static int mmc_execute_tuning(struct mmc *mmc)
78049dba033SZiyuan Xu {
78149dba033SZiyuan Xu #ifdef CONFIG_DM_MMC
78249dba033SZiyuan Xu 	struct dm_mmc_ops *ops = mmc_get_ops(mmc->dev);
78349dba033SZiyuan Xu #endif
78449dba033SZiyuan Xu 	u32 opcode;
78549dba033SZiyuan Xu 
78649dba033SZiyuan Xu 	if (IS_SD(mmc))
78749dba033SZiyuan Xu 		opcode = MMC_SEND_TUNING_BLOCK;
78849dba033SZiyuan Xu 	else
78949dba033SZiyuan Xu 		opcode = MMC_SEND_TUNING_BLOCK_HS200;
79049dba033SZiyuan Xu 
79149dba033SZiyuan Xu #ifndef CONFIG_DM_MMC
79249dba033SZiyuan Xu 	if (mmc->cfg->ops->execute_tuning) {
79349dba033SZiyuan Xu 		return mmc->cfg->ops->execute_tuning(mmc, opcode);
79449dba033SZiyuan Xu #else
79549dba033SZiyuan Xu 	if (ops->execute_tuning) {
79649dba033SZiyuan Xu 		return ops->execute_tuning(mmc->dev, opcode);
79749dba033SZiyuan Xu #endif
79849dba033SZiyuan Xu 	} else {
79949dba033SZiyuan Xu 		debug("Tuning feature required for HS200 mode.\n");
80049dba033SZiyuan Xu 		return -EIO;
80149dba033SZiyuan Xu 	}
80249dba033SZiyuan Xu }
80349dba033SZiyuan Xu 
80449dba033SZiyuan Xu static int mmc_hs200_tuning(struct mmc *mmc)
80549dba033SZiyuan Xu {
80649dba033SZiyuan Xu 	return mmc_execute_tuning(mmc);
80749dba033SZiyuan Xu }
80849dba033SZiyuan Xu 
809e61cd3d7SZiyuan Xu static int mmc_select_hs(struct mmc *mmc)
810e61cd3d7SZiyuan Xu {
811e61cd3d7SZiyuan Xu 	int ret;
812e61cd3d7SZiyuan Xu 
813e61cd3d7SZiyuan Xu 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
814e61cd3d7SZiyuan Xu 			 EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS);
815e61cd3d7SZiyuan Xu 
816e61cd3d7SZiyuan Xu 	if (!ret)
817e61cd3d7SZiyuan Xu 		mmc_set_timing(mmc, MMC_TIMING_MMC_HS);
818e61cd3d7SZiyuan Xu 
819e61cd3d7SZiyuan Xu 	return ret;
820e61cd3d7SZiyuan Xu }
821e61cd3d7SZiyuan Xu 
8225545757fSZiyuan Xu static int mmc_select_hs_ddr(struct mmc *mmc)
8235545757fSZiyuan Xu {
8245545757fSZiyuan Xu 	u32 ext_csd_bits;
8255545757fSZiyuan Xu 	int err = 0;
8265545757fSZiyuan Xu 
8275545757fSZiyuan Xu 	if (mmc->bus_width == MMC_BUS_WIDTH_1BIT)
8285545757fSZiyuan Xu 		return 0;
8295545757fSZiyuan Xu 
8305545757fSZiyuan Xu 	ext_csd_bits = (mmc->bus_width == MMC_BUS_WIDTH_8BIT) ?
8315545757fSZiyuan Xu 			EXT_CSD_DDR_BUS_WIDTH_8 : EXT_CSD_DDR_BUS_WIDTH_4;
8325545757fSZiyuan Xu 
8335545757fSZiyuan Xu 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
8345545757fSZiyuan Xu 			 EXT_CSD_BUS_WIDTH, ext_csd_bits);
8355545757fSZiyuan Xu 	if (err)
8365545757fSZiyuan Xu 		return err;
8375545757fSZiyuan Xu 
8385545757fSZiyuan Xu 	mmc_set_timing(mmc, MMC_TIMING_MMC_DDR52);
8395545757fSZiyuan Xu 
8405545757fSZiyuan Xu 	return 0;
8415545757fSZiyuan Xu }
8425545757fSZiyuan Xu 
84349dba033SZiyuan Xu static int mmc_select_hs200(struct mmc *mmc)
84449dba033SZiyuan Xu {
84549dba033SZiyuan Xu 	int ret;
84649dba033SZiyuan Xu 
84749dba033SZiyuan Xu 	/*
84849dba033SZiyuan Xu 	 * Set the bus width(4 or 8) with host's support and
84949dba033SZiyuan Xu 	 * switch to HS200 mode if bus width is set successfully.
85049dba033SZiyuan Xu 	 */
85149dba033SZiyuan Xu 	ret = mmc_select_bus_width(mmc);
85249dba033SZiyuan Xu 
85349dba033SZiyuan Xu 	if (ret > 0) {
85449dba033SZiyuan Xu 		ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
85549dba033SZiyuan Xu 				   EXT_CSD_HS_TIMING,
85649dba033SZiyuan Xu 				   EXT_CSD_TIMING_HS200, false);
85749dba033SZiyuan Xu 
85849dba033SZiyuan Xu 		if (ret)
85949dba033SZiyuan Xu 			return ret;
86049dba033SZiyuan Xu 
86149dba033SZiyuan Xu 		mmc_set_timing(mmc, MMC_TIMING_MMC_HS200);
86249dba033SZiyuan Xu 	}
86349dba033SZiyuan Xu 
86449dba033SZiyuan Xu 	return ret;
86549dba033SZiyuan Xu }
86649dba033SZiyuan Xu 
867b673f29aSZiyuan Xu static int mmc_select_hs400(struct mmc *mmc)
868b673f29aSZiyuan Xu {
869b673f29aSZiyuan Xu 	int ret;
870b673f29aSZiyuan Xu 
871b673f29aSZiyuan Xu 	/* Switch card to HS mode */
872b673f29aSZiyuan Xu 	ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
873b673f29aSZiyuan Xu 			   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS, false);
874b673f29aSZiyuan Xu 	if (ret)
875b673f29aSZiyuan Xu 		return ret;
876b673f29aSZiyuan Xu 
877b673f29aSZiyuan Xu 	/* Set host controller to HS timing */
878b673f29aSZiyuan Xu 	mmc_set_timing(mmc, MMC_TIMING_MMC_HS);
879b673f29aSZiyuan Xu 
880b673f29aSZiyuan Xu 	/* Reduce frequency to HS frequency */
881b673f29aSZiyuan Xu 	mmc_set_clock(mmc, MMC_HIGH_52_MAX_DTR);
882b673f29aSZiyuan Xu 
883b673f29aSZiyuan Xu 	ret = mmc_send_status(mmc, 1000);
884b673f29aSZiyuan Xu 	if (ret)
885b673f29aSZiyuan Xu 		return ret;
886b673f29aSZiyuan Xu 
887b673f29aSZiyuan Xu 	/* Switch card to DDR */
888b673f29aSZiyuan Xu 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
889b673f29aSZiyuan Xu 			 EXT_CSD_BUS_WIDTH,
890b673f29aSZiyuan Xu 			 EXT_CSD_DDR_BUS_WIDTH_8);
891b673f29aSZiyuan Xu 	if (ret)
892b673f29aSZiyuan Xu 		return ret;
893b673f29aSZiyuan Xu 
894b673f29aSZiyuan Xu 	/* Switch card to HS400 */
895b673f29aSZiyuan Xu 	ret = __mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
896b673f29aSZiyuan Xu 			   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS400, false);
897b673f29aSZiyuan Xu 	if (ret)
898b673f29aSZiyuan Xu 		return ret;
899b673f29aSZiyuan Xu 
900b673f29aSZiyuan Xu 	/* Set host controller to HS400 timing and frequency */
901b673f29aSZiyuan Xu 	mmc_set_timing(mmc, MMC_TIMING_MMC_HS400);
902b673f29aSZiyuan Xu 
903b673f29aSZiyuan Xu 	return ret;
904b673f29aSZiyuan Xu }
905b673f29aSZiyuan Xu 
906227f658eSZiyuan Xu static u32 mmc_select_card_type(struct mmc *mmc, u8 *ext_csd)
907227f658eSZiyuan Xu {
908227f658eSZiyuan Xu 	u8 card_type;
909227f658eSZiyuan Xu 	u32 host_caps, avail_type = 0;
910227f658eSZiyuan Xu 
911227f658eSZiyuan Xu 	card_type = ext_csd[EXT_CSD_CARD_TYPE];
912227f658eSZiyuan Xu 	host_caps = mmc->cfg->host_caps;
913227f658eSZiyuan Xu 
914227f658eSZiyuan Xu 	if ((host_caps & MMC_MODE_HS) &&
915227f658eSZiyuan Xu 	    (card_type & EXT_CSD_CARD_TYPE_26))
916227f658eSZiyuan Xu 		avail_type |= EXT_CSD_CARD_TYPE_26;
917227f658eSZiyuan Xu 
918227f658eSZiyuan Xu 	if ((host_caps & MMC_MODE_HS) &&
919227f658eSZiyuan Xu 	    (card_type & EXT_CSD_CARD_TYPE_52))
920227f658eSZiyuan Xu 		avail_type |= EXT_CSD_CARD_TYPE_52;
921227f658eSZiyuan Xu 
922227f658eSZiyuan Xu 	/*
923227f658eSZiyuan Xu 	 * For the moment, u-boot doesn't support signal voltage
924227f658eSZiyuan Xu 	 * switch, therefor we assume that host support ddr52
925227f658eSZiyuan Xu 	 * at 1.8v or 3.3v I/O(1.2v I/O not supported, hs200 and
926227f658eSZiyuan Xu 	 * hs400 are the same).
927227f658eSZiyuan Xu 	 */
928227f658eSZiyuan Xu 	if ((host_caps & MMC_MODE_DDR_52MHz) &&
929227f658eSZiyuan Xu 	    (card_type & EXT_CSD_CARD_TYPE_DDR_1_8V))
930227f658eSZiyuan Xu 		avail_type |= EXT_CSD_CARD_TYPE_DDR_1_8V;
931227f658eSZiyuan Xu 
932227f658eSZiyuan Xu 	if ((host_caps & MMC_MODE_HS200) &&
933227f658eSZiyuan Xu 	    (card_type & EXT_CSD_CARD_TYPE_HS200_1_8V))
934227f658eSZiyuan Xu 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V;
935227f658eSZiyuan Xu 
936227f658eSZiyuan Xu 	/*
937227f658eSZiyuan Xu 	 * If host can support HS400, it means that host can also
938227f658eSZiyuan Xu 	 * support HS200.
939227f658eSZiyuan Xu 	 */
940227f658eSZiyuan Xu 	if ((host_caps & MMC_MODE_HS400) &&
941227f658eSZiyuan Xu 	    (host_caps & MMC_MODE_8BIT) &&
942227f658eSZiyuan Xu 	    (card_type & EXT_CSD_CARD_TYPE_HS400_1_8V))
943227f658eSZiyuan Xu 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V |
944227f658eSZiyuan Xu 				EXT_CSD_CARD_TYPE_HS400_1_8V;
945227f658eSZiyuan Xu 
946227f658eSZiyuan Xu 	if ((host_caps & MMC_MODE_HS400ES) &&
947227f658eSZiyuan Xu 	    (host_caps & MMC_MODE_8BIT) &&
948227f658eSZiyuan Xu 	    ext_csd[EXT_CSD_STROBE_SUPPORT] &&
949227f658eSZiyuan Xu 	    (avail_type & EXT_CSD_CARD_TYPE_HS400_1_8V))
950227f658eSZiyuan Xu 		avail_type |= EXT_CSD_CARD_TYPE_HS200_1_8V |
951227f658eSZiyuan Xu 				EXT_CSD_CARD_TYPE_HS400_1_8V |
952227f658eSZiyuan Xu 				EXT_CSD_CARD_TYPE_HS400ES;
953227f658eSZiyuan Xu 
954227f658eSZiyuan Xu 	return avail_type;
955227f658eSZiyuan Xu }
956227f658eSZiyuan Xu 
95749dba033SZiyuan Xu static void mmc_set_bus_speed(struct mmc *mmc, u8 avail_type)
95849dba033SZiyuan Xu {
95949dba033SZiyuan Xu 	int clock = 0;
96049dba033SZiyuan Xu 
96149dba033SZiyuan Xu 	if (mmc_card_hs(mmc))
96249dba033SZiyuan Xu 		clock = (avail_type & EXT_CSD_CARD_TYPE_52) ?
96349dba033SZiyuan Xu 			MMC_HIGH_52_MAX_DTR : MMC_HIGH_26_MAX_DTR;
96449dba033SZiyuan Xu 	else if (mmc_card_hs200(mmc) ||
96549dba033SZiyuan Xu 		 mmc_card_hs400(mmc) ||
96649dba033SZiyuan Xu 		 mmc_card_hs400es(mmc))
96749dba033SZiyuan Xu 		clock = MMC_HS200_MAX_DTR;
96849dba033SZiyuan Xu 
96949dba033SZiyuan Xu 	mmc_set_clock(mmc, clock);
97049dba033SZiyuan Xu }
97149dba033SZiyuan Xu 
972fdbb873eSKim Phillips static int mmc_change_freq(struct mmc *mmc)
973272cc70bSAndy Fleming {
9748bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
975227f658eSZiyuan Xu 	u32 avail_type;
976272cc70bSAndy Fleming 	int err;
977272cc70bSAndy Fleming 
978fc5b32fbSAndrew Gabbasov 	mmc->card_caps = 0;
979272cc70bSAndy Fleming 
980d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
981d52ebf10SThomas Chou 		return 0;
982d52ebf10SThomas Chou 
983272cc70bSAndy Fleming 	/* Only version 4 supports high-speed */
984272cc70bSAndy Fleming 	if (mmc->version < MMC_VERSION_4)
985272cc70bSAndy Fleming 		return 0;
986272cc70bSAndy Fleming 
987fc5b32fbSAndrew Gabbasov 	mmc->card_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
988fc5b32fbSAndrew Gabbasov 
989272cc70bSAndy Fleming 	err = mmc_send_ext_csd(mmc, ext_csd);
990272cc70bSAndy Fleming 
991272cc70bSAndy Fleming 	if (err)
992272cc70bSAndy Fleming 		return err;
993272cc70bSAndy Fleming 
994227f658eSZiyuan Xu 	avail_type = mmc_select_card_type(mmc, ext_csd);
995272cc70bSAndy Fleming 
99649dba033SZiyuan Xu 	if (avail_type & EXT_CSD_CARD_TYPE_HS200)
99749dba033SZiyuan Xu 		err = mmc_select_hs200(mmc);
998*1f250d0aSJason Zhu 	else if (avail_type & EXT_CSD_CARD_TYPE_HS)
999e61cd3d7SZiyuan Xu 		err = mmc_select_hs(mmc);
1000227f658eSZiyuan Xu 	else
1001227f658eSZiyuan Xu 		err = -EINVAL;
1002272cc70bSAndy Fleming 
1003272cc70bSAndy Fleming 	if (err)
1004a5e27b41SHeiko Schocher 		return err;
1005272cc70bSAndy Fleming 
100649dba033SZiyuan Xu 	mmc_set_bus_speed(mmc, avail_type);
1007272cc70bSAndy Fleming 
1008b673f29aSZiyuan Xu 	if (mmc_card_hs200(mmc)) {
100949dba033SZiyuan Xu 		err = mmc_hs200_tuning(mmc);
1010b673f29aSZiyuan Xu 		if (avail_type & EXT_CSD_CARD_TYPE_HS400 &&
1011b673f29aSZiyuan Xu 		    mmc->bus_width == MMC_BUS_WIDTH_8BIT) {
1012b673f29aSZiyuan Xu 			err = mmc_select_hs400(mmc);
1013b673f29aSZiyuan Xu 			mmc_set_bus_speed(mmc, avail_type);
1014b673f29aSZiyuan Xu 		}
1015b673f29aSZiyuan Xu 	} else if (!mmc_card_hs400es(mmc)) {
101649dba033SZiyuan Xu 		err = mmc_select_bus_width(mmc) > 0 ? 0 : err;
10175545757fSZiyuan Xu 		if (!err && avail_type & EXT_CSD_CARD_TYPE_DDR_52)
10185545757fSZiyuan Xu 			err = mmc_select_hs_ddr(mmc);
10195545757fSZiyuan Xu 	}
102049dba033SZiyuan Xu 
1021272cc70bSAndy Fleming 	return err;
1022272cc70bSAndy Fleming }
1023272cc70bSAndy Fleming 
1024f866a46dSStephen Warren static int mmc_set_capacity(struct mmc *mmc, int part_num)
1025f866a46dSStephen Warren {
1026f866a46dSStephen Warren 	switch (part_num) {
1027f866a46dSStephen Warren 	case 0:
1028f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_user;
1029f866a46dSStephen Warren 		break;
1030f866a46dSStephen Warren 	case 1:
1031f866a46dSStephen Warren 	case 2:
1032f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_boot;
1033f866a46dSStephen Warren 		break;
1034f866a46dSStephen Warren 	case 3:
1035f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_rpmb;
1036f866a46dSStephen Warren 		break;
1037f866a46dSStephen Warren 	case 4:
1038f866a46dSStephen Warren 	case 5:
1039f866a46dSStephen Warren 	case 6:
1040f866a46dSStephen Warren 	case 7:
1041f866a46dSStephen Warren 		mmc->capacity = mmc->capacity_gp[part_num - 4];
1042f866a46dSStephen Warren 		break;
1043f866a46dSStephen Warren 	default:
1044f866a46dSStephen Warren 		return -1;
1045f866a46dSStephen Warren 	}
1046f866a46dSStephen Warren 
1047c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len);
1048f866a46dSStephen Warren 
1049f866a46dSStephen Warren 	return 0;
1050f866a46dSStephen Warren }
1051f866a46dSStephen Warren 
10527dba0b93SSimon Glass int mmc_switch_part(struct mmc *mmc, unsigned int part_num)
1053bc897b1dSLei Wen {
1054f866a46dSStephen Warren 	int ret;
1055bc897b1dSLei Wen 
1056f866a46dSStephen Warren 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
1057bc897b1dSLei Wen 			 (mmc->part_config & ~PART_ACCESS_MASK)
1058bc897b1dSLei Wen 			 | (part_num & PART_ACCESS_MASK));
1059f866a46dSStephen Warren 
10606dc93e70SPeter Bigot 	/*
10616dc93e70SPeter Bigot 	 * Set the capacity if the switch succeeded or was intended
10626dc93e70SPeter Bigot 	 * to return to representing the raw device.
10636dc93e70SPeter Bigot 	 */
1064873cc1d7SStephen Warren 	if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) {
10656dc93e70SPeter Bigot 		ret = mmc_set_capacity(mmc, part_num);
1066fdbb139fSSimon Glass 		mmc_get_blk_desc(mmc)->hwpart = part_num;
1067873cc1d7SStephen Warren 	}
10686dc93e70SPeter Bigot 
10696dc93e70SPeter Bigot 	return ret;
1070bc897b1dSLei Wen }
1071bc897b1dSLei Wen 
1072ac9da0e0SDiego Santa Cruz int mmc_hwpart_config(struct mmc *mmc,
1073ac9da0e0SDiego Santa Cruz 		      const struct mmc_hwpart_conf *conf,
1074ac9da0e0SDiego Santa Cruz 		      enum mmc_hwpart_conf_mode mode)
1075ac9da0e0SDiego Santa Cruz {
1076ac9da0e0SDiego Santa Cruz 	u8 part_attrs = 0;
1077ac9da0e0SDiego Santa Cruz 	u32 enh_size_mult;
1078ac9da0e0SDiego Santa Cruz 	u32 enh_start_addr;
1079ac9da0e0SDiego Santa Cruz 	u32 gp_size_mult[4];
1080ac9da0e0SDiego Santa Cruz 	u32 max_enh_size_mult;
1081ac9da0e0SDiego Santa Cruz 	u32 tot_enh_size_mult = 0;
10828dda5b0eSDiego Santa Cruz 	u8 wr_rel_set;
1083ac9da0e0SDiego Santa Cruz 	int i, pidx, err;
1084ac9da0e0SDiego Santa Cruz 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
1085ac9da0e0SDiego Santa Cruz 
1086ac9da0e0SDiego Santa Cruz 	if (mode < MMC_HWPART_CONF_CHECK || mode > MMC_HWPART_CONF_COMPLETE)
1087ac9da0e0SDiego Santa Cruz 		return -EINVAL;
1088ac9da0e0SDiego Santa Cruz 
1089ac9da0e0SDiego Santa Cruz 	if (IS_SD(mmc) || (mmc->version < MMC_VERSION_4_41)) {
1090ac9da0e0SDiego Santa Cruz 		printf("eMMC >= 4.4 required for enhanced user data area\n");
1091ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1092ac9da0e0SDiego Santa Cruz 	}
1093ac9da0e0SDiego Santa Cruz 
1094ac9da0e0SDiego Santa Cruz 	if (!(mmc->part_support & PART_SUPPORT)) {
1095ac9da0e0SDiego Santa Cruz 		printf("Card does not support partitioning\n");
1096ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1097ac9da0e0SDiego Santa Cruz 	}
1098ac9da0e0SDiego Santa Cruz 
1099ac9da0e0SDiego Santa Cruz 	if (!mmc->hc_wp_grp_size) {
1100ac9da0e0SDiego Santa Cruz 		printf("Card does not define HC WP group size\n");
1101ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1102ac9da0e0SDiego Santa Cruz 	}
1103ac9da0e0SDiego Santa Cruz 
1104ac9da0e0SDiego Santa Cruz 	/* check partition alignment and total enhanced size */
1105ac9da0e0SDiego Santa Cruz 	if (conf->user.enh_size) {
1106ac9da0e0SDiego Santa Cruz 		if (conf->user.enh_size % mmc->hc_wp_grp_size ||
1107ac9da0e0SDiego Santa Cruz 		    conf->user.enh_start % mmc->hc_wp_grp_size) {
1108ac9da0e0SDiego Santa Cruz 			printf("User data enhanced area not HC WP group "
1109ac9da0e0SDiego Santa Cruz 			       "size aligned\n");
1110ac9da0e0SDiego Santa Cruz 			return -EINVAL;
1111ac9da0e0SDiego Santa Cruz 		}
1112ac9da0e0SDiego Santa Cruz 		part_attrs |= EXT_CSD_ENH_USR;
1113ac9da0e0SDiego Santa Cruz 		enh_size_mult = conf->user.enh_size / mmc->hc_wp_grp_size;
1114ac9da0e0SDiego Santa Cruz 		if (mmc->high_capacity) {
1115ac9da0e0SDiego Santa Cruz 			enh_start_addr = conf->user.enh_start;
1116ac9da0e0SDiego Santa Cruz 		} else {
1117ac9da0e0SDiego Santa Cruz 			enh_start_addr = (conf->user.enh_start << 9);
1118ac9da0e0SDiego Santa Cruz 		}
1119ac9da0e0SDiego Santa Cruz 	} else {
1120ac9da0e0SDiego Santa Cruz 		enh_size_mult = 0;
1121ac9da0e0SDiego Santa Cruz 		enh_start_addr = 0;
1122ac9da0e0SDiego Santa Cruz 	}
1123ac9da0e0SDiego Santa Cruz 	tot_enh_size_mult += enh_size_mult;
1124ac9da0e0SDiego Santa Cruz 
1125ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
1126ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size % mmc->hc_wp_grp_size) {
1127ac9da0e0SDiego Santa Cruz 			printf("GP%i partition not HC WP group size "
1128ac9da0e0SDiego Santa Cruz 			       "aligned\n", pidx+1);
1129ac9da0e0SDiego Santa Cruz 			return -EINVAL;
1130ac9da0e0SDiego Santa Cruz 		}
1131ac9da0e0SDiego Santa Cruz 		gp_size_mult[pidx] = conf->gp_part[pidx].size / mmc->hc_wp_grp_size;
1132ac9da0e0SDiego Santa Cruz 		if (conf->gp_part[pidx].size && conf->gp_part[pidx].enhanced) {
1133ac9da0e0SDiego Santa Cruz 			part_attrs |= EXT_CSD_ENH_GP(pidx);
1134ac9da0e0SDiego Santa Cruz 			tot_enh_size_mult += gp_size_mult[pidx];
1135ac9da0e0SDiego Santa Cruz 		}
1136ac9da0e0SDiego Santa Cruz 	}
1137ac9da0e0SDiego Santa Cruz 
1138ac9da0e0SDiego Santa Cruz 	if (part_attrs && ! (mmc->part_support & ENHNCD_SUPPORT)) {
1139ac9da0e0SDiego Santa Cruz 		printf("Card does not support enhanced attribute\n");
1140ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1141ac9da0e0SDiego Santa Cruz 	}
1142ac9da0e0SDiego Santa Cruz 
1143ac9da0e0SDiego Santa Cruz 	err = mmc_send_ext_csd(mmc, ext_csd);
1144ac9da0e0SDiego Santa Cruz 	if (err)
1145ac9da0e0SDiego Santa Cruz 		return err;
1146ac9da0e0SDiego Santa Cruz 
1147ac9da0e0SDiego Santa Cruz 	max_enh_size_mult =
1148ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+2] << 16) +
1149ac9da0e0SDiego Santa Cruz 		(ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT+1] << 8) +
1150ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_MAX_ENH_SIZE_MULT];
1151ac9da0e0SDiego Santa Cruz 	if (tot_enh_size_mult > max_enh_size_mult) {
1152ac9da0e0SDiego Santa Cruz 		printf("Total enhanced size exceeds maximum (%u > %u)\n",
1153ac9da0e0SDiego Santa Cruz 		       tot_enh_size_mult, max_enh_size_mult);
1154ac9da0e0SDiego Santa Cruz 		return -EMEDIUMTYPE;
1155ac9da0e0SDiego Santa Cruz 	}
1156ac9da0e0SDiego Santa Cruz 
11578dda5b0eSDiego Santa Cruz 	/* The default value of EXT_CSD_WR_REL_SET is device
11588dda5b0eSDiego Santa Cruz 	 * dependent, the values can only be changed if the
11598dda5b0eSDiego Santa Cruz 	 * EXT_CSD_HS_CTRL_REL bit is set. The values can be
11608dda5b0eSDiego Santa Cruz 	 * changed only once and before partitioning is completed. */
11618dda5b0eSDiego Santa Cruz 	wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
11628dda5b0eSDiego Santa Cruz 	if (conf->user.wr_rel_change) {
11638dda5b0eSDiego Santa Cruz 		if (conf->user.wr_rel_set)
11648dda5b0eSDiego Santa Cruz 			wr_rel_set |= EXT_CSD_WR_DATA_REL_USR;
11658dda5b0eSDiego Santa Cruz 		else
11668dda5b0eSDiego Santa Cruz 			wr_rel_set &= ~EXT_CSD_WR_DATA_REL_USR;
11678dda5b0eSDiego Santa Cruz 	}
11688dda5b0eSDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
11698dda5b0eSDiego Santa Cruz 		if (conf->gp_part[pidx].wr_rel_change) {
11708dda5b0eSDiego Santa Cruz 			if (conf->gp_part[pidx].wr_rel_set)
11718dda5b0eSDiego Santa Cruz 				wr_rel_set |= EXT_CSD_WR_DATA_REL_GP(pidx);
11728dda5b0eSDiego Santa Cruz 			else
11738dda5b0eSDiego Santa Cruz 				wr_rel_set &= ~EXT_CSD_WR_DATA_REL_GP(pidx);
11748dda5b0eSDiego Santa Cruz 		}
11758dda5b0eSDiego Santa Cruz 	}
11768dda5b0eSDiego Santa Cruz 
11778dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET] &&
11788dda5b0eSDiego Santa Cruz 	    !(ext_csd[EXT_CSD_WR_REL_PARAM] & EXT_CSD_HS_CTRL_REL)) {
11798dda5b0eSDiego Santa Cruz 		puts("Card does not support host controlled partition write "
11808dda5b0eSDiego Santa Cruz 		     "reliability settings\n");
11818dda5b0eSDiego Santa Cruz 		return -EMEDIUMTYPE;
11828dda5b0eSDiego Santa Cruz 	}
11838dda5b0eSDiego Santa Cruz 
1184ac9da0e0SDiego Santa Cruz 	if (ext_csd[EXT_CSD_PARTITION_SETTING] &
1185ac9da0e0SDiego Santa Cruz 	    EXT_CSD_PARTITION_SETTING_COMPLETED) {
1186ac9da0e0SDiego Santa Cruz 		printf("Card already partitioned\n");
1187ac9da0e0SDiego Santa Cruz 		return -EPERM;
1188ac9da0e0SDiego Santa Cruz 	}
1189ac9da0e0SDiego Santa Cruz 
1190ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_CHECK)
1191ac9da0e0SDiego Santa Cruz 		return 0;
1192ac9da0e0SDiego Santa Cruz 
1193ac9da0e0SDiego Santa Cruz 	/* Partitioning requires high-capacity size definitions */
1194ac9da0e0SDiego Santa Cruz 	if (!(ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01)) {
1195ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1196ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ERASE_GROUP_DEF, 1);
1197ac9da0e0SDiego Santa Cruz 
1198ac9da0e0SDiego Santa Cruz 		if (err)
1199ac9da0e0SDiego Santa Cruz 			return err;
1200ac9da0e0SDiego Santa Cruz 
1201ac9da0e0SDiego Santa Cruz 		ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1202ac9da0e0SDiego Santa Cruz 
1203ac9da0e0SDiego Santa Cruz 		/* update erase group size to be high-capacity */
1204ac9da0e0SDiego Santa Cruz 		mmc->erase_grp_size =
1205ac9da0e0SDiego Santa Cruz 			ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1206ac9da0e0SDiego Santa Cruz 
1207ac9da0e0SDiego Santa Cruz 	}
1208ac9da0e0SDiego Santa Cruz 
1209ac9da0e0SDiego Santa Cruz 	/* all OK, write the configuration */
1210ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 4; i++) {
1211ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1212ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_START_ADDR+i,
1213ac9da0e0SDiego Santa Cruz 				 (enh_start_addr >> (i*8)) & 0xFF);
1214ac9da0e0SDiego Santa Cruz 		if (err)
1215ac9da0e0SDiego Santa Cruz 			return err;
1216ac9da0e0SDiego Santa Cruz 	}
1217ac9da0e0SDiego Santa Cruz 	for (i = 0; i < 3; i++) {
1218ac9da0e0SDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1219ac9da0e0SDiego Santa Cruz 				 EXT_CSD_ENH_SIZE_MULT+i,
1220ac9da0e0SDiego Santa Cruz 				 (enh_size_mult >> (i*8)) & 0xFF);
1221ac9da0e0SDiego Santa Cruz 		if (err)
1222ac9da0e0SDiego Santa Cruz 			return err;
1223ac9da0e0SDiego Santa Cruz 	}
1224ac9da0e0SDiego Santa Cruz 	for (pidx = 0; pidx < 4; pidx++) {
1225ac9da0e0SDiego Santa Cruz 		for (i = 0; i < 3; i++) {
1226ac9da0e0SDiego Santa Cruz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1227ac9da0e0SDiego Santa Cruz 					 EXT_CSD_GP_SIZE_MULT+pidx*3+i,
1228ac9da0e0SDiego Santa Cruz 					 (gp_size_mult[pidx] >> (i*8)) & 0xFF);
1229ac9da0e0SDiego Santa Cruz 			if (err)
1230ac9da0e0SDiego Santa Cruz 				return err;
1231ac9da0e0SDiego Santa Cruz 		}
1232ac9da0e0SDiego Santa Cruz 	}
1233ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1234ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITIONS_ATTRIBUTE, part_attrs);
1235ac9da0e0SDiego Santa Cruz 	if (err)
1236ac9da0e0SDiego Santa Cruz 		return err;
1237ac9da0e0SDiego Santa Cruz 
1238ac9da0e0SDiego Santa Cruz 	if (mode == MMC_HWPART_CONF_SET)
1239ac9da0e0SDiego Santa Cruz 		return 0;
1240ac9da0e0SDiego Santa Cruz 
12418dda5b0eSDiego Santa Cruz 	/* The WR_REL_SET is a write-once register but shall be
12428dda5b0eSDiego Santa Cruz 	 * written before setting PART_SETTING_COMPLETED. As it is
12438dda5b0eSDiego Santa Cruz 	 * write-once we can only write it when completing the
12448dda5b0eSDiego Santa Cruz 	 * partitioning. */
12458dda5b0eSDiego Santa Cruz 	if (wr_rel_set != ext_csd[EXT_CSD_WR_REL_SET]) {
12468dda5b0eSDiego Santa Cruz 		err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
12478dda5b0eSDiego Santa Cruz 				 EXT_CSD_WR_REL_SET, wr_rel_set);
12488dda5b0eSDiego Santa Cruz 		if (err)
12498dda5b0eSDiego Santa Cruz 			return err;
12508dda5b0eSDiego Santa Cruz 	}
12518dda5b0eSDiego Santa Cruz 
1252ac9da0e0SDiego Santa Cruz 	/* Setting PART_SETTING_COMPLETED confirms the partition
1253ac9da0e0SDiego Santa Cruz 	 * configuration but it only becomes effective after power
1254ac9da0e0SDiego Santa Cruz 	 * cycle, so we do not adjust the partition related settings
1255ac9da0e0SDiego Santa Cruz 	 * in the mmc struct. */
1256ac9da0e0SDiego Santa Cruz 
1257ac9da0e0SDiego Santa Cruz 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
1258ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING,
1259ac9da0e0SDiego Santa Cruz 			 EXT_CSD_PARTITION_SETTING_COMPLETED);
1260ac9da0e0SDiego Santa Cruz 	if (err)
1261ac9da0e0SDiego Santa Cruz 		return err;
1262ac9da0e0SDiego Santa Cruz 
1263ac9da0e0SDiego Santa Cruz 	return 0;
1264ac9da0e0SDiego Santa Cruz }
1265ac9da0e0SDiego Santa Cruz 
1266e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
126748972d90SThierry Reding int mmc_getcd(struct mmc *mmc)
126848972d90SThierry Reding {
126948972d90SThierry Reding 	int cd;
127048972d90SThierry Reding 
127148972d90SThierry Reding 	cd = board_mmc_getcd(mmc);
127248972d90SThierry Reding 
1273d4e1da4eSPeter Korsgaard 	if (cd < 0) {
127493bfd616SPantelis Antoniou 		if (mmc->cfg->ops->getcd)
127593bfd616SPantelis Antoniou 			cd = mmc->cfg->ops->getcd(mmc);
1276d4e1da4eSPeter Korsgaard 		else
1277d4e1da4eSPeter Korsgaard 			cd = 1;
1278d4e1da4eSPeter Korsgaard 	}
127948972d90SThierry Reding 
128048972d90SThierry Reding 	return cd;
128148972d90SThierry Reding }
12828ca51e51SSimon Glass #endif
128348972d90SThierry Reding 
1284fdbb873eSKim Phillips static int sd_switch(struct mmc *mmc, int mode, int group, u8 value, u8 *resp)
1285272cc70bSAndy Fleming {
1286272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1287272cc70bSAndy Fleming 	struct mmc_data data;
1288272cc70bSAndy Fleming 
1289272cc70bSAndy Fleming 	/* Switch the frequency */
1290272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SWITCH_FUNC;
1291272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1292272cc70bSAndy Fleming 	cmd.cmdarg = (mode << 31) | 0xffffff;
1293272cc70bSAndy Fleming 	cmd.cmdarg &= ~(0xf << (group * 4));
1294272cc70bSAndy Fleming 	cmd.cmdarg |= value << (group * 4);
1295272cc70bSAndy Fleming 
1296272cc70bSAndy Fleming 	data.dest = (char *)resp;
1297272cc70bSAndy Fleming 	data.blocksize = 64;
1298272cc70bSAndy Fleming 	data.blocks = 1;
1299272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
1300272cc70bSAndy Fleming 
1301272cc70bSAndy Fleming 	return mmc_send_cmd(mmc, &cmd, &data);
1302272cc70bSAndy Fleming }
1303272cc70bSAndy Fleming 
1304272cc70bSAndy Fleming 
1305fdbb873eSKim Phillips static int sd_change_freq(struct mmc *mmc)
1306272cc70bSAndy Fleming {
1307272cc70bSAndy Fleming 	int err;
1308272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1309f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, scr, 2);
1310f781dd38SAnton staaf 	ALLOC_CACHE_ALIGN_BUFFER(uint, switch_status, 16);
1311272cc70bSAndy Fleming 	struct mmc_data data;
1312272cc70bSAndy Fleming 	int timeout;
1313272cc70bSAndy Fleming 
1314272cc70bSAndy Fleming 	mmc->card_caps = 0;
1315272cc70bSAndy Fleming 
1316d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc))
1317d52ebf10SThomas Chou 		return 0;
1318d52ebf10SThomas Chou 
1319272cc70bSAndy Fleming 	/* Read the SCR to find out if this card supports higher speeds */
1320272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_APP_CMD;
1321272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1322272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1323272cc70bSAndy Fleming 
1324272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1325272cc70bSAndy Fleming 
1326272cc70bSAndy Fleming 	if (err)
1327272cc70bSAndy Fleming 		return err;
1328272cc70bSAndy Fleming 
1329272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_APP_SEND_SCR;
1330272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R1;
1331272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1332272cc70bSAndy Fleming 
1333272cc70bSAndy Fleming 	timeout = 3;
1334272cc70bSAndy Fleming 
1335272cc70bSAndy Fleming retry_scr:
1336f781dd38SAnton staaf 	data.dest = (char *)scr;
1337272cc70bSAndy Fleming 	data.blocksize = 8;
1338272cc70bSAndy Fleming 	data.blocks = 1;
1339272cc70bSAndy Fleming 	data.flags = MMC_DATA_READ;
1340272cc70bSAndy Fleming 
1341272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, &data);
1342272cc70bSAndy Fleming 
1343272cc70bSAndy Fleming 	if (err) {
1344272cc70bSAndy Fleming 		if (timeout--)
1345272cc70bSAndy Fleming 			goto retry_scr;
1346272cc70bSAndy Fleming 
1347272cc70bSAndy Fleming 		return err;
1348272cc70bSAndy Fleming 	}
1349272cc70bSAndy Fleming 
13504e3d89baSYauhen Kharuzhy 	mmc->scr[0] = __be32_to_cpu(scr[0]);
13514e3d89baSYauhen Kharuzhy 	mmc->scr[1] = __be32_to_cpu(scr[1]);
1352272cc70bSAndy Fleming 
1353272cc70bSAndy Fleming 	switch ((mmc->scr[0] >> 24) & 0xf) {
1354272cc70bSAndy Fleming 	case 0:
1355272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1356272cc70bSAndy Fleming 		break;
1357272cc70bSAndy Fleming 	case 1:
1358272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_10;
1359272cc70bSAndy Fleming 		break;
1360272cc70bSAndy Fleming 	case 2:
1361272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
13621741c64dSJaehoon Chung 		if ((mmc->scr[0] >> 15) & 0x1)
13631741c64dSJaehoon Chung 			mmc->version = SD_VERSION_3;
1364272cc70bSAndy Fleming 		break;
1365272cc70bSAndy Fleming 	default:
1366272cc70bSAndy Fleming 		mmc->version = SD_VERSION_1_0;
1367272cc70bSAndy Fleming 		break;
1368272cc70bSAndy Fleming 	}
1369272cc70bSAndy Fleming 
1370b44c7083SAlagu Sankar 	if (mmc->scr[0] & SD_DATA_4BIT)
1371b44c7083SAlagu Sankar 		mmc->card_caps |= MMC_MODE_4BIT;
1372b44c7083SAlagu Sankar 
1373272cc70bSAndy Fleming 	/* Version 1.0 doesn't support switching */
1374272cc70bSAndy Fleming 	if (mmc->version == SD_VERSION_1_0)
1375272cc70bSAndy Fleming 		return 0;
1376272cc70bSAndy Fleming 
1377272cc70bSAndy Fleming 	timeout = 4;
1378272cc70bSAndy Fleming 	while (timeout--) {
1379272cc70bSAndy Fleming 		err = sd_switch(mmc, SD_SWITCH_CHECK, 0, 1,
1380f781dd38SAnton staaf 				(u8 *)switch_status);
1381272cc70bSAndy Fleming 
1382272cc70bSAndy Fleming 		if (err)
1383272cc70bSAndy Fleming 			return err;
1384272cc70bSAndy Fleming 
1385272cc70bSAndy Fleming 		/* The high-speed function is busy.  Try again */
13864e3d89baSYauhen Kharuzhy 		if (!(__be32_to_cpu(switch_status[7]) & SD_HIGHSPEED_BUSY))
1387272cc70bSAndy Fleming 			break;
1388272cc70bSAndy Fleming 	}
1389272cc70bSAndy Fleming 
1390272cc70bSAndy Fleming 	/* If high-speed isn't supported, we return */
13914e3d89baSYauhen Kharuzhy 	if (!(__be32_to_cpu(switch_status[3]) & SD_HIGHSPEED_SUPPORTED))
1392272cc70bSAndy Fleming 		return 0;
1393272cc70bSAndy Fleming 
13942c3fbf4cSMacpaul Lin 	/*
13952c3fbf4cSMacpaul Lin 	 * If the host doesn't support SD_HIGHSPEED, do not switch card to
13962c3fbf4cSMacpaul Lin 	 * HIGHSPEED mode even if the card support SD_HIGHSPPED.
13972c3fbf4cSMacpaul Lin 	 * This can avoid furthur problem when the card runs in different
13982c3fbf4cSMacpaul Lin 	 * mode between the host.
13992c3fbf4cSMacpaul Lin 	 */
140093bfd616SPantelis Antoniou 	if (!((mmc->cfg->host_caps & MMC_MODE_HS_52MHz) &&
140193bfd616SPantelis Antoniou 		(mmc->cfg->host_caps & MMC_MODE_HS)))
14022c3fbf4cSMacpaul Lin 		return 0;
14032c3fbf4cSMacpaul Lin 
1404f781dd38SAnton staaf 	err = sd_switch(mmc, SD_SWITCH_SWITCH, 0, 1, (u8 *)switch_status);
1405272cc70bSAndy Fleming 
1406272cc70bSAndy Fleming 	if (err)
1407272cc70bSAndy Fleming 		return err;
1408272cc70bSAndy Fleming 
14094e3d89baSYauhen Kharuzhy 	if ((__be32_to_cpu(switch_status[4]) & 0x0f000000) == 0x01000000)
1410272cc70bSAndy Fleming 		mmc->card_caps |= MMC_MODE_HS;
1411272cc70bSAndy Fleming 
1412272cc70bSAndy Fleming 	return 0;
1413272cc70bSAndy Fleming }
1414272cc70bSAndy Fleming 
14153697e599SPeng Fan static int sd_read_ssr(struct mmc *mmc)
14163697e599SPeng Fan {
14173697e599SPeng Fan 	int err, i;
14183697e599SPeng Fan 	struct mmc_cmd cmd;
14193697e599SPeng Fan 	ALLOC_CACHE_ALIGN_BUFFER(uint, ssr, 16);
14203697e599SPeng Fan 	struct mmc_data data;
14213697e599SPeng Fan 	int timeout = 3;
14223697e599SPeng Fan 	unsigned int au, eo, et, es;
14233697e599SPeng Fan 
14243697e599SPeng Fan 	cmd.cmdidx = MMC_CMD_APP_CMD;
14253697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
14263697e599SPeng Fan 	cmd.cmdarg = mmc->rca << 16;
14273697e599SPeng Fan 
14283697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, NULL);
14293697e599SPeng Fan 	if (err)
14303697e599SPeng Fan 		return err;
14313697e599SPeng Fan 
14323697e599SPeng Fan 	cmd.cmdidx = SD_CMD_APP_SD_STATUS;
14333697e599SPeng Fan 	cmd.resp_type = MMC_RSP_R1;
14343697e599SPeng Fan 	cmd.cmdarg = 0;
14353697e599SPeng Fan 
14363697e599SPeng Fan retry_ssr:
14373697e599SPeng Fan 	data.dest = (char *)ssr;
14383697e599SPeng Fan 	data.blocksize = 64;
14393697e599SPeng Fan 	data.blocks = 1;
14403697e599SPeng Fan 	data.flags = MMC_DATA_READ;
14413697e599SPeng Fan 
14423697e599SPeng Fan 	err = mmc_send_cmd(mmc, &cmd, &data);
14433697e599SPeng Fan 	if (err) {
14443697e599SPeng Fan 		if (timeout--)
14453697e599SPeng Fan 			goto retry_ssr;
14463697e599SPeng Fan 
14473697e599SPeng Fan 		return err;
14483697e599SPeng Fan 	}
14493697e599SPeng Fan 
14503697e599SPeng Fan 	for (i = 0; i < 16; i++)
14513697e599SPeng Fan 		ssr[i] = be32_to_cpu(ssr[i]);
14523697e599SPeng Fan 
14533697e599SPeng Fan 	au = (ssr[2] >> 12) & 0xF;
14543697e599SPeng Fan 	if ((au <= 9) || (mmc->version == SD_VERSION_3)) {
14553697e599SPeng Fan 		mmc->ssr.au = sd_au_size[au];
14563697e599SPeng Fan 		es = (ssr[3] >> 24) & 0xFF;
14573697e599SPeng Fan 		es |= (ssr[2] & 0xFF) << 8;
14583697e599SPeng Fan 		et = (ssr[3] >> 18) & 0x3F;
14593697e599SPeng Fan 		if (es && et) {
14603697e599SPeng Fan 			eo = (ssr[3] >> 16) & 0x3;
14613697e599SPeng Fan 			mmc->ssr.erase_timeout = (et * 1000) / es;
14623697e599SPeng Fan 			mmc->ssr.erase_offset = eo * 1000;
14633697e599SPeng Fan 		}
14643697e599SPeng Fan 	} else {
14653697e599SPeng Fan 		debug("Invalid Allocation Unit Size.\n");
14663697e599SPeng Fan 	}
14673697e599SPeng Fan 
14683697e599SPeng Fan 	return 0;
14693697e599SPeng Fan }
14703697e599SPeng Fan 
1471272cc70bSAndy Fleming /* frequency bases */
1472272cc70bSAndy Fleming /* divided by 10 to be nice to platforms without floating point */
14735f837c2cSMike Frysinger static const int fbase[] = {
1474272cc70bSAndy Fleming 	10000,
1475272cc70bSAndy Fleming 	100000,
1476272cc70bSAndy Fleming 	1000000,
1477272cc70bSAndy Fleming 	10000000,
1478272cc70bSAndy Fleming };
1479272cc70bSAndy Fleming 
1480272cc70bSAndy Fleming /* Multiplier values for TRAN_SPEED.  Multiplied by 10 to be nice
1481272cc70bSAndy Fleming  * to platforms without floating point.
1482272cc70bSAndy Fleming  */
148361fe076fSSimon Glass static const u8 multipliers[] = {
1484272cc70bSAndy Fleming 	0,	/* reserved */
1485272cc70bSAndy Fleming 	10,
1486272cc70bSAndy Fleming 	12,
1487272cc70bSAndy Fleming 	13,
1488272cc70bSAndy Fleming 	15,
1489272cc70bSAndy Fleming 	20,
1490272cc70bSAndy Fleming 	25,
1491272cc70bSAndy Fleming 	30,
1492272cc70bSAndy Fleming 	35,
1493272cc70bSAndy Fleming 	40,
1494272cc70bSAndy Fleming 	45,
1495272cc70bSAndy Fleming 	50,
1496272cc70bSAndy Fleming 	55,
1497272cc70bSAndy Fleming 	60,
1498272cc70bSAndy Fleming 	70,
1499272cc70bSAndy Fleming 	80,
1500272cc70bSAndy Fleming };
1501272cc70bSAndy Fleming 
1502e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
1503fdbb873eSKim Phillips static void mmc_set_ios(struct mmc *mmc)
1504272cc70bSAndy Fleming {
150593bfd616SPantelis Antoniou 	if (mmc->cfg->ops->set_ios)
150693bfd616SPantelis Antoniou 		mmc->cfg->ops->set_ios(mmc);
1507272cc70bSAndy Fleming }
1508ad77484aSZiyuan Xu 
1509ad77484aSZiyuan Xu static bool mmc_card_busy(struct mmc *mmc)
1510ad77484aSZiyuan Xu {
1511ad77484aSZiyuan Xu 	if (!mmc->cfg->ops->card_busy)
1512ad77484aSZiyuan Xu 		return -ENOSYS;
1513ad77484aSZiyuan Xu 
1514ad77484aSZiyuan Xu 	return mmc->cfg->ops->card_busy(mmc);
1515ad77484aSZiyuan Xu }
1516ad77484aSZiyuan Xu 
1517ad77484aSZiyuan Xu static bool mmc_can_card_busy(struct mmc *)
1518ad77484aSZiyuan Xu {
1519ad77484aSZiyuan Xu 	return !!mmc->cfg->ops->card_busy;
1520ad77484aSZiyuan Xu }
15218ca51e51SSimon Glass #endif
1522272cc70bSAndy Fleming 
1523fdbb873eSKim Phillips static int mmc_startup(struct mmc *mmc)
1524272cc70bSAndy Fleming {
1525f866a46dSStephen Warren 	int err, i;
15263e3ff0acSZiyuan Xu 	uint mult, freq, tran_speed;
1527639b7827SYoshihiro Shimoda 	u64 cmult, csize, capacity;
1528272cc70bSAndy Fleming 	struct mmc_cmd cmd;
15298bfa195eSSimon Glass 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
15300c453bb7SDiego Santa Cruz 	bool has_parts = false;
15318a0cf490SDiego Santa Cruz 	bool part_completed;
1532c40fdca6SSimon Glass 	struct blk_desc *bdesc;
1533272cc70bSAndy Fleming 
1534d52ebf10SThomas Chou #ifdef CONFIG_MMC_SPI_CRC_ON
1535d52ebf10SThomas Chou 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
1536d52ebf10SThomas Chou 		cmd.cmdidx = MMC_CMD_SPI_CRC_ON_OFF;
1537d52ebf10SThomas Chou 		cmd.resp_type = MMC_RSP_R1;
1538d52ebf10SThomas Chou 		cmd.cmdarg = 1;
1539d52ebf10SThomas Chou 		err = mmc_send_cmd(mmc, &cmd, NULL);
1540d52ebf10SThomas Chou 
1541d52ebf10SThomas Chou 		if (err)
1542d52ebf10SThomas Chou 			return err;
1543d52ebf10SThomas Chou 	}
1544d52ebf10SThomas Chou #endif
1545d52ebf10SThomas Chou 
1546272cc70bSAndy Fleming 	/* Put the Card in Identify Mode */
1547d52ebf10SThomas Chou 	cmd.cmdidx = mmc_host_is_spi(mmc) ? MMC_CMD_SEND_CID :
1548d52ebf10SThomas Chou 		MMC_CMD_ALL_SEND_CID; /* cmd not supported in spi */
1549272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1550272cc70bSAndy Fleming 	cmd.cmdarg = 0;
1551272cc70bSAndy Fleming 
1552272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1553272cc70bSAndy Fleming 
1554272cc70bSAndy Fleming 	if (err)
1555272cc70bSAndy Fleming 		return err;
1556272cc70bSAndy Fleming 
1557272cc70bSAndy Fleming 	memcpy(mmc->cid, cmd.response, 16);
1558272cc70bSAndy Fleming 
1559272cc70bSAndy Fleming 	/*
1560272cc70bSAndy Fleming 	 * For MMC cards, set the Relative Address.
1561272cc70bSAndy Fleming 	 * For SD cards, get the Relatvie Address.
1562272cc70bSAndy Fleming 	 * This also puts the cards into Standby State
1563272cc70bSAndy Fleming 	 */
1564d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1565272cc70bSAndy Fleming 		cmd.cmdidx = SD_CMD_SEND_RELATIVE_ADDR;
1566272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1567272cc70bSAndy Fleming 		cmd.resp_type = MMC_RSP_R6;
1568272cc70bSAndy Fleming 
1569272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1570272cc70bSAndy Fleming 
1571272cc70bSAndy Fleming 		if (err)
1572272cc70bSAndy Fleming 			return err;
1573272cc70bSAndy Fleming 
1574272cc70bSAndy Fleming 		if (IS_SD(mmc))
1575998be3ddSRabin Vincent 			mmc->rca = (cmd.response[0] >> 16) & 0xffff;
1576d52ebf10SThomas Chou 	}
1577272cc70bSAndy Fleming 
1578272cc70bSAndy Fleming 	/* Get the Card-Specific Data */
1579272cc70bSAndy Fleming 	cmd.cmdidx = MMC_CMD_SEND_CSD;
1580272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R2;
1581272cc70bSAndy Fleming 	cmd.cmdarg = mmc->rca << 16;
1582272cc70bSAndy Fleming 
1583272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1584272cc70bSAndy Fleming 
1585272cc70bSAndy Fleming 	if (err)
1586272cc70bSAndy Fleming 		return err;
1587272cc70bSAndy Fleming 
1588998be3ddSRabin Vincent 	mmc->csd[0] = cmd.response[0];
1589998be3ddSRabin Vincent 	mmc->csd[1] = cmd.response[1];
1590998be3ddSRabin Vincent 	mmc->csd[2] = cmd.response[2];
1591998be3ddSRabin Vincent 	mmc->csd[3] = cmd.response[3];
1592272cc70bSAndy Fleming 
1593272cc70bSAndy Fleming 	if (mmc->version == MMC_VERSION_UNKNOWN) {
15940b453ffeSRabin Vincent 		int version = (cmd.response[0] >> 26) & 0xf;
1595272cc70bSAndy Fleming 
1596272cc70bSAndy Fleming 		switch (version) {
1597272cc70bSAndy Fleming 		case 0:
1598272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1599272cc70bSAndy Fleming 			break;
1600272cc70bSAndy Fleming 		case 1:
1601272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_4;
1602272cc70bSAndy Fleming 			break;
1603272cc70bSAndy Fleming 		case 2:
1604272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_2_2;
1605272cc70bSAndy Fleming 			break;
1606272cc70bSAndy Fleming 		case 3:
1607272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_3;
1608272cc70bSAndy Fleming 			break;
1609272cc70bSAndy Fleming 		case 4:
1610272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_4;
1611272cc70bSAndy Fleming 			break;
1612272cc70bSAndy Fleming 		default:
1613272cc70bSAndy Fleming 			mmc->version = MMC_VERSION_1_2;
1614272cc70bSAndy Fleming 			break;
1615272cc70bSAndy Fleming 		}
1616272cc70bSAndy Fleming 	}
1617272cc70bSAndy Fleming 
1618272cc70bSAndy Fleming 	/* divide frequency by 10, since the mults are 10x bigger */
16190b453ffeSRabin Vincent 	freq = fbase[(cmd.response[0] & 0x7)];
16200b453ffeSRabin Vincent 	mult = multipliers[((cmd.response[0] >> 3) & 0xf)];
1621272cc70bSAndy Fleming 
16223e3ff0acSZiyuan Xu 	tran_speed = freq * mult;
1623272cc70bSAndy Fleming 
1624ab71188cSMarkus Niebel 	mmc->dsr_imp = ((cmd.response[1] >> 12) & 0x1);
1625998be3ddSRabin Vincent 	mmc->read_bl_len = 1 << ((cmd.response[1] >> 16) & 0xf);
1626272cc70bSAndy Fleming 
1627272cc70bSAndy Fleming 	if (IS_SD(mmc))
1628272cc70bSAndy Fleming 		mmc->write_bl_len = mmc->read_bl_len;
1629272cc70bSAndy Fleming 	else
1630998be3ddSRabin Vincent 		mmc->write_bl_len = 1 << ((cmd.response[3] >> 22) & 0xf);
1631272cc70bSAndy Fleming 
1632272cc70bSAndy Fleming 	if (mmc->high_capacity) {
1633272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3f) << 16
1634272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xffff0000) >> 16;
1635272cc70bSAndy Fleming 		cmult = 8;
1636272cc70bSAndy Fleming 	} else {
1637272cc70bSAndy Fleming 		csize = (mmc->csd[1] & 0x3ff) << 2
1638272cc70bSAndy Fleming 			| (mmc->csd[2] & 0xc0000000) >> 30;
1639272cc70bSAndy Fleming 		cmult = (mmc->csd[2] & 0x00038000) >> 15;
1640272cc70bSAndy Fleming 	}
1641272cc70bSAndy Fleming 
1642f866a46dSStephen Warren 	mmc->capacity_user = (csize + 1) << (cmult + 2);
1643f866a46dSStephen Warren 	mmc->capacity_user *= mmc->read_bl_len;
1644f866a46dSStephen Warren 	mmc->capacity_boot = 0;
1645f866a46dSStephen Warren 	mmc->capacity_rpmb = 0;
1646f866a46dSStephen Warren 	for (i = 0; i < 4; i++)
1647f866a46dSStephen Warren 		mmc->capacity_gp[i] = 0;
1648272cc70bSAndy Fleming 
16498bfa195eSSimon Glass 	if (mmc->read_bl_len > MMC_MAX_BLOCK_LEN)
16508bfa195eSSimon Glass 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
1651272cc70bSAndy Fleming 
16528bfa195eSSimon Glass 	if (mmc->write_bl_len > MMC_MAX_BLOCK_LEN)
16538bfa195eSSimon Glass 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
1654272cc70bSAndy Fleming 
1655ab71188cSMarkus Niebel 	if ((mmc->dsr_imp) && (0xffffffff != mmc->dsr)) {
1656ab71188cSMarkus Niebel 		cmd.cmdidx = MMC_CMD_SET_DSR;
1657ab71188cSMarkus Niebel 		cmd.cmdarg = (mmc->dsr & 0xffff) << 16;
1658ab71188cSMarkus Niebel 		cmd.resp_type = MMC_RSP_NONE;
1659ab71188cSMarkus Niebel 		if (mmc_send_cmd(mmc, &cmd, NULL))
1660ab71188cSMarkus Niebel 			printf("MMC: SET_DSR failed\n");
1661ab71188cSMarkus Niebel 	}
1662ab71188cSMarkus Niebel 
1663272cc70bSAndy Fleming 	/* Select the card, and put it into Transfer Mode */
1664d52ebf10SThomas Chou 	if (!mmc_host_is_spi(mmc)) { /* cmd not supported in spi */
1665272cc70bSAndy Fleming 		cmd.cmdidx = MMC_CMD_SELECT_CARD;
1666fe8f7066SAjay Bhargav 		cmd.resp_type = MMC_RSP_R1;
1667272cc70bSAndy Fleming 		cmd.cmdarg = mmc->rca << 16;
1668272cc70bSAndy Fleming 		err = mmc_send_cmd(mmc, &cmd, NULL);
1669272cc70bSAndy Fleming 
1670272cc70bSAndy Fleming 		if (err)
1671272cc70bSAndy Fleming 			return err;
1672d52ebf10SThomas Chou 	}
1673272cc70bSAndy Fleming 
1674e6f99a56SLei Wen 	/*
1675e6f99a56SLei Wen 	 * For SD, its erase group is always one sector
1676e6f99a56SLei Wen 	 */
1677e6f99a56SLei Wen 	mmc->erase_grp_size = 1;
1678bc897b1dSLei Wen 	mmc->part_config = MMCPART_NOAVAILABLE;
1679d23e2c09SSukumar Ghorai 	if (!IS_SD(mmc) && (mmc->version >= MMC_VERSION_4)) {
1680d23e2c09SSukumar Ghorai 		/* check  ext_csd version and capacity */
1681d23e2c09SSukumar Ghorai 		err = mmc_send_ext_csd(mmc, ext_csd);
16829cf199ebSDiego Santa Cruz 		if (err)
16839cf199ebSDiego Santa Cruz 			return err;
16849cf199ebSDiego Santa Cruz 		if (ext_csd[EXT_CSD_REV] >= 2) {
1685639b7827SYoshihiro Shimoda 			/*
1686639b7827SYoshihiro Shimoda 			 * According to the JEDEC Standard, the value of
1687639b7827SYoshihiro Shimoda 			 * ext_csd's capacity is valid if the value is more
1688639b7827SYoshihiro Shimoda 			 * than 2GB
1689639b7827SYoshihiro Shimoda 			 */
16900560db18SLei Wen 			capacity = ext_csd[EXT_CSD_SEC_CNT] << 0
16910560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 1] << 8
16920560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 2] << 16
16930560db18SLei Wen 					| ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
16948bfa195eSSimon Glass 			capacity *= MMC_MAX_BLOCK_LEN;
1695b1f1e821SŁukasz Majewski 			if ((capacity >> 20) > 2 * 1024)
1696f866a46dSStephen Warren 				mmc->capacity_user = capacity;
1697d23e2c09SSukumar Ghorai 		}
1698bc897b1dSLei Wen 
169964f4a619SJaehoon Chung 		switch (ext_csd[EXT_CSD_REV]) {
170064f4a619SJaehoon Chung 		case 1:
170164f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_1;
170264f4a619SJaehoon Chung 			break;
170364f4a619SJaehoon Chung 		case 2:
170464f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_2;
170564f4a619SJaehoon Chung 			break;
170664f4a619SJaehoon Chung 		case 3:
170764f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_3;
170864f4a619SJaehoon Chung 			break;
170964f4a619SJaehoon Chung 		case 5:
171064f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_41;
171164f4a619SJaehoon Chung 			break;
171264f4a619SJaehoon Chung 		case 6:
171364f4a619SJaehoon Chung 			mmc->version = MMC_VERSION_4_5;
171464f4a619SJaehoon Chung 			break;
1715edab723bSMarkus Niebel 		case 7:
1716edab723bSMarkus Niebel 			mmc->version = MMC_VERSION_5_0;
1717edab723bSMarkus Niebel 			break;
17181a3619cfSStefan Wahren 		case 8:
17191a3619cfSStefan Wahren 			mmc->version = MMC_VERSION_5_1;
17201a3619cfSStefan Wahren 			break;
172164f4a619SJaehoon Chung 		}
172264f4a619SJaehoon Chung 
17238a0cf490SDiego Santa Cruz 		/* The partition data may be non-zero but it is only
17248a0cf490SDiego Santa Cruz 		 * effective if PARTITION_SETTING_COMPLETED is set in
17258a0cf490SDiego Santa Cruz 		 * EXT_CSD, so ignore any data if this bit is not set,
17268a0cf490SDiego Santa Cruz 		 * except for enabling the high-capacity group size
17278a0cf490SDiego Santa Cruz 		 * definition (see below). */
17288a0cf490SDiego Santa Cruz 		part_completed = !!(ext_csd[EXT_CSD_PARTITION_SETTING] &
17298a0cf490SDiego Santa Cruz 				    EXT_CSD_PARTITION_SETTING_COMPLETED);
17308a0cf490SDiego Santa Cruz 
17310c453bb7SDiego Santa Cruz 		/* store the partition info of emmc */
17320c453bb7SDiego Santa Cruz 		mmc->part_support = ext_csd[EXT_CSD_PARTITIONING_SUPPORT];
17330c453bb7SDiego Santa Cruz 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) ||
17340c453bb7SDiego Santa Cruz 		    ext_csd[EXT_CSD_BOOT_MULT])
17350c453bb7SDiego Santa Cruz 			mmc->part_config = ext_csd[EXT_CSD_PART_CONF];
17368a0cf490SDiego Santa Cruz 		if (part_completed &&
17378a0cf490SDiego Santa Cruz 		    (ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & ENHNCD_SUPPORT))
17380c453bb7SDiego Santa Cruz 			mmc->part_attr = ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE];
1739a6a1f5f8SJason Zhu 		if (ext_csd[EXT_CSD_SEC_FEATURE_SUPPORT] & EXT_CSD_SEC_GB_CL_EN)
1740a6a1f5f8SJason Zhu 			mmc->esr.mmc_can_trim = 1;
17410c453bb7SDiego Santa Cruz 
17420c453bb7SDiego Santa Cruz 		mmc->capacity_boot = ext_csd[EXT_CSD_BOOT_MULT] << 17;
17430c453bb7SDiego Santa Cruz 
17440c453bb7SDiego Santa Cruz 		mmc->capacity_rpmb = ext_csd[EXT_CSD_RPMB_MULT] << 17;
17450c453bb7SDiego Santa Cruz 
17460c453bb7SDiego Santa Cruz 		for (i = 0; i < 4; i++) {
17470c453bb7SDiego Santa Cruz 			int idx = EXT_CSD_GP_SIZE_MULT + i * 3;
17488a0cf490SDiego Santa Cruz 			uint mult = (ext_csd[idx + 2] << 16) +
17490c453bb7SDiego Santa Cruz 				(ext_csd[idx + 1] << 8) + ext_csd[idx];
17508a0cf490SDiego Santa Cruz 			if (mult)
17518a0cf490SDiego Santa Cruz 				has_parts = true;
17528a0cf490SDiego Santa Cruz 			if (!part_completed)
17538a0cf490SDiego Santa Cruz 				continue;
17548a0cf490SDiego Santa Cruz 			mmc->capacity_gp[i] = mult;
17550c453bb7SDiego Santa Cruz 			mmc->capacity_gp[i] *=
17560c453bb7SDiego Santa Cruz 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
17570c453bb7SDiego Santa Cruz 			mmc->capacity_gp[i] *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1758f8e89d67SDiego Santa Cruz 			mmc->capacity_gp[i] <<= 19;
17590c453bb7SDiego Santa Cruz 		}
17600c453bb7SDiego Santa Cruz 
17618a0cf490SDiego Santa Cruz 		if (part_completed) {
1762a7f852b6SDiego Santa Cruz 			mmc->enh_user_size =
1763a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_SIZE_MULT+2] << 16) +
1764a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_SIZE_MULT+1] << 8) +
1765a7f852b6SDiego Santa Cruz 				ext_csd[EXT_CSD_ENH_SIZE_MULT];
1766a7f852b6SDiego Santa Cruz 			mmc->enh_user_size *= ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE];
1767a7f852b6SDiego Santa Cruz 			mmc->enh_user_size *= ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
1768a7f852b6SDiego Santa Cruz 			mmc->enh_user_size <<= 19;
1769a7f852b6SDiego Santa Cruz 			mmc->enh_user_start =
1770a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+3] << 24) +
1771a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+2] << 16) +
1772a7f852b6SDiego Santa Cruz 				(ext_csd[EXT_CSD_ENH_START_ADDR+1] << 8) +
1773a7f852b6SDiego Santa Cruz 				ext_csd[EXT_CSD_ENH_START_ADDR];
1774a7f852b6SDiego Santa Cruz 			if (mmc->high_capacity)
1775a7f852b6SDiego Santa Cruz 				mmc->enh_user_start <<= 9;
17768a0cf490SDiego Santa Cruz 		}
1777a7f852b6SDiego Santa Cruz 
1778e6f99a56SLei Wen 		/*
17791937e5aaSOliver Metz 		 * Host needs to enable ERASE_GRP_DEF bit if device is
17801937e5aaSOliver Metz 		 * partitioned. This bit will be lost every time after a reset
17811937e5aaSOliver Metz 		 * or power off. This will affect erase size.
1782e6f99a56SLei Wen 		 */
17838a0cf490SDiego Santa Cruz 		if (part_completed)
17840c453bb7SDiego Santa Cruz 			has_parts = true;
17851937e5aaSOliver Metz 		if ((ext_csd[EXT_CSD_PARTITIONING_SUPPORT] & PART_SUPPORT) &&
17860c453bb7SDiego Santa Cruz 		    (ext_csd[EXT_CSD_PARTITIONS_ATTRIBUTE] & PART_ENH_ATTRIB))
17870c453bb7SDiego Santa Cruz 			has_parts = true;
17880c453bb7SDiego Santa Cruz 		if (has_parts) {
17891937e5aaSOliver Metz 			err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL,
17901937e5aaSOliver Metz 				EXT_CSD_ERASE_GROUP_DEF, 1);
17911937e5aaSOliver Metz 
17921937e5aaSOliver Metz 			if (err)
17931937e5aaSOliver Metz 				return err;
1794021a8055SHannes Petermaier 			else
1795021a8055SHannes Petermaier 				ext_csd[EXT_CSD_ERASE_GROUP_DEF] = 1;
1796037dc0abSDiego Santa Cruz 		}
17971937e5aaSOliver Metz 
1798037dc0abSDiego Santa Cruz 		if (ext_csd[EXT_CSD_ERASE_GROUP_DEF] & 0x01) {
17991937e5aaSOliver Metz 			/* Read out group size from ext_csd */
18000560db18SLei Wen 			mmc->erase_grp_size =
1801a4ff9f83SDiego Santa Cruz 				ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE] * 1024;
1802d7b29129SMarkus Niebel 			/*
1803d7b29129SMarkus Niebel 			 * if high capacity and partition setting completed
1804d7b29129SMarkus Niebel 			 * SEC_COUNT is valid even if it is smaller than 2 GiB
1805d7b29129SMarkus Niebel 			 * JEDEC Standard JESD84-B45, 6.2.4
1806d7b29129SMarkus Niebel 			 */
18078a0cf490SDiego Santa Cruz 			if (mmc->high_capacity && part_completed) {
1808d7b29129SMarkus Niebel 				capacity = (ext_csd[EXT_CSD_SEC_CNT]) |
1809d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 1] << 8) |
1810d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 2] << 16) |
1811d7b29129SMarkus Niebel 					(ext_csd[EXT_CSD_SEC_CNT + 3] << 24);
1812d7b29129SMarkus Niebel 				capacity *= MMC_MAX_BLOCK_LEN;
1813d7b29129SMarkus Niebel 				mmc->capacity_user = capacity;
1814d7b29129SMarkus Niebel 			}
18158bfa195eSSimon Glass 		} else {
18161937e5aaSOliver Metz 			/* Calculate the group size from the csd value. */
1817e6f99a56SLei Wen 			int erase_gsz, erase_gmul;
1818e6f99a56SLei Wen 			erase_gsz = (mmc->csd[2] & 0x00007c00) >> 10;
1819e6f99a56SLei Wen 			erase_gmul = (mmc->csd[2] & 0x000003e0) >> 5;
1820e6f99a56SLei Wen 			mmc->erase_grp_size = (erase_gsz + 1)
1821e6f99a56SLei Wen 				* (erase_gmul + 1);
1822e6f99a56SLei Wen 		}
1823037dc0abSDiego Santa Cruz 
1824037dc0abSDiego Santa Cruz 		mmc->hc_wp_grp_size = 1024
1825037dc0abSDiego Santa Cruz 			* ext_csd[EXT_CSD_HC_ERASE_GRP_SIZE]
1826037dc0abSDiego Santa Cruz 			* ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
18279e41a00bSDiego Santa Cruz 
18289e41a00bSDiego Santa Cruz 		mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
1829f866a46dSStephen Warren 	}
1830f866a46dSStephen Warren 
1831c40fdca6SSimon Glass 	err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart);
1832f866a46dSStephen Warren 	if (err)
1833f866a46dSStephen Warren 		return err;
1834d23e2c09SSukumar Ghorai 
1835272cc70bSAndy Fleming 	if (IS_SD(mmc))
1836272cc70bSAndy Fleming 		err = sd_change_freq(mmc);
1837272cc70bSAndy Fleming 	else
1838272cc70bSAndy Fleming 		err = mmc_change_freq(mmc);
1839272cc70bSAndy Fleming 
1840272cc70bSAndy Fleming 	if (err)
1841272cc70bSAndy Fleming 		return err;
1842272cc70bSAndy Fleming 
1843272cc70bSAndy Fleming 	/* Restrict card's capabilities by what the host can do */
184493bfd616SPantelis Antoniou 	mmc->card_caps &= mmc->cfg->host_caps;
1845272cc70bSAndy Fleming 
1846272cc70bSAndy Fleming 	if (IS_SD(mmc)) {
1847272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_4BIT) {
1848272cc70bSAndy Fleming 			cmd.cmdidx = MMC_CMD_APP_CMD;
1849272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1850272cc70bSAndy Fleming 			cmd.cmdarg = mmc->rca << 16;
1851272cc70bSAndy Fleming 
1852272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1853272cc70bSAndy Fleming 			if (err)
1854272cc70bSAndy Fleming 				return err;
1855272cc70bSAndy Fleming 
1856272cc70bSAndy Fleming 			cmd.cmdidx = SD_CMD_APP_SET_BUS_WIDTH;
1857272cc70bSAndy Fleming 			cmd.resp_type = MMC_RSP_R1;
1858272cc70bSAndy Fleming 			cmd.cmdarg = 2;
1859272cc70bSAndy Fleming 			err = mmc_send_cmd(mmc, &cmd, NULL);
1860272cc70bSAndy Fleming 			if (err)
1861272cc70bSAndy Fleming 				return err;
1862272cc70bSAndy Fleming 
1863272cc70bSAndy Fleming 			mmc_set_bus_width(mmc, 4);
1864272cc70bSAndy Fleming 		}
1865272cc70bSAndy Fleming 
18663697e599SPeng Fan 		err = sd_read_ssr(mmc);
18673697e599SPeng Fan 		if (err)
18683697e599SPeng Fan 			return err;
18693697e599SPeng Fan 
1870272cc70bSAndy Fleming 		if (mmc->card_caps & MMC_MODE_HS)
18713e3ff0acSZiyuan Xu 			tran_speed = 50000000;
1872272cc70bSAndy Fleming 		else
18733e3ff0acSZiyuan Xu 			tran_speed = 25000000;
1874ad5fd922SJaehoon Chung 
18753e3ff0acSZiyuan Xu 		mmc_set_clock(mmc, tran_speed);
187649dba033SZiyuan Xu 	}
1877272cc70bSAndy Fleming 
18785af8f45cSAndrew Gabbasov 	/* Fix the block length for DDR mode */
187949dba033SZiyuan Xu 	if (mmc_card_ddr(mmc)) {
18805af8f45cSAndrew Gabbasov 		mmc->read_bl_len = MMC_MAX_BLOCK_LEN;
18815af8f45cSAndrew Gabbasov 		mmc->write_bl_len = MMC_MAX_BLOCK_LEN;
18825af8f45cSAndrew Gabbasov 	}
18835af8f45cSAndrew Gabbasov 
1884272cc70bSAndy Fleming 	/* fill in device description */
1885c40fdca6SSimon Glass 	bdesc = mmc_get_blk_desc(mmc);
1886c40fdca6SSimon Glass 	bdesc->lun = 0;
1887c40fdca6SSimon Glass 	bdesc->hwpart = 0;
1888c40fdca6SSimon Glass 	bdesc->type = 0;
1889c40fdca6SSimon Glass 	bdesc->blksz = mmc->read_bl_len;
1890c40fdca6SSimon Glass 	bdesc->log2blksz = LOG2(bdesc->blksz);
1891c40fdca6SSimon Glass 	bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len);
1892fc011f64SSjoerd Simons #if !defined(CONFIG_SPL_BUILD) || \
1893fc011f64SSjoerd Simons 		(defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \
1894fc011f64SSjoerd Simons 		!defined(CONFIG_USE_TINY_PRINTF))
1895c40fdca6SSimon Glass 	sprintf(bdesc->vendor, "Man %06x Snr %04x%04x",
1896babce5f6STaylor Hutt 		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
1897babce5f6STaylor Hutt 		(mmc->cid[3] >> 16) & 0xffff);
1898c40fdca6SSimon Glass 	sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
18990b453ffeSRabin Vincent 		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
1900babce5f6STaylor Hutt 		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
1901babce5f6STaylor Hutt 		(mmc->cid[2] >> 24) & 0xff);
1902c40fdca6SSimon Glass 	sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
1903babce5f6STaylor Hutt 		(mmc->cid[2] >> 16) & 0xf);
190456196826SPaul Burton #else
1905c40fdca6SSimon Glass 	bdesc->vendor[0] = 0;
1906c40fdca6SSimon Glass 	bdesc->product[0] = 0;
1907c40fdca6SSimon Glass 	bdesc->revision[0] = 0;
190856196826SPaul Burton #endif
1909122efd43SMikhail Kshevetskiy #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
1910c40fdca6SSimon Glass 	part_init(bdesc);
1911122efd43SMikhail Kshevetskiy #endif
1912272cc70bSAndy Fleming 
1913272cc70bSAndy Fleming 	return 0;
1914272cc70bSAndy Fleming }
1915272cc70bSAndy Fleming 
1916fdbb873eSKim Phillips static int mmc_send_if_cond(struct mmc *mmc)
1917272cc70bSAndy Fleming {
1918272cc70bSAndy Fleming 	struct mmc_cmd cmd;
1919272cc70bSAndy Fleming 	int err;
1920272cc70bSAndy Fleming 
1921272cc70bSAndy Fleming 	cmd.cmdidx = SD_CMD_SEND_IF_COND;
1922272cc70bSAndy Fleming 	/* We set the bit if the host supports voltages between 2.7 and 3.6 V */
192393bfd616SPantelis Antoniou 	cmd.cmdarg = ((mmc->cfg->voltages & 0xff8000) != 0) << 8 | 0xaa;
1924272cc70bSAndy Fleming 	cmd.resp_type = MMC_RSP_R7;
1925272cc70bSAndy Fleming 
1926272cc70bSAndy Fleming 	err = mmc_send_cmd(mmc, &cmd, NULL);
1927272cc70bSAndy Fleming 
1928272cc70bSAndy Fleming 	if (err)
1929272cc70bSAndy Fleming 		return err;
1930272cc70bSAndy Fleming 
1931998be3ddSRabin Vincent 	if ((cmd.response[0] & 0xff) != 0xaa)
1932915ffa52SJaehoon Chung 		return -EOPNOTSUPP;
1933272cc70bSAndy Fleming 	else
1934272cc70bSAndy Fleming 		mmc->version = SD_VERSION_2;
1935272cc70bSAndy Fleming 
1936272cc70bSAndy Fleming 	return 0;
1937272cc70bSAndy Fleming }
1938272cc70bSAndy Fleming 
1939c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
194095de9ab2SPaul Kocialkowski /* board-specific MMC power initializations. */
194195de9ab2SPaul Kocialkowski __weak void board_mmc_power_init(void)
194295de9ab2SPaul Kocialkowski {
194395de9ab2SPaul Kocialkowski }
194405cbeb7cSSimon Glass #endif
194595de9ab2SPaul Kocialkowski 
19462051aefeSPeng Fan static int mmc_power_init(struct mmc *mmc)
19472051aefeSPeng Fan {
1948c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
194905cbeb7cSSimon Glass #if defined(CONFIG_DM_REGULATOR) && !defined(CONFIG_SPL_BUILD)
19502051aefeSPeng Fan 	struct udevice *vmmc_supply;
19512051aefeSPeng Fan 	int ret;
19522051aefeSPeng Fan 
19532051aefeSPeng Fan 	ret = device_get_supply_regulator(mmc->dev, "vmmc-supply",
19542051aefeSPeng Fan 					  &vmmc_supply);
19552051aefeSPeng Fan 	if (ret) {
1956288db7c7SJaehoon Chung 		debug("%s: No vmmc supply\n", mmc->dev->name);
19572051aefeSPeng Fan 		return 0;
19582051aefeSPeng Fan 	}
19592051aefeSPeng Fan 
19602051aefeSPeng Fan 	ret = regulator_set_enable(vmmc_supply, true);
19612051aefeSPeng Fan 	if (ret) {
19622051aefeSPeng Fan 		puts("Error enabling VMMC supply\n");
19632051aefeSPeng Fan 		return ret;
19642051aefeSPeng Fan 	}
19652051aefeSPeng Fan #endif
196605cbeb7cSSimon Glass #else /* !CONFIG_DM_MMC */
196705cbeb7cSSimon Glass 	/*
196805cbeb7cSSimon Glass 	 * Driver model should use a regulator, as above, rather than calling
196905cbeb7cSSimon Glass 	 * out to board code.
197005cbeb7cSSimon Glass 	 */
197105cbeb7cSSimon Glass 	board_mmc_power_init();
197205cbeb7cSSimon Glass #endif
19732051aefeSPeng Fan 	return 0;
19742051aefeSPeng Fan }
19752051aefeSPeng Fan 
1976e9550449SChe-Liang Chiou int mmc_start_init(struct mmc *mmc)
1977272cc70bSAndy Fleming {
19788ca51e51SSimon Glass 	bool no_card;
1979afd5932bSMacpaul Lin 	int err;
1980272cc70bSAndy Fleming 
1981ab769f22SPantelis Antoniou 	/* we pretend there's no card when init is NULL */
19828ca51e51SSimon Glass 	no_card = mmc_getcd(mmc) == 0;
1983e7881d85SSimon Glass #if !CONFIG_IS_ENABLED(DM_MMC)
19848ca51e51SSimon Glass 	no_card = no_card || (mmc->cfg->ops->init == NULL);
19858ca51e51SSimon Glass #endif
19868ca51e51SSimon Glass 	if (no_card) {
198748972d90SThierry Reding 		mmc->has_init = 0;
198856196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
198948972d90SThierry Reding 		printf("MMC: no card present\n");
199056196826SPaul Burton #endif
1991915ffa52SJaehoon Chung 		return -ENOMEDIUM;
199248972d90SThierry Reding 	}
199348972d90SThierry Reding 
1994bc897b1dSLei Wen 	if (mmc->has_init)
1995bc897b1dSLei Wen 		return 0;
1996bc897b1dSLei Wen 
19975a8dbdc6SYangbo Lu #ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
19985a8dbdc6SYangbo Lu 	mmc_adapter_card_type_ident();
19995a8dbdc6SYangbo Lu #endif
20002051aefeSPeng Fan 	err = mmc_power_init(mmc);
20012051aefeSPeng Fan 	if (err)
20022051aefeSPeng Fan 		return err;
200395de9ab2SPaul Kocialkowski 
2004e7881d85SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
20058ca51e51SSimon Glass 	/* The device has already been probed ready for use */
20068ca51e51SSimon Glass #else
2007ab769f22SPantelis Antoniou 	/* made sure it's not NULL earlier */
200893bfd616SPantelis Antoniou 	err = mmc->cfg->ops->init(mmc);
2009272cc70bSAndy Fleming 	if (err)
2010272cc70bSAndy Fleming 		return err;
20118ca51e51SSimon Glass #endif
2012b86b85e2SIlya Yanok 	mmc_set_bus_width(mmc, 1);
2013b86b85e2SIlya Yanok 	mmc_set_clock(mmc, 1);
201481db2d36SZiyuan Xu 	mmc_set_timing(mmc, MMC_TIMING_LEGACY);
2015b86b85e2SIlya Yanok 
2016272cc70bSAndy Fleming 	/* Reset the Card */
2017272cc70bSAndy Fleming 	err = mmc_go_idle(mmc);
2018272cc70bSAndy Fleming 
2019272cc70bSAndy Fleming 	if (err)
2020272cc70bSAndy Fleming 		return err;
2021272cc70bSAndy Fleming 
2022bc897b1dSLei Wen 	/* The internal partition reset to user partition(0) at every CMD0*/
2023c40fdca6SSimon Glass 	mmc_get_blk_desc(mmc)->hwpart = 0;
2024bc897b1dSLei Wen 
2025272cc70bSAndy Fleming 	/* Test for SD version 2 */
2026272cc70bSAndy Fleming 	err = mmc_send_if_cond(mmc);
2027272cc70bSAndy Fleming 
2028272cc70bSAndy Fleming 	/* Now try to get the SD card's operating condition */
2029272cc70bSAndy Fleming 	err = sd_send_op_cond(mmc);
2030272cc70bSAndy Fleming 
2031272cc70bSAndy Fleming 	/* If the command timed out, we check for an MMC card */
2032915ffa52SJaehoon Chung 	if (err == -ETIMEDOUT) {
2033272cc70bSAndy Fleming 		err = mmc_send_op_cond(mmc);
2034272cc70bSAndy Fleming 
2035bd47c135SAndrew Gabbasov 		if (err) {
203656196826SPaul Burton #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
2037272cc70bSAndy Fleming 			printf("Card did not respond to voltage select!\n");
203856196826SPaul Burton #endif
2039915ffa52SJaehoon Chung 			return -EOPNOTSUPP;
2040272cc70bSAndy Fleming 		}
2041272cc70bSAndy Fleming 	}
2042272cc70bSAndy Fleming 
2043bd47c135SAndrew Gabbasov 	if (!err)
2044e9550449SChe-Liang Chiou 		mmc->init_in_progress = 1;
2045e9550449SChe-Liang Chiou 
2046e9550449SChe-Liang Chiou 	return err;
2047e9550449SChe-Liang Chiou }
2048e9550449SChe-Liang Chiou 
2049e9550449SChe-Liang Chiou static int mmc_complete_init(struct mmc *mmc)
2050e9550449SChe-Liang Chiou {
2051e9550449SChe-Liang Chiou 	int err = 0;
2052e9550449SChe-Liang Chiou 
2053bd47c135SAndrew Gabbasov 	mmc->init_in_progress = 0;
2054e9550449SChe-Liang Chiou 	if (mmc->op_cond_pending)
2055e9550449SChe-Liang Chiou 		err = mmc_complete_op_cond(mmc);
2056e9550449SChe-Liang Chiou 
2057e9550449SChe-Liang Chiou 	if (!err)
2058bc897b1dSLei Wen 		err = mmc_startup(mmc);
2059bc897b1dSLei Wen 	if (err)
2060bc897b1dSLei Wen 		mmc->has_init = 0;
2061bc897b1dSLei Wen 	else
2062bc897b1dSLei Wen 		mmc->has_init = 1;
2063e9550449SChe-Liang Chiou 	return err;
2064e9550449SChe-Liang Chiou }
2065e9550449SChe-Liang Chiou 
2066e9550449SChe-Liang Chiou int mmc_init(struct mmc *mmc)
2067e9550449SChe-Liang Chiou {
2068bd47c135SAndrew Gabbasov 	int err = 0;
2069ce9eca94SMarek Vasut 	__maybe_unused unsigned start;
2070c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC)
207133fb211dSSimon Glass 	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev);
2072e9550449SChe-Liang Chiou 
207333fb211dSSimon Glass 	upriv->mmc = mmc;
207433fb211dSSimon Glass #endif
2075e9550449SChe-Liang Chiou 	if (mmc->has_init)
2076e9550449SChe-Liang Chiou 		return 0;
2077d803fea5SMateusz Zalega 
2078d803fea5SMateusz Zalega 	start = get_timer(0);
2079d803fea5SMateusz Zalega 
2080e9550449SChe-Liang Chiou 	if (!mmc->init_in_progress)
2081e9550449SChe-Liang Chiou 		err = mmc_start_init(mmc);
2082e9550449SChe-Liang Chiou 
2083bd47c135SAndrew Gabbasov 	if (!err)
2084e9550449SChe-Liang Chiou 		err = mmc_complete_init(mmc);
2085919b4858SJagan Teki 	if (err)
2086919b4858SJagan Teki 		printf("%s: %d, time %lu\n", __func__, err, get_timer(start));
2087919b4858SJagan Teki 
2088bc897b1dSLei Wen 	return err;
2089272cc70bSAndy Fleming }
2090272cc70bSAndy Fleming 
2091ab71188cSMarkus Niebel int mmc_set_dsr(struct mmc *mmc, u16 val)
2092ab71188cSMarkus Niebel {
2093ab71188cSMarkus Niebel 	mmc->dsr = val;
2094ab71188cSMarkus Niebel 	return 0;
2095ab71188cSMarkus Niebel }
2096ab71188cSMarkus Niebel 
2097cee9ab7cSJeroen Hofstee /* CPU-specific MMC initializations */
2098cee9ab7cSJeroen Hofstee __weak int cpu_mmc_init(bd_t *bis)
2099272cc70bSAndy Fleming {
2100272cc70bSAndy Fleming 	return -1;
2101272cc70bSAndy Fleming }
2102272cc70bSAndy Fleming 
2103cee9ab7cSJeroen Hofstee /* board-specific MMC initializations. */
2104cee9ab7cSJeroen Hofstee __weak int board_mmc_init(bd_t *bis)
2105cee9ab7cSJeroen Hofstee {
2106cee9ab7cSJeroen Hofstee 	return -1;
2107cee9ab7cSJeroen Hofstee }
2108272cc70bSAndy Fleming 
2109e9550449SChe-Liang Chiou void mmc_set_preinit(struct mmc *mmc, int preinit)
2110e9550449SChe-Liang Chiou {
2111e9550449SChe-Liang Chiou 	mmc->preinit = preinit;
2112e9550449SChe-Liang Chiou }
2113e9550449SChe-Liang Chiou 
2114c4d660d4SSimon Glass #if CONFIG_IS_ENABLED(DM_MMC) && defined(CONFIG_SPL_BUILD)
21158e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
21168e3332e2SSjoerd Simons {
21178e3332e2SSjoerd Simons 	return 0;
21188e3332e2SSjoerd Simons }
2119c4d660d4SSimon Glass #elif CONFIG_IS_ENABLED(DM_MMC)
21208e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
21218e3332e2SSjoerd Simons {
21224a1db6d8SSimon Glass 	int ret, i;
21238e3332e2SSjoerd Simons 	struct uclass *uc;
21244a1db6d8SSimon Glass 	struct udevice *dev;
21258e3332e2SSjoerd Simons 
21268e3332e2SSjoerd Simons 	ret = uclass_get(UCLASS_MMC, &uc);
21278e3332e2SSjoerd Simons 	if (ret)
21288e3332e2SSjoerd Simons 		return ret;
21298e3332e2SSjoerd Simons 
21304a1db6d8SSimon Glass 	/*
21314a1db6d8SSimon Glass 	 * Try to add them in sequence order. Really with driver model we
21324a1db6d8SSimon Glass 	 * should allow holes, but the current MMC list does not allow that.
21334a1db6d8SSimon Glass 	 * So if we request 0, 1, 3 we will get 0, 1, 2.
21344a1db6d8SSimon Glass 	 */
21354a1db6d8SSimon Glass 	for (i = 0; ; i++) {
21364a1db6d8SSimon Glass 		ret = uclass_get_device_by_seq(UCLASS_MMC, i, &dev);
21374a1db6d8SSimon Glass 		if (ret == -ENODEV)
21384a1db6d8SSimon Glass 			break;
21394a1db6d8SSimon Glass 	}
21404a1db6d8SSimon Glass 	uclass_foreach_dev(dev, uc) {
21414a1db6d8SSimon Glass 		ret = device_probe(dev);
21428e3332e2SSjoerd Simons 		if (ret)
21434a1db6d8SSimon Glass 			printf("%s - probe failed: %d\n", dev->name, ret);
21448e3332e2SSjoerd Simons 	}
21458e3332e2SSjoerd Simons 
21468e3332e2SSjoerd Simons 	return 0;
21478e3332e2SSjoerd Simons }
21488e3332e2SSjoerd Simons #else
21498e3332e2SSjoerd Simons static int mmc_probe(bd_t *bis)
21508e3332e2SSjoerd Simons {
21518e3332e2SSjoerd Simons 	if (board_mmc_init(bis) < 0)
21528e3332e2SSjoerd Simons 		cpu_mmc_init(bis);
21538e3332e2SSjoerd Simons 
21548e3332e2SSjoerd Simons 	return 0;
21558e3332e2SSjoerd Simons }
21568e3332e2SSjoerd Simons #endif
2157e9550449SChe-Liang Chiou 
2158272cc70bSAndy Fleming int mmc_initialize(bd_t *bis)
2159272cc70bSAndy Fleming {
21601b26bab1SDaniel Kochmański 	static int initialized = 0;
21618e3332e2SSjoerd Simons 	int ret;
21621b26bab1SDaniel Kochmański 	if (initialized)	/* Avoid initializing mmc multiple times */
21631b26bab1SDaniel Kochmański 		return 0;
21641b26bab1SDaniel Kochmański 	initialized = 1;
21651b26bab1SDaniel Kochmański 
2166c4d660d4SSimon Glass #if !CONFIG_IS_ENABLED(BLK)
2167b5b838f1SMarek Vasut #if !CONFIG_IS_ENABLED(MMC_TINY)
2168c40fdca6SSimon Glass 	mmc_list_init();
2169c40fdca6SSimon Glass #endif
2170b5b838f1SMarek Vasut #endif
21718e3332e2SSjoerd Simons 	ret = mmc_probe(bis);
21728e3332e2SSjoerd Simons 	if (ret)
21738e3332e2SSjoerd Simons 		return ret;
2174272cc70bSAndy Fleming 
2175bb0dc108SYing Zhang #ifndef CONFIG_SPL_BUILD
2176272cc70bSAndy Fleming 	print_mmc_devices(',');
2177bb0dc108SYing Zhang #endif
2178272cc70bSAndy Fleming 
2179c40fdca6SSimon Glass 	mmc_do_preinit();
2180272cc70bSAndy Fleming 	return 0;
2181272cc70bSAndy Fleming }
2182cd3d4880STomas Melin 
2183cd3d4880STomas Melin #ifdef CONFIG_CMD_BKOPS_ENABLE
2184cd3d4880STomas Melin int mmc_set_bkops_enable(struct mmc *mmc)
2185cd3d4880STomas Melin {
2186cd3d4880STomas Melin 	int err;
2187cd3d4880STomas Melin 	ALLOC_CACHE_ALIGN_BUFFER(u8, ext_csd, MMC_MAX_BLOCK_LEN);
2188cd3d4880STomas Melin 
2189cd3d4880STomas Melin 	err = mmc_send_ext_csd(mmc, ext_csd);
2190cd3d4880STomas Melin 	if (err) {
2191cd3d4880STomas Melin 		puts("Could not get ext_csd register values\n");
2192cd3d4880STomas Melin 		return err;
2193cd3d4880STomas Melin 	}
2194cd3d4880STomas Melin 
2195cd3d4880STomas Melin 	if (!(ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)) {
2196cd3d4880STomas Melin 		puts("Background operations not supported on device\n");
2197cd3d4880STomas Melin 		return -EMEDIUMTYPE;
2198cd3d4880STomas Melin 	}
2199cd3d4880STomas Melin 
2200cd3d4880STomas Melin 	if (ext_csd[EXT_CSD_BKOPS_EN] & 0x1) {
2201cd3d4880STomas Melin 		puts("Background operations already enabled\n");
2202cd3d4880STomas Melin 		return 0;
2203cd3d4880STomas Melin 	}
2204cd3d4880STomas Melin 
2205cd3d4880STomas Melin 	err = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BKOPS_EN, 1);
2206cd3d4880STomas Melin 	if (err) {
2207cd3d4880STomas Melin 		puts("Failed to enable manual background operations\n");
2208cd3d4880STomas Melin 		return err;
2209cd3d4880STomas Melin 	}
2210cd3d4880STomas Melin 
2211cd3d4880STomas Melin 	puts("Enabled manual background operations\n");
2212cd3d4880STomas Melin 
2213cd3d4880STomas Melin 	return 0;
2214cd3d4880STomas Melin }
2215cd3d4880STomas Melin #endif
2216